Browse Source

ENH: Created new install script generation framework. The INSTALL command creates the generators which are later used by cmLocalGenerator to create the cmake_install.cmake files. A new target installation interface is provided by the INSTALL command which fixes several problems with the INSTALL_TARGETS command. See bug#2691. Bugs 1481 and 1695 are addressed by these changes.

Brad King 19 years ago
parent
commit
96f0266228

+ 6 - 0
Source/CMakeLists.txt

@@ -115,6 +115,12 @@ SET(SRCS
   cmGlobalGenerator.h
   cmGlobalUnixMakefileGenerator3.cxx
   cmGlobalUnixMakefileGenerator3.h
+  cmInstallGenerator.h
+  cmInstallGenerator.cxx
+  cmInstallScriptGenerator.h
+  cmInstallScriptGenerator.cxx
+  cmInstallTargetGenerator.h
+  cmInstallTargetGenerator.cxx
   cmListFileCache.cxx
   cmListFileCache.h
   cmListFileLexer.c

+ 261 - 1
Source/cmInstallCommand.cxx

@@ -16,8 +16,38 @@
 =========================================================================*/
 #include "cmInstallCommand.h"
 
+#include "cmInstallScriptGenerator.h"
+#include "cmInstallTargetGenerator.h"
+
 // cmInstallCommand
 bool cmInstallCommand::InitialPass(std::vector<std::string> const& args)
+{
+  // Allow calling with no arguments so that arguments may be built up
+  // using a variable that may be left empty.
+  if(args.empty())
+    {
+    return true;
+    }
+
+  // Switch among the command modes.
+  if(args[0] == "SCRIPT")
+    {
+    return this->HandleScriptMode(args);
+    }
+  else if(args[0] == "TARGETS")
+    {
+    return this->HandleTargetsMode(args);
+    }
+
+  // Unknown mode.
+  cmStdString e = "called with unknown mode ";
+  e += args[0];
+  this->SetError(e.c_str());
+  return false;
+}
+
+//----------------------------------------------------------------------------
+bool cmInstallCommand::HandleScriptMode(std::vector<std::string> const& args)
 {
   bool doing_script = false;
   for(size_t i=0; i < args.size(); ++i)
@@ -41,7 +71,8 @@ bool cmInstallCommand::InitialPass(std::vector<std::string> const& args)
         this->SetError("given a directory as value of SCRIPT argument.");
         return false;
         }
-      m_Makefile->AddInstallScript(script.c_str());
+      m_Makefile->AddInstallGenerator(
+        new cmInstallScriptGenerator(script.c_str()));
       }
     }
   if(doing_script)
@@ -49,6 +80,235 @@ bool cmInstallCommand::InitialPass(std::vector<std::string> const& args)
     this->SetError("given no value for SCRIPT argument.");
     return false;
     }
+  return true;
+}
+
+//----------------------------------------------------------------------------
+bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
+{
+  // This is the TARGETS mode.
+  bool doing_targets = true;
+  bool doing_destination = false;
+  bool library_settings = true;
+  bool runtime_settings = true;
+  std::vector<cmTarget*> targets;
+  const char* library_destination = 0;
+  const char* runtime_destination = 0;
+  cmLocalGenerator* lg = m_Makefile->GetLocalGenerator();
+  cmGlobalGenerator* gg = lg->GetGlobalGenerator();
+  for(unsigned int i=1; i < args.size(); ++i)
+    {
+    if(args[i] == "DESTINATION")
+      {
+      // Switch to setting the destination property.
+      doing_targets = false;
+      doing_destination = true;
+      }
+    else if(args[i] == "LIBRARY")
+      {
+      // Switch to setting only library properties.
+      doing_targets = false;
+      doing_destination = false;
+      library_settings = true;
+      runtime_settings = false;
+      }
+    else if(args[i] == "RUNTIME")
+      {
+      // Switch to setting only runtime properties.
+      doing_targets = false;
+      doing_destination = false;
+      library_settings = false;
+      runtime_settings = true;
+      }
+    else if(doing_targets)
+      {
+      // Lookup this target in the current project.
+      if(cmTarget* target = m_Makefile->FindTarget(args[i].c_str()))
+        {
+        // Found the target.  Check its type.
+        if(target->GetType() != cmTarget::EXECUTABLE &&
+           target->GetType() != cmTarget::STATIC_LIBRARY &&
+           target->GetType() != cmTarget::SHARED_LIBRARY &&
+           target->GetType() != cmTarget::MODULE_LIBRARY)
+          {
+          cmOStringStream e;
+          e << "TARGETS given target \"" << args[i]
+            << "\" which is not an executable, library, or module.";
+          this->SetError(e.str().c_str());
+          return false;
+          }
+
+        // Store the target in the list to be installed.
+        targets.push_back(target);
+        }
+      else
+        {
+        // Did not find the target.
+        cmOStringStream e;
+        e << "TARGETS given target \"" << args[i]
+          << "\" which does not exist in this directory.";
+        this->SetError(e.str().c_str());
+        return false;
+        }
+      }
+    else if(doing_destination)
+      {
+      // Set the destination in the active set(s) of properties.
+      if(library_settings)
+        {
+        library_destination = args[i].c_str();
+        }
+      if(runtime_settings)
+        {
+        runtime_destination = args[i].c_str();
+        }
+      doing_destination = false;
+      }
+    else
+      {
+      // Unknown argument.
+      cmOStringStream e;
+      e << "TARGETS given unknown argument \"" << args[i] << "\".";
+      this->SetError(e.str().c_str());
+      return false;
+      }
+    }
+
+  // Check if there is something to do.
+  if(targets.empty())
+    {
+    return true;
+    }
+  if(!library_destination && !runtime_destination)
+    {
+    this->SetError("TARGETS given no DESTINATION!");
+    return false;
+    }
+
+  // Compute destination paths.
+  std::string library_dest;
+  std::string runtime_dest;
+  this->ComputeDestination(library_destination, library_dest);
+  this->ComputeDestination(runtime_destination, runtime_dest);
+
+  // Generate install script code to install the given targets.
+  for(std::vector<cmTarget*>::iterator ti = targets.begin();
+      ti != targets.end(); ++ti)
+    {
+    // Handle each target type.
+    cmTarget& target = *(*ti);
+    switch(target.GetType())
+      {
+      case cmTarget::SHARED_LIBRARY:
+        {
+        // Shared libraries are handled differently on DLL and non-DLL
+        // platforms.  All windows platforms are DLL platforms
+        // including cygwin.  Currently no other platform is a DLL
+        // platform.
+#if defined(_WIN32) || defined(__CYGWIN__)
+        // This is a DLL platform.
+        if(library_destination)
+          {
+          // The import library uses the LIBRARY properties.
+          m_Makefile->AddInstallGenerator(
+            new cmInstallTargetGenerator(target, library_dest.c_str(), true));
+          }
+        if(runtime_destination)
+          {
+          // The DLL uses the RUNTIME properties.
+          m_Makefile->AddInstallGenerator(
+            new cmInstallTargetGenerator(target, runtime_dest.c_str(), false));
+          }
+#else
+        // This is a non-DLL platform.
+        if(library_destination)
+          {
+          // The shared library uses the LIBRARY properties.
+          m_Makefile->AddInstallGenerator(
+            new cmInstallTargetGenerator(target, library_dest.c_str()));
+          }
+#endif
+        }
+        break;
+      case cmTarget::STATIC_LIBRARY:
+      case cmTarget::MODULE_LIBRARY:
+        {
+        // Static libraries and modules use LIBRARY properties.
+        if(library_destination)
+          {
+          m_Makefile->AddInstallGenerator(
+            new cmInstallTargetGenerator(target, library_dest.c_str()));
+          }
+        else
+          {
+          cmOStringStream e;
+          e << "TARGETS given no LIBRARY DESTINATION for ";
+          if(target.GetType() == cmTarget::STATIC_LIBRARY)
+            {
+            e << "static library";
+            }
+          else
+            {
+            e << "module";
+            }
+          e << " target \"" << target.GetName() << "\".";
+          this->SetError(e.str().c_str());
+          return false;
+          }
+        }
+        break;
+      case cmTarget::EXECUTABLE:
+        {
+        // Executables use the RUNTIME properties.
+        if(runtime_destination)
+          {
+          m_Makefile->AddInstallGenerator(
+            new cmInstallTargetGenerator(target, runtime_dest.c_str()));
+          }
+        else
+          {
+          cmOStringStream e;
+          e << "TARGETS given no RUNTIME DESTINATION for executable target \""
+            << target.GetName() << "\".";
+          this->SetError(e.str().c_str());
+          return false;
+          }
+        }
+        break;
+      default:
+        // This should never happen due to the above type check.
+        // Ignore the case.
+        break;
+      }
+    }
 
   return true;
 }
+
+//----------------------------------------------------------------------------
+void cmInstallCommand::ComputeDestination(const char* destination,
+                                          std::string& dest)
+{
+  if(destination)
+    {
+    if(cmSystemTools::FileIsFullPath(destination))
+      {
+      // Full paths are absolute.
+      dest = destination;
+      }
+    else
+      {
+      // Relative paths are treated with respect to the installation prefix.
+      dest = "${CMAKE_INSTALL_PREFIX}/";
+      dest += destination;
+      }
+
+    // Format the path nicely.  Note this also removes trailing
+    // slashes.
+    cmSystemTools::ConvertToUnixSlashes(dest);
+    }
+  else
+    {
+    dest = "";
+    }
+}

+ 55 - 9
Source/cmInstallCommand.h

@@ -52,7 +52,7 @@ public:
    */
   virtual const char* GetTerseDocumentation()
     {
-    return "Install rule specification interface command.";
+    return "Specify rules to run at install time.";
     }
 
   /**
@@ -61,19 +61,65 @@ public:
   virtual const char* GetFullDocumentation()
     {
     return
-      "  INSTALL(SCRIPT <script1> [SCRIPT <script2> [...]])\n"
-      "Specify rules to run at install time.  If SCRIPT is given the "
-      "file named after it will be included in the install scripts.  "
-      "Multiple SCRIPTs may be given within a single source directory "
-      "and the scripts will be run in the order given.  "
-      "The processing order of these scripts relative to install rules "
+      "This command generates installation rules for a project.  "
+      "Rules specified by calls to this command within a source directory "
+      "are executed in order during installation.  "
+      "The order across directories is not defined.\n"
+      "There are multiple signatures for this command:\n"
+      "  INSTALL(TARGETS [targets...] [[LIBRARY|RUNTIME]\n"
+      "                                [DESTINATION <destination>]\n"
+      "                               ] [...])\n"
+      "The TARGETS form specifies rules for installing targets from a "
+      "project.  There are two kinds of target files that may be "
+      "installed: library and runtime.  Static libraries and modules "
+      "are always treated as library targets.  Executables are always "
+      "treated as runtime targets.  For non-DLL platforms, shared libraries "
+      "are treated as library targets.  For DLL platforms, the DLL part of "
+      "a shared library is treated as a runtime target and the corresponding "
+      "import library is treated as a library target.  All Windows-based "
+      "systems including Cygwin are DLL platforms.  The LIBRARY and RUNTIME "
+      "arguments change the type of target to which the following properties "
+      "apply.  If neither is given the installation properties apply to "
+      "both target types.  If only one is given then only targets of that "
+      "type will be installed (which can be used to install just a DLL or "
+      "just an import library).\n"
+      "DESTINATION arguments specify the directory on disk to which the "
+      "target file will be installed.  "
+      "If a full path (with a leading slash or drive letter) is given it "
+      "is used directly.  If a relative path is given it is interpreted "
+      "relative to the value of CMAKE_INSTALL_PREFIX.\n"
+      "One or more groups of properties may be specified in a single call "
+      "to the TARGETS form of this command.  A target may be installed more "
+      "than once to different locations.  Consider hypothetical "
+      "targets \"myExe\", \"mySharedLib\", and \"myStaticLib\".  The code\n"
+      "    INSTALL(TARGETS myExe mySharedLib myStaticLib\n"
+      "            RUNTIME DESTINATION bin\n"
+      "            LIBRARY DESTINATION lib)\n"
+      "    INSTALL(TARGETS mySharedLib DESTINATION /some/full/path)\n"
+      "will install myExe to <prefix>/bin and myStaticLib to <prefix>/lib.  "
+      "On non-DLL platforms mySharedLib will be installed to <prefix>/lib and "
+      "/some/full/path.  On DLL platforms the mySharedLib DLL will be "
+      "installed to <prefix>/bin and /some/full/path and its import library "
+      "will be installed to <prefix>/lib and /some/full/path.  On non-DLL "
+      "platforms mySharedLib will be installed to <prefix>/lib and "
+      "/some/full/path.\n"
+      "  INSTALL(SCRIPT <file1> [SCRIPT <file2> [...]])\n"
+      "The SCRIPT form will invoke the given CMake script files during "
+      "installation.\n"
+      "NOTE: This command supercedes the INSTALL_TARGETS command and the "
+      "target properties PRE_INSTALL_SCRIPT and POST_INSTALL_SCRIPT.  "
+      "The processing order of these install rules relative to those "
       "generated by INSTALL_TARGETS, INSTALL_FILES, and INSTALL_PROGRAMS "
-      "commands is not specified.\n"
-      "This command is a placeholder for a future larger interface."
+      "commands is not defined.\n"
       ;
     }
 
   cmTypeMacro(cmInstallCommand, cmCommand);
+
+private:
+  bool HandleScriptMode(std::vector<std::string> const& args);
+  bool HandleTargetsMode(std::vector<std::string> const& args);
+  void ComputeDestination(const char* destination, std::string& dest);
 };
 
 

+ 82 - 0
Source/cmInstallGenerator.cxx

@@ -0,0 +1,82 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#include "cmInstallGenerator.h"
+
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+
+//----------------------------------------------------------------------------
+cmInstallGenerator
+::cmInstallGenerator()
+{
+  this->ConfigurationName = 0;
+  this->ConfigurationTypes = 0;
+}
+
+//----------------------------------------------------------------------------
+cmInstallGenerator
+::~cmInstallGenerator()
+{
+}
+
+//----------------------------------------------------------------------------
+void
+cmInstallGenerator
+::Generate(std::ostream& os, const char* config,
+           std::vector<std::string> const& configurationTypes)
+{
+  this->ConfigurationName = config;
+  this->ConfigurationTypes = &configurationTypes;
+  this->GenerateScript(os);
+  this->ConfigurationName = 0;
+  this->ConfigurationTypes = 0;
+}
+
+//----------------------------------------------------------------------------
+void cmInstallGenerator::AddInstallRule(std::ostream& os,
+                                        const char* dest,
+                                        int type,
+                                        const char* files,
+                                        bool optional /* = false */,
+                                        const char* properties /* = 0 */)
+{
+  // TODO: Make optional files use IF(EXISTS) to not report if not
+  // installing.
+  std::string sfiles = files;
+  std::string destination = dest;
+  std::string stype;
+  switch(type)
+    {
+    case cmTarget::INSTALL_PROGRAMS: stype = "PROGRAM"; break;
+    case cmTarget::EXECUTABLE:       stype = "EXECUTABLE"; break;
+    case cmTarget::STATIC_LIBRARY:   stype = "STATIC_LIBRARY"; break;
+    case cmTarget::SHARED_LIBRARY:   stype = "SHARED_LIBRARY"; break;
+    case cmTarget::MODULE_LIBRARY:   stype = "MODULE"; break;
+    case cmTarget::INSTALL_FILES:
+    default:                         stype = "FILE"; break;
+    }
+  std::string fname = cmSystemTools::GetFilenameName(sfiles.c_str());
+  os << "MESSAGE(STATUS \"Installing " << destination.c_str()
+     << "/" << fname.c_str() << "\")\n"
+     << "FILE(INSTALL DESTINATION \"" << destination.c_str()
+     << "\" TYPE " << stype.c_str() << (optional?" OPTIONAL":"") ;
+  if(properties && *properties)
+    {
+    os << " PROPERTIES" << properties;
+    }
+  os << " FILES \"" << sfiles.c_str() << "\")\n";
+}

+ 48 - 0
Source/cmInstallGenerator.h

@@ -0,0 +1,48 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef cmInstallGenerator_h
+#define cmInstallGenerator_h
+
+#include "cmStandardIncludes.h"
+
+class cmLocalGenerator;
+
+/** \class cmInstallGenerator
+ * \brief Support class for generating install scripts.
+ *
+ */
+class cmInstallGenerator
+{
+public:
+  cmInstallGenerator();
+  virtual ~cmInstallGenerator();
+
+  void Generate(std::ostream& os, const char* config,
+                std::vector<std::string> const& configurationTypes);
+
+  static void AddInstallRule(std::ostream& os, const char* dest, int type,
+                             const char* files, bool optional = false,
+                             const char* properties = 0);
+
+protected:
+  virtual void GenerateScript(std::ostream& os)=0;
+
+  const char* ConfigurationName;
+  std::vector<std::string> const* ConfigurationTypes;
+};
+
+#endif

+ 35 - 0
Source/cmInstallScriptGenerator.cxx

@@ -0,0 +1,35 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#include "cmInstallScriptGenerator.h"
+
+//----------------------------------------------------------------------------
+cmInstallScriptGenerator
+::cmInstallScriptGenerator(const char* script): Script(script)
+{
+}
+
+//----------------------------------------------------------------------------
+cmInstallScriptGenerator
+::~cmInstallScriptGenerator()
+{
+}
+
+//----------------------------------------------------------------------------
+void cmInstallScriptGenerator::GenerateScript(std::ostream& os)
+{
+  os << "INCLUDE(\"" << this->Script << "\")\n";
+}

+ 36 - 0
Source/cmInstallScriptGenerator.h

@@ -0,0 +1,36 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef cmInstallScriptGenerator_h
+#define cmInstallScriptGenerator_h
+
+#include "cmInstallGenerator.h"
+
+/** \class cmInstallScriptGenerator
+ * \brief Generate target installation rules.
+ */
+class cmInstallScriptGenerator: public cmInstallGenerator
+{
+public:
+  cmInstallScriptGenerator(const char* script);
+  virtual ~cmInstallScriptGenerator();
+
+protected:
+  virtual void GenerateScript(std::ostream& os);
+  std::string Script;
+};
+
+#endif

+ 191 - 0
Source/cmInstallTargetGenerator.cxx

@@ -0,0 +1,191 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#include "cmInstallTargetGenerator.h"
+
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmTarget.h"
+
+//----------------------------------------------------------------------------
+cmInstallTargetGenerator
+::cmInstallTargetGenerator(cmTarget& t, const char* dest, bool implib):
+  Target(&t), Destination(dest), ImportLibrary(implib)
+{
+}
+
+//----------------------------------------------------------------------------
+cmInstallTargetGenerator
+::~cmInstallTargetGenerator()
+{
+}
+
+//----------------------------------------------------------------------------
+void cmInstallTargetGenerator::GenerateScript(std::ostream& os)
+{
+  // Compute the build tree directory from which to copy the target.
+  std::string fromDir;
+  if(this->Target->NeedRelinkBeforeInstall())
+    {
+    fromDir = this->Target->GetMakefile()->GetStartOutputDirectory();
+    fromDir += "/CMakeFiles/CMakeRelink.dir/";
+    }
+  else
+    {
+    fromDir = this->Target->GetDirectory();
+    fromDir += "/";
+    }
+
+  // Write variable settings to do per-configuration references.
+  this->PrepareInstallReference(os);
+
+  // Create the per-configuration reference.
+  std::string fromName = this->GetInstallReference();
+  std::string fromFile = fromDir;
+  fromFile += fromName;
+
+  // Setup special properties for some target types.
+  std::string props;
+  const char* properties = 0;
+  cmTarget::TargetType type = this->Target->GetType();
+  switch(type)
+    {
+    case cmTarget::SHARED_LIBRARY:
+      {
+      // Add shared library installation properties if this platform
+      // supports them.
+      const char* lib_version = this->Target->GetProperty("VERSION");
+      const char* lib_soversion = this->Target->GetProperty("SOVERSION");
+      if(!this->Target->GetMakefile()
+         ->GetDefinition("CMAKE_SHARED_LIBRARY_SONAME_C_FLAG"))
+        {
+        // Versioning is supported only for shared libraries and modules,
+        // and then only when the platform supports an soname flag.
+        lib_version = 0;
+        lib_soversion = 0;
+        }
+      if(lib_version)
+        {
+        props += " VERSION ";
+        props += lib_version;
+        }
+      if(lib_soversion)
+        {
+        props += " SOVERSION ";
+        props += lib_soversion;
+        }
+      properties = props.c_str();
+      }
+      break;
+    case cmTarget::EXECUTABLE:
+      {
+      // Add executable installation properties if this platform
+      // supports them.
+#if defined(_WIN32) && !defined(__CYGWIN__)
+      const char* exe_version = 0;
+#else
+      const char* exe_version = this->Target->GetProperty("VERSION");
+#endif
+      if(exe_version)
+        {
+        props += " VERSION ";
+        props += exe_version;
+        properties = props.c_str();
+        }
+
+      // Handle OSX Bundles.
+      if(this->Target->GetPropertyAsBool("MACOSX_BUNDLE"))
+        {
+        // Compute the source locations of the bundle executable and
+        // Info.plist file.
+        std::string plist = fromFile;
+        plist += ".app/Contents/Info.plist";
+        fromFile += ".app/Contents/MacOS/";
+        fromFile += fromName;
+
+        // Compute the destination locations of the bundle executable
+        // and Info.plist file.
+        std::string bdest = this->Destination;
+        bdest += "/";
+        bdest += fromName;
+        std::string pdest = bdest;
+        pdest += ".app/Contents";
+        bdest += ".app/Contents/MacOS";
+
+        // Install the Info.plist file.
+        this->AddInstallRule(os, pdest.c_str(), cmTarget::INSTALL_FILES,
+                             plist.c_str());
+        }
+      }
+      break;
+    case cmTarget::STATIC_LIBRARY:
+    case cmTarget::MODULE_LIBRARY:
+      // Nothing special for modules or static libraries.
+      break;
+    default:
+      break;
+    }
+
+  // Write code to install the target file.
+  this->AddInstallRule(os, this->Destination.c_str(), type, fromFile.c_str(),
+                       this->ImportLibrary, properties);
+}
+
+//----------------------------------------------------------------------------
+void
+cmInstallTargetGenerator
+::PrepareInstallReference(std::ostream& os)
+{
+  // If the target name may vary with the configuration type then
+  // store all possible names ahead of time in variables.
+  std::string fname;
+  for(std::vector<std::string>::const_iterator i =
+        this->ConfigurationTypes->begin();
+      i != this->ConfigurationTypes->end(); ++i)
+    {
+    // Set a variable with the target name for this configuration.
+    fname = this->Target->GetFullName(i->c_str(), this->ImportLibrary);
+    os << "SET(" << this->Target->GetName()
+       << (this->ImportLibrary? "_IMPNAME_" : "_NAME_") << *i
+       << " \"" << fname << "\")\n";
+    }
+}
+
+//----------------------------------------------------------------------------
+std::string cmInstallTargetGenerator::GetInstallReference()
+{
+  if(this->ConfigurationTypes->empty())
+    {
+    return this->Target->GetFullName(this->ConfigurationName,
+                                     this->ImportLibrary);
+    }
+  else
+    {
+    std::string ref = "${";
+    ref += this->Target->GetName();
+    if(this->ImportLibrary)
+      {
+      ref += "_IMPNAME_";
+      }
+    else
+      {
+      ref += "_NAME_";
+      }
+    ref += "${CMAKE_INSTALL_CONFIG_NAME}}";
+    return ref;
+    }
+}

+ 43 - 0
Source/cmInstallTargetGenerator.h

@@ -0,0 +1,43 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef cmInstallTargetGenerator_h
+#define cmInstallTargetGenerator_h
+
+#include "cmInstallGenerator.h"
+
+class cmTarget;
+
+/** \class cmInstallTargetGenerator
+ * \brief Generate target installation rules.
+ */
+class cmInstallTargetGenerator: public cmInstallGenerator
+{
+public:
+  cmInstallTargetGenerator(cmTarget& t, const char* dest,
+                           bool implib = false);
+  virtual ~cmInstallTargetGenerator();
+
+protected:
+  virtual void GenerateScript(std::ostream& os);
+  void PrepareInstallReference(std::ostream& os);
+  std::string GetInstallReference();
+  cmTarget* Target;
+  std::string Destination;
+  bool ImportLibrary;
+};
+
+#endif

+ 3 - 1
Source/cmInstallTargetsCommand.h

@@ -53,7 +53,7 @@ public:
    */
   virtual const char* GetTerseDocumentation() 
     {
-    return "Create install rules for targets.";
+    return "Old installation command.  Use the INSTALL command.";
     }
   
   /**
@@ -62,6 +62,8 @@ public:
   virtual const char* GetFullDocumentation()
     {
     return
+      "This command has been superceded by the INSTALL command.  It "
+      "is provided for compatibility with older CMake code.\n"
       "  INSTALL_TARGETS(<dir> [RUNTIME_DIRECTORY dir] target target)\n"
       "Create rules to install the listed targets into the given directory.  "
       "The directory <dir> is relative to the installation prefix, which "

+ 164 - 361
Source/cmLocalGenerator.cxx

@@ -15,13 +15,18 @@
 
 =========================================================================*/
 #include "cmLocalGenerator.h"
+
+#include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
-#include "cmake.h"
+#include "cmInstallGenerator.h"
+#include "cmInstallScriptGenerator.h"
+#include "cmInstallTargetGenerator.h"
 #include "cmMakefile.h"
-#include "cmGeneratedFileStream.h"
-#include "cmSourceFile.h"
 #include "cmOrderLinkDirectories.h"
+#include "cmSourceFile.h"
 #include "cmTest.h"
+#include "cmake.h"
+
 #include <ctype.h> // for isalpha
 
 cmLocalGenerator::cmLocalGenerator()
@@ -238,11 +243,11 @@ void cmLocalGenerator::GenerateTestFiles()
     }
 }
 
+//----------------------------------------------------------------------------
 void cmLocalGenerator::GenerateInstallRules()
 {
-  cmTargets &tgts = m_Makefile->GetTargets();
-  const char* prefix
-    = m_Makefile->GetDefinition("CMAKE_INSTALL_PREFIX");
+  // Compute the install prefix.
+  const char* prefix = m_Makefile->GetDefinition("CMAKE_INSTALL_PREFIX");
 #if defined(_WIN32) && !defined(__CYGWIN__)
   std::string prefix_win32;
   if(!prefix)
@@ -270,6 +275,19 @@ void cmLocalGenerator::GenerateInstallRules()
     }
 #endif
 
+  // Compute the set of configurations.
+  std::vector<std::string> configurationTypes;
+  if(const char* types = m_Makefile->GetDefinition("CMAKE_CONFIGURATION_TYPES"))
+    {
+    cmSystemTools::ExpandListArgument(types, configurationTypes);
+    }
+  const char* config = 0;
+  if(configurationTypes.empty())
+    {
+    config = m_Makefile->GetDefinition("CMAKE_BUILD_TYPE");
+    }
+
+  // Create the install script file.
   std::string file = m_Makefile->GetStartOutputDirectory();
   std::string homedir = m_Makefile->GetHomeOutputDirectory();
   std::string currdir = m_Makefile->GetCurrentOutputDirectory();
@@ -285,25 +303,16 @@ void cmLocalGenerator::GenerateInstallRules()
   cmGeneratedFileStream fout(file.c_str());
   fout.SetCopyIfDifferent(true);
 
-  fout << "# Install script for directory: " << m_Makefile->GetCurrentDirectory() 
-    << std::endl << std::endl;
+  // Write the header.
+  fout << "# Install script for directory: "
+       << m_Makefile->GetCurrentDirectory() << std::endl << std::endl;
   fout << "# Set the install prefix" << std::endl
     << "IF(NOT CMAKE_INSTALL_PREFIX)" << std::endl
     << "  SET(CMAKE_INSTALL_PREFIX \"" << prefix << "\")" << std::endl
     << "ENDIF(NOT CMAKE_INSTALL_PREFIX)" << std::endl
     << std::endl;
 
-  std::vector<std::string> configurationTypes;
-  if(const char* types = m_Makefile->GetDefinition("CMAKE_CONFIGURATION_TYPES"))
-    {
-    cmSystemTools::ExpandListArgument(types, configurationTypes);
-    }
-  const char* config = 0;
-  if(configurationTypes.empty())
-    {
-    config = m_Makefile->GetDefinition("CMAKE_BUILD_TYPE");
-    }
-
+  // Write support code for generating per-configuration install rules.
   fout <<
     "# Set the install configuration name.\n"
     "IF(NOT CMAKE_INSTALL_CONFIG_NAME)\n"
@@ -317,250 +326,19 @@ void cmLocalGenerator::GenerateInstallRules()
     "ENDIF(NOT CMAKE_INSTALL_CONFIG_NAME)\n"
     "\n";
 
-  std::string libOutPath = "";
-  if (m_Makefile->GetDefinition("LIBRARY_OUTPUT_PATH"))
+  // Ask each install generator to write its code.
+  std::vector<cmInstallGenerator*> const& installers =
+    m_Makefile->GetInstallGenerators();
+  for(std::vector<cmInstallGenerator*>::const_iterator gi = installers.begin();
+      gi != installers.end(); ++gi)
     {
-    libOutPath = m_Makefile->GetDefinition("LIBRARY_OUTPUT_PATH");
-    if(libOutPath.size())
-      {
-      if(libOutPath[libOutPath.size() -1] != '/')
-        {
-        libOutPath += "/";
-        }
-      }
-    }
-
-  std::string exeOutPath = "";
-  if (m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH"))
-    {
-    exeOutPath =
-      m_Makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH");
-    if(exeOutPath.size())
-      {
-      if(exeOutPath[exeOutPath.size() -1] != '/')
-        {
-        exeOutPath += "/";
-        }
-      }
-    }
-  if ( libOutPath.size() == 0 )
-    {
-    // LIBRARY_OUTPUT_PATH not defined
-    libOutPath = currdir + "/";
-    }
-  if ( exeOutPath.size() == 0 )
-    {
-    // EXECUTABLE_OUTPUT_PATH not defined
-    exeOutPath = currdir + "/";
-    }
-  std::string relinkDir = currdir + "/CMakeFiles/CMakeRelink.dir/";
-
-  // Include user-specified install scripts.
-  std::vector<std::string> const& installScripts =
-    m_Makefile->GetInstallScripts();
-  for(std::vector<std::string>::const_iterator s = installScripts.begin();
-      s != installScripts.end(); ++s)
-    {
-    fout << "INCLUDE(\"" << s->c_str() << "\")" << std::endl;
+    (*gi)->Generate(fout, config, configurationTypes);
     }
 
-  std::string destination;
-  for(cmTargets::iterator l = tgts.begin(); 
-    l != tgts.end(); l++)
-    {
-    const char* preinstall = l->second.GetProperty("PRE_INSTALL_SCRIPT");
-    const char* postinstall = l->second.GetProperty("POST_INSTALL_SCRIPT");
-    if ( preinstall )
-      {
-      fout << "INCLUDE(\"" << preinstall << "\")" << std::endl;
-      }
-    if (l->second.GetInstallPath() != "")
-      {
-      bool need_relink = l->second.NeedRelinkBeforeInstall();
-      destination = "${CMAKE_INSTALL_PREFIX}" + l->second.GetInstallPath();
-      if(destination[destination.size()-1] == '/')
-        {
-        destination = destination.substr(0, destination.size()-1);
-        }
-      cmSystemTools::ConvertToUnixSlashes(destination);
-      const char* dest = destination.c_str();
-      int type = l->second.GetType();
-      std::string fname;
-      std::string props;
-      const char* properties = 0;
-      const char* files;
-
-      this->PrepareInstallReference(fout, l->second, configurationTypes);
-
-      // now install the target
-      switch (type)
-        {
-        case cmTarget::SHARED_LIBRARY:
-          {
-          // Special code to handle DLL
-          fname = l->second.GetFullName();
-          std::string ext = cmSystemTools::GetFilenameLastExtension(fname);
-          ext = cmSystemTools::LowerCase(ext);
-          if ( ext == ".dll" )
-            {
-            // Install the .lib separately.
-            std::string libname = need_relink? relinkDir : libOutPath;
-            libname += this->GetInstallReference(l->second, config,
-                                                 configurationTypes,
-                                                 true);
-            files = libname.c_str();
-            this->AddInstallRule(fout, dest, cmTarget::STATIC_LIBRARY, files, true);
-
-            // Change the destination to the .dll destination.
-            destination = "${CMAKE_INSTALL_PREFIX}" + l->second.GetRuntimeInstallPath();
-            if(destination[destination.size()-1] == '/')
-              {
-              destination = destination.substr(0, destination.size()-1);
-              }
-            dest = destination.c_str();
-            }
-          else
-            {
-            // Add shared library installation properties.
-            const char* lib_version = l->second.GetProperty("VERSION");
-            const char* lib_soversion = l->second.GetProperty("SOVERSION");
-            if(!m_Makefile->GetDefinition("CMAKE_SHARED_LIBRARY_SONAME_C_FLAG"))
-              {
-              // Versioning is supported only for shared libraries and modules,
-              // and then only when the platform supports an soname flag.
-              lib_version = 0;
-              lib_soversion = 0;
-              }
-            if ( lib_version )
-              {
-              props += " VERSION ";
-              props += lib_version;
-              }
-            if ( lib_soversion )
-              {
-              props += " SOVERSION ";
-              props += lib_soversion;
-              }
-            properties = props.c_str();
-            }
-          }
-          /* No "break;" because we want to install the library here.  */
-        case cmTarget::STATIC_LIBRARY:
-        case cmTarget::MODULE_LIBRARY:
-          {
-          fname = need_relink? relinkDir : libOutPath;
-          fname += this->GetInstallReference(l->second, config,
-                                             configurationTypes);
-          files = fname.c_str();
-          this->AddInstallRule(fout, dest, type, files, false, properties);
-          }
-          break;
-        case cmTarget::EXECUTABLE:
-          {
-#if defined(_WIN32) && !defined(__CYGWIN__)
-          const char* exe_version = 0;
-#else
-          const char* exe_version = l->second.GetProperty("VERSION");
-#endif
-          if(exe_version)
-            {
-            props += " VERSION ";
-            props += exe_version;
-            properties = props.c_str();
-            }
-          std::string exeName =
-            this->GetInstallReference(l->second, config, configurationTypes);
-          fname = need_relink? relinkDir : exeOutPath;
-          fname += exeName;
-          if(l->second.GetPropertyAsBool("MACOSX_BUNDLE"))
-            {
-            std::string plist = fname;
-            plist += ".app/Contents/Info.plist";
-            fname += ".app/Contents/MacOS/";
-            fname += exeName;
-            files = fname.c_str();
-            std::string bdest = dest;
-            bdest += "/";
-            bdest += exeName;
-            std::string pdest = bdest;
-            pdest += ".app/Contents";
-            bdest += ".app/Contents/MacOS";
-            // first install the actual executable
-            this->AddInstallRule(fout, bdest.c_str(), type, files,
-                                 false, properties);
-            files = plist.c_str();
-            // now install the Info.plist file
-            this->AddInstallRule(fout, pdest.c_str(),
-                                 cmTarget::INSTALL_FILES, files);
-            }
-          else
-            {
-            files = fname.c_str();
-            this->AddInstallRule(fout, dest, type, files, false,
-                                 properties);
-            }
-          }
-          break;
-        case cmTarget::INSTALL_FILES:
-          {
-          std::string sourcePath = m_Makefile->GetCurrentDirectory();
-          std::string binaryPath = m_Makefile->GetCurrentOutputDirectory();
-          sourcePath += "/";
-          binaryPath += "/";
-          const std::vector<std::string> &sf = l->second.GetSourceLists();
-          std::vector<std::string>::const_iterator i;
-          for (i = sf.begin(); i != sf.end(); ++i)
-            {
-            std::string f = *i;
-            if(f.substr(0, sourcePath.length()) == sourcePath)
-              {
-              f = f.substr(sourcePath.length());
-              }
-            else if(f.substr(0, binaryPath.length()) == binaryPath)
-              {
-              f = f.substr(binaryPath.length());
-              }
-
-            files = i->c_str();
-            this->AddInstallRule(fout, dest, type, files);
-            }
-          }
-          break;
-        case cmTarget::INSTALL_PROGRAMS:
-          {
-          std::string sourcePath = m_Makefile->GetCurrentDirectory();
-          std::string binaryPath = m_Makefile->GetCurrentOutputDirectory();
-          sourcePath += "/";
-          binaryPath += "/";
-          const std::vector<std::string> &sf = l->second.GetSourceLists();
-          std::vector<std::string>::const_iterator i;
-          for (i = sf.begin(); i != sf.end(); ++i)
-            {
-            std::string f = *i;
-            if(f.substr(0, sourcePath.length()) == sourcePath)
-              {
-              f = f.substr(sourcePath.length());
-              }
-            else if(f.substr(0, binaryPath.length()) == binaryPath)
-              {
-              f = f.substr(binaryPath.length());
-              }
-            files = i->c_str();
-            this->AddInstallRule(fout, dest, type, files);
-            }
-          }
-          break;
-        case cmTarget::UTILITY:
-        default:
-          break;
-        }
-      }
-    if ( postinstall )
-      {
-      fout << "INCLUDE(\"" << postinstall << "\")" << std::endl;
-      }
-    }
+  // Write rules from old-style specification stored in targets.
+  this->GenerateTargetInstallRules(fout, config, configurationTypes);
 
+  // Include install scripts from subdirectories.
   if ( this->Children.size())
     {
     std::vector<cmLocalGenerator*>::const_iterator i = this->Children.begin();
@@ -573,6 +351,8 @@ void cmLocalGenerator::GenerateInstallRules()
       }
     fout << std::endl;;
     }
+
+  // Record the install manifest.
   if ( toplevel_install )
     {
     fout << "FILE(WRITE \"" << homedir.c_str() << "/install_manifest.txt\" "
@@ -584,36 +364,6 @@ void cmLocalGenerator::GenerateInstallRules()
     }
 }
 
-void cmLocalGenerator::AddInstallRule(std::ostream& fout, const char* dest, 
-  int type, const char* files, bool optional /* = false */, const char* properties /* = 0 */)
-{
-  std::string sfiles = files;
-  std::string destination = dest;
-  std::string stype;
-  switch ( type )
-    {
-  case cmTarget::INSTALL_PROGRAMS: stype = "PROGRAM"; break;
-  case cmTarget::EXECUTABLE: stype = "EXECUTABLE"; break;
-  case cmTarget::STATIC_LIBRARY:   stype = "STATIC_LIBRARY"; break;
-  case cmTarget::SHARED_LIBRARY:   stype = "SHARED_LIBRARY"; break;
-  case cmTarget::MODULE_LIBRARY:   stype = "MODULE"; break;
-  case cmTarget::INSTALL_FILES:
-  default:                         stype = "FILE"; break;
-    }
-  std::string fname = cmSystemTools::GetFilenameName(sfiles.c_str());
-  fout 
-    << "MESSAGE(STATUS \"Installing " << destination.c_str() 
-    << "/" << fname.c_str() << "\")\n" 
-    << "FILE(INSTALL DESTINATION \"" << destination.c_str() 
-    << "\" TYPE " << stype.c_str() << (optional?" OPTIONAL":"") ;
-  if ( properties && *properties )
-    {
-    fout << " PROPERTIES" << properties;
-    }
-  fout
-    << " FILES \"" << sfiles.c_str() << "\")\n";
-}
-
 void cmLocalGenerator::AddCustomCommandToCreateObject(const char* ofname, 
                                                       const char* lang, 
                                                       cmSourceFile& source,
@@ -1632,78 +1382,6 @@ cmLocalGenerator::ComputeLinkInformation(cmTarget& target,
     }
 }
 
-//----------------------------------------------------------------------------
-std::string
-cmLocalGenerator::GetInstallReference(cmTarget& target, const char* config,
-                                      std::vector<std::string> const& configs,
-                                      bool implib /* = false*/)
-{
-  if(configs.empty())
-    {
-    std::string ref = target.GetFullName(config);
-    if(implib)
-      {
-      ref = cmSystemTools::GetFilenameWithoutLastExtension(ref);
-      ref += ".lib";
-      }
-    return ref;
-    }
-  else
-    {
-    std::string ref = "${";
-    ref += target.GetName();
-    if(implib)
-      {
-      ref += "_LIBNAME_";
-      }
-    else
-      {
-      ref += "_NAME_";
-      }
-    ref += "${CMAKE_INSTALL_CONFIG_NAME}}";
-    return ref;
-    }
-}
-
-//----------------------------------------------------------------------------
-void
-cmLocalGenerator
-::PrepareInstallReference(std::ostream& fout, cmTarget& target,
-                          std::vector<std::string> const& configs)
-{
-  // If the target name may vary with the configuration type then
-  // store all possible names ahead of time in variables.
-  cmTarget::TargetType type = target.GetType();
-  if(type == cmTarget::SHARED_LIBRARY ||
-     type == cmTarget::STATIC_LIBRARY ||
-     type == cmTarget::MODULE_LIBRARY ||
-     type == cmTarget::EXECUTABLE)
-    {
-    std::string fname;
-    for(std::vector<std::string>::const_iterator i = configs.begin();
-        i != configs.end(); ++i)
-      {
-      // Set a variable with the target name for this
-      // configuration.
-      fname = target.GetFullName(i->c_str());
-      fout << "SET(" << target.GetName() << "_NAME_" << *i
-           << " \"" << fname << "\")\n";
-
-#ifdef _WIN32
-      // If the target is a .dll then add the corresponding .lib
-      // name in its own variable.
-      if(type == cmTarget::SHARED_LIBRARY)
-        {
-        fname = cmSystemTools::GetFilenameWithoutExtension(fname);
-        fname += ".lib";
-        fout << "SET(" << target.GetName() << "_LIBNAME_" << *i
-             << " \"" << fname << "\")\n";
-        }
-#endif
-      }
-    }
-}
-
 //----------------------------------------------------------------------------
 void cmLocalGenerator::AddLanguageFlags(std::string& flags,
                                                      const char* lang)
@@ -1938,3 +1616,128 @@ std::string cmLocalGenerator::Convert(const char* source,
     }
   return result;
 }
+
+//----------------------------------------------------------------------------
+void
+cmLocalGenerator
+::GenerateTargetInstallRules(
+  std::ostream& os, const char* config,
+  std::vector<std::string> const& configurationTypes)
+{
+  // Convert the old-style install specification from each target to
+  // an install generator and run it.
+  cmTargets& tgts = m_Makefile->GetTargets();
+  for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); ++l)
+    {
+    // Include the user-specified pre-install script for this target.
+    if(const char* preinstall = l->second.GetProperty("PRE_INSTALL_SCRIPT"))
+      {
+      cmInstallScriptGenerator g(preinstall);
+      g.Generate(os, config, configurationTypes);
+      }
+
+    // Install this target if a destination is given.
+    if(l->second.GetInstallPath() != "")
+      {
+      // Compute the full install destination.  Note that converting
+      // to unix slashes also removes any trailing slash.
+      std::string destination = "${CMAKE_INSTALL_PREFIX}";
+      destination += l->second.GetInstallPath();
+      cmSystemTools::ConvertToUnixSlashes(destination);
+
+      // Generate the proper install generator for this target type.
+      switch(l->second.GetType())
+        {
+        case cmTarget::EXECUTABLE:
+        case cmTarget::STATIC_LIBRARY:
+        case cmTarget::MODULE_LIBRARY:
+          {
+          // Use a target install generator.
+          cmInstallTargetGenerator g(l->second, destination.c_str(), false);
+          g.Generate(os, config, configurationTypes);
+          }
+          break;
+        case cmTarget::SHARED_LIBRARY:
+          {
+#if defined(_WIN32) || defined(__CYGWIN__)
+          // Special code to handle DLL.  Install the import library
+          // to the normal destination and the DLL to the runtime
+          // destination.
+          cmInstallTargetGenerator g1(l->second, destination.c_str(), true);
+          g1.Generate(os, config, configurationTypes);
+          destination = "${CMAKE_INSTALL_PREFIX}";
+          destination += l->second.GetRuntimeInstallPath();
+          cmSystemTools::ConvertToUnixSlashes(destination);
+          cmInstallTargetGenerator g2(l->second, destination.c_str(), false);
+          g2.Generate(os, config, configurationTypes);
+#else
+          // Use a target install generator.
+          cmInstallTargetGenerator g(l->second, destination.c_str(), false);
+          g.Generate(os, config, configurationTypes);
+#endif
+          }
+          break;
+        case cmTarget::INSTALL_FILES:
+          {
+          std::string sourcePath = m_Makefile->GetCurrentDirectory();
+          std::string binaryPath = m_Makefile->GetCurrentOutputDirectory();
+          sourcePath += "/";
+          binaryPath += "/";
+          const std::vector<std::string> &sf = l->second.GetSourceLists();
+          std::vector<std::string>::const_iterator i;
+          for (i = sf.begin(); i != sf.end(); ++i)
+            {
+            std::string f = *i;
+            if(f.substr(0, sourcePath.length()) == sourcePath)
+              {
+              f = f.substr(sourcePath.length());
+              }
+            else if(f.substr(0, binaryPath.length()) == binaryPath)
+              {
+              f = f.substr(binaryPath.length());
+              }
+            cmInstallGenerator::AddInstallRule(os, destination.c_str(),
+                                               cmTarget::INSTALL_FILES,
+                                               i->c_str());
+            }
+          }
+          break;
+        case cmTarget::INSTALL_PROGRAMS:
+          {
+          std::string sourcePath = m_Makefile->GetCurrentDirectory();
+          std::string binaryPath = m_Makefile->GetCurrentOutputDirectory();
+          sourcePath += "/";
+          binaryPath += "/";
+          const std::vector<std::string> &sf = l->second.GetSourceLists();
+          std::vector<std::string>::const_iterator i;
+          for (i = sf.begin(); i != sf.end(); ++i)
+            {
+            std::string f = *i;
+            if(f.substr(0, sourcePath.length()) == sourcePath)
+              {
+              f = f.substr(sourcePath.length());
+              }
+            else if(f.substr(0, binaryPath.length()) == binaryPath)
+              {
+              f = f.substr(binaryPath.length());
+              }
+            cmInstallGenerator::AddInstallRule(os, destination.c_str(),
+                                               cmTarget::INSTALL_PROGRAMS,
+                                               i->c_str());
+            }
+          }
+          break;
+        case cmTarget::UTILITY:
+        default:
+          break;
+        }
+      }
+
+    // Include the user-specified post-install script for this target.
+    if(const char* postinstall = l->second.GetProperty("POST_INSTALL_SCRIPT"))
+      {
+      cmInstallScriptGenerator g(postinstall);
+      g.Generate(os, config, configurationTypes);
+      }
+    }
+}

+ 5 - 10
Source/cmLocalGenerator.h

@@ -177,14 +177,6 @@ protected:
   ///! put all the libraries for a target on into the given stream
   virtual void OutputLinkLibraries(std::ostream&, cmTarget&, bool relink);
 
-  /** Compute the string to use to refer to a target in an install
-      file.  */
-  std::string GetInstallReference(cmTarget& target, const char* config,
-                                  std::vector<std::string> const& configs,
-                                  bool implib = false);
-  void PrepareInstallReference(std::ostream& fout, cmTarget& target,
-                               std::vector<std::string> const& configs);
-
   /** Get the include flags for the current makefile and language.  */
   void GetIncludeDirectories(std::vector<std::string>& dirs);
 
@@ -226,8 +218,11 @@ protected:
   // of the types listed will be compiled as custom commands and added
   // to a custom target.
   void CreateCustomTargetsAndCommands(std::set<cmStdString> const&);
-  virtual void AddInstallRule(std::ostream& fout, const char* dest, int type, 
-    const char* files, bool optional = false, const char* properties = 0);
+
+  // Handle old-style install rules stored in the targets.
+  void GenerateTargetInstallRules(
+    std::ostream& os, const char* config,
+    std::vector<std::string> const& configurationTypes);
 
   cmMakefile *m_Makefile;
   cmGlobalGenerator *m_GlobalGenerator;

+ 8 - 0
Source/cmMakefile.cxx

@@ -15,6 +15,7 @@
 
 =========================================================================*/
 #include "cmMakefile.h"
+
 #include "cmCommand.h"
 #include "cmSourceFile.h"
 #include "cmSystemTools.h"
@@ -29,6 +30,7 @@
 #ifdef CMAKE_BUILD_WITH_CMAKE
 #  include "cmVariableWatch.h"
 #endif
+#include "cmInstallGenerator.h"
 #include "cmake.h"
 #include <stdlib.h> // required for atoi
 
@@ -125,6 +127,12 @@ unsigned int cmMakefile::GetCacheMinorVersion()
 
 cmMakefile::~cmMakefile()
 {
+  for(std::vector<cmInstallGenerator*>::iterator
+        i = m_InstallGenerators.begin();
+      i != m_InstallGenerators.end(); ++i)
+    {
+    delete *i;
+    }
   for(std::vector<cmSourceFile*>::iterator i = m_SourceFiles.begin();
       i != m_SourceFiles.end(); ++i)
     {

+ 6 - 7
Source/cmMakefile.h

@@ -28,6 +28,7 @@
 
 class cmFunctionBlocker;
 class cmCommand;
+class cmInstallGenerator;
 class cmLocalGenerator;
 class cmMakeDepend;
 class cmSourceFile;
@@ -672,11 +673,10 @@ public:
   void SetPreOrder(bool p) { this->PreOrder = p; }
   bool GetPreOrder() { return this->PreOrder; }
 
-  /** Add a script file to be invoked during installation.  */
-  void AddInstallScript(const char* script)
-    { m_InstallScripts.push_back(script); }
-  std::vector<std::string> const& GetInstallScripts()
-    { return m_InstallScripts; }
+  void AddInstallGenerator(cmInstallGenerator* g)
+    { m_InstallGenerators.push_back(g); }
+  std::vector<cmInstallGenerator*>& GetInstallGenerators()
+    { return m_InstallGenerators; }
 protected:
   // add link libraries and directories to the target
   void AddGlobalLinkInformation(const char* name, cmTarget& target);
@@ -709,8 +709,7 @@ protected:
   
   cmTarget::LinkLibraries m_LinkLibraries;
 
-  // List of install-time scripts.  This should not be inherited.
-  std::vector<std::string> m_InstallScripts;
+  std::vector<cmInstallGenerator*> m_InstallGenerators;
 
   std::string m_IncludeFileRegularExpression;
   std::string m_ComplainFileRegularExpression;

+ 23 - 13
Source/cmSetTargetPropertiesCommand.h

@@ -58,17 +58,25 @@ public:
         "Set properties on a target. The syntax for the command is to "
         "list all the files you want "
         "to change, and then provide the values you want to set next.  "
-        "Properties that cmake knows about are PREFIX and SUFFIX for UNIX "
-        "systems and libraries.   CMake also knows about LINK_FLAGS, which "
-        "can be used to add extra flags to the link step of a target. "
+        "You can use any prop value pair you want and "
+        "extract it later with the GET_TARGET_PROPERTY command.\n"
+        "Properties that affect the name of a target's output file are "
+        "as follows.  "
+        "The PREFIX and SUFFIX properties override the default target name "
+        "prefix (such as \"lib\") and suffix (such as \".so\"). "
+        "IMPORT_PREFIX and IMPORT_SUFFIX are the equivalent properties for "
+        "the import library corresponding to a DLL "
+        "(for SHARED library targets).  "
+        "OUTPUT_NAME sets the real name of a target when it is built and "
+        "can be used to help create two targets of the same name even though "
+        "CMake requires unique logical target names.\n"
+        "The LINK_FLAGS property can be used to add extra flags to the "
+        "link step of a target. "
         "DEFINE_SYMBOL sets the name of the preprocessor symbol defined when "
         "compiling sources in a shared library. "
         "If not set here then it is set to target_EXPORTS by default "
         "(with some substitutions if the target is not a valid C "
-        "identifier). "
-        "PRE_INSTALL_SCRIPT specifies a CMake script that is run "
-        "prior to installing the target. POST_INSTALL_SCRIPT specifies "
-        "a CMake script that is run after target is installed. "
+        "identifier).\n"
         "For shared libraries VERSION and SOVERSION can be used to specify "
         "the build version and api version respectively. When building or "
         "installing appropriate symlinks are created if the platform "
@@ -77,9 +85,7 @@ public:
         "the same version number. "
         "For executables VERSION can be used to specify the build version. "
         "When building or installing appropriate symlinks are created if "
-        "the platform supports symlinks. "
-        "The OUTPUT_NAME can be used to set an output name that is "
-        "used in place of the target name when creating executables.\n"
+        "the platform supports symlinks.\n"
         "There are a few properties used to specify RPATH rules. "
         "INSTALL_RPATH is a semicolon-separated list specifying the rpath "
         "to use in installed targets (for platforms that support it). "
@@ -96,9 +102,13 @@ public:
         "PROJECT_LABEL can be used to change the name of "
         "the target in an IDE like visual studio.  VS_KEYWORD can be set "
         "to change the visual studio keyword, for example QT integration "
-        "works better if this is set to Qt4VSv1.0. "
-        "You can use any prop value pair you want and "
-        "extract it later with the GET_TARGET_PROPERTY command.";
+        "works better if this is set to Qt4VSv1.0.\n"
+        "The PRE_INSTALL_SCRIPT and POST_INSTALL_SCRIPT properties are the "
+        "old way to specify CMake scripts to run before and after "
+        "installing a target.  They are used only when the old "
+        "INSTALL_TARGETS command is used to install the target.  Use the "
+        "INSTALL command instead."
+        ;
     }
   
   cmTypeMacro(cmSetTargetPropertiesCommand, cmCommand);

+ 2 - 2
Tests/SimpleInstall/CMakeLists.txt

@@ -83,8 +83,8 @@ ELSE(STAGE2)
   ADD_DEPENDENCIES(test2 test3)
   ADD_DEPENDENCIES(test4 test2)
 
-  INSTALL_TARGETS(/bin SimpleInstall)
-  INSTALL_TARGETS(/lib test1 test2 test3 test4)
+  INSTALL(TARGETS SimpleInstall test1 test2 test3 test4
+          RUNTIME DESTINATION bin LIBRARY DESTINATION lib)
   INSTALL_FILES(/include FILES lib1.h lib2.h lib3.h)
 
   # Test user-specified install scripts.

+ 2 - 2
Tests/SimpleInstallS2/CMakeLists.txt

@@ -83,8 +83,8 @@ ELSE(STAGE2)
   ADD_DEPENDENCIES(test2 test3)
   ADD_DEPENDENCIES(test4 test2)
 
-  INSTALL_TARGETS(/bin SimpleInstall)
-  INSTALL_TARGETS(/lib test1 test2 test3 test4)
+  INSTALL(TARGETS SimpleInstall test1 test2 test3 test4
+          RUNTIME DESTINATION bin LIBRARY DESTINATION lib)
   INSTALL_FILES(/include FILES lib1.h lib2.h lib3.h)
 
   # Test user-specified install scripts.

+ 3 - 0
bootstrap

@@ -97,6 +97,9 @@ CMAKE_CXX_SOURCES="\
   cmGlobalGenerator \
   cmGlob \
   cmLocalGenerator \
+  cmInstallGenerator \
+  cmInstallScriptGenerator \
+  cmInstallTargetGenerator \
   cmSourceFile \
   cmSystemTools \
   cmFileTimeComparison \