summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Antoniak <kfazol@gmail.com>2019-05-30 16:11:10 +0200
committerBrad King <brad.king@kitware.com>2019-06-03 10:17:17 -0400
commitfec441ec17d74b6444fad2a3e32a47dd19f1be5b (patch)
tree073dc1ab354485e4be0caba5730b83bad97a979f
parent3cb5a8d9b3add4394b12d61b5ce83ea6ca148fd1 (diff)
downloadcmake-fec441ec17d74b6444fad2a3e32a47dd19f1be5b.tar.gz
Teach CROSSCOMPILING_EMULATOR to support arguments
Fixes: #19321
-rw-r--r--Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst4
-rw-r--r--Help/release/dev/emulator-arguments.rst6
-rw-r--r--Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst4
-rw-r--r--Source/cmCustomCommandGenerator.cxx57
-rw-r--r--Source/cmCustomCommandGenerator.h4
-rw-r--r--Tests/RunCMake/CMakeLists.txt4
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddCustomCommandWithArg-build-check.cmake3
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddCustomCommandWithArg.cmake14
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg-build-check.cmake1
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg.cmake9
-rw-r--r--Tests/RunCMake/CrosscompilingEmulator/RunCMakeTest.cmake9
-rw-r--r--Tests/RunCMake/pseudo_emulator_custom_command_arg.c30
12 files changed, 129 insertions, 16 deletions
diff --git a/Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst b/Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst
index a0811bcaa4..87c5978bc9 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 0000000000..3edb790096
--- /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 e7774f213b..1d013b7a66 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 e58fc764b8..89aaad0dce 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 7fd60c0c4f..766f4b81d8 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 0ccfca8d68..6e6b9f1da1 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 0000000000..9ca6106605
--- /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 0000000000..d9059ca6e9
--- /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 0000000000..13c0db96ac
--- /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 0000000000..dcd80d53ac
--- /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 71aaad19bd..97b7b5a317 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 0000000000..d00deda538
--- /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;
+}