|
|
|
/* 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 <algorithm>
|
|
|
|
#include <iterator>
|
|
|
|
#include <sstream>
|
|
|
|
#include <utility>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include <cm/memory>
|
|
|
|
|
|
|
|
#include "cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.h"
|
|
|
|
#include "cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h"
|
|
|
|
#include "cmRuntimeDependencyArchive.h"
|
|
|
|
#include "cmStringAlgorithms.h"
|
|
|
|
#include "cmSystemTools.h"
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
# include <windows.h>
|
|
|
|
|
|
|
|
# include "cmsys/Encoding.hxx"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
void ReplaceWithActualNameCasing(std::string& path)
|
|
|
|
{
|
|
|
|
WIN32_FIND_DATAW findData;
|
|
|
|
HANDLE hFind = ::FindFirstFileW(
|
|
|
|
cmsys::Encoding::ToWindowsExtendedPath(path).c_str(), &findData);
|
|
|
|
|
|
|
|
if (hFind != INVALID_HANDLE_VALUE) {
|
|
|
|
auto onDiskName = cmsys::Encoding::ToNarrow(findData.cFileName);
|
|
|
|
::FindClose(hFind);
|
|
|
|
path.replace(path.end() - onDiskName.size(), path.end(), onDiskName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
#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;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct WinPEDependency
|
|
|
|
{
|
|
|
|
WinPEDependency(std::string o)
|
|
|
|
: Original(std::move(o))
|
|
|
|
, LowerCase(cmSystemTools::LowerCase(Original))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
std::string const Original;
|
|
|
|
std::string const LowerCase;
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<WinPEDependency> depends;
|
|
|
|
depends.reserve(needed.size());
|
|
|
|
std::move(needed.begin(), needed.end(), std::back_inserter(depends));
|
|
|
|
std::string origin = cmSystemTools::GetFilenamePath(file);
|
|
|
|
|
|
|
|
for (auto const& lib : depends) {
|
|
|
|
if (!this->Archive->IsPreExcluded(lib.LowerCase)) {
|
|
|
|
std::string path;
|
|
|
|
bool resolved = false;
|
|
|
|
if (!this->ResolveDependency(lib.LowerCase, origin, path, resolved)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (resolved) {
|
|
|
|
if (!this->Archive->IsPostExcluded(path)) {
|
|
|
|
#ifdef _WIN32
|
|
|
|
ReplaceWithActualNameCasing(path);
|
|
|
|
#else
|
|
|
|
path.replace(path.end() - lib.Original.size(), path.end(),
|
|
|
|
lib.Original);
|
|
|
|
#endif
|
|
|
|
bool unique;
|
|
|
|
this->Archive->AddResolvedPath(lib.Original, path, unique);
|
|
|
|
if (unique &&
|
|
|
|
!this->ScanDependencies(path, cmStateEnums::SHARED_LIBRARY)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this->Archive->AddUnresolvedPath(lib.Original);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 = cmStrCat(searchPath, '/', name);
|
|
|
|
if (cmSystemTools::PathExists(path)) {
|
|
|
|
resolved = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
resolved = false;
|
|
|
|
return true;
|
|
|
|
}
|