file: Add GET_RUNTIME_DEPENDENCIES mode

Co-Authored-by: Bryon Bean <bryon.bean@kitware.com>
This commit is contained in:
Kyle Edwards
2019-03-14 11:58:34 -04:00
parent f36719111d
commit 1f9ef25130
88 changed files with 3684 additions and 3 deletions

View File

@@ -13,6 +13,7 @@ Synopsis
file(`STRINGS`_ <filename> <out-var> [...])
file(`\<HASH\> <HASH_>`_ <filename> <out-var>)
file(`TIMESTAMP`_ <filename> <out-var> [...])
file(`GET_RUNTIME_DEPENDENCIES`_ [...])
`Writing`_
file({`WRITE`_ | `APPEND`_} <filename> <content>...)
@@ -130,6 +131,273 @@ timestamp variable will be set to the empty string ("").
See the :command:`string(TIMESTAMP)` command for documentation of
the ``<format>`` and ``UTC`` options.
.. _GET_RUNTIME_DEPENDENCIES:
.. code-block:: cmake
file(GET_RUNTIME_DEPENDENCIES
[RESOLVED_DEPENDENCIES_VAR <deps_var>]
[UNRESOLVED_DEPENDENCIES_VAR <unresolved_deps_var>]
[CONFLICTING_DEPENDENICES_PREFIX <conflicting_deps_prefix>]
[EXECUTABLES [<executable_files>...]]
[LIBRARIES [<library_files>...]]
[MODULES [<module_files>...]]
[DIRECTORIES [<directories>...]]
[BUNDLE_EXECUTABLE <bundle_executable_file>]
[PRE_INCLUDE_REGEXES [<regexes>...]]
[PRE_EXCLUDE_REGEXES [<regexes>...]]
[POST_INCLUDE_REGEXES [<regexes>...]]
[POST_EXCLUDE_REGEXES [<regexes>...]]
)
Recursively get the list of libraries depended on by the given files.
Please note that this sub-command is not intended to be used in project mode.
Instead, use it in an :command:`install(CODE)` or :command:`install(SCRIPT)`
block. For example:
.. code-block:: cmake
install(CODE [[
file(GET_RUNTIME_DEPENDENCIES
# ...
)
]])
The arguments are as follows:
``RESOLVED_DEPENDENCIES_VAR <deps_var>``
Name of the variable in which to store the list of resolved dependencies.
``UNRESOLVED_DEPENDENCIES_VAR <unresolved_deps_var>``
Name of the variable in which to store the list of unresolved dependencies.
If this variable is not specified, and there are any unresolved dependencies,
an error is issued.
``CONFLICTING_DEPENDENCIES_PREFIX <conflicting_deps_prefix>``
Variable prefix in which to store conflicting dependency information.
Dependencies are conflicting if two files with the same name are found in
two different directories. The list of filenames that conflict are stored in
``<conflicting_deps_prefix>_FILENAMES``. For each filename, the list of paths
that were found for that filename are stored in
``<conflicting_deps_prefix>_<filename>``.
``EXECUTABLES <executable_files>``
List of executable files to read for dependencies. These are executables that
are typically created with :command:`add_executable`, but they do not have to
be created by CMake. On Apple platforms, the paths to these files determine
the value of ``@executable_path`` when recursively resolving the libraries.
Specifying ``STATIC`` libraries, ``MODULE`` s, or ``SHARED`` libraries here
will result in undefined behavior.
``LIBRARIES <library_files>``
List of library files to read for dependencies. These are libraries that are
typically created with :command:`add_library(SHARED)`, but they do not have
to be created by CMake. Specifying ``STATIC`` libraries, ``MODULE`` s, or
executables here will result in undefined behavior.
``MODULES <module_files>``
List of loadable module files to read for dependencies. These are modules
that are typically created with :command:`add_library(MODULE)`, but they do
not have to be created by CMake. They are typically used by calling
``dlopen()`` at runtime rather than linked at link time with ``ld -l``.
Specifying ``STATIC`` libraries, ``SHARED`` libraries, or executables here
will result in undefined behavior.
``DIRECTORIES <directories>``
List of additional directories to search for dependencies. On Linux
platforms, these directories are searched if the dependency is not found in
any of the other usual paths. If it is found in such a directory, a warning
is issued, because it means that the file is incomplete (it does not list all
of the directories that contain its dependencies.) On Windows platforms,
these directories are searched if the dependency is not found in any of the
other search paths, but no warning is issued, because searching other paths
is a normal part of Windows dependency resolution. On Apple platforms, this
argument has no effect.
``BUNDLE_EXECTUBLE <bundle_executable_file>``
Executable to treat as the "bundle executable" when resolving libraries. On
Apple platforms, this argument determines the value of ``@executable_path``
when recursively resolving libraries for ``LIBRARIES`` and ``MODULES`` files.
It has no effect on ``EXECUTABLES`` files. On other platforms, it has no
effect. This is typically (but not always) one of the executables in the
``EXECUTABLES`` argument which designates the "main" executable of the
package.
The following arguments specify filters for including or excluding libraries to
be resolved. See below for a full description of how they work.
``PRE_INCLUDE_REGEXES <regexes>``
List of pre-include regexes through which to filter the names of
not-yet-resolved dependencies.
``PRE_EXCLUDE_REGEXES <regexes>``
List of pre-exclude regexes through which to filter the names of
not-yet-resolved dependencies.
``POST_INCLUDE_REGEXES <regexes>``
List of post-include regexes through which to filter the names of resolved
dependencies.
``POST_EXCLUDE_REGEXES <regexes>``
List of post-exclude regexes through which to filter the names of resolved
dependencies.
These arguments can be used to blacklist unwanted system libraries when
resolving the dependencies, or to whitelist libraries from a specific
directory. The filtering works as follows:
1. If the not-yet-resolved dependency matches any of the
``PRE_INCLUDE_REGEXES``, steps 2 and 3 are skipped, and the dependency
resolution proceeds to step 4.
2. If the not-yet-resolved dependency matches any of the
``PRE_EXCLUDE_REGEXES``, dependency resolution stops for that dependency.
3. Otherwise, dependency resolution proceeds.
4. ``file(GET_RUNTIME_DEPENDENCIES)`` searches for the dependency according to
the linking rules of the platform (see below).
5. If the dependency is found, and its full path matches one of the
``POST_INCLUDE_REGEXES``, the full path is added to the resolved
dependencies, and ``file(GET_RUNTIME_DEPENDENCIES)`` recursively resolves
that library's own dependencies. Otherwise, resolution proceeds to step 6.
6. If the dependency is found, but its full path matches one of the
``POST_EXCLUDE_REGEXES``, it is not added to the resolved dependencies, and
dependency resolution stops for that dependency.
7. If the dependency is found, and its full path does not match either
``POST_INCLUDE_REGEXES`` or ``POST_EXCLUDE_REGEXES``, the full path is added
to the resolved dependencies, and ``file(GET_RUNTIME_DEPENDENCIES)``
recursively resolves that library's own dependencies.
Different platforms have different rules for how dependencies are resolved.
These specifics are described here.
On Linux platforms, library resolution works as follows:
1. If the depending file does not have any ``RUNPATH`` entries, and the library
exists in one of the depending file's ``RPATH`` entries, or its parents', in
that order, the dependency is resolved to that file.
2. Otherwise, if the depending file has any ``RUNPATH`` entries, and the
library exists in one of those entries, the dependency is resolved to that
file.
3. Otherwise, if the library exists in one of the directories listed by
``ldconfig``, the dependency is resolved to that file.
4. Otherwise, if the library exists in one of the ``DIRECTORIES`` entries, the
dependency is resolved to that file. In this case, a warning is issued,
because finding a file in one of the ``DIRECTORIES`` means that the
depending file is not complete (it does not list all the directories from
which it pulls dependencies.)
5. Otherwise, the dependency is unresolved.
On Windows platforms, library resolution works as follows:
1. The dependent DLL name is converted to lowercase. Windows DLL names are
case-insensitive, and some linkers mangle the case of the DLL dependency
names. However, this makes it more difficult for ``PRE_INCLUDE_REGEXES``,
``PRE_EXCLUDE_REGEXES``, ``POST_INCLUDE_REGEXES``, and
``POST_EXCLUDE_REGEXES`` to properly filter DLL names - every regex would
have to check for both uppercase and lowercase letters. For example:
.. code-block:: cmake
file(GET_RUNTIME_DEPENDENCIES
# ...
PRE_INCLUDE_REGEXES "^[Mm][Yy][Ll][Ii][Bb][Rr][Aa][Rr][Yy]\\.[Dd][Ll][Ll]$"
)
Converting the DLL name to lowercase allows the regexes to only match
lowercase names, thus simplifying the regex. For example:
.. code-block:: cmake
file(GET_RUNTIME_DEPENDENCIES
# ...
PRE_INCLUDE_REGEXES "^mylibrary\\.dll$"
)
This regex will match ``mylibrary.dll`` regardless of how it is cased,
either on disk or in the depending file. (For example, it will match
``mylibrary.dll``, ``MyLibrary.dll``, and ``MYLIBRARY.DLL``.)
Please note that the directory portion of any resolved DLLs retains its
casing and is not converted to lowercase. Only the filename portion is
converted.
2. (**Not yet implemented**) If the depending file is a Windows Store app, and
the dependency is listed as a dependency in the application's package
manifest, the dependency is resolved to that file.
3. Otherwise, if the library exists in the same directory as the depending
file, the dependency is resolved to that file.
4. Otherwise, if the library exists in either the operating system's
``system32`` directory or the ``Windows`` directory, in that order, the
dependency is resolved to that file.
5. Otherwise, if the library exists in one of the directories specified by
``DIRECTORIES``, in the order they are listed, the dependency is resolved to
that file. (In this case, a warning is not issued, because searching other
directories is a normal part of Windows library resolution.)
6. Otherwise, the dependency is unresolved.
On Apple platforms, library resolution works as follows:
1. If the dependency starts with ``@executable_path/``, and an ``EXECUTABLES``
argument is in the process of being resolved, and replacing
``@executable_path/`` with the directory of the executable yields an
existing file, the dependency is resolved to that file.
2. Otherwise, if the dependency starts with ``@executable_path/``, and there is
a ``BUNDLE_EXECUTABLE`` argument, and replacing ``@executable_path/`` with
the directory of the bundle executable yields an existing file, the
dependency is resolved to that file.
3. Otherwise, if the dependency starts with ``@loader_path/``, and replacing
``@loader_path/`` with the directory of the depending file yields an
existing file, the dependency is resolved to that file.
4. Otherwise, if the dependency starts with ``@rpath/``, and replacing
``@rpath/`` with one of the ``RPATH`` entries of the depending file yields
an existing file, the dependency is resolved to that file. (Note that
``RPATH`` entries that start with ``@executable_path/`` or ``@loader_path/``
also have these items replaced with the appropriate path.)
5. Otherwise, if the dependency is an absolute file that exists, the dependency
is resolved to that file.
6. Otherwise, the dependency is unresolved.
This function accepts several variables that determine which tool is used for
dependency resolution:
.. variable:: CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM
Determines which operating system and executable format the files are built
for. This could be one of several values:
* ``linux+elf``
* ``windows+pe``
* ``macos+macho``
If this variable is not specified, it is determined automatically by system
introspection.
.. variable:: CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL
Determines the tool to use for dependency resolution. It could be one of
several values, depending on the value of
:variable:`CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM`:
================================================= =============================================
``CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM`` ``CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL``
================================================= =============================================
``linux+elf`` ``objdump``
``windows+pe`` ``dumpbin``
``windows+pe`` ``objdump``
``macos+macho`` ``otool``
================================================= =============================================
If this variable is not specified, it is determined automatically by system
introspection.
.. variable:: CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND
Determines the path to the tool to use for dependency resolution. This is the
actual path to ``objdump``, ``dumpbin``, or ``otool``.
If this variable is not specified, it is determined automatically by system
introspection.
Writing
^^^^^^^

View File

@@ -0,0 +1,7 @@
get-runtime-dependencies
------------------------
* The :command:`file` command learned a new sub-command,
``GET_RUNTIME_DEPENDENCIES``, which allows you to recursively get the list of
libraries linked by an executable or library. This sub-command is intended as
a replacement for :module:`GetPrerequisites`.

View File

@@ -146,6 +146,28 @@ set(SRCS
cmArgumentParser.cxx
cmArgumentParser.h
cmBase32.cxx
cmBinUtilsLinker.cxx
cmBinUtilsLinker.h
cmBinUtilsLinuxELFGetRuntimeDependenciesTool.cxx
cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h
cmBinUtilsLinuxELFLinker.cxx
cmBinUtilsLinuxELFLinker.h
cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.cxx
cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h
cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.cxx
cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h
cmBinUtilsMacOSMachOLinker.cxx
cmBinUtilsMacOSMachOLinker.h
cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx
cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.h
cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.cxx
cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h
cmBinUtilsWindowsPEGetRuntimeDependenciesTool.cxx
cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h
cmBinUtilsWindowsPELinker.cxx
cmBinUtilsWindowsPELinker.h
cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx
cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h
cmCacheManager.cxx
cmCacheManager.h
cmCLocaleEnvironmentScope.h
@@ -295,6 +317,10 @@ set(SRCS
cmInstallTargetGenerator.cxx
cmInstallDirectoryGenerator.h
cmInstallDirectoryGenerator.cxx
cmLDConfigLDConfigTool.cxx
cmLDConfigLDConfigTool.h
cmLDConfigTool.cxx
cmLDConfigTool.h
cmLinkedTree.h
cmLinkItem.cxx
cmLinkItem.h
@@ -360,6 +386,8 @@ set(SRCS
cmQtAutoRcc.h
cmRST.cxx
cmRST.h
cmRuntimeDependencyArchive.cxx
cmRuntimeDependencyArchive.h
cmScriptGenerator.h
cmScriptGenerator.cxx
cmSourceFile.cxx

View File

@@ -0,0 +1,15 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmBinUtilsLinker.h"
#include "cmRuntimeDependencyArchive.h"
cmBinUtilsLinker::cmBinUtilsLinker(cmRuntimeDependencyArchive* archive)
: Archive(archive)
{
}
void cmBinUtilsLinker::SetError(const std::string& e)
{
this->Archive->SetError(e);
}

30
Source/cmBinUtilsLinker.h Normal file
View File

@@ -0,0 +1,30 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmBinUtilsLinker_h
#define cmBinUtilsLinker_h
#include "cmStateTypes.h"
#include <string>
class cmRuntimeDependencyArchive;
class cmBinUtilsLinker
{
public:
cmBinUtilsLinker(cmRuntimeDependencyArchive* archive);
virtual ~cmBinUtilsLinker() = default;
virtual bool Prepare() { return true; }
virtual bool ScanDependencies(std::string const& file,
cmStateEnums::TargetType type) = 0;
protected:
cmRuntimeDependencyArchive* Archive;
void SetError(const std::string& e);
};
#endif // cmBinUtilsLinker_h

View File

@@ -0,0 +1,18 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h"
#include "cmRuntimeDependencyArchive.h"
cmBinUtilsLinuxELFGetRuntimeDependenciesTool::
cmBinUtilsLinuxELFGetRuntimeDependenciesTool(
cmRuntimeDependencyArchive* archive)
: Archive(archive)
{
}
void cmBinUtilsLinuxELFGetRuntimeDependenciesTool::SetError(
const std::string& error)
{
this->Archive->SetError(error);
}

View File

@@ -0,0 +1,30 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmBinUtilsLinuxELFGetRuntimeDependenciesTool_h
#define cmBinUtilsLinuxELFGetRuntimeDependenciesTool_h
#include <string>
#include <vector>
class cmRuntimeDependencyArchive;
class cmBinUtilsLinuxELFGetRuntimeDependenciesTool
{
public:
cmBinUtilsLinuxELFGetRuntimeDependenciesTool(
cmRuntimeDependencyArchive* archive);
virtual ~cmBinUtilsLinuxELFGetRuntimeDependenciesTool() = default;
virtual bool GetFileInfo(std::string const& file,
std::vector<std::string>& needed,
std::vector<std::string>& rpaths,
std::vector<std::string>& runpaths) = 0;
protected:
cmRuntimeDependencyArchive* Archive;
void SetError(const std::string& e);
};
#endif // cmBinUtilsLinuxELFGetRuntimeDependenciesTool_h

View File

@@ -0,0 +1,177 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmBinUtilsLinuxELFLinker.h"
#include "cmAlgorithms.h"
#include "cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h"
#include "cmLDConfigLDConfigTool.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmRuntimeDependencyArchive.h"
#include "cmSystemTools.h"
#include <cmsys/RegularExpression.hxx>
#include <memory>
#include <sstream>
static std::string ReplaceOrigin(const std::string& rpath,
const std::string& origin)
{
static const cmsys::RegularExpression originRegex(
"(\\$ORIGIN)([^a-zA-Z0-9_]|$)");
static const cmsys::RegularExpression originCurlyRegex("\\${ORIGIN}");
cmsys::RegularExpressionMatch match;
if (originRegex.find(rpath.c_str(), match)) {
std::string begin = rpath.substr(0, match.start(1));
std::string end = rpath.substr(match.end(1));
return begin + origin + end;
}
if (originCurlyRegex.find(rpath.c_str(), match)) {
std::string begin = rpath.substr(0, match.start());
std::string end = rpath.substr(match.end());
return begin + origin + end;
}
return rpath;
}
cmBinUtilsLinuxELFLinker::cmBinUtilsLinuxELFLinker(
cmRuntimeDependencyArchive* archive)
: cmBinUtilsLinker(archive)
{
}
bool cmBinUtilsLinuxELFLinker::Prepare()
{
std::string tool = this->Archive->GetGetRuntimeDependenciesTool();
if (tool.empty()) {
tool = "objdump";
}
if (tool == "objdump") {
this->Tool =
cm::make_unique<cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool>(
this->Archive);
} else {
std::ostringstream e;
e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL: " << tool;
this->SetError(e.str());
return false;
}
std::string ldConfigTool =
this->Archive->GetMakefile()->GetSafeDefinition("CMAKE_LDCONFIG_TOOL");
if (ldConfigTool.empty()) {
ldConfigTool = "ldconfig";
}
if (ldConfigTool == "ldconfig") {
this->LDConfigTool =
cm::make_unique<cmLDConfigLDConfigTool>(this->Archive);
} else {
std::ostringstream e;
e << "Invalid value for CMAKE_LDCONFIG_TOOL: " << ldConfigTool;
this->SetError(e.str());
return false;
}
return true;
}
bool cmBinUtilsLinuxELFLinker::ScanDependencies(
std::string const& file, cmStateEnums::TargetType /* unused */)
{
std::vector<std::string> parentRpaths;
return this->ScanDependencies(file, parentRpaths);
}
bool cmBinUtilsLinuxELFLinker::ScanDependencies(
std::string const& file, std::vector<std::string> const& parentRpaths)
{
std::string origin = cmSystemTools::GetFilenamePath(file);
std::vector<std::string> needed;
std::vector<std::string> rpaths;
std::vector<std::string> runpaths;
if (!this->Tool->GetFileInfo(file, needed, rpaths, runpaths)) {
return false;
}
for (auto& runpath : runpaths) {
runpath = ReplaceOrigin(runpath, origin);
}
for (auto& rpath : rpaths) {
rpath = ReplaceOrigin(rpath, origin);
}
std::vector<std::string> searchPaths;
if (!runpaths.empty()) {
searchPaths = runpaths;
} else {
searchPaths = rpaths;
searchPaths.insert(searchPaths.end(), parentRpaths.begin(),
parentRpaths.end());
}
std::vector<std::string> ldConfigPaths;
if (!this->LDConfigTool->GetLDConfigPaths(ldConfigPaths)) {
return false;
}
searchPaths.insert(searchPaths.end(), ldConfigPaths.begin(),
ldConfigPaths.end());
for (auto const& dep : needed) {
if (!this->Archive->IsPreExcluded(dep)) {
std::string path;
bool resolved = false;
if (dep.find('/') != std::string::npos) {
this->SetError("Paths to dependencies are not supported");
return false;
}
if (!this->ResolveDependency(dep, searchPaths, path, resolved)) {
return false;
}
if (resolved) {
if (!this->Archive->IsPostExcluded(path)) {
bool unique;
this->Archive->AddResolvedPath(dep, path, unique);
if (unique && !this->ScanDependencies(path, rpaths)) {
return false;
}
}
} else {
this->Archive->AddUnresolvedPath(dep);
}
}
}
return true;
}
bool cmBinUtilsLinuxELFLinker::ResolveDependency(
std::string const& name, std::vector<std::string> const& searchPaths,
std::string& path, bool& resolved)
{
for (auto const& searchPath : searchPaths) {
path = searchPath + '/' + name;
if (cmSystemTools::PathExists(path)) {
resolved = true;
return true;
}
}
for (auto const& searchPath : this->Archive->GetSearchDirectories()) {
path = searchPath + '/' + name;
if (cmSystemTools::PathExists(path)) {
std::ostringstream warning;
warning << "Dependency " << name << " found in search directory:\n "
<< searchPath
<< "\nSee file(GET_RUNTIME_DEPENDENCIES) documentation for "
<< "more information.";
this->Archive->GetMakefile()->IssueMessage(MessageType::WARNING,
warning.str());
resolved = true;
return true;
}
}
resolved = false;
return true;
}

View File

@@ -0,0 +1,44 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmBinUtilsLinuxELFLinker_h
#define cmBinUtilsLinuxELFLinker_h
#include "cmBinUtilsLinker.h"
#include "cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h"
#include "cmLDConfigTool.h"
#include "cmStateTypes.h"
#include <memory> // IWYU pragma: keep
#include <string>
#include <vector>
class cmRuntimeDependencyArchive;
class cmBinUtilsLinuxELFLinker : public cmBinUtilsLinker
{
public:
cmBinUtilsLinuxELFLinker(cmRuntimeDependencyArchive* archive);
bool Prepare() override;
bool ScanDependencies(std::string const& file,
cmStateEnums::TargetType type) override;
private:
std::unique_ptr<cmBinUtilsLinuxELFGetRuntimeDependenciesTool> Tool;
std::unique_ptr<cmLDConfigTool> LDConfigTool;
bool HaveLDConfigPaths = false;
std::vector<std::string> LDConfigPaths;
bool ScanDependencies(std::string const& file,
std::vector<std::string> const& parentRpaths);
bool ResolveDependency(std::string const& name,
std::vector<std::string> const& searchPaths,
std::string& path, bool& resolved);
bool GetLDConfigPaths();
};
#endif // cmBinUtilsLinuxELFLinker_h

View File

@@ -0,0 +1,84 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h"
#include "cmRuntimeDependencyArchive.h"
#include "cmSystemTools.h"
#include "cmUVProcessChain.h"
#include <cmsys/RegularExpression.hxx>
#include <sstream>
cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool::
cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool(
cmRuntimeDependencyArchive* archive)
: cmBinUtilsLinuxELFGetRuntimeDependenciesTool(archive)
{
}
bool cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool::GetFileInfo(
std::string const& file, std::vector<std::string>& needed,
std::vector<std::string>& rpaths, std::vector<std::string>& runpaths)
{
cmUVProcessChainBuilder builder;
builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT);
std::vector<std::string> command;
if (!this->Archive->GetGetRuntimeDependenciesCommand("objdump", command)) {
this->SetError("Could not find objdump");
return false;
}
command.emplace_back("-p");
command.push_back(file);
builder.AddCommand(command);
auto process = builder.Start();
if (!process.Valid()) {
std::ostringstream e;
e << "Failed to start objdump process for:\n " << file;
this->SetError(e.str());
return false;
}
std::string line;
static const cmsys::RegularExpression neededRegex("^ *NEEDED *([^\n]*)$");
static const cmsys::RegularExpression rpathRegex("^ *RPATH *([^\n]*)$");
static const cmsys::RegularExpression runpathRegex("^ *RUNPATH *([^\n]*)$");
while (std::getline(*process.OutputStream(), line)) {
cmsys::RegularExpressionMatch match;
if (neededRegex.find(line.c_str(), match)) {
needed.push_back(match.match(1));
} else if (rpathRegex.find(line.c_str(), match)) {
std::vector<std::string> rpathSplit =
cmSystemTools::SplitString(match.match(1), ':');
rpaths.reserve(rpaths.size() + rpathSplit.size());
for (auto const& rpath : rpathSplit) {
rpaths.push_back(rpath);
}
} else if (runpathRegex.find(line.c_str(), match)) {
std::vector<std::string> runpathSplit =
cmSystemTools::SplitString(match.match(1), ':');
runpaths.reserve(runpaths.size() + runpathSplit.size());
for (auto const& runpath : runpathSplit) {
runpaths.push_back(runpath);
}
}
}
if (!process.Wait()) {
std::ostringstream e;
e << "Failed to wait on objdump process for:\n " << file;
this->SetError(e.str());
return false;
}
auto status = process.GetStatus();
if (!status[0] || status[0]->ExitStatus != 0) {
std::ostringstream e;
e << "Failed to run objdump on:\n " << file;
this->SetError(e.str());
return false;
}
return true;
}

View File

@@ -0,0 +1,26 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmBinUtilsLinuxELFGetRuntimeCollectDependenciesTool_h
#define cmBinUtilsLinuxELFGetRuntimeCollectDependenciesTool_h
#include "cmBinUtilsLinuxELFGetRuntimeDependenciesTool.h"
#include <string>
#include <vector>
class cmRuntimeDependencyArchive;
class cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool
: public cmBinUtilsLinuxELFGetRuntimeDependenciesTool
{
public:
cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool(
cmRuntimeDependencyArchive* archive);
bool GetFileInfo(std::string const& file, std::vector<std::string>& needed,
std::vector<std::string>& rpaths,
std::vector<std::string>& runpaths) override;
};
#endif // cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool_h

View File

@@ -0,0 +1,19 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h"
#include "cmRuntimeDependencyArchive.h"
cmBinUtilsMacOSMachOGetRuntimeDependenciesTool::
cmBinUtilsMacOSMachOGetRuntimeDependenciesTool(
cmRuntimeDependencyArchive* archive)
: Archive(archive)
{
}
void cmBinUtilsMacOSMachOGetRuntimeDependenciesTool::SetError(
const std::string& error)
{
this->Archive->SetError(error);
}

View File

@@ -0,0 +1,29 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmBinUtilsMacOSMachOGetRuntimeDependenciesTool_h
#define cmBinUtilsMacOSMachOGetRuntimeDependenciesTool_h
#include <string>
#include <vector>
class cmRuntimeDependencyArchive;
class cmBinUtilsMacOSMachOGetRuntimeDependenciesTool
{
public:
cmBinUtilsMacOSMachOGetRuntimeDependenciesTool(
cmRuntimeDependencyArchive* archive);
virtual ~cmBinUtilsMacOSMachOGetRuntimeDependenciesTool() = default;
virtual bool GetFileInfo(std::string const& file,
std::vector<std::string>& libs,
std::vector<std::string>& rpaths) = 0;
protected:
cmRuntimeDependencyArchive* Archive;
void SetError(const std::string& error);
};
#endif // cmBinUtilsMacOSMachOGetRuntimeDependenciesTool_h

View File

@@ -0,0 +1,228 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmBinUtilsMacOSMachOLinker.h"
#include "cmAlgorithms.h"
#include "cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.h"
#include "cmRuntimeDependencyArchive.h"
#include "cmSystemTools.h"
#include <sstream>
#include <string>
#include <vector>
cmBinUtilsMacOSMachOLinker::cmBinUtilsMacOSMachOLinker(
cmRuntimeDependencyArchive* archive)
: cmBinUtilsLinker(archive)
{
}
bool cmBinUtilsMacOSMachOLinker::Prepare()
{
std::string tool = this->Archive->GetGetRuntimeDependenciesTool();
if (tool.empty()) {
tool = "otool";
}
if (tool == "otool") {
this->Tool =
cm::make_unique<cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool>(
this->Archive);
} else {
std::ostringstream e;
e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL: " << tool;
this->SetError(e.str());
return false;
}
return true;
}
bool cmBinUtilsMacOSMachOLinker::ScanDependencies(
std::string const& file, cmStateEnums::TargetType type)
{
std::string executableFile;
if (type == cmStateEnums::EXECUTABLE) {
executableFile = file;
} else {
executableFile = this->Archive->GetBundleExecutable();
}
std::string executablePath;
if (!executableFile.empty()) {
executablePath = cmSystemTools::GetFilenamePath(executableFile);
}
return this->ScanDependencies(file, executablePath);
}
bool cmBinUtilsMacOSMachOLinker::ScanDependencies(
std::string const& file, std::string const& executablePath)
{
std::vector<std::string> libs, rpaths;
if (!this->Tool->GetFileInfo(file, libs, rpaths)) {
return false;
}
std::string loaderPath = cmSystemTools::GetFilenamePath(file);
return this->GetFileDependencies(libs, executablePath, loaderPath, rpaths);
}
bool cmBinUtilsMacOSMachOLinker::GetFileDependencies(
std::vector<std::string> const& names, std::string const& executablePath,
std::string const& loaderPath, std::vector<std::string> const& rpaths)
{
for (std::string const& name : names) {
if (!this->Archive->IsPreExcluded(name)) {
std::string path;
bool resolved;
if (!this->ResolveDependency(name, executablePath, loaderPath, rpaths,
path, resolved)) {
return false;
}
if (resolved) {
if (!this->Archive->IsPostExcluded(path)) {
auto filename = cmSystemTools::GetFilenameName(path);
bool unique;
this->Archive->AddResolvedPath(filename, path, unique);
if (unique && !this->ScanDependencies(path, executablePath)) {
return false;
}
}
} else {
this->Archive->AddUnresolvedPath(name);
}
}
}
return true;
}
bool cmBinUtilsMacOSMachOLinker::ResolveDependency(
std::string const& name, std::string const& executablePath,
std::string const& loaderPath, std::vector<std::string> const& rpaths,
std::string& path, bool& resolved)
{
resolved = false;
if (cmHasLiteralPrefix(name, "@rpath/")) {
if (!this->ResolveRPathDependency(name, executablePath, loaderPath, rpaths,
path, resolved)) {
return false;
}
} else if (cmHasLiteralPrefix(name, "@loader_path/")) {
if (!this->ResolveLoaderPathDependency(name, loaderPath, path, resolved)) {
return false;
}
} else if (cmHasLiteralPrefix(name, "@executable_path/")) {
if (!this->ResolveExecutablePathDependency(name, executablePath, path,
resolved)) {
return false;
}
} else {
resolved = true;
path = name;
}
if (resolved && !cmSystemTools::FileIsFullPath(path)) {
this->SetError("Resolved path is not absolute");
return false;
}
return true;
}
bool cmBinUtilsMacOSMachOLinker::ResolveExecutablePathDependency(
std::string const& name, std::string const& executablePath,
std::string& path, bool& resolved)
{
if (executablePath.empty()) {
resolved = false;
return true;
}
// 16 is == "@executable_path".length()
path = name;
path.replace(0, 16, executablePath);
if (!cmSystemTools::PathExists(path)) {
resolved = false;
return true;
}
resolved = true;
return true;
}
bool cmBinUtilsMacOSMachOLinker::ResolveLoaderPathDependency(
std::string const& name, std::string const& loaderPath, std::string& path,
bool& resolved)
{
if (loaderPath.empty()) {
resolved = false;
return true;
}
// 12 is "@loader_path".length();
path = name;
path.replace(0, 12, loaderPath);
if (!cmSystemTools::PathExists(path)) {
resolved = false;
return true;
}
resolved = true;
return true;
}
bool cmBinUtilsMacOSMachOLinker::ResolveRPathDependency(
std::string const& name, std::string const& executablePath,
std::string const& loaderPath, std::vector<std::string> const& rpaths,
std::string& path, bool& resolved)
{
for (std::string const& rpath : rpaths) {
std::string searchFile = name;
searchFile.replace(0, 6, rpath);
if (cmHasLiteralPrefix(searchFile, "@loader_path/")) {
if (!this->ResolveLoaderPathDependency(searchFile, loaderPath, path,
resolved)) {
return false;
}
if (resolved) {
return true;
}
} else if (cmHasLiteralPrefix(searchFile, "@executable_path/")) {
if (!this->ResolveExecutablePathDependency(searchFile, executablePath,
path, resolved)) {
return false;
}
if (resolved) {
return true;
}
} else if (cmSystemTools::PathExists(searchFile)) {
/*
* paraphrasing @ben.boeckel:
* if /b/libB.dylib is supposed to be used,
* /a/libbB.dylib will be found first if it exists. CMake tries to
* sort rpath directories to avoid this, but sometimes there is no
* right answer.
*
* I believe it is possible to resolve this using otools -l
* then checking the LC_LOAD_DYLIB command whose name is
* equal to the value of search_file, UNLESS the build
* specifically sets the RPath to paths that will match
* duplicate libs; at this point can we just point to
* user error, or is there a reason why the advantages
* to this scenario outweigh its disadvantages?
*
* Also priority seems to be the order as passed in when compiled
* so as long as this method's resolution guarantees priority
* in that manner further checking should not be necessary?
*/
path = searchFile;
resolved = true;
return true;
}
}
resolved = false;
return true;
}

View File

@@ -0,0 +1,59 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmBinUtilsMacOSMachOLinker_h
#define cmBinUtilsMacOSMachOLinker_h
#include "cmBinUtilsLinker.h"
#include "cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h"
#include "cmStateTypes.h"
#include <memory> // IWYU pragma: keep
#include <string>
#include <vector>
class cmRuntimeDependencyArchive;
class cmBinUtilsMacOSMachOLinker : public cmBinUtilsLinker
{
public:
cmBinUtilsMacOSMachOLinker(cmRuntimeDependencyArchive* archive);
bool Prepare() override;
bool ScanDependencies(std::string const& file,
cmStateEnums::TargetType type) override;
private:
std::unique_ptr<cmBinUtilsMacOSMachOGetRuntimeDependenciesTool> Tool;
bool ScanDependencies(std::string const& file,
std::string const& executablePath);
bool GetFileDependencies(std::vector<std::string> const& names,
std::string const& executablePath,
std::string const& loaderPath,
std::vector<std::string> const& rpaths);
bool ResolveDependency(std::string const& name,
std::string const& executablePath,
std::string const& loaderPath,
std::vector<std::string> const& rpaths,
std::string& path, bool& resolved);
bool ResolveExecutablePathDependency(std::string const& name,
std::string const& executablePath,
std::string& path, bool& resolved);
bool ResolveLoaderPathDependency(std::string const& name,
std::string const& loaderPath,
std::string& path, bool& resolved);
bool ResolveRPathDependency(std::string const& name,
std::string const& executablePath,
std::string const& loaderPath,
std::vector<std::string> const& rpaths,
std::string& path, bool& resolved);
};
#endif // cmBinUtilsMacOSMachOLinker_h

View File

@@ -0,0 +1,100 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.h"
#include "cmRuntimeDependencyArchive.h"
#include "cmUVProcessChain.h"
#include <cmsys/RegularExpression.hxx>
#include <sstream>
cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool::
cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool(
cmRuntimeDependencyArchive* archive)
: cmBinUtilsMacOSMachOGetRuntimeDependenciesTool(archive)
{
}
bool cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool::GetFileInfo(
std::string const& file, std::vector<std::string>& libs,
std::vector<std::string>& rpaths)
{
std::vector<std::string> command;
if (!this->Archive->GetGetRuntimeDependenciesCommand("otool", command)) {
this->SetError("Could not find otool");
return false;
}
command.emplace_back("-l");
command.emplace_back(file);
cmUVProcessChainBuilder builder;
builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
.AddCommand(command);
auto process = builder.Start();
if (!process.Valid()) {
std::ostringstream e;
e << "Failed to start otool process for:\n " << file;
this->SetError(e.str());
return false;
}
std::string line;
static const cmsys::RegularExpression rpathRegex("^ *cmd LC_RPATH$");
static const cmsys::RegularExpression loadDylibRegex(
"^ *cmd LC_LOAD_DYLIB$");
static const cmsys::RegularExpression pathRegex(
"^ *path (.*) \\(offset [0-9]+\\)$");
static const cmsys::RegularExpression nameRegex(
"^ *name (.*) \\(offset [0-9]+\\)$");
while (std::getline(*process.OutputStream(), line)) {
cmsys::RegularExpressionMatch cmdMatch;
if (rpathRegex.find(line.c_str(), cmdMatch)) {
if (!std::getline(*process.OutputStream(), line) ||
!std::getline(*process.OutputStream(), line)) {
this->SetError("Invalid output from otool");
return false;
}
cmsys::RegularExpressionMatch pathMatch;
if (pathRegex.find(line.c_str(), pathMatch)) {
rpaths.push_back(pathMatch.match(1));
} else {
this->SetError("Invalid output from otool");
return false;
}
} else if (loadDylibRegex.find(line.c_str(), cmdMatch)) {
if (!std::getline(*process.OutputStream(), line) ||
!std::getline(*process.OutputStream(), line)) {
this->SetError("Invalid output from otool");
return false;
}
cmsys::RegularExpressionMatch nameMatch;
if (nameRegex.find(line.c_str(), nameMatch)) {
libs.push_back(nameMatch.match(1));
} else {
this->SetError("Invalid output from otool");
return false;
}
}
}
if (!process.Wait()) {
std::ostringstream e;
e << "Failed to wait on otool process for:\n " << file;
this->SetError(e.str());
return false;
}
auto status = process.GetStatus();
if (!status[0] || status[0]->ExitStatus != 0) {
std::ostringstream e;
e << "Failed to run otool on:\n " << file;
this->SetError(e.str());
return false;
}
return true;
}

View File

@@ -0,0 +1,25 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool_h
#define cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool_h
#include "cmBinUtilsMacOSMachOGetRuntimeDependenciesTool.h"
#include <string>
#include <vector>
class cmRuntimeDependencyArchive;
class cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool
: public cmBinUtilsMacOSMachOGetRuntimeDependenciesTool
{
public:
cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool(
cmRuntimeDependencyArchive* archive);
bool GetFileInfo(std::string const& file, std::vector<std::string>& libs,
std::vector<std::string>& rpaths) override;
};
#endif // cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool_h

View File

@@ -0,0 +1,67 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h"
#include "cmRuntimeDependencyArchive.h"
#include "cmUVProcessChain.h"
#include <cmsys/RegularExpression.hxx>
#include <sstream>
cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool::
cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool(
cmRuntimeDependencyArchive* archive)
: cmBinUtilsWindowsPEGetRuntimeDependenciesTool(archive)
{
}
bool cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool::GetFileInfo(
const std::string& file, std::vector<std::string>& needed)
{
cmUVProcessChainBuilder builder;
builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT);
std::vector<std::string> command;
if (!this->Archive->GetGetRuntimeDependenciesCommand("dumpbin", command)) {
this->SetError("Could not find dumpbin");
return false;
}
command.emplace_back("/dependents");
command.push_back(file);
builder.AddCommand(command);
auto process = builder.Start();
if (!process.Valid()) {
std::ostringstream e;
e << "Failed to start dumpbin process for:\n " << file;
this->SetError(e.str());
return false;
}
std::string line;
static const cmsys::RegularExpression regex(
"^ ([^\n]*\\.[Dd][Ll][Ll])\r$");
while (std::getline(*process.OutputStream(), line)) {
cmsys::RegularExpressionMatch match;
if (regex.find(line.c_str(), match)) {
needed.push_back(match.match(1));
}
}
if (!process.Wait()) {
std::ostringstream e;
e << "Failed to wait on dumpbin process for:\n " << file;
this->SetError(e.str());
return false;
}
auto status = process.GetStatus();
if (!status[0] || status[0]->ExitStatus != 0) {
std::ostringstream e;
e << "Failed to run dumpbin on:\n " << file;
this->SetError(e.str());
return false;
}
return true;
}

View File

@@ -0,0 +1,25 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool_h
#define cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool_h
#include "cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h"
#include <string>
#include <vector>
class cmRuntimeDependencyArchive;
class cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool
: public cmBinUtilsWindowsPEGetRuntimeDependenciesTool
{
public:
cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool(
cmRuntimeDependencyArchive* archive);
bool GetFileInfo(const std::string& file,
std::vector<std::string>& needed) override;
};
#endif // cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool_h

View File

@@ -0,0 +1,18 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h"
#include "cmRuntimeDependencyArchive.h"
cmBinUtilsWindowsPEGetRuntimeDependenciesTool::
cmBinUtilsWindowsPEGetRuntimeDependenciesTool(
cmRuntimeDependencyArchive* archive)
: Archive(archive)
{
}
void cmBinUtilsWindowsPEGetRuntimeDependenciesTool::SetError(
const std::string& error)
{
this->Archive->SetError(error);
}

View File

@@ -0,0 +1,28 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmBinUtilsWindowsPEGetRuntimeDependenciesTool_h
#define cmBinUtilsWindowsPEGetRuntimeDependenciesTool_h
#include <string>
#include <vector>
class cmRuntimeDependencyArchive;
class cmBinUtilsWindowsPEGetRuntimeDependenciesTool
{
public:
cmBinUtilsWindowsPEGetRuntimeDependenciesTool(
cmRuntimeDependencyArchive* archive);
virtual ~cmBinUtilsWindowsPEGetRuntimeDependenciesTool() = default;
virtual bool GetFileInfo(const std::string& file,
std::vector<std::string>& needed) = 0;
protected:
cmRuntimeDependencyArchive* Archive;
void SetError(const std::string& error);
};
#endif // cmBinUtilsWindowsPEGetRuntimeDependenciesTool_h

View File

@@ -0,0 +1,121 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmBinUtilsWindowsPELinker.h"
#include "cmAlgorithms.h"
#include "cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h"
#include "cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h"
#include "cmRuntimeDependencyArchive.h"
#include "cmSystemTools.h"
#include <memory>
#include <sstream>
#include <vector>
#ifdef _WIN32
# include <windows.h>
#endif
cmBinUtilsWindowsPELinker::cmBinUtilsWindowsPELinker(
cmRuntimeDependencyArchive* archive)
: cmBinUtilsLinker(archive)
{
}
bool cmBinUtilsWindowsPELinker::Prepare()
{
std::string tool = this->Archive->GetGetRuntimeDependenciesTool();
if (tool.empty()) {
std::vector<std::string> command;
if (this->Archive->GetGetRuntimeDependenciesCommand("dumpbin", command)) {
tool = "dumpbin";
} else {
tool = "objdump";
}
}
if (tool == "dumpbin") {
this->Tool =
cm::make_unique<cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool>(
this->Archive);
} else if (tool == "objdump") {
this->Tool =
cm::make_unique<cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool>(
this->Archive);
} else {
std::ostringstream e;
e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL: " << tool;
this->SetError(e.str());
return false;
}
return true;
}
bool cmBinUtilsWindowsPELinker::ScanDependencies(
std::string const& file, cmStateEnums::TargetType /* unused */)
{
std::vector<std::string> needed;
if (!this->Tool->GetFileInfo(file, needed)) {
return false;
}
for (auto& n : needed) {
n = cmSystemTools::LowerCase(n);
}
std::string origin = cmSystemTools::GetFilenamePath(file);
for (auto const& lib : needed) {
if (!this->Archive->IsPreExcluded(lib)) {
std::string path;
bool resolved = false;
if (!this->ResolveDependency(lib, origin, path, resolved)) {
return false;
}
if (resolved) {
if (!this->Archive->IsPostExcluded(path)) {
bool unique;
this->Archive->AddResolvedPath(lib, path, unique);
if (unique &&
!this->ScanDependencies(path, cmStateEnums::SHARED_LIBRARY)) {
return false;
}
}
} else {
this->Archive->AddUnresolvedPath(lib);
}
}
}
return true;
}
bool cmBinUtilsWindowsPELinker::ResolveDependency(std::string const& name,
std::string const& origin,
std::string& path,
bool& resolved)
{
auto dirs = this->Archive->GetSearchDirectories();
#ifdef _WIN32
char buf[MAX_PATH];
unsigned int len;
if ((len = GetWindowsDirectoryA(buf, MAX_PATH)) > 0) {
dirs.insert(dirs.begin(), std::string(buf, len));
}
if ((len = GetSystemDirectoryA(buf, MAX_PATH)) > 0) {
dirs.insert(dirs.begin(), std::string(buf, len));
}
#endif
dirs.insert(dirs.begin(), origin);
for (auto const& searchPath : dirs) {
path = searchPath + '/' + name;
if (cmSystemTools::PathExists(path)) {
resolved = true;
return true;
}
}
resolved = false;
return true;
}

View File

@@ -0,0 +1,33 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmBinUtilsWindowsPELinker_h
#define cmBinUtilsWindowsPELinker_h
#include "cmBinUtilsLinker.h"
#include "cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h"
#include "cmStateTypes.h"
#include <memory> // IWYU pragma: keep
#include <string>
class cmRuntimeDependencyArchive;
class cmBinUtilsWindowsPELinker : public cmBinUtilsLinker
{
public:
cmBinUtilsWindowsPELinker(cmRuntimeDependencyArchive* archive);
bool Prepare() override;
bool ScanDependencies(std::string const& file,
cmStateEnums::TargetType type) override;
private:
std::unique_ptr<cmBinUtilsWindowsPEGetRuntimeDependenciesTool> Tool;
bool ResolveDependency(std::string const& name, std::string const& origin,
std::string& path, bool& resolved);
};
#endif // cmBinUtilsWindowsPELinker_h

View File

@@ -0,0 +1,67 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h"
#include "cmRuntimeDependencyArchive.h"
#include "cmUVProcessChain.h"
#include <cmsys/RegularExpression.hxx>
#include <sstream>
cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool::
cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool(
cmRuntimeDependencyArchive* archive)
: cmBinUtilsWindowsPEGetRuntimeDependenciesTool(archive)
{
}
bool cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool::GetFileInfo(
const std::string& file, std::vector<std::string>& needed)
{
cmUVProcessChainBuilder builder;
builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT);
std::vector<std::string> command;
if (!this->Archive->GetGetRuntimeDependenciesCommand("objdump", command)) {
this->SetError("Could not find objdump");
return false;
}
command.emplace_back("-p");
command.push_back(file);
builder.AddCommand(command);
auto process = builder.Start();
if (!process.Valid()) {
std::ostringstream e;
e << "Failed to start objdump process for:\n " << file;
this->SetError(e.str());
return false;
}
std::string line;
static const cmsys::RegularExpression regex(
"^\t*DLL Name: ([^\n]*\\.[Dd][Ll][Ll])\r$");
while (std::getline(*process.OutputStream(), line)) {
cmsys::RegularExpressionMatch match;
if (regex.find(line.c_str(), match)) {
needed.push_back(match.match(1));
}
}
if (!process.Wait()) {
std::ostringstream e;
e << "Failed to wait on objdump process for:\n " << file;
this->SetError(e.str());
return false;
}
auto status = process.GetStatus();
if (!status[0] || status[0]->ExitStatus != 0) {
std::ostringstream e;
e << "Failed to run objdump on:\n " << file;
this->SetError(e.str());
return false;
}
return true;
}

View File

@@ -0,0 +1,25 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool_h
#define cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool_h
#include "cmBinUtilsWindowsPEGetRuntimeDependenciesTool.h"
#include <string>
#include <vector>
class cmRuntimeDependencyArchive;
class cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool
: public cmBinUtilsWindowsPEGetRuntimeDependenciesTool
{
public:
cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool(
cmRuntimeDependencyArchive* archive);
bool GetFileInfo(const std::string& file,
std::vector<std::string>& needed) override;
};
#endif // cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool_h

View File

@@ -12,7 +12,9 @@
#include <assert.h>
#include <cmath>
#include <ctype.h>
#include <map>
#include <memory> // IWYU pragma: keep
#include <set>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
@@ -34,6 +36,8 @@
#include "cmMessageType.h"
#include "cmPolicies.h"
#include "cmRange.h"
#include "cmRuntimeDependencyArchive.h"
#include "cmState.h"
#include "cmSystemTools.h"
#include "cmTimestamp.h"
#include "cm_sys_stat.h"
@@ -184,6 +188,9 @@ bool cmFileCommand::InitialPass(std::vector<std::string> const& args,
if (subCommand == "CREATE_LINK") {
return this->HandleCreateLinkCommand(args);
}
if (subCommand == "GET_RUNTIME_DEPENDENCIES") {
return this->HandleGetRuntimeDependenciesCommand(args);
}
std::string e = "does not recognize sub-command " + subCommand;
this->SetError(e);
@@ -2690,3 +2697,171 @@ bool cmFileCommand::HandleCreateLinkCommand(
return true;
}
bool cmFileCommand::HandleGetRuntimeDependenciesCommand(
std::vector<std::string> const& args)
{
static const std::set<std::string> supportedPlatforms = { "Windows", "Linux",
"Darwin" };
std::string platform =
this->Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
if (!supportedPlatforms.count(platform)) {
std::ostringstream e;
e << "GET_RUNTIME_DEPENDENCIES is not supported on system \"" << platform
<< "\"";
this->SetError(e.str());
cmSystemTools::SetFatalErrorOccured();
return false;
}
if (this->Makefile->GetState()->GetMode() == cmState::Project) {
this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING,
"You have used file(GET_RUNTIME_DEPENDENCIES)"
" in project mode. This is probably not what "
"you intended to do. Instead, please consider"
" using it in an install(CODE) or "
"install(SCRIPT) command. For example:"
"\n install(CODE [["
"\n file(GET_RUNTIME_DEPENDENCIES"
"\n # ..."
"\n )"
"\n ]])");
}
struct Arguments
{
std::string ResolvedDependenciesVar;
std::string UnresolvedDependenciesVar;
std::string ConflictingDependenciesPrefix;
std::string BundleExecutable;
std::vector<std::string> Executables;
std::vector<std::string> Libraries;
std::vector<std::string> Directories;
std::vector<std::string> Modules;
std::vector<std::string> PreIncludeRegexes;
std::vector<std::string> PreExcludeRegexes;
std::vector<std::string> PostIncludeRegexes;
std::vector<std::string> PostExcludeRegexes;
};
static auto const parser =
cmArgumentParser<Arguments>{}
.Bind("RESOLVED_DEPENDENCIES_VAR"_s, &Arguments::ResolvedDependenciesVar)
.Bind("UNRESOLVED_DEPENDENCIES_VAR"_s,
&Arguments::UnresolvedDependenciesVar)
.Bind("CONFLICTING_DEPENDENCIES_PREFIX"_s,
&Arguments::ConflictingDependenciesPrefix)
.Bind("BUNDLE_EXECUTABLE"_s, &Arguments::BundleExecutable)
.Bind("EXECUTABLES"_s, &Arguments::Executables)
.Bind("LIBRARIES"_s, &Arguments::Libraries)
.Bind("MODULES"_s, &Arguments::Modules)
.Bind("DIRECTORIES"_s, &Arguments::Directories)
.Bind("PRE_INCLUDE_REGEXES"_s, &Arguments::PreIncludeRegexes)
.Bind("PRE_EXCLUDE_REGEXES"_s, &Arguments::PreExcludeRegexes)
.Bind("POST_INCLUDE_REGEXES"_s, &Arguments::PostIncludeRegexes)
.Bind("POST_EXCLUDE_REGEXES"_s, &Arguments::PostExcludeRegexes);
std::vector<std::string> unrecognizedArguments;
std::vector<std::string> keywordsMissingValues;
auto parsedArgs =
parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
&keywordsMissingValues);
auto argIt = unrecognizedArguments.begin();
if (argIt != unrecognizedArguments.end()) {
std::ostringstream e;
e << "Unrecognized argument: \"" << *argIt << "\"";
this->SetError(e.str());
cmSystemTools::SetFatalErrorOccured();
return false;
}
argIt = keywordsMissingValues.begin();
if (argIt != keywordsMissingValues.end()) {
std::ostringstream e;
e << "Keyword missing value: " << *argIt;
this->SetError(e.str());
cmSystemTools::SetFatalErrorOccured();
return false;
}
cmRuntimeDependencyArchive archive(
this, parsedArgs.Directories, parsedArgs.BundleExecutable,
parsedArgs.PreIncludeRegexes, parsedArgs.PreExcludeRegexes,
parsedArgs.PostIncludeRegexes, parsedArgs.PostExcludeRegexes);
if (!archive.Prepare()) {
cmSystemTools::SetFatalErrorOccured();
return false;
}
if (!archive.GetRuntimeDependencies(
parsedArgs.Executables, parsedArgs.Libraries, parsedArgs.Modules)) {
cmSystemTools::SetFatalErrorOccured();
return false;
}
std::vector<std::string> deps, unresolvedDeps, conflictingDeps;
for (auto const& val : archive.GetResolvedPaths()) {
bool unique = true;
auto it = val.second.begin();
assert(it != val.second.end());
auto const& firstPath = *it;
while (++it != val.second.end()) {
if (!cmSystemTools::SameFile(firstPath, *it)) {
unique = false;
break;
}
}
if (unique) {
deps.push_back(firstPath);
} else if (!parsedArgs.ConflictingDependenciesPrefix.empty()) {
conflictingDeps.push_back(val.first);
std::vector<std::string> paths;
paths.insert(paths.begin(), val.second.begin(), val.second.end());
std::string varName =
parsedArgs.ConflictingDependenciesPrefix + "_" + val.first;
std::string pathsStr = cmJoin(paths, ";");
this->Makefile->AddDefinition(varName, pathsStr.c_str());
} else {
std::ostringstream e;
e << "Multiple conflicting paths found for " << val.first << ":";
for (auto const& path : val.second) {
e << "\n " << path;
}
this->SetError(e.str());
cmSystemTools::SetFatalErrorOccured();
return false;
}
}
if (!archive.GetUnresolvedPaths().empty()) {
if (!parsedArgs.UnresolvedDependenciesVar.empty()) {
unresolvedDeps.insert(unresolvedDeps.begin(),
archive.GetUnresolvedPaths().begin(),
archive.GetUnresolvedPaths().end());
} else {
auto it = archive.GetUnresolvedPaths().begin();
assert(it != archive.GetUnresolvedPaths().end());
std::ostringstream e;
e << "Could not resolve file " << *it;
this->SetError(e.str());
cmSystemTools::SetFatalErrorOccured();
return false;
}
}
if (!parsedArgs.ResolvedDependenciesVar.empty()) {
std::string val = cmJoin(deps, ";");
this->Makefile->AddDefinition(parsedArgs.ResolvedDependenciesVar,
val.c_str());
}
if (!parsedArgs.UnresolvedDependenciesVar.empty()) {
std::string val = cmJoin(unresolvedDeps, ";");
this->Makefile->AddDefinition(parsedArgs.UnresolvedDependenciesVar,
val.c_str());
}
if (!parsedArgs.ConflictingDependenciesPrefix.empty()) {
std::string val = cmJoin(conflictingDeps, ";");
this->Makefile->AddDefinition(
parsedArgs.ConflictingDependenciesPrefix + "_FILENAMES", val.c_str());
}
return true;
}

View File

@@ -62,6 +62,8 @@ protected:
bool HandleSizeCommand(std::vector<std::string> const& args);
bool HandleReadSymlinkCommand(std::vector<std::string> const& args);
bool HandleCreateLinkCommand(std::vector<std::string> const& args);
bool HandleGetRuntimeDependenciesCommand(
std::vector<std::string> const& args);
private:
void AddEvaluationFile(const std::string& inputName,

View File

@@ -0,0 +1,70 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmLDConfigLDConfigTool.h"
#include "cmMakefile.h"
#include "cmRuntimeDependencyArchive.h"
#include "cmSystemTools.h"
#include "cmUVProcessChain.h"
#include "cmsys/RegularExpression.hxx"
#include <istream>
#include <string>
#include <vector>
cmLDConfigLDConfigTool::cmLDConfigLDConfigTool(
cmRuntimeDependencyArchive* archive)
: cmLDConfigTool(archive)
{
}
bool cmLDConfigLDConfigTool::GetLDConfigPaths(std::vector<std::string>& paths)
{
std::string ldConfigPath =
this->Archive->GetMakefile()->GetSafeDefinition("CMAKE_LDCONFIG_COMMAND");
if (ldConfigPath.empty()) {
ldConfigPath = cmSystemTools::FindProgram(
"ldconfig", { "/sbin", "/usr/sbin", "/usr/local/sbin" });
if (ldConfigPath.empty()) {
this->Archive->SetError("Could not find ldconfig");
return false;
}
}
std::vector<std::string> ldConfigCommand;
cmSystemTools::ExpandListArgument(ldConfigPath, ldConfigCommand);
ldConfigCommand.emplace_back("-v");
ldConfigCommand.emplace_back("-N"); // Don't rebuild the cache.
ldConfigCommand.emplace_back("-X"); // Don't update links.
cmUVProcessChainBuilder builder;
builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
.AddCommand(ldConfigCommand);
auto process = builder.Start();
if (!process.Valid()) {
this->Archive->SetError("Failed to start ldconfig process");
return false;
}
std::string line;
static const cmsys::RegularExpression regex("^([^\t:]*):");
while (std::getline(*process.OutputStream(), line)) {
cmsys::RegularExpressionMatch match;
if (regex.find(line.c_str(), match)) {
paths.push_back(match.match(1));
}
}
if (!process.Wait()) {
this->Archive->SetError("Failed to wait on ldconfig process");
return false;
}
auto status = process.GetStatus();
if (!status[0] || status[0]->ExitStatus != 0) {
this->Archive->SetError("Failed to run ldconfig");
return false;
}
return true;
}

View File

@@ -0,0 +1,22 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmLDConfigLDConfigTool_h
#define cmLDConfigLDConfigTool_h
#include "cmLDConfigTool.h"
#include <string>
#include <vector>
class cmRuntimeDependencyArchive;
class cmLDConfigLDConfigTool : public cmLDConfigTool
{
public:
cmLDConfigLDConfigTool(cmRuntimeDependencyArchive* archive);
bool GetLDConfigPaths(std::vector<std::string>& paths) override;
};
#endif

View File

@@ -0,0 +1,9 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmLDConfigTool.h"
cmLDConfigTool::cmLDConfigTool(cmRuntimeDependencyArchive* archive)
: Archive(archive)
{
}

24
Source/cmLDConfigTool.h Normal file
View File

@@ -0,0 +1,24 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmLDConfigTool_h
#define cmLDConfigTool_h
#include <string>
#include <vector>
class cmRuntimeDependencyArchive;
class cmLDConfigTool
{
public:
cmLDConfigTool(cmRuntimeDependencyArchive* archive);
virtual ~cmLDConfigTool() = default;
virtual bool GetLDConfigPaths(std::vector<std::string>& paths) = 0;
protected:
cmRuntimeDependencyArchive* Archive;
};
#endif

View File

@@ -0,0 +1,378 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmRuntimeDependencyArchive.h"
#include "cmAlgorithms.h"
#include "cmBinUtilsLinuxELFLinker.h"
#include "cmBinUtilsMacOSMachOLinker.h"
#include "cmBinUtilsWindowsPELinker.h"
#include "cmCommand.h"
#include "cmMakefile.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
#if defined(_WIN32)
# include "cmGlobalGenerator.h"
# ifdef CMAKE_BUILD_WITH_CMAKE
# include "cmGlobalVisualStudioVersionedGenerator.h"
# endif
# include "cmVSSetupHelper.h"
# include "cmsys/Glob.hxx"
#endif
#include <algorithm>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#if defined(_WIN32)
static void AddVisualStudioPath(std::vector<std::string>& paths,
const std::string& prefix,
unsigned int version, cmGlobalGenerator* gg)
{
// If generating for the VS IDE, use the same instance.
std::string vsloc;
bool found = false;
# ifdef CMAKE_BUILD_WITH_CMAKE
if (gg->GetName().find(prefix) == 0) {
cmGlobalVisualStudioVersionedGenerator* vsgen =
static_cast<cmGlobalVisualStudioVersionedGenerator*>(gg);
if (vsgen->GetVSInstance(vsloc)) {
found = true;
}
}
# endif
// Otherwise, find a VS instance ourselves.
if (!found) {
cmVSSetupAPIHelper vsSetupAPIHelper(version);
if (vsSetupAPIHelper.GetVSInstanceInfo(vsloc)) {
cmSystemTools::ConvertToUnixSlashes(vsloc);
found = true;
}
}
if (found) {
cmsys::Glob glob;
glob.SetListDirs(true);
glob.FindFiles(vsloc + "/VC/Tools/MSVC/*");
for (auto const& vcdir : glob.GetFiles()) {
paths.push_back(vcdir + "/bin/Hostx64/x64");
paths.push_back(vcdir + "/bin/Hostx86/x64");
paths.push_back(vcdir + "/bin/Hostx64/x86");
paths.push_back(vcdir + "/bin/Hostx86/x86");
}
}
}
static void AddRegistryPath(std::vector<std::string>& paths,
const std::string& path, cmMakefile* mf)
{
// We should view the registry as the target application would view
// it.
cmSystemTools::KeyWOW64 view = cmSystemTools::KeyWOW64_32;
cmSystemTools::KeyWOW64 other_view = cmSystemTools::KeyWOW64_64;
if (mf->PlatformIs64Bit()) {
view = cmSystemTools::KeyWOW64_64;
other_view = cmSystemTools::KeyWOW64_32;
}
// Expand using the view of the target application.
std::string expanded = path;
cmSystemTools::ExpandRegistryValues(expanded, view);
cmSystemTools::GlobDirs(expanded, paths);
// Executables can be either 32-bit or 64-bit, so expand using the
// alternative view.
expanded = path;
cmSystemTools::ExpandRegistryValues(expanded, other_view);
cmSystemTools::GlobDirs(expanded, paths);
}
static void AddEnvPath(std::vector<std::string>& paths, const std::string& var,
const std::string& suffix)
{
std::string value;
if (cmSystemTools::GetEnv(var, value)) {
paths.push_back(value + suffix);
}
}
#endif
static cmsys::RegularExpression TransformCompile(const std::string& str)
{
return cmsys::RegularExpression(str);
}
cmRuntimeDependencyArchive::cmRuntimeDependencyArchive(
cmCommand* command, std::vector<std::string> searchDirectories,
std::string bundleExecutable,
const std::vector<std::string>& preIncludeRegexes,
const std::vector<std::string>& preExcludeRegexes,
const std::vector<std::string>& postIncludeRegexes,
const std::vector<std::string>& postExcludeRegexes)
: Command(command)
, SearchDirectories(std::move(searchDirectories))
, BundleExecutable(std::move(bundleExecutable))
, PreIncludeRegexes(preIncludeRegexes.size())
, PreExcludeRegexes(preExcludeRegexes.size())
, PostIncludeRegexes(postIncludeRegexes.size())
, PostExcludeRegexes(postExcludeRegexes.size())
{
std::transform(preIncludeRegexes.begin(), preIncludeRegexes.end(),
this->PreIncludeRegexes.begin(), TransformCompile);
std::transform(preExcludeRegexes.begin(), preExcludeRegexes.end(),
this->PreExcludeRegexes.begin(), TransformCompile);
std::transform(postIncludeRegexes.begin(), postIncludeRegexes.end(),
this->PostIncludeRegexes.begin(), TransformCompile);
std::transform(postExcludeRegexes.begin(), postExcludeRegexes.end(),
this->PostExcludeRegexes.begin(), TransformCompile);
}
bool cmRuntimeDependencyArchive::Prepare()
{
std::string platform = this->GetMakefile()->GetSafeDefinition(
"CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM");
if (platform.empty()) {
std::string systemName =
this->GetMakefile()->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
if (systemName == "Windows") {
platform = "windows+pe";
} else if (systemName == "Darwin") {
platform = "macos+macho";
} else if (systemName == "Linux") {
platform = "linux+elf";
}
}
if (platform == "linux+elf") {
this->Linker = cm::make_unique<cmBinUtilsLinuxELFLinker>(this);
} else if (platform == "windows+pe") {
this->Linker = cm::make_unique<cmBinUtilsWindowsPELinker>(this);
} else if (platform == "macos+macho") {
this->Linker = cm::make_unique<cmBinUtilsMacOSMachOLinker>(this);
} else {
std::ostringstream e;
e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM: "
<< platform;
this->SetError(e.str());
return false;
}
return this->Linker->Prepare();
}
bool cmRuntimeDependencyArchive::GetRuntimeDependencies(
const std::vector<std::string>& executables,
const std::vector<std::string>& libraries,
const std::vector<std::string>& modules)
{
for (auto const& exe : executables) {
if (!this->Linker->ScanDependencies(exe, cmStateEnums::EXECUTABLE)) {
return false;
}
}
for (auto const& lib : libraries) {
if (!this->Linker->ScanDependencies(lib, cmStateEnums::SHARED_LIBRARY)) {
return false;
}
}
for (auto const& mod : modules) {
if (!this->Linker->ScanDependencies(mod, cmStateEnums::MODULE_LIBRARY)) {
return false;
}
}
return true;
}
void cmRuntimeDependencyArchive::SetError(const std::string& e)
{
this->Command->SetError(e);
}
std::string cmRuntimeDependencyArchive::GetBundleExecutable()
{
return this->BundleExecutable;
}
const std::vector<std::string>&
cmRuntimeDependencyArchive::GetSearchDirectories()
{
return this->SearchDirectories;
}
std::string cmRuntimeDependencyArchive::GetGetRuntimeDependenciesTool()
{
return this->GetMakefile()->GetSafeDefinition(
"CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL");
}
bool cmRuntimeDependencyArchive::GetGetRuntimeDependenciesCommand(
const std::string& search, std::vector<std::string>& command)
{
// First see if it was supplied by the user
std::string toolCommand = this->GetMakefile()->GetSafeDefinition(
"CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND");
if (!toolCommand.empty()) {
cmSystemTools::ExpandListArgument(toolCommand, command);
return true;
}
// Now go searching for it
std::vector<std::string> paths;
#ifdef _WIN32
cmGlobalGenerator* gg = this->GetMakefile()->GetGlobalGenerator();
// Add newer Visual Studio paths
AddVisualStudioPath(paths, "Visual Studio 16 ", 16, gg);
AddVisualStudioPath(paths, "Visual Studio 15 ", 15, gg);
// Add older Visual Studio paths
AddRegistryPath(
paths,
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\14.0;InstallDir]/"
"../../VC/bin",
this->GetMakefile());
AddEnvPath(paths, "VS140COMNTOOLS", "/../../VC/bin");
paths.push_back(
"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin");
AddRegistryPath(
paths,
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\12.0;InstallDir]/"
"../../VC/bin",
this->GetMakefile());
AddEnvPath(paths, "VS120COMNTOOLS", "/../../VC/bin");
paths.push_back(
"C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin");
AddRegistryPath(
paths,
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\11.0;InstallDir]/"
"../../VC/bin",
this->GetMakefile());
AddEnvPath(paths, "VS110COMNTOOLS", "/../../VC/bin");
paths.push_back(
"C:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/bin");
AddRegistryPath(
paths,
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;InstallDir]/"
"../../VC/bin",
this->GetMakefile());
AddEnvPath(paths, "VS100COMNTOOLS", "/../../VC/bin");
paths.push_back(
"C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/bin");
AddRegistryPath(
paths,
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0;InstallDir]/"
"../../VC/bin",
this->GetMakefile());
AddEnvPath(paths, "VS90COMNTOOLS", "/../../VC/bin");
paths.push_back("C:/Program Files/Microsoft Visual Studio 9.0/VC/bin");
paths.push_back("C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin");
AddRegistryPath(
paths,
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0;InstallDir]/"
"../../VC/bin",
this->GetMakefile());
AddEnvPath(paths, "VS80COMNTOOLS", "/../../VC/bin");
paths.push_back("C:/Program Files/Microsoft Visual Studio 8/VC/BIN");
paths.push_back("C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN");
AddRegistryPath(
paths,
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.1;InstallDir]/"
"../../VC7/bin",
this->GetMakefile());
AddEnvPath(paths, "VS71COMNTOOLS", "/../../VC7/bin");
paths.push_back(
"C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN");
paths.push_back(
"C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN");
#endif
std::string program = cmSystemTools::FindProgram(search, paths);
if (!program.empty()) {
command = { program };
return true;
}
// Couldn't find it
return false;
}
bool cmRuntimeDependencyArchive::IsPreExcluded(const std::string& name)
{
cmsys::RegularExpressionMatch match;
for (auto const& regex : this->PreIncludeRegexes) {
if (regex.find(name.c_str(), match)) {
return false;
}
}
for (auto const& regex : this->PreExcludeRegexes) {
if (regex.find(name.c_str(), match)) {
return true;
}
}
return false;
}
bool cmRuntimeDependencyArchive::IsPostExcluded(const std::string& name)
{
cmsys::RegularExpressionMatch match;
for (auto const& regex : this->PostIncludeRegexes) {
if (regex.find(name.c_str(), match)) {
return false;
}
}
for (auto const& regex : this->PostExcludeRegexes) {
if (regex.find(name.c_str(), match)) {
return true;
}
}
return false;
}
void cmRuntimeDependencyArchive::AddResolvedPath(const std::string& name,
const std::string& path,
bool& unique)
{
auto it =
this->ResolvedPaths
.insert(std::pair<std::string, std::set<std::string>>{ name, {} })
.first;
unique = true;
for (auto const& other : it->second) {
if (cmSystemTools::SameFile(path, other)) {
unique = false;
break;
}
}
it->second.insert(path);
}
void cmRuntimeDependencyArchive::AddUnresolvedPath(const std::string& name)
{
this->UnresolvedPaths.insert(name);
}
cmMakefile* cmRuntimeDependencyArchive::GetMakefile()
{
return this->Command->GetMakefile();
}
const std::map<std::string, std::set<std::string>>&
cmRuntimeDependencyArchive::GetResolvedPaths()
{
return this->ResolvedPaths;
}
const std::set<std::string>& cmRuntimeDependencyArchive::GetUnresolvedPaths()
{
return this->UnresolvedPaths;
}

View File

@@ -0,0 +1,70 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmRuntimeDependencyArchive_h
#define cmRuntimeDependencyArchive_h
#include "cmBinUtilsLinker.h"
#include "cmsys/RegularExpression.hxx"
#include <map>
#include <memory> // IWYU pragma: keep
#include <set>
#include <string>
#include <vector>
class cmCommand;
class cmMakefile;
class cmRuntimeDependencyArchive
{
public:
explicit cmRuntimeDependencyArchive(
cmCommand* command, std::vector<std::string> searchDirectories,
std::string bundleExecutable,
const std::vector<std::string>& preIncludeRegexes,
const std::vector<std::string>& preExcludeRegexes,
const std::vector<std::string>& postIncludeRegexes,
const std::vector<std::string>& postExcludeRegexes);
bool Prepare();
bool GetRuntimeDependencies(const std::vector<std::string>& executables,
const std::vector<std::string>& libraries,
const std::vector<std::string>& modules);
void SetError(const std::string& e);
std::string GetBundleExecutable();
const std::vector<std::string>& GetSearchDirectories();
std::string GetGetRuntimeDependenciesTool();
bool GetGetRuntimeDependenciesCommand(const std::string& search,
std::vector<std::string>& command);
bool IsPreExcluded(const std::string& name);
bool IsPostExcluded(const std::string& name);
void AddResolvedPath(const std::string& name, const std::string& path,
bool& unique);
void AddUnresolvedPath(const std::string& name);
cmMakefile* GetMakefile();
const std::map<std::string, std::set<std::string>>& GetResolvedPaths();
const std::set<std::string>& GetUnresolvedPaths();
private:
cmCommand* Command;
std::unique_ptr<cmBinUtilsLinker> Linker;
std::string GetRuntimeDependenciesTool;
std::vector<std::string> GetRuntimeDependenciesCommand;
std::vector<std::string> SearchDirectories;
std::string BundleExecutable;
std::vector<cmsys::RegularExpression> PreIncludeRegexes;
std::vector<cmsys::RegularExpression> PreExcludeRegexes;
std::vector<cmsys::RegularExpression> PostIncludeRegexes;
std::vector<cmsys::RegularExpression> PostExcludeRegexes;
std::map<std::string, std::set<std::string>> ResolvedPaths;
std::set<std::string> UnresolvedPaths;
};
#endif // cmRuntimeDependencyArchive_h

View File

@@ -408,7 +408,7 @@ else()
set(NO_NAMELINK 0)
endif()
add_RunCMake_test(install -DNO_NAMELINK=${NO_NAMELINK} -DCYGWIN=${CYGWIN})
add_RunCMake_test(install -DNO_NAMELINK=${NO_NAMELINK} -DCYGWIN=${CYGWIN} -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
add_RunCMake_test(CPackCommandLine)
add_RunCMake_test(CPackConfig)
add_RunCMake_test(CPackInstallProperties)

View File

@@ -1,3 +1,6 @@
cmake_minimum_required(VERSION 3.4)
if(RunCMake_TEST MATCHES "^file-GET_RUNTIME_DEPENDENCIES")
cmake_policy(SET CMP0087 NEW)
endif()
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)

View File

@@ -139,6 +139,36 @@ run_install_test(FILES-PERMISSIONS)
run_install_test(TARGETS-RPATH)
run_install_test(InstallRequiredSystemLibraries)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
run_install_test(file-GET_RUNTIME_DEPENDENCIES-macos)
run_install_test(file-GET_RUNTIME_DEPENDENCIES-macos-unresolved)
run_install_test(file-GET_RUNTIME_DEPENDENCIES-macos-conflict)
run_install_test(file-GET_RUNTIME_DEPENDENCIES-macos-notfile)
run_cmake(file-GET_RUNTIME_DEPENDENCIES-project)
run_cmake(file-GET_RUNTIME_DEPENDENCIES-badargs1)
run_cmake(file-GET_RUNTIME_DEPENDENCIES-badargs2)
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
run_install_test(file-GET_RUNTIME_DEPENDENCIES-windows)
run_install_test(file-GET_RUNTIME_DEPENDENCIES-windows-unresolved)
run_install_test(file-GET_RUNTIME_DEPENDENCIES-windows-conflict)
run_install_test(file-GET_RUNTIME_DEPENDENCIES-windows-notfile)
run_cmake(file-GET_RUNTIME_DEPENDENCIES-project)
run_cmake(file-GET_RUNTIME_DEPENDENCIES-badargs1)
run_cmake(file-GET_RUNTIME_DEPENDENCIES-badargs2)
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
if(NOT CMAKE_C_COMPILER_ID MATCHES "^XL")
run_install_test(file-GET_RUNTIME_DEPENDENCIES-linux)
endif()
run_install_test(file-GET_RUNTIME_DEPENDENCIES-linux-unresolved)
run_install_test(file-GET_RUNTIME_DEPENDENCIES-linux-conflict)
run_install_test(file-GET_RUNTIME_DEPENDENCIES-linux-notfile)
run_cmake(file-GET_RUNTIME_DEPENDENCIES-project)
run_cmake(file-GET_RUNTIME_DEPENDENCIES-badargs1)
run_cmake(file-GET_RUNTIME_DEPENDENCIES-badargs2)
else()
run_cmake(file-GET_RUNTIME_DEPENDENCIES-unsupported)
endif()
set(run_install_test_components 1)
run_install_test(FILES-EXCLUDE_FROM_ALL)
run_install_test(TARGETS-EXCLUDE_FROM_ALL)

View File

@@ -0,0 +1,18 @@
^CMake Warning \(dev\) at file-GET_RUNTIME_DEPENDENCIES-badargs1\.cmake:[0-9]+ \(file\):
You have used file\(GET_RUNTIME_DEPENDENCIES\) in project mode\. This is
probably not what you intended to do\. Instead, please consider using it in
an install\(CODE\) or install\(SCRIPT\) command\. For example:
install\(CODE \[\[
file\(GET_RUNTIME_DEPENDENCIES
# \.\.\.
\)
]]\)
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
This warning is for project developers\. Use -Wno-dev to suppress it\.
CMake Error at file-GET_RUNTIME_DEPENDENCIES-badargs1\.cmake:[0-9]+ \(file\):
file Unrecognized argument: "invalid"
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)$

View File

@@ -0,0 +1,2 @@
file(GET_RUNTIME_DEPENDENCIES invalid)
message(FATAL_ERROR "This message should not be displayed")

View File

@@ -0,0 +1,18 @@
^CMake Warning \(dev\) at file-GET_RUNTIME_DEPENDENCIES-badargs2\.cmake:[0-9]+ \(file\):
You have used file\(GET_RUNTIME_DEPENDENCIES\) in project mode\. This is
probably not what you intended to do\. Instead, please consider using it in
an install\(CODE\) or install\(SCRIPT\) command\. For example:
install\(CODE \[\[
file\(GET_RUNTIME_DEPENDENCIES
# \.\.\.
\)
]]\)
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
This warning is for project developers\. Use -Wno-dev to suppress it\.
CMake Error at file-GET_RUNTIME_DEPENDENCIES-badargs2\.cmake:[0-9]+ \(file\):
file Keyword missing value: BUNDLE_EXECUTABLE
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)$

View File

@@ -0,0 +1,2 @@
file(GET_RUNTIME_DEPENDENCIES BUNDLE_EXECUTABLE)
message(FATAL_ERROR "This message should not be displayed")

View File

@@ -0,0 +1,44 @@
function(check_contents filename contents_regex)
if(EXISTS "${CMAKE_INSTALL_PREFIX}/${filename}")
file(READ "${CMAKE_INSTALL_PREFIX}/${filename}" contents)
if(NOT contents MATCHES "${contents_regex}")
string(APPEND RunCMake_TEST_FAILED "File contents:
${contents}
do not match what we expected:
${contents_regex}
in file:
${CMAKE_INSTALL_PREFIX}/${filename}\n")
set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
endif()
else()
string(APPEND RunCMake_TEST_FAILED "File ${CMAKE_INSTALL_PREFIX}/${filename} does not exist")
set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
endif()
endfunction()
set(_check
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/libtest_rpath\.so]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/libtest_runpath\.so]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/rpath/librpath\.so]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/rpath_parent/librpath_parent\.so]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/rpath_search/librpath_search\.so]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/runpath/librunpath\.so]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/runpath_search/librunpath_search\.so]]
)
check_contents(deps/deps1.txt "^${_check}$")
check_contents(deps/deps2.txt "^${_check}$")
check_contents(deps/deps3.txt "^${_check}$")
set(_check
[[librpath_unresolved\.so]]
[[librunpath_parent_unresolved\.so]]
[[librunpath_unresolved\.so]]
)
check_contents(deps/udeps1.txt "^${_check}$")
check_contents(deps/udeps2.txt "^${_check}$")
check_contents(deps/udeps3.txt "^${_check}$")
set(_check
"^libconflict\\.so:[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/conflict/libconflict\\.so;[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/conflict2/libconflict\\.so\n$"
)
check_contents(deps/cdeps1.txt "${_check}")
check_contents(deps/cdeps2.txt "${_check}")
check_contents(deps/cdeps3.txt "${_check}")

View File

@@ -0,0 +1,119 @@
^CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
Dependency librpath_search_postexcluded\.so found in search directory:
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/rpath_search_postexcluded
See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
Call Stack \(most recent call first\):
cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
Dependency librpath_search\.so found in search directory:
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/rpath_search
See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
Call Stack \(most recent call first\):
cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
Dependency librunpath_search_postexcluded\.so found in search directory:
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/runpath_search_postexcluded
See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
Call Stack \(most recent call first\):
cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
Dependency librunpath_search\.so found in search directory:
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/runpath_search
See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
Call Stack \(most recent call first\):
cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
Dependency librpath_search_postexcluded\.so found in search directory:
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/rpath_search_postexcluded
See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
Call Stack \(most recent call first\):
cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
Dependency librpath_search\.so found in search directory:
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/rpath_search
See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
Call Stack \(most recent call first\):
cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
Dependency librunpath_search_postexcluded\.so found in search directory:
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/runpath_search_postexcluded
See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
Call Stack \(most recent call first\):
cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
Dependency librunpath_search\.so found in search directory:
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/runpath_search
See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
Call Stack \(most recent call first\):
cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
Dependency librpath_search_postexcluded\.so found in search directory:
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/rpath_search_postexcluded
See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
Call Stack \(most recent call first\):
cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
Dependency librpath_search\.so found in search directory:
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/rpath_search
See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
Call Stack \(most recent call first\):
cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
Dependency librunpath_search_postexcluded\.so found in search directory:
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/runpath_search_postexcluded
See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
Call Stack \(most recent call first\):
cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)
*CMake Warning at cmake_install\.cmake:[0-9]+ \(file\):
Dependency librunpath_search\.so found in search directory:
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-build/root-all/lib/runpath_search
See file\(GET_RUNTIME_DEPENDENCIES\) documentation for more information\.
Call Stack \(most recent call first\):
cmake_install\.cmake:[0-9]+ \(exec_get_runtime_dependencies\)$

View File

@@ -0,0 +1,7 @@
^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
file Multiple conflicting paths found for librpath\.so:
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-conflict-build/root-all/lib/rpath1/librpath\.so
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-conflict-build/root-all/lib/rpath2/librpath\.so$

View File

@@ -0,0 +1,54 @@
enable_language(C)
set(test1_names rpath)
set(test2_names rpath)
file(WRITE "${CMAKE_BINARY_DIR}/rpath.c" "void rpath(void) {}\n")
add_library(rpath SHARED "${CMAKE_BINARY_DIR}/rpath.c")
install(TARGETS rpath DESTINATION lib/rpath1)
install(TARGETS rpath DESTINATION lib/rpath2)
file(REMOVE "${CMAKE_BINARY_DIR}/test1.c")
add_library(test1 SHARED "${CMAKE_BINARY_DIR}/test1.c")
foreach(name ${test1_names})
file(APPEND "${CMAKE_BINARY_DIR}/test1.c" "extern void ${name}(void);\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/test1.c" "void test1(void)\n{\n")
foreach(name ${test1_names})
file(APPEND "${CMAKE_BINARY_DIR}/test1.c" " ${name}();\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/test1.c" "}\n")
target_link_libraries(test1 PRIVATE ${test1_names})
set_property(TARGET test1 PROPERTY INSTALL_RPATH
"${CMAKE_BINARY_DIR}/root-all/lib/rpath1"
)
file(REMOVE "${CMAKE_BINARY_DIR}/test2.c")
add_library(test2 SHARED "${CMAKE_BINARY_DIR}/test2.c")
foreach(name ${test2_names})
file(APPEND "${CMAKE_BINARY_DIR}/test2.c" "extern void ${name}(void);\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/test2.c" "void test2(void)\n{\n")
foreach(name ${test2_names})
file(APPEND "${CMAKE_BINARY_DIR}/test2.c" " ${name}();\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/test2.c" "}\n")
target_link_libraries(test2 PRIVATE ${test2_names})
set_property(TARGET test2 PROPERTY INSTALL_RPATH
"${CMAKE_BINARY_DIR}/root-all/lib/rpath2"
)
install(TARGETS test1 test2 DESTINATION lib)
install(CODE [[
file(GET_RUNTIME_DEPENDENCIES
LIBRARIES
"${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:test1>"
"${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:test2>"
PRE_INCLUDE_REGEXES "^librpath\\.so$"
PRE_EXCLUDE_REGEXES ".*"
)
message(FATAL_ERROR "This message should not be displayed")
]])

View File

@@ -0,0 +1,5 @@
^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
file Failed to run objdump on:
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-linux-notfile-build/root-all/bin/\.\./lib/libtest\.so$

View File

@@ -0,0 +1,29 @@
enable_language(C)
file(WRITE "${CMAKE_BINARY_DIR}/test.c" "void test(void) {}\n")
file(WRITE "${CMAKE_BINARY_DIR}/main.c" [[extern void test(void);
int main(void)
{
test();
return 0;
}
]])
add_library(test SHARED "${CMAKE_BINARY_DIR}/test.c")
add_executable(exe "${CMAKE_BINARY_DIR}/main.c")
target_link_libraries(exe PRIVATE test)
set_property(TARGET exe PROPERTY INSTALL_RPATH "\\\${ORIGIN}/../lib")
install(TARGETS exe DESTINATION bin)
install(CODE [[
file(MAKE_DIRECTORY "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:test>")
file(GET_RUNTIME_DEPENDENCIES
EXECUTABLES
"${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:exe>"
PRE_INCLUDE_REGEXES "^libtest\\.so$"
PRE_EXCLUDE_REGEXES ".*"
)
message(FATAL_ERROR "This message should not be displayed")
]])

View File

@@ -0,0 +1,2 @@
^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
file Could not resolve file libunresolved\.so$

View File

@@ -0,0 +1,18 @@
enable_language(C)
file(WRITE "${CMAKE_BINARY_DIR}/testlib.c" "extern void unresolved(void);\nvoid testlib(void)\n{\n unresolved();\n}\n")
add_library(testlib SHARED "${CMAKE_BINARY_DIR}/testlib.c")
file(WRITE "${CMAKE_BINARY_DIR}/unresolved.c" "void unresolved(void) {}\n")
add_library(unresolved SHARED "${CMAKE_BINARY_DIR}/unresolved.c")
target_link_libraries(testlib PRIVATE unresolved)
install(TARGETS testlib DESTINATION lib)
install(CODE [[
file(GET_RUNTIME_DEPENDENCIES
PRE_INCLUDE_REGEXES "^libunresolved\\.so$"
PRE_EXCLUDE_REGEXES ".*"
LIBRARIES
"${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:testlib>"
)
message(FATAL_ERROR "This message should not be displayed")
]])

View File

@@ -0,0 +1,168 @@
enable_language(C)
set(test_rpath_names
preexcluded
rpath_postexcluded
rpath
rpath_parent_postexcluded
rpath_parent
rpath_origin_postexcluded
rpath_origin
rpath_search_postexcluded
rpath_search
rpath_unresolved
conflict
)
set(test_runpath_names
runpath_postexcluded
runpath
runpath_origin_postexcluded
runpath_origin
runpath_parent_unresolved
runpath_search_postexcluded
runpath_search
runpath_unresolved
)
file(REMOVE "${CMAKE_BINARY_DIR}/test_rpath.c")
add_library(test_rpath SHARED "${CMAKE_BINARY_DIR}/test_rpath.c")
foreach(name ${test_rpath_names})
file(WRITE "${CMAKE_BINARY_DIR}/${name}.c" "void ${name}(void) {}\n")
add_library(${name} SHARED "${CMAKE_BINARY_DIR}/${name}.c")
file(APPEND "${CMAKE_BINARY_DIR}/test_rpath.c" "extern void ${name}(void);\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/test_rpath.c" "void test_rpath(void)\n{\n")
foreach(name ${test_rpath_names})
file(APPEND "${CMAKE_BINARY_DIR}/test_rpath.c" " ${name}();\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/test_rpath.c" "}\n")
install(TARGETS rpath_postexcluded DESTINATION lib/rpath_postexcluded)
install(TARGETS rpath DESTINATION lib/rpath)
install(TARGETS rpath_origin_postexcluded DESTINATION lib/rpath_origin_postexcluded)
install(TARGETS rpath_origin DESTINATION lib/rpath_origin)
install(TARGETS rpath_parent_postexcluded DESTINATION lib/rpath_parent_postexcluded)
install(TARGETS rpath rpath_origin rpath_parent DESTINATION lib/rpath_parent)
install(TARGETS rpath_search_postexcluded DESTINATION lib/rpath_search_postexcluded)
install(TARGETS rpath rpath_origin rpath_parent rpath_search DESTINATION lib/rpath_search)
install(TARGETS conflict DESTINATION lib/conflict)
target_link_libraries(test_rpath PRIVATE ${test_rpath_names})
set_property(TARGET test_rpath PROPERTY INSTALL_RPATH
"${CMAKE_BINARY_DIR}/root-all/lib/rpath_postexcluded"
"${CMAKE_BINARY_DIR}/root-all/lib/rpath"
"\\\$ORIGIN/rpath_origin_postexcluded"
"\\\${ORIGIN}/rpath_origin" # This must be double-escaped because of issue #19225.
"${CMAKE_BINARY_DIR}/root-all/lib/conflict"
)
target_link_options(test_rpath PRIVATE -Wl,--disable-new-dtags)
file(REMOVE "${CMAKE_BINARY_DIR}/test_runpath.c")
add_library(test_runpath SHARED "${CMAKE_BINARY_DIR}/test_runpath.c")
foreach(name ${test_runpath_names} rpath conflict)
file(WRITE "${CMAKE_BINARY_DIR}/${name}.c" "void ${name}(void) {}\n")
if(NOT name MATCHES "^(rpath|conflict)$")
add_library(${name} SHARED "${CMAKE_BINARY_DIR}/${name}.c")
endif()
file(APPEND "${CMAKE_BINARY_DIR}/test_runpath.c" "extern void ${name}(void);\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/test_runpath.c" "void test_runpath(void)\n{\n")
foreach(name ${test_runpath_names} rpath conflict)
file(APPEND "${CMAKE_BINARY_DIR}/test_runpath.c" " ${name}();\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/test_runpath.c" "}\n")
install(TARGETS runpath_postexcluded DESTINATION lib/runpath_postexcluded)
install(TARGETS runpath DESTINATION lib/runpath)
install(TARGETS runpath_origin_postexcluded DESTINATION lib/runpath_origin_postexcluded)
install(TARGETS runpath_origin DESTINATION lib/runpath_origin)
install(TARGETS runpath_parent_unresolved DESTINATION lib/runpath_parent_unresolved)
install(TARGETS runpath_search_postexcluded DESTINATION lib/runpath_search_postexcluded)
install(TARGETS runpath runpath_origin runpath_search DESTINATION lib/runpath_search)
install(TARGETS conflict DESTINATION lib/conflict2)
target_link_libraries(test_runpath PRIVATE ${test_runpath_names} rpath conflict)
set_property(TARGET test_runpath PROPERTY INSTALL_RPATH
"${CMAKE_BINARY_DIR}/root-all/lib/runpath/../rpath" # Ensure that files that don't conflict are treated correctly
"${CMAKE_BINARY_DIR}/root-all/lib/runpath_postexcluded"
"${CMAKE_BINARY_DIR}/root-all/lib/runpath"
"\\\${ORIGIN}/runpath_origin_postexcluded" # This must be double-escaped because of issue #19225.
"\\\$ORIGIN/runpath_origin"
"${CMAKE_BINARY_DIR}/root-all/lib/conflict2"
)
target_link_options(test_runpath PRIVATE -Wl,--enable-new-dtags)
set_property(TARGET test_rpath ${test_rpath_names} test_runpath ${test_runpath_names} PROPERTY LIBRARY_OUTPUT_DIRECTORY lib)
install(TARGETS test_rpath test_runpath DESTINATION lib)
add_executable(topexe file-GET_RUNTIME_DEPENDENCIES-linux/topexe.c)
add_library(toplib SHARED file-GET_RUNTIME_DEPENDENCIES-linux/toplib.c)
add_library(topmod MODULE file-GET_RUNTIME_DEPENDENCIES-linux/toplib.c)
target_link_libraries(topexe PRIVATE test_rpath test_runpath)
target_link_libraries(toplib PRIVATE test_rpath test_runpath)
target_link_libraries(topmod PRIVATE test_rpath test_runpath)
set_property(TARGET topexe toplib topmod PROPERTY INSTALL_RPATH
"${CMAKE_BINARY_DIR}/root-all/lib"
"${CMAKE_BINARY_DIR}/root-all/lib/rpath_parent_postexcluded"
"${CMAKE_BINARY_DIR}/root-all/lib/rpath_parent"
"${CMAKE_BINARY_DIR}/root-all/lib/runpath_parent_unresolved"
)
target_link_options(topexe PRIVATE -Wl,--disable-new-dtags)
target_link_options(toplib PRIVATE -Wl,--disable-new-dtags)
target_link_options(topmod PRIVATE -Wl,--disable-new-dtags)
install(TARGETS topexe toplib RUNTIME DESTINATION bin LIBRARY DESTINATION lib)
install(TARGETS topmod LIBRARY DESTINATION lib/modules)
install(CODE [[
function(exec_get_runtime_dependencies depsfile udepsfile cdepsfile)
file(GET_RUNTIME_DEPENDENCIES
RESOLVED_DEPENDENCIES_VAR deps
UNRESOLVED_DEPENDENCIES_VAR udeps
CONFLICTING_DEPENDENCIES_PREFIX cdeps
PRE_INCLUDE_REGEXES
"^lib(test_rpath|rpath_postexcluded|rpath|rpath_parent_postexcluded|rpath_parent|rpath_origin_postexcluded|rpath_origin|rpath_search_postexcluded|rpath_search|rpath_unresolved|test_runpath|runpath_postexcluded|runpath|runpath_origin_postexcluded|runpath_origin|runpath_parent_unresolved|runpath_search_postexcluded|runpath_search|runpath_unresolved|conflict)\\.so$"
"^libc\\.so"
PRE_EXCLUDE_REGEXES ".*"
POST_INCLUDE_REGEXES "^.*/(libtest_rpath|rpath/librpath|rpath_parent/librpath_parent|rpath_search/librpath_search|libtest_runpath|runpath/librunpath|runpath_origin_postexcluded|runpath_origin|runpath_search/librunpath_search|conflict2?/libconflict)\\.so$"
POST_EXCLUDE_REGEXES ".*"
DIRECTORIES
"${CMAKE_INSTALL_PREFIX}/lib/rpath_search_postexcluded"
"${CMAKE_INSTALL_PREFIX}/lib/rpath_search"
"${CMAKE_INSTALL_PREFIX}/lib/runpath_search_postexcluded"
"${CMAKE_INSTALL_PREFIX}/lib/runpath_search"
${ARGN}
)
list(SORT deps)
list(SORT udeps)
list(SORT cdeps_FILENAMES)
file(WRITE "${CMAKE_INSTALL_PREFIX}/deps/${depsfile}" "${deps}")
file(WRITE "${CMAKE_INSTALL_PREFIX}/deps/${udepsfile}" "${udeps}")
file(WRITE "${CMAKE_INSTALL_PREFIX}/deps/${cdepsfile}" "")
foreach(cdep IN LISTS cdeps_FILENAMES)
set(cdep_values ${cdeps_${cdep}})
list(SORT cdep_values)
file(APPEND "${CMAKE_INSTALL_PREFIX}/deps/${cdepsfile}" "${cdep}:${cdep_values}\n")
endforeach()
endfunction()
exec_get_runtime_dependencies(
deps1.txt udeps1.txt cdeps1.txt
EXECUTABLES
"${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:topexe>"
)
exec_get_runtime_dependencies(
deps2.txt udeps2.txt cdeps2.txt
LIBRARIES
"${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:toplib>"
)
exec_get_runtime_dependencies(
deps3.txt udeps3.txt cdeps3.txt
MODULES
"${CMAKE_INSTALL_PREFIX}/lib/modules/$<TARGET_FILE_NAME:topmod>"
)
]])

View File

@@ -0,0 +1,9 @@
extern void test_rpath(void);
extern void test_runpath(void);
int main(void)
{
test_rpath();
test_runpath();
return 0;
}

View File

@@ -0,0 +1,8 @@
extern void test_rpath(void);
extern void test_runpath(void);
void toplib(void)
{
test_rpath();
test_runpath();
}

View File

@@ -0,0 +1,157 @@
function(check_contents filename contents_regex)
if(EXISTS "${CMAKE_INSTALL_PREFIX}/${filename}")
file(READ "${CMAKE_INSTALL_PREFIX}/${filename}" contents)
if(NOT contents MATCHES "${contents_regex}")
string(APPEND RunCMake_TEST_FAILED "File contents:
${contents}
do not match what we expected:
${contents_regex}
in file:
${CMAKE_INSTALL_PREFIX}/${filename}\n")
set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
endif()
else()
string(APPEND RunCMake_TEST_FAILED "File ${CMAKE_INSTALL_PREFIX}/${filename} does not exist")
set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
endif()
endfunction()
set(_check
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/bin/../lib/executable_path/libexecutable_path\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/bin/../lib/rpath_executable_path/librpath_executable_path\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/libtestlib\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/loader_path/libloader_path\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/../rpath/librpath\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/libnormal\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/rpath_loader_path/librpath_loader_path\.dylib]]
[[/usr/lib/libSystem\.B\.dylib]]
)
check_contents(deps/deps1.txt "^${_check}$")
set(_check
[[@executable_path/../lib/executable_path_bundle/libexecutable_path_bundle\.dylib]]
[[@loader_path/loader_path_unresolved/libloader_path_unresolved\.dylib]]
[[@rpath/librpath_executable_path_bundle\.dylib]]
[[@rpath/librpath_loader_path_unresolved\.dylib]]
[[@rpath/librpath_unresolved\.dylib]]
)
check_contents(deps/udeps1.txt "^${_check}$")
set(_check
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/libtestlib\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/loader_path/libloader_path\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/../rpath/librpath\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/libnormal\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/rpath_loader_path/librpath_loader_path\.dylib]]
[[/usr/lib/libSystem\.B\.dylib]]
)
check_contents(deps/deps2.txt "^${_check}$")
set(_check
[[@executable_path/../lib/executable_path/libexecutable_path\.dylib]]
[[@executable_path/../lib/executable_path_bundle/libexecutable_path_bundle\.dylib]]
[[@executable_path/../lib/executable_path_postexcluded/libexecutable_path_postexcluded\.dylib]]
[[@loader_path/loader_path_unresolved/libloader_path_unresolved\.dylib]]
[[@rpath/librpath_executable_path\.dylib]]
[[@rpath/librpath_executable_path_bundle\.dylib]]
[[@rpath/librpath_executable_path_postexcluded\.dylib]]
[[@rpath/librpath_loader_path_unresolved\.dylib]]
[[@rpath/librpath_unresolved\.dylib]]
)
check_contents(deps/udeps2.txt "^${_check}$")
set(_check
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/libtestlib\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/loader_path/libloader_path\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/../rpath/librpath\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/libnormal\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/rpath_loader_path/librpath_loader_path\.dylib]]
[[/usr/lib/libSystem\.B\.dylib]]
)
check_contents(deps/deps3.txt "^${_check}$")
set(_check
[[@executable_path/../lib/executable_path/libexecutable_path\.dylib]]
[[@executable_path/../lib/executable_path_bundle/libexecutable_path_bundle\.dylib]]
[[@executable_path/../lib/executable_path_postexcluded/libexecutable_path_postexcluded\.dylib]]
[[@loader_path/loader_path_unresolved/libloader_path_unresolved\.dylib]]
[[@rpath/librpath_executable_path\.dylib]]
[[@rpath/librpath_executable_path_bundle\.dylib]]
[[@rpath/librpath_executable_path_postexcluded\.dylib]]
[[@rpath/librpath_loader_path_unresolved\.dylib]]
[[@rpath/librpath_unresolved\.dylib]]
)
check_contents(deps/udeps3.txt "^${_check}$")
set(_check
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/bin/../lib/executable_path/libexecutable_path\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/bin/../lib/rpath_executable_path/librpath_executable_path\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/libtestlib\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/loader_path/libloader_path\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/../rpath/librpath\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/libnormal\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/rpath_loader_path/librpath_loader_path\.dylib]]
[[/usr/lib/libSystem\.B\.dylib]]
)
check_contents(deps/deps4.txt "^${_check}$")
set(_check
[[@executable_path/../lib/executable_path_bundle/libexecutable_path_bundle\.dylib]]
[[@loader_path/loader_path_unresolved/libloader_path_unresolved\.dylib]]
[[@rpath/librpath_executable_path_bundle\.dylib]]
[[@rpath/librpath_loader_path_unresolved\.dylib]]
[[@rpath/librpath_unresolved\.dylib]]
)
check_contents(deps/udeps4.txt "^${_check}$")
set(_check
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/bundle_executable/bin/../lib/executable_path_bundle/libexecutable_path_bundle\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/libtestlib\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/loader_path/libloader_path\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/../rpath/librpath\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/libnormal\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/rpath_loader_path/librpath_loader_path\.dylib]]
[[/usr/lib/libSystem\.B\.dylib]]
)
check_contents(deps/deps5.txt "^${_check}$")
set(_check
[[@executable_path/../lib/executable_path/libexecutable_path\.dylib]]
[[@loader_path/loader_path_unresolved/libloader_path_unresolved\.dylib]]
[[@rpath/librpath_executable_path\.dylib]]
[[@rpath/librpath_executable_path_bundle\.dylib]]
[[@rpath/librpath_loader_path_unresolved\.dylib]]
[[@rpath/librpath_unresolved\.dylib]]
)
check_contents(deps/udeps5.txt "^${_check}$")
set(_check
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/bundle_executable/bin/../lib/executable_path_bundle/libexecutable_path_bundle\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/libtestlib\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/loader_path/libloader_path\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/../rpath/librpath\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/normal/libnormal\.dylib]]
[[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/rpath_loader_path/librpath_loader_path\.dylib]]
[[/usr/lib/libSystem\.B\.dylib]]
)
check_contents(deps/deps6.txt "^${_check}$")
set(_check
[[@executable_path/../lib/executable_path/libexecutable_path\.dylib]]
[[@loader_path/loader_path_unresolved/libloader_path_unresolved\.dylib]]
[[@rpath/librpath_executable_path\.dylib]]
[[@rpath/librpath_executable_path_bundle\.dylib]]
[[@rpath/librpath_loader_path_unresolved\.dylib]]
[[@rpath/librpath_unresolved\.dylib]]
)
check_contents(deps/udeps6.txt "^${_check}$")
set(_check
"^libconflict\\.dylib:[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/conflict/libconflict\\.dylib;[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-build/root-all/executable/lib/conflict2/libconflict\\.dylib\n$"
)
check_contents(deps/cdeps1.txt "${_check}")
check_contents(deps/cdeps2.txt "${_check}")
check_contents(deps/cdeps3.txt "${_check}")
check_contents(deps/cdeps4.txt "${_check}")
check_contents(deps/cdeps5.txt "${_check}")
check_contents(deps/cdeps6.txt "${_check}")

View File

@@ -0,0 +1,7 @@
^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
file Multiple conflicting paths found for librpath\.dylib:
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-conflict-build/root-all/lib/rpath1/librpath\.dylib
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-conflict-build/root-all/lib/rpath2/librpath\.dylib$

View File

@@ -0,0 +1,55 @@
enable_language(C)
set(test1_names rpath)
set(test2_names rpath)
file(WRITE "${CMAKE_BINARY_DIR}/rpath.c" "void rpath(void) {}\n")
add_library(rpath SHARED "${CMAKE_BINARY_DIR}/rpath.c")
set_property(TARGET rpath PROPERTY INSTALL_NAME_DIR @rpath)
install(TARGETS rpath DESTINATION lib/rpath1)
install(TARGETS rpath DESTINATION lib/rpath2)
file(REMOVE "${CMAKE_BINARY_DIR}/test1.c")
add_library(test1 SHARED "${CMAKE_BINARY_DIR}/test1.c")
foreach(name ${test1_names})
file(APPEND "${CMAKE_BINARY_DIR}/test1.c" "extern void ${name}(void);\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/test1.c" "void test1(void)\n{\n")
foreach(name ${test1_names})
file(APPEND "${CMAKE_BINARY_DIR}/test1.c" " ${name}();\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/test1.c" "}\n")
target_link_libraries(test1 PRIVATE ${test1_names})
set_property(TARGET test1 PROPERTY INSTALL_RPATH
"${CMAKE_BINARY_DIR}/root-all/lib/rpath1"
)
file(REMOVE "${CMAKE_BINARY_DIR}/test2.c")
add_library(test2 SHARED "${CMAKE_BINARY_DIR}/test2.c")
foreach(name ${test2_names})
file(APPEND "${CMAKE_BINARY_DIR}/test2.c" "extern void ${name}(void);\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/test2.c" "void test2(void)\n{\n")
foreach(name ${test2_names})
file(APPEND "${CMAKE_BINARY_DIR}/test2.c" " ${name}();\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/test2.c" "}\n")
target_link_libraries(test2 PRIVATE ${test2_names})
set_property(TARGET test2 PROPERTY INSTALL_RPATH
"${CMAKE_BINARY_DIR}/root-all/lib/rpath2"
)
install(TARGETS test1 test2 DESTINATION lib)
install(CODE [[
file(GET_RUNTIME_DEPENDENCIES
LIBRARIES
"${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:test1>"
"${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:test2>"
PRE_INCLUDE_REGEXES "^@rpath/librpath\\.dylib$"
PRE_EXCLUDE_REGEXES ".*"
)
message(FATAL_ERROR "This message should not be displayed")
]])

View File

@@ -0,0 +1,5 @@
^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
file Failed to run otool on:
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-macos-notfile-build/root-all/bin/\.\./lib/libtest\.dylib$

View File

@@ -0,0 +1,30 @@
enable_language(C)
file(WRITE "${CMAKE_BINARY_DIR}/test.c" "void test(void) {}\n")
file(WRITE "${CMAKE_BINARY_DIR}/main.c" [[extern void test(void);
int main(void)
{
test();
return 0;
}
]])
add_library(test SHARED "${CMAKE_BINARY_DIR}/test.c")
set_property(TARGET test PROPERTY INSTALL_NAME_DIR @rpath)
add_executable(exe "${CMAKE_BINARY_DIR}/main.c")
target_link_libraries(exe PRIVATE test)
set_property(TARGET exe PROPERTY INSTALL_RPATH "@loader_path/../lib")
install(TARGETS exe DESTINATION bin)
install(CODE [[
file(MAKE_DIRECTORY "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:test>")
file(GET_RUNTIME_DEPENDENCIES
EXECUTABLES
"${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:exe>"
PRE_INCLUDE_REGEXES "^@rpath/libtest\\.dylib$"
PRE_EXCLUDE_REGEXES ".*"
)
message(FATAL_ERROR "This message should not be displayed")
]])

View File

@@ -0,0 +1,2 @@
^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
file Could not resolve file @rpath/libunresolved\.dylib$

View File

@@ -0,0 +1,18 @@
enable_language(C)
file(WRITE "${CMAKE_BINARY_DIR}/testlib.c" "extern void unresolved(void);\nvoid testlib(void)\n{\n unresolved();\n}\n")
add_library(testlib SHARED "${CMAKE_BINARY_DIR}/testlib.c")
file(WRITE "${CMAKE_BINARY_DIR}/unresolved.c" "void unresolved(void) {}\n")
add_library(unresolved SHARED "${CMAKE_BINARY_DIR}/unresolved.c")
target_link_libraries(testlib PRIVATE unresolved)
install(TARGETS testlib DESTINATION lib)
install(CODE [[
file(GET_RUNTIME_DEPENDENCIES
PRE_INCLUDE_REGEXES "^@rpath/libunresolved\\.dylib$"
PRE_EXCLUDE_REGEXES ".*"
LIBRARIES
"${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:testlib>"
)
message(FATAL_ERROR "This message should not be displayed")
]])

View File

@@ -0,0 +1,216 @@
enable_language(C)
set(testlib_names
preexcluded
executable_path
executable_path_bundle
executable_path_postexcluded
loader_path
loader_path_unresolved
loader_path_postexcluded
rpath
rpath_unresolved
rpath_postexcluded
rpath_executable_path
rpath_executable_path_bundle
rpath_executable_path_postexcluded
rpath_loader_path
rpath_loader_path_unresolved
rpath_loader_path_postexcluded
normal
normal_unresolved
normal_postexcluded
conflict
)
file(REMOVE "${CMAKE_BINARY_DIR}/testlib.c")
add_library(testlib SHARED "${CMAKE_BINARY_DIR}/testlib.c")
foreach(name ${testlib_names})
if(name STREQUAL "normal")
file(WRITE "${CMAKE_BINARY_DIR}/normal.c" "extern void rpath(void);\nvoid normal(void)\n{\n rpath();\n}\n")
else()
file(WRITE "${CMAKE_BINARY_DIR}/${name}.c" "void ${name}(void) {}\n")
endif()
add_library(${name} SHARED "${CMAKE_BINARY_DIR}/${name}.c")
file(APPEND "${CMAKE_BINARY_DIR}/testlib.c" "extern void ${name}(void);\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/testlib.c" "void testlib(void)\n{\n")
foreach(name ${testlib_names})
file(APPEND "${CMAKE_BINARY_DIR}/testlib.c" " ${name}();\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/testlib.c" "}\n")
set_property(TARGET ${testlib_names} PROPERTY BUILD_WITH_INSTALL_NAME_DIR 1)
target_link_libraries(normal PRIVATE rpath)
set_property(TARGET normal PROPERTY INSTALL_RPATH
"${CMAKE_BINARY_DIR}/root-all/executable/lib/normal/../rpath"
)
file(WRITE "${CMAKE_BINARY_DIR}/testlib_conflict.c" "extern void conflict(void);\nvoid testlib_conflict(void)\n{\n conflict();\n}\n")
add_library(testlib_conflict SHARED "${CMAKE_BINARY_DIR}/testlib_conflict.c")
target_link_libraries(testlib_conflict PRIVATE conflict)
set_property(TARGET testlib PROPERTY INSTALL_RPATH
"${CMAKE_BINARY_DIR}/root-all/executable/lib/rpath"
"${CMAKE_BINARY_DIR}/root-all/executable/lib/rpath_unresolved"
"${CMAKE_BINARY_DIR}/root-all/executable/lib/rpath_postexcluded"
"${CMAKE_BINARY_DIR}/root-all/executable/lib/conflict"
@executable_path/../lib/rpath_executable_path
@executable_path/../lib/rpath_executable_path_unresolved
@executable_path/../lib/rpath_executable_path_postexcluded
@loader_path/rpath_loader_path
@loader_path/rpath_loader_path_unresolved
@loader_path/rpath_loader_path_postexcluded
)
set_property(TARGET testlib_conflict PROPERTY INSTALL_RPATH
"${CMAKE_BINARY_DIR}/root-all/executable/lib/conflict2"
)
foreach(t
executable_path
executable_path_postexcluded
loader_path
loader_path_postexcluded
rpath
rpath_postexcluded
rpath_executable_path
rpath_executable_path_postexcluded
rpath_loader_path
rpath_loader_path_postexcluded
conflict
)
install(TARGETS ${t} DESTINATION executable/lib/${t})
endforeach()
install(TARGETS conflict DESTINATION executable/lib/conflict2)
foreach(t
executable_path_bundle
executable_path_postexcluded
loader_path_postexcluded
rpath_postexcluded
rpath_executable_path_bundle
rpath_executable_path_postexcluded
rpath_loader_path_postexcluded
)
install(TARGETS ${t} DESTINATION bundle_executable/lib/${t})
endforeach()
foreach(t executable_path executable_path_bundle executable_path_postexcluded)
set_property(TARGET ${t} PROPERTY INSTALL_NAME_DIR @executable_path/../lib/${t})
endforeach()
foreach(t loader_path loader_path_unresolved loader_path_postexcluded)
set_property(TARGET ${t} PROPERTY INSTALL_NAME_DIR @loader_path/${t})
endforeach()
foreach(t
rpath
rpath_unresolved
rpath_postexcluded
rpath_executable_path
rpath_executable_path_bundle
rpath_executable_path_postexcluded
rpath_loader_path
rpath_loader_path_unresolved
rpath_loader_path_postexcluded
conflict
)
set_property(TARGET ${t} PROPERTY INSTALL_NAME_DIR @rpath)
endforeach()
foreach(t normal normal_unresolved normal_postexcluded)
set_property(TARGET ${t} PROPERTY INSTALL_NAME_DIR "${CMAKE_BINARY_DIR}/root-all/executable/lib/${t}")
if(NOT t STREQUAL "normal_unresolved")
install(TARGETS ${t} DESTINATION executable/lib/${t})
endif()
endforeach()
target_link_libraries(testlib PRIVATE ${testlib_names})
add_executable(topexe file-GET_RUNTIME_DEPENDENCIES-macos/topexe.c)
add_library(toplib SHARED file-GET_RUNTIME_DEPENDENCIES-macos/toplib.c)
add_library(topmod MODULE file-GET_RUNTIME_DEPENDENCIES-macos/toplib.c)
target_link_libraries(topexe PRIVATE testlib)
target_link_libraries(toplib PRIVATE testlib)
target_link_libraries(topmod PRIVATE testlib)
set_property(TARGET topexe toplib topmod PROPERTY INSTALL_RPATH "${CMAKE_BINARY_DIR}/root-all/executable/lib")
install(TARGETS topexe toplib topmod testlib testlib_conflict RUNTIME DESTINATION executable/bin LIBRARY DESTINATION executable/lib)
install(TARGETS topexe toplib topmod testlib testlib_conflict RUNTIME DESTINATION bundle_executable/bin LIBRARY DESTINATION bundle_executable/lib)
install(CODE [[
function(exec_get_runtime_dependencies depsfile udepsfile cdepsfile)
file(GET_RUNTIME_DEPENDENCIES
RESOLVED_DEPENDENCIES_VAR deps
UNRESOLVED_DEPENDENCIES_VAR udeps
CONFLICTING_DEPENDENCIES_PREFIX cdeps
PRE_INCLUDE_REGEXES "^.*/lib(testlib|executable_path|executable_path_bundle|executable_path_postexcluded|loader_path|loader_path_unresolved|loader_path_postexcluded|rpath|rpath_unresolved|rpath_postexcluded|rpath_executable_path|rpath_executable_path_bundle|rpath_executable_path_postexcluded|rpath_loader_path|rpath_loader_path_unresolved|rpath_loader_path_postexcluded|normal|normal_unresolved|normal_postexcluded|conflict|System\\.B)\\.dylib$"
PRE_EXCLUDE_REGEXES ".*"
POST_INCLUDE_REGEXES "^.*/lib(testlib|executable_path|executable_path_bundle|loader_path|rpath|rpath_executable_path|rpath_executable_path_bundle|rpath_loader_path|normal|conflict|System\\.B)\\.dylib$"
POST_EXCLUDE_REGEXES ".*"
${ARGN}
)
list(SORT deps)
list(SORT udeps)
list(SORT cdeps_FILENAMES)
file(WRITE "${CMAKE_INSTALL_PREFIX}/deps/${depsfile}" "${deps}")
file(WRITE "${CMAKE_INSTALL_PREFIX}/deps/${udepsfile}" "${udeps}")
file(WRITE "${CMAKE_INSTALL_PREFIX}/deps/${cdepsfile}" "")
foreach(cdep IN LISTS cdeps_FILENAMES)
set(cdep_values ${cdeps_${cdep}})
list(SORT cdep_values)
file(APPEND "${CMAKE_INSTALL_PREFIX}/deps/${cdepsfile}" "${cdep}:${cdep_values}\n")
endforeach()
endfunction()
exec_get_runtime_dependencies(
deps1.txt udeps1.txt cdeps1.txt
EXECUTABLES
"${CMAKE_INSTALL_PREFIX}/executable/bin/$<TARGET_FILE_NAME:topexe>"
LIBRARIES
"${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:testlib_conflict>"
)
exec_get_runtime_dependencies(
deps2.txt udeps2.txt cdeps2.txt
LIBRARIES
"${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:toplib>"
"${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:testlib_conflict>"
)
exec_get_runtime_dependencies(
deps3.txt udeps3.txt cdeps3.txt
MODULES
"${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:topmod>"
LIBRARIES
"${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:testlib_conflict>"
)
exec_get_runtime_dependencies(
deps4.txt udeps4.txt cdeps4.txt
EXECUTABLES
"${CMAKE_INSTALL_PREFIX}/executable/bin/$<TARGET_FILE_NAME:topexe>"
LIBRARIES
"${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:testlib_conflict>"
BUNDLE_EXECUTABLE
"${CMAKE_INSTALL_PREFIX}/bundle_executable/bin/$<TARGET_FILE_NAME:topexe>"
)
exec_get_runtime_dependencies(
deps5.txt udeps5.txt cdeps5.txt
LIBRARIES
"${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:toplib>"
"${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:testlib_conflict>"
BUNDLE_EXECUTABLE "${CMAKE_INSTALL_PREFIX}/bundle_executable/bin/$<TARGET_FILE_NAME:topexe>"
)
exec_get_runtime_dependencies(
deps6.txt udeps6.txt cdeps6.txt
MODULES
"${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:topmod>"
LIBRARIES
"${CMAKE_INSTALL_PREFIX}/executable/lib/$<TARGET_FILE_NAME:testlib_conflict>"
BUNDLE_EXECUTABLE "${CMAKE_INSTALL_PREFIX}/bundle_executable/bin/$<TARGET_FILE_NAME:topexe>"
)
]])

View File

@@ -0,0 +1,7 @@
extern void testlib(void);
int main(void)
{
testlib();
return 0;
}

View File

@@ -0,0 +1,6 @@
extern void testlib(void);
void toplib(void)
{
testlib();
}

View File

@@ -0,0 +1,13 @@
^CMake Warning \(dev\) at file-GET_RUNTIME_DEPENDENCIES-project\.cmake:[0-9]+ \(file\):
You have used file\(GET_RUNTIME_DEPENDENCIES\) in project mode\. This is
probably not what you intended to do\. Instead, please consider using it in
an install\(CODE\) or install\(SCRIPT\) command\. For example:
install\(CODE \[\[
file\(GET_RUNTIME_DEPENDENCIES
# \.\.\.
\)
]]\)
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
This warning is for project developers\. Use -Wno-dev to suppress it\.$

View File

@@ -0,0 +1 @@
file(GET_RUNTIME_DEPENDENCIES RESOLVED_DEPENDENCIES_VAR deps)

View File

@@ -0,0 +1,5 @@
^CMake Error at file-GET_RUNTIME_DEPENDENCIES-unsupported\.cmake:[0-9]+ \(file\):
file GET_RUNTIME_DEPENDENCIES is not supported on system "[^
]+"
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)$

View File

@@ -0,0 +1,2 @@
file(GET_RUNTIME_DEPENDENCIES RESOLVED_DEPENDENCIES_VAR deps)
message(FATAL_ERROR "This message should not be displayed")

View File

@@ -0,0 +1,38 @@
function(check_contents filename contents_regex)
if(EXISTS "${CMAKE_INSTALL_PREFIX}/${filename}")
file(READ "${CMAKE_INSTALL_PREFIX}/${filename}" contents)
if(NOT contents MATCHES "${contents_regex}")
string(APPEND RunCMake_TEST_FAILED "File contents:
${contents}
do not match what we expected:
${contents_regex}
in file:
${CMAKE_INSTALL_PREFIX}/${filename}\n")
set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
endif()
else()
string(APPEND RunCMake_TEST_FAILED "File ${CMAKE_INSTALL_PREFIX}/${filename} does not exist")
set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
endif()
endfunction()
set(_check
[=[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-build/root-all/bin/\.conflict/\.\./(lib)?libdir\.dll]=]
[=[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-build/root-all/bin/\.search/(lib)?search\.dll]=]
[=[[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-build/root-all/bin/(lib)?testlib\.dll]=]
)
check_contents(deps/deps1.txt "^${_check}$")
check_contents(deps/deps2.txt "^${_check}$")
check_contents(deps/deps3.txt "^${_check}$")
set(_check
[=[(lib)?unresolved\.dll]=]
)
check_contents(deps/udeps1.txt "^${_check}$")
check_contents(deps/udeps2.txt "^${_check}$")
check_contents(deps/udeps3.txt "^${_check}$")
set(_check
"^(lib)?conflict\\.dll:[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-build/root-all/bin/\\.conflict/(lib)?conflict\\.dll;[^;]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-build/root-all/bin/(lib)?conflict\\.dll\n$"
)
check_contents(deps/cdeps1.txt "${_check}")
check_contents(deps/cdeps2.txt "${_check}")
check_contents(deps/cdeps3.txt "${_check}")

View File

@@ -0,0 +1,7 @@
^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
file Multiple conflicting paths found for (lib)?path\.dll:
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-conflict-build/root-all/lib/test1/(lib)?path\.dll
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-conflict-build/root-all/lib/test2/(lib)?path\.dll$

View File

@@ -0,0 +1,47 @@
enable_language(C)
set(test1_names path)
set(test2_names path)
file(WRITE "${CMAKE_BINARY_DIR}/path.c" "__declspec(dllexport) void path(void) {}\n")
add_library(path SHARED "${CMAKE_BINARY_DIR}/path.c")
file(REMOVE "${CMAKE_BINARY_DIR}/test1.c")
add_library(test1 SHARED "${CMAKE_BINARY_DIR}/test1.c")
foreach(name ${test1_names})
file(APPEND "${CMAKE_BINARY_DIR}/test1.c" "__declspec(dllimport) extern void ${name}(void);\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/test1.c" "__declspec(dllexport) void test1(void)\n{\n")
foreach(name ${test1_names})
file(APPEND "${CMAKE_BINARY_DIR}/test1.c" " ${name}();\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/test1.c" "}\n")
target_link_libraries(test1 PRIVATE ${test1_names})
file(REMOVE "${CMAKE_BINARY_DIR}/test2.c")
add_library(test2 SHARED "${CMAKE_BINARY_DIR}/test2.c")
foreach(name ${test2_names})
file(APPEND "${CMAKE_BINARY_DIR}/test2.c" "__declspec(dllimport) extern void ${name}(void);\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/test2.c" "__declspec(dllexport) void test2(void)\n{\n")
foreach(name ${test2_names})
file(APPEND "${CMAKE_BINARY_DIR}/test2.c" " ${name}();\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/test2.c" "}\n")
target_link_libraries(test2 PRIVATE ${test2_names})
install(TARGETS test1 path DESTINATION lib/test1)
install(TARGETS test2 path DESTINATION lib/test2)
install(CODE [[
file(GET_RUNTIME_DEPENDENCIES
LIBRARIES
"${CMAKE_INSTALL_PREFIX}/lib/test1/$<TARGET_FILE_NAME:test1>"
"${CMAKE_INSTALL_PREFIX}/lib/test2/$<TARGET_FILE_NAME:test2>"
PRE_INCLUDE_REGEXES "^(lib)?path\\.dll$"
PRE_EXCLUDE_REGEXES ".*"
)
message(FATAL_ERROR "This message should not be displayed")
]])

View File

@@ -0,0 +1,5 @@
^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
file Failed to run (dumpbin|objdump) on:
[^
]*/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-windows-notfile-build/root-all/bin/(lib)?test\.dll$

View File

@@ -0,0 +1,28 @@
enable_language(C)
file(WRITE "${CMAKE_BINARY_DIR}/test.c" "__declspec(dllexport) void test(void) {}\n")
file(WRITE "${CMAKE_BINARY_DIR}/main.c" [[__declspec(dllimport) extern void test(void);
int main(void)
{
test();
return 0;
}
]])
add_library(test SHARED "${CMAKE_BINARY_DIR}/test.c")
add_executable(exe "${CMAKE_BINARY_DIR}/main.c")
target_link_libraries(exe PRIVATE test)
install(TARGETS exe DESTINATION bin)
install(CODE [[
file(MAKE_DIRECTORY "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:test>")
file(GET_RUNTIME_DEPENDENCIES
EXECUTABLES
"${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:exe>"
PRE_INCLUDE_REGEXES "^(lib)?test\\.dll$"
PRE_EXCLUDE_REGEXES ".*"
)
message(FATAL_ERROR "This message should not be displayed")
]])

View File

@@ -0,0 +1,2 @@
^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
file Could not resolve file (lib)?unresolved\.dll$

View File

@@ -0,0 +1,18 @@
enable_language(C)
file(WRITE "${CMAKE_BINARY_DIR}/testlib.c" "__declspec(dllimport) extern void unresolved(void);\n__declspec(dllexport) void testlib(void)\n{\n unresolved();\n}\n")
add_library(testlib SHARED "${CMAKE_BINARY_DIR}/testlib.c")
file(WRITE "${CMAKE_BINARY_DIR}/unresolved.c" "__declspec(dllexport) void unresolved(void) {}\n")
add_library(unresolved SHARED "${CMAKE_BINARY_DIR}/unresolved.c")
target_link_libraries(testlib PRIVATE unresolved)
install(TARGETS testlib DESTINATION lib)
install(CODE [[
file(GET_RUNTIME_DEPENDENCIES
PRE_INCLUDE_REGEXES "^(lib)?unresolved\\.dll$"
PRE_EXCLUDE_REGEXES ".*"
LIBRARIES
"${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:testlib>"
)
message(FATAL_ERROR "This message should not be displayed")
]])

View File

@@ -0,0 +1,114 @@
enable_language(C)
set(testlib_names
preexcluded
libdir_postexcluded
libdir
search_postexcluded
search
unresolved
conflict
)
file(REMOVE "${CMAKE_BINARY_DIR}/testlib.c")
add_library(testlib SHARED "${CMAKE_BINARY_DIR}/testlib.c")
foreach(name ${testlib_names})
file(WRITE "${CMAKE_BINARY_DIR}/${name}.c" "__declspec(dllexport) void ${name}(void) {}\n")
add_library(${name} SHARED "${CMAKE_BINARY_DIR}/${name}.c")
file(APPEND "${CMAKE_BINARY_DIR}/testlib.c" "__declspec(dllimport) extern void ${name}(void);\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/testlib.c" "__declspec(dllexport) void testlib(void)\n{\n")
foreach(name ${testlib_names})
file(APPEND "${CMAKE_BINARY_DIR}/testlib.c" " ${name}();\n")
endforeach()
file(APPEND "${CMAKE_BINARY_DIR}/testlib.c" "}\n")
target_link_libraries(testlib PRIVATE ${testlib_names})
file(WRITE "${CMAKE_BINARY_DIR}/testlib_conflict.c" "__declspec(dllimport) extern void conflict(void);\n__declspec(dllexport) void testlib_conflict(void)\n{\n conflict();\n}\n")
add_library(testlib_conflict SHARED "${CMAKE_BINARY_DIR}/testlib_conflict.c")
target_link_libraries(testlib_conflict PRIVATE conflict)
file(WRITE "${CMAKE_BINARY_DIR}/testlib_noconflict.c" "__declspec(dllimport) extern void libdir(void);\n__declspec(dllexport) void testlib_noconflict(void)\n{\n libdir();\n}\n")
add_library(testlib_noconflict SHARED "${CMAKE_BINARY_DIR}/testlib_noconflict.c")
target_link_libraries(testlib_noconflict PRIVATE libdir)
install(TARGETS testlib libdir_postexcluded libdir conflict testlib_noconflict DESTINATION bin)
install(TARGETS libdir search_postexcluded search DESTINATION bin/.search) # Prefixing with "." ensures it is the first item after list(SORT)
install(TARGETS testlib_conflict conflict DESTINATION bin/.conflict)
add_executable(topexe file-GET_RUNTIME_DEPENDENCIES-windows/topexe.c)
add_library(toplib SHARED file-GET_RUNTIME_DEPENDENCIES-windows/toplib.c)
add_library(topmod MODULE file-GET_RUNTIME_DEPENDENCIES-windows/toplib.c)
target_link_libraries(topexe PRIVATE testlib)
target_link_libraries(toplib PRIVATE testlib)
target_link_libraries(topmod PRIVATE testlib)
install(TARGETS topexe toplib topmod DESTINATION bin)
install(CODE [[
function(exec_get_runtime_dependencies depsfile udepsfile cdepsfile)
file(GET_RUNTIME_DEPENDENCIES
RESOLVED_DEPENDENCIES_VAR deps
UNRESOLVED_DEPENDENCIES_VAR udeps
CONFLICTING_DEPENDENCIES_PREFIX cdeps
PRE_INCLUDE_REGEXES
"^(lib)?testlib\\.dll$"
"^(lib)?libdir_postexcluded\\.dll$"
"^(lib)?libdir\\.dll$"
"^(lib)?search_postexcluded\\.dll$"
"^(lib)?search\\.dll$"
"^(lib)?unresolved\\.dll$"
"^(lib)?conflict\\.dll$"
"^kernel32\\.dll$"
PRE_EXCLUDE_REGEXES ".*"
POST_INCLUDE_REGEXES
"^.*/(lib)?testlib\\.dll$"
"^.*/(lib)?libdir\\.dll$"
"^.*/(lib)?search\\.dll$"
"^.*/(lib)?conflict\\.dll$"
POST_EXCLUDE_REGEXES ".*"
DIRECTORIES
"${CMAKE_INSTALL_PREFIX}/bin/.search"
${ARGN}
)
list(SORT deps)
list(SORT udeps)
list(SORT cdeps_FILENAMES)
file(WRITE "${CMAKE_INSTALL_PREFIX}/deps/${depsfile}" "${deps}")
file(WRITE "${CMAKE_INSTALL_PREFIX}/deps/${udepsfile}" "${udeps}")
file(WRITE "${CMAKE_INSTALL_PREFIX}/deps/${cdepsfile}" "")
foreach(cdep IN LISTS cdeps_FILENAMES)
set(cdep_values ${cdeps_${cdep}})
list(SORT cdep_values)
file(APPEND "${CMAKE_INSTALL_PREFIX}/deps/${cdepsfile}" "${cdep}:${cdep_values}\n")
endforeach()
endfunction()
exec_get_runtime_dependencies(
deps1.txt udeps1.txt cdeps1.txt
EXECUTABLES
"${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:topexe>"
LIBRARIES
"${CMAKE_INSTALL_PREFIX}/bin/.conflict/$<TARGET_FILE_NAME:testlib_conflict>"
"${CMAKE_INSTALL_PREFIX}/bin/.conflict/../$<TARGET_FILE_NAME:testlib_noconflict>"
)
exec_get_runtime_dependencies(
deps2.txt udeps2.txt cdeps2.txt
LIBRARIES
"${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:toplib>"
"${CMAKE_INSTALL_PREFIX}/bin/.conflict/$<TARGET_FILE_NAME:testlib_conflict>"
"${CMAKE_INSTALL_PREFIX}/bin/.conflict/../$<TARGET_FILE_NAME:testlib_noconflict>"
)
exec_get_runtime_dependencies(
deps3.txt udeps3.txt cdeps3.txt
MODULES
"${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:topmod>"
LIBRARIES
"${CMAKE_INSTALL_PREFIX}/bin/.conflict/$<TARGET_FILE_NAME:testlib_conflict>"
"${CMAKE_INSTALL_PREFIX}/bin/.conflict/../$<TARGET_FILE_NAME:testlib_noconflict>"
)
]])

View File

@@ -0,0 +1,7 @@
__declspec(dllimport) extern void testlib(void);
int main(void)
{
testlib();
return 0;
}

View File

@@ -0,0 +1,6 @@
__declspec(dllimport) extern void testlib(void);
__declspec(dllexport) void toplib(void)
{
testlib();
}

View File

@@ -261,6 +261,17 @@ CMAKE_CXX_SOURCES="\
cmAddSubDirectoryCommand \
cmAddTestCommand \
cmArgumentParser \
cmBinUtilsLinker \
cmBinUtilsLinuxELFGetRuntimeDependenciesTool \
cmBinUtilsLinuxELFLinker \
cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool \
cmBinUtilsMacOSMachOGetRuntimeDependenciesTool \
cmBinUtilsMacOSMachOLinker \
cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool \
cmBinUtilsWindowsPEGetRuntimeDependenciesTool \
cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool \
cmBinUtilsWindowsPELinker \
cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool \
cmBreakCommand \
cmBuildCommand \
cmCMakeMinimumRequired \
@@ -357,6 +368,8 @@ CMAKE_CXX_SOURCES="\
cmInstallTargetGenerator \
cmInstallTargetsCommand \
cmInstalledFile \
cmLDConfigLDConfigTool \
cmLDConfigTool \
cmLinkDirectoriesCommand \
cmLinkItem \
cmLinkLineComputer \
@@ -394,6 +407,7 @@ CMAKE_CXX_SOURCES="\
cmPropertyMap \
cmReturnCommand \
cmRulePlaceholderExpander \
cmRuntimeDependencyArchive \
cmScriptGenerator \
cmSearchPath \
cmSeparateArgumentsCommand \
@@ -443,7 +457,9 @@ CMAKE_CXX_SOURCES="\
if ${cmake_system_mingw}; then
CMAKE_CXX_SOURCES="${CMAKE_CXX_SOURCES}\
cmGlobalMSYSMakefileGenerator \
cmGlobalMinGWMakefileGenerator"
cmGlobalMinGWMakefileGenerator \
cmVSSetupHelper \
"
fi
LexerParser_CXX_SOURCES="\
@@ -1370,7 +1386,7 @@ libs=""
uv_c_flags=""
if ${cmake_system_mingw}; then
uv_c_flags="${uv_c_flags} -DWIN32_LEAN_AND_MEAN -D_WIN32_WINNT=0x0600"
libs="${libs} -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv"
libs="${libs} -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -lole32 -loleaut32"
else
uv_c_flags="${uv_c_flags} -DCMAKE_BOOTSTRAP"
case "${cmake_system}" in