1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
4 #include "cmRuntimeDependencyArchive.h"
14 #include "cmBinUtilsLinuxELFLinker.h"
15 #include "cmBinUtilsMacOSMachOLinker.h"
16 #include "cmBinUtilsWindowsPELinker.h"
17 #include "cmExecutionStatus.h"
19 #include "cmMakefile.h"
20 #include "cmStateTypes.h"
21 #include "cmSystemTools.h"
24 # include "cmGlobalGenerator.h"
25 # ifndef CMAKE_BOOTSTRAP
26 # include "cmGlobalVisualStudioVersionedGenerator.h"
28 # include "cmsys/Glob.hxx"
30 # include "cmVSSetupHelper.h"
34 static void AddVisualStudioPath(std::vector
<std::string
>& paths
,
35 const std::string
& prefix
,
36 unsigned int version
, cmGlobalGenerator
* gg
)
38 // If generating for the VS IDE, use the same instance.
41 # ifndef CMAKE_BOOTSTRAP
42 if (cmHasPrefix(gg
->GetName(), prefix
)) {
43 cmGlobalVisualStudioVersionedGenerator
* vsgen
=
44 static_cast<cmGlobalVisualStudioVersionedGenerator
*>(gg
);
45 if (vsgen
->GetVSInstance(vsloc
)) {
51 // Otherwise, find a VS instance ourselves.
53 cmVSSetupAPIHelper
vsSetupAPIHelper(version
);
54 if (vsSetupAPIHelper
.GetVSInstanceInfo(vsloc
)) {
55 cmSystemTools::ConvertToUnixSlashes(vsloc
);
62 glob
.SetListDirs(true);
63 glob
.FindFiles(vsloc
+ "/VC/Tools/MSVC/*");
64 for (auto const& vcdir
: glob
.GetFiles()) {
65 paths
.push_back(vcdir
+ "/bin/Hostx64/x64");
66 paths
.push_back(vcdir
+ "/bin/Hostx86/x64");
67 paths
.push_back(vcdir
+ "/bin/Hostx64/x86");
68 paths
.push_back(vcdir
+ "/bin/Hostx86/x86");
73 static void AddRegistryPath(std::vector
<std::string
>& paths
,
74 const std::string
& path
, cmMakefile
* mf
)
76 // We should view the registry as the target application would view
78 cmSystemTools::KeyWOW64 view
= cmSystemTools::KeyWOW64_32
;
79 cmSystemTools::KeyWOW64 other_view
= cmSystemTools::KeyWOW64_64
;
80 if (mf
->PlatformIs64Bit()) {
81 view
= cmSystemTools::KeyWOW64_64
;
82 other_view
= cmSystemTools::KeyWOW64_32
;
85 // Expand using the view of the target application.
86 std::string expanded
= path
;
87 cmSystemTools::ExpandRegistryValues(expanded
, view
);
88 cmSystemTools::GlobDirs(expanded
, paths
);
90 // Executables can be either 32-bit or 64-bit, so expand using the
93 cmSystemTools::ExpandRegistryValues(expanded
, other_view
);
94 cmSystemTools::GlobDirs(expanded
, paths
);
97 static void AddEnvPath(std::vector
<std::string
>& paths
, const std::string
& var
,
98 const std::string
& suffix
)
101 if (cmSystemTools::GetEnv(var
, value
)) {
102 paths
.push_back(value
+ suffix
);
107 static cmsys::RegularExpression
TransformCompile(const std::string
& str
)
109 return cmsys::RegularExpression(str
);
112 cmRuntimeDependencyArchive::cmRuntimeDependencyArchive(
113 cmExecutionStatus
& status
, std::vector
<std::string
> searchDirectories
,
114 std::string bundleExecutable
,
115 const std::vector
<std::string
>& preIncludeRegexes
,
116 const std::vector
<std::string
>& preExcludeRegexes
,
117 const std::vector
<std::string
>& postIncludeRegexes
,
118 const std::vector
<std::string
>& postExcludeRegexes
,
119 std::vector
<std::string
> postIncludeFiles
,
120 std::vector
<std::string
> postExcludeFiles
,
121 std::vector
<std::string
> postExcludeFilesStrict
)
123 , SearchDirectories(std::move(searchDirectories
))
124 , BundleExecutable(std::move(bundleExecutable
))
125 , PreIncludeRegexes(preIncludeRegexes
.size())
126 , PreExcludeRegexes(preExcludeRegexes
.size())
127 , PostIncludeRegexes(postIncludeRegexes
.size())
128 , PostExcludeRegexes(postExcludeRegexes
.size())
129 , PostIncludeFiles(std::move(postIncludeFiles
))
130 , PostExcludeFiles(std::move(postExcludeFiles
))
131 , PostExcludeFilesStrict(std::move(postExcludeFilesStrict
))
133 std::transform(preIncludeRegexes
.begin(), preIncludeRegexes
.end(),
134 this->PreIncludeRegexes
.begin(), TransformCompile
);
135 std::transform(preExcludeRegexes
.begin(), preExcludeRegexes
.end(),
136 this->PreExcludeRegexes
.begin(), TransformCompile
);
137 std::transform(postIncludeRegexes
.begin(), postIncludeRegexes
.end(),
138 this->PostIncludeRegexes
.begin(), TransformCompile
);
139 std::transform(postExcludeRegexes
.begin(), postExcludeRegexes
.end(),
140 this->PostExcludeRegexes
.begin(), TransformCompile
);
143 bool cmRuntimeDependencyArchive::Prepare()
145 std::string platform
= this->GetMakefile()->GetSafeDefinition(
146 "CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM");
147 if (platform
.empty()) {
148 std::string systemName
=
149 this->GetMakefile()->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
150 if (systemName
== "Windows") {
151 platform
= "windows+pe";
152 } else if (systemName
== "Darwin") {
153 platform
= "macos+macho";
154 } else if (systemName
== "Linux") {
155 platform
= "linux+elf";
158 if (platform
== "linux+elf") {
159 this->Linker
= cm::make_unique
<cmBinUtilsLinuxELFLinker
>(this);
160 } else if (platform
== "windows+pe") {
161 this->Linker
= cm::make_unique
<cmBinUtilsWindowsPELinker
>(this);
162 } else if (platform
== "macos+macho") {
163 this->Linker
= cm::make_unique
<cmBinUtilsMacOSMachOLinker
>(this);
165 std::ostringstream e
;
166 e
<< "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM: "
168 this->SetError(e
.str());
172 return this->Linker
->Prepare();
175 bool cmRuntimeDependencyArchive::GetRuntimeDependencies(
176 const std::vector
<std::string
>& executables
,
177 const std::vector
<std::string
>& libraries
,
178 const std::vector
<std::string
>& modules
)
180 for (auto const& exe
: executables
) {
181 if (!this->Linker
->ScanDependencies(exe
, cmStateEnums::EXECUTABLE
)) {
185 for (auto const& lib
: libraries
) {
186 if (!this->Linker
->ScanDependencies(lib
, cmStateEnums::SHARED_LIBRARY
)) {
191 modules
.begin(), modules
.end(), [this](std::string
const& mod
) -> bool {
192 return this->Linker
->ScanDependencies(mod
, cmStateEnums::MODULE_LIBRARY
);
196 void cmRuntimeDependencyArchive::SetError(const std::string
& e
)
198 this->Status
.SetError(e
);
201 const std::string
& cmRuntimeDependencyArchive::GetBundleExecutable() const
203 return this->BundleExecutable
;
206 const std::vector
<std::string
>&
207 cmRuntimeDependencyArchive::GetSearchDirectories() const
209 return this->SearchDirectories
;
212 const std::string
& cmRuntimeDependencyArchive::GetGetRuntimeDependenciesTool()
215 return this->GetMakefile()->GetSafeDefinition(
216 "CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL");
219 bool cmRuntimeDependencyArchive::GetGetRuntimeDependenciesCommand(
220 const std::string
& search
, std::vector
<std::string
>& command
) const
222 // First see if it was supplied by the user
223 std::string toolCommand
= this->GetMakefile()->GetSafeDefinition(
224 "CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND");
225 if (toolCommand
.empty() && search
== "objdump") {
226 toolCommand
= this->GetMakefile()->GetSafeDefinition("CMAKE_OBJDUMP");
228 if (!toolCommand
.empty()) {
229 cmExpandList(toolCommand
, command
);
233 // Now go searching for it
234 std::vector
<std::string
> paths
;
236 cmGlobalGenerator
* gg
= this->GetMakefile()->GetGlobalGenerator();
238 // Add newer Visual Studio paths
239 AddVisualStudioPath(paths
, "Visual Studio 17 ", 17, gg
);
240 AddVisualStudioPath(paths
, "Visual Studio 16 ", 16, gg
);
241 AddVisualStudioPath(paths
, "Visual Studio 15 ", 15, gg
);
243 // Add older Visual Studio paths
246 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\14.0;InstallDir]/"
248 this->GetMakefile());
249 AddEnvPath(paths
, "VS140COMNTOOLS", "/../../VC/bin");
251 "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin");
254 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\12.0;InstallDir]/"
256 this->GetMakefile());
257 AddEnvPath(paths
, "VS120COMNTOOLS", "/../../VC/bin");
259 "C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin");
262 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\11.0;InstallDir]/"
264 this->GetMakefile());
265 AddEnvPath(paths
, "VS110COMNTOOLS", "/../../VC/bin");
267 "C:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/bin");
270 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;InstallDir]/"
272 this->GetMakefile());
273 AddEnvPath(paths
, "VS100COMNTOOLS", "/../../VC/bin");
275 "C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/bin");
278 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0;InstallDir]/"
280 this->GetMakefile());
281 AddEnvPath(paths
, "VS90COMNTOOLS", "/../../VC/bin");
282 paths
.push_back("C:/Program Files/Microsoft Visual Studio 9.0/VC/bin");
283 paths
.push_back("C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin");
286 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0;InstallDir]/"
288 this->GetMakefile());
289 AddEnvPath(paths
, "VS80COMNTOOLS", "/../../VC/bin");
290 paths
.push_back("C:/Program Files/Microsoft Visual Studio 8/VC/BIN");
291 paths
.push_back("C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN");
294 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.1;InstallDir]/"
296 this->GetMakefile());
297 AddEnvPath(paths
, "VS71COMNTOOLS", "/../../VC7/bin");
299 "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN");
301 "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN");
304 std::string program
= cmSystemTools::FindProgram(search
, paths
);
305 if (!program
.empty()) {
306 command
= { program
};
314 bool cmRuntimeDependencyArchive::IsPreExcluded(const std::string
& name
) const
316 cmsys::RegularExpressionMatch match
;
317 auto const regexMatch
=
318 [&match
, name
](const cmsys::RegularExpression
& regex
) -> bool {
319 return regex
.find(name
.c_str(), match
);
321 auto const regexSearch
=
323 const std::vector
<cmsys::RegularExpression
>& regexes
) -> bool {
324 return std::any_of(regexes
.begin(), regexes
.end(), regexMatch
);
327 return !regexSearch(this->PreIncludeRegexes
) &&
328 regexSearch(this->PreExcludeRegexes
);
331 bool cmRuntimeDependencyArchive::IsPostExcluded(const std::string
& name
) const
333 cmsys::RegularExpressionMatch match
;
334 auto const regexMatch
=
335 [&match
, name
](const cmsys::RegularExpression
& regex
) -> bool {
336 return regex
.find(name
.c_str(), match
);
338 auto const regexSearch
=
340 const std::vector
<cmsys::RegularExpression
>& regexes
) -> bool {
341 return std::any_of(regexes
.begin(), regexes
.end(), regexMatch
);
343 auto const fileMatch
= [name
](const std::string
& file
) -> bool {
344 return cmSystemTools::SameFile(file
, name
);
346 auto const fileSearch
=
347 [&fileMatch
](const std::vector
<std::string
>& files
) -> bool {
348 return std::any_of(files
.begin(), files
.end(), fileMatch
);
351 return fileSearch(this->PostExcludeFilesStrict
) ||
352 (!(regexSearch(this->PostIncludeRegexes
) ||
353 fileSearch(this->PostIncludeFiles
)) &&
354 (regexSearch(this->PostExcludeRegexes
) ||
355 fileSearch(this->PostExcludeFiles
)));
358 void cmRuntimeDependencyArchive::AddResolvedPath(
359 const std::string
& name
, const std::string
& path
, bool& unique
,
360 std::vector
<std::string
> rpaths
)
362 auto it
= this->ResolvedPaths
.emplace(name
, std::set
<std::string
>{}).first
;
364 for (auto const& other
: it
->second
) {
365 if (cmSystemTools::SameFile(path
, other
)) {
370 it
->second
.insert(path
);
371 this->RPaths
[path
] = std::move(rpaths
);
374 void cmRuntimeDependencyArchive::AddUnresolvedPath(const std::string
& name
)
376 this->UnresolvedPaths
.insert(name
);
379 cmMakefile
* cmRuntimeDependencyArchive::GetMakefile() const
381 return &this->Status
.GetMakefile();
384 const std::map
<std::string
, std::set
<std::string
>>&
385 cmRuntimeDependencyArchive::GetResolvedPaths() const
387 return this->ResolvedPaths
;
390 const std::set
<std::string
>& cmRuntimeDependencyArchive::GetUnresolvedPaths()
393 return this->UnresolvedPaths
;
396 const std::map
<std::string
, std::vector
<std::string
>>&
397 cmRuntimeDependencyArchive::GetRPaths() const
402 bool cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies(
403 const std::string
& platform
)
405 static const std::set
<std::string
> supportedPlatforms
= { "Windows", "Linux",
407 return supportedPlatforms
.count(platform
);