Browse Source

Fix custom command target substitution with CROSSCOMPILING_EMULATOR

In commit v3.6.0-rc1~88^2 (CustomCommandGenerator: Add support for
CROSSCOMPILING_EMULATOR, 2016-05-04) logic was introduced to substitute
a target's `CROSSCOMPILING_EMULATOR` for argv0 in a custom command.
However, it broke the case when the argv0 was a target name and now
fails to expand the target name to its location at the same time as
inserting the emulator.  Fix the latter case.

Inspired-by: Brian Maher <[email protected]>
Closes: #16288
Brad King 9 years ago
parent
commit
e7480d670b

+ 32 - 13
Source/cmCustomCommandGenerator.cxx

@@ -38,32 +38,44 @@ unsigned int cmCustomCommandGenerator::GetNumberOfCommands() const
   return static_cast<unsigned int>(this->CC.GetCommandLines().size());
 }
 
-bool cmCustomCommandGenerator::UseCrossCompilingEmulator(unsigned int c) const
+const char* cmCustomCommandGenerator::GetCrossCompilingEmulator(
+  unsigned int c) const
 {
+  if (!this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING")) {
+    return CM_NULLPTR;
+  }
   std::string const& argv0 = this->CC.GetCommandLines()[c][0];
   cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
-  if (target && target->GetType() == cmStateEnums::EXECUTABLE) {
-    return target->GetProperty("CROSSCOMPILING_EMULATOR") != CM_NULLPTR;
+  if (target && target->GetType() == cmStateEnums::EXECUTABLE &&
+      !target->IsImported()) {
+    return target->GetProperty("CROSSCOMPILING_EMULATOR");
   }
-  return false;
+  return CM_NULLPTR;
 }
 
-std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const
+const char* cmCustomCommandGenerator::GetArgv0Location(unsigned int c) const
 {
   std::string const& argv0 = this->CC.GetCommandLines()[c][0];
   cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
   if (target && target->GetType() == cmStateEnums::EXECUTABLE &&
       (target->IsImported() ||
+       target->GetProperty("CROSSCOMPILING_EMULATOR") ||
        !this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING"))) {
     return target->GetLocation(this->Config);
   }
-  if (target && target->GetType() == cmStateEnums::EXECUTABLE) {
-    const char* emulator = target->GetProperty("CROSSCOMPILING_EMULATOR");
-    if (emulator) {
-      return std::string(emulator);
-    }
+  return CM_NULLPTR;
+}
+
+std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const
+{
+  if (const char* emulator = this->GetCrossCompilingEmulator(c)) {
+    return std::string(emulator);
+  }
+  if (const char* location = this->GetArgv0Location(c)) {
+    return std::string(location);
   }
 
+  std::string const& argv0 = this->CC.GetCommandLines()[c][0];
   CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = this->GE->Parse(argv0);
   std::string exe = cge->Evaluate(this->LG, this->Config);
 
@@ -99,13 +111,20 @@ void cmCustomCommandGenerator::AppendArguments(unsigned int c,
                                                std::string& cmd) const
 {
   unsigned int offset = 1;
-  if (this->UseCrossCompilingEmulator(c)) {
+  if (this->GetCrossCompilingEmulator(c) != CM_NULLPTR) {
     offset = 0;
   }
   cmCustomCommandLine const& commandLine = this->CC.GetCommandLines()[c];
   for (unsigned int j = offset; j < commandLine.size(); ++j) {
-    std::string arg =
-      this->GE->Parse(commandLine[j])->Evaluate(this->LG, this->Config);
+    std::string arg;
+    if (const char* location =
+          j == 0 ? this->GetArgv0Location(c) : CM_NULLPTR) {
+      // GetCommand returned the emulator instead of the argv0 location,
+      // so transform the latter now.
+      arg = location;
+    } else {
+      arg = this->GE->Parse(commandLine[j])->Evaluate(this->LG, this->Config);
+    }
     cmd += " ";
     if (this->OldStyle) {
       cmd += escapeForShellOldStyle(arg);

+ 3 - 1
Source/cmCustomCommandGenerator.h

@@ -23,6 +23,9 @@ class cmCustomCommandGenerator
   mutable bool DependsDone;
   mutable std::vector<std::string> Depends;
 
+  const char* GetCrossCompilingEmulator(unsigned int c) const;
+  const char* GetArgv0Location(unsigned int c) const;
+
 public:
   cmCustomCommandGenerator(cmCustomCommand const& cc,
                            const std::string& config, cmLocalGenerator* lg);
@@ -30,7 +33,6 @@ public:
   cmCustomCommand const& GetCC() const { return this->CC; }
   unsigned int GetNumberOfCommands() const;
   std::string GetCommand(unsigned int c) const;
-  bool UseCrossCompilingEmulator(unsigned int c) const;
   void AppendArguments(unsigned int c, std::string& cmd) const;
   const char* GetComment() const;
   std::string GetWorkingDirectory() const;

+ 2 - 1
Tests/RunCMake/pseudo_emulator_custom_command.c

@@ -14,7 +14,8 @@
 int main(int argc, const char* argv[])
 {
   const char* substring_failure = "generated_exe_emulator_unexpected";
-  const char* substring_success = "generated_exe_emulator_expected";
+  // 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* str = argv[1];
   if (argc < 2) {
     return EXIT_FAILURE;