Merge topic 'pkgc-name-prefix'

f59bab006d PkgC: Add NAME and PREFIX

Acked-by: Kitware Robot <kwrobot@kitware.com>
Tested-by: buildbot <buildbot@kitware.com>
Merge-request: !10473
This commit is contained in:
Brad King 2025-03-17 15:52:09 +00:00 committed by Kitware Robot
commit c005babf89
7 changed files with 135 additions and 28 deletions

View File

@ -34,9 +34,9 @@ PkgConfig Targets
``cmake_pkg_config`` may recursively generate target-like names in the global ``cmake_pkg_config`` may recursively generate target-like names in the global
scope in order to resolve a package ``IMPORT`` or ``POPULATE`` command. These 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 names take the form of ``@foreign_pkgcfg::[<prefix>_]<package>`` and are exposed
:prop_tgt:`INTERFACE_LINK_LIBRARIES` target property of an ``IMPORT``-generated via the :prop_tgt:`INTERFACE_LINK_LIBRARIES` target property of an
target. ``IMPORT``-generated target.
It is not possible to modify or address these pkg-config native targets via 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 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`` #. If no top build directory path is available, the ``pc_top_builddir``
package variable is not set package variable is not set
``BIND_PC_REQUIRES`` ``PREFIX <name>``
A list of ``<Name>=<Target>`` pairs, the ``Name`` is a package name as it Specifying a prefix creates an independent collection of pkg-config targets
appears in the ``Requires`` list of a pkg-config file and the ``Target`` is a 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). CMake-native target name (not a pkg-config target).
When a given package name appears in the ``Requires`` list of a package, it 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>] cmake_pkg_config(POPULATE <package> [<version>]
[REQUIRED] [EXACT] [QUIET] [REQUIRED] [EXACT] [QUIET]
[PREFIX <prefix>]
[BIND_PC_REQUIRES <<name>=<target>>...] [BIND_PC_REQUIRES <<name>=<target>>...]
[STRICTNESS <mode>] [STRICTNESS <mode>]
[ENV_MODE <mode>] [ENV_MODE <mode>]
@ -339,6 +347,8 @@ package was found.
cmake_pkg_config(IMPORT <package> [<version>] cmake_pkg_config(IMPORT <package> [<version>]
[REQUIRED] [EXACT] [QUIET] [REQUIRED] [EXACT] [QUIET]
[NAME <name>]
[PREFIX <prefix>]
[BIND_PC_REQUIRES <<name>=<target>>...] [BIND_PC_REQUIRES <<name>=<target>>...]
[STRICTNESS <mode>] [STRICTNESS <mode>]
[ENV_MODE <mode>] [ENV_MODE <mode>]
@ -350,7 +360,11 @@ package was found.
Creates a native CMake ``IMPORTED`` target that can be linked to via Creates a native CMake ``IMPORTED`` target that can be linked to via
:command:`target_link_libraries`. This new target is named :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 A ``PKGCONFIG_<package>_FOUND`` variable will be set to indicate whether the
package was found. package was found.
``NAME``
Overrides the name of the created CMake target to ``PkgConfig::<name>``. This
*does not* affect the ``PKGCONFIG_<package>_FOUND`` variable.

View File

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

View File

@ -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()

View File

@ -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()

View File

@ -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>
"
)

View File

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

View File

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