mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-17 15:32:10 +08:00

committed by
Brad King

parent
3cb5a8d9b3
commit
fec441ec17
@@ -6,6 +6,10 @@ This command will be added as a prefix to :command:`add_test`,
|
|||||||
:command:`add_custom_command`, and :command:`add_custom_target` commands
|
:command:`add_custom_command`, and :command:`add_custom_target` commands
|
||||||
for built target system executables.
|
for built target system executables.
|
||||||
|
|
||||||
|
If this property contains a :ref:`semicolon-separated list <CMake Language
|
||||||
|
Lists>`, then the first value is the command and remaining values are its
|
||||||
|
arguments.
|
||||||
|
|
||||||
This property is initialized by the value of the
|
This property is initialized by the value of the
|
||||||
:variable:`CMAKE_CROSSCOMPILING_EMULATOR` variable if it is set when a target
|
:variable:`CMAKE_CROSSCOMPILING_EMULATOR` variable if it is set when a target
|
||||||
is created.
|
is created.
|
||||||
|
6
Help/release/dev/emulator-arguments.rst
Normal file
6
Help/release/dev/emulator-arguments.rst
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
emulator-arguments
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* The :variable:`CMAKE_CROSSCOMPILING_EMULATOR` variable and corresponding
|
||||||
|
:prop_tgt:`CROSSCOMPILING_EMULATOR` target property learned to support
|
||||||
|
arguments to the emulator.
|
@@ -5,6 +5,10 @@ This variable is only used when :variable:`CMAKE_CROSSCOMPILING` is on. It
|
|||||||
should point to a command on the host system that can run executable built
|
should point to a command on the host system that can run executable built
|
||||||
for the target system.
|
for the target system.
|
||||||
|
|
||||||
|
If this variable contains a :ref:`semicolon-separated list <CMake Language
|
||||||
|
Lists>`, then the first value is the command and remaining values are its
|
||||||
|
arguments.
|
||||||
|
|
||||||
The command will be used to run :command:`try_run` generated executables,
|
The command will be used to run :command:`try_run` generated executables,
|
||||||
which avoids manual population of the ``TryRunResults.cmake`` file.
|
which avoids manual population of the ``TryRunResults.cmake`` file.
|
||||||
|
|
||||||
|
@@ -75,6 +75,8 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
|
|||||||
cmSystemTools::CollapseFullPath(this->WorkingDirectory, build_dir);
|
cmSystemTools::CollapseFullPath(this->WorkingDirectory, build_dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->FillEmulatorsWithArguments();
|
||||||
}
|
}
|
||||||
|
|
||||||
cmCustomCommandGenerator::~cmCustomCommandGenerator()
|
cmCustomCommandGenerator::~cmCustomCommandGenerator()
|
||||||
@@ -87,19 +89,38 @@ unsigned int cmCustomCommandGenerator::GetNumberOfCommands() const
|
|||||||
return static_cast<unsigned int>(this->CC.GetCommandLines().size());
|
return static_cast<unsigned int>(this->CC.GetCommandLines().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* cmCustomCommandGenerator::GetCrossCompilingEmulator(
|
void cmCustomCommandGenerator::FillEmulatorsWithArguments()
|
||||||
unsigned int c) const
|
|
||||||
{
|
{
|
||||||
if (!this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING")) {
|
if (!this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING")) {
|
||||||
return nullptr;
|
return;
|
||||||
}
|
}
|
||||||
std::string const& argv0 = this->CommandLines[c][0];
|
|
||||||
cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
|
for (unsigned int c = 0; c < this->GetNumberOfCommands(); ++c) {
|
||||||
if (target && target->GetType() == cmStateEnums::EXECUTABLE &&
|
std::string const& argv0 = this->CommandLines[c][0];
|
||||||
!target->IsImported()) {
|
cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
|
||||||
return target->GetProperty("CROSSCOMPILING_EMULATOR");
|
if (target && target->GetType() == cmStateEnums::EXECUTABLE &&
|
||||||
|
!target->IsImported()) {
|
||||||
|
|
||||||
|
const char* emulator_property =
|
||||||
|
target->GetProperty("CROSSCOMPILING_EMULATOR");
|
||||||
|
if (!emulator_property) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->EmulatorsWithArguments.emplace_back();
|
||||||
|
cmSystemTools::ExpandListArgument(emulator_property,
|
||||||
|
this->EmulatorsWithArguments[c]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> cmCustomCommandGenerator::GetCrossCompilingEmulator(
|
||||||
|
unsigned int c) const
|
||||||
|
{
|
||||||
|
if (c >= this->EmulatorsWithArguments.size()) {
|
||||||
|
return std::vector<std::string>();
|
||||||
|
}
|
||||||
|
return this->EmulatorsWithArguments[c];
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* cmCustomCommandGenerator::GetArgv0Location(unsigned int c) const
|
const char* cmCustomCommandGenerator::GetArgv0Location(unsigned int c) const
|
||||||
@@ -129,8 +150,9 @@ bool cmCustomCommandGenerator::HasOnlyEmptyCommandLines() const
|
|||||||
|
|
||||||
std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const
|
std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const
|
||||||
{
|
{
|
||||||
if (const char* emulator = this->GetCrossCompilingEmulator(c)) {
|
std::vector<std::string> emulator = this->GetCrossCompilingEmulator(c);
|
||||||
return std::string(emulator);
|
if (!emulator.empty()) {
|
||||||
|
return emulator[0];
|
||||||
}
|
}
|
||||||
if (const char* location = this->GetArgv0Location(c)) {
|
if (const char* location = this->GetArgv0Location(c)) {
|
||||||
return std::string(location);
|
return std::string(location);
|
||||||
@@ -168,9 +190,20 @@ void cmCustomCommandGenerator::AppendArguments(unsigned int c,
|
|||||||
std::string& cmd) const
|
std::string& cmd) const
|
||||||
{
|
{
|
||||||
unsigned int offset = 1;
|
unsigned int offset = 1;
|
||||||
if (this->GetCrossCompilingEmulator(c) != nullptr) {
|
std::vector<std::string> emulator = this->GetCrossCompilingEmulator(c);
|
||||||
|
if (!emulator.empty()) {
|
||||||
|
for (unsigned j = 1; j < emulator.size(); ++j) {
|
||||||
|
cmd += " ";
|
||||||
|
if (this->OldStyle) {
|
||||||
|
cmd += escapeForShellOldStyle(emulator[j]);
|
||||||
|
} else {
|
||||||
|
cmd += this->LG->EscapeForShell(emulator[j], this->MakeVars);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmCustomCommandLine const& commandLine = this->CommandLines[c];
|
cmCustomCommandLine const& commandLine = this->CommandLines[c];
|
||||||
for (unsigned int j = offset; j < commandLine.size(); ++j) {
|
for (unsigned int j = offset; j < commandLine.size(); ++j) {
|
||||||
std::string arg;
|
std::string arg;
|
||||||
|
@@ -22,10 +22,12 @@ class cmCustomCommandGenerator
|
|||||||
bool MakeVars;
|
bool MakeVars;
|
||||||
cmGeneratorExpression* GE;
|
cmGeneratorExpression* GE;
|
||||||
cmCustomCommandLines CommandLines;
|
cmCustomCommandLines CommandLines;
|
||||||
|
std::vector<std::vector<std::string>> EmulatorsWithArguments;
|
||||||
std::vector<std::string> Depends;
|
std::vector<std::string> Depends;
|
||||||
std::string WorkingDirectory;
|
std::string WorkingDirectory;
|
||||||
|
|
||||||
const char* GetCrossCompilingEmulator(unsigned int c) const;
|
void FillEmulatorsWithArguments();
|
||||||
|
std::vector<std::string> GetCrossCompilingEmulator(unsigned int c) const;
|
||||||
const char* GetArgv0Location(unsigned int c) const;
|
const char* GetArgv0Location(unsigned int c) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@@ -448,9 +448,11 @@ endif()
|
|||||||
|
|
||||||
add_executable(pseudo_emulator pseudo_emulator.c)
|
add_executable(pseudo_emulator pseudo_emulator.c)
|
||||||
add_executable(pseudo_emulator_custom_command pseudo_emulator_custom_command.c)
|
add_executable(pseudo_emulator_custom_command pseudo_emulator_custom_command.c)
|
||||||
|
add_executable(pseudo_emulator_custom_command_arg pseudo_emulator_custom_command_arg.c)
|
||||||
add_RunCMake_test(CrosscompilingEmulator
|
add_RunCMake_test(CrosscompilingEmulator
|
||||||
-DPSEUDO_EMULATOR=$<TARGET_FILE:pseudo_emulator>
|
-DPSEUDO_EMULATOR=$<TARGET_FILE:pseudo_emulator>
|
||||||
-DPSEUDO_EMULATOR_CUSTOM_COMMAND=$<TARGET_FILE:pseudo_emulator_custom_command>)
|
-DPSEUDO_EMULATOR_CUSTOM_COMMAND=$<TARGET_FILE:pseudo_emulator_custom_command>
|
||||||
|
-DPSEUDO_EMULATOR_CUSTOM_COMMAND_ARG=$<TARGET_FILE:pseudo_emulator_custom_command_arg>)
|
||||||
if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
|
if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
|
||||||
if(UNIX AND NOT CYGWIN)
|
if(UNIX AND NOT CYGWIN)
|
||||||
execute_process(COMMAND ldd --help
|
execute_process(COMMAND ldd --help
|
||||||
|
@@ -0,0 +1,3 @@
|
|||||||
|
if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/output")
|
||||||
|
message(FATAL_ERROR "Failed to create output: ${RunCMake_TEST_BINARY_DIR}/output")
|
||||||
|
endif()
|
@@ -0,0 +1,14 @@
|
|||||||
|
set(CMAKE_CROSSCOMPILING 1)
|
||||||
|
|
||||||
|
# Executable: Return error code different from 0
|
||||||
|
add_executable(generated_exe_emulator_expected simple_src_exiterror.cxx)
|
||||||
|
|
||||||
|
add_custom_command(OUTPUT output
|
||||||
|
COMMAND generated_exe_emulator_expected
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/output
|
||||||
|
DEPENDS generated_exe_emulator_expected)
|
||||||
|
|
||||||
|
add_custom_target(ensure_build ALL
|
||||||
|
SOURCES
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/output
|
||||||
|
)
|
@@ -0,0 +1 @@
|
|||||||
|
include(${CMAKE_CURRENT_LIST_DIR}/AddCustomCommandWithArg-build-check.cmake)
|
@@ -0,0 +1,9 @@
|
|||||||
|
set(CMAKE_CROSSCOMPILING 1)
|
||||||
|
|
||||||
|
# Executable: Return error code different from 0
|
||||||
|
add_executable(generated_exe_emulator_expected simple_src_exiterror.cxx)
|
||||||
|
|
||||||
|
add_custom_target(generate_output ALL
|
||||||
|
generated_exe_emulator_expected
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/output
|
||||||
|
DEPENDS generated_exe_emulator_expected)
|
@@ -11,13 +11,18 @@ function(CustomCommandGenerator_run_and_build case)
|
|||||||
# Use a single build tree for a few tests without cleaning.
|
# Use a single build tree for a few tests without cleaning.
|
||||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build)
|
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build)
|
||||||
set(RunCMake_TEST_NO_CLEAN 1)
|
set(RunCMake_TEST_NO_CLEAN 1)
|
||||||
set(RunCMake_TEST_OPTIONS
|
|
||||||
"-DCMAKE_CROSSCOMPILING_EMULATOR=${PSEUDO_EMULATOR_CUSTOM_COMMAND}")
|
|
||||||
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
|
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
|
||||||
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
|
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
|
||||||
run_cmake(${case})
|
run_cmake(${case})
|
||||||
run_cmake_command(${case}-build ${CMAKE_COMMAND} --build .)
|
run_cmake_command(${case}-build ${CMAKE_COMMAND} --build .)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
set(RunCMake_TEST_OPTIONS
|
||||||
|
"-DCMAKE_CROSSCOMPILING_EMULATOR=${PSEUDO_EMULATOR_CUSTOM_COMMAND}")
|
||||||
CustomCommandGenerator_run_and_build(AddCustomCommand)
|
CustomCommandGenerator_run_and_build(AddCustomCommand)
|
||||||
CustomCommandGenerator_run_and_build(AddCustomTarget)
|
CustomCommandGenerator_run_and_build(AddCustomTarget)
|
||||||
|
|
||||||
|
set(RunCMake_TEST_OPTIONS
|
||||||
|
"-DCMAKE_CROSSCOMPILING_EMULATOR=${PSEUDO_EMULATOR_CUSTOM_COMMAND_ARG}\;custom_argument")
|
||||||
|
CustomCommandGenerator_run_and_build(AddCustomCommandWithArg)
|
||||||
|
CustomCommandGenerator_run_and_build(AddCustomTargetWithArg)
|
||||||
|
30
Tests/RunCMake/pseudo_emulator_custom_command_arg.c
Normal file
30
Tests/RunCMake/pseudo_emulator_custom_command_arg.c
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// Usage:
|
||||||
|
//
|
||||||
|
// /path/to/program arg1 [arg2 [...]]
|
||||||
|
//
|
||||||
|
// Return EXIT_SUCCESS if 'custom_argument' string was found
|
||||||
|
// in <arg1> and 'generated_exe_emulator_expected'
|
||||||
|
// string was found in <arg2>
|
||||||
|
// Return EXIT_FAILURE if 'custom_argument' string was not
|
||||||
|
// found in <arg1> or 'generated_exe_emulator_expected'
|
||||||
|
// string was not found in <arg2>.
|
||||||
|
|
||||||
|
int main(int argc, const char* argv[])
|
||||||
|
{
|
||||||
|
// Require a slash to make sure it is a path and not a target name.
|
||||||
|
const char* substring_success = "/generated_exe_emulator_expected";
|
||||||
|
const char* substring_custom_argument = "custom_argument";
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
if (strstr(argv[1], substring_custom_argument) != 0 &&
|
||||||
|
strstr(argv[2], substring_success) != 0) {
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
Reference in New Issue
Block a user