浏览代码

Merge topic 'custom-command-generator-expressions'

4499d50 Mark CustomCommand test perconfig.out as SYMBOLIC
f0cdb60 Introduce "generator expression" syntax to custom commands (#11209)
4749e4c Record set of targets used in cmGeneratorExpression
ef9e9de Optionally suppress errors in cmGeneratorExpression
45e1953 Factor per-config sample targets out of 'Testing' test
4091bca Factor generator expression docs out of add_test
bfb7288 Record backtrace in cmCustomCommand
Brad King 15 年之前
父节点
当前提交
31b0657e7d

+ 1 - 0
Source/CMakeLists.txt

@@ -158,6 +158,7 @@ SET(SRCS
   cmDocumentationFormatterText.cxx
   cmDocumentationFormatterText.cxx
   cmDocumentationFormatterUsage.cxx
   cmDocumentationFormatterUsage.cxx
   cmDocumentationSection.cxx
   cmDocumentationSection.cxx
+  cmDocumentGeneratorExpressions.h
   cmDocumentVariables.cxx
   cmDocumentVariables.cxx
   cmDynamicLoader.cxx
   cmDynamicLoader.cxx
   cmDynamicLoader.h
   cmDynamicLoader.h

+ 10 - 2
Source/cmAddCustomCommandCommand.h

@@ -13,6 +13,7 @@
 #define cmAddCustomCommandCommand_h
 #define cmAddCustomCommandCommand_h
 
 
 #include "cmCommand.h"
 #include "cmCommand.h"
+#include "cmDocumentGeneratorExpressions.h"
 
 
 /** \class cmAddCustomCommandCommand
 /** \class cmAddCustomCommandCommand
  * \brief 
  * \brief 
@@ -146,8 +147,15 @@ public:
       "target-level dependency will be added so that the executable target "
       "target-level dependency will be added so that the executable target "
       "will be built before any target using this custom command.  However "
       "will be built before any target using this custom command.  However "
       "this does NOT add a file-level dependency that would cause the "
       "this does NOT add a file-level dependency that would cause the "
-      "custom command to re-run whenever the executable is recompiled.\n"
-
+      "custom command to re-run whenever the executable is recompiled."
+      "\n"
+      "Arguments to COMMAND may use \"generator expressions\" with the "
+      "syntax \"$<...>\".  "
+      CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
+      "References to target names in generator expressions imply "
+      "target-level dependencies, but NOT file-level dependencies.  "
+      "List target names with the DEPENDS option to add file dependencies."
+      "\n"
       "The DEPENDS option specifies files on which the command depends.  "
       "The DEPENDS option specifies files on which the command depends.  "
       "If any dependency is an OUTPUT of another custom command in the "
       "If any dependency is an OUTPUT of another custom command in the "
       "same directory (CMakeLists.txt file) CMake automatically brings the "
       "same directory (CMakeLists.txt file) CMake automatically brings the "

+ 2 - 13
Source/cmAddTestCommand.h

@@ -13,6 +13,7 @@
 #define cmAddTestCommand_h
 #define cmAddTestCommand_h
 
 
 #include "cmCommand.h"
 #include "cmCommand.h"
+#include "cmDocumentGeneratorExpressions.h"
 
 
 /** \class cmAddTestCommand
 /** \class cmAddTestCommand
  * \brief Add a test to the lists of tests to run.
  * \brief Add a test to the lists of tests to run.
@@ -77,19 +78,7 @@ public:
       "\n"
       "\n"
       "Arguments after COMMAND may use \"generator expressions\" with the "
       "Arguments after COMMAND may use \"generator expressions\" with the "
       "syntax \"$<...>\".  "
       "syntax \"$<...>\".  "
-      "These expressions are evaluted during build system generation and "
-      "produce information specific to each generated build configuration.  "
-      "Valid expressions are:\n"
-      "  $<CONFIGURATION>          = configuration name\n"
-      "  $<TARGET_FILE:tgt>        = main file (.exe, .so.1.2, .a)\n"
-      "  $<TARGET_LINKER_FILE:tgt> = file used to link (.a, .lib, .so)\n"
-      "  $<TARGET_SONAME_FILE:tgt> = file with soname (.so.3)\n"
-      "where \"tgt\" is the name of a target.  "
-      "Target file expressions produce a full path, but _DIR and _NAME "
-      "versions can produce the directory and file name components:\n"
-      "  $<TARGET_FILE_DIR:tgt>/$<TARGET_FILE_NAME:tgt>\n"
-      "  $<TARGET_LINKER_FILE_DIR:tgt>/$<TARGET_LINKER_FILE_NAME:tgt>\n"
-      "  $<TARGET_SONAME_FILE_DIR:tgt>/$<TARGET_SONAME_FILE_NAME:tgt>\n"
+      CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
       "Example usage:\n"
       "Example usage:\n"
       "  add_test(NAME mytest\n"
       "  add_test(NAME mytest\n"
       "           COMMAND testDriver --config $<CONFIGURATION>\n"
       "           COMMAND testDriver --config $<CONFIGURATION>\n"

+ 24 - 3
Source/cmCustomCommand.cxx

@@ -11,6 +11,8 @@
 ============================================================================*/
 ============================================================================*/
 #include "cmCustomCommand.h"
 #include "cmCustomCommand.h"
 
 
+#include "cmMakefile.h"
+
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 cmCustomCommand::cmCustomCommand()
 cmCustomCommand::cmCustomCommand()
 {
 {
@@ -28,12 +30,14 @@ cmCustomCommand::cmCustomCommand(const cmCustomCommand& r):
   Comment(r.Comment),
   Comment(r.Comment),
   WorkingDirectory(r.WorkingDirectory),
   WorkingDirectory(r.WorkingDirectory),
   EscapeAllowMakeVars(r.EscapeAllowMakeVars),
   EscapeAllowMakeVars(r.EscapeAllowMakeVars),
-  EscapeOldStyle(r.EscapeOldStyle)
+  EscapeOldStyle(r.EscapeOldStyle),
+  Backtrace(new cmListFileBacktrace(*r.Backtrace))
 {
 {
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
-cmCustomCommand::cmCustomCommand(const std::vector<std::string>& outputs,
+cmCustomCommand::cmCustomCommand(cmMakefile* mf,
+                                 const std::vector<std::string>& outputs,
                                  const std::vector<std::string>& depends,
                                  const std::vector<std::string>& depends,
                                  const cmCustomCommandLines& commandLines,
                                  const cmCustomCommandLines& commandLines,
                                  const char* comment,
                                  const char* comment,
@@ -45,10 +49,21 @@ cmCustomCommand::cmCustomCommand(const std::vector<std::string>& outputs,
   Comment(comment?comment:""),
   Comment(comment?comment:""),
   WorkingDirectory(workingDirectory?workingDirectory:""),
   WorkingDirectory(workingDirectory?workingDirectory:""),
   EscapeAllowMakeVars(false),
   EscapeAllowMakeVars(false),
-  EscapeOldStyle(true)
+  EscapeOldStyle(true),
+  Backtrace(new cmListFileBacktrace)
 {
 {
   this->EscapeOldStyle = true;
   this->EscapeOldStyle = true;
   this->EscapeAllowMakeVars = false;
   this->EscapeAllowMakeVars = false;
+  if(mf)
+    {
+    mf->GetBacktrace(*this->Backtrace);
+    }
+}
+
+//----------------------------------------------------------------------------
+cmCustomCommand::~cmCustomCommand()
+{
+  delete this->Backtrace;
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
@@ -130,6 +145,12 @@ void cmCustomCommand::SetEscapeAllowMakeVars(bool b)
   this->EscapeAllowMakeVars = b;
   this->EscapeAllowMakeVars = b;
 }
 }
 
 
+//----------------------------------------------------------------------------
+cmListFileBacktrace const& cmCustomCommand::GetBacktrace() const
+{
+  return *this->Backtrace;
+}
+
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 cmCustomCommand::ImplicitDependsList const&
 cmCustomCommand::ImplicitDependsList const&
 cmCustomCommand::GetImplicitDepends() const
 cmCustomCommand::GetImplicitDepends() const

+ 10 - 1
Source/cmCustomCommand.h

@@ -13,6 +13,8 @@
 #define cmCustomCommand_h
 #define cmCustomCommand_h
 
 
 #include "cmStandardIncludes.h"
 #include "cmStandardIncludes.h"
+class cmMakefile;
+class cmListFileBacktrace;
 
 
 /** \class cmCustomCommand
 /** \class cmCustomCommand
  * \brief A class to encapsulate a custom command
  * \brief A class to encapsulate a custom command
@@ -27,12 +29,15 @@ public:
   cmCustomCommand(const cmCustomCommand& r);
   cmCustomCommand(const cmCustomCommand& r);
 
 
   /** Main constructor specifies all information for the command.  */
   /** Main constructor specifies all information for the command.  */
-  cmCustomCommand(const std::vector<std::string>& outputs,
+  cmCustomCommand(cmMakefile* mf,
+                  const std::vector<std::string>& outputs,
                   const std::vector<std::string>& depends,
                   const std::vector<std::string>& depends,
                   const cmCustomCommandLines& commandLines,
                   const cmCustomCommandLines& commandLines,
                   const char* comment,
                   const char* comment,
                   const char* workingDirectory);
                   const char* workingDirectory);
 
 
+  ~cmCustomCommand();
+
   /** Get the output file produced by the command.  */
   /** Get the output file produced by the command.  */
   const std::vector<std::string>& GetOutputs() const;
   const std::vector<std::string>& GetOutputs() const;
 
 
@@ -63,6 +68,9 @@ public:
   bool GetEscapeAllowMakeVars() const;
   bool GetEscapeAllowMakeVars() const;
   void SetEscapeAllowMakeVars(bool b);
   void SetEscapeAllowMakeVars(bool b);
 
 
+  /** Backtrace of the command that created this custom command.  */
+  cmListFileBacktrace const& GetBacktrace() const;
+
   typedef std::pair<cmStdString, cmStdString> ImplicitDependsPair;
   typedef std::pair<cmStdString, cmStdString> ImplicitDependsPair;
   class ImplicitDependsList: public std::vector<ImplicitDependsPair> {};
   class ImplicitDependsList: public std::vector<ImplicitDependsPair> {};
   void SetImplicitDepends(ImplicitDependsList const&);
   void SetImplicitDepends(ImplicitDependsList const&);
@@ -78,6 +86,7 @@ private:
   std::string WorkingDirectory;
   std::string WorkingDirectory;
   bool EscapeAllowMakeVars;
   bool EscapeAllowMakeVars;
   bool EscapeOldStyle;
   bool EscapeOldStyle;
+  cmListFileBacktrace* Backtrace;
   ImplicitDependsList ImplicitDepends;
   ImplicitDependsList ImplicitDepends;
 };
 };
 
 

+ 11 - 3
Source/cmCustomCommandGenerator.cxx

@@ -14,15 +14,23 @@
 #include "cmMakefile.h"
 #include "cmMakefile.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommand.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalGenerator.h"
+#include "cmGeneratorExpression.h"
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 cmCustomCommandGenerator::cmCustomCommandGenerator(
 cmCustomCommandGenerator::cmCustomCommandGenerator(
   cmCustomCommand const& cc, const char* config, cmMakefile* mf):
   cmCustomCommand const& cc, const char* config, cmMakefile* mf):
   CC(cc), Config(config), Makefile(mf), LG(mf->GetLocalGenerator()),
   CC(cc), Config(config), Makefile(mf), LG(mf->GetLocalGenerator()),
-  OldStyle(cc.GetEscapeOldStyle()), MakeVars(cc.GetEscapeAllowMakeVars())
+  OldStyle(cc.GetEscapeOldStyle()), MakeVars(cc.GetEscapeAllowMakeVars()),
+  GE(new cmGeneratorExpression(mf, config, cc.GetBacktrace()))
 {
 {
 }
 }
 
 
+//----------------------------------------------------------------------------
+cmCustomCommandGenerator::~cmCustomCommandGenerator()
+{
+  delete this->GE;
+}
+
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 unsigned int cmCustomCommandGenerator::GetNumberOfCommands() const
 unsigned int cmCustomCommandGenerator::GetNumberOfCommands() const
 {
 {
@@ -39,7 +47,7 @@ std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const
     {
     {
     return target->GetLocation(this->Config);
     return target->GetLocation(this->Config);
     }
     }
-  return argv0;
+  return this->GE->Process(argv0);
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
@@ -50,7 +58,7 @@ cmCustomCommandGenerator
   cmCustomCommandLine const& commandLine = this->CC.GetCommandLines()[c];
   cmCustomCommandLine const& commandLine = this->CC.GetCommandLines()[c];
   for(unsigned int j=1;j < commandLine.size(); ++j)
   for(unsigned int j=1;j < commandLine.size(); ++j)
     {
     {
-    std::string const& arg = commandLine[j];
+    std::string arg = this->GE->Process(commandLine[j]);
     cmd += " ";
     cmd += " ";
     if(this->OldStyle)
     if(this->OldStyle)
       {
       {

+ 3 - 0
Source/cmCustomCommandGenerator.h

@@ -17,6 +17,7 @@
 class cmCustomCommand;
 class cmCustomCommand;
 class cmMakefile;
 class cmMakefile;
 class cmLocalGenerator;
 class cmLocalGenerator;
+class cmGeneratorExpression;
 
 
 class cmCustomCommandGenerator
 class cmCustomCommandGenerator
 {
 {
@@ -26,9 +27,11 @@ class cmCustomCommandGenerator
   cmLocalGenerator* LG;
   cmLocalGenerator* LG;
   bool OldStyle;
   bool OldStyle;
   bool MakeVars;
   bool MakeVars;
+  cmGeneratorExpression* GE;
 public:
 public:
   cmCustomCommandGenerator(cmCustomCommand const& cc, const char* config,
   cmCustomCommandGenerator(cmCustomCommand const& cc, const char* config,
                            cmMakefile* mf);
                            cmMakefile* mf);
+  ~cmCustomCommandGenerator();
   unsigned int GetNumberOfCommands() const;
   unsigned int GetNumberOfCommands() const;
   std::string GetCommand(unsigned int c) const;
   std::string GetCommand(unsigned int c) const;
   void AppendArguments(unsigned int c, std::string& cmd) const;
   void AppendArguments(unsigned int c, std::string& cmd) const;

+ 30 - 0
Source/cmDocumentGeneratorExpressions.h

@@ -0,0 +1,30 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2010 Kitware, Inc., Insight Software Consortium
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#ifndef cmDocumentGeneratorExpressions_h
+#define cmDocumentGeneratorExpressions_h
+
+#define CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS                       \
+  "Generator expressions are evaluted during build system generation "  \
+  "to produce information specific to each build configuration.  "      \
+  "Valid expressions are:\n"                                            \
+  "  $<CONFIGURATION>          = configuration name\n"                  \
+  "  $<TARGET_FILE:tgt>        = main file (.exe, .so.1.2, .a)\n"       \
+  "  $<TARGET_LINKER_FILE:tgt> = file used to link (.a, .lib, .so)\n"   \
+  "  $<TARGET_SONAME_FILE:tgt> = file with soname (.so.3)\n"            \
+  "where \"tgt\" is the name of a target.  "                            \
+  "Target file expressions produce a full path, but _DIR and _NAME "    \
+  "versions can produce the directory and file name components:\n"      \
+  "  $<TARGET_FILE_DIR:tgt>/$<TARGET_FILE_NAME:tgt>\n"                  \
+  "  $<TARGET_LINKER_FILE_DIR:tgt>/$<TARGET_LINKER_FILE_NAME:tgt>\n"    \
+  "  $<TARGET_SONAME_FILE_DIR:tgt>/$<TARGET_SONAME_FILE_NAME:tgt>\n"
+
+#endif

+ 5 - 3
Source/cmGeneratorExpression.cxx

@@ -17,8 +17,8 @@
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 cmGeneratorExpression::cmGeneratorExpression(
 cmGeneratorExpression::cmGeneratorExpression(
   cmMakefile* mf, const char* config,
   cmMakefile* mf, const char* config,
-  cmListFileBacktrace const& backtrace):
-  Makefile(mf), Config(config), Backtrace(backtrace)
+  cmListFileBacktrace const& backtrace, bool quiet):
+  Makefile(mf), Config(config), Backtrace(backtrace), Quiet(quiet)
 {
 {
   this->TargetInfo.compile("^\\$<TARGET"
   this->TargetInfo.compile("^\\$<TARGET"
                            "(|_SONAME|_LINKER)"  // File with what purpose?
                            "(|_SONAME|_LINKER)"  // File with what purpose?
@@ -87,7 +87,7 @@ bool cmGeneratorExpression::Evaluate()
     this->Data.insert(this->Data.end(), result.begin(), result.end());
     this->Data.insert(this->Data.end(), result.begin(), result.end());
     return true;
     return true;
     }
     }
-  else
+  else if(!this->Quiet)
     {
     {
     // Failure.  Report the error message.
     // Failure.  Report the error message.
     cmOStringStream e;
     cmOStringStream e;
@@ -99,6 +99,7 @@ bool cmGeneratorExpression::Evaluate()
                      this->Backtrace);
                      this->Backtrace);
     return false;
     return false;
     }
     }
+  return true;
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
@@ -140,6 +141,7 @@ bool cmGeneratorExpression::EvaluateTargetInfo(std::string& result)
     result = "Target \"" + name + "\" is not an executable or library.";
     result = "Target \"" + name + "\" is not an executable or library.";
     return false;
     return false;
     }
     }
+  this->Targets.insert(target);
 
 
   // Lookup the target file with the given purpose.
   // Lookup the target file with the given purpose.
   std::string purpose = this->TargetInfo.match(1);
   std::string purpose = this->TargetInfo.match(1);

+ 9 - 1
Source/cmGeneratorExpression.h

@@ -15,6 +15,7 @@
 
 
 #include <cmsys/RegularExpression.hxx>
 #include <cmsys/RegularExpression.hxx>
 
 
+class cmTarget;
 class cmMakefile;
 class cmMakefile;
 class cmListFileBacktrace;
 class cmListFileBacktrace;
 
 
@@ -32,18 +33,25 @@ class cmGeneratorExpression
 public:
 public:
   /** Construct with an evaluation context and configuration.  */
   /** Construct with an evaluation context and configuration.  */
   cmGeneratorExpression(cmMakefile* mf, const char* config,
   cmGeneratorExpression(cmMakefile* mf, const char* config,
-                        cmListFileBacktrace const& backtrace);
+                        cmListFileBacktrace const& backtrace,
+                        bool quiet = false);
 
 
   /** Evaluate generator expressions in a string.  */
   /** Evaluate generator expressions in a string.  */
   const char* Process(std::string const& input);
   const char* Process(std::string const& input);
   const char* Process(const char* input);
   const char* Process(const char* input);
+
+  /** Get set of targets found during evaluations.  */
+  std::set<cmTarget*> const& GetTargets() const
+    { return this->Targets; }
 private:
 private:
   cmMakefile* Makefile;
   cmMakefile* Makefile;
   const char* Config;
   const char* Config;
   cmListFileBacktrace const& Backtrace;
   cmListFileBacktrace const& Backtrace;
+  bool Quiet;
   std::vector<char> Data;
   std::vector<char> Data;
   std::stack<size_t> Barriers;
   std::stack<size_t> Barriers;
   cmsys::RegularExpression TargetInfo;
   cmsys::RegularExpression TargetInfo;
+  std::set<cmTarget*> Targets;
   bool Evaluate();
   bool Evaluate();
   bool Evaluate(const char* expr, std::string& result);
   bool Evaluate(const char* expr, std::string& result);
   bool EvaluateTargetInfo(std::string& result);
   bool EvaluateTargetInfo(std::string& result);

+ 1 - 1
Source/cmGlobalGenerator.cxx

@@ -1879,7 +1879,7 @@ cmTarget cmGlobalGenerator::CreateGlobalTarget(
   std::vector<std::string> no_outputs;
   std::vector<std::string> no_outputs;
   std::vector<std::string> no_depends;
   std::vector<std::string> no_depends;
   // Store the custom command in the target.
   // Store the custom command in the target.
-  cmCustomCommand cc(no_outputs, no_depends, *commandLines, 0,
+  cmCustomCommand cc(0, no_outputs, no_depends, *commandLines, 0,
                      workingDirectory);
                      workingDirectory);
   target.GetPostBuildCommands().push_back(cc);
   target.GetPostBuildCommands().push_back(cc);
   target.SetProperty("EchoString", message);
   target.SetProperty("EchoString", message);

+ 1 - 1
Source/cmLocalVisualStudio6Generator.cxx

@@ -838,7 +838,7 @@ cmLocalVisualStudio6Generator::MaybeCreateOutputDir(cmTarget& target,
   std::vector<std::string> no_depends;
   std::vector<std::string> no_depends;
   cmCustomCommandLines commands;
   cmCustomCommandLines commands;
   commands.push_back(command);
   commands.push_back(command);
-  pcc.reset(new cmCustomCommand(no_output, no_depends, commands, 0, 0));
+  pcc.reset(new cmCustomCommand(0, no_output, no_depends, commands, 0, 0));
   pcc->SetEscapeOldStyle(false);
   pcc->SetEscapeOldStyle(false);
   pcc->SetEscapeAllowMakeVars(true);
   pcc->SetEscapeAllowMakeVars(true);
   return pcc;
   return pcc;

+ 1 - 1
Source/cmLocalVisualStudioGenerator.cxx

@@ -53,7 +53,7 @@ cmLocalVisualStudioGenerator::MaybeCreateImplibDir(cmTarget& target,
   std::vector<std::string> no_depends;
   std::vector<std::string> no_depends;
   cmCustomCommandLines commands;
   cmCustomCommandLines commands;
   commands.push_back(command);
   commands.push_back(command);
-  pcc.reset(new cmCustomCommand(no_output, no_depends, commands, 0, 0));
+  pcc.reset(new cmCustomCommand(0, no_output, no_depends, commands, 0, 0));
   pcc->SetEscapeOldStyle(false);
   pcc->SetEscapeOldStyle(false);
   pcc->SetEscapeAllowMakeVars(true);
   pcc->SetEscapeAllowMakeVars(true);
   return pcc;
   return pcc;

+ 3 - 2
Source/cmMakefile.cxx

@@ -827,7 +827,8 @@ cmMakefile::AddCustomCommandToTarget(const char* target,
     {
     {
     // Add the command to the appropriate build step for the target.
     // Add the command to the appropriate build step for the target.
     std::vector<std::string> no_output;
     std::vector<std::string> no_output;
-    cmCustomCommand cc(no_output, depends, commandLines, comment, workingDir);
+    cmCustomCommand cc(this, no_output, depends,
+                       commandLines, comment, workingDir);
     cc.SetEscapeOldStyle(escapeOldStyle);
     cc.SetEscapeOldStyle(escapeOldStyle);
     cc.SetEscapeAllowMakeVars(true);
     cc.SetEscapeAllowMakeVars(true);
     switch(type)
     switch(type)
@@ -947,7 +948,7 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs,
   if(file)
   if(file)
     {
     {
     cmCustomCommand* cc =
     cmCustomCommand* cc =
-      new cmCustomCommand(outputs, depends2, commandLines,
+      new cmCustomCommand(this, outputs, depends2, commandLines,
                           comment, workingDir);
                           comment, workingDir);
     cc->SetEscapeOldStyle(escapeOldStyle);
     cc->SetEscapeOldStyle(escapeOldStyle);
     cc->SetEscapeAllowMakeVars(true);
     cc->SetEscapeAllowMakeVars(true);

+ 17 - 0
Source/cmTarget.cxx

@@ -17,6 +17,7 @@
 #include "cmGlobalGenerator.h"
 #include "cmGlobalGenerator.h"
 #include "cmComputeLinkInformation.h"
 #include "cmComputeLinkInformation.h"
 #include "cmListFileCache.h"
 #include "cmListFileCache.h"
+#include "cmGeneratorExpression.h"
 #include <cmsys/RegularExpression.hxx>
 #include <cmsys/RegularExpression.hxx>
 #include <map>
 #include <map>
 #include <set>
 #include <set>
@@ -1402,6 +1403,7 @@ cmTargetTraceDependencies
 {
 {
   // Transform command names that reference targets built in this
   // Transform command names that reference targets built in this
   // project to corresponding target-level dependencies.
   // project to corresponding target-level dependencies.
+  cmGeneratorExpression ge(this->Makefile, 0, cc.GetBacktrace(), true);
   for(cmCustomCommandLines::const_iterator cit = cc.GetCommandLines().begin();
   for(cmCustomCommandLines::const_iterator cit = cc.GetCommandLines().begin();
       cit != cc.GetCommandLines().end(); ++cit)
       cit != cc.GetCommandLines().end(); ++cit)
     {
     {
@@ -1418,6 +1420,21 @@ cmTargetTraceDependencies
         this->Target->AddUtility(command.c_str());
         this->Target->AddUtility(command.c_str());
         }
         }
       }
       }
+
+    // Check for target references in generator expressions.
+    for(cmCustomCommandLine::const_iterator cli = cit->begin();
+        cli != cit->end(); ++cli)
+      {
+      ge.Process(*cli);
+      }
+    }
+
+  // Add target-level dependencies referenced by generator expressions.
+  std::set<cmTarget*> targets = ge.GetTargets();
+  for(std::set<cmTarget*>::iterator ti = targets.begin();
+      ti != targets.end(); ++ti)
+    {
+    this->Target->AddUtility((*ti)->GetName());
     }
     }
 
 
   // Queue the custom command dependencies.
   // Queue the custom command dependencies.

+ 13 - 0
Tests/CustomCommand/CMakeLists.txt

@@ -423,3 +423,16 @@ ADD_CUSTOM_TARGET(DifferentName ALL
   )
   )
 #
 #
 # </SameNameTest>
 # </SameNameTest>
+
+# Per-config target name and generator expressions.
+ADD_SUBDIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../PerConfig PerConfig)
+ADD_CUSTOM_COMMAND(
+  OUTPUT perconfig.out
+  COMMAND ${PerConfig_COMMAND}
+  DEPENDS ${PerConfig_DEPENDS}
+  VERBATIM
+  )
+SET_PROPERTY(SOURCE perconfig.out PROPERTY SYMBOLIC 1)
+ADD_CUSTOM_TARGET(perconfig_target ALL
+  COMMAND ${CMAKE_COMMAND} -E echo "perconfig=$<TARGET_FILE:perconfig>" "config=$<CONFIGURATION>"
+  DEPENDS perconfig.out)

+ 34 - 0
Tests/PerConfig/CMakeLists.txt

@@ -0,0 +1,34 @@
+project(PerConfig C)
+
+# Targets with per-configuration names.
+ADD_LIBRARY(pcStatic STATIC pcStatic.c)
+SET_PROPERTY(TARGET pcStatic PROPERTY RELEASE_POSTFIX -opt)
+SET_PROPERTY(TARGET pcStatic PROPERTY DEBUG_POSTFIX -dbg)
+ADD_LIBRARY(pcShared SHARED pcShared.c)
+SET_PROPERTY(TARGET pcShared PROPERTY RELEASE_POSTFIX -opt)
+SET_PROPERTY(TARGET pcShared PROPERTY DEBUG_POSTFIX -dbg)
+SET_PROPERTY(TARGET pcShared PROPERTY VERSION 1.2)
+SET_PROPERTY(TARGET pcShared PROPERTY SOVERSION 3)
+IF(NOT WIN32)
+  SET(soname_file -DpcShared_soname_file=$<TARGET_SONAME_FILE:pcShared>)
+ENDIF()
+ADD_EXECUTABLE(perconfig perconfig.c)
+TARGET_LINK_LIBRARIES(perconfig pcStatic pcShared)
+SET_PROPERTY(TARGET perconfig PROPERTY RELEASE_POSTFIX -opt)
+SET_PROPERTY(TARGET perconfig PROPERTY DEBUG_POSTFIX -dbg)
+
+SET(PerConfig_COMMAND
+  ${CMAKE_COMMAND}
+    -Dconfiguration=$<CONFIGURATION>
+    -Dperconfig_file_dir=$<TARGET_FILE_DIR:perconfig>
+    -Dperconfig_file_name=$<TARGET_FILE_NAME:perconfig>
+    -Dperconfig_file=$<TARGET_FILE:perconfig>
+    -DpcStatic_file=$<TARGET_FILE:pcStatic>
+    -DpcStatic_linker_file=$<TARGET_LINKER_FILE:pcStatic>
+    -DpcShared_file=$<TARGET_FILE:pcShared>
+    -DpcShared_linker_file=$<TARGET_LINKER_FILE:pcShared>
+    ${soname_file}
+    -P ${PerConfig_SOURCE_DIR}/perconfig.cmake
+    )
+SET(PerConfig_COMMAND "${PerConfig_COMMAND}" PARENT_SCOPE)
+SET(PerConfig_DEPENDS ${PerConfig_SOURCE_DIR}/perconfig.cmake perconfig pcStatic pcShared)

+ 0 - 0
Tests/Testing/pcShared.c → Tests/PerConfig/pcShared.c


+ 0 - 0
Tests/Testing/pcShared.h → Tests/PerConfig/pcShared.h


+ 0 - 0
Tests/Testing/pcStatic.c → Tests/PerConfig/pcStatic.c


+ 0 - 0
Tests/Testing/perconfig.c → Tests/PerConfig/perconfig.c


+ 1 - 1
Tests/Testing/driver.cmake → Tests/PerConfig/perconfig.cmake

@@ -10,7 +10,7 @@ foreach(v
     pcShared_linker_file
     pcShared_linker_file
     pcShared_soname_file
     pcShared_soname_file
     )
     )
-  message("${v}=${${v}}")
+  message(STATUS "${v}=${${v}}")
 endforeach()
 endforeach()
 
 
 # Verify that file names match as expected.
 # Verify that file names match as expected.

+ 3 - 31
Tests/Testing/CMakeLists.txt

@@ -53,35 +53,7 @@ ADD_TEST(testing.1 ${Testing_BINARY_DIR}/bin/testing)
 #
 #
 ADD_SUBDIRECTORY(Sub/Sub2)
 ADD_SUBDIRECTORY(Sub/Sub2)
 
 
-# Per-config target name test.
-ADD_LIBRARY(pcStatic STATIC pcStatic.c)
-SET_PROPERTY(TARGET pcStatic PROPERTY RELEASE_POSTFIX -opt)
-SET_PROPERTY(TARGET pcStatic PROPERTY DEBUG_POSTFIX -dbg)
-ADD_LIBRARY(pcShared SHARED pcShared.c)
-SET_PROPERTY(TARGET pcShared PROPERTY RELEASE_POSTFIX -opt)
-SET_PROPERTY(TARGET pcShared PROPERTY DEBUG_POSTFIX -dbg)
-SET_PROPERTY(TARGET pcShared PROPERTY VERSION 1.2)
-SET_PROPERTY(TARGET pcShared PROPERTY SOVERSION 3)
-IF(NOT WIN32)
-  SET(soname_file -DpcShared_soname_file=$<TARGET_SONAME_FILE:pcShared>)
-ENDIF()
-ADD_EXECUTABLE(perconfig perconfig.c)
-TARGET_LINK_LIBRARIES(perconfig pcStatic pcShared)
-SET_PROPERTY(TARGET perconfig PROPERTY RELEASE_POSTFIX -opt)
-SET_PROPERTY(TARGET perconfig PROPERTY DEBUG_POSTFIX -dbg)
+# Per-config target name and generator expressions.
+ADD_SUBDIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../PerConfig PerConfig)
 ADD_TEST(NAME testing.perconfig COMMAND perconfig)
 ADD_TEST(NAME testing.perconfig COMMAND perconfig)
-
-# Test using a driver script with generator expressions.
-ADD_TEST(NAME testing.driver
-  COMMAND ${CMAKE_COMMAND}
-    -Dconfiguration=$<CONFIGURATION>
-    -Dperconfig_file_dir=$<TARGET_FILE_DIR:perconfig>
-    -Dperconfig_file_name=$<TARGET_FILE_NAME:perconfig>
-    -Dperconfig_file=$<TARGET_FILE:perconfig>
-    -DpcStatic_file=$<TARGET_FILE:pcStatic>
-    -DpcStatic_linker_file=$<TARGET_LINKER_FILE:pcStatic>
-    -DpcShared_file=$<TARGET_FILE:pcShared>
-    -DpcShared_linker_file=$<TARGET_LINKER_FILE:pcShared>
-    ${soname_file}
-    -P ${Testing_SOURCE_DIR}/driver.cmake
-  )
+ADD_TEST(NAME testing.driver COMMAND ${PerConfig_COMMAND})