Browse Source

ENH: Improve exporting/importing of targets

  - Use real name instead of link for location of versioned targets
  - Error when a target is exported multiple times
Brad King 18 years ago
parent
commit
9e64d5b272

+ 25 - 4
Source/cmExportBuildFileGenerator.cxx

@@ -33,8 +33,20 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
       tei != this->Exports->end(); ++tei)
     {
     cmTarget* te = *tei;
-    this->ExportedTargets.insert(te);
-    this->GenerateImportTargetCode(os, te);
+    if(this->ExportedTargets.insert(te).second)
+      {
+      this->GenerateImportTargetCode(os, te);
+      }
+    else
+      {
+      if(this->ExportCommand && this->ExportCommand->ErrorMessage.empty())
+        {
+        cmOStringStream e;
+        e << "given target \"" << te->GetName() << "\" more than once.";
+        this->ExportCommand->ErrorMessage = e.str();
+        }
+      return false;
+      }
     }
 
   // Generate import file content for each configuration.
@@ -93,12 +105,21 @@ cmExportBuildFileGenerator
   {
   std::string prop = "IMPORTED_LOCATION";
   prop += suffix;
-  std::string value = target->GetFullPath(config, false);
-  if(target->IsAppBundleOnApple())
+  std::string value;
+  if(target->IsFrameworkOnApple())
     {
+    value = target->GetFullPath(config, false);
+    }
+  else if(target->IsAppBundleOnApple())
+    {
+    value = target->GetFullPath(config, false);
     value += ".app/Contents/MacOS/";
     value += target->GetFullName(config, false);
     }
+  else
+    {
+    value = target->GetFullPath(config, false, true);
+    }
   properties[prop] = value;
   }
 

+ 1 - 1
Source/cmExportCommand.cxx

@@ -169,7 +169,7 @@ bool cmExportCommand
     }
 
   // Generate the import file.
-  if(!ebfg.GenerateImportFile())
+  if(!ebfg.GenerateImportFile() && this->ErrorMessage.empty())
     {
     this->SetError("could not write export file.");
     return false;

+ 52 - 22
Source/cmExportInstallFileGenerator.cxx

@@ -36,8 +36,19 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
       tei != this->ExportSet->end(); ++tei)
     {
     cmTargetExport* te = *tei;
-    this->ExportedTargets.insert(te->Target);
-    this->GenerateImportTargetCode(os, te->Target);
+    if(this->ExportedTargets.insert(te->Target).second)
+      {
+      this->GenerateImportTargetCode(os, te->Target);
+      }
+    else
+      {
+      cmOStringStream e;
+      e << "INSTALL(EXPORT \"" << this->Name << "\" ...) "
+        << "includes target \"" << te->Target->GetName()
+        << "\" more than once in the export set.";
+      cmSystemTools::Error(e.str().c_str());
+      return false;
+      }
     }
 
   // Now load per-configuration properties for them.
@@ -204,11 +215,8 @@ cmExportInstallFileGenerator
     return;
     }
 
-  {
-  // Construct the property name.
-  std::string prop = (itgen->IsImportLibrary()?
-                      "IMPORTED_IMPLIB" : "IMPORTED_LOCATION");
-  prop += suffix;
+  // Get the target to be installed.
+  cmTarget* target = itgen->GetTarget();
 
   // Construct the installed location of the target.
   std::string dest = itgen->GetDestination();
@@ -225,25 +233,47 @@ cmExportInstallFileGenerator
   value += dest;
   value += "/";
 
-  // Append the installed file name.
-  std::string fname = itgen->GetInstallFilename(config);
-  value += fname;
-
-  // Fix name for frameworks and bundles.
-  if(itgen->GetTarget()->IsFrameworkOnApple())
+  if(itgen->IsImportLibrary())
     {
-    value += ".framework/";
-    value += fname;
+    // Construct the property name.
+    std::string prop = "IMPORTED_IMPLIB";
+    prop += suffix;
+
+    // Append the installed file name.
+    value += itgen->GetInstallFilename(target, config,
+                                       cmInstallTargetGenerator::NameImplib);
+
+    // Store the property.
+    properties[prop] = value;
     }
-  else if(itgen->GetTarget()->IsAppBundleOnApple())
+  else
     {
-    value += ".app/Contents/MacOS/";
-    value += fname;
-    }
+    // Construct the property name.
+    std::string prop = "IMPORTED_LOCATION";
+    prop += suffix;
 
-  // Store the property.
-  properties[prop] = value;
-  }
+    // Append the installed file name.
+    if(target->IsFrameworkOnApple())
+      {
+      value += itgen->GetInstallFilename(target, config);
+      value += ".framework/";
+      value += itgen->GetInstallFilename(target, config);
+      }
+    else if(target->IsAppBundleOnApple())
+      {
+      value += itgen->GetInstallFilename(target, config);
+      value += ".app/Contents/MacOS/";
+      value += itgen->GetInstallFilename(target, config);
+      }
+    else
+      {
+      value += itgen->GetInstallFilename(target, config,
+                                         cmInstallTargetGenerator::NameReal);
+      }
+
+    // Store the property.
+    properties[prop] = value;
+    }
 }
 
 //----------------------------------------------------------------------------

+ 11 - 2
Source/cmInstallCommand.cxx

@@ -394,6 +394,9 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
     cmInstallFilesGenerator* publicHeaderGenerator = 0;
     cmInstallFilesGenerator* resourceGenerator = 0;
 
+    // Track whether this is a namelink-only rule.
+    bool namelinkOnly = false;
+
     switch(target.GetType())
       {
       case cmTarget::SHARED_LIBRARY:
@@ -464,6 +467,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
               libraryGenerator = CreateInstallTargetGenerator(target, 
                                                            libraryArgs, false);
               libraryGenerator->SetNamelinkMode(namelinkMode);
+              namelinkOnly =
+                (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
               }
             else
               {
@@ -503,6 +508,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
           libraryGenerator = CreateInstallTargetGenerator(target, libraryArgs, 
                                                           false);
           libraryGenerator->SetNamelinkMode(namelinkMode);
+          namelinkOnly =
+            (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
           }
         else
           {
@@ -583,7 +590,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
     createInstallGeneratorsForTargetFileSets = false;
     }
 
-  if(createInstallGeneratorsForTargetFileSets)
+  if(createInstallGeneratorsForTargetFileSets && !namelinkOnly)
     {
     const char* files = target.GetProperty("PRIVATE_HEADER");
     if ((files) && (*files))
@@ -673,7 +680,9 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
     this->Makefile->AddInstallGenerator(publicHeaderGenerator);
     this->Makefile->AddInstallGenerator(resourceGenerator);
 
-    if (!exports.GetString().empty())
+    // Add this install rule to an export if one was specified and
+    // this is not a namelink-only rule.
+    if(!exports.GetString().empty() && !namelinkOnly)
       {
       this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
         ->AddTargetToExports(exports.GetCString(), &target, 

+ 23 - 14
Source/cmInstallTargetGenerator.cxx

@@ -144,10 +144,10 @@ cmInstallTargetGenerator
                              Indent const& indent)
 {
   // Compute the full path to the main installed file for this target.
+  NameType nameType = this->ImportLibrary? NameImplib : NameNormal;
   std::string toInstallPath = this->GetInstallDestination();
   toInstallPath += "/";
-  toInstallPath += this->GetInstallFilename(this->Target, config,
-                                              this->ImportLibrary, false);
+  toInstallPath += this->GetInstallFilename(this->Target, config, nameType);
 
   // Track whether post-install operations should be added to the
   // script.
@@ -194,8 +194,8 @@ cmInstallTargetGenerator
         // Need to apply install_name_tool and stripping to binary
         // inside bundle.
         toInstallPath += ".app/Contents/MacOS/";
-        toInstallPath += this->GetInstallFilename(this->Target, config,
-                                                  this->ImportLibrary, false);
+        toInstallPath +=
+          this->GetInstallFilename(this->Target, config, nameType);
         literal_args += " USE_SOURCE_PERMISSIONS";
         }
       else
@@ -250,7 +250,7 @@ cmInstallTargetGenerator
       // inside framework.
       toInstallPath += ".framework/";
       toInstallPath += this->GetInstallFilename(this->Target, config,
-                                                this->ImportLibrary, false);
+                                                NameNormal);
 
       literal_args += " USE_SOURCE_PERMISSIONS";
       }
@@ -369,16 +369,16 @@ cmInstallTargetGenerator
 std::string
 cmInstallTargetGenerator::GetInstallFilename(const char* config) const
 {
+  NameType nameType = this->ImportLibrary? NameImplib : NameNormal;
   return
     cmInstallTargetGenerator::GetInstallFilename(this->Target, config,
-                                                 this->ImportLibrary, false);
+                                                 nameType);
 }
 
 //----------------------------------------------------------------------------
 std::string cmInstallTargetGenerator::GetInstallFilename(cmTarget* target,
                                                          const char* config,
-                                                         bool implib,
-                                                         bool useSOName)
+                                                         NameType nameType)
 {
   std::string fname;
   // Compute the name of the library.
@@ -391,11 +391,16 @@ std::string cmInstallTargetGenerator::GetInstallFilename(cmTarget* target,
     target->GetExecutableNames(targetName, targetNameReal,
                                targetNameImport, targetNamePDB,
                                config);
-    if(implib)
+    if(nameType == NameImplib)
       {
       // Use the import library name.
       fname = targetNameImport;
       }
+    else if(nameType == NameReal)
+      {
+      // Use the canonical name.
+      fname = targetNameReal;
+      }
     else
       {
       // Use the canonical name.
@@ -411,16 +416,21 @@ std::string cmInstallTargetGenerator::GetInstallFilename(cmTarget* target,
     std::string targetNamePDB;
     target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
                             targetNameImport, targetNamePDB, config);
-    if(implib)
+    if(nameType == NameImplib)
       {
       // Use the import library name.
       fname = targetNameImport;
       }
-    else if(useSOName)
+    else if(nameType == NameSO)
       {
       // Use the soname.
       fname = targetNameSO;
       }
+    else if(nameType == NameReal)
+      {
+      // Use the real name.
+      fname = targetNameReal;
+      }
     else
       {
       // Use the canonical name.
@@ -474,7 +484,7 @@ cmInstallTargetGenerator
         // The directory portions differ.  Append the filename to
         // create the mapping.
         std::string fname =
-          this->GetInstallFilename(tgt, config, false, true);
+          this->GetInstallFilename(tgt, config, NameSO);
 
         // Map from the build-tree install_name.
         for_build += fname;
@@ -511,8 +521,7 @@ cmInstallTargetGenerator
       {
       // Prepare to refer to the install-tree install_name.
       new_id = for_install;
-      new_id += this->GetInstallFilename(this->Target, config,
-                                         this->ImportLibrary, true);
+      new_id += this->GetInstallFilename(this->Target, config, NameSO);
       }
     }
 

+ 12 - 2
Source/cmInstallTargetGenerator.h

@@ -45,10 +45,20 @@ public:
     NamelinkModeSkip
   };
   void SetNamelinkMode(NamelinkModeType mode) { this->NamelinkMode = mode; }
+  NamelinkModeType GetNamelinkMode() const { return this->NamelinkMode; }
 
   std::string GetInstallFilename(const char* config) const;
-  static std::string GetInstallFilename(cmTarget*target, const char* config, 
-                                        bool implib, bool useSOName);
+
+  enum NameType
+  {
+    NameNormal,
+    NameImplib,
+    NameSO,
+    NameReal
+  };
+
+  static std::string GetInstallFilename(cmTarget*target, const char* config,
+                                        NameType nameType = NameNormal);
 
   cmTarget* GetTarget() const { return this->Target; }
   bool IsImportLibrary() const { return this->ImportLibrary; }

+ 4 - 1
Tests/ExportImport/Export/CMakeLists.txt

@@ -8,6 +8,7 @@ endif(CMAKE_ANSI_CFLAGS)
 add_library(testExe1lib STATIC testExe1lib.c) # not exported
 add_executable(testExe1 testExe1.c)
 target_link_libraries(testExe1 testExe1lib)
+set_property(TARGET testExe1 PROPERTY VERSION 4)
 
 add_library(testExe2libImp SHARED testExe2libImp.c)
 set_property(TARGET testExe2libImp PROPERTY LIBRARY_OUTPUT_DIRECTORY impl)
@@ -27,6 +28,8 @@ set_property(TARGET testLib3Imp PROPERTY LIBRARY_OUTPUT_DIRECTORY impl)
 add_library(testLib3 SHARED testLib3.c)
 target_link_libraries(testLib3 testLib3Imp)
 set_property(TARGET testLib3 PROPERTY LINK_INTERFACE_LIBRARIES "")
+set_property(TARGET testLib3 PROPERTY VERSION 1.2)
+set_property(TARGET testLib3 PROPERTY SOVERSION 3)
 
 add_library(testLib4 SHARED testLib4.c)
 set_property(TARGET testLib4 PROPERTY FRAMEWORK 1)
@@ -41,7 +44,7 @@ install(
   testExe2lib
   EXPORT exp
   RUNTIME DESTINATION bin
-  LIBRARY DESTINATION lib
+  LIBRARY DESTINATION lib NAMELINK_SKIP
   ARCHIVE DESTINATION lib
   FRAMEWORK DESTINATION Frameworks
   BUNDLE DESTINATION Applications