CMake/Source/cmSearchPath.cxx
Nemanja Ivanovic e7f78309e7 find_library: Construct paths by removing 'unknown' from library arch
The compiler used for a build sometimes disagrees with
the remainder of the toolchain wrt. to the architecture
triple. Specifically, Clang will typically put its
libraries in `<arch>-unknown-<os>-<env>` but it uses
the GCC toolchain on many targets (which often has
its libraries in `<arch>-<os>-<env>`). In such cases
CMake will acquire the triple from Clang and use it
in library search paths for libraries that are provided
by the GCC toolchain. This of course fails due to the
mismatch.

This patch augments the list of search paths with ones
that include the architecture triple with any occurrences
of 'unknown' removed.

Fixes: #24175
2022-12-01 17:55:39 -05:00

244 lines
7.2 KiB
C++

/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmSearchPath.h"
#include <algorithm>
#include <cassert>
#include <utility>
#include <cm/optional>
#include "cmFindCommon.h"
#include "cmMakefile.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmValue.h"
#include "cmWindowsRegistry.h"
cmSearchPath::cmSearchPath(cmFindCommon* findCmd)
: FC(findCmd)
{
}
cmSearchPath::~cmSearchPath() = default;
void cmSearchPath::ExtractWithout(const std::set<std::string>& ignorePaths,
const std::set<std::string>& ignorePrefixes,
std::vector<std::string>& outPaths,
bool clear) const
{
if (clear) {
outPaths.clear();
}
for (auto const& path : this->Paths) {
if (ignorePaths.count(path.Path) == 0 &&
ignorePrefixes.count(path.Prefix) == 0) {
outPaths.push_back(path.Path);
}
}
}
void cmSearchPath::AddPath(const std::string& path)
{
this->AddPathInternal(path, "");
}
void cmSearchPath::AddUserPath(const std::string& path)
{
assert(this->FC != nullptr);
std::vector<std::string> outPaths;
cmWindowsRegistry registry(*this->FC->Makefile,
cmWindowsRegistry::SimpleTypes);
auto expandedPaths = registry.ExpandExpression(path, this->FC->RegistryView);
if (expandedPaths) {
for (const auto& expandedPath : expandedPaths.value()) {
cmSystemTools::GlobDirs(expandedPath, outPaths);
}
}
// Process them all from the current directory
for (std::string const& p : outPaths) {
this->AddPathInternal(
p, "", this->FC->Makefile->GetCurrentSourceDirectory().c_str());
}
}
void cmSearchPath::AddCMakePath(const std::string& variable)
{
assert(this->FC != nullptr);
// Get a path from a CMake variable.
if (cmValue value = this->FC->Makefile->GetDefinition(variable)) {
std::vector<std::string> expanded = cmExpandedList(*value);
for (std::string const& p : expanded) {
this->AddPathInternal(
p, "", this->FC->Makefile->GetCurrentSourceDirectory().c_str());
}
}
}
void cmSearchPath::AddEnvPath(const std::string& variable)
{
std::vector<std::string> expanded;
cmSystemTools::GetPath(expanded, variable.c_str());
for (std::string const& p : expanded) {
this->AddPathInternal(p, "");
}
}
void cmSearchPath::AddCMakePrefixPath(const std::string& variable)
{
assert(this->FC != nullptr);
// Get a path from a CMake variable.
if (cmValue value = this->FC->Makefile->GetDefinition(variable)) {
std::vector<std::string> expanded = cmExpandedList(*value);
this->AddPrefixPaths(
expanded, this->FC->Makefile->GetCurrentSourceDirectory().c_str());
}
}
static std::string cmSearchPathStripBin(std::string const& s)
{
// If the path is a PREFIX/bin case then add its parent instead.
if ((cmHasLiteralSuffix(s, "/bin")) || (cmHasLiteralSuffix(s, "/sbin"))) {
return cmSystemTools::GetFilenamePath(s);
}
return s;
}
void cmSearchPath::AddEnvPrefixPath(const std::string& variable, bool stripBin)
{
std::vector<std::string> expanded;
cmSystemTools::GetPath(expanded, variable.c_str());
if (stripBin) {
std::transform(expanded.begin(), expanded.end(), expanded.begin(),
cmSearchPathStripBin);
}
this->AddPrefixPaths(expanded);
}
void cmSearchPath::AddSuffixes(const std::vector<std::string>& suffixes)
{
std::vector<PathWithPrefix> inPaths;
inPaths.swap(this->Paths);
this->Paths.reserve(inPaths.size() * (suffixes.size() + 1));
for (PathWithPrefix& inPath : inPaths) {
cmSystemTools::ConvertToUnixSlashes(inPath.Path);
cmSystemTools::ConvertToUnixSlashes(inPath.Prefix);
// if *i is only / then do not add a //
// this will get incorrectly considered a network
// path on windows and cause huge delays.
std::string p = inPath.Path;
if (!p.empty() && p.back() != '/') {
p += "/";
}
// Combine with all the suffixes
for (std::string const& suffix : suffixes) {
this->Paths.push_back(PathWithPrefix{ p + suffix, inPath.Prefix });
}
// And now the original w/o any suffix
this->Paths.push_back(std::move(inPath));
}
}
void cmSearchPath::AddPrefixPaths(const std::vector<std::string>& paths,
const char* base)
{
assert(this->FC != nullptr);
// default for programs
std::string subdir = "bin";
if (this->FC->CMakePathName == "INCLUDE") {
subdir = "include";
} else if (this->FC->CMakePathName == "LIBRARY") {
subdir = "lib";
} else if (this->FC->CMakePathName == "FRAMEWORK") {
subdir.clear(); // ? what to do for frameworks ?
}
for (std::string const& path : paths) {
std::string dir = path;
if (!subdir.empty() && !dir.empty() && dir.back() != '/') {
dir += "/";
}
std::string prefix = dir;
if (!prefix.empty() && prefix != "/") {
prefix.erase(prefix.size() - 1);
}
if (subdir == "include" || subdir == "lib") {
cmValue arch =
this->FC->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE");
if (cmNonempty(arch)) {
std::string archNoUnknown = arch;
auto unknownAtPos = archNoUnknown.find("-unknown-");
bool foundUnknown = unknownAtPos != std::string::npos;
if (foundUnknown) {
// Replace "-unknown-" with "-".
archNoUnknown.replace(unknownAtPos, 9, "-");
}
if (this->FC->Makefile->IsDefinitionSet("CMAKE_SYSROOT") &&
this->FC->Makefile->IsDefinitionSet(
"CMAKE_PREFIX_LIBRARY_ARCHITECTURE")) {
if (foundUnknown) {
this->AddPathInternal(cmStrCat('/', archNoUnknown, dir, subdir),
cmStrCat('/', archNoUnknown, prefix), base);
}
this->AddPathInternal(cmStrCat('/', *arch, dir, subdir),
cmStrCat('/', *arch, prefix), base);
} else {
if (foundUnknown) {
this->AddPathInternal(cmStrCat(dir, subdir, '/', archNoUnknown),
prefix, base);
}
this->AddPathInternal(cmStrCat(dir, subdir, '/', *arch), prefix,
base);
}
}
}
std::string add = dir + subdir;
if (add != "/") {
this->AddPathInternal(add, prefix, base);
}
if (subdir == "bin") {
this->AddPathInternal(dir + "sbin", prefix, base);
}
if (!subdir.empty() && path != "/") {
this->AddPathInternal(path, prefix, base);
}
}
}
void cmSearchPath::AddPathInternal(const std::string& path,
const std::string& prefix, const char* base)
{
assert(this->FC != nullptr);
std::string collapsedPath = cmSystemTools::CollapseFullPath(path, base);
if (collapsedPath.empty()) {
return;
}
std::string collapsedPrefix;
if (!prefix.empty()) {
collapsedPrefix = cmSystemTools::CollapseFullPath(prefix, base);
}
// Insert the path if has not already been emitted.
PathWithPrefix pathWithPrefix{ std::move(collapsedPath),
std::move(collapsedPrefix) };
if (this->FC->SearchPathsEmitted.insert(pathWithPrefix).second) {
this->Paths.emplace_back(std::move(pathWithPrefix));
}
}