From 6c0b7f0f6007c081e95f2415501c5246cd9ea10a Mon Sep 17 00:00:00 2001
From: Robert Goulet <robert.goulet@autodesk.com>
Date: Mon, 15 Jun 2015 15:00:55 -0400
Subject: [PATCH] Add generator expressions support to target properties
 OUTPUT_NAME and RUNTIME_OUTPUT_DIRECTORY, and to the DESTINATION property of
 the install command.

---
 Help/command/install.rst                          |  4 +++
 Help/prop_tgt/OUTPUT_NAME.rst                     |  5 +++
 Help/prop_tgt/OUTPUT_NAME_CONFIG.rst              |  5 +++
 Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.rst        |  5 +++
 Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst |  6 ++++
 Source/cmInstallCommand.cxx                       | 30 +++++++++---------
 Source/cmInstallDirectoryGenerator.cxx            |  7 +++--
 Source/cmInstallDirectoryGenerator.h              |  3 +-
 Source/cmInstallExportGenerator.cxx               | 17 +++++------
 Source/cmInstallExportGenerator.h                 |  4 ---
 Source/cmInstallFilesGenerator.cxx                |  5 ++-
 Source/cmInstallFilesGenerator.h                  |  1 -
 Source/cmInstallGenerator.cxx                     | 25 ++++++++++++++-
 Source/cmInstallGenerator.h                       | 10 ++++--
 Source/cmInstallScriptGenerator.cxx               |  5 +--
 Source/cmInstallScriptGenerator.h                 |  2 +-
 Source/cmInstallTargetGenerator.cxx               | 13 ++------
 Source/cmInstallTargetGenerator.h                 |  4 +--
 Source/cmLocalGenerator.cxx                       |  6 ++--
 Source/cmScriptGenerator.cxx                      |  2 ++
 Source/cmTarget.cxx                               | 37 ++++++++++++++++-------
 Tests/ExportImport/Export/CMakeLists.txt          | 22 ++++++++++++--
 Tests/ExportImport/Export/testExe4.c              | 24 +++++++++++++++
 Tests/ExportImport/Export/testLib7.c              |  1 +
 Tests/ExportImport/Import/A/CMakeLists.txt        | 14 +++++++++
 Tests/ExportImport/Import/A/imp_testExe1.c        |  6 ++--
 26 files changed, 188 insertions(+), 75 deletions(-)
 create mode 100644 Tests/ExportImport/Export/testExe4.c
 create mode 100644 Tests/ExportImport/Export/testLib7.c

diff --git a/Help/command/install.rst b/Help/command/install.rst
index c99ed73..9c17bba 100644
--- a/Help/command/install.rst
+++ b/Help/command/install.rst
@@ -192,6 +192,10 @@ The list of ``files...`` given to ``FILES`` or ``PROGRAMS`` may use
 However, if any item begins in a generator expression it must evaluate
 to a full path.
 
+The install destination given to the files install ``DESTINATION`` may
+use "generator expressions" with the syntax ``$<...>``.  See the
+:manual:`cmake-generator-expressions(7)` manual for available expressions.
+
 Installing Directories
 ^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/Help/prop_tgt/OUTPUT_NAME.rst b/Help/prop_tgt/OUTPUT_NAME.rst
index 97bf010..6427064 100644
--- a/Help/prop_tgt/OUTPUT_NAME.rst
+++ b/Help/prop_tgt/OUTPUT_NAME.rst
@@ -6,3 +6,8 @@ Output name for target files.
 This sets the base name for output files created for an executable or
 library target.  If not set, the logical target name is used by
 default.
+
+Contents of ``OUTPUT_NAME`` may use "generator expressions" with
+the syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
diff --git a/Help/prop_tgt/OUTPUT_NAME_CONFIG.rst b/Help/prop_tgt/OUTPUT_NAME_CONFIG.rst
index 7bfbcbc..1eeb3dc 100644
--- a/Help/prop_tgt/OUTPUT_NAME_CONFIG.rst
+++ b/Help/prop_tgt/OUTPUT_NAME_CONFIG.rst
@@ -4,3 +4,8 @@ OUTPUT_NAME_<CONFIG>
 Per-configuration target file base name.
 
 This is the configuration-specific version of OUTPUT_NAME.
+
+Contents of ``OUTPUT_NAME_<CONFIG>`` may use "generator expressions" with
+the syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
diff --git a/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.rst b/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.rst
index 12390f5..906dcf6 100644
--- a/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.rst
+++ b/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.rst
@@ -7,3 +7,8 @@ RUNTIME_OUTPUT_DIRECTORY
 .. include:: XXX_OUTPUT_DIRECTORY.txt
 
 See also the :prop_tgt:`RUNTIME_OUTPUT_DIRECTORY_<CONFIG>` target property.
+
+Contents of ``RUNTIME_OUTPUT_DIRECTORY`` may use "generator expressions" with
+the syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
diff --git a/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst
index c100346..0784d24 100644
--- a/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst
+++ b/Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst
@@ -11,3 +11,9 @@ per-configuration subdirectory to the specified directory.  This
 property is initialized by the value of the
 :variable:`CMAKE_RUNTIME_OUTPUT_DIRECTORY_<CONFIG>` variable if
 it is set when a target is created.
+
+Contents of ``RUNTIME_OUTPUT_DIRECTORY_<CONFIG>`` may use "generator
+expressions" with the syntax ``$<...>``.  See the :manual:
+`cmake-generator-expressions(7)` manual for available expressions.  See the
+:manual:`cmake-buildsystem(7)` manual for more on defining buildsystem
+properties.
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 899b088..1ff159a 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -22,12 +22,12 @@
 
 #include <cmsys/Glob.hxx>
 
-static cmInstallTargetGenerator* CreateInstallTargetGenerator(cmTarget& target,
+static cmInstallTargetGenerator* CreateInstallTargetGenerator(cmMakefile* mf, cmTarget& target,
      const cmInstallCommandArguments& args, bool impLib, bool forceOpt = false)
 {
   cmInstallGenerator::MessageLevel message =
     cmInstallGenerator::SelectMessageLevel(target.GetMakefile());
-  return new cmInstallTargetGenerator(target, args.GetDestination().c_str(),
+  return new cmInstallTargetGenerator(mf, target, args.GetDestination().c_str(),
                         impLib, args.GetPermissions().c_str(),
                         args.GetConfigurations(), args.GetComponent().c_str(),
                         message,
@@ -172,7 +172,7 @@ bool cmInstallCommand::HandleScriptMode(std::vector<std::string> const& args)
         return false;
         }
       this->Makefile->AddInstallGenerator(
-        new cmInstallScriptGenerator(script.c_str(), false,
+        new cmInstallScriptGenerator(this->GetMakefile(), script.c_str(), false,
                                      component.c_str()));
       }
     else if(doing_code)
@@ -180,7 +180,7 @@ bool cmInstallCommand::HandleScriptMode(std::vector<std::string> const& args)
       doing_code = false;
       std::string code = args[i];
       this->Makefile->AddInstallGenerator(
-        new cmInstallScriptGenerator(code.c_str(), true,
+        new cmInstallScriptGenerator(this->GetMakefile(), code.c_str(), true,
                                      component.c_str()));
       }
     }
@@ -465,13 +465,13 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
           if(!archiveArgs.GetDestination().empty())
             {
             // The import library uses the ARCHIVE properties.
-            archiveGenerator = CreateInstallTargetGenerator(target,
+            archiveGenerator = CreateInstallTargetGenerator(this->GetMakefile(), target,
                                                             archiveArgs, true);
             }
           if(!runtimeArgs.GetDestination().empty())
             {
             // The DLL uses the RUNTIME properties.
-            runtimeGenerator = CreateInstallTargetGenerator(target,
+            runtimeGenerator = CreateInstallTargetGenerator(this->GetMakefile(), target,
                                                            runtimeArgs, false);
             }
           if ((archiveGenerator==0) && (runtimeGenerator==0))
@@ -496,7 +496,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
             // Use the FRAMEWORK properties.
             if (!frameworkArgs.GetDestination().empty())
               {
-              frameworkGenerator = CreateInstallTargetGenerator(target,
+              frameworkGenerator = CreateInstallTargetGenerator(this->GetMakefile(), target,
                                                          frameworkArgs, false);
               }
             else
@@ -513,7 +513,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
             // The shared library uses the LIBRARY properties.
             if (!libraryArgs.GetDestination().empty())
               {
-              libraryGenerator = CreateInstallTargetGenerator(target,
+              libraryGenerator = CreateInstallTargetGenerator(this->GetMakefile(), target,
                                                            libraryArgs, false);
               libraryGenerator->SetNamelinkMode(namelinkMode);
               namelinkOnly =
@@ -536,7 +536,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
         // Static libraries use ARCHIVE properties.
         if (!archiveArgs.GetDestination().empty())
           {
-          archiveGenerator = CreateInstallTargetGenerator(target, archiveArgs,
+          archiveGenerator = CreateInstallTargetGenerator(this->GetMakefile(), target, archiveArgs,
                                                           false);
           }
         else
@@ -554,7 +554,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
         // Modules use LIBRARY properties.
         if (!libraryArgs.GetDestination().empty())
           {
-          libraryGenerator = CreateInstallTargetGenerator(target, libraryArgs,
+          libraryGenerator = CreateInstallTargetGenerator(this->GetMakefile(), target, libraryArgs,
                                                           false);
           libraryGenerator->SetNamelinkMode(namelinkMode);
           namelinkOnly =
@@ -577,7 +577,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
           // Application bundles use the BUNDLE properties.
           if (!bundleArgs.GetDestination().empty())
             {
-            bundleGenerator = CreateInstallTargetGenerator(target, bundleArgs,
+            bundleGenerator = CreateInstallTargetGenerator(this->GetMakefile(), target, bundleArgs,
                                                            false);
             }
           else if(!runtimeArgs.GetDestination().empty())
@@ -588,7 +588,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
               // For CMake 2.4 compatibility fallback to the RUNTIME
               // properties.
               bundleGenerator =
-                CreateInstallTargetGenerator(target, runtimeArgs, false);
+                CreateInstallTargetGenerator(this->GetMakefile(), target, runtimeArgs, false);
               }
             else if(failure)
               {
@@ -609,7 +609,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
           // Executables use the RUNTIME properties.
           if (!runtimeArgs.GetDestination().empty())
             {
-            runtimeGenerator = CreateInstallTargetGenerator(target,
+            runtimeGenerator = CreateInstallTargetGenerator(this->GetMakefile(), target,
                                                            runtimeArgs, false);
             }
           else
@@ -629,7 +629,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
            target.IsExecutableWithExports())
           {
           // The import library uses the ARCHIVE properties.
-          archiveGenerator = CreateInstallTargetGenerator(target,
+          archiveGenerator = CreateInstallTargetGenerator(this->GetMakefile(), target,
                                                       archiveArgs, true, true);
           }
         }
@@ -1265,7 +1265,7 @@ cmInstallCommand::HandleDirectoryMode(std::vector<std::string> const& args)
 
   // Create the directory install generator.
   this->Makefile->AddInstallGenerator(
-    new cmInstallDirectoryGenerator(dirs, destination,
+    new cmInstallDirectoryGenerator(this->GetMakefile(), dirs, destination,
                                     permissions_file.c_str(),
                                     permissions_dir.c_str(),
                                     configurations,
diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx
index 7593380..a604e0b 100644
--- a/Source/cmInstallDirectoryGenerator.cxx
+++ b/Source/cmInstallDirectoryGenerator.cxx
@@ -15,7 +15,8 @@
 
 //----------------------------------------------------------------------------
 cmInstallDirectoryGenerator
-::cmInstallDirectoryGenerator(std::vector<std::string> const& dirs,
+::cmInstallDirectoryGenerator(cmMakefile* mf,
+                              std::vector<std::string> const& dirs,
                               const char* dest,
                               const char* file_permissions,
                               const char* dir_permissions,
@@ -24,7 +25,7 @@ cmInstallDirectoryGenerator
                               MessageLevel message,
                               const char* literal_args,
                               bool optional):
-  cmInstallGenerator(dest, configurations, component, message),
+  cmInstallGenerator(mf, dest, configurations, component, message),
   Directories(dirs),
   FilePermissions(file_permissions), DirPermissions(dir_permissions),
   LiteralArguments(literal_args), Optional(optional)
@@ -45,7 +46,7 @@ cmInstallDirectoryGenerator::GenerateScriptActions(std::ostream& os,
   // Write code to install the directories.
   const char* no_rename = 0;
   this->AddInstallRule(os,
-                       this->Destination,
+                       this->GetDestination(),
                        cmInstallType_DIRECTORY,
                        this->Directories,
                        this->Optional,
diff --git a/Source/cmInstallDirectoryGenerator.h b/Source/cmInstallDirectoryGenerator.h
index 165ab91..d3b3def 100644
--- a/Source/cmInstallDirectoryGenerator.h
+++ b/Source/cmInstallDirectoryGenerator.h
@@ -20,7 +20,8 @@
 class cmInstallDirectoryGenerator: public cmInstallGenerator
 {
 public:
-  cmInstallDirectoryGenerator(std::vector<std::string> const& dirs,
+  cmInstallDirectoryGenerator(cmMakefile* mf,
+                              std::vector<std::string> const& dirs,
                               const char* dest,
                               const char* file_permissions,
                               const char* dir_permissions,
diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx
index 7f6aa4d..8a33a65 100644
--- a/Source/cmInstallExportGenerator.cxx
+++ b/Source/cmInstallExportGenerator.cxx
@@ -36,13 +36,12 @@ cmInstallExportGenerator::cmInstallExportGenerator(
   const char* filename, const char* name_space,
   bool exportOld,
   cmMakefile* mf)
-  :cmInstallGenerator(destination, configurations, component, message)
+  :cmInstallGenerator(mf, destination, configurations, component, message)
   ,ExportSet(exportSet)
   ,FilePermissions(file_permissions)
   ,FileName(filename)
   ,Namespace(name_space)
   ,ExportOld(exportOld)
-  ,Makefile(mf)
 {
   this->EFGen = new cmExportInstallFileGenerator(this);
   exportSet->AddInstallation(this);
@@ -62,7 +61,7 @@ void cmInstallExportGenerator::ComputeTempDir()
   this->TempDir = this->Makefile->GetCurrentBinaryDirectory();
   this->TempDir += cmake::GetCMakeFilesDirectory();
   this->TempDir += "/Export";
-  if(this->Destination.empty())
+  if(this->GetDestination().empty())
     {
     return;
     }
@@ -82,7 +81,7 @@ void cmInstallExportGenerator::ComputeTempDir()
     {
     // Keep the total path length below the limit.
     std::string::size_type max_len = max_total_len - this->TempDir.size();
-    if(this->Destination.size() > max_len)
+    if(this->GetDestination().size() > max_len)
       {
       useMD5 = true;
       }
@@ -95,11 +94,11 @@ void cmInstallExportGenerator::ComputeTempDir()
     {
     // Replace the destination path with a hash to keep it short.
     this->TempDir +=
-      cmSystemTools::ComputeStringMD5(this->Destination);
+      cmSystemTools::ComputeStringMD5(this->GetDestination());
     }
   else
     {
-    std::string dest = this->Destination;
+    std::string dest = this->GetDestination();
     // Avoid unix full paths.
     if(dest[0] == '/')
       {
@@ -185,7 +184,7 @@ cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os,
     files.push_back(i->second);
     std::string config_test = this->CreateConfigTest(i->first);
     os << indent << "if(" << config_test << ")\n";
-    this->AddInstallRule(os, this->Destination,
+    this->AddInstallRule(os, this->GetDestination(),
                          cmInstallType_FILES, files, false,
                          this->FilePermissions.c_str(), 0, 0, 0,
                          indent.Next());
@@ -200,7 +199,7 @@ void cmInstallExportGenerator::GenerateScriptActions(std::ostream& os,
 {
   // Remove old per-configuration export files if the main changes.
   std::string installedDir = "$ENV{DESTDIR}";
-  installedDir += this->ConvertToAbsoluteDestination(this->Destination);
+  installedDir += this->ConvertToAbsoluteDestination(this->GetDestination());
   installedDir += "/";
   std::string installedFile = installedDir;
   installedFile += this->FileName;
@@ -225,7 +224,7 @@ void cmInstallExportGenerator::GenerateScriptActions(std::ostream& os,
   // Install the main export file.
   std::vector<std::string> files;
   files.push_back(this->MainImportFile);
-  this->AddInstallRule(os, this->Destination,
+  this->AddInstallRule(os, this->GetDestination(),
                        cmInstallType_FILES, files, false,
                        this->FilePermissions.c_str(), 0, 0, 0, indent);
 }
diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h
index 3e078f2..5d0e288 100644
--- a/Source/cmInstallExportGenerator.h
+++ b/Source/cmInstallExportGenerator.h
@@ -41,9 +41,6 @@ public:
 
   const std::string& GetNamespace() const { return this->Namespace; }
 
-  std::string const& GetDestination() const
-    { return this->Destination; }
-
 protected:
   virtual void GenerateScript(std::ostream& os);
   virtual void GenerateScriptConfigs(std::ostream& os, Indent const& indent);
@@ -57,7 +54,6 @@ protected:
   std::string FileName;
   std::string Namespace;
   bool ExportOld;
-  cmMakefile* Makefile;
 
   std::string TempDir;
   std::string MainImportFile;
diff --git a/Source/cmInstallFilesGenerator.cxx b/Source/cmInstallFilesGenerator.cxx
index ff2c6e5..b1e201a 100644
--- a/Source/cmInstallFilesGenerator.cxx
+++ b/Source/cmInstallFilesGenerator.cxx
@@ -26,8 +26,7 @@ cmInstallFilesGenerator
                           MessageLevel message,
                           const char* rename,
                           bool optional):
-  cmInstallGenerator(dest, configurations, component, message),
-  Makefile(mf),
+  cmInstallGenerator(mf, dest, configurations, component, message),
   Files(files),
   FilePermissions(file_permissions),
   Rename(rename),
@@ -59,7 +58,7 @@ void cmInstallFilesGenerator::AddFilesInstallRule(
   // Write code to install the files.
   const char* no_dir_permissions = 0;
   this->AddInstallRule(os,
-                       this->Destination,
+                       this->GetDestination(),
                        (this->Programs
                         ? cmInstallType_PROGRAMS
                         : cmInstallType_FILES),
diff --git a/Source/cmInstallFilesGenerator.h b/Source/cmInstallFilesGenerator.h
index bf482d6..91d563e 100644
--- a/Source/cmInstallFilesGenerator.h
+++ b/Source/cmInstallFilesGenerator.h
@@ -41,7 +41,6 @@ protected:
   void AddFilesInstallRule(std::ostream& os, Indent const& indent,
                            std::vector<std::string> const& files);
 
-  cmMakefile* Makefile;
   std::vector<std::string> Files;
   std::string FilePermissions;
   std::string Rename;
diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx
index 2e1c5f0..2e8e744 100644
--- a/Source/cmInstallGenerator.cxx
+++ b/Source/cmInstallGenerator.cxx
@@ -16,15 +16,22 @@
 
 //----------------------------------------------------------------------------
 cmInstallGenerator
-::cmInstallGenerator(const char* destination,
+::cmInstallGenerator(cmMakefile* mf,
+                     const char* destination,
                      std::vector<std::string> const& configurations,
                      const char* component,
                      MessageLevel message):
   cmScriptGenerator("CMAKE_INSTALL_CONFIG_NAME", configurations),
+  Makefile(mf),
   Destination(destination? destination:""),
   Component(component? component:""),
   Message(message)
 {
+  // We need per-config actions if destination have generator expressions.
+  if(cmGeneratorExpression::Find(Destination) != std::string::npos)
+    {
+    this->ActionsPerConfig = true;
+    }
 }
 
 //----------------------------------------------------------------------------
@@ -180,6 +187,22 @@ bool cmInstallGenerator::InstallsForConfig(const std::string& config)
 }
 
 //----------------------------------------------------------------------------
+std::string cmInstallGenerator::GetDestination() const
+{
+  return GetDestination(this->ConfigurationName);
+}
+
+std::string cmInstallGenerator::GetDestination(std::string const& config) const
+{
+  if(!config.empty())
+    {
+    cmGeneratorExpression ge;
+    cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(Destination);
+    return cge->Evaluate(this->Makefile, config);  
+    }
+  return Destination;
+}
+
 std::string
 cmInstallGenerator::ConvertToAbsoluteDestination(std::string const& dest) const
 {
diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h
index c4191e4..c493d63 100644
--- a/Source/cmInstallGenerator.h
+++ b/Source/cmInstallGenerator.h
@@ -33,7 +33,8 @@ public:
     MessageNever
   };
 
-  cmInstallGenerator(const char* destination,
+  cmInstallGenerator(cmMakefile* mf,
+                     const char* destination,
                      std::vector<std::string> const& configurations,
                      const char* component,
                      MessageLevel message);
@@ -54,6 +55,8 @@ public:
 
   /** Get the install destination as it should appear in the
       installation script.  */
+  std::string GetDestination() const;
+  std::string GetDestination(std::string const& config) const;
   std::string ConvertToAbsoluteDestination(std::string const& dest) const;
 
   /** Test if this generator installs something for a given configuration.  */
@@ -68,9 +71,12 @@ protected:
   std::string CreateComponentTest(const char* component);
 
   // Information shared by most generator types.
-  std::string Destination;
+  cmMakefile* Makefile;
   std::string Component;
   MessageLevel Message;
+
+private:
+  std::string Destination;
 };
 
 #endif
diff --git a/Source/cmInstallScriptGenerator.cxx b/Source/cmInstallScriptGenerator.cxx
index 933aa07..106a7af 100644
--- a/Source/cmInstallScriptGenerator.cxx
+++ b/Source/cmInstallScriptGenerator.cxx
@@ -13,9 +13,10 @@
 
 //----------------------------------------------------------------------------
 cmInstallScriptGenerator
-::cmInstallScriptGenerator(const char* script, bool code,
+::cmInstallScriptGenerator(cmMakefile* mf,
+                           const char* script, bool code,
                            const char* component) :
-  cmInstallGenerator(0, std::vector<std::string>(), component, MessageDefault),
+  cmInstallGenerator(mf, 0, std::vector<std::string>(), component, MessageDefault),
   Script(script), Code(code)
 {
 }
diff --git a/Source/cmInstallScriptGenerator.h b/Source/cmInstallScriptGenerator.h
index 54a7b21..9088a5c 100644
--- a/Source/cmInstallScriptGenerator.h
+++ b/Source/cmInstallScriptGenerator.h
@@ -20,7 +20,7 @@
 class cmInstallScriptGenerator: public cmInstallGenerator
 {
 public:
-  cmInstallScriptGenerator(const char* script, bool code,
+  cmInstallScriptGenerator(cmMakefile* mf, const char* script, bool code,
     const char* component);
   virtual ~cmInstallScriptGenerator();
 
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index 5115788..197c43c 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -22,13 +22,13 @@
 
 //----------------------------------------------------------------------------
 cmInstallTargetGenerator
-::cmInstallTargetGenerator(cmTarget& t, const char* dest, bool implib,
+::cmInstallTargetGenerator(cmMakefile* mf, cmTarget& t, const char* dest, bool implib,
                            const char* file_permissions,
                            std::vector<std::string> const& configurations,
                            const char* component,
                            MessageLevel message,
                            bool optional):
-  cmInstallGenerator(dest, configurations, component, message), Target(&t),
+  cmInstallGenerator(mf, dest, configurations, component, message), Target(&t),
   FilePermissions(file_permissions),
   ImportLibrary(implib),
   Optional(optional)
@@ -339,15 +339,6 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
 
 //----------------------------------------------------------------------------
 std::string
-cmInstallTargetGenerator::GetDestination(std::string const& config) const
-{
-  cmGeneratorExpression ge;
-  return ge.Parse(this->Destination)
-    ->Evaluate(this->Target->GetMakefile(), config);
-}
-
-//----------------------------------------------------------------------------
-std::string
 cmInstallTargetGenerator::GetInstallFilename(const std::string& config) const
 {
   NameType nameType = this->ImportLibrary? NameImplib : NameNormal;
diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h
index db69220..cf1bf60 100644
--- a/Source/cmInstallTargetGenerator.h
+++ b/Source/cmInstallTargetGenerator.h
@@ -22,7 +22,7 @@ class cmInstallTargetGenerator: public cmInstallGenerator
 {
 public:
   cmInstallTargetGenerator(
-    cmTarget& t, const char* dest, bool implib,
+    cmMakefile* mf, cmTarget& t, const char* dest, bool implib,
     const char* file_permissions,
     std::vector<std::string> const& configurations,
     const char* component,
@@ -59,8 +59,6 @@ public:
   cmTarget* GetTarget() const { return this->Target; }
   bool IsImportLibrary() const { return this->ImportLibrary; }
 
-  std::string GetDestination(std::string const& config) const;
-
 protected:
   virtual void GenerateScript(std::ostream& os);
   virtual void GenerateScriptForConfig(std::ostream& os,
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 98accf9..55b90b6 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -2578,7 +2578,7 @@ class cmInstallTargetGeneratorLocal: public cmInstallTargetGenerator
 public:
   cmInstallTargetGeneratorLocal(cmTarget& t, const char* dest, bool implib):
     cmInstallTargetGenerator(
-      t, dest, implib, "", std::vector<std::string>(), "Unspecified",
+      this->Makefile, t, dest, implib, "", std::vector<std::string>(), "Unspecified",
       cmInstallGenerator::SelectMessageLevel(t.GetMakefile()),
       false) {}
 };
@@ -2603,7 +2603,7 @@ cmLocalGenerator
     // Include the user-specified pre-install script for this target.
     if(const char* preinstall = l->second.GetProperty("PRE_INSTALL_SCRIPT"))
       {
-      cmInstallScriptGenerator g(preinstall, false, 0);
+      cmInstallScriptGenerator g(this->Makefile, preinstall, false, 0);
       g.Generate(os, config, configurationTypes);
       }
 
@@ -2664,7 +2664,7 @@ cmLocalGenerator
     // Include the user-specified post-install script for this target.
     if(const char* postinstall = l->second.GetProperty("POST_INSTALL_SCRIPT"))
       {
-      cmInstallScriptGenerator g(postinstall, false, 0);
+      cmInstallScriptGenerator g(this->Makefile, postinstall, false, 0);
       g.Generate(os, config, configurationTypes);
       }
     }
diff --git a/Source/cmScriptGenerator.cxx b/Source/cmScriptGenerator.cxx
index e44b236..b26b9e8 100644
--- a/Source/cmScriptGenerator.cxx
+++ b/Source/cmScriptGenerator.cxx
@@ -216,6 +216,7 @@ void cmScriptGenerator::GenerateScriptActionsPerConfig(std::ostream& os,
         i != this->ConfigurationTypes->end(); ++i)
       {
       const char* config = i->c_str();
+      this->ConfigurationName = config;
       if(this->GeneratesForConfig(config))
         {
         // Generate a per-configuration block.
@@ -224,6 +225,7 @@ void cmScriptGenerator::GenerateScriptActionsPerConfig(std::ostream& os,
         this->GenerateScriptForConfig(os, config, indent.Next());
         first = false;
         }
+      this->ConfigurationName = "";
       }
     if(!first)
       {
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index c7a13bc..04b7339 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -2677,30 +2677,37 @@ cmTarget::CompileInfo const* cmTarget::GetCompileInfo(
 std::string cmTarget::GetDirectory(const std::string& config,
                                    bool implib) const
 {
+  std::string outDir = "";
   if (this->IsImported())
     {
-    // Return the directory from which the target is imported.
-    return
-      cmSystemTools::GetFilenamePath(
+    // The directory from which the target is imported.
+    outDir = cmSystemTools::GetFilenamePath(
       this->ImportedGetFullPath(config, implib));
     }
   else if(OutputInfo const* info = this->GetOutputInfo(config))
     {
-    // Return the directory in which the target will be built.
-    return implib? info->ImpDir : info->OutDir;
+    // The directory in which the target will be built.
+    outDir = implib? info->ImpDir : info->OutDir;
     }
-  return "";
+
+  cmGeneratorExpression ge;
+  cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(outDir);
+  return cge->Evaluate(this->Makefile, config);
 }
 
 //----------------------------------------------------------------------------
 std::string cmTarget::GetPDBDirectory(const std::string& config) const
 {
+  std::string pdbDir = "";
   if(OutputInfo const* info = this->GetOutputInfo(config))
     {
     // Return the directory in which the target will be built.
-    return info->PdbDir;
+    pdbDir = info->PdbDir;
     }
-  return "";
+
+  cmGeneratorExpression ge;
+  cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(pdbDir);
+  return cge->Evaluate(this->Makefile, config);
 }
 
 //----------------------------------------------------------------------------
@@ -4586,15 +4593,23 @@ std::string cmTarget::GetOutputName(const std::string& config,
   // OUTPUT_NAME
   props.push_back("OUTPUT_NAME");
 
+  std::string outName = "";
   for(std::vector<std::string>::const_iterator i = props.begin();
       i != props.end(); ++i)
     {
-    if(const char* outName = this->GetProperty(*i))
+    if(const char* outNameProp = this->GetProperty(*i))
       {
-      return outName;
+      outName = outNameProp;
+      break;
       }
     }
-  return this->GetName();
+
+  if(outName.empty())
+    outName = this->GetName();
+
+  cmGeneratorExpression ge;
+  cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(outName);
+  return cge->Evaluate(this->Makefile, config); 
 }
 
 //----------------------------------------------------------------------------
diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt
index 0df42d9..16dd123 100644
--- a/Tests/ExportImport/Export/CMakeLists.txt
+++ b/Tests/ExportImport/Export/CMakeLists.txt
@@ -73,6 +73,15 @@ install(TARGETS testLibPerConfigDest EXPORT exp
   DESTINATION lib/$<$<BOOL:$<CONFIG>>:$<CONFIG>>$<$<NOT:$<BOOL:$<CONFIG>>>:NoConfig>
   )
 
+# Test [<CONFIG>_]OUTPUT_NAME properties with generator expressions
+add_library(testLib7 STATIC testLib7.c)
+set_property(TARGET testLib7 PROPERTY DEBUG_OUTPUT_NAME testLib7-$<CONFIG>)
+set_property(TARGET testLib7 PROPERTY RELEASE_OUTPUT_NAME testLib7-$<CONFIG>)
+set_property(TARGET testLib7 PROPERTY OUTPUT_NAME testLib7-$<CONFIG>)
+
+# Test install(...DESTINATION) with generator expressions
+install(FILES $<TARGET_FILE:testLib7> DESTINATION testLib7-$<CONFIG>)
+
 # Work-around: Visual Studio 6 does not support per-target object files.
 set(VS6)
 if("${CMAKE_GENERATOR}" MATCHES "Visual Studio 6")
@@ -99,6 +108,13 @@ target_link_libraries(testLib4
 add_executable(testExe3 testExe3.c)
 set_property(TARGET testExe3 PROPERTY MACOSX_BUNDLE 1)
 
+# Test RUNTIME_OUTPUT_DIRECTORY[_<CONFIG>] properties with generator expressions
+add_executable(testExe4 testExe4.c)
+target_link_libraries(testExe4 testExe1lib)
+set_property(TARGET testExe4 PROPERTY RUNTIME_OUTPUT_DIRECTORY_DEBUG testExe4-$<CONFIG>)
+set_property(TARGET testExe4 PROPERTY RUNTIME_OUTPUT_DIRECTORY_RELEASE testExe4-$<CONFIG>)
+set_property(TARGET testExe4 PROPERTY RUNTIME_OUTPUT_DIRECTORY testExe4-$<CONFIG>)
+
 # Test cyclic dependencies.
 add_library(testLibCycleA STATIC
   testLibCycleA1.c testLibCycleA2.c testLibCycleA3.c)
@@ -444,9 +460,9 @@ install(FILES
 # Install and export from install tree.
 install(
   TARGETS
-  testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3
+  testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3 testExe4
   testExe2lib testLib4lib testLib4libdbg testLib4libopt
-  testLib6
+  testLib6 testLib7
   testLibCycleA testLibCycleB
   cmp0022NEW cmp0022OLD
   systemlib
@@ -505,7 +521,7 @@ export(TARGETS testExe1 testLib1 testLib2 testLib3
   NAMESPACE bld_
   FILE ExportBuildTree.cmake
   )
-export(TARGETS testExe2 testLib4 testLib5 testLib6 testExe3 testExe2lib
+export(TARGETS testExe2 testLib4 testLib5 testLib6 testLib7 testExe3 testExe4 testExe2lib
   testLib4lib testLib4libdbg testLib4libopt
   testLibCycleA testLibCycleB
   testLibPerConfigDest
diff --git a/Tests/ExportImport/Export/testExe4.c b/Tests/ExportImport/Export/testExe4.c
new file mode 100644
index 0000000..731057e
--- /dev/null
+++ b/Tests/ExportImport/Export/testExe4.c
@@ -0,0 +1,24 @@
+#include <stdio.h>
+
+int main(int argc, const char* argv[])
+{
+  if(argc < 2)
+    {
+    fprintf(stderr, "Must specify output file.\n");
+    return 1;
+    }
+  {
+  FILE* f = fopen(argv[1], "w");
+  if(f)
+    {
+    fprintf(f, "int generated_by_testExe4() { return 0; }\n");
+    fclose(f);
+    }
+  else
+    {
+    fprintf(stderr, "Error writing to %s\n", argv[1]);
+    return 1;
+    }
+  }
+  return 0;
+}
diff --git a/Tests/ExportImport/Export/testLib7.c b/Tests/ExportImport/Export/testLib7.c
new file mode 100644
index 0000000..7acae9e
--- /dev/null
+++ b/Tests/ExportImport/Export/testLib7.c
@@ -0,0 +1 @@
+int testLib7(void) { return 0; }
diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt
index 17d983a..0f56495 100644
--- a/Tests/ExportImport/Import/A/CMakeLists.txt
+++ b/Tests/ExportImport/Import/A/CMakeLists.txt
@@ -19,11 +19,17 @@ add_custom_command(
   COMMAND exp_testExe3 ${Import_BINARY_DIR}/exp_generated3.c
   DEPENDS exp_testExe3
   )
+add_custom_command(
+  OUTPUT ${Import_BINARY_DIR}/exp_generated4.c
+  COMMAND exp_testExe4 ${Import_BINARY_DIR}/exp_generated4.c
+  DEPENDS exp_testExe4
+  )
 
 add_executable(imp_testExe1
   imp_testExe1.c
   ${Import_BINARY_DIR}/exp_generated.c
   ${Import_BINARY_DIR}/exp_generated3.c
+  ${Import_BINARY_DIR}/exp_generated4.c
   )
 
 # Try linking to a library imported from the install tree.
@@ -33,6 +39,7 @@ target_link_libraries(imp_testExe1
   exp_testLib4
   exp_testLib5
   exp_testLib6
+  exp_testLib7
   exp_testLibCycleA
   exp_testLibPerConfigDest
   )
@@ -52,11 +59,17 @@ add_custom_command(
   COMMAND bld_testExe3 ${Import_BINARY_DIR}/bld_generated3.c
   DEPENDS bld_testExe3
   )
+add_custom_command(
+  OUTPUT ${Import_BINARY_DIR}/bld_generated4.c
+  COMMAND bld_testExe4 ${Import_BINARY_DIR}/bld_generated4.c
+  DEPENDS bld_testExe4
+  )
 
 add_executable(imp_testExe1b
   imp_testExe1.c
   ${Import_BINARY_DIR}/bld_generated.c
   ${Import_BINARY_DIR}/bld_generated3.c
+  ${Import_BINARY_DIR}/bld_generated4.c
   )
 
 # Try linking to a library imported from the build tree.
@@ -66,6 +79,7 @@ target_link_libraries(imp_testExe1b
   bld_testLib4
   bld_testLib5
   bld_testLib6
+  bld_testLib7
   bld_testLibCycleA
   bld_testLibPerConfigDest
   )
diff --git a/Tests/ExportImport/Import/A/imp_testExe1.c b/Tests/ExportImport/Import/A/imp_testExe1.c
index 150fcef..0a74309 100644
--- a/Tests/ExportImport/Import/A/imp_testExe1.c
+++ b/Tests/ExportImport/Import/A/imp_testExe1.c
@@ -1,11 +1,13 @@
 extern int generated_by_testExe1();
 extern int generated_by_testExe3();
+extern int generated_by_testExe4();
 extern int testLib2();
 extern int testLib3();
 extern int testLib4();
 extern int testLib4lib();
 extern int testLib5();
 extern int testLib6();
+extern int testLib7();
 extern int testLibCycleA1();
 extern int testLibPerConfigDest();
 
@@ -21,7 +23,7 @@ extern testLib4libcfg(void);
 int main()
 {
   return (testLib2() + generated_by_testExe1() + testLib3() + testLib4()
-          + testLib5() + testLib6() + testLibCycleA1()
+          + testLib5() + testLib6() + testLib7() + testLibCycleA1()
           + testLibPerConfigDest()
-          + generated_by_testExe3() + testLib4lib() + testLib4libcfg());
+          + generated_by_testExe3() + generated_by_testExe4() + testLib4lib() + testLib4libcfg());
 }
-- 
1.9.5.msysgit.1

