1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file LICENSE.rst 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;
}
|