From e332853f1954a79256ae0919c70b3fe10684c3c1 Mon Sep 17 00:00:00 2001
From: Robert Goulet <robert.goulet@autodesk.com>
Date: Fri, 12 Jun 2015 10:16:09 -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.

---
 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 | 16 ++++++++++++++
 17 files changed, 117 insertions(+), 70 deletions(-)

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 398d5c9..6be4afe 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -2675,30 +2675,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);
 }
 
 //----------------------------------------------------------------------------
@@ -4584,15 +4591,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..702f63f 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 testLib1.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 testExe1.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)
-- 
1.9.5.msysgit.1

