فهرست منبع

PkgC: Add NAME and PREFIX

Fixes: #26067
Vito Gamberini 9 ماه پیش
والد
کامیت
f59bab006d

+ 21 - 7
Help/command/cmake_pkg_config.rst

@@ -34,9 +34,9 @@ PkgConfig Targets
 
 ``cmake_pkg_config`` may recursively generate target-like names in the global
 scope in order to resolve a package ``IMPORT`` or ``POPULATE`` command. These
-names take the form of ``@foreign_pkgcfg::<package>`` and are exposed via the
-:prop_tgt:`INTERFACE_LINK_LIBRARIES` target property of an ``IMPORT``-generated
-target.
+names take the form of ``@foreign_pkgcfg::[<prefix>_]<package>`` and are exposed
+via the :prop_tgt:`INTERFACE_LINK_LIBRARIES` target property of an
+``IMPORT``-generated target.
 
 It is not possible to modify or address these pkg-config native targets via
 normal target-based commands. Limited control over their generation is possible
@@ -180,9 +180,16 @@ common between them. They are:
   #. If no top build directory path is available, the ``pc_top_builddir``
      package variable is not set
 
-``BIND_PC_REQUIRES``
-  A list of ``<Name>=<Target>`` pairs, the ``Name`` is a package name as it
-  appears in the ``Requires`` list of a pkg-config file and the ``Target`` is a
+``PREFIX <name>``
+  Specifying a prefix creates an independent collection of pkg-config targets
+  separate from previously populated targets. This enables multiple version of
+  a given package to co-exist, for example packages from different sysroots.
+
+  The default prefix is an empty string.
+
+``BIND_PC_REQUIRES <<name>=<target>>...``
+  A list of ``<name>=<target>`` pairs, the ``name`` is a package name as it
+  appears in the ``Requires`` list of a pkg-config file and the ``target`` is a
   CMake-native target name (not a pkg-config target).
 
   When a given package name appears in the ``Requires`` list of a package, it
@@ -311,6 +318,7 @@ The following variables will be populated from the contents of package file:
 
     cmake_pkg_config(POPULATE <package> [<version>]
                     [REQUIRED] [EXACT] [QUIET]
+                    [PREFIX <prefix>]
                     [BIND_PC_REQUIRES <<name>=<target>>...]
                     [STRICTNESS <mode>]
                     [ENV_MODE <mode>]
@@ -339,6 +347,8 @@ package was found.
 
     cmake_pkg_config(IMPORT <package> [<version>]
                     [REQUIRED] [EXACT] [QUIET]
+                    [NAME <name>]
+                    [PREFIX <prefix>]
                     [BIND_PC_REQUIRES <<name>=<target>>...]
                     [STRICTNESS <mode>]
                     [ENV_MODE <mode>]
@@ -350,7 +360,11 @@ package was found.
 
 Creates a native CMake ``IMPORTED`` target that can be linked to via
 :command:`target_link_libraries`. This new target is named
-``PkgConfig::<package>``.
+``PkgConfig::<package>`` by default.
 
 A ``PKGCONFIG_<package>_FOUND`` variable will be set to indicate whether the
 package was found.
+
+``NAME``
+  Overrides the name of the created CMake target to ``PkgConfig::<name>``. This
+  *does not* affect the ``PKGCONFIG_<package>_FOUND`` variable.

+ 47 - 20
Source/cmCMakePkgConfigCommand.cxx

@@ -37,6 +37,7 @@
 namespace {
 struct ExtractArguments;
 struct PopulateArguments;
+struct ImportArguments;
 }
 
 namespace {
@@ -797,10 +798,11 @@ bool HandleExtractCommand(std::vector<std::string> const& args,
 using pkgStack = std::unordered_map<std::string, std::vector<pkgStackEntry>>;
 using pkgProviders = std::unordered_map<std::string, std::string>;
 
-cmTarget* CreateCMakeTarget(std::string const& name, cmPkgConfigResult& pkg,
-                            pkgProviders& providers, cmMakefile& mf)
+cmTarget* CreateCMakeTarget(std::string const& name, std::string const& prefix,
+                            cmPkgConfigResult& pkg, pkgProviders& providers,
+                            cmMakefile& mf)
 {
-  auto* tgt = mf.AddForeignTarget("pkgcfg", name);
+  auto* tgt = mf.AddForeignTarget("pkgcfg", cmStrCat(prefix, name));
 
   tgt->AppendProperty("VERSION", pkg.Version());
 
@@ -829,13 +831,14 @@ cmTarget* CreateCMakeTarget(std::string const& name, cmPkgConfigResult& pkg,
     }
 
     tgt->AppendProperty("INTERFACE_LINK_LIBRARIES",
-                        cmStrCat("@foreign_pkgcfg::", dep.Name));
+                        cmStrCat("@foreign_pkgcfg::", prefix, dep.Name));
   }
   return tgt;
 }
 
 bool CheckPackageDependencies(
-  std::string const& name, cmPkgConfigResult& pkg, pkgStack& inStack,
+  std::string const& name, std::string const& prefix, cmPkgConfigResult& pkg,
+  pkgStack& inStack,
   std::unordered_map<std::string, cmPkgConfigResult>& outStack,
   pkgProviders& providers, ImportEnv& imEnv)
 {
@@ -846,7 +849,7 @@ bool CheckPackageDependencies(
     }
 
     auto* tgt = imEnv.status.GetMakefile().FindTargetToUse(
-      cmStrCat("@foreign_pkgcfg::", dep.Name),
+      cmStrCat("@foreign_pkgcfg::", prefix, dep.Name),
       cmStateEnums::TargetDomain::FOREIGN);
     if (tgt) {
       auto ver = tgt->GetProperty("VERSION");
@@ -882,17 +885,23 @@ bool CheckPackageDependencies(
 
 struct PopulateArguments : CommonArguments
 {
-  cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> providers;
+  cm::optional<std::string> Prefix;
+  cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Providers;
 };
 
-auto const PopulateParser =
-  BIND_COMMON(PopulateArguments)
-    .Bind("BIND_PC_REQUIRES"_s, &PopulateArguments::providers);
+#define BIND_POPULATE(argtype)                                                \
+  BIND_COMMON(argtype)                                                        \
+    .Bind("PREFIX"_s, &argtype::Prefix)                                       \
+    .Bind("BIND_PC_REQUIRES"_s, &argtype::Providers)
+
+auto const PopulateParser = BIND_POPULATE(PopulateArguments);
 
 std::pair<bool, bool> PopulatePCTarget(PopulateArguments& args,
                                        cmExecutionStatus& status)
 {
 
+  std::string prefix = args.Prefix ? cmStrCat(*args.Prefix, "_"_s) : "";
+
   auto& mf = status.GetMakefile();
   auto maybeEnv = HandleCommon(args, status);
 
@@ -903,8 +912,8 @@ std::pair<bool, bool> PopulatePCTarget(PopulateArguments& args,
   auto& imEnv = maybeEnv->second;
 
   pkgProviders providers;
-  if (args.providers) {
-    for (auto const& provider_str : *args.providers) {
+  if (args.Providers) {
+    for (auto const& provider_str : *args.Providers) {
       auto assignment = provider_str.find('=');
       if (assignment != std::string::npos) {
         providers.emplace(provider_str.substr(0, assignment),
@@ -927,7 +936,7 @@ std::pair<bool, bool> PopulatePCTarget(PopulateArguments& args,
   }
   imEnv.exact = false;
 
-  if (!CheckPackageDependencies(*args.Package, *maybePackage, inStack,
+  if (!CheckPackageDependencies(*args.Package, prefix, *maybePackage, inStack,
                                 outStack, providers, imEnv)) {
     return { !args.Required, false };
   }
@@ -940,8 +949,8 @@ std::pair<bool, bool> PopulatePCTarget(PopulateArguments& args,
     if (!maybePackage) {
       return { !args.Required, false };
     }
-    if (!CheckPackageDependencies(name, *maybePackage, inStack, outStack,
-                                  providers, imEnv)) {
+    if (!CheckPackageDependencies(name, prefix, *maybePackage, inStack,
+                                  outStack, providers, imEnv)) {
       return { !args.Required, false };
     }
     inStack.erase(name);
@@ -949,7 +958,7 @@ std::pair<bool, bool> PopulatePCTarget(PopulateArguments& args,
   }
 
   for (auto& entry : outStack) {
-    CreateCMakeTarget(entry.first, entry.second, providers, mf);
+    CreateCMakeTarget(entry.first, prefix, entry.second, providers, mf);
   }
 
   return { true, true };
@@ -961,7 +970,11 @@ bool HandlePopulateCommand(std::vector<std::string> const& args,
   std::vector<std::string> unparsed;
   auto parsedArgs = PopulateParser.Parse(args, &unparsed);
 
-  auto foreign_name = cmStrCat("@foreign_pkgcfg::", *parsedArgs.Package);
+  std::string prefix =
+    parsedArgs.Prefix ? cmStrCat(*parsedArgs.Prefix, "_"_s) : "";
+
+  auto foreign_name =
+    cmStrCat("@foreign_pkgcfg::", prefix, *parsedArgs.Package);
   auto found_var = cmStrCat("PKGCONFIG_", *parsedArgs.Package, "_FOUND");
 
   auto& mf = status.GetMakefile();
@@ -976,13 +989,27 @@ bool HandlePopulateCommand(std::vector<std::string> const& args,
   return result.first;
 }
 
+struct ImportArguments : PopulateArguments
+{
+  cm::optional<std::string> Name;
+};
+
+auto const ImportParser =
+  BIND_POPULATE(ImportArguments).Bind("NAME"_s, &ImportArguments::Name);
+
 bool HandleImportCommand(std::vector<std::string> const& args,
                          cmExecutionStatus& status)
 {
   std::vector<std::string> unparsed;
-  auto parsedArgs = PopulateParser.Parse(args, &unparsed);
-  auto foreign_name = cmStrCat("@foreign_pkgcfg::", *parsedArgs.Package);
-  auto local_name = cmStrCat("PkgConfig::", *parsedArgs.Package);
+  auto parsedArgs = ImportParser.Parse(args, &unparsed);
+
+  std::string prefix =
+    parsedArgs.Prefix ? cmStrCat(*parsedArgs.Prefix, "_"_s) : "";
+
+  auto foreign_name =
+    cmStrCat("@foreign_pkgcfg::", prefix, *parsedArgs.Package);
+  auto local_name =
+    cmStrCat("PkgConfig::", parsedArgs.Name.value_or(*parsedArgs.Package));
   auto found_var = cmStrCat("PKGCONFIG_", *parsedArgs.Package, "_FOUND");
 
   auto& mf = status.GetMakefile();

+ 13 - 0
Tests/RunCMake/cmake_pkg_config/ImportName.cmake

@@ -0,0 +1,13 @@
+set(CMAKE_PKG_CONFIG_PC_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageRoot/RequiresPackages)
+
+cmake_pkg_config(IMPORT alpha REQUIRED
+  NAME moe
+)
+
+if(TARGET PkgConfig::alpha)
+  message("cmake_pkg_config target rename created PkgConfig::<package> target")
+endif()
+
+if(NOT TARGET PkgConfig::moe)
+  message("cmake_pkg_config target rename failed to create PkgConfig::<name> target")
+endif()

+ 13 - 0
Tests/RunCMake/cmake_pkg_config/ImportPrefix-check.cmake

@@ -0,0 +1,13 @@
+set(expected
+"larry: Alpha
+curly: Alpha
+moe: AltAlpha
+shemp: AltAlpha
+"
+)
+
+file(READ "${RunCMake_TEST_BINARY_DIR}/import-prefix.txt" actual)
+
+if(NOT(expected STREQUAL actual))
+  set(RunCMake_TEST_FAILED "cmake_pkg_config import-prefix.txt does not match expected:\n${actual}")
+endif()

+ 33 - 0
Tests/RunCMake/cmake_pkg_config/ImportPrefix.cmake

@@ -0,0 +1,33 @@
+set(CMAKE_PKG_CONFIG_PC_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageRoot/RequiresPackages)
+
+cmake_pkg_config(IMPORT alpha REQUIRED
+  NAME larry
+)
+
+set(CMAKE_PKG_CONFIG_PC_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageRoot/AltRequiresPackages)
+
+cmake_pkg_config(IMPORT alpha REQUIRED
+  NAME curly
+)
+
+cmake_pkg_config(IMPORT alpha REQUIRED
+  NAME moe
+  PREFIX moe
+)
+
+set(CMAKE_PKG_CONFIG_PC_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageRoot/RequiresPackages)
+
+cmake_pkg_config(IMPORT alpha REQUIRED
+  NAME shemp
+  PREFIX moe
+)
+
+file(GENERATE
+  OUTPUT import-prefix.txt
+  CONTENT
+"larry: $<TARGET_PROPERTY:PkgConfig::larry,INTERFACE_COMPILE_OPTIONS>
+curly: $<TARGET_PROPERTY:PkgConfig::curly,INTERFACE_COMPILE_OPTIONS>
+moe: $<TARGET_PROPERTY:PkgConfig::moe,INTERFACE_COMPILE_OPTIONS>
+shemp: $<TARGET_PROPERTY:PkgConfig::shemp,INTERFACE_COMPILE_OPTIONS>
+"
+)

+ 5 - 0
Tests/RunCMake/cmake_pkg_config/PackageRoot/AltRequiresPackages/alpha.pc

@@ -0,0 +1,5 @@
+Name: AltAlpha
+Description: AltAlpha
+Version: 1.0.0
+
+Cflags: AltAlpha

+ 3 - 1
Tests/RunCMake/cmake_pkg_config/RunCMakeTest.cmake

@@ -16,8 +16,10 @@ run_cmake(ExtractRequired)
 run_cmake(ExtractReroot)
 run_cmake(ExtractUninstalled)
 run_cmake(ExtractVersion)
-run_cmake(ImportSimple)
+run_cmake(ImportName)
+run_cmake(ImportPrefix)
 run_cmake(ImportRequires)
+run_cmake(ImportSimple)
 run_cmake(ImportTransitiveFail)
 run_cmake(ImportTransitiveVersion)
 run_cmake(ImportTransitiveVersionFail)