فهرست منبع

Teach CROSSCOMPILING_EMULATOR to support arguments

Fixes: #19321
Marek Antoniak 6 سال پیش
والد
کامیت
fec441ec17

+ 4 - 0
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.

+ 6 - 0
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.

+ 4 - 0
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.
 

+ 45 - 12
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;

+ 3 - 1
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:

+ 3 - 1
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

+ 3 - 0
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()

+ 14 - 0
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
+)

+ 1 - 0
Tests/RunCMake/CrosscompilingEmulator/AddCustomTargetWithArg-build-check.cmake

@@ -0,0 +1 @@
+include(${CMAKE_CURRENT_LIST_DIR}/AddCustomCommandWithArg-build-check.cmake)

+ 9 - 0
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)

+ 7 - 2
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)

+ 30 - 0
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;
+}