mirror of
https://github.com/Kitware/CMake.git
synced 2026-11-07 05:46:42 +00:00
54 files changed
+813
-184
No files matched your search
@@ -12,9 +12,11 @@ Process pkg-config format package files.
|
||||
Synopsis
|
||||
^^^^^^^^
|
||||
|
||||
.. code-block:: cmake
|
||||
.. parsed-literal::
|
||||
|
||||
cmake_pkg_config(EXTRACT <package> [<version>] [...])
|
||||
cmake_pkg_config(`EXTRACT`_ <package> [<version>] [...])
|
||||
cmake_pkg_config(`POPULATE`_ <package> [<version>] [...])
|
||||
cmake_pkg_config(`IMPORT`_ <package> [<version>] [...])
|
||||
|
||||
Introduction
|
||||
^^^^^^^^^^^^
|
||||
@@ -27,7 +29,31 @@ search patterns. The optional ``<version>`` string has the same format and
|
||||
semantics as a pkg-config style version specifier, with the exception that if
|
||||
no comparison operator is specified ``=`` is assumed.
|
||||
|
||||
.. _`common options`:
|
||||
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.
|
||||
|
||||
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
|
||||
via the ``POPULATE`` command, but modification should generally be performed
|
||||
inside the corresponding package file, not downstream in CMake.
|
||||
|
||||
Pkg-config targets are reused across commands. Once a given package name has
|
||||
been resolved via ``POPULATE`` or ``IMPORT`` (but not ``EXTRACT``), all future
|
||||
requests for the corresponding package name by those commands will resolve to
|
||||
the previously generated pkg-config target.
|
||||
|
||||
``EXTRACT`` always performs the complete package name lookup in order to allow
|
||||
searches for multiple installations of the same package in custom dependency
|
||||
management schemes.
|
||||
|
||||
Common Options
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
There are multiple signatures for this command, and some of the options are
|
||||
common between them. They are:
|
||||
@@ -143,7 +169,7 @@ common between them. They are:
|
||||
library directory paths and ``pc_sysrootdir`` will be set to ``/``
|
||||
|
||||
``TOP_BUILD_DIR <path>``
|
||||
Overrides the top build directory path used to derived the ``pc_top_builddir``
|
||||
Overrides the top build directory path used to derive the ``pc_top_builddir``
|
||||
package variable.
|
||||
|
||||
When this option is not provided, the default top build directory path is
|
||||
@@ -154,29 +180,41 @@ 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
|
||||
CMake-native target name (not a pkg-config target).
|
||||
|
||||
When a given package name appears in the ``Requires`` list of a package, it
|
||||
will be fulfilled with the associated CMake target. This behavior applies to
|
||||
all dependencies in the pkg-config graph that have not been previously
|
||||
populated.
|
||||
|
||||
Signatures
|
||||
^^^^^^^^^^
|
||||
|
||||
.. signature::
|
||||
cmake_pkg_config(EXTRACT <package> [<version>] [...])
|
||||
|
||||
.. versionadded:: 3.31
|
||||
|
||||
Extract the contents of the package into variables.
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
cmake_pkg_config(EXTRACT <package> [<version>]
|
||||
[REQUIRED] [EXACT] [QUIET]
|
||||
[SYSTEM_INCLUDE_DIRS <path>...]
|
||||
[SYSTEM_LIBRARY_DIRS <path>...]
|
||||
[ALLOW_SYSTEM_INCLUDES <bool>]
|
||||
[ALLOW_SYSTEM_LIBS <bool>]
|
||||
[STRICTNESS <mode>]
|
||||
[ENV_MODE <mode>]
|
||||
[PC_LIBDIR <path>...]
|
||||
[PC_PATH <path>...]
|
||||
[DISABLE_UNINSTALLED <bool>]
|
||||
[PC_SYSROOT_DIR <path>]
|
||||
[TOP_BUILD_DIR <path>]
|
||||
[SYSTEM_INCLUDE_DIRS <path>...]
|
||||
[SYSTEM_LIBRARY_DIRS <path>...]
|
||||
[ALLOW_SYSTEM_INCLUDES <bool>]
|
||||
[ALLOW_SYSTEM_LIBS <bool>])
|
||||
[TOP_BUILD_DIR <path>])
|
||||
|
||||
The following variables will be populated from the contents of package file:
|
||||
|
||||
@@ -261,3 +299,58 @@ The following variables will be populated from the contents of package file:
|
||||
#. ``CMAKE_PKG_CONFIG_ALLOW_SYS_LIBS``
|
||||
#. If the ``PKG_CONFIG_ALLOW_SYSTEM_LIBS`` environment variable is defined
|
||||
the flags are preserved, otherwise they are filtered during flag mangling.
|
||||
|
||||
.. signature::
|
||||
cmake_pkg_config(POPULATE <package> [<version>] [...])
|
||||
|
||||
.. versionadded:: 4.1
|
||||
|
||||
Populate a package in the pkg-config target namespace
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
cmake_pkg_config(POPULATE <package> [<version>]
|
||||
[REQUIRED] [EXACT] [QUIET]
|
||||
[BIND_PC_REQUIRES <<name>=<target>>...]
|
||||
[STRICTNESS <mode>]
|
||||
[ENV_MODE <mode>]
|
||||
[PC_LIBDIR <path>...]
|
||||
[PC_PATH <path>...]
|
||||
[DISABLE_UNINSTALLED <bool>]
|
||||
[PC_SYSROOT_DIR <path>]
|
||||
[TOP_BUILD_DIR <path>])
|
||||
|
||||
``POPULATE`` enables manual control of resolution of a given package's
|
||||
``Requires`` list without importing onto a native CMake target. Once populated,
|
||||
a package and its dependencies will be used for resolution of all future
|
||||
``POPULATE`` and ``IMPORT`` commands.
|
||||
|
||||
A ``PKGCONFIG_<package>_FOUND`` variable will be set to indicate whether the
|
||||
package was found.
|
||||
|
||||
.. signature::
|
||||
cmake_pkg_config(IMPORT <package> [<version>] [...])
|
||||
|
||||
.. versionadded:: 4.1
|
||||
|
||||
Import a pkg-config target as a CMake :prop_tgt:`IMPORTED` target
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
cmake_pkg_config(IMPORT <package> [<version>]
|
||||
[REQUIRED] [EXACT] [QUIET]
|
||||
[BIND_PC_REQUIRES <<name>=<target>>...]
|
||||
[STRICTNESS <mode>]
|
||||
[ENV_MODE <mode>]
|
||||
[PC_LIBDIR <path>...]
|
||||
[PC_PATH <path>...]
|
||||
[DISABLE_UNINSTALLED <bool>]
|
||||
[PC_SYSROOT_DIR <path>]
|
||||
[TOP_BUILD_DIR <path>])
|
||||
|
||||
Creates a native CMake ``IMPORTED`` target that can be linked to via
|
||||
:command:`target_link_libraries`. This new target is named
|
||||
``PkgConfig::<package>``.
|
||||
|
||||
A ``PKGCONFIG_<package>_FOUND`` variable will be set to indicate whether the
|
||||
package was found.
|
||||
@@ -0,0 +1,6 @@
|
||||
cmake-pkg-config-import
|
||||
-----------------------
|
||||
|
||||
* The :command:`cmake_pkg_config` command now supports the ``IMPORT`` and
|
||||
``POPULATE`` subcommands for interfacing CMake targets with pkg-config based
|
||||
dependencies.
|
||||
+412
-107
@@ -6,6 +6,7 @@
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -28,12 +29,14 @@
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSubcommandTable.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmTarget.h"
|
||||
#include "cmValue.h"
|
||||
#include <cmllpkgc/llpkgc.h>
|
||||
|
||||
// IWYU wants this
|
||||
namespace {
|
||||
struct ExtractArguments;
|
||||
struct PopulateArguments;
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -441,89 +444,59 @@ void CollectEnv(cmMakefile& mf, cmPkgConfigEnv& env,
|
||||
*env.SysLibs += GetPkgConfSysLibs(mf);
|
||||
}
|
||||
|
||||
cm::optional<cmPkgConfigResult> HandleCommon(CommonArguments& args,
|
||||
cmExecutionStatus& status)
|
||||
struct ImportEnv
|
||||
{
|
||||
bool required;
|
||||
bool quiet;
|
||||
bool exact;
|
||||
bool err;
|
||||
CommonArguments::StrictnessType strictness;
|
||||
cmExecutionStatus& status;
|
||||
};
|
||||
|
||||
auto& mf = status.GetMakefile();
|
||||
|
||||
if (!args.CheckArgs(status)) {
|
||||
return {};
|
||||
void warn_or_error(std::string const& err, ImportEnv& imEnv)
|
||||
{
|
||||
if (imEnv.required) {
|
||||
imEnv.status.SetError(err);
|
||||
cmSystemTools::SetFatalErrorOccurred();
|
||||
} else if (!imEnv.quiet) {
|
||||
imEnv.status.GetMakefile().IssueMessage(MessageType::WARNING, err);
|
||||
}
|
||||
imEnv.err = true;
|
||||
}
|
||||
|
||||
auto warn_or_error = [&](std::string const& err) {
|
||||
if (args.Required) {
|
||||
status.SetError(err);
|
||||
cmSystemTools::SetFatalErrorOccurred();
|
||||
} else if (!args.Quiet) {
|
||||
mf.IssueMessage(MessageType::WARNING, err);
|
||||
}
|
||||
};
|
||||
|
||||
cm::filesystem::path path{ *args.Package };
|
||||
|
||||
cmPkgConfigEnv env;
|
||||
|
||||
if (args.PcLibdir) {
|
||||
env.LibDirs = std::move(*args.PcLibdir);
|
||||
}
|
||||
|
||||
if (args.PcPath) {
|
||||
env.Path = std::move(*args.PcPath);
|
||||
}
|
||||
|
||||
if (args.DisableUninstalled) {
|
||||
env.DisableUninstalled = args.DisableUninstalled;
|
||||
}
|
||||
|
||||
if (args.SysrootDir) {
|
||||
env.SysrootDir = std::move(*args.SysrootDir);
|
||||
}
|
||||
|
||||
if (args.TopBuildDir) {
|
||||
env.TopBuildDir = std::move(*args.TopBuildDir);
|
||||
}
|
||||
|
||||
CollectEnv(mf, env, args.EnvMode);
|
||||
cm::optional<cmPkgConfigResult> ReadPackage(std::string const& package,
|
||||
ImportEnv& imEnv,
|
||||
cmPkgConfigEnv& pcEnv)
|
||||
{
|
||||
cm::optional<cmPkgConfigResult> result;
|
||||
cm::filesystem::path path{ package };
|
||||
|
||||
if (path.extension() == ".pc") {
|
||||
if (!cmSystemTools::FileExists(path.string())) {
|
||||
warn_or_error(cmStrCat("Could not find '", *args.Package, "'"));
|
||||
return {};
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
|
||||
std::vector<std::string> search;
|
||||
if (env.Path) {
|
||||
search = *env.Path;
|
||||
if (env.LibDirs) {
|
||||
search += *env.LibDirs;
|
||||
}
|
||||
} else if (env.LibDirs) {
|
||||
search = *env.LibDirs;
|
||||
}
|
||||
|
||||
if (env.DisableUninstalled && !*env.DisableUninstalled) {
|
||||
if (pcEnv.DisableUninstalled && !*pcEnv.DisableUninstalled) {
|
||||
auto uninstalled = path;
|
||||
uninstalled.concat("-uninstalled.pc");
|
||||
uninstalled =
|
||||
cmSystemTools::FindFile(uninstalled.string(), search, true);
|
||||
cmSystemTools::FindFile(uninstalled.string(), pcEnv.search, true);
|
||||
if (uninstalled.empty()) {
|
||||
path =
|
||||
cmSystemTools::FindFile(path.concat(".pc").string(), search, true);
|
||||
path = cmSystemTools::FindFile(path.concat(".pc").string(),
|
||||
pcEnv.search, true);
|
||||
if (path.empty()) {
|
||||
warn_or_error(cmStrCat("Could not find '", *args.Package, "'"));
|
||||
return {};
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
path = uninstalled;
|
||||
}
|
||||
} else {
|
||||
path =
|
||||
cmSystemTools::FindFile(path.concat(".pc").string(), search, true);
|
||||
path = cmSystemTools::FindFile(path.concat(".pc").string(), pcEnv.search,
|
||||
true);
|
||||
if (path.empty()) {
|
||||
warn_or_error(cmStrCat("Could not find '", *args.Package, "'"));
|
||||
return {};
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -534,8 +507,9 @@ cm::optional<cmPkgConfigResult> HandleCommon(CommonArguments& args,
|
||||
cmsys::ifstream ifs(path.string().c_str(), std::ios::binary);
|
||||
|
||||
if (!ifs) {
|
||||
warn_or_error(cmStrCat("Could not open file '", path.string(), "'"));
|
||||
return {};
|
||||
warn_or_error(cmStrCat("Could not open file '", path.string(), "'"),
|
||||
imEnv);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<char[]> buf(new char[len]);
|
||||
@@ -543,8 +517,9 @@ cm::optional<cmPkgConfigResult> HandleCommon(CommonArguments& args,
|
||||
|
||||
// Shouldn't have hit eof on previous read, should hit eof now
|
||||
if (ifs.fail() || ifs.eof() || ifs.get() != EOF) {
|
||||
warn_or_error(cmStrCat("Error while reading file '", path.string(), "'"));
|
||||
return {};
|
||||
warn_or_error(cmStrCat("Error while reading file '", path.string(), "'"),
|
||||
imEnv);
|
||||
return result;
|
||||
}
|
||||
|
||||
using StrictnessType = CommonArguments::StrictnessType;
|
||||
@@ -552,53 +527,161 @@ cm::optional<cmPkgConfigResult> HandleCommon(CommonArguments& args,
|
||||
cmPkgConfigParser parser;
|
||||
auto err = parser.Finish(buf.get(), len);
|
||||
|
||||
if (args.Strictness != StrictnessType::STRICTNESS_BEST_EFFORT &&
|
||||
if (imEnv.strictness != StrictnessType::STRICTNESS_BEST_EFFORT &&
|
||||
err != PCE_OK) {
|
||||
warn_or_error(cmStrCat("Parsing failed for file '", path.string(), "'"));
|
||||
return {};
|
||||
warn_or_error(cmStrCat("Parsing failed for file '", path.string(), "'"),
|
||||
imEnv);
|
||||
return result;
|
||||
}
|
||||
|
||||
cm::optional<cmPkgConfigResult> result;
|
||||
if (args.Strictness == StrictnessType::STRICTNESS_STRICT) {
|
||||
result = cmPkgConfigResolver::ResolveStrict(parser.Data(), std::move(env));
|
||||
} else if (args.Strictness == StrictnessType::STRICTNESS_PERMISSIVE) {
|
||||
result =
|
||||
cmPkgConfigResolver::ResolvePermissive(parser.Data(), std::move(env));
|
||||
if (imEnv.strictness == StrictnessType::STRICTNESS_STRICT) {
|
||||
result = cmPkgConfigResolver::ResolveStrict(parser.Data(), pcEnv);
|
||||
} else if (imEnv.strictness == StrictnessType::STRICTNESS_PERMISSIVE) {
|
||||
result = cmPkgConfigResolver::ResolvePermissive(parser.Data(), pcEnv);
|
||||
} else {
|
||||
result =
|
||||
cmPkgConfigResolver::ResolveBestEffort(parser.Data(), std::move(env));
|
||||
result = cmPkgConfigResolver::ResolveBestEffort(parser.Data(), pcEnv);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
warn_or_error(
|
||||
cmStrCat("Resolution failed for file '", path.string(), "'"));
|
||||
} else if (args.Exact) {
|
||||
warn_or_error(cmStrCat("Resolution failed for file '", path.string(), "'"),
|
||||
imEnv);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cm::optional<cmPkgConfigResult> ImportPackage(
|
||||
std::string const& package, cm::optional<std::string> version,
|
||||
ImportEnv& imEnv, cmPkgConfigEnv& pcEnv)
|
||||
{
|
||||
auto result = ReadPackage(package, imEnv, pcEnv);
|
||||
|
||||
if (!result) {
|
||||
if (!imEnv.err) {
|
||||
warn_or_error(cmStrCat("Could not find pkg-config: '", package, "'"),
|
||||
imEnv);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if (imEnv.exact) {
|
||||
std::string ver;
|
||||
|
||||
if (args.Version) {
|
||||
ver = cmPkgConfigResolver::ParseVersion(*args.Version).Version;
|
||||
if (version) {
|
||||
ver = cmPkgConfigResolver::ParseVersion(*version).Version;
|
||||
}
|
||||
|
||||
if (ver != result->Version()) {
|
||||
warn_or_error(
|
||||
cmStrCat("Package '", *args.Package, "' version '", result->Version(),
|
||||
"' does not meet exact version requirement '", ver, "'"));
|
||||
cmStrCat("Package '", package, "' version '", result->Version(),
|
||||
"' does not meet exact version requirement '", ver, "'"),
|
||||
imEnv);
|
||||
return {};
|
||||
}
|
||||
|
||||
} else if (args.Version) {
|
||||
auto rv = cmPkgConfigResolver::ParseVersion(*args.Version);
|
||||
} else if (version) {
|
||||
auto rv = cmPkgConfigResolver::ParseVersion(*version);
|
||||
if (!cmPkgConfigResolver::CheckVersion(rv, result->Version())) {
|
||||
warn_or_error(
|
||||
cmStrCat("Package '", *args.Package, "' version '", result->Version(),
|
||||
"' does not meet version requirement '", *args.Version, "'"));
|
||||
cmStrCat("Package '", package, "' version '", result->Version(),
|
||||
"' does not meet version requirement '", *version, "'"),
|
||||
imEnv);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
result->env = &pcEnv;
|
||||
return result;
|
||||
}
|
||||
|
||||
struct pkgStackEntry
|
||||
{
|
||||
cmPkgConfigVersionReq ver;
|
||||
std::string parent;
|
||||
};
|
||||
|
||||
cm::optional<cmPkgConfigResult> ImportPackage(
|
||||
std::string const& package, std::vector<pkgStackEntry> const& reqs,
|
||||
ImportEnv& imEnv, cmPkgConfigEnv& pcEnv)
|
||||
{
|
||||
auto result = ReadPackage(package, imEnv, pcEnv);
|
||||
|
||||
if (!result) {
|
||||
if (!imEnv.err) {
|
||||
std::string req_str = cmStrCat("'", reqs.begin()->parent, "'");
|
||||
for (auto it = reqs.begin() + 1; it != reqs.end(); ++it) {
|
||||
req_str = cmStrCat(req_str, ", '", it->parent, "'");
|
||||
}
|
||||
warn_or_error(cmStrCat("Could not find pkg-config: '", package,
|
||||
"' required by: ", req_str),
|
||||
imEnv);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
auto ver = result->Version();
|
||||
for (auto const& req : reqs) {
|
||||
|
||||
if (!cmPkgConfigResolver::CheckVersion(req.ver, ver)) {
|
||||
warn_or_error(cmStrCat("Package '", package, "' version '", ver,
|
||||
"' does not meet version requirement '",
|
||||
req.ver.string(), "' ", "of '", req.parent, "'"),
|
||||
imEnv);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
result->env = &pcEnv;
|
||||
return result;
|
||||
}
|
||||
|
||||
cm::optional<std::pair<cmPkgConfigEnv, ImportEnv>> HandleCommon(
|
||||
CommonArguments& args, cmExecutionStatus& status)
|
||||
{
|
||||
|
||||
auto& mf = status.GetMakefile();
|
||||
|
||||
if (!args.CheckArgs(status)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
cmPkgConfigEnv pcEnv;
|
||||
|
||||
if (args.PcLibdir) {
|
||||
pcEnv.LibDirs = std::move(*args.PcLibdir);
|
||||
}
|
||||
|
||||
if (args.PcPath) {
|
||||
pcEnv.Path = std::move(*args.PcPath);
|
||||
}
|
||||
|
||||
pcEnv.DisableUninstalled = args.DisableUninstalled;
|
||||
|
||||
if (args.SysrootDir) {
|
||||
pcEnv.SysrootDir = std::move(*args.SysrootDir);
|
||||
}
|
||||
|
||||
if (args.TopBuildDir) {
|
||||
pcEnv.TopBuildDir = std::move(*args.TopBuildDir);
|
||||
}
|
||||
|
||||
CollectEnv(mf, pcEnv, args.EnvMode);
|
||||
|
||||
if (pcEnv.Path) {
|
||||
pcEnv.search = *pcEnv.Path;
|
||||
if (pcEnv.LibDirs) {
|
||||
pcEnv.search += *pcEnv.LibDirs;
|
||||
}
|
||||
} else if (pcEnv.LibDirs) {
|
||||
pcEnv.search = *pcEnv.LibDirs;
|
||||
}
|
||||
|
||||
return std::pair<cmPkgConfigEnv, ImportEnv>{
|
||||
pcEnv,
|
||||
{ args.Required, args.Quiet, args.Exact, false, args.Strictness, status }
|
||||
};
|
||||
}
|
||||
|
||||
struct ExtractArguments : CommonArguments
|
||||
{
|
||||
cm::optional<bool> AllowSystemIncludes;
|
||||
@@ -623,35 +706,41 @@ bool HandleExtractCommand(std::vector<std::string> const& args,
|
||||
|
||||
std::vector<std::string> unparsed;
|
||||
auto parsedArgs = ExtractParser.Parse(args, &unparsed);
|
||||
auto maybeResolved = HandleCommon(parsedArgs, status);
|
||||
auto maybeEnv = HandleCommon(parsedArgs, status);
|
||||
|
||||
if (!maybeResolved) {
|
||||
if (!maybeEnv) {
|
||||
return !parsedArgs.Required;
|
||||
}
|
||||
auto& pcEnv = maybeEnv->first;
|
||||
auto& imEnv = maybeEnv->second;
|
||||
|
||||
auto& resolved = *maybeResolved;
|
||||
auto version = resolved.Version();
|
||||
auto maybePackage =
|
||||
ImportPackage(*parsedArgs.Package, parsedArgs.Version, imEnv, pcEnv);
|
||||
if (!maybePackage) {
|
||||
return !parsedArgs.Required;
|
||||
}
|
||||
auto& package = *maybePackage;
|
||||
|
||||
if (parsedArgs.AllowSystemIncludes) {
|
||||
resolved.env.AllowSysCflags = *parsedArgs.AllowSystemIncludes;
|
||||
pcEnv.AllowSysCflags = *parsedArgs.AllowSystemIncludes;
|
||||
}
|
||||
|
||||
if (parsedArgs.AllowSystemLibs) {
|
||||
resolved.env.AllowSysLibs = *parsedArgs.AllowSystemLibs;
|
||||
pcEnv.AllowSysLibs = *parsedArgs.AllowSystemLibs;
|
||||
}
|
||||
|
||||
if (parsedArgs.SystemIncludeDirs) {
|
||||
resolved.env.SysCflags = *parsedArgs.SystemIncludeDirs;
|
||||
pcEnv.SysCflags = *parsedArgs.SystemIncludeDirs;
|
||||
}
|
||||
|
||||
if (parsedArgs.SystemLibraryDirs) {
|
||||
resolved.env.SysLibs = *parsedArgs.SystemLibraryDirs;
|
||||
pcEnv.SysLibs = *parsedArgs.SystemLibraryDirs;
|
||||
}
|
||||
|
||||
auto& mf = status.GetMakefile();
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_NAME", resolved.Name());
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_DESCRIPTION", resolved.Description());
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_VERSION", version);
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_NAME", package.Name());
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_DESCRIPTION", package.Description());
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_VERSION", package.Version());
|
||||
|
||||
auto make_list = [&](char const* def,
|
||||
std::vector<cmPkgConfigDependency> const& deps) {
|
||||
@@ -665,26 +754,26 @@ bool HandleExtractCommand(std::vector<std::string> const& args,
|
||||
mf.AddDefinition(def, cmList::to_string(vec));
|
||||
};
|
||||
|
||||
make_list("CMAKE_PKG_CONFIG_CONFLICTS", resolved.Conflicts());
|
||||
make_list("CMAKE_PKG_CONFIG_PROVIDES", resolved.Provides());
|
||||
make_list("CMAKE_PKG_CONFIG_REQUIRES", resolved.Requires());
|
||||
make_list("CMAKE_PKG_CONFIG_REQUIRES_PRIVATE", resolved.Requires(true));
|
||||
make_list("CMAKE_PKG_CONFIG_CONFLICTS", package.Conflicts());
|
||||
make_list("CMAKE_PKG_CONFIG_PROVIDES", package.Provides());
|
||||
make_list("CMAKE_PKG_CONFIG_REQUIRES", package.Requires());
|
||||
make_list("CMAKE_PKG_CONFIG_REQUIRES_PRIVATE", package.Requires(true));
|
||||
|
||||
auto cflags = resolved.Cflags();
|
||||
auto cflags = package.Cflags();
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_CFLAGS", cflags.Flagline);
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_INCLUDES",
|
||||
cmList::to_string(cflags.Includes));
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_COMPILE_OPTIONS",
|
||||
cmList::to_string(cflags.CompileOptions));
|
||||
|
||||
cflags = resolved.Cflags(true);
|
||||
cflags = package.Cflags(true);
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_CFLAGS_PRIVATE", cflags.Flagline);
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_INCLUDES_PRIVATE",
|
||||
cmList::to_string(cflags.Includes));
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_COMPILE_OPTIONS_PRIVATE",
|
||||
cmList::to_string(cflags.CompileOptions));
|
||||
|
||||
auto libs = resolved.Libs();
|
||||
auto libs = package.Libs();
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_LIBS", libs.Flagline);
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_LIBDIRS",
|
||||
cmList::to_string(libs.LibDirs));
|
||||
@@ -693,7 +782,7 @@ bool HandleExtractCommand(std::vector<std::string> const& args,
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_LINK_OPTIONS",
|
||||
cmList::to_string(libs.LinkOptions));
|
||||
|
||||
libs = resolved.Libs(true);
|
||||
libs = package.Libs(true);
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_LIBS_PRIVATE", libs.Flagline);
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_LIBDIRS_PRIVATE",
|
||||
cmList::to_string(libs.LibDirs));
|
||||
@@ -704,6 +793,220 @@ bool HandleExtractCommand(std::vector<std::string> const& args,
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
auto* tgt = mf.AddForeignTarget("pkgcfg", name);
|
||||
|
||||
tgt->AppendProperty("VERSION", pkg.Version());
|
||||
|
||||
auto libs = pkg.Libs();
|
||||
for (auto const& flag : libs.LibNames) {
|
||||
tgt->AppendProperty("INTERFACE_LINK_LIBRARIES", flag.substr(2));
|
||||
}
|
||||
for (auto const& flag : libs.LibDirs) {
|
||||
tgt->AppendProperty("INTERFACE_LINK_DIRECTORIES", flag.substr(2));
|
||||
}
|
||||
tgt->AppendProperty("INTERFACE_LINK_OPTIONS",
|
||||
cmList::to_string(libs.LinkOptions));
|
||||
|
||||
auto cflags = pkg.Cflags();
|
||||
for (auto const& flag : cflags.Includes) {
|
||||
tgt->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES", flag.substr(2));
|
||||
}
|
||||
tgt->AppendProperty("INTERFACE_COMPILE_OPTIONS",
|
||||
cmList::to_string(cflags.CompileOptions));
|
||||
|
||||
for (auto& dep : pkg.Requires()) {
|
||||
auto it = providers.find(dep.Name);
|
||||
if (it != providers.end()) {
|
||||
tgt->AppendProperty("INTERFACE_LINK_LIBRARIES", it->second);
|
||||
continue;
|
||||
}
|
||||
|
||||
tgt->AppendProperty("INTERFACE_LINK_LIBRARIES",
|
||||
cmStrCat("@foreign_pkgcfg::", dep.Name));
|
||||
}
|
||||
return tgt;
|
||||
}
|
||||
|
||||
bool CheckPackageDependencies(
|
||||
std::string const& name, cmPkgConfigResult& pkg, pkgStack& inStack,
|
||||
std::unordered_map<std::string, cmPkgConfigResult>& outStack,
|
||||
pkgProviders& providers, ImportEnv& imEnv)
|
||||
{
|
||||
for (auto& dep : pkg.Requires()) {
|
||||
auto prov_it = providers.find(dep.Name);
|
||||
if (prov_it != providers.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* tgt = imEnv.status.GetMakefile().FindTargetToUse(
|
||||
cmStrCat("@foreign_pkgcfg::", dep.Name),
|
||||
cmStateEnums::TargetDomain::FOREIGN);
|
||||
if (tgt) {
|
||||
auto ver = tgt->GetProperty("VERSION");
|
||||
if (!cmPkgConfigResolver::CheckVersion(dep.VerReq, *ver)) {
|
||||
warn_or_error(cmStrCat("Package '", dep.Name, "' version '", *ver,
|
||||
"' does not meet version requirement '",
|
||||
dep.VerReq.string(), "' ", "of '", name, "'"),
|
||||
imEnv);
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
auto it = outStack.find(dep.Name);
|
||||
if (it != outStack.end()) {
|
||||
auto ver = it->second.Version();
|
||||
if (!cmPkgConfigResolver::CheckVersion(dep.VerReq, ver)) {
|
||||
warn_or_error(cmStrCat("Package '", dep.Name, "' version '", ver,
|
||||
"' does not meet version requirement '",
|
||||
dep.VerReq.string(), "' ", "of '", name, "'"),
|
||||
imEnv);
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
inStack[dep.Name].emplace_back(
|
||||
pkgStackEntry{ std::move(dep.VerReq), name });
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct PopulateArguments : CommonArguments
|
||||
{
|
||||
cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> providers;
|
||||
};
|
||||
|
||||
auto const PopulateParser =
|
||||
BIND_COMMON(PopulateArguments)
|
||||
.Bind("BIND_PC_REQUIRES"_s, &PopulateArguments::providers);
|
||||
|
||||
std::pair<bool, bool> PopulatePCTarget(PopulateArguments& args,
|
||||
cmExecutionStatus& status)
|
||||
{
|
||||
|
||||
auto& mf = status.GetMakefile();
|
||||
auto maybeEnv = HandleCommon(args, status);
|
||||
|
||||
if (!maybeEnv) {
|
||||
return { !args.Required, false };
|
||||
}
|
||||
auto& pcEnv = maybeEnv->first;
|
||||
auto& imEnv = maybeEnv->second;
|
||||
|
||||
pkgProviders 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),
|
||||
provider_str.substr(assignment + 1));
|
||||
} else {
|
||||
imEnv.status.SetError(cmStrCat(
|
||||
"No '=' found in BIND_PC_REQUIRES argument '", provider_str, "'"));
|
||||
cmSystemTools::SetFatalErrorOccurred();
|
||||
return { false, false };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pkgStack inStack;
|
||||
std::unordered_map<std::string, cmPkgConfigResult> outStack;
|
||||
|
||||
auto maybePackage = ImportPackage(*args.Package, args.Version, imEnv, pcEnv);
|
||||
if (!maybePackage) {
|
||||
return { !args.Required, false };
|
||||
}
|
||||
imEnv.exact = false;
|
||||
|
||||
if (!CheckPackageDependencies(*args.Package, *maybePackage, inStack,
|
||||
outStack, providers, imEnv)) {
|
||||
return { !args.Required, false };
|
||||
}
|
||||
outStack[*args.Package] = std::move(*maybePackage);
|
||||
|
||||
while (!inStack.empty()) {
|
||||
auto name = inStack.begin()->first;
|
||||
auto reqs = inStack.begin()->second;
|
||||
maybePackage = ImportPackage(name, reqs, imEnv, pcEnv);
|
||||
if (!maybePackage) {
|
||||
return { !args.Required, false };
|
||||
}
|
||||
if (!CheckPackageDependencies(name, *maybePackage, inStack, outStack,
|
||||
providers, imEnv)) {
|
||||
return { !args.Required, false };
|
||||
}
|
||||
inStack.erase(name);
|
||||
outStack[std::move(name)] = std::move(*maybePackage);
|
||||
}
|
||||
|
||||
for (auto& entry : outStack) {
|
||||
CreateCMakeTarget(entry.first, entry.second, providers, mf);
|
||||
}
|
||||
|
||||
return { true, true };
|
||||
}
|
||||
|
||||
bool HandlePopulateCommand(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 found_var = cmStrCat("PKGCONFIG_", *parsedArgs.Package, "_FOUND");
|
||||
|
||||
auto& mf = status.GetMakefile();
|
||||
|
||||
if (mf.FindTargetToUse(foreign_name, cmStateEnums::TargetDomain::FOREIGN)) {
|
||||
mf.AddDefinition(found_var, "TRUE");
|
||||
return true;
|
||||
}
|
||||
|
||||
auto result = PopulatePCTarget(parsedArgs, status);
|
||||
mf.AddDefinition(found_var, result.second ? "TRUE" : "FALSE");
|
||||
return result.first;
|
||||
}
|
||||
|
||||
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 found_var = cmStrCat("PKGCONFIG_", *parsedArgs.Package, "_FOUND");
|
||||
|
||||
auto& mf = status.GetMakefile();
|
||||
|
||||
if (mf.FindTargetToUse(local_name)) {
|
||||
mf.AddDefinition(found_var, "TRUE");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!mf.FindTargetToUse(foreign_name, cmStateEnums::TargetDomain::FOREIGN)) {
|
||||
auto result = PopulatePCTarget(parsedArgs, status);
|
||||
if (!result.second) {
|
||||
mf.AddDefinition(found_var, "FALSE");
|
||||
return result.first;
|
||||
}
|
||||
}
|
||||
|
||||
mf.AddDefinition(found_var, "TRUE");
|
||||
auto* tgt = mf.AddImportedTarget(
|
||||
local_name, cmStateEnums::TargetType::INTERFACE_LIBRARY, false);
|
||||
tgt->AppendProperty("INTERFACE_LINK_LIBRARIES", foreign_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool cmCMakePkgConfigCommand(std::vector<std::string> const& args,
|
||||
@@ -716,6 +1019,8 @@ bool cmCMakePkgConfigCommand(std::vector<std::string> const& args,
|
||||
|
||||
static cmSubcommandTable const subcommand{
|
||||
{ "EXTRACT"_s, HandleExtractCommand },
|
||||
{ "POPULATE"_s, HandlePopulateCommand },
|
||||
{ "IMPORT"_s, HandleImportCommand },
|
||||
};
|
||||
|
||||
return subcommand(args[0], args, status);
|
||||
|
||||
@@ -3796,14 +3796,14 @@ cmTarget* cmMakefile::AddImportedTarget(std::string const& name,
|
||||
cmTarget* cmMakefile::AddForeignTarget(std::string const& origin,
|
||||
std::string const& name)
|
||||
{
|
||||
auto foreign_name = cmStrCat("@foreign_", origin, "::", name);
|
||||
std::unique_ptr<cmTarget> target(new cmTarget(
|
||||
cmStrCat("@foreign_", origin, "::", name),
|
||||
cmStateEnums::TargetType::INTERFACE_LIBRARY, cmTarget::Visibility::Foreign,
|
||||
this, cmTarget::PerConfig::Yes));
|
||||
foreign_name, cmStateEnums::TargetType::INTERFACE_LIBRARY,
|
||||
cmTarget::Visibility::Foreign, this, cmTarget::PerConfig::Yes));
|
||||
|
||||
this->ImportedTargets[name] = target.get();
|
||||
this->ImportedTargets[foreign_name] = target.get();
|
||||
this->GetGlobalGenerator()->IndexTarget(target.get());
|
||||
this->GetStateSnapshot().GetDirectory().AddImportedTargetName(name);
|
||||
this->GetStateSnapshot().GetDirectory().AddImportedTargetName(foreign_name);
|
||||
|
||||
this->ImportedTargetsOwned.push_back(std::move(target));
|
||||
return this->ImportedTargetsOwned.back().get();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <cm/string_view>
|
||||
|
||||
#include "cmPkgConfigParser.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -57,6 +58,27 @@ std::string AppendAndTrim(std::string& str, cm::string_view sv)
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string cmPkgConfigVersionReq::string() const
|
||||
{
|
||||
switch (Operation) {
|
||||
case ANY:
|
||||
return "";
|
||||
case LT:
|
||||
return cmStrCat("<", Version);
|
||||
case LT_EQ:
|
||||
return cmStrCat("<=", Version);
|
||||
case EQ:
|
||||
return cmStrCat("=", Version);
|
||||
case NEQ:
|
||||
return cmStrCat("!=", Version);
|
||||
case GT_EQ:
|
||||
return cmStrCat(">=", Version);
|
||||
case GT:
|
||||
return cmStrCat(">", Version);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string cmPkgConfigResult::StrOrDefault(std::string const& key,
|
||||
cm::string_view def)
|
||||
{
|
||||
@@ -127,24 +149,24 @@ cmPkgConfigCflagsResult cmPkgConfigResult::Cflags(bool priv)
|
||||
|
||||
auto tokens = cmPkgConfigResolver::TokenizeFlags(cflags);
|
||||
|
||||
if (env.AllowSysCflags) {
|
||||
if (env.SysrootDir) {
|
||||
return cmPkgConfigResolver::MangleCflags(tokens, *env.SysrootDir);
|
||||
if (env->AllowSysCflags) {
|
||||
if (env->SysrootDir) {
|
||||
return cmPkgConfigResolver::MangleCflags(tokens, *env->SysrootDir);
|
||||
}
|
||||
return cmPkgConfigResolver::MangleCflags(tokens);
|
||||
}
|
||||
|
||||
if (env.SysCflags) {
|
||||
if (env.SysrootDir) {
|
||||
return cmPkgConfigResolver::MangleCflags(tokens, *env.SysrootDir,
|
||||
*env.SysCflags);
|
||||
if (env->SysCflags) {
|
||||
if (env->SysrootDir) {
|
||||
return cmPkgConfigResolver::MangleCflags(tokens, *env->SysrootDir,
|
||||
*env->SysCflags);
|
||||
}
|
||||
return cmPkgConfigResolver::MangleCflags(tokens, *env.SysCflags);
|
||||
return cmPkgConfigResolver::MangleCflags(tokens, *env->SysCflags);
|
||||
}
|
||||
|
||||
if (env.SysrootDir) {
|
||||
if (env->SysrootDir) {
|
||||
return cmPkgConfigResolver::MangleCflags(
|
||||
tokens, *env.SysrootDir, std::vector<std::string>{ "/usr/include" });
|
||||
tokens, *env->SysrootDir, std::vector<std::string>{ "/usr/include" });
|
||||
}
|
||||
|
||||
return cmPkgConfigResolver::MangleCflags(
|
||||
@@ -160,24 +182,24 @@ cmPkgConfigLibsResult cmPkgConfigResult::Libs(bool priv)
|
||||
|
||||
auto tokens = cmPkgConfigResolver::TokenizeFlags(it->second);
|
||||
|
||||
if (env.AllowSysLibs) {
|
||||
if (env.SysrootDir) {
|
||||
return cmPkgConfigResolver::MangleLibs(tokens, *env.SysrootDir);
|
||||
if (env->AllowSysLibs) {
|
||||
if (env->SysrootDir) {
|
||||
return cmPkgConfigResolver::MangleLibs(tokens, *env->SysrootDir);
|
||||
}
|
||||
return cmPkgConfigResolver::MangleLibs(tokens);
|
||||
}
|
||||
|
||||
if (env.SysLibs) {
|
||||
if (env.SysrootDir) {
|
||||
return cmPkgConfigResolver::MangleLibs(tokens, *env.SysrootDir,
|
||||
*env.SysLibs);
|
||||
if (env->SysLibs) {
|
||||
if (env->SysrootDir) {
|
||||
return cmPkgConfigResolver::MangleLibs(tokens, *env->SysrootDir,
|
||||
*env->SysLibs);
|
||||
}
|
||||
return cmPkgConfigResolver::MangleLibs(tokens, *env.SysLibs);
|
||||
return cmPkgConfigResolver::MangleLibs(tokens, *env->SysLibs);
|
||||
}
|
||||
|
||||
if (env.SysrootDir) {
|
||||
if (env->SysrootDir) {
|
||||
return cmPkgConfigResolver::MangleLibs(
|
||||
tokens, *env.SysrootDir, std::vector<std::string>{ "/usr/lib" });
|
||||
tokens, *env->SysrootDir, std::vector<std::string>{ "/usr/lib" });
|
||||
}
|
||||
|
||||
return cmPkgConfigResolver::MangleLibs(
|
||||
@@ -210,7 +232,7 @@ cm::optional<cmPkgConfigResult> cmPkgConfigResolver::ResolveStrict(
|
||||
config.Variables["pc_top_builddir"] = *env.TopBuildDir;
|
||||
}
|
||||
|
||||
config.env = std::move(env);
|
||||
config.env = &env;
|
||||
|
||||
for (auto const& entry : entries) {
|
||||
std::string key(entry.Key);
|
||||
@@ -288,7 +310,7 @@ cmPkgConfigResult cmPkgConfigResolver::ResolveBestEffort(
|
||||
result.Variables["pc_top_builddir"] = *env.TopBuildDir;
|
||||
}
|
||||
|
||||
result.env = std::move(env);
|
||||
result.env = &env;
|
||||
|
||||
for (auto const& entry : entries) {
|
||||
std::string key(entry.Key);
|
||||
|
||||
@@ -43,6 +43,8 @@ struct cmPkgConfigVersionReq
|
||||
GT,
|
||||
} Operation = ANY;
|
||||
std::string Version;
|
||||
|
||||
std::string string() const;
|
||||
};
|
||||
|
||||
struct cmPkgConfigDependency
|
||||
@@ -60,6 +62,7 @@ struct cmPkgConfigEnv
|
||||
|
||||
cm::optional<std::string> SysrootDir;
|
||||
cm::optional<std::string> TopBuildDir;
|
||||
std::vector<std::string> search;
|
||||
|
||||
cm::optional<bool> DisableUninstalled;
|
||||
|
||||
@@ -84,7 +87,7 @@ public:
|
||||
cmPkgConfigCflagsResult Cflags(bool priv = false);
|
||||
cmPkgConfigLibsResult Libs(bool priv = false);
|
||||
|
||||
cmPkgConfigEnv env;
|
||||
cmPkgConfigEnv* env;
|
||||
|
||||
private:
|
||||
std::string StrOrDefault(std::string const& key, cm::string_view def = "");
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,4 @@
|
||||
CMake Error at ExtractRequired.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
cmake_pkg_config Could not find pkg-config: 'does-not-exist'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+4
-4
@@ -1,25 +1,25 @@
|
||||
CMake Warning at TestStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Resolution failed for file[^
|
||||
]*(.)*/PackageRoot/no-name.pc'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Resolution failed for file[^
|
||||
]*(.)*/PackageRoot/no-description.pc'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Resolution failed for file[^
|
||||
]*(.)*/PackageRoot/no-version.pc'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Parsing failed for file[^
|
||||
]*(.)*/PackageRoot/invalid.pc'
|
||||
Call Stack \(most recent call first\):
|
||||
+5
-5
@@ -1,25 +1,25 @@
|
||||
CMake Warning at TestStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Resolution failed for file[^
|
||||
]*(.)*/PackageRoot/no-name.pc'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Resolution failed for file[^
|
||||
]*(.)*/PackageRoot/no-description.pc'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Resolution failed for file[^
|
||||
]*(.)*/PackageRoot/no-version.pc'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Parsing failed for file[^
|
||||
]*(.)*/PackageRoot/invalid.pc'
|
||||
Call Stack \(most recent call first\):
|
||||
@@ -28,7 +28,7 @@ Call Stack \(most recent call first\):
|
||||
|
||||
Cflags: lowercase
|
||||
CFlags: uppercase
|
||||
CMake Warning at TestStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Resolution failed for file[^
|
||||
]*(.)*/PackageRoot/cflags-bothcase-f.pc'
|
||||
Call Stack \(most recent call first\):
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+17
-17
@@ -1,103 +1,103 @@
|
||||
CMake Warning at TestVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Package 'a' version 'aa' does not meet version requirement '<a'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Package 'a' version 'aa' does not meet version requirement '>aaa'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Package 'a' version 'aa' does not meet version requirement '>bb'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Package 'a' version 'aa' does not meet version requirement '>1'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Package 'empty-key' version '' does not meet version requirement '!='
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Package 'empty-key' version '' does not meet version requirement '=0'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Package 'one' version '11' does not meet version requirement '<1'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Package 'one' version '11' does not meet version requirement '>111'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Package 'one' version '11' does not meet version requirement '>22'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Package 'one' version '11' does not meet version requirement '<a'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Package 'onedot' version '1.1.1' does not meet version requirement '>1.2.1'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Package 'onedot' version '1.1.1' does not meet version requirement '>
|
||||
1.2.1'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Package 'onedot' version '1.1.1' does not meet exact version requirement
|
||||
'01.01.01'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Package 'pseudo-empty' version '~0' does not meet version requirement '=~'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Package 'pseudo-empty' version '~0' does not meet version requirement
|
||||
'!=~0'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Package 'tilde' version '~~1' does not meet version requirement '>~1'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
CMake Warning at TestVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
CMake Warning at ExtractVersion.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Package 'tilde' version '~~1' does not meet version requirement '<~~~1'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
File renamed without changes.
@@ -0,0 +1,14 @@
|
||||
set(expected
|
||||
"alpha: Alpha
|
||||
bravo: Bravo;Alpha
|
||||
charlie: Charlie;Bravo;Alpha
|
||||
delta: Delta
|
||||
echo: Echo;Bravo;Alpha;Delta
|
||||
"
|
||||
)
|
||||
|
||||
file(READ "${RunCMake_TEST_BINARY_DIR}/import-requires.txt" actual)
|
||||
|
||||
if(NOT(expected STREQUAL actual))
|
||||
set(RunCMake_TEST_FAILED "cmake_pkg_config import-requires.txt does not match expected:\n${actual}")
|
||||
endif()
|
||||
@@ -0,0 +1,18 @@
|
||||
set(CMAKE_PKG_CONFIG_PC_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageRoot/RequiresPackages)
|
||||
|
||||
cmake_pkg_config(IMPORT echo REQUIRED)
|
||||
cmake_pkg_config(IMPORT delta REQUIRED)
|
||||
cmake_pkg_config(IMPORT charlie REQUIRED)
|
||||
cmake_pkg_config(IMPORT bravo REQUIRED)
|
||||
cmake_pkg_config(IMPORT alpha REQUIRED)
|
||||
|
||||
file(GENERATE
|
||||
OUTPUT import-requires.txt
|
||||
CONTENT
|
||||
"alpha: $<TARGET_PROPERTY:PkgConfig::alpha,INTERFACE_COMPILE_OPTIONS>
|
||||
bravo: $<TARGET_PROPERTY:PkgConfig::bravo,INTERFACE_COMPILE_OPTIONS>
|
||||
charlie: $<TARGET_PROPERTY:PkgConfig::charlie,INTERFACE_COMPILE_OPTIONS>
|
||||
delta: $<TARGET_PROPERTY:PkgConfig::delta,INTERFACE_COMPILE_OPTIONS>
|
||||
echo: $<TARGET_PROPERTY:PkgConfig::echo,INTERFACE_COMPILE_OPTIONS>
|
||||
"
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
set(expected
|
||||
"Import Simple Found: TRUE
|
||||
Include Directories: ${RunCMake_SOURCE_DIR}/TestDirectories/Include
|
||||
Compile Options: TestCflag
|
||||
Link Directories: ${RunCMake_SOURCE_DIR}/TestDirectories/Library
|
||||
Link Libraries: @foreign_pkgcfg::import-simple
|
||||
Link Options: TestLinkOption
|
||||
"
|
||||
)
|
||||
|
||||
file(READ "${RunCMake_TEST_BINARY_DIR}/import-simple.txt" actual)
|
||||
|
||||
if(NOT(expected STREQUAL actual))
|
||||
set(RunCMake_TEST_FAILED "cmake_pkg_config import-simple.txt does not match expected:\n${actual}")
|
||||
endif()
|
||||
@@ -0,0 +1,15 @@
|
||||
set(CMAKE_PKG_CONFIG_SYSROOT_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
cmake_pkg_config(IMPORT import-simple REQUIRED)
|
||||
|
||||
file(GENERATE
|
||||
OUTPUT import-simple.txt
|
||||
CONTENT
|
||||
"Import Simple Found: ${PKGCONFIG_import-simple_FOUND}
|
||||
Include Directories: $<TARGET_PROPERTY:PkgConfig::import-simple,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
Compile Options: $<TARGET_PROPERTY:PkgConfig::import-simple,INTERFACE_COMPILE_OPTIONS>
|
||||
Link Directories: $<TARGET_PROPERTY:PkgConfig::import-simple,INTERFACE_LINK_DIRECTORIES>
|
||||
Link Libraries: $<TARGET_PROPERTY:PkgConfig::import-simple,INTERFACE_LINK_LIBRARIES>
|
||||
Link Options: $<TARGET_PROPERTY:PkgConfig::import-simple,INTERFACE_LINK_OPTIONS>
|
||||
"
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,11 @@
|
||||
CMake Warning at ImportTransitiveFail.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Could not find pkg-config: 'foxtrot' required by: 'golf'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
Import Golf Found: FALSE
|
||||
CMake Error at ImportTransitiveFail.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
cmake_pkg_config Could not find pkg-config: 'foxtrot' required by: 'golf'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
@@ -0,0 +1,5 @@
|
||||
set(CMAKE_PKG_CONFIG_PC_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageRoot/RequiresPackages)
|
||||
|
||||
cmake_pkg_config(IMPORT golf)
|
||||
message("Import Golf Found: ${PKGCONFIG_golf_FOUND}")
|
||||
cmake_pkg_config(IMPORT golf REQUIRED)
|
||||
@@ -0,0 +1,3 @@
|
||||
set(CMAKE_PKG_CONFIG_PC_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageRoot/RequiresPackages)
|
||||
|
||||
cmake_pkg_config(IMPORT india)
|
||||
@@ -0,0 +1,5 @@
|
||||
CMake Warning at ImportTransitiveVersionFail.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Package 'alpha' version '1.0.0' does not meet version requirement '>=2.0.0'
|
||||
of 'hotel'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
@@ -0,0 +1,4 @@
|
||||
set(CMAKE_PKG_CONFIG_PC_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageRoot/RequiresPackages)
|
||||
|
||||
cmake_pkg_config(POPULATE bravo)
|
||||
cmake_pkg_config(IMPORT hotel)
|
||||
@@ -0,0 +1,5 @@
|
||||
Name: Alpha
|
||||
Description: Alpha
|
||||
Version: 1.0.0
|
||||
|
||||
Cflags: Alpha
|
||||
@@ -0,0 +1,6 @@
|
||||
Name: Bravo
|
||||
Description: Bravo
|
||||
Version: 1.0.0
|
||||
|
||||
Cflags: Bravo
|
||||
Requires: alpha
|
||||
@@ -0,0 +1,6 @@
|
||||
Name: Charlie
|
||||
Description: Charlie
|
||||
Version: 1.0.0
|
||||
|
||||
Cflags: Charlie
|
||||
Requires: bravo
|
||||
@@ -0,0 +1,5 @@
|
||||
Name: Delta
|
||||
Description: Delta
|
||||
Version: 1.0.0
|
||||
|
||||
Cflags: Delta
|
||||
@@ -0,0 +1,6 @@
|
||||
Name: Echo
|
||||
Description: Echo
|
||||
Version: 1.0.0
|
||||
|
||||
Cflags: Echo
|
||||
Requires: bravo delta
|
||||
@@ -0,0 +1,6 @@
|
||||
Name: Golf
|
||||
Description: Golf
|
||||
Version: 1.0.0
|
||||
|
||||
Cflags: Golf
|
||||
Requires: foxtrot
|
||||
@@ -0,0 +1,6 @@
|
||||
Name: Hotel
|
||||
Description: Hotel
|
||||
Version: 1.0.0
|
||||
|
||||
Cflags: Hotel
|
||||
Requires: alpha >= 2.0.0
|
||||
@@ -0,0 +1,6 @@
|
||||
Name: India
|
||||
Description: India
|
||||
Version: 1.0.0
|
||||
|
||||
Cflags: India
|
||||
Requires: alpha = 1.0.0 bravo > 0.5.0
|
||||
@@ -0,0 +1,6 @@
|
||||
Name: Juliet
|
||||
Description: Juliet
|
||||
Version: 1.0.0
|
||||
|
||||
Cflags: Juliet
|
||||
Requires: golf
|
||||
@@ -0,0 +1,6 @@
|
||||
Name: Import Simple
|
||||
Description: A simple import with no dependencies
|
||||
Version: 1.0.0
|
||||
|
||||
Cflags: -I/TestDirectories/Include TestCflag
|
||||
Libs: -L/TestDirectories/Library -ldummy TestLinkOption
|
||||
@@ -0,0 +1,8 @@
|
||||
Found Alpha: TRUE
|
||||
CMake Warning at PopulateFoundVar.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Could not find pkg-config: 'foxtrot'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
Found Foxtrot: FALSE
|
||||
@@ -0,0 +1,7 @@
|
||||
set(CMAKE_PKG_CONFIG_PC_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageRoot/RequiresPackages)
|
||||
|
||||
cmake_pkg_config(POPULATE alpha)
|
||||
message("Found Alpha: ${PKGCONFIG_alpha_FOUND}")
|
||||
|
||||
cmake_pkg_config(POPULATE foxtrot)
|
||||
message("Found Foxtrot: ${PKGCONFIG_foxtrot_FOUND}")
|
||||
@@ -0,0 +1,10 @@
|
||||
set(expected
|
||||
"juliet: Juliet;Golf;Foxtrot
|
||||
"
|
||||
)
|
||||
|
||||
file(READ "${RunCMake_TEST_BINARY_DIR}/populate-missing.txt" actual)
|
||||
|
||||
if(NOT(expected STREQUAL actual))
|
||||
set(RunCMake_TEST_FAILED "cmake_pkg_config populate-missing.txt does not match expected:\n${actual}")
|
||||
endif()
|
||||
@@ -0,0 +1,19 @@
|
||||
set(CMAKE_PKG_CONFIG_PC_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageRoot/RequiresPackages)
|
||||
|
||||
add_library(native-foxtrot INTERFACE)
|
||||
target_compile_options(native-foxtrot INTERFACE Foxtrot)
|
||||
|
||||
cmake_pkg_config(
|
||||
POPULATE golf
|
||||
BIND_PC_REQUIRES
|
||||
foxtrot=native-foxtrot
|
||||
)
|
||||
|
||||
cmake_pkg_config(IMPORT juliet)
|
||||
|
||||
file(GENERATE
|
||||
OUTPUT populate-missing.txt
|
||||
CONTENT
|
||||
"juliet: $<TARGET_PROPERTY:PkgConfig::juliet,INTERFACE_COMPILE_OPTIONS>
|
||||
"
|
||||
)
|
||||
@@ -3,16 +3,23 @@ include(RunCMake)
|
||||
set(cmd ${CMAKE_COMMAND} ${CMAKE_CURRENT_LIST_DIR} -G ${RunCMake_GENERATOR})
|
||||
|
||||
foreach(strictness IN ITEMS STRICT PERMISSIVE BEST_EFFORT)
|
||||
run_cmake_command(TestStrictness-${strictness} ${cmd}
|
||||
-DRunCMake_TEST=TestStrictness -DSTRICTNESS=${strictness}
|
||||
run_cmake_command(ExtractStrictness-${strictness} ${cmd}
|
||||
-DRunCMake_TEST=ExtractStrictness -DSTRICTNESS=${strictness}
|
||||
)
|
||||
endforeach()
|
||||
|
||||
run_cmake(TestEnv)
|
||||
run_cmake(TestExtract)
|
||||
run_cmake(TestMangle)
|
||||
run_cmake(TestQuiet)
|
||||
run_cmake(TestRequired)
|
||||
run_cmake(TestReroot)
|
||||
run_cmake(TestUninstalled)
|
||||
run_cmake(TestVersion)
|
||||
run_cmake(ExtractEnv)
|
||||
run_cmake(ExtractFields)
|
||||
run_cmake(ExtractMangle)
|
||||
run_cmake(ExtractQuiet)
|
||||
run_cmake(ExtractRequired)
|
||||
run_cmake(ExtractReroot)
|
||||
run_cmake(ExtractUninstalled)
|
||||
run_cmake(ExtractVersion)
|
||||
run_cmake(ImportSimple)
|
||||
run_cmake(ImportRequires)
|
||||
run_cmake(ImportTransitiveFail)
|
||||
run_cmake(ImportTransitiveVersion)
|
||||
run_cmake(ImportTransitiveVersionFail)
|
||||
run_cmake(PopulateFoundVar)
|
||||
run_cmake(PopulateMissing)
|
||||
Whitespace-only changes.
Whitespace-only changes.
@@ -1,4 +0,0 @@
|
||||
CMake Error at TestRequired.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
cmake_pkg_config Could not find 'does-not-exist'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
Reference in new issue
Block a user