diff options
author | Marek Antoniak <kfazol@gmail.com> | 2019-05-30 14:11:10 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2019-06-03 14:17:17 (GMT) |
commit | fec441ec17d74b6444fad2a3e32a47dd19f1be5b (patch) | |
tree | 073dc1ab354485e4be0caba5730b83bad97a979f | |
parent | 3cb5a8d9b3add4394b12d61b5ce83ea6ca148fd1 (diff) | |
download | CMake-fec441ec17d74b6444fad2a3e32a47dd19f1be5b.zip CMake-fec441ec17d74b6444fad2a3e32a47dd19f1be5b.tar.gz CMake-fec441ec17d74b6444fad2a3e32a47dd19f1be5b.tar.bz2 |
Teach CROSSCOMPILING_EMULATOR to support arguments
Fixes: #19321
12 files changed, 129 insertions, 16 deletions
diff --git a/Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst b/Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst index a0811bc..87c5978 100644 --- a/Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst +++ b/Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst @@ -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 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 :variable:`CMAKE_CROSSCOMPILING_EMULATOR` variable if it is set when a target is created. diff --git a/Help/release/dev/emulator-arguments.rst b/Help/release/dev/emulator-arguments.rst new file mode 100644 index 0000000..3edb790 --- /dev/null +++ b/Help/release/dev/emulator-arguments.rst @@ -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. diff --git a/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst b/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst index e7774f2..1d013b7 100644 --- a/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst +++ b/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst @@ -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 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, which avoids manual population of the ``TryRunResults.cmake`` file. diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx index e58fc76..89aaad0 100644 --- a/Source/cmCustomCommandGenerator.cxx +++ b/Source/cmCustomCommandGenerator.cxx @@ -75,6 +75,8 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc, cmSystemTools::CollapseFullPath(this->WorkingDirectory, build_dir); } } + + this->FillEmulatorsWithArguments(); } cmCustomCommandGenerator::~cmCustomCommandGenerator() @@ -87,19 +89,38 @@ unsigned int cmCustomCommandGenerator::GetNumberOfCommands() const return static_cast<unsigned int>(this->CC.GetCommandLines().size()); } -const char* cmCustomCommandGenerator::GetCrossCompilingEmulator( - unsigned int c) const +void cmCustomCommandGenerator::FillEmulatorsWithArguments() { if (!this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING")) { - return nullptr; + return; } - std::string const& argv0 = this->CommandLines[c][0]; - cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0); - if (target && target->GetType() == cmStateEnums::EXECUTABLE && - !target->IsImported()) { - return target->GetProperty("CROSSCOMPILING_EMULATOR"); + + for (unsigned int c = 0; c < this->GetNumberOfCommands(); ++c) { + std::string const& argv0 = this->CommandLines[c][0]; + cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0); + 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 @@ -129,8 +150,9 @@ bool cmCustomCommandGenerator::HasOnlyEmptyCommandLines() const std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const { - if (const char* emulator = this->GetCrossCompilingEmulator(c)) { - return std::string(emulator); + std::vector<std::string> emulator = this->GetCrossCompilingEmulator(c); + if (!emulator.empty()) { + return emulator[0]; } if (const char* location = this->GetArgv0Location(c)) { return std::string(location); @@ -168,9 +190,20 @@ void cmCustomCommandGenerator::AppendArguments(unsigned int c, std::string& cmd) const { 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; } + cmCustomCommandLine const& commandLine = this->CommandLines[c]; for (unsigned int j = offset; j < commandLine.size(); ++j) { std::string arg; diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h index 7fd60c0..766f4b8 100644 --- a/Source/cmCustomCommandGenerator.h +++ b/Source/cmCustomCommandGenerator.h @@ -22,10 +22,12 @@ class cmCustomCommandGenerator bool MakeVars; cmGeneratorExpression* GE; cmCustomCommandLines CommandLines; + std::vector<std::vector<std::string>> EmulatorsWithArguments; std::vector<std::string> Depends; 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; public: diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 0ccfca8..6e6b9f1 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -448,9 +448,11 @@ endif() add_executable(pseudo_emulator pseudo_emulator.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 -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(UNIX AND NOT CYGWIN) execute_process(COMMAND ldd --help diff --git a/Tests/RunCMake/CrosscompilingEmulator/AddCustomCommandWithArg-build-check.cmake b/Tests/RunCMake/CrosscompilingEmulator/AddCustomCommandWithArg-build-check.cmake new file mode 100644 index 0000000..9ca6106 --- /dev/null +++ b/Tests/RunCMake/CrosscompilingEmulator/AddCustomCommandWithArg-build-check.cmake @@ -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() diff --git a/Tests/RunCMake/CrosscompilingEmulator/AddCustomCommandWithArg.cmake b/Tests/RunCMake/CrosscompilingEmulator/AddCustomCommandWithArg.cmake new file mode 100644 index 0000000..d9059ca --- /dev/null +++ b/Tests/RunCMake/CrosscompilingEmulator/AddCustomCommandWithArg.cmake @@ -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 +) diff --git a/Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg-build-check.cmake b/Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg-build-check.cmake new file mode 100644 index 0000000..13c0db9 --- /dev/null +++ b/Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg-build-check.cmake @@ -0,0 +1 @@ +include(${CMAKE_CURRENT_LIST_DIR}/AddCustomCommandWithArg-build-check.cmake) diff --git a/Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg.cmake b/Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg.cmake new file mode 100644 index 0000000..dcd80d5 --- /dev/null +++ b/Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg.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) diff --git a/Tests/RunCMake/CrosscompilingEmulator/RunCMakeTest.cmake b/Tests/RunCMake/CrosscompilingEmulator/RunCMakeTest.cmake index 71aaad1..97b7b5a 100644 --- a/Tests/RunCMake/CrosscompilingEmulator/RunCMakeTest.cmake +++ b/Tests/RunCMake/CrosscompilingEmulator/RunCMakeTest.cmake @@ -11,13 +11,18 @@ function(CustomCommandGenerator_run_and_build case) # Use a single build tree for a few tests without cleaning. set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build) 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(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") run_cmake(${case}) run_cmake_command(${case}-build ${CMAKE_COMMAND} --build .) endfunction() +set(RunCMake_TEST_OPTIONS +"-DCMAKE_CROSSCOMPILING_EMULATOR=${PSEUDO_EMULATOR_CUSTOM_COMMAND}") CustomCommandGenerator_run_and_build(AddCustomCommand) 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) diff --git a/Tests/RunCMake/pseudo_emulator_custom_command_arg.c b/Tests/RunCMake/pseudo_emulator_custom_command_arg.c new file mode 100644 index 0000000..d00deda --- /dev/null +++ b/Tests/RunCMake/pseudo_emulator_custom_command_arg.c @@ -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; +} |