Преглед на файлове

install: add NAMELINK_COMPONENT argument

For shared libraries, this allows you to specify separate components
for the shared library and for the namelink.

Suggested in https://cmake.org/pipermail/cmake-developers/2014-December/024032.html.
Kyle Edwards преди 7 години
родител
ревизия
0212d7c762
променени са 4 файла, в които са добавени 113 реда и са изтрити 15 реда
  1. 51 8
      Help/command/install.rst
  2. 39 7
      Source/cmInstallCommand.cxx
  3. 20 0
      Source/cmInstallCommandArguments.cxx
  4. 3 0
      Source/cmInstallCommandArguments.h

+ 51 - 8
Help/command/install.rst

@@ -103,6 +103,7 @@ Installing Targets
            [PERMISSIONS permissions...]
            [CONFIGURATIONS [Debug|Release|...]]
            [COMPONENT <component>]
+           [NAMELINK_COMPONENT <component>]
            [OPTIONAL] [EXCLUDE_FROM_ALL]
            [NAMELINK_ONLY|NAMELINK_SKIP]
           ] [...]
@@ -167,7 +168,7 @@ just a DLL or just an import library.)
 In addition to the common options listed above, each target can accept
 the following additional arguments:
 
-``NAMELINK_ONLY``
+``NAMELINK_COMPONENT``
   On some platforms a versioned shared library has a symbolic link such
   as::
 
@@ -175,13 +176,51 @@ the following additional arguments:
 
   where ``lib<name>.so.1`` is the soname of the library and ``lib<name>.so``
   is a "namelink" allowing linkers to find the library when given
-  ``-l<name>``. The ``NAMELINK_ONLY`` option causes the installation of only
-  the namelink when a library target is installed. On platforms where
-  versioned shared libraries do not have namelinks or when a library is not
-  versioned, the ``NAMELINK_ONLY`` option installs nothing. It is an error to
-  use this parameter outside of a ``LIBRARY`` block. See the
-  :prop_tgt:`VERSION` and :prop_tgt:`SOVERSION` target properties for details
-  on creating versioned shared libraries.
+  ``-l<name>``. The ``NAMELINK_COMPONENT`` option is similar to the
+  ``COMPONENT`` option, but it changes the installation component of a shared
+  library namelink if one is generated. If not specified, this defaults to the
+  value of ``COMPONENT``. It is an error to use this parameter outside of a
+  ``LIBRARY`` block.
+
+  Consider the following example:
+
+  .. code-block:: cmake
+
+    install(TARGETS mylib
+            LIBRARY
+              DESTINATION lib
+              COMPONENT Libraries
+              NAMELINK_COMPONENT Development
+            PUBLIC_HEADER
+              DESTINATION include
+              COMPONENT Development
+           )
+
+  In this scenario, if you choose to install only the ``Development``
+  component, both the headers and namelink will be installed without the
+  library. (If you don't also install the ``Libraries`` component, the
+  namelink will be a dangling symlink, and projects that link to the library
+  will have build errors.) If you install only the ``Libraries`` component,
+  only the library will be installed, without the headers and namelink.
+
+  This option is typically used for package managers that have separate
+  runtime and development packages. For example, on Debian systems, the
+  library is expected to be in the runtime package, and the headers and
+  namelink are expected to be in the development package.
+
+  See the :prop_tgt:`VERSION` and :prop_tgt:`SOVERSION` target properties for
+  details on creating versioned shared libraries.
+
+``NAMELINK_ONLY``
+  This option causes the installation of only the namelink when a library
+  target is installed. On platforms where versioned shared libraries do not
+  have namelinks or when a library is not versioned, the ``NAMELINK_ONLY``
+  option installs nothing. It is an error to use this parameter outside of a
+  ``LIBRARY`` block.
+
+  When ``NAMELINK_ONLY`` is given, either ``NAMELINK_COMPONENT`` or
+  ``COMPONENT`` may be used to specify the installation component of the
+  namelink, but ``COMPONENT`` should generally be preferred.
 
 ``NAMELINK_SKIP``
   Similar to ``NAMELINK_ONLY``, but it has the opposite effect: it causes the
@@ -192,6 +231,10 @@ the following additional arguments:
   installs the library. It is an error to use this parameter outside of a
   ``LIBRARY`` block.
 
+  If ``NAMELINK_SKIP`` is specified, ``NAMELINK_COMPONENT`` has no effect. It
+  is not recommended to use ``NAMELINK_SKIP`` in conjunction with
+  ``NAMELINK_COMPONENT``.
+
 The ``install(TARGETS)`` command can also accept the following options at the
 top level:
 

+ 39 - 7
Source/cmInstallCommand.cxx

@@ -33,16 +33,17 @@ class cmExecutionStatus;
 
 static cmInstallTargetGenerator* CreateInstallTargetGenerator(
   cmTarget& target, const cmInstallCommandArguments& args, bool impLib,
-  bool forceOpt = false)
+  bool forceOpt = false, bool namelink = false)
 {
   cmInstallGenerator::MessageLevel message =
     cmInstallGenerator::SelectMessageLevel(target.GetMakefile());
   target.SetHaveInstallRule(true);
+  const char* component = namelink ? args.GetNamelinkComponent().c_str()
+                                   : args.GetComponent().c_str();
   return new cmInstallTargetGenerator(
     target.GetName(), args.GetDestination().c_str(), impLib,
-    args.GetPermissions().c_str(), args.GetConfigurations(),
-    args.GetComponent().c_str(), message, args.GetExcludeFromAll(),
-    args.GetOptional() || forceOpt);
+    args.GetPermissions().c_str(), args.GetConfigurations(), component,
+    message, args.GetExcludeFromAll(), args.GetOptional() || forceOpt);
 }
 
 static cmInstallFilesGenerator* CreateInstallFilesGenerator(
@@ -313,6 +314,20 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
       "The NAMELINK_SKIP option may be specified only following LIBRARY.");
     return false;
   }
+  if (archiveArgs.HasNamelinkComponent() ||
+      runtimeArgs.HasNamelinkComponent() ||
+      objectArgs.HasNamelinkComponent() ||
+      frameworkArgs.HasNamelinkComponent() ||
+      bundleArgs.HasNamelinkComponent() ||
+      privateHeaderArgs.HasNamelinkComponent() ||
+      publicHeaderArgs.HasNamelinkComponent() ||
+      resourceArgs.HasNamelinkComponent()) {
+    this->SetError(
+      "TARGETS given NAMELINK_COMPONENT option not in LIBRARY group.  "
+      "The NAMELINK_COMPONENT option may be specified only following "
+      "LIBRARY.");
+    return false;
+  }
   if (libraryArgs.GetNamelinkOnly() && libraryArgs.GetNamelinkSkip()) {
     this->SetError("TARGETS given NAMELINK_ONLY and NAMELINK_SKIP.  "
                    "At most one of these two options may be specified.");
@@ -377,6 +392,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
   // any files of the given type.
   bool installsArchive = false;
   bool installsLibrary = false;
+  bool installsNamelink = false;
   bool installsRuntime = false;
   bool installsObject = false;
   bool installsFramework = false;
@@ -391,6 +407,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
     cmTarget& target = *ti;
     cmInstallTargetGenerator* archiveGenerator = nullptr;
     cmInstallTargetGenerator* libraryGenerator = nullptr;
+    cmInstallTargetGenerator* namelinkGenerator = nullptr;
     cmInstallTargetGenerator* runtimeGenerator = nullptr;
     cmInstallTargetGenerator* objectGenerator = nullptr;
     cmInstallTargetGenerator* frameworkGenerator = nullptr;
@@ -453,9 +470,18 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
           } else {
             // The shared library uses the LIBRARY properties.
             if (!libraryArgs.GetDestination().empty()) {
-              libraryGenerator =
-                CreateInstallTargetGenerator(target, libraryArgs, false);
-              libraryGenerator->SetNamelinkMode(namelinkMode);
+              if (namelinkMode != cmInstallTargetGenerator::NamelinkModeOnly) {
+                libraryGenerator =
+                  CreateInstallTargetGenerator(target, libraryArgs, false);
+                libraryGenerator->SetNamelinkMode(
+                  cmInstallTargetGenerator::NamelinkModeSkip);
+              }
+              if (namelinkMode != cmInstallTargetGenerator::NamelinkModeSkip) {
+                namelinkGenerator = CreateInstallTargetGenerator(
+                  target, libraryArgs, false, false, true);
+                namelinkGenerator->SetNamelinkMode(
+                  cmInstallTargetGenerator::NamelinkModeOnly);
+              }
               namelinkOnly =
                 (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
             } else {
@@ -684,6 +710,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
     // Keep track of whether we're installing anything in each category
     installsArchive = installsArchive || archiveGenerator != nullptr;
     installsLibrary = installsLibrary || libraryGenerator != nullptr;
+    installsNamelink = installsNamelink || namelinkGenerator != nullptr;
     installsRuntime = installsRuntime || runtimeGenerator != nullptr;
     installsObject = installsObject || objectGenerator != nullptr;
     installsFramework = installsFramework || frameworkGenerator != nullptr;
@@ -696,6 +723,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
 
     this->Makefile->AddInstallGenerator(archiveGenerator);
     this->Makefile->AddInstallGenerator(libraryGenerator);
+    this->Makefile->AddInstallGenerator(namelinkGenerator);
     this->Makefile->AddInstallGenerator(runtimeGenerator);
     this->Makefile->AddInstallGenerator(objectGenerator);
     this->Makefile->AddInstallGenerator(frameworkGenerator);
@@ -735,6 +763,10 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
     this->Makefile->GetGlobalGenerator()->AddInstallComponent(
       libraryArgs.GetComponent().c_str());
   }
+  if (installsNamelink) {
+    this->Makefile->GetGlobalGenerator()->AddInstallComponent(
+      libraryArgs.GetNamelinkComponent().c_str());
+  }
   if (installsRuntime) {
     this->Makefile->GetGlobalGenerator()->AddInstallComponent(
       runtimeArgs.GetComponent().c_str());

+ 20 - 0
Source/cmInstallCommandArguments.cxx

@@ -21,6 +21,7 @@ cmInstallCommandArguments::cmInstallCommandArguments(
   , ArgumentGroup()
   , Destination(&Parser, "DESTINATION", &ArgumentGroup)
   , Component(&Parser, "COMPONENT", &ArgumentGroup)
+  , NamelinkComponent(&Parser, "NAMELINK_COMPONENT", &ArgumentGroup)
   , ExcludeFromAll(&Parser, "EXCLUDE_FROM_ALL", &ArgumentGroup)
   , Rename(&Parser, "RENAME", &ArgumentGroup)
   , Permissions(&Parser, "PERMISSIONS", &ArgumentGroup)
@@ -59,6 +60,14 @@ const std::string& cmInstallCommandArguments::GetComponent() const
   return unspecifiedComponent;
 }
 
+const std::string& cmInstallCommandArguments::GetNamelinkComponent() const
+{
+  if (!this->NamelinkComponent.GetString().empty()) {
+    return this->NamelinkComponent.GetString();
+  }
+  return this->GetComponent();
+}
+
 const std::string& cmInstallCommandArguments::GetRename() const
 {
   if (!this->Rename.GetString().empty()) {
@@ -125,6 +134,17 @@ bool cmInstallCommandArguments::GetNamelinkSkip() const
   return false;
 }
 
+bool cmInstallCommandArguments::HasNamelinkComponent() const
+{
+  if (!this->NamelinkComponent.GetString().empty()) {
+    return true;
+  }
+  if (this->GenericArguments != nullptr) {
+    return this->GenericArguments->HasNamelinkComponent();
+  }
+  return false;
+}
+
 const std::vector<std::string>& cmInstallCommandArguments::GetConfigurations()
   const
 {

+ 3 - 0
Source/cmInstallCommandArguments.h

@@ -26,6 +26,7 @@ public:
 
   const std::string& GetDestination() const;
   const std::string& GetComponent() const;
+  const std::string& GetNamelinkComponent() const;
   bool GetExcludeFromAll() const;
   const std::string& GetRename() const;
   const std::string& GetPermissions() const;
@@ -33,6 +34,7 @@ public:
   bool GetOptional() const;
   bool GetNamelinkOnly() const;
   bool GetNamelinkSkip() const;
+  bool HasNamelinkComponent() const;
 
   // once HandleDirectoryMode() is also switched to using
   // cmInstallCommandArguments then these two functions can become non-static
@@ -45,6 +47,7 @@ private:
   cmInstallCommandArguments(); // disabled
   cmCAString Destination;
   cmCAString Component;
+  cmCAString NamelinkComponent;
   cmCAEnabler ExcludeFromAll;
   cmCAString Rename;
   cmCAStringVector Permissions;