mirror of
https://github.com/Kitware/CMake.git
synced 2025-12-31 10:50:16 -06:00
PkgC: Add cmake_pkg_config(EXTRACT) command
* Wraps the llpkgc parser with cmPkgConfigParser * Adds various resolution and mangling code under cmPkgConfigResolver * Documents new command cmake_pkg_config(EXTRACT). Documentation is written with the assumption additional subcommands will be added soon. * Adds various tests for the above
This commit is contained in:
261
Help/command/cmake_pkg_config.rst
Normal file
261
Help/command/cmake_pkg_config.rst
Normal file
@@ -0,0 +1,261 @@
|
||||
cmake_pkg_config
|
||||
----------------
|
||||
|
||||
.. only:: html
|
||||
|
||||
.. contents::
|
||||
|
||||
Process pkg-config format package files.
|
||||
|
||||
Synopsis
|
||||
^^^^^^^^
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
cmake_pkg_config(EXTRACT <package> [<version>] [...])
|
||||
|
||||
Introduction
|
||||
^^^^^^^^^^^^
|
||||
|
||||
This command generates CMake variables and targets from pkg-config format
|
||||
package files natively, without needing to invoke or even require the presence
|
||||
of a pkg-config implementation. A ``<package>`` is either an absolute path to a
|
||||
package file, or a package name to be searched for using the typical pkg-config
|
||||
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`:
|
||||
|
||||
There are multiple signatures for this command, and some of the options are
|
||||
common between them. They are:
|
||||
|
||||
``EXACT`` / ``QUIET`` / ``REQUIRED``
|
||||
The ``EXACT`` option requests that the version string be matched exactly
|
||||
(including empty string, if no version is provided), overriding the typical
|
||||
pkg-config version comparison algorithm. This will ignore any comparison
|
||||
operator attached to the version string.
|
||||
|
||||
The ``QUIET`` option disables informational messages, including those
|
||||
indicating that the package cannot be found if it is not ``REQUIRED``. The
|
||||
``REQUIRED`` option stops processing with an error message if the package
|
||||
cannot be found.
|
||||
|
||||
``STRICTNESS <mode>``
|
||||
Specify how strictly the contents of the package files will be verified during
|
||||
parsing and resolution. An invalid file, under the provided strictness mode,
|
||||
will cause the command to fail. Possible modes are:
|
||||
|
||||
* ``STRICT``: Closely mirrors the behavior of the original FDO pkg-config.
|
||||
Variables and keywords must be unique. Variables must be defined before
|
||||
they are used. The Name, Description, and Version keywords must be present.
|
||||
The overall structure of the file must be valid and parsable.
|
||||
|
||||
* ``PERMISSIVE``: Closely mirrors the behavior of the pkgconf implementation.
|
||||
Duplicate variables are overridden. Duplicate keywords are appended.
|
||||
Undefined variables resolve to empty strings. The Name, Description, and
|
||||
Version keywords must be present. The overall structure of the file must be
|
||||
valid and parsable.
|
||||
|
||||
* ``BEST_EFFORT``: Same behavior as ``PERMISSIVE`` with regards to duplicate
|
||||
or uninitialized variables and keywords, but will not fail under any
|
||||
conditions. Package files which require BEST_EFFORT will fail validation
|
||||
under all other major implementations and should be fixed.
|
||||
|
||||
The default strictness is ``PERMISSIVE``.
|
||||
|
||||
``ENV_MODE``
|
||||
Specifies which environment variables will be queried when running a given
|
||||
command. Possible modes are:
|
||||
|
||||
* ``FDO``: Queries only the original set of ``PKG_CONFIG_*`` environment
|
||||
variables used by the freedesktop.org ``pkg-config`` implementation.
|
||||
|
||||
* ``PKGCONF``: Queries the more extensive set of environment variables used
|
||||
by the ``pkgconf`` implementation.
|
||||
|
||||
* ``IGNORE``: Ignores the presence, absence, and value of environment
|
||||
variables entirely. In all cases an environment variable would be queried
|
||||
its treated as defined, but with a value of empty string for the purpose
|
||||
of the operation. This does not modify the current environment. For boolean
|
||||
environment variables, such as ``PKG_CONFIG_ALLOW_*``, this means they are
|
||||
evaluated as truthy.
|
||||
|
||||
``PKG_CONFIG_SYSROOT_PATH`` is a minor exception. When ``ENV_MODE IGNORE``
|
||||
is used, no root path prepending will occur by default and ``pc_sysrootdir``
|
||||
remains defaulted to ``/``.
|
||||
|
||||
Target-generating subcommands always ignore flag-filtering environment
|
||||
variables. The default environment mode is ``PKGCONF``.
|
||||
|
||||
``PC_LIBDIR <path>...``
|
||||
Overrides the default search location for package files; also used to derive
|
||||
the ``pc_path`` package variable.
|
||||
|
||||
When this option is not provided, the default library directory is the first
|
||||
available of the following values:
|
||||
|
||||
#. ``CMAKE_PKG_CONFIG_PC_LIB_DIRS``
|
||||
#. The ``PKG_CONFIG_LIBDIR`` environment variable
|
||||
#. The output of ``pkg-config --variable pc_path pkg-config``
|
||||
#. A platform-dependent default value
|
||||
|
||||
``PC_PATH <path>...``
|
||||
Overrides the supplemental package file directories which will be prepended
|
||||
to the search path; also used to derive the ``pc_path`` package variable.
|
||||
|
||||
When this option is not provided, the default paths are the first available of
|
||||
the following values:
|
||||
|
||||
#. ``CMAKE_PKG_CONFIG_PC_PATH``
|
||||
#. The ``PKG_CONFIG_PATH`` environment variable
|
||||
#. Empty list
|
||||
|
||||
``DISABLE_UNINSTALLED <bool>``
|
||||
Overrides the search behavior for "uninstalled" package files. These are
|
||||
package files with an "-uninstalled" suffix which describe packages integrated
|
||||
directly from a build tree.
|
||||
|
||||
Normally such package files have higher priority than "installed" packages.
|
||||
When ``DISABLE_UNINSTALLED`` is true, searching for "uninstalled" packages
|
||||
is disabled.
|
||||
|
||||
When this option is not provided, the default search behavior is determined
|
||||
by the first available of the following values:
|
||||
|
||||
#. ``CMAKE_PKG_CONFIG_DISABLE_UNINSTALLED``
|
||||
#. If the ``PKG_CONFIG_DISABLE_UNINSTALLED`` environment variable is defined
|
||||
the search is disabled, otherwise it is enabled.
|
||||
|
||||
``PC_SYSROOT_DIR <path>``
|
||||
Overrides the root path which will be prepended to paths specified by ``-I``
|
||||
compile flags and ``-L`` library search locations; also used to derive the
|
||||
``pc_sysrootdir`` package variable.
|
||||
|
||||
When this option is not provided, the default root path is provided by the
|
||||
first available of the following values:
|
||||
|
||||
#. ``CMAKE_PKG_CONFIG_SYSROOT_DIR``
|
||||
#. The ``PKG_CONFIG_SYSROOT_DIR`` environment variable
|
||||
#. If no root path is available, nothing will be prepended to include or
|
||||
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``
|
||||
package variable.
|
||||
|
||||
When this option is not provided, the default top build directory path is
|
||||
the first available of the following values:
|
||||
|
||||
#. ``CMAKE_PKG_CONFIG_TOP_BUILD_DIR``
|
||||
#. The ``PKG_CONFIG_TOP_BUILD_DIR`` environment variable
|
||||
#. If no top build directory path is available, the ``pc_top_builddir``
|
||||
package variable is not set
|
||||
|
||||
Signatures
|
||||
^^^^^^^^^^
|
||||
|
||||
.. signature::
|
||||
cmake_pkg_config(EXTRACT <package> [<version>] [...])
|
||||
|
||||
Extract the contents of the package into variables.
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
cmake_pkg_config(EXTRACT <package> [<version>]
|
||||
[REQUIRED] [EXACT] [QUIET]
|
||||
[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>])
|
||||
|
||||
The following variables will be populated from the contents of package file:
|
||||
|
||||
==================================== ====== ========================================================================================
|
||||
Variable Type Definition
|
||||
==================================== ====== ========================================================================================
|
||||
``CMAKE_PKG_CONFIG_NAME`` String Value of the ``Name`` keyword
|
||||
``CMAKE_PKG_CONFIG_DESCRIPTION`` String Value of the ``Description`` keyword
|
||||
``CMAKE_PKG_CONFIG_VERSION`` String Value of the ``Version`` keyword
|
||||
``CMAKE_PKG_CONFIG_PROVIDES`` List Value of the ``Provides`` keyword
|
||||
``CMAKE_PKG_CONFIG_REQUIRES`` List Value of the ``Requires`` keyword
|
||||
``CMAKE_PKG_CONFIG_CONFLICTS`` List Value of the ``Conflicts`` keyword
|
||||
``CMAKE_PKG_CONFIG_CFLAGS`` String Value of the ``CFlags`` / ``Cflags`` keyword
|
||||
``CMAKE_PKG_CONFIG_INCLUDES`` List All ``-I`` prefixed flags from ``CMAKE_PKG_CONFIG_CFLAGS``
|
||||
``CMAKE_PKG_CONFIG_COMPILE_OPTIONS`` List All flags not prefixed with ``-I`` from ``CMAKE_PKG_CONFIG_CFLAGS``
|
||||
``CMAKE_PKG_CONFIG_LIBS`` String Value of the ``Libs`` keyword
|
||||
``CMAKE_PKG_CONFIG_LIBDIRS`` List All ``-L`` prefixed flags from ``CMAKE_PKG_CONFIG_LIBS``
|
||||
``CMAKE_PKG_CONFIG_LIBNAMES`` List All ``-l`` prefixed flags from ``CMAKE_PKG_CONFIG_LIBS``
|
||||
``CMAKE_PKG_CONFIG_LINK_OPTIONS`` List All flags not prefixed with ``-L`` or ``-l`` from ``CMAKE_PKG_CONFIG_LIBS``
|
||||
``CMAKE_PKG_CONFIG_*_PRIVATE`` \* ``CFLAGS`` / ``LIBS`` / ``REQUIRES`` and derived, but in their ``.private`` suffix forms
|
||||
==================================== ====== ========================================================================================
|
||||
|
||||
``SYSTEM_INCLUDE_DIRS``
|
||||
Overrides the "system" directories for the purpose of flag mangling include
|
||||
directories in ``CMAKE_PKG_CONFIG_CFLAGS`` and derived variables.
|
||||
|
||||
When this option is not provided, the default directories are provided by the
|
||||
first available of the following values:
|
||||
|
||||
#. ``CMAKE_PKG_CONFIG_SYS_INCLUDE_DIRS``
|
||||
#. The ``PKG_CONFIG_SYSTEM_INCLUDE_PATH`` environment variable
|
||||
#. The output of ``pkgconf --variable pc_system_includedirs pkg-config``
|
||||
#. A platform-dependent default value
|
||||
|
||||
Additionally, when the ``ENV_MODE`` is ``PKGCONF`` the
|
||||
``CMAKE_PKG_CONFIG_PKGCONF_INCLUDES`` variable will be concatenated to the
|
||||
list if available. If it is not available, the following environment variables
|
||||
will be queried and concatenated:
|
||||
|
||||
* ``CPATH``
|
||||
* ``C_INCLUDE_PATH``
|
||||
* ``CPLUS_INCLUDE_PATH``
|
||||
* ``OBJC_INCLUDE_PATH``
|
||||
* ``INCLUDE`` (Windows Only)
|
||||
|
||||
``SYSTEM_LIBRARY_DIRS``
|
||||
Overrides the "system" directories for the purpose of flag mangling library
|
||||
directories in ``CMAKE_PKG_CONFIG_LIBS`` and derived variables.
|
||||
|
||||
When this option is not provided, the default directories are provided by the
|
||||
first available of the following values:
|
||||
|
||||
#. ``CMAKE_PKG_CONFIG_SYS_LIB_DIRS``
|
||||
#. The ``PKG_CONFIG_SYSTEM_LIBRARY_PATH`` environment variable
|
||||
#. The output of ``pkgconf --variable pc_system_libdirs pkg-config``
|
||||
#. A platform-dependent default value
|
||||
|
||||
Additionally, when the ``ENV_MODE`` is ``PKGCONF`` the
|
||||
``CMAKE_PKG_CONFIG_PKGCONF_LIB_DIRS`` variable will be concatenated to the
|
||||
list if available. If it is not available, the ``LIBRARY_PATH`` environment
|
||||
variable will be queried and concatenated.
|
||||
|
||||
``ALLOW_SYSTEM_INCLUDES``
|
||||
Preserves "system" directories during flag mangling of include directories
|
||||
in ``CMAKE_PKG_CONFIG_CFLAGS`` and derived variables.
|
||||
|
||||
When this option is not provided, the default value is determined by the first
|
||||
available of the following values:
|
||||
|
||||
#. ``CMAKE_PKG_CONFIG_ALLOW_SYS_INCLUDES``
|
||||
#. If the ``PKG_CONFIG_ALLOW_SYSTEM_CFLAGS`` environment variable is defined
|
||||
the flags are preserved, otherwise they are filtered during flag mangling.
|
||||
|
||||
|
||||
``ALLOW_SYSTEM_LIBS``
|
||||
Preserves "system" directories during flag mangling of library directories
|
||||
in ``CMAKE_PKG_CONFIG_LIBS`` and derived variables.
|
||||
|
||||
When this option is not provided, the default value is determined by the first
|
||||
available of the following values:
|
||||
|
||||
#. ``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.
|
||||
@@ -22,6 +22,7 @@ These commands are always available.
|
||||
/command/cmake_minimum_required
|
||||
/command/cmake_parse_arguments
|
||||
/command/cmake_path
|
||||
/command/cmake_pkg_config
|
||||
/command/cmake_policy
|
||||
/command/configure_file
|
||||
/command/continue
|
||||
|
||||
@@ -373,6 +373,10 @@ add_library(
|
||||
cmLocalCommonGenerator.h
|
||||
cmLocalGenerator.cxx
|
||||
cmLocalGenerator.h
|
||||
cmPkgConfigParser.cxx
|
||||
cmPkgConfigParser.h
|
||||
cmPkgConfigResolver.cxx
|
||||
cmPkgConfigResolver.h
|
||||
cmPlaceholderExpander.cxx
|
||||
cmPlaceholderExpander.h
|
||||
cmRulePlaceholderExpander.cxx
|
||||
@@ -537,6 +541,8 @@ add_library(
|
||||
cmCMakeMinimumRequired.h
|
||||
cmCMakePathCommand.h
|
||||
cmCMakePathCommand.cxx
|
||||
cmCMakePkgConfigCommand.h
|
||||
cmCMakePkgConfigCommand.cxx
|
||||
cmCMakePolicyCommand.cxx
|
||||
cmCMakePolicyCommand.h
|
||||
cmConditionEvaluator.cxx
|
||||
|
||||
722
Source/cmCMakePkgConfigCommand.cxx
Normal file
722
Source/cmCMakePkgConfigCommand.cxx
Normal file
@@ -0,0 +1,722 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
|
||||
#include "cmCMakePkgConfigCommand.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/filesystem>
|
||||
#include <cm/optional>
|
||||
#include <cm/string_view>
|
||||
#include <cmext/string_view>
|
||||
|
||||
#include "cmsys/FStream.hxx"
|
||||
|
||||
#include "cmArgumentParser.h"
|
||||
#include "cmArgumentParserTypes.h"
|
||||
#include "cmExecutionStatus.h"
|
||||
#include "cmList.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmMessageType.h"
|
||||
#include "cmPkgConfigParser.h"
|
||||
#include "cmPkgConfigResolver.h"
|
||||
#include "cmStateTypes.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSubcommandTable.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmValue.h"
|
||||
#include <cmllpkgc/llpkgc.h>
|
||||
|
||||
// IWYU wants this
|
||||
namespace {
|
||||
struct ExtractArguments;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
cm::optional<std::string> GetPkgConfigBin(cmMakefile& mf)
|
||||
{
|
||||
cm::optional<std::string> result;
|
||||
|
||||
auto pkgcfg = mf.GetDefinition("CMAKE_PKG_CONFIG_BIN");
|
||||
if (pkgcfg.IsNOTFOUND()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (pkgcfg) {
|
||||
result = *pkgcfg;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string path = cmSystemTools::FindProgram("pkgconf");
|
||||
if (path.empty()) {
|
||||
path = cmSystemTools::FindProgram("pkg-config");
|
||||
if (path.empty()) {
|
||||
mf.AddCacheDefinition("CMAKE_PKG_CONFIG_BIN", "pkg-config-NOTFOUND",
|
||||
"Location of pkg-config or pkgconf binary",
|
||||
cmStateEnums::FILEPATH);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
mf.AddCacheDefinition("CMAKE_PKG_CONFIG_BIN", path,
|
||||
"Location of pkg-config or pkgconf binary",
|
||||
cmStateEnums::FILEPATH);
|
||||
|
||||
result = std::move(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetLocations(cmMakefile& mf, const char* cachevar,
|
||||
const char* envvar, const char* desc,
|
||||
const char* pcvar, bool need_pkgconf,
|
||||
std::vector<std::string> default_locs)
|
||||
{
|
||||
auto def = mf.GetDefinition(cachevar);
|
||||
if (def) {
|
||||
return cmList(def);
|
||||
}
|
||||
|
||||
std::string paths;
|
||||
if (cmSystemTools::GetEnv(envvar, paths)) {
|
||||
cmPkgConfigResolver::ReplaceSep(paths);
|
||||
mf.AddCacheDefinition(cachevar, paths, desc, cmStateEnums::STRING);
|
||||
return cmList(paths);
|
||||
}
|
||||
|
||||
auto pkgcfg = GetPkgConfigBin(mf);
|
||||
if (!pkgcfg || (need_pkgconf && (pkgcfg->find("pkgconf") == pkgcfg->npos))) {
|
||||
mf.AddCacheDefinition(cachevar, cmList::to_string(default_locs), desc,
|
||||
cmStateEnums::STRING);
|
||||
return default_locs;
|
||||
}
|
||||
|
||||
std::string out;
|
||||
cmSystemTools::RunSingleCommand({ *pkgcfg, pcvar, "pkg-config" }, &out,
|
||||
nullptr, nullptr, nullptr,
|
||||
cmSystemTools::OUTPUT_NONE);
|
||||
|
||||
cmPkgConfigResolver::ReplaceSep(out);
|
||||
out = cmTrimWhitespace(out);
|
||||
mf.AddCacheDefinition(cachevar, out, desc, cmStateEnums::STRING);
|
||||
return cmList(out);
|
||||
}
|
||||
|
||||
std::vector<std::string> GetPcLibDirs(cmMakefile& mf)
|
||||
{
|
||||
std::vector<std::string> default_locs = {
|
||||
#ifndef _WIN32
|
||||
"/usr/lib/pkgconfig", "/usr/share/pkgconfig"
|
||||
#endif
|
||||
};
|
||||
return GetLocations(mf, "CMAKE_PKG_CONFIG_PC_LIB_DIRS", "PKG_CONFIG_LIBDIR",
|
||||
"Default search locations for package files",
|
||||
"--variable=pc_path", false, std::move(default_locs));
|
||||
}
|
||||
|
||||
std::vector<std::string> GetSysLibDirs(cmMakefile& mf)
|
||||
{
|
||||
std::vector<std::string> default_locs = {
|
||||
#ifndef _WIN32
|
||||
"/lib", "/usr/lib"
|
||||
#endif
|
||||
};
|
||||
return GetLocations(
|
||||
mf, "CMAKE_PKG_CONFIG_SYS_LIB_DIRS", "PKG_CONFIG_SYSTEM_LIBRARY_PATH",
|
||||
"System library directories filtered by flag mangling",
|
||||
"--variable=pc_system_libdirs", true, std::move(default_locs));
|
||||
}
|
||||
|
||||
std::vector<std::string> GetSysCflags(cmMakefile& mf)
|
||||
{
|
||||
std::vector<std::string> default_locs = {
|
||||
#ifndef _WIN32
|
||||
"/usr/include"
|
||||
#endif
|
||||
};
|
||||
return GetLocations(
|
||||
mf, "CMAKE_PKG_CONFIG_SYS_INCLUDE_DIRS", "PKG_CONFIG_SYSTEM_INCLUDE_PATH",
|
||||
"System include directories filtered by flag mangling",
|
||||
"--variable=pc_system_includedirs", true, std::move(default_locs));
|
||||
}
|
||||
|
||||
std::vector<std::string> GetPkgConfSysLibs(cmMakefile& mf)
|
||||
{
|
||||
auto def = mf.GetDefinition("CMAKE_PKG_CONFIG_PKGCONF_LIB_DIRS");
|
||||
if (def) {
|
||||
return cmList(def);
|
||||
}
|
||||
|
||||
std::string paths;
|
||||
if (!cmSystemTools::GetEnv("LIBRARY_PATH", paths)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
cmPkgConfigResolver::ReplaceSep(paths);
|
||||
mf.AddCacheDefinition("CMAKE_PKG_CONFIG_PKGCONF_LIB_DIRS", paths,
|
||||
"Additional system library directories filtered by "
|
||||
"flag mangling in PKGCONF mode",
|
||||
cmStateEnums::STRING);
|
||||
return cmList(paths);
|
||||
}
|
||||
|
||||
std::vector<std::string> GetPkgConfSysCflags(cmMakefile& mf)
|
||||
{
|
||||
auto def = mf.GetDefinition("CMAKE_PKG_CONFIG_PKGCONF_INCLUDES");
|
||||
if (def) {
|
||||
return cmList(def);
|
||||
}
|
||||
|
||||
std::string paths;
|
||||
auto get_and_append = [&](const char* var) {
|
||||
if (paths.empty()) {
|
||||
cmSystemTools::GetEnv(var, paths);
|
||||
} else {
|
||||
std::string tmp;
|
||||
cmSystemTools::GetEnv(var, tmp);
|
||||
if (!tmp.empty()) {
|
||||
paths += ";" + tmp;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
get_and_append("CPATH");
|
||||
get_and_append("C_INCLUDE_PATH");
|
||||
get_and_append("CPLUS_INCLUDE_PATH");
|
||||
get_and_append("OBJC_INCLUDE_PATH");
|
||||
|
||||
#ifdef _WIN32
|
||||
get_and_append("INCLUDE");
|
||||
#endif
|
||||
|
||||
cmPkgConfigResolver::ReplaceSep(paths);
|
||||
mf.AddCacheDefinition("CMAKE_PKG_CONFIG_PKGCONF_INCLUDES", paths,
|
||||
"Additional system include directories filtered by "
|
||||
"flag mangling in PKGCONF mode",
|
||||
cmStateEnums::STRING);
|
||||
return cmList(paths);
|
||||
}
|
||||
|
||||
std::vector<std::string> GetPcPath(cmMakefile& mf)
|
||||
{
|
||||
auto def = mf.GetDefinition("CMAKE_PKG_CONFIG_PC_PATH");
|
||||
if (def) {
|
||||
return cmList(def);
|
||||
}
|
||||
|
||||
std::string pcpath;
|
||||
if (cmSystemTools::GetEnv("PKG_CONFIG_PATH", pcpath)) {
|
||||
auto result = cmSystemTools::SplitString(pcpath, cmPkgConfigResolver::Sep);
|
||||
mf.AddCacheDefinition(
|
||||
"CMAKE_PKG_CONFIG_PC_PATH", cmList::to_string(result),
|
||||
"Additional search locations for package files", cmStateEnums::STRING);
|
||||
return result;
|
||||
}
|
||||
|
||||
mf.AddCacheDefinition("CMAKE_PKG_CONFIG_PC_PATH", "",
|
||||
"Additional search locations for package files",
|
||||
cmStateEnums::STRING);
|
||||
return {};
|
||||
}
|
||||
|
||||
cm::optional<std::string> GetPath(cmMakefile& mf, const char* cachevar,
|
||||
const char* envvar, const char* desc)
|
||||
{
|
||||
cm::optional<std::string> result;
|
||||
|
||||
auto def = mf.GetDefinition(cachevar);
|
||||
if (def) {
|
||||
result = *def;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string path;
|
||||
if (cmSystemTools::GetEnv(envvar, path)) {
|
||||
mf.AddCacheDefinition(cachevar, path, desc, cmStateEnums::FILEPATH);
|
||||
result = std::move(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cm::optional<std::string> GetSysrootDir(cmMakefile& mf)
|
||||
{
|
||||
return GetPath(mf, "CMAKE_PKG_CONFIG_SYSROOT_DIR", "PKG_CONFIG_SYSROOT_DIR",
|
||||
"System root used for re-rooting package includes and "
|
||||
"library directories");
|
||||
}
|
||||
|
||||
cm::optional<std::string> GetTopBuildDir(cmMakefile& mf)
|
||||
{
|
||||
return GetPath(mf, "CMAKE_PKG_CONFIG_TOP_BUILD_DIR",
|
||||
"PKG_CONFIG_TOP_BUILD_DIR",
|
||||
"Package file top_build_dir variable default value");
|
||||
}
|
||||
|
||||
bool GetBool(cmMakefile& mf, const char* cachevar, const char* envvar,
|
||||
const char* desc)
|
||||
{
|
||||
auto def = mf.GetDefinition(cachevar);
|
||||
if (def) {
|
||||
return def.IsOn();
|
||||
}
|
||||
|
||||
if (cmSystemTools::HasEnv(envvar)) {
|
||||
mf.AddCacheDefinition(cachevar, "ON", desc, cmStateEnums::BOOL);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetDisableUninstalled(cmMakefile& mf)
|
||||
{
|
||||
return GetBool(mf, "CMAKE_PKG_CONFIG_DISABLE_UNINSTALLED",
|
||||
"PKG_CONFIG_DISABLE_UNINSTALLED",
|
||||
"Disable search for `-uninstalled` (build tree) packages");
|
||||
}
|
||||
|
||||
bool GetAllowSysLibs(cmMakefile& mf)
|
||||
{
|
||||
return GetBool(mf, "CMAKE_PKG_CONFIG_ALLOW_SYS_LIBS",
|
||||
"PKG_CONFIG_ALLOW_SYSTEM_LIBS",
|
||||
"Allow system library directories during flag mangling");
|
||||
}
|
||||
|
||||
bool GetAllowSysInclude(cmMakefile& mf)
|
||||
{
|
||||
return GetBool(mf, "CMAKE_PKG_CONFIG_ALLOW_SYS_INCLUDES",
|
||||
"PKG_CONFIG_ALLOW_SYSTEM_CFLAGS",
|
||||
"Allow system include paths during flag manglging");
|
||||
}
|
||||
|
||||
struct CommonArguments : ArgumentParser::ParseResult
|
||||
{
|
||||
bool Required = false;
|
||||
bool Exact = false;
|
||||
bool Quiet = false;
|
||||
|
||||
enum StrictnessType
|
||||
{
|
||||
STRICTNESS_STRICT,
|
||||
STRICTNESS_PERMISSIVE,
|
||||
STRICTNESS_BEST_EFFORT,
|
||||
};
|
||||
|
||||
StrictnessType Strictness = STRICTNESS_PERMISSIVE;
|
||||
std::string StrictnessError;
|
||||
|
||||
ArgumentParser::Continue SetStrictness(cm::string_view strictness)
|
||||
{
|
||||
if (strictness == "STRICT"_s) {
|
||||
Strictness = STRICTNESS_STRICT;
|
||||
} else if (strictness == "PERMISSIVE"_s) {
|
||||
Strictness = STRICTNESS_PERMISSIVE;
|
||||
} else if (strictness == "BEST_EFFORT"_s) {
|
||||
Strictness = STRICTNESS_BEST_EFFORT;
|
||||
} else {
|
||||
StrictnessError =
|
||||
cmStrCat("Invalid 'STRICTNESS' '", strictness,
|
||||
"'; must be one of 'STRICT', 'PERMISSIVE', or 'BEST_EFFORT'");
|
||||
}
|
||||
return ArgumentParser::Continue::Yes;
|
||||
}
|
||||
|
||||
enum EnvModeType
|
||||
{
|
||||
ENVMODE_FDO,
|
||||
ENVMODE_PKGCONF,
|
||||
ENVMODE_IGNORE,
|
||||
};
|
||||
|
||||
EnvModeType EnvMode = ENVMODE_PKGCONF;
|
||||
std::string EnvModeError;
|
||||
|
||||
ArgumentParser::Continue SetEnvMode(cm::string_view envMode)
|
||||
{
|
||||
if (envMode == "FDO"_s) {
|
||||
EnvMode = ENVMODE_FDO;
|
||||
} else if (envMode == "PKGCONF"_s) {
|
||||
EnvMode = ENVMODE_PKGCONF;
|
||||
} else if (envMode == "IGNORE"_s) {
|
||||
EnvMode = ENVMODE_IGNORE;
|
||||
} else {
|
||||
EnvModeError =
|
||||
cmStrCat("Invalid 'ENV_MODE' '", envMode,
|
||||
"'; must be one of 'FDO', 'PKGCONF', or 'IGNORE'");
|
||||
}
|
||||
return ArgumentParser::Continue::Yes;
|
||||
}
|
||||
|
||||
cm::optional<std::string> Package;
|
||||
cm::optional<std::string> Version;
|
||||
cm::optional<std::string> SysrootDir;
|
||||
cm::optional<std::string> TopBuildDir;
|
||||
|
||||
cm::optional<bool> DisableUninstalled;
|
||||
|
||||
cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> PcPath;
|
||||
cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> PcLibdir;
|
||||
|
||||
bool CheckArgs(cmExecutionStatus& status) const
|
||||
{
|
||||
|
||||
if (!Package) {
|
||||
status.SetError("A package name or absolute path must be specified");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!StrictnessError.empty()) {
|
||||
status.SetError(StrictnessError);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!EnvModeError.empty()) {
|
||||
status.SetError(EnvModeError);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#define BIND_COMMON(argtype) \
|
||||
(cmArgumentParser<argtype>{}) \
|
||||
.Bind(1, &argtype::Package) \
|
||||
.Bind(2, &argtype::Version) \
|
||||
.Bind("REQUIRED"_s, &argtype::Required) \
|
||||
.Bind("EXACT"_s, &argtype::Exact) \
|
||||
.Bind("QUIET"_s, &argtype::Quiet) \
|
||||
.Bind("STRICTNESS"_s, &argtype::SetStrictness) \
|
||||
.Bind("ENV_MODE"_s, &argtype::SetEnvMode) \
|
||||
.Bind("PC_SYSROOT_DIR"_s, &argtype::SysrootDir) \
|
||||
.Bind("TOP_BUILD_DIR"_s, &argtype::TopBuildDir) \
|
||||
.Bind("DISABLE_UNINSTALLED"_s, &argtype::DisableUninstalled) \
|
||||
.Bind("PC_LIBDIR"_s, &argtype::PcLibdir) \
|
||||
.Bind("PC_PATH"_s, &argtype::PcPath)
|
||||
|
||||
void CollectEnv(cmMakefile& mf, cmPkgConfigEnv& env,
|
||||
CommonArguments::EnvModeType mode)
|
||||
{
|
||||
if (mode == CommonArguments::EnvModeType::ENVMODE_IGNORE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!env.Path) {
|
||||
env.Path = GetPcPath(mf);
|
||||
}
|
||||
|
||||
if (!env.LibDirs) {
|
||||
env.LibDirs = GetPcLibDirs(mf);
|
||||
}
|
||||
|
||||
if (!env.DisableUninstalled) {
|
||||
env.DisableUninstalled = GetDisableUninstalled(mf);
|
||||
}
|
||||
|
||||
if (!env.SysrootDir) {
|
||||
env.SysrootDir = GetSysrootDir(mf);
|
||||
}
|
||||
|
||||
if (!env.TopBuildDir) {
|
||||
env.TopBuildDir = GetTopBuildDir(mf);
|
||||
}
|
||||
|
||||
env.AllowSysCflags = GetAllowSysInclude(mf);
|
||||
env.SysCflags = GetSysCflags(mf);
|
||||
|
||||
env.AllowSysLibs = GetAllowSysLibs(mf);
|
||||
env.SysLibs = GetSysLibDirs(mf);
|
||||
|
||||
if (mode == CommonArguments::EnvModeType::ENVMODE_FDO) {
|
||||
return;
|
||||
}
|
||||
|
||||
*env.SysCflags += GetPkgConfSysCflags(mf);
|
||||
*env.SysLibs += GetPkgConfSysLibs(mf);
|
||||
}
|
||||
|
||||
cm::optional<cmPkgConfigResult> HandleCommon(CommonArguments& args,
|
||||
cmExecutionStatus& status)
|
||||
{
|
||||
|
||||
auto& mf = status.GetMakefile();
|
||||
|
||||
if (!args.CheckArgs(status)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto warn_or_error = [&](const std::string& 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);
|
||||
|
||||
if (path.extension() == ".pc") {
|
||||
if (!cmSystemTools::FileExists(path.string())) {
|
||||
warn_or_error(cmStrCat("Could not find '", *args.Package, "'"));
|
||||
return {};
|
||||
}
|
||||
} 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) {
|
||||
auto uninstalled = path;
|
||||
uninstalled.concat("-uninstalled.pc");
|
||||
uninstalled =
|
||||
cmSystemTools::FindFile(uninstalled.string(), search, true);
|
||||
if (uninstalled.empty()) {
|
||||
path =
|
||||
cmSystemTools::FindFile(path.concat(".pc").string(), search, true);
|
||||
if (path.empty()) {
|
||||
warn_or_error(cmStrCat("Could not find '", *args.Package, "'"));
|
||||
return {};
|
||||
}
|
||||
} else {
|
||||
path = uninstalled;
|
||||
}
|
||||
} else {
|
||||
path =
|
||||
cmSystemTools::FindFile(path.concat(".pc").string(), search, true);
|
||||
if (path.empty()) {
|
||||
warn_or_error(cmStrCat("Could not find '", *args.Package, "'"));
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto len = cmSystemTools::FileLength(path.string());
|
||||
|
||||
// Windows requires this weird string -> c_str dance
|
||||
cmsys::ifstream ifs(path.string().c_str(), std::ios::binary);
|
||||
|
||||
if (!ifs) {
|
||||
warn_or_error(cmStrCat("Could not open file '", path.string(), "'"));
|
||||
return {};
|
||||
}
|
||||
|
||||
std::unique_ptr<char[]> buf(new char[len]);
|
||||
ifs.read(buf.get(), len);
|
||||
|
||||
// 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 {};
|
||||
}
|
||||
|
||||
using StrictnessType = CommonArguments::StrictnessType;
|
||||
|
||||
cmPkgConfigParser parser;
|
||||
auto err = parser.Finish(buf.get(), len);
|
||||
|
||||
if (args.Strictness != StrictnessType::STRICTNESS_BEST_EFFORT &&
|
||||
err != PCE_OK) {
|
||||
warn_or_error(cmStrCat("Parsing failed for file '", path.string(), "'"));
|
||||
return {};
|
||||
}
|
||||
|
||||
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));
|
||||
} else {
|
||||
result =
|
||||
cmPkgConfigResolver::ResolveBestEffort(parser.Data(), std::move(env));
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
warn_or_error(
|
||||
cmStrCat("Resolution failed for file '", path.string(), "'"));
|
||||
} else if (args.Exact) {
|
||||
std::string ver;
|
||||
|
||||
if (args.Version) {
|
||||
ver = cmPkgConfigResolver::ParseVersion(*args.Version).Version;
|
||||
}
|
||||
|
||||
if (ver != result->Version()) {
|
||||
warn_or_error(
|
||||
cmStrCat("Package '", *args.Package, "' version '", result->Version(),
|
||||
"' does not meet exact version requirement '", ver, "'"));
|
||||
return {};
|
||||
}
|
||||
|
||||
} else if (args.Version) {
|
||||
auto rv = cmPkgConfigResolver::ParseVersion(*args.Version);
|
||||
if (!cmPkgConfigResolver::CheckVersion(rv, result->Version())) {
|
||||
warn_or_error(
|
||||
cmStrCat("Package '", *args.Package, "' version '", result->Version(),
|
||||
"' does not meet version requirement '", *args.Version, "'"));
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct ExtractArguments : CommonArguments
|
||||
{
|
||||
cm::optional<bool> AllowSystemIncludes;
|
||||
cm::optional<bool> AllowSystemLibs;
|
||||
|
||||
cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>>
|
||||
SystemIncludeDirs;
|
||||
cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>>
|
||||
SystemLibraryDirs;
|
||||
};
|
||||
|
||||
const auto ExtractParser =
|
||||
BIND_COMMON(ExtractArguments)
|
||||
.Bind("ALLOW_SYSTEM_INCLUDES"_s, &ExtractArguments::AllowSystemIncludes)
|
||||
.Bind("ALLOW_SYSTEM_LIBS"_s, &ExtractArguments::AllowSystemLibs)
|
||||
.Bind("SYSTEM_INCLUDE_DIRS"_s, &ExtractArguments::SystemIncludeDirs)
|
||||
.Bind("SYSTEM_LIBRARY_DIRS"_s, &ExtractArguments::SystemLibraryDirs);
|
||||
|
||||
bool HandleExtractCommand(std::vector<std::string> const& args,
|
||||
cmExecutionStatus& status)
|
||||
{
|
||||
|
||||
std::vector<std::string> unparsed;
|
||||
auto parsedArgs = ExtractParser.Parse(args, &unparsed);
|
||||
auto maybeResolved = HandleCommon(parsedArgs, status);
|
||||
|
||||
if (!maybeResolved) {
|
||||
return !parsedArgs.Required;
|
||||
}
|
||||
|
||||
auto& resolved = *maybeResolved;
|
||||
auto version = resolved.Version();
|
||||
|
||||
if (parsedArgs.AllowSystemIncludes) {
|
||||
resolved.env.AllowSysCflags = *parsedArgs.AllowSystemIncludes;
|
||||
}
|
||||
|
||||
if (parsedArgs.AllowSystemLibs) {
|
||||
resolved.env.AllowSysLibs = *parsedArgs.AllowSystemLibs;
|
||||
}
|
||||
|
||||
if (parsedArgs.SystemIncludeDirs) {
|
||||
resolved.env.SysCflags = *parsedArgs.SystemIncludeDirs;
|
||||
}
|
||||
|
||||
if (parsedArgs.SystemLibraryDirs) {
|
||||
resolved.env.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);
|
||||
|
||||
auto make_list = [&](const char* def,
|
||||
const std::vector<cmPkgConfigDependency>& deps) {
|
||||
std::vector<cm::string_view> vec;
|
||||
vec.reserve(deps.size());
|
||||
|
||||
for (const auto& dep : deps) {
|
||||
vec.emplace_back(dep.Name);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
auto cflags = resolved.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);
|
||||
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();
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_LIBS", libs.Flagline);
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_LIBDIRS",
|
||||
cmList::to_string(libs.LibDirs));
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_LIBNAMES",
|
||||
cmList::to_string(libs.LibNames));
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_LINK_OPTIONS",
|
||||
cmList::to_string(libs.LinkOptions));
|
||||
|
||||
libs = resolved.Libs(true);
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_LIBS_PRIVATE", libs.Flagline);
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_LIBDIRS_PRIVATE",
|
||||
cmList::to_string(libs.LibDirs));
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_LIBNAMES_PRIVATE",
|
||||
cmList::to_string(libs.LibNames));
|
||||
mf.AddDefinition("CMAKE_PKG_CONFIG_LINK_OPTIONS_PRIVATE",
|
||||
cmList::to_string(libs.LinkOptions));
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool cmCMakePkgConfigCommand(std::vector<std::string> const& args,
|
||||
cmExecutionStatus& status)
|
||||
{
|
||||
if (args.size() < 2) {
|
||||
status.SetError("must be called with at least two arguments.");
|
||||
return false;
|
||||
}
|
||||
|
||||
static cmSubcommandTable const subcommand{
|
||||
{ "EXTRACT"_s, HandleExtractCommand },
|
||||
};
|
||||
|
||||
return subcommand(args[0], args, status);
|
||||
}
|
||||
13
Source/cmCMakePkgConfigCommand.h
Normal file
13
Source/cmCMakePkgConfigCommand.h
Normal file
@@ -0,0 +1,13 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#pragma once
|
||||
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class cmExecutionStatus;
|
||||
|
||||
bool cmCMakePkgConfigCommand(std::vector<std::string> const& args,
|
||||
cmExecutionStatus& status);
|
||||
@@ -94,6 +94,7 @@
|
||||
# include "cmAuxSourceDirectoryCommand.h"
|
||||
# include "cmBuildNameCommand.h"
|
||||
# include "cmCMakeHostSystemInformationCommand.h"
|
||||
# include "cmCMakePkgConfigCommand.h"
|
||||
# include "cmExportCommand.h"
|
||||
# include "cmExportLibraryDependenciesCommand.h"
|
||||
# include "cmFLTKWrapUICommand.h"
|
||||
@@ -208,6 +209,7 @@ void GetScriptingCommands(cmState* state)
|
||||
#if !defined(CMAKE_BOOTSTRAP)
|
||||
state->AddBuiltinCommand("cmake_host_system_information",
|
||||
cmCMakeHostSystemInformationCommand);
|
||||
state->AddBuiltinCommand("cmake_pkg_config", cmCMakePkgConfigCommand);
|
||||
state->AddBuiltinCommand("load_cache", cmLoadCacheCommand);
|
||||
state->AddBuiltinCommand("remove", cmRemoveCommand);
|
||||
state->AddBuiltinCommand("variable_watch", cmVariableWatchCommand);
|
||||
|
||||
151
Source/cmPkgConfigParser.cxx
Normal file
151
Source/cmPkgConfigParser.cxx
Normal file
@@ -0,0 +1,151 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
|
||||
#include "cmPkgConfigParser.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/string_view>
|
||||
|
||||
#include <cmllpkgc/llpkgc.h>
|
||||
|
||||
cmPkgConfigValueElement::cmPkgConfigValueElement(bool isVariable,
|
||||
cm::string_view data)
|
||||
: IsVariable{ isVariable }
|
||||
, Data{ data }
|
||||
{
|
||||
}
|
||||
|
||||
cmPkgConfigEntry::cmPkgConfigEntry(bool isVariable, cm::string_view key)
|
||||
: IsVariable{ isVariable }
|
||||
, Key{ key }
|
||||
{
|
||||
}
|
||||
|
||||
cmPkgConfigParser::cmPkgConfigParser()
|
||||
{
|
||||
llpkgc_init(static_cast<llpkgc_t*>(this), &Settings_);
|
||||
}
|
||||
|
||||
llpkgc_errno_t cmPkgConfigParser::Parse(char* buf, std::size_t len)
|
||||
{
|
||||
return llpkgc_execute(static_cast<llpkgc_t*>(this), buf, len);
|
||||
}
|
||||
|
||||
llpkgc_errno_t cmPkgConfigParser::Finish()
|
||||
{
|
||||
return llpkgc_finish(static_cast<llpkgc_t*>(this));
|
||||
}
|
||||
|
||||
llpkgc_errno_t cmPkgConfigParser::Finish(char* buf, std::size_t len)
|
||||
{
|
||||
Parse(buf, len);
|
||||
return llpkgc_finish(static_cast<llpkgc_t*>(this));
|
||||
}
|
||||
|
||||
int cmPkgConfigParser::OnSpanNext(const char*, std::size_t len)
|
||||
{
|
||||
Len_ += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmPkgConfigParser::OnSpanNextTr(llpkgc_t* parser, const char* at,
|
||||
std::size_t len)
|
||||
{
|
||||
return static_cast<cmPkgConfigParser*>(parser)->OnSpanNext(at, len);
|
||||
}
|
||||
|
||||
int cmPkgConfigParser::OnKey(const char* at, std::size_t len)
|
||||
{
|
||||
Ptr_ = at;
|
||||
Len_ = len;
|
||||
Settings_.on_key = OnSpanNextTr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmPkgConfigParser::OnKeyTr(llpkgc_t* parser, const char* at,
|
||||
std::size_t len)
|
||||
{
|
||||
return static_cast<cmPkgConfigParser*>(parser)->OnKey(at, len);
|
||||
}
|
||||
|
||||
int cmPkgConfigParser::OnKeywordComplete()
|
||||
{
|
||||
Data_.emplace_back(false, cm::string_view{ Ptr_, Len_ });
|
||||
Settings_.on_key = OnKeyTr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmPkgConfigParser::OnKeywordCompleteTr(llpkgc_t* parser)
|
||||
{
|
||||
return static_cast<cmPkgConfigParser*>(parser)->OnKeywordComplete();
|
||||
}
|
||||
|
||||
int cmPkgConfigParser::OnVariableComplete()
|
||||
{
|
||||
Data_.emplace_back(true, cm::string_view{ Ptr_, Len_ });
|
||||
Settings_.on_key = OnKeyTr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmPkgConfigParser::OnVariableCompleteTr(llpkgc_t* parser)
|
||||
{
|
||||
return static_cast<cmPkgConfigParser*>(parser)->OnVariableComplete();
|
||||
}
|
||||
|
||||
int cmPkgConfigParser::OnValueLiteral(const char* at, std::size_t len)
|
||||
{
|
||||
Ptr_ = at;
|
||||
Len_ = len;
|
||||
Settings_.on_value_literal = OnSpanNextTr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmPkgConfigParser::OnValueLiteralTr(llpkgc_t* parser, const char* at,
|
||||
std::size_t len)
|
||||
{
|
||||
return static_cast<cmPkgConfigParser*>(parser)->OnValueLiteral(at, len);
|
||||
}
|
||||
|
||||
int cmPkgConfigParser::OnValueLiteralComplete()
|
||||
{
|
||||
Settings_.on_value_literal = OnValueLiteralTr;
|
||||
|
||||
if (Len_) {
|
||||
Data_.back().Val.emplace_back(false, cm::string_view{ Ptr_, Len_ });
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmPkgConfigParser::OnValueLiteralCompleteTr(llpkgc_t* parser)
|
||||
{
|
||||
return static_cast<cmPkgConfigParser*>(parser)->OnValueLiteralComplete();
|
||||
}
|
||||
|
||||
int cmPkgConfigParser::OnValueVariable(const char* at, std::size_t len)
|
||||
{
|
||||
Ptr_ = at;
|
||||
Len_ = len;
|
||||
Settings_.on_value_variable = OnSpanNextTr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmPkgConfigParser::OnValueVariableTr(llpkgc_t* parser, const char* at,
|
||||
std::size_t len)
|
||||
{
|
||||
return static_cast<cmPkgConfigParser*>(parser)->OnValueVariable(at, len);
|
||||
}
|
||||
|
||||
int cmPkgConfigParser::OnValueVariableComplete()
|
||||
{
|
||||
Settings_.on_value_variable = OnValueVariableTr;
|
||||
Data_.back().Val.emplace_back(true, cm::string_view{ Ptr_, Len_ });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmPkgConfigParser::OnValueVariableCompleteTr(llpkgc_t* parser)
|
||||
{
|
||||
return static_cast<cmPkgConfigParser*>(parser)->OnValueVariableComplete();
|
||||
}
|
||||
93
Source/cmPkgConfigParser.h
Normal file
93
Source/cmPkgConfigParser.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/string_view>
|
||||
|
||||
#include <cmllpkgc/llpkgc.h>
|
||||
|
||||
struct cmPkgConfigValueElement
|
||||
{
|
||||
|
||||
cmPkgConfigValueElement() = default;
|
||||
|
||||
cmPkgConfigValueElement(bool isVariable, cm::string_view data);
|
||||
|
||||
bool IsVariable;
|
||||
cm::string_view Data;
|
||||
};
|
||||
|
||||
struct cmPkgConfigEntry
|
||||
{
|
||||
|
||||
cmPkgConfigEntry() = default;
|
||||
|
||||
cmPkgConfigEntry(bool isVariable, cm::string_view key);
|
||||
|
||||
bool IsVariable;
|
||||
cm::string_view Key;
|
||||
std::vector<cmPkgConfigValueElement> Val;
|
||||
};
|
||||
|
||||
class cmPkgConfigParser : llpkgc_t
|
||||
{
|
||||
public:
|
||||
cmPkgConfigParser();
|
||||
|
||||
llpkgc_errno_t Parse(char* buf, std::size_t len);
|
||||
|
||||
llpkgc_errno_t Finish();
|
||||
llpkgc_errno_t Finish(char* buf, std::size_t len);
|
||||
|
||||
std::vector<cmPkgConfigEntry>& Data() { return Data_; }
|
||||
|
||||
private:
|
||||
int OnSpanNext(const char*, std::size_t len);
|
||||
static int OnSpanNextTr(llpkgc_t* parser, const char* at, std::size_t len);
|
||||
|
||||
int OnKey(const char* at, std::size_t len);
|
||||
static int OnKeyTr(llpkgc_t* parser, const char* at, std::size_t len);
|
||||
|
||||
int OnKeywordComplete();
|
||||
static int OnKeywordCompleteTr(llpkgc_t* parser);
|
||||
|
||||
int OnVariableComplete();
|
||||
static int OnVariableCompleteTr(llpkgc_t* parser);
|
||||
|
||||
int OnValueLiteral(const char* at, std::size_t len);
|
||||
static int OnValueLiteralTr(llpkgc_t* parser, const char* at,
|
||||
std::size_t len);
|
||||
|
||||
int OnValueLiteralComplete();
|
||||
static int OnValueLiteralCompleteTr(llpkgc_t* parser);
|
||||
|
||||
int OnValueVariable(const char* at, std::size_t len);
|
||||
static int OnValueVariableTr(llpkgc_t* parser, const char* at,
|
||||
std::size_t len);
|
||||
|
||||
int OnValueVariableComplete();
|
||||
static int OnValueVariableCompleteTr(llpkgc_t* parser);
|
||||
|
||||
llpkgc_settings_t Settings_{
|
||||
OnKeyTr,
|
||||
OnValueLiteralTr,
|
||||
OnValueVariableTr,
|
||||
nullptr, // on_line_begin
|
||||
OnKeywordCompleteTr,
|
||||
OnVariableCompleteTr,
|
||||
OnValueLiteralCompleteTr,
|
||||
OnValueVariableCompleteTr,
|
||||
nullptr, // on_value_complete
|
||||
nullptr, // on_pkgc_complete
|
||||
};
|
||||
|
||||
const char* Ptr_;
|
||||
std::size_t Len_;
|
||||
std::vector<cmPkgConfigEntry> Data_;
|
||||
};
|
||||
870
Source/cmPkgConfigResolver.cxx
Normal file
870
Source/cmPkgConfigResolver.cxx
Normal file
@@ -0,0 +1,870 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
|
||||
#include "cmPkgConfigResolver.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/optional>
|
||||
#include <cm/string_view>
|
||||
|
||||
#include "cmPkgConfigParser.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void TrimBack(std::string& str)
|
||||
{
|
||||
if (!str.empty()) {
|
||||
auto it = str.end() - 1;
|
||||
for (; std::isspace(*it); --it) {
|
||||
if (it == str.begin()) {
|
||||
str.clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
str.erase(++it, str.end());
|
||||
}
|
||||
}
|
||||
|
||||
std::string AppendAndTrim(std::string& str, cm::string_view sv)
|
||||
{
|
||||
auto size = str.length();
|
||||
str += sv;
|
||||
if (str.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto begin = str.begin() + size;
|
||||
auto cur = str.end() - 1;
|
||||
|
||||
while (cur != begin && std::isspace(*cur)) {
|
||||
--cur;
|
||||
}
|
||||
|
||||
if (std::isspace(*cur)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return { &*begin, static_cast<std::size_t>(cur - begin) + 1 };
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string cmPkgConfigResult::StrOrDefault(const std::string& key,
|
||||
cm::string_view def)
|
||||
{
|
||||
auto it = Keywords.find(key);
|
||||
return it == Keywords.end() ? std::string{ def } : it->second;
|
||||
};
|
||||
|
||||
std::string cmPkgConfigResult::Name()
|
||||
{
|
||||
return StrOrDefault("Name");
|
||||
}
|
||||
|
||||
std::string cmPkgConfigResult::Description()
|
||||
{
|
||||
return StrOrDefault("Description");
|
||||
}
|
||||
|
||||
std::string cmPkgConfigResult::Version()
|
||||
{
|
||||
return StrOrDefault("Version");
|
||||
}
|
||||
|
||||
std::vector<cmPkgConfigDependency> cmPkgConfigResult::Conflicts()
|
||||
{
|
||||
auto it = Keywords.find("Conflicts");
|
||||
if (it == Keywords.end()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return cmPkgConfigResolver::ParseDependencies(it->second);
|
||||
}
|
||||
|
||||
std::vector<cmPkgConfigDependency> cmPkgConfigResult::Provides()
|
||||
{
|
||||
auto it = Keywords.find("Provides");
|
||||
if (it == Keywords.end()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return cmPkgConfigResolver::ParseDependencies(it->second);
|
||||
}
|
||||
|
||||
std::vector<cmPkgConfigDependency> cmPkgConfigResult::Requires(bool priv)
|
||||
{
|
||||
auto it = Keywords.find(priv ? "Requires.private" : "Requires");
|
||||
if (it == Keywords.end()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return cmPkgConfigResolver::ParseDependencies(it->second);
|
||||
}
|
||||
|
||||
cmPkgConfigCflagsResult cmPkgConfigResult::Cflags(bool priv)
|
||||
{
|
||||
std::string cflags;
|
||||
auto it = Keywords.find(priv ? "Cflags.private" : "Cflags");
|
||||
if (it != Keywords.end()) {
|
||||
cflags += it->second;
|
||||
}
|
||||
|
||||
it = Keywords.find(priv ? "CFlags.private" : "CFlags");
|
||||
if (it != Keywords.end()) {
|
||||
if (!cflags.empty()) {
|
||||
cflags += " ";
|
||||
}
|
||||
cflags += it->second;
|
||||
}
|
||||
|
||||
auto tokens = cmPkgConfigResolver::TokenizeFlags(cflags);
|
||||
|
||||
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);
|
||||
}
|
||||
return cmPkgConfigResolver::MangleCflags(tokens, *env.SysCflags);
|
||||
}
|
||||
|
||||
if (env.SysrootDir) {
|
||||
return cmPkgConfigResolver::MangleCflags(
|
||||
tokens, *env.SysrootDir, std::vector<std::string>{ "/usr/include" });
|
||||
}
|
||||
|
||||
return cmPkgConfigResolver::MangleCflags(
|
||||
tokens, std::vector<std::string>{ "/usr/include" });
|
||||
}
|
||||
|
||||
cmPkgConfigLibsResult cmPkgConfigResult::Libs(bool priv)
|
||||
{
|
||||
auto it = Keywords.find(priv ? "Libs.private" : "Libs");
|
||||
if (it == Keywords.end()) {
|
||||
return cmPkgConfigLibsResult();
|
||||
}
|
||||
|
||||
auto tokens = cmPkgConfigResolver::TokenizeFlags(it->second);
|
||||
|
||||
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);
|
||||
}
|
||||
return cmPkgConfigResolver::MangleLibs(tokens, *env.SysLibs);
|
||||
}
|
||||
|
||||
if (env.SysrootDir) {
|
||||
return cmPkgConfigResolver::MangleLibs(
|
||||
tokens, *env.SysrootDir, std::vector<std::string>{ "/usr/lib" });
|
||||
}
|
||||
|
||||
return cmPkgConfigResolver::MangleLibs(
|
||||
tokens, std::vector<std::string>{ "/usr/lib" });
|
||||
}
|
||||
|
||||
void cmPkgConfigResolver::ReplaceSep(std::string& list)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
std::replace(list.begin(), list.end(), ':', ';');
|
||||
#else
|
||||
static_cast<void>(list); // Unused parameter
|
||||
#endif
|
||||
}
|
||||
|
||||
cm::optional<cmPkgConfigResult> cmPkgConfigResolver::ResolveStrict(
|
||||
const std::vector<cmPkgConfigEntry>& entries, cmPkgConfigEnv env)
|
||||
{
|
||||
cm::optional<cmPkgConfigResult> result;
|
||||
cmPkgConfigResult config;
|
||||
auto& keys = config.Keywords;
|
||||
|
||||
if (env.SysrootDir) {
|
||||
config.Variables["pc_sysrootdir"] = *env.SysrootDir;
|
||||
} else {
|
||||
config.Variables["pc_sysrootdir"] = "/";
|
||||
}
|
||||
|
||||
if (env.TopBuildDir) {
|
||||
config.Variables["pc_top_builddir"] = *env.TopBuildDir;
|
||||
}
|
||||
|
||||
config.env = std::move(env);
|
||||
|
||||
for (const auto& entry : entries) {
|
||||
std::string key(entry.Key);
|
||||
if (entry.IsVariable) {
|
||||
if (config.Variables.find(key) != config.Variables.end()) {
|
||||
return result;
|
||||
}
|
||||
auto var = HandleVariableStrict(entry, config.Variables);
|
||||
if (!var) {
|
||||
return result;
|
||||
}
|
||||
config.Variables[key] = *var;
|
||||
} else {
|
||||
if (key == "Cflags" && keys.find("CFlags") != keys.end()) {
|
||||
return result;
|
||||
}
|
||||
if (key == "CFlags" && keys.find("Cflags") != keys.end()) {
|
||||
return result;
|
||||
}
|
||||
if (key == "Cflags.private" &&
|
||||
keys.find("CFlags.private") != keys.end()) {
|
||||
return result;
|
||||
}
|
||||
if (key == "CFlags.private" &&
|
||||
keys.find("Cflags.private") != keys.end()) {
|
||||
return result;
|
||||
}
|
||||
if (keys.find(key) != keys.end()) {
|
||||
return result;
|
||||
}
|
||||
keys[key] = HandleKeyword(entry, config.Variables);
|
||||
}
|
||||
}
|
||||
|
||||
if (keys.find("Name") == keys.end() ||
|
||||
keys.find("Description") == keys.end() ||
|
||||
keys.find("Version") == keys.end()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = std::move(config);
|
||||
return result;
|
||||
}
|
||||
|
||||
cm::optional<cmPkgConfigResult> cmPkgConfigResolver::ResolvePermissive(
|
||||
const std::vector<cmPkgConfigEntry>& entries, cmPkgConfigEnv env)
|
||||
{
|
||||
cm::optional<cmPkgConfigResult> result;
|
||||
|
||||
cmPkgConfigResult config = ResolveBestEffort(entries, std::move(env));
|
||||
const auto& keys = config.Keywords;
|
||||
|
||||
if (keys.find("Name") == keys.end() ||
|
||||
keys.find("Description") == keys.end() ||
|
||||
keys.find("Version") == keys.end()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = std::move(config);
|
||||
return result;
|
||||
}
|
||||
|
||||
cmPkgConfigResult cmPkgConfigResolver::ResolveBestEffort(
|
||||
const std::vector<cmPkgConfigEntry>& entries, cmPkgConfigEnv env)
|
||||
{
|
||||
cmPkgConfigResult result;
|
||||
|
||||
if (env.SysrootDir) {
|
||||
result.Variables["pc_sysrootdir"] = *env.SysrootDir;
|
||||
} else {
|
||||
result.Variables["pc_sysrootdir"] = "/";
|
||||
}
|
||||
|
||||
if (env.TopBuildDir) {
|
||||
result.Variables["pc_top_builddir"] = *env.TopBuildDir;
|
||||
}
|
||||
|
||||
result.env = std::move(env);
|
||||
|
||||
for (const auto& entry : entries) {
|
||||
std::string key(entry.Key);
|
||||
if (entry.IsVariable) {
|
||||
result.Variables[key] =
|
||||
HandleVariablePermissive(entry, result.Variables);
|
||||
} else {
|
||||
result.Keywords[key] += HandleKeyword(entry, result.Variables);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string cmPkgConfigResolver::HandleVariablePermissive(
|
||||
const cmPkgConfigEntry& entry,
|
||||
const std::unordered_map<std::string, std::string>& variables)
|
||||
{
|
||||
std::string result;
|
||||
for (const auto& segment : entry.Val) {
|
||||
if (!segment.IsVariable) {
|
||||
result += segment.Data;
|
||||
} else if (entry.Key != segment.Data) {
|
||||
auto it = variables.find(std::string{ segment.Data });
|
||||
if (it != variables.end()) {
|
||||
result += it->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TrimBack(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
cm::optional<std::string> cmPkgConfigResolver::HandleVariableStrict(
|
||||
const cmPkgConfigEntry& entry,
|
||||
const std::unordered_map<std::string, std::string>& variables)
|
||||
{
|
||||
cm::optional<std::string> result;
|
||||
|
||||
std::string value;
|
||||
for (const auto& segment : entry.Val) {
|
||||
if (!segment.IsVariable) {
|
||||
value += segment.Data;
|
||||
} else if (entry.Key == segment.Data) {
|
||||
return result;
|
||||
} else {
|
||||
auto it = variables.find(std::string{ segment.Data });
|
||||
if (it != variables.end()) {
|
||||
value += it->second;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TrimBack(value);
|
||||
result = std::move(value);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string cmPkgConfigResolver::HandleKeyword(
|
||||
const cmPkgConfigEntry& entry,
|
||||
const std::unordered_map<std::string, std::string>& variables)
|
||||
{
|
||||
std::string result;
|
||||
for (const auto& segment : entry.Val) {
|
||||
if (!segment.IsVariable) {
|
||||
result += segment.Data;
|
||||
} else {
|
||||
auto it = variables.find(std::string{ segment.Data });
|
||||
if (it != variables.end()) {
|
||||
result += it->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TrimBack(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<cm::string_view> cmPkgConfigResolver::TokenizeFlags(
|
||||
const std::string& flagline)
|
||||
{
|
||||
std::vector<cm::string_view> result;
|
||||
|
||||
auto it = flagline.begin();
|
||||
while (it != flagline.end() && std::isspace(*it)) {
|
||||
++it;
|
||||
}
|
||||
|
||||
while (it != flagline.end()) {
|
||||
const char* start = &(*it);
|
||||
std::size_t len = 0;
|
||||
|
||||
for (; it != flagline.end() && !std::isspace(*it); ++it) {
|
||||
++len;
|
||||
}
|
||||
|
||||
for (; it != flagline.end() && std::isspace(*it); ++it) {
|
||||
++len;
|
||||
}
|
||||
|
||||
result.emplace_back(start, len);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cmPkgConfigCflagsResult cmPkgConfigResolver::MangleCflags(
|
||||
const std::vector<cm::string_view>& flags)
|
||||
{
|
||||
cmPkgConfigCflagsResult result;
|
||||
|
||||
for (auto flag : flags) {
|
||||
if (flag.rfind("-I", 0) == 0) {
|
||||
result.Includes.emplace_back(AppendAndTrim(result.Flagline, flag));
|
||||
} else {
|
||||
result.CompileOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cmPkgConfigCflagsResult cmPkgConfigResolver::MangleCflags(
|
||||
const std::vector<cm::string_view>& flags, const std::string& sysroot)
|
||||
{
|
||||
cmPkgConfigCflagsResult result;
|
||||
|
||||
for (auto flag : flags) {
|
||||
if (flag.rfind("-I", 0) == 0) {
|
||||
std::string reroot = Reroot(flag, "-I", sysroot);
|
||||
result.Includes.emplace_back(AppendAndTrim(result.Flagline, reroot));
|
||||
} else {
|
||||
result.CompileOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cmPkgConfigCflagsResult cmPkgConfigResolver::MangleCflags(
|
||||
const std::vector<cm::string_view>& flags,
|
||||
const std::vector<std::string>& syspaths)
|
||||
{
|
||||
cmPkgConfigCflagsResult result;
|
||||
|
||||
for (auto flag : flags) {
|
||||
if (flag.rfind("-I", 0) == 0) {
|
||||
cm::string_view noprefix{ flag.data() + 2, flag.size() - 2 };
|
||||
|
||||
if (std::all_of(syspaths.begin(), syspaths.end(),
|
||||
[&](const std::string& path) {
|
||||
return noprefix.rfind(path, 0) == noprefix.npos;
|
||||
})) {
|
||||
result.Includes.emplace_back(AppendAndTrim(result.Flagline, flag));
|
||||
}
|
||||
|
||||
} else {
|
||||
result.CompileOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cmPkgConfigCflagsResult cmPkgConfigResolver::MangleCflags(
|
||||
const std::vector<cm::string_view>& flags, const std::string& sysroot,
|
||||
const std::vector<std::string>& syspaths)
|
||||
{
|
||||
cmPkgConfigCflagsResult result;
|
||||
|
||||
for (auto flag : flags) {
|
||||
if (flag.rfind("-I", 0) == 0) {
|
||||
std::string reroot = Reroot(flag, "-I", sysroot);
|
||||
cm::string_view noprefix{ reroot.data() + 2, reroot.size() - 2 };
|
||||
|
||||
if (std::all_of(syspaths.begin(), syspaths.end(),
|
||||
[&](const std::string& path) {
|
||||
return noprefix.rfind(path, 0) == noprefix.npos;
|
||||
})) {
|
||||
result.Includes.emplace_back(AppendAndTrim(result.Flagline, reroot));
|
||||
}
|
||||
|
||||
} else {
|
||||
result.CompileOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cmPkgConfigLibsResult cmPkgConfigResolver::MangleLibs(
|
||||
const std::vector<cm::string_view>& flags)
|
||||
{
|
||||
cmPkgConfigLibsResult result;
|
||||
|
||||
for (auto flag : flags) {
|
||||
if (flag.rfind("-L", 0) == 0) {
|
||||
result.LibDirs.emplace_back(AppendAndTrim(result.Flagline, flag));
|
||||
} else if (flag.rfind("-l", 0) == 0) {
|
||||
result.LibNames.emplace_back(AppendAndTrim(result.Flagline, flag));
|
||||
} else {
|
||||
result.LinkOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cmPkgConfigLibsResult cmPkgConfigResolver::MangleLibs(
|
||||
const std::vector<cm::string_view>& flags, const std::string& sysroot)
|
||||
{
|
||||
cmPkgConfigLibsResult result;
|
||||
|
||||
for (auto flag : flags) {
|
||||
if (flag.rfind("-L", 0) == 0) {
|
||||
std::string reroot = Reroot(flag, "-L", sysroot);
|
||||
result.LibDirs.emplace_back(AppendAndTrim(result.Flagline, reroot));
|
||||
} else if (flag.rfind("-l", 0) == 0) {
|
||||
result.LibNames.emplace_back(AppendAndTrim(result.Flagline, flag));
|
||||
} else {
|
||||
result.LinkOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cmPkgConfigLibsResult cmPkgConfigResolver::MangleLibs(
|
||||
const std::vector<cm::string_view>& flags,
|
||||
const std::vector<std::string>& syspaths)
|
||||
{
|
||||
cmPkgConfigLibsResult result;
|
||||
|
||||
for (auto flag : flags) {
|
||||
if (flag.rfind("-L", 0) == 0) {
|
||||
cm::string_view noprefix{ flag.data() + 2, flag.size() - 2 };
|
||||
|
||||
if (std::all_of(syspaths.begin(), syspaths.end(),
|
||||
[&](const std::string& path) {
|
||||
return noprefix.rfind(path, 0) == noprefix.npos;
|
||||
})) {
|
||||
result.LibDirs.emplace_back(AppendAndTrim(result.Flagline, flag));
|
||||
}
|
||||
|
||||
} else if (flag.rfind("-l", 0) == 0) {
|
||||
result.LibNames.emplace_back(AppendAndTrim(result.Flagline, flag));
|
||||
} else {
|
||||
result.LinkOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cmPkgConfigLibsResult cmPkgConfigResolver::MangleLibs(
|
||||
const std::vector<cm::string_view>& flags, const std::string& sysroot,
|
||||
const std::vector<std::string>& syspaths)
|
||||
{
|
||||
cmPkgConfigLibsResult result;
|
||||
|
||||
for (auto flag : flags) {
|
||||
if (flag.rfind("-L", 0) == 0) {
|
||||
std::string reroot = Reroot(flag, "-L", sysroot);
|
||||
cm::string_view noprefix{ reroot.data() + 2, reroot.size() - 2 };
|
||||
|
||||
if (std::all_of(syspaths.begin(), syspaths.end(),
|
||||
[&](const std::string& path) {
|
||||
return noprefix.rfind(path, 0) == noprefix.npos;
|
||||
})) {
|
||||
result.LibDirs.emplace_back(AppendAndTrim(result.Flagline, reroot));
|
||||
}
|
||||
|
||||
} else if (flag.rfind("-l", 0) == 0) {
|
||||
result.LibNames.emplace_back(AppendAndTrim(result.Flagline, flag));
|
||||
} else {
|
||||
result.LinkOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string cmPkgConfigResolver::Reroot(cm::string_view flag,
|
||||
cm::string_view prefix,
|
||||
const std::string& sysroot)
|
||||
{
|
||||
std::string result = std::string{ prefix };
|
||||
result += sysroot;
|
||||
result += cm::string_view{ flag.data() + prefix.length(),
|
||||
flag.size() - prefix.length() };
|
||||
return result;
|
||||
}
|
||||
|
||||
cmPkgConfigVersionReq cmPkgConfigResolver::ParseVersion(
|
||||
std::string::const_iterator& cur, std::string::const_iterator end)
|
||||
{
|
||||
cmPkgConfigVersionReq result;
|
||||
if (*cur == '=') {
|
||||
result.Operation = result.EQ;
|
||||
++cur;
|
||||
} else if (*cur == '>') {
|
||||
++cur;
|
||||
|
||||
if (cur == end) {
|
||||
result.Operation = result.GT;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (*cur == '=') {
|
||||
result.Operation = result.GT_EQ;
|
||||
++cur;
|
||||
} else {
|
||||
result.Operation = result.GT;
|
||||
}
|
||||
|
||||
} else if (*cur == '<') {
|
||||
++cur;
|
||||
|
||||
if (cur == end) {
|
||||
result.Operation = result.LT;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (*cur == '=') {
|
||||
result.Operation = result.LT_EQ;
|
||||
++cur;
|
||||
} else {
|
||||
result.Operation = result.LT;
|
||||
}
|
||||
|
||||
} else if (*cur == '!') {
|
||||
++cur;
|
||||
|
||||
if (cur == end) {
|
||||
result.Operation = result.ANY;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (*cur == '=') {
|
||||
result.Operation = result.NEQ;
|
||||
++cur;
|
||||
} else {
|
||||
result.Operation = result.ANY;
|
||||
}
|
||||
}
|
||||
|
||||
for (;; ++cur) {
|
||||
if (cur == end) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!std::isspace(*cur)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (; cur != end && !std::isspace(*cur) && *cur != ','; ++cur) {
|
||||
result.Version += *cur;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<cmPkgConfigDependency> cmPkgConfigResolver::ParseDependencies(
|
||||
const std::string& deps)
|
||||
{
|
||||
|
||||
std::vector<cmPkgConfigDependency> result;
|
||||
|
||||
auto cur = deps.begin();
|
||||
auto end = deps.end();
|
||||
|
||||
while (cur != end) {
|
||||
while ((std::isspace(*cur) || *cur == ',')) {
|
||||
if (++cur == end) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
result.emplace_back();
|
||||
auto& dep = result.back();
|
||||
|
||||
while (!std::isspace(*cur) && *cur != ',') {
|
||||
dep.Name += *cur;
|
||||
if (++cur == end) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
auto in_operator = [&]() -> bool {
|
||||
for (;; ++cur) {
|
||||
if (cur == end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*cur == '>' || *cur == '=' || *cur == '<' || *cur == '!') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!std::isspace(*cur)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!in_operator()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dep.VerReq = ParseVersion(cur, end);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool cmPkgConfigResolver::CheckVersion(const cmPkgConfigVersionReq& desired,
|
||||
const std::string& provided)
|
||||
{
|
||||
|
||||
if (desired.Operation == cmPkgConfigVersionReq::ANY) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://blog.jasonantman.com/2014/07/how-yum-and-rpm-compare-versions/
|
||||
|
||||
auto check_with_op = [&](int comp) -> bool {
|
||||
switch (desired.Operation) {
|
||||
case cmPkgConfigVersionReq::EQ:
|
||||
return comp == 0;
|
||||
case cmPkgConfigVersionReq::NEQ:
|
||||
return comp != 0;
|
||||
case cmPkgConfigVersionReq::GT:
|
||||
return comp < 0;
|
||||
case cmPkgConfigVersionReq::GT_EQ:
|
||||
return comp <= 0;
|
||||
case cmPkgConfigVersionReq::LT:
|
||||
return comp > 0;
|
||||
case cmPkgConfigVersionReq::LT_EQ:
|
||||
return comp >= 0;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
if (desired.Version == provided) {
|
||||
return check_with_op(0);
|
||||
}
|
||||
|
||||
auto a_cur = desired.Version.begin();
|
||||
auto a_end = desired.Version.end();
|
||||
|
||||
auto b_cur = provided.begin();
|
||||
auto b_end = provided.end();
|
||||
|
||||
while (a_cur != a_end && b_cur != b_end) {
|
||||
while (a_cur != a_end && !std::isalnum(*a_cur) && *a_cur != '~') {
|
||||
++a_cur;
|
||||
}
|
||||
|
||||
while (b_cur != b_end && !std::isalnum(*b_cur) && *b_cur != '~') {
|
||||
++b_cur;
|
||||
}
|
||||
|
||||
if (a_cur == a_end || b_cur == b_end) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (*a_cur == '~' || *b_cur == '~') {
|
||||
if (*a_cur != '~') {
|
||||
return check_with_op(1);
|
||||
}
|
||||
|
||||
if (*b_cur != '~') {
|
||||
return check_with_op(-1);
|
||||
}
|
||||
|
||||
++a_cur;
|
||||
++b_cur;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto a_seg = a_cur;
|
||||
auto b_seg = b_cur;
|
||||
bool is_num;
|
||||
|
||||
if (std::isdigit(*a_cur)) {
|
||||
is_num = true;
|
||||
while (a_cur != a_end && std::isdigit(*a_cur)) {
|
||||
++a_cur;
|
||||
}
|
||||
|
||||
while (b_cur != b_end && std::isdigit(*b_cur)) {
|
||||
++b_cur;
|
||||
}
|
||||
|
||||
} else {
|
||||
is_num = false;
|
||||
while (a_cur != a_end && std::isalpha(*a_cur)) {
|
||||
++a_cur;
|
||||
}
|
||||
|
||||
while (b_cur != b_end && std::isalpha(*b_cur)) {
|
||||
++b_cur;
|
||||
}
|
||||
}
|
||||
|
||||
auto a_len = std::distance(a_seg, a_cur);
|
||||
auto b_len = std::distance(b_seg, b_cur);
|
||||
|
||||
if (!b_len) {
|
||||
return check_with_op(is_num ? 1 : -1);
|
||||
}
|
||||
|
||||
if (is_num) {
|
||||
while (a_seg != a_cur && *a_seg == '0') {
|
||||
++a_seg;
|
||||
}
|
||||
|
||||
while (b_seg != b_cur && *b_seg == '0') {
|
||||
++b_seg;
|
||||
}
|
||||
|
||||
a_len = std::distance(a_seg, a_cur);
|
||||
b_len = std::distance(b_seg, b_cur);
|
||||
|
||||
if (a_len != b_len) {
|
||||
return check_with_op(a_len > b_len ? 1 : -1);
|
||||
}
|
||||
|
||||
auto cmp = std::memcmp(&*a_seg, &*b_seg, a_len);
|
||||
if (cmp) {
|
||||
return check_with_op(cmp);
|
||||
}
|
||||
} else {
|
||||
auto cmp = std::memcmp(&*a_seg, &*b_seg, std::min(a_len, b_len));
|
||||
if (cmp) {
|
||||
return check_with_op(cmp);
|
||||
}
|
||||
|
||||
if (a_len != b_len) {
|
||||
return check_with_op(a_len > b_len ? 1 : -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (a_cur == a_end) {
|
||||
if (b_cur == b_end) {
|
||||
return check_with_op(0);
|
||||
}
|
||||
return check_with_op(-1);
|
||||
}
|
||||
|
||||
return check_with_op(1);
|
||||
}
|
||||
|
||||
cmPkgConfigVersionReq cmPkgConfigResolver::ParseVersion(
|
||||
const std::string& version)
|
||||
{
|
||||
cmPkgConfigVersionReq result;
|
||||
|
||||
auto cur = version.begin();
|
||||
auto end = version.end();
|
||||
|
||||
if (cur == end) {
|
||||
result.Operation = cmPkgConfigVersionReq::EQ;
|
||||
return result;
|
||||
}
|
||||
|
||||
result = ParseVersion(cur, end);
|
||||
cur = version.begin();
|
||||
|
||||
if (*cur != '=' && *cur != '!' && *cur != '<' && *cur != '>') {
|
||||
result.Operation = cmPkgConfigVersionReq::EQ;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
172
Source/cmPkgConfigResolver.h
Normal file
172
Source/cmPkgConfigResolver.h
Normal file
@@ -0,0 +1,172 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/optional>
|
||||
#include <cm/string_view>
|
||||
|
||||
// From cmPkgConfigParser.h, IWYU doesn't like including the header
|
||||
struct cmPkgConfigEntry;
|
||||
|
||||
struct cmPkgConfigCflagsResult
|
||||
{
|
||||
std::string Flagline;
|
||||
std::vector<std::string> Includes;
|
||||
std::vector<std::string> CompileOptions;
|
||||
};
|
||||
|
||||
struct cmPkgConfigLibsResult
|
||||
{
|
||||
std::string Flagline;
|
||||
std::vector<std::string> LibDirs;
|
||||
std::vector<std::string> LibNames;
|
||||
std::vector<std::string> LinkOptions;
|
||||
};
|
||||
|
||||
struct cmPkgConfigVersionReq
|
||||
{
|
||||
enum
|
||||
{
|
||||
ANY = 0,
|
||||
LT,
|
||||
LT_EQ,
|
||||
EQ,
|
||||
NEQ,
|
||||
GT_EQ,
|
||||
GT,
|
||||
} Operation = ANY;
|
||||
std::string Version;
|
||||
};
|
||||
|
||||
struct cmPkgConfigDependency
|
||||
{
|
||||
std::string Name;
|
||||
cmPkgConfigVersionReq VerReq;
|
||||
};
|
||||
|
||||
struct cmPkgConfigEnv
|
||||
{
|
||||
cm::optional<std::vector<std::string>> Path;
|
||||
cm::optional<std::vector<std::string>> LibDirs;
|
||||
cm::optional<std::vector<std::string>> SysCflags;
|
||||
cm::optional<std::vector<std::string>> SysLibs;
|
||||
|
||||
cm::optional<std::string> SysrootDir;
|
||||
cm::optional<std::string> TopBuildDir;
|
||||
|
||||
cm::optional<bool> DisableUninstalled;
|
||||
|
||||
bool AllowSysCflags = true;
|
||||
bool AllowSysLibs = true;
|
||||
};
|
||||
|
||||
class cmPkgConfigResult
|
||||
{
|
||||
public:
|
||||
std::unordered_map<std::string, std::string> Keywords;
|
||||
std::unordered_map<std::string, std::string> Variables;
|
||||
|
||||
std::string Name();
|
||||
std::string Description();
|
||||
std::string Version();
|
||||
|
||||
std::vector<cmPkgConfigDependency> Conflicts();
|
||||
std::vector<cmPkgConfigDependency> Provides();
|
||||
std::vector<cmPkgConfigDependency> Requires(bool priv = false);
|
||||
|
||||
cmPkgConfigCflagsResult Cflags(bool priv = false);
|
||||
cmPkgConfigLibsResult Libs(bool priv = false);
|
||||
|
||||
cmPkgConfigEnv env;
|
||||
|
||||
private:
|
||||
std::string StrOrDefault(const std::string& key, cm::string_view def = "");
|
||||
};
|
||||
|
||||
class cmPkgConfigResolver
|
||||
{
|
||||
friend class cmPkgConfigResult;
|
||||
|
||||
public:
|
||||
static cm::optional<cmPkgConfigResult> ResolveStrict(
|
||||
const std::vector<cmPkgConfigEntry>& entries, cmPkgConfigEnv env);
|
||||
|
||||
static cm::optional<cmPkgConfigResult> ResolvePermissive(
|
||||
const std::vector<cmPkgConfigEntry>& entries, cmPkgConfigEnv env);
|
||||
|
||||
static cmPkgConfigResult ResolveBestEffort(
|
||||
const std::vector<cmPkgConfigEntry>& entries, cmPkgConfigEnv env);
|
||||
|
||||
static cmPkgConfigVersionReq ParseVersion(const std::string& version);
|
||||
|
||||
static bool CheckVersion(const cmPkgConfigVersionReq& desired,
|
||||
const std::string& provided);
|
||||
|
||||
static void ReplaceSep(std::string& list);
|
||||
|
||||
#ifdef _WIN32
|
||||
static const char Sep = ';';
|
||||
#else
|
||||
static const char Sep = ':';
|
||||
#endif
|
||||
|
||||
private:
|
||||
static std::string HandleVariablePermissive(
|
||||
const cmPkgConfigEntry& entry,
|
||||
const std::unordered_map<std::string, std::string>& variables);
|
||||
|
||||
static cm::optional<std::string> HandleVariableStrict(
|
||||
const cmPkgConfigEntry& entry,
|
||||
const std::unordered_map<std::string, std::string>& variables);
|
||||
|
||||
static std::string HandleKeyword(
|
||||
const cmPkgConfigEntry& entry,
|
||||
const std::unordered_map<std::string, std::string>& variables);
|
||||
|
||||
static std::vector<cm::string_view> TokenizeFlags(
|
||||
const std::string& flagline);
|
||||
|
||||
static cmPkgConfigCflagsResult MangleCflags(
|
||||
const std::vector<cm::string_view>& flags);
|
||||
|
||||
static cmPkgConfigCflagsResult MangleCflags(
|
||||
const std::vector<cm::string_view>& flags, const std::string& sysroot);
|
||||
|
||||
static cmPkgConfigCflagsResult MangleCflags(
|
||||
const std::vector<cm::string_view>& flags,
|
||||
const std::vector<std::string>& syspaths);
|
||||
|
||||
static cmPkgConfigCflagsResult MangleCflags(
|
||||
const std::vector<cm::string_view>& flags, const std::string& sysroot,
|
||||
const std::vector<std::string>& syspaths);
|
||||
|
||||
static cmPkgConfigLibsResult MangleLibs(
|
||||
const std::vector<cm::string_view>& flags);
|
||||
|
||||
static cmPkgConfigLibsResult MangleLibs(
|
||||
const std::vector<cm::string_view>& flags, const std::string& sysroot);
|
||||
|
||||
static cmPkgConfigLibsResult MangleLibs(
|
||||
const std::vector<cm::string_view>& flags,
|
||||
const std::vector<std::string>& syspaths);
|
||||
|
||||
static cmPkgConfigLibsResult MangleLibs(
|
||||
const std::vector<cm::string_view>& flags, const std::string& sysroot,
|
||||
const std::vector<std::string>& syspaths);
|
||||
|
||||
static std::string Reroot(cm::string_view flag, cm::string_view prefix,
|
||||
const std::string& sysroot);
|
||||
|
||||
static cmPkgConfigVersionReq ParseVersion(std::string::const_iterator& cur,
|
||||
std::string::const_iterator end);
|
||||
|
||||
static std::vector<cmPkgConfigDependency> ParseDependencies(
|
||||
const std::string& deps);
|
||||
};
|
||||
@@ -560,6 +560,7 @@ add_RunCMake_test(cmake_language)
|
||||
add_RunCMake_test(cmake_minimum_required)
|
||||
add_RunCMake_test(cmake_parse_arguments)
|
||||
add_RunCMake_test(cmake_path -DMSYS=${MSYS})
|
||||
add_RunCMake_test(cmake_pkg_config)
|
||||
add_RunCMake_test(continue)
|
||||
add_executable(color_warning color_warning.c)
|
||||
add_executable(fake_build_command fake_build_command.c)
|
||||
|
||||
5
Tests/RunCMake/cmake_pkg_config/CMakeLists.txt
Normal file
5
Tests/RunCMake/cmake_pkg_config/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.30)
|
||||
project(${RunCMake_TEST} NONE)
|
||||
|
||||
set(CMAKE_PKG_CONFIG_PC_LIB_DIRS ${CMAKE_CURRENT_LIST_DIR}/PackageRoot)
|
||||
include(${RunCMake_TEST}.cmake)
|
||||
@@ -0,0 +1,3 @@
|
||||
Name:
|
||||
Version: aa
|
||||
Description:
|
||||
@@ -0,0 +1,3 @@
|
||||
Name:
|
||||
Version: 11
|
||||
Description:
|
||||
@@ -0,0 +1,3 @@
|
||||
Name:
|
||||
Version: 1.1.1
|
||||
Description:
|
||||
@@ -0,0 +1,3 @@
|
||||
Name:
|
||||
Version: ~0
|
||||
Description:
|
||||
@@ -0,0 +1,3 @@
|
||||
Name:
|
||||
Version: ~~1
|
||||
Description:
|
||||
@@ -0,0 +1,3 @@
|
||||
Name:
|
||||
Version: 01
|
||||
Description:
|
||||
@@ -0,0 +1,15 @@
|
||||
Name: Extract All
|
||||
Description: All flags example
|
||||
Version: 1.0.0
|
||||
|
||||
Conflicts: Alpha Beta
|
||||
Provides: Gamma Delta
|
||||
|
||||
Requires: Epsilon Zea
|
||||
Requires.private: Eta Theta
|
||||
|
||||
Cflags: Iota -IKappa Lambda -IMu
|
||||
Cflags.private: Nu -IXi Omnicron -IPi
|
||||
|
||||
Libs: Rho -LSigma -lTau Upsilon -LPhi -lChi
|
||||
Libs.private: Psi -LOmega -lMoe Larry -LCurly -lShemp
|
||||
3
Tests/RunCMake/cmake_pkg_config/PackageRoot/bar.pc
Normal file
3
Tests/RunCMake/cmake_pkg_config/PackageRoot/bar.pc
Normal file
@@ -0,0 +1,3 @@
|
||||
Name: Bar
|
||||
Description: Bar Description
|
||||
Version: 1.0.0
|
||||
3
Tests/RunCMake/cmake_pkg_config/PackageRoot/baz.pc
Normal file
3
Tests/RunCMake/cmake_pkg_config/PackageRoot/baz.pc
Normal file
@@ -0,0 +1,3 @@
|
||||
Name: Baz
|
||||
Description: Baz Description
|
||||
Version: 1.0.0
|
||||
@@ -0,0 +1,6 @@
|
||||
Name: Cflags Bothcase
|
||||
Description: The f is lowercase and uppercase
|
||||
Version: 1.0.0
|
||||
|
||||
Cflags: lowercase
|
||||
CFlags: uppercase
|
||||
@@ -0,0 +1,5 @@
|
||||
Name: Cflags Lowercase
|
||||
Description: The f is lowercase
|
||||
Version: 1.0.0
|
||||
|
||||
Cflags: lowercase
|
||||
@@ -0,0 +1,5 @@
|
||||
Name: CFlags Uppercase
|
||||
Description: The f is uppercase
|
||||
Version: 1.0.0
|
||||
|
||||
CFlags: uppercase
|
||||
3
Tests/RunCMake/cmake_pkg_config/PackageRoot/empty-key.pc
Normal file
3
Tests/RunCMake/cmake_pkg_config/PackageRoot/empty-key.pc
Normal file
@@ -0,0 +1,3 @@
|
||||
Name:
|
||||
Description:
|
||||
Version:
|
||||
3
Tests/RunCMake/cmake_pkg_config/PackageRoot/foo.pc
Normal file
3
Tests/RunCMake/cmake_pkg_config/PackageRoot/foo.pc
Normal file
@@ -0,0 +1,3 @@
|
||||
Name: Foo
|
||||
Description: Foo Description
|
||||
Version: 1.0.0
|
||||
4
Tests/RunCMake/cmake_pkg_config/PackageRoot/invalid.pc
Normal file
4
Tests/RunCMake/cmake_pkg_config/PackageRoot/invalid.pc
Normal file
@@ -0,0 +1,4 @@
|
||||
Name: Invalid
|
||||
Description: Will cause a parse error
|
||||
Version: 1.0.0
|
||||
BrokenKey
|
||||
@@ -0,0 +1,2 @@
|
||||
Name: name
|
||||
Version: version
|
||||
2
Tests/RunCMake/cmake_pkg_config/PackageRoot/no-name.pc
Normal file
2
Tests/RunCMake/cmake_pkg_config/PackageRoot/no-name.pc
Normal file
@@ -0,0 +1,2 @@
|
||||
Description: description
|
||||
Version: version
|
||||
@@ -0,0 +1,2 @@
|
||||
Name: name
|
||||
Description: description
|
||||
@@ -0,0 +1,5 @@
|
||||
Name: Qux
|
||||
Description: Qux Description
|
||||
Version: 1.0.0
|
||||
|
||||
Cflags: QuxUninstalled
|
||||
5
Tests/RunCMake/cmake_pkg_config/PackageRoot/qux.pc
Normal file
5
Tests/RunCMake/cmake_pkg_config/PackageRoot/qux.pc
Normal file
@@ -0,0 +1,5 @@
|
||||
Name: Qux
|
||||
Description: Qux Description
|
||||
Version: 1.0.0
|
||||
|
||||
Cflags: QuxInstalled
|
||||
6
Tests/RunCMake/cmake_pkg_config/PackageRoot/relocate.pc
Normal file
6
Tests/RunCMake/cmake_pkg_config/PackageRoot/relocate.pc
Normal file
@@ -0,0 +1,6 @@
|
||||
Name: Relocate
|
||||
Description: For testing relocation and flag mangling
|
||||
Version: 1.0.0
|
||||
|
||||
Cflags: -I/Alpha Beta -I/Gamma
|
||||
Libs: -L/Delta Epsilon -L/Zeta
|
||||
18
Tests/RunCMake/cmake_pkg_config/RunCMakeTest.cmake
Normal file
18
Tests/RunCMake/cmake_pkg_config/RunCMakeTest.cmake
Normal file
@@ -0,0 +1,18 @@
|
||||
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}
|
||||
)
|
||||
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)
|
||||
15
Tests/RunCMake/cmake_pkg_config/TestEnv-stderr.txt
Normal file
15
Tests/RunCMake/cmake_pkg_config/TestEnv-stderr.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
Includes: -I/Alpha;-I/Gamma
|
||||
LibDirs: -L/Delta;-L/Zeta
|
||||
Cflags: QuxInstalled
|
||||
PC_LIB_DIRS: Alpha;Beta
|
||||
PC_PATH: [^
|
||||
]*/PackageRoot
|
||||
DISABLE_UNINSTALLED: ON
|
||||
SYSROOT_DIR: Delta
|
||||
TOP_BUILD_DIR: Epsilon
|
||||
SYSTEM_INCLUDE_DIRS: Zeta;Eta
|
||||
SYSTEM_LIB_DIRS: Theta;Iota
|
||||
ALLOW_SYSTEM_INCLUDES: ON
|
||||
ALLOW_SYSTEM_LIBRARIES: ON
|
||||
PKGCONF_INCLUDES: Mu;Nu;Xi;Omnicron;Pi;Rho;Sigma;Tau
|
||||
PKGCONF_LIB_DIRS: Upsilon;Phi
|
||||
75
Tests/RunCMake/cmake_pkg_config/TestEnv.cmake
Normal file
75
Tests/RunCMake/cmake_pkg_config/TestEnv.cmake
Normal file
@@ -0,0 +1,75 @@
|
||||
set(CMAKE_PKG_CONFIG_PC_LIB_DIRS)
|
||||
|
||||
set(ENV{PKG_CONFIG_PATH} ${CMAKE_CURRENT_LIST_DIR}/PackageRoot)
|
||||
|
||||
if(WIN32)
|
||||
set(sep ";")
|
||||
else()
|
||||
set(sep ":")
|
||||
endif()
|
||||
|
||||
set(ENV{PKG_CONFIG_LIBDIR} "Alpha${sep}Beta")
|
||||
set(ENV{PKG_CONFIG_DISABLE_UNINSTALLED} Gamma)
|
||||
set(ENV{PKG_CONFIG_SYSROOT_DIR} Delta)
|
||||
set(ENV{PKG_CONFIG_TOP_BUILD_DIR} Epsilon)
|
||||
set(ENV{PKG_CONFIG_SYSTEM_INCLUDE_PATH} "Zeta${sep}Eta")
|
||||
set(ENV{PKG_CONFIG_SYSTEM_LIBRARY_PATH} "Theta${sep}Iota")
|
||||
set(ENV{PKG_CONFIG_ALLOW_SYSTEM_CFLAGS} Kappa)
|
||||
set(ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS} Lambda)
|
||||
|
||||
set(ENV{CPATH} "Mu${sep}Nu")
|
||||
set(ENV{C_INCLUDE_PATH} "Xi${sep}Omnicron")
|
||||
set(ENV{CPLUS_INCLUDE_PATH} "Pi${sep}Rho")
|
||||
|
||||
if(WIN32)
|
||||
set(ENV{OBJC_INCLUDE_PATH} Sigma)
|
||||
set(ENV{INCLUDE} Tau)
|
||||
else()
|
||||
set(ENV{OBJC_INCLUDE_PATH} Sigma:Tau)
|
||||
endif()
|
||||
|
||||
set(ENV{LIBRARY_PATH} "Upsilon${sep}Phi")
|
||||
|
||||
cmake_pkg_config(
|
||||
EXTRACT relocate
|
||||
ENV_MODE IGNORE
|
||||
PC_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageRoot
|
||||
SYSTEM_INCLUDE_DIRS /Alpha
|
||||
SYSTEM_LIBRARY_DIRS /Beta
|
||||
)
|
||||
|
||||
# Shouldn't mangle, ALLOW_SYSTEM_* should default to on under ENV IGNORE
|
||||
message("Includes: ${CMAKE_PKG_CONFIG_INCLUDES}")
|
||||
message("LibDirs: ${CMAKE_PKG_CONFIG_LIBDIRS}")
|
||||
|
||||
cmake_pkg_config(
|
||||
EXTRACT qux
|
||||
ENV_MODE IGNORE
|
||||
PC_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageRoot
|
||||
)
|
||||
|
||||
# Shouldn't find uninstalled package
|
||||
message("Cflags: ${CMAKE_PKG_CONFIG_CFLAGS}")
|
||||
|
||||
cmake_pkg_config(
|
||||
EXTRACT foo
|
||||
ENV_MODE FDO
|
||||
)
|
||||
|
||||
message("PC_LIB_DIRS: ${CMAKE_PKG_CONFIG_PC_LIB_DIRS}")
|
||||
message("PC_PATH: ${CMAKE_PKG_CONFIG_PC_PATH}")
|
||||
message("DISABLE_UNINSTALLED: ${CMAKE_PKG_CONFIG_DISABLE_UNINSTALLED}")
|
||||
message("SYSROOT_DIR: ${CMAKE_PKG_CONFIG_SYSROOT_DIR}")
|
||||
message("TOP_BUILD_DIR: ${CMAKE_PKG_CONFIG_TOP_BUILD_DIR}")
|
||||
message("SYSTEM_INCLUDE_DIRS: ${CMAKE_PKG_CONFIG_SYS_INCLUDE_DIRS}")
|
||||
message("SYSTEM_LIB_DIRS: ${CMAKE_PKG_CONFIG_SYS_LIB_DIRS}")
|
||||
message("ALLOW_SYSTEM_INCLUDES: ${CMAKE_PKG_CONFIG_ALLOW_SYS_INCLUDES}")
|
||||
message("ALLOW_SYSTEM_LIBRARIES: ${CMAKE_PKG_CONFIG_ALLOW_SYS_LIBS}")
|
||||
|
||||
cmake_pkg_config(
|
||||
EXTRACT foo
|
||||
ENV_MODE PKGCONF
|
||||
)
|
||||
|
||||
message("PKGCONF_INCLUDES: ${CMAKE_PKG_CONFIG_PKGCONF_INCLUDES}")
|
||||
message("PKGCONF_LIB_DIRS: ${CMAKE_PKG_CONFIG_PKGCONF_LIB_DIRS}")
|
||||
21
Tests/RunCMake/cmake_pkg_config/TestExtract-stderr.txt
Normal file
21
Tests/RunCMake/cmake_pkg_config/TestExtract-stderr.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
Name: Extract All
|
||||
Description: All flags example
|
||||
Version: 1.0.0
|
||||
Conflicts: Alpha;Beta
|
||||
Provides: Gamma;Delta
|
||||
Requires: Epsilon;Zea
|
||||
Requires.private: Eta;Theta
|
||||
Cflags: Iota -IKappa Lambda -IMu
|
||||
Includes: -IKappa;-IMu
|
||||
CompileOptions: Iota;Lambda
|
||||
Cflags.private: Nu -IXi Omnicron -IPi
|
||||
Includes.private: -IXi;-IPi
|
||||
CompileOptions.private: Nu;Omnicron
|
||||
Libs: Rho -LSigma -lTau Upsilon -LPhi -lChi
|
||||
LibDirs: -LSigma;-LPhi
|
||||
LibNames: -lTau;-lChi
|
||||
LinkOptions: Rho;Upsilon
|
||||
Libs.private: Psi -LOmega -lMoe Larry -LCurly -lShemp
|
||||
LibDirs.private: -LOmega;-LCurly
|
||||
LibNames.private: -lMoe;-lShemp
|
||||
LinkOptions.private: Psi;Larry
|
||||
29
Tests/RunCMake/cmake_pkg_config/TestExtract.cmake
Normal file
29
Tests/RunCMake/cmake_pkg_config/TestExtract.cmake
Normal file
@@ -0,0 +1,29 @@
|
||||
cmake_pkg_config(EXTRACT all-extract-fields)
|
||||
|
||||
message("Name: ${CMAKE_PKG_CONFIG_NAME}")
|
||||
message("Description: ${CMAKE_PKG_CONFIG_DESCRIPTION}")
|
||||
message("Version: ${CMAKE_PKG_CONFIG_VERSION}")
|
||||
|
||||
message("Conflicts: ${CMAKE_PKG_CONFIG_CONFLICTS}")
|
||||
message("Provides: ${CMAKE_PKG_CONFIG_PROVIDES}")
|
||||
|
||||
message("Requires: ${CMAKE_PKG_CONFIG_REQUIRES}")
|
||||
message("Requires.private: ${CMAKE_PKG_CONFIG_REQUIRES_PRIVATE}")
|
||||
|
||||
message("Cflags: ${CMAKE_PKG_CONFIG_CFLAGS}")
|
||||
message("Includes: ${CMAKE_PKG_CONFIG_INCLUDES}")
|
||||
message("CompileOptions: ${CMAKE_PKG_CONFIG_COMPILE_OPTIONS}")
|
||||
|
||||
message("Cflags.private: ${CMAKE_PKG_CONFIG_CFLAGS_PRIVATE}")
|
||||
message("Includes.private: ${CMAKE_PKG_CONFIG_INCLUDES_PRIVATE}")
|
||||
message("CompileOptions.private: ${CMAKE_PKG_CONFIG_COMPILE_OPTIONS_PRIVATE}")
|
||||
|
||||
message("Libs: ${CMAKE_PKG_CONFIG_LIBS}")
|
||||
message("LibDirs: ${CMAKE_PKG_CONFIG_LIBDIRS}")
|
||||
message("LibNames: ${CMAKE_PKG_CONFIG_LIBNAMES}")
|
||||
message("LinkOptions: ${CMAKE_PKG_CONFIG_LINK_OPTIONS}")
|
||||
|
||||
message("Libs.private: ${CMAKE_PKG_CONFIG_LIBS_PRIVATE}")
|
||||
message("LibDirs.private: ${CMAKE_PKG_CONFIG_LIBDIRS_PRIVATE}")
|
||||
message("LibNames.private: ${CMAKE_PKG_CONFIG_LIBNAMES_PRIVATE}")
|
||||
message("LinkOptions.private: ${CMAKE_PKG_CONFIG_LINK_OPTIONS_PRIVATE}")
|
||||
8
Tests/RunCMake/cmake_pkg_config/TestMangle-stderr.txt
Normal file
8
Tests/RunCMake/cmake_pkg_config/TestMangle-stderr.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
Cflags: Beta -I/Gamma
|
||||
Includes: -I/Gamma
|
||||
Libs: Epsilon -L/Zeta
|
||||
LibDirs: -L/Zeta
|
||||
Cflags: -I/Alpha Beta -I/Gamma
|
||||
Includes: -I/Alpha;-I/Gamma
|
||||
Libs: -L/Delta Epsilon -L/Zeta
|
||||
LibDirs: -L/Delta;-L/Zeta
|
||||
22
Tests/RunCMake/cmake_pkg_config/TestMangle.cmake
Normal file
22
Tests/RunCMake/cmake_pkg_config/TestMangle.cmake
Normal file
@@ -0,0 +1,22 @@
|
||||
set(CMAKE_PKG_CONFIG_SYS_INCLUDE_DIRS /Alpha)
|
||||
set(CMAKE_PKG_CONFIG_SYS_LIB_DIRS /Delta)
|
||||
|
||||
cmake_pkg_config(EXTRACT relocate)
|
||||
|
||||
message("Cflags: ${CMAKE_PKG_CONFIG_CFLAGS}")
|
||||
message("Includes: ${CMAKE_PKG_CONFIG_INCLUDES}")
|
||||
|
||||
message("Libs: ${CMAKE_PKG_CONFIG_LIBS}")
|
||||
message("LibDirs: ${CMAKE_PKG_CONFIG_LIBDIRS}")
|
||||
|
||||
cmake_pkg_config(
|
||||
EXTRACT relocate
|
||||
ALLOW_SYSTEM_INCLUDES ON
|
||||
ALLOW_SYSTEM_LIBS ON
|
||||
)
|
||||
|
||||
message("Cflags: ${CMAKE_PKG_CONFIG_CFLAGS}")
|
||||
message("Includes: ${CMAKE_PKG_CONFIG_INCLUDES}")
|
||||
|
||||
message("Libs: ${CMAKE_PKG_CONFIG_LIBS}")
|
||||
message("LibDirs: ${CMAKE_PKG_CONFIG_LIBDIRS}")
|
||||
29
Tests/RunCMake/cmake_pkg_config/TestQuiet.cmake
Normal file
29
Tests/RunCMake/cmake_pkg_config/TestQuiet.cmake
Normal file
@@ -0,0 +1,29 @@
|
||||
cmake_pkg_config(
|
||||
EXTRACT foo
|
||||
QUIET
|
||||
STRICTNESS STRICT
|
||||
)
|
||||
|
||||
cmake_pkg_config(
|
||||
EXTRACT no-name
|
||||
QUIET
|
||||
STRICTNESS STRICT
|
||||
)
|
||||
|
||||
cmake_pkg_config(
|
||||
EXTRACT empty-key
|
||||
QUIET
|
||||
STRICTNESS STRICT
|
||||
)
|
||||
|
||||
cmake_pkg_config(
|
||||
EXTRACT cflags-bothcase-f
|
||||
QUIET
|
||||
STRICTNESS STRICT
|
||||
)
|
||||
|
||||
cmake_pkg_config(
|
||||
EXTRACT does-not-exist
|
||||
QUIET
|
||||
STRICTNESS STRICT
|
||||
)
|
||||
1
Tests/RunCMake/cmake_pkg_config/TestRequired-result.txt
Normal file
1
Tests/RunCMake/cmake_pkg_config/TestRequired-result.txt
Normal file
@@ -0,0 +1 @@
|
||||
1
|
||||
4
Tests/RunCMake/cmake_pkg_config/TestRequired-stderr.txt
Normal file
4
Tests/RunCMake/cmake_pkg_config/TestRequired-stderr.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
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\)
|
||||
9
Tests/RunCMake/cmake_pkg_config/TestRequired.cmake
Normal file
9
Tests/RunCMake/cmake_pkg_config/TestRequired.cmake
Normal file
@@ -0,0 +1,9 @@
|
||||
cmake_pkg_config(
|
||||
EXTRACT foo
|
||||
REQUIRED
|
||||
)
|
||||
|
||||
cmake_pkg_config(
|
||||
EXTRACT does-not-exist
|
||||
REQUIRED
|
||||
)
|
||||
4
Tests/RunCMake/cmake_pkg_config/TestReroot-stderr.txt
Normal file
4
Tests/RunCMake/cmake_pkg_config/TestReroot-stderr.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Cflags: -I/NewRoot/Alpha Beta -I/NewRoot/Gamma
|
||||
Includes: -I/NewRoot/Alpha;-I/NewRoot/Gamma
|
||||
Libs: -L/NewRoot/Delta Epsilon -L/NewRoot/Zeta
|
||||
LibDirs: -L/NewRoot/Delta;-L/NewRoot/Zeta
|
||||
10
Tests/RunCMake/cmake_pkg_config/TestReroot.cmake
Normal file
10
Tests/RunCMake/cmake_pkg_config/TestReroot.cmake
Normal file
@@ -0,0 +1,10 @@
|
||||
cmake_pkg_config(
|
||||
EXTRACT relocate
|
||||
PC_SYSROOT_DIR /NewRoot
|
||||
)
|
||||
|
||||
message("Cflags: ${CMAKE_PKG_CONFIG_CFLAGS}")
|
||||
message("Includes: ${CMAKE_PKG_CONFIG_INCLUDES}")
|
||||
|
||||
message("Libs: ${CMAKE_PKG_CONFIG_LIBS}")
|
||||
message("LibDirs: ${CMAKE_PKG_CONFIG_LIBDIRS}")
|
||||
@@ -0,0 +1,3 @@
|
||||
Cflags: lowercase
|
||||
CFlags: uppercase
|
||||
Cflags: lowercase uppercase
|
||||
@@ -0,0 +1,31 @@
|
||||
CMake Warning at TestStrictness.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\):
|
||||
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\):
|
||||
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\):
|
||||
Parsing failed for file[^
|
||||
]*(.)*/PackageRoot/invalid.pc'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
Cflags: lowercase
|
||||
CFlags: uppercase
|
||||
Cflags: lowercase uppercase
|
||||
@@ -0,0 +1,38 @@
|
||||
CMake Warning at TestStrictness.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\):
|
||||
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\):
|
||||
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\):
|
||||
Parsing failed for file[^
|
||||
]*(.)*/PackageRoot/invalid.pc'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
Cflags: lowercase
|
||||
CFlags: uppercase
|
||||
CMake Warning at TestStrictness.cmake:[0-9]+ \(cmake_pkg_config\):
|
||||
Resolution failed for file[^
|
||||
]*(.)*/PackageRoot/cflags-bothcase-f.pc'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
|
||||
|
||||
Cflags:
|
||||
51
Tests/RunCMake/cmake_pkg_config/TestStrictness.cmake
Normal file
51
Tests/RunCMake/cmake_pkg_config/TestStrictness.cmake
Normal file
@@ -0,0 +1,51 @@
|
||||
cmake_pkg_config(
|
||||
EXTRACT foo
|
||||
STRICTNESS ${STRICTNESS}
|
||||
REQUIRED
|
||||
)
|
||||
|
||||
cmake_pkg_config(
|
||||
EXTRACT empty-key
|
||||
STRICTNESS ${STRICTNESS}
|
||||
REQUIRED
|
||||
)
|
||||
|
||||
cmake_pkg_config(
|
||||
EXTRACT no-name
|
||||
STRICTNESS ${STRICTNESS}
|
||||
)
|
||||
|
||||
cmake_pkg_config(
|
||||
EXTRACT no-description
|
||||
STRICTNESS ${STRICTNESS}
|
||||
)
|
||||
|
||||
cmake_pkg_config(
|
||||
EXTRACT no-version
|
||||
STRICTNESS ${STRICTNESS}
|
||||
)
|
||||
|
||||
cmake_pkg_config(
|
||||
EXTRACT invalid
|
||||
STRICTNESS ${STRICTNESS}
|
||||
)
|
||||
|
||||
cmake_pkg_config(
|
||||
EXTRACT cflags-lowercase-f
|
||||
STRICTNESS ${STRICTNESS}
|
||||
)
|
||||
message("Cflags: ${CMAKE_PKG_CONFIG_CFLAGS}")
|
||||
|
||||
set(CMAKE_PKG_CONFIG_CFLAGS)
|
||||
cmake_pkg_config(
|
||||
EXTRACT cflags-uppercase-f
|
||||
STRICTNESS ${STRICTNESS}
|
||||
)
|
||||
message("CFlags: ${CMAKE_PKG_CONFIG_CFLAGS}")
|
||||
|
||||
set(CMAKE_PKG_CONFIG_CFLAGS)
|
||||
cmake_pkg_config(
|
||||
EXTRACT cflags-bothcase-f
|
||||
STRICTNESS ${STRICTNESS}
|
||||
)
|
||||
message("Cflags: ${CMAKE_PKG_CONFIG_CFLAGS}")
|
||||
@@ -0,0 +1,2 @@
|
||||
QuxUninstalled
|
||||
QuxInstalled
|
||||
10
Tests/RunCMake/cmake_pkg_config/TestUninstalled.cmake
Normal file
10
Tests/RunCMake/cmake_pkg_config/TestUninstalled.cmake
Normal file
@@ -0,0 +1,10 @@
|
||||
cmake_pkg_config(EXTRACT qux)
|
||||
|
||||
message(${CMAKE_PKG_CONFIG_CFLAGS})
|
||||
|
||||
cmake_pkg_config(
|
||||
EXTRACT qux
|
||||
DISABLE_UNINSTALLED ON
|
||||
)
|
||||
|
||||
message(${CMAKE_PKG_CONFIG_CFLAGS})
|
||||
103
Tests/RunCMake/cmake_pkg_config/TestVersion-stderr.txt
Normal file
103
Tests/RunCMake/cmake_pkg_config/TestVersion-stderr.txt
Normal file
@@ -0,0 +1,103 @@
|
||||
CMake Warning at TestVersion.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\):
|
||||
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\):
|
||||
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\):
|
||||
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\):
|
||||
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\):
|
||||
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\):
|
||||
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\):
|
||||
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\):
|
||||
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\):
|
||||
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\):
|
||||
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\):
|
||||
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\):
|
||||
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\):
|
||||
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\):
|
||||
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\):
|
||||
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\):
|
||||
Package 'tilde' version '~~1' does not meet version requirement '<~~~1'
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists.txt:[0-9]+ \(include\)
|
||||
65
Tests/RunCMake/cmake_pkg_config/TestVersion.cmake
Normal file
65
Tests/RunCMake/cmake_pkg_config/TestVersion.cmake
Normal file
@@ -0,0 +1,65 @@
|
||||
set(CMAKE_PKG_CONFIG_PC_PATH ${CMAKE_CURRENT_LIST_DIR}/PackageRoot/VersionPackages)
|
||||
|
||||
# Good = Should Succeed
|
||||
# Bad = Should Warn
|
||||
|
||||
cmake_pkg_config(EXTRACT a =aa) # Good
|
||||
cmake_pkg_config(EXTRACT a >a) # Good
|
||||
cmake_pkg_config(EXTRACT a <a) # Bad
|
||||
cmake_pkg_config(EXTRACT a >aaa) # Bad
|
||||
cmake_pkg_config(EXTRACT a <aaa) # Good
|
||||
|
||||
cmake_pkg_config(EXTRACT a !=bb) # Good
|
||||
cmake_pkg_config(EXTRACT a >bb) # Bad
|
||||
cmake_pkg_config(EXTRACT a <bb) # Good
|
||||
|
||||
cmake_pkg_config(EXTRACT a >1) # Bad
|
||||
cmake_pkg_config(EXTRACT a <1) # Good
|
||||
|
||||
cmake_pkg_config(EXTRACT empty-key =) # Good
|
||||
cmake_pkg_config(EXTRACT empty-key !=) # Bad
|
||||
cmake_pkg_config(EXTRACT empty-key =0) # Bad
|
||||
cmake_pkg_config(EXTRACT empty-key !=0) # Good
|
||||
|
||||
cmake_pkg_config(EXTRACT empty-key EXACT) # Good
|
||||
|
||||
cmake_pkg_config(EXTRACT one =11) # Good
|
||||
cmake_pkg_config(EXTRACT one >1) # Good
|
||||
cmake_pkg_config(EXTRACT one <1) # Bad
|
||||
cmake_pkg_config(EXTRACT one >111) # Bad
|
||||
cmake_pkg_config(EXTRACT one <111) # Good
|
||||
|
||||
cmake_pkg_config(EXTRACT one !=22) # Good
|
||||
cmake_pkg_config(EXTRACT one >22) # Bad
|
||||
cmake_pkg_config(EXTRACT one <22) # Good
|
||||
|
||||
cmake_pkg_config(EXTRACT one >a) # Good
|
||||
cmake_pkg_config(EXTRACT one <a) # Bad
|
||||
|
||||
cmake_pkg_config(EXTRACT onedot 1.1.1) # Good
|
||||
cmake_pkg_config(EXTRACT onedot 01.01.01) # Good
|
||||
cmake_pkg_config(EXTRACT onedot =1.1.1) # Good
|
||||
cmake_pkg_config(EXTRACT onedot =01.01.01) # Good
|
||||
cmake_pkg_config(EXTRACT onedot <1.2.1) # Good
|
||||
cmake_pkg_config(EXTRACT onedot >1.2.1) # Bad
|
||||
|
||||
cmake_pkg_config(EXTRACT onedot "< 1.2.1") # Good
|
||||
cmake_pkg_config(EXTRACT onedot "> 1.2.1") # Bad
|
||||
|
||||
cmake_pkg_config(EXTRACT onedot 1.1.1 EXACT) # Good
|
||||
cmake_pkg_config(EXTRACT onedot =1.1.1 EXACT) # Good
|
||||
cmake_pkg_config(EXTRACT onedot =01.01.01 EXACT) # Bad
|
||||
|
||||
cmake_pkg_config(EXTRACT pseudo-empty =~) # Bad
|
||||
cmake_pkg_config(EXTRACT pseudo-empty !=~) # Good
|
||||
cmake_pkg_config(EXTRACT pseudo-empty =~0) # Good
|
||||
cmake_pkg_config(EXTRACT pseudo-empty !=~0) # Bad
|
||||
|
||||
cmake_pkg_config(EXTRACT tilde =~~1) # Good
|
||||
cmake_pkg_config(EXTRACT tilde <~1) # Good
|
||||
cmake_pkg_config(EXTRACT tilde >~1) # Bad
|
||||
cmake_pkg_config(EXTRACT tilde <~~~1) # Bad
|
||||
cmake_pkg_config(EXTRACT tilde >~~~1) # Good
|
||||
|
||||
cmake_pkg_config(EXTRACT zeroone =1) # Good
|
||||
cmake_pkg_config(EXTRACT zeroone =001) # Good
|
||||
Reference in New Issue
Block a user