From 0212d7c7629bb1a866da4f6c69b780c6d43f26f3 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Wed, 18 Apr 2018 14:53:10 -0400 Subject: 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. --- Help/command/install.rst | 59 +++++++++++++++++++++++++++++++----- Source/cmInstallCommand.cxx | 46 +++++++++++++++++++++++----- Source/cmInstallCommandArguments.cxx | 20 ++++++++++++ Source/cmInstallCommandArguments.h | 3 ++ 4 files changed, 113 insertions(+), 15 deletions(-) diff --git a/Help/command/install.rst b/Help/command/install.rst index 1037edf..63ba210 100644 --- a/Help/command/install.rst +++ b/Help/command/install.rst @@ -103,6 +103,7 @@ Installing Targets [PERMISSIONS permissions...] [CONFIGURATIONS [Debug|Release|...]] [COMPONENT ] + [NAMELINK_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.so.1`` is the soname of the library and ``lib.so`` is a "namelink" allowing linkers to find the library when given - ``-l``. 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``. 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: diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index b5291a1..b325b0c 100644 --- a/Source/cmInstallCommand.cxx +++ b/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 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 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 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 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 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 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 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()); diff --git a/Source/cmInstallCommandArguments.cxx b/Source/cmInstallCommandArguments.cxx index 7b79ab5..2d6dc12 100644 --- a/Source/cmInstallCommandArguments.cxx +++ b/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& cmInstallCommandArguments::GetConfigurations() const { diff --git a/Source/cmInstallCommandArguments.h b/Source/cmInstallCommandArguments.h index a576e72..ee6e865 100644 --- a/Source/cmInstallCommandArguments.h +++ b/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; -- cgit v0.12