cmRuntimeDependencyArchive.cxx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmRuntimeDependencyArchive.h"
  4. #include "cmBinUtilsLinuxELFLinker.h"
  5. #include "cmBinUtilsMacOSMachOLinker.h"
  6. #include "cmBinUtilsWindowsPELinker.h"
  7. #include "cmExecutionStatus.h"
  8. #include "cmMakefile.h"
  9. #include "cmStateTypes.h"
  10. #include "cmStringAlgorithms.h"
  11. #include "cmSystemTools.h"
  12. #if defined(_WIN32)
  13. # include "cmGlobalGenerator.h"
  14. # ifndef CMAKE_BOOTSTRAP
  15. # include "cmGlobalVisualStudioVersionedGenerator.h"
  16. # endif
  17. # include "cmsys/Glob.hxx"
  18. # include "cmVSSetupHelper.h"
  19. #endif
  20. #include <algorithm>
  21. #include <sstream>
  22. #include <string>
  23. #include <utility>
  24. #include <vector>
  25. #include <cm/memory>
  26. #if defined(_WIN32)
  27. static void AddVisualStudioPath(std::vector<std::string>& paths,
  28. const std::string& prefix,
  29. unsigned int version, cmGlobalGenerator* gg)
  30. {
  31. // If generating for the VS IDE, use the same instance.
  32. std::string vsloc;
  33. bool found = false;
  34. # ifndef CMAKE_BOOTSTRAP
  35. if (cmHasPrefix(gg->GetName(), prefix)) {
  36. cmGlobalVisualStudioVersionedGenerator* vsgen =
  37. static_cast<cmGlobalVisualStudioVersionedGenerator*>(gg);
  38. if (vsgen->GetVSInstance(vsloc)) {
  39. found = true;
  40. }
  41. }
  42. # endif
  43. // Otherwise, find a VS instance ourselves.
  44. if (!found) {
  45. cmVSSetupAPIHelper vsSetupAPIHelper(version);
  46. if (vsSetupAPIHelper.GetVSInstanceInfo(vsloc)) {
  47. cmSystemTools::ConvertToUnixSlashes(vsloc);
  48. found = true;
  49. }
  50. }
  51. if (found) {
  52. cmsys::Glob glob;
  53. glob.SetListDirs(true);
  54. glob.FindFiles(vsloc + "/VC/Tools/MSVC/*");
  55. for (auto const& vcdir : glob.GetFiles()) {
  56. paths.push_back(vcdir + "/bin/Hostx64/x64");
  57. paths.push_back(vcdir + "/bin/Hostx86/x64");
  58. paths.push_back(vcdir + "/bin/Hostx64/x86");
  59. paths.push_back(vcdir + "/bin/Hostx86/x86");
  60. }
  61. }
  62. }
  63. static void AddRegistryPath(std::vector<std::string>& paths,
  64. const std::string& path, cmMakefile* mf)
  65. {
  66. // We should view the registry as the target application would view
  67. // it.
  68. cmSystemTools::KeyWOW64 view = cmSystemTools::KeyWOW64_32;
  69. cmSystemTools::KeyWOW64 other_view = cmSystemTools::KeyWOW64_64;
  70. if (mf->PlatformIs64Bit()) {
  71. view = cmSystemTools::KeyWOW64_64;
  72. other_view = cmSystemTools::KeyWOW64_32;
  73. }
  74. // Expand using the view of the target application.
  75. std::string expanded = path;
  76. cmSystemTools::ExpandRegistryValues(expanded, view);
  77. cmSystemTools::GlobDirs(expanded, paths);
  78. // Executables can be either 32-bit or 64-bit, so expand using the
  79. // alternative view.
  80. expanded = path;
  81. cmSystemTools::ExpandRegistryValues(expanded, other_view);
  82. cmSystemTools::GlobDirs(expanded, paths);
  83. }
  84. static void AddEnvPath(std::vector<std::string>& paths, const std::string& var,
  85. const std::string& suffix)
  86. {
  87. std::string value;
  88. if (cmSystemTools::GetEnv(var, value)) {
  89. paths.push_back(value + suffix);
  90. }
  91. }
  92. #endif
  93. static cmsys::RegularExpression TransformCompile(const std::string& str)
  94. {
  95. return cmsys::RegularExpression(str);
  96. }
  97. cmRuntimeDependencyArchive::cmRuntimeDependencyArchive(
  98. cmExecutionStatus& status, std::vector<std::string> searchDirectories,
  99. std::string bundleExecutable,
  100. const std::vector<std::string>& preIncludeRegexes,
  101. const std::vector<std::string>& preExcludeRegexes,
  102. const std::vector<std::string>& postIncludeRegexes,
  103. const std::vector<std::string>& postExcludeRegexes)
  104. : Status(status)
  105. , SearchDirectories(std::move(searchDirectories))
  106. , BundleExecutable(std::move(bundleExecutable))
  107. , PreIncludeRegexes(preIncludeRegexes.size())
  108. , PreExcludeRegexes(preExcludeRegexes.size())
  109. , PostIncludeRegexes(postIncludeRegexes.size())
  110. , PostExcludeRegexes(postExcludeRegexes.size())
  111. {
  112. std::transform(preIncludeRegexes.begin(), preIncludeRegexes.end(),
  113. this->PreIncludeRegexes.begin(), TransformCompile);
  114. std::transform(preExcludeRegexes.begin(), preExcludeRegexes.end(),
  115. this->PreExcludeRegexes.begin(), TransformCompile);
  116. std::transform(postIncludeRegexes.begin(), postIncludeRegexes.end(),
  117. this->PostIncludeRegexes.begin(), TransformCompile);
  118. std::transform(postExcludeRegexes.begin(), postExcludeRegexes.end(),
  119. this->PostExcludeRegexes.begin(), TransformCompile);
  120. }
  121. bool cmRuntimeDependencyArchive::Prepare()
  122. {
  123. std::string platform = this->GetMakefile()->GetSafeDefinition(
  124. "CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM");
  125. if (platform.empty()) {
  126. std::string systemName =
  127. this->GetMakefile()->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
  128. if (systemName == "Windows") {
  129. platform = "windows+pe";
  130. } else if (systemName == "Darwin") {
  131. platform = "macos+macho";
  132. } else if (systemName == "Linux") {
  133. platform = "linux+elf";
  134. }
  135. }
  136. if (platform == "linux+elf") {
  137. this->Linker = cm::make_unique<cmBinUtilsLinuxELFLinker>(this);
  138. } else if (platform == "windows+pe") {
  139. this->Linker = cm::make_unique<cmBinUtilsWindowsPELinker>(this);
  140. } else if (platform == "macos+macho") {
  141. this->Linker = cm::make_unique<cmBinUtilsMacOSMachOLinker>(this);
  142. } else {
  143. std::ostringstream e;
  144. e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM: "
  145. << platform;
  146. this->SetError(e.str());
  147. return false;
  148. }
  149. return this->Linker->Prepare();
  150. }
  151. bool cmRuntimeDependencyArchive::GetRuntimeDependencies(
  152. const std::vector<std::string>& executables,
  153. const std::vector<std::string>& libraries,
  154. const std::vector<std::string>& modules)
  155. {
  156. for (auto const& exe : executables) {
  157. if (!this->Linker->ScanDependencies(exe, cmStateEnums::EXECUTABLE)) {
  158. return false;
  159. }
  160. }
  161. for (auto const& lib : libraries) {
  162. if (!this->Linker->ScanDependencies(lib, cmStateEnums::SHARED_LIBRARY)) {
  163. return false;
  164. }
  165. }
  166. for (auto const& mod : modules) {
  167. if (!this->Linker->ScanDependencies(mod, cmStateEnums::MODULE_LIBRARY)) {
  168. return false;
  169. }
  170. }
  171. return true;
  172. }
  173. void cmRuntimeDependencyArchive::SetError(const std::string& e)
  174. {
  175. this->Status.SetError(e);
  176. }
  177. std::string cmRuntimeDependencyArchive::GetBundleExecutable()
  178. {
  179. return this->BundleExecutable;
  180. }
  181. const std::vector<std::string>&
  182. cmRuntimeDependencyArchive::GetSearchDirectories()
  183. {
  184. return this->SearchDirectories;
  185. }
  186. std::string cmRuntimeDependencyArchive::GetGetRuntimeDependenciesTool()
  187. {
  188. return this->GetMakefile()->GetSafeDefinition(
  189. "CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL");
  190. }
  191. bool cmRuntimeDependencyArchive::GetGetRuntimeDependenciesCommand(
  192. const std::string& search, std::vector<std::string>& command)
  193. {
  194. // First see if it was supplied by the user
  195. std::string toolCommand = this->GetMakefile()->GetSafeDefinition(
  196. "CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND");
  197. if (toolCommand.empty() && search == "objdump") {
  198. toolCommand = this->GetMakefile()->GetSafeDefinition("CMAKE_OBJDUMP");
  199. }
  200. if (!toolCommand.empty()) {
  201. cmExpandList(toolCommand, command);
  202. return true;
  203. }
  204. // Now go searching for it
  205. std::vector<std::string> paths;
  206. #ifdef _WIN32
  207. cmGlobalGenerator* gg = this->GetMakefile()->GetGlobalGenerator();
  208. // Add newer Visual Studio paths
  209. AddVisualStudioPath(paths, "Visual Studio 16 ", 16, gg);
  210. AddVisualStudioPath(paths, "Visual Studio 15 ", 15, gg);
  211. // Add older Visual Studio paths
  212. AddRegistryPath(
  213. paths,
  214. "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\14.0;InstallDir]/"
  215. "../../VC/bin",
  216. this->GetMakefile());
  217. AddEnvPath(paths, "VS140COMNTOOLS", "/../../VC/bin");
  218. paths.push_back(
  219. "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin");
  220. AddRegistryPath(
  221. paths,
  222. "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\12.0;InstallDir]/"
  223. "../../VC/bin",
  224. this->GetMakefile());
  225. AddEnvPath(paths, "VS120COMNTOOLS", "/../../VC/bin");
  226. paths.push_back(
  227. "C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin");
  228. AddRegistryPath(
  229. paths,
  230. "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\11.0;InstallDir]/"
  231. "../../VC/bin",
  232. this->GetMakefile());
  233. AddEnvPath(paths, "VS110COMNTOOLS", "/../../VC/bin");
  234. paths.push_back(
  235. "C:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/bin");
  236. AddRegistryPath(
  237. paths,
  238. "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;InstallDir]/"
  239. "../../VC/bin",
  240. this->GetMakefile());
  241. AddEnvPath(paths, "VS100COMNTOOLS", "/../../VC/bin");
  242. paths.push_back(
  243. "C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/bin");
  244. AddRegistryPath(
  245. paths,
  246. "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0;InstallDir]/"
  247. "../../VC/bin",
  248. this->GetMakefile());
  249. AddEnvPath(paths, "VS90COMNTOOLS", "/../../VC/bin");
  250. paths.push_back("C:/Program Files/Microsoft Visual Studio 9.0/VC/bin");
  251. paths.push_back("C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin");
  252. AddRegistryPath(
  253. paths,
  254. "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0;InstallDir]/"
  255. "../../VC/bin",
  256. this->GetMakefile());
  257. AddEnvPath(paths, "VS80COMNTOOLS", "/../../VC/bin");
  258. paths.push_back("C:/Program Files/Microsoft Visual Studio 8/VC/BIN");
  259. paths.push_back("C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN");
  260. AddRegistryPath(
  261. paths,
  262. "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.1;InstallDir]/"
  263. "../../VC7/bin",
  264. this->GetMakefile());
  265. AddEnvPath(paths, "VS71COMNTOOLS", "/../../VC7/bin");
  266. paths.push_back(
  267. "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN");
  268. paths.push_back(
  269. "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN");
  270. #endif
  271. std::string program = cmSystemTools::FindProgram(search, paths);
  272. if (!program.empty()) {
  273. command = { program };
  274. return true;
  275. }
  276. // Couldn't find it
  277. return false;
  278. }
  279. bool cmRuntimeDependencyArchive::IsPreExcluded(const std::string& name)
  280. {
  281. cmsys::RegularExpressionMatch match;
  282. for (auto const& regex : this->PreIncludeRegexes) {
  283. if (regex.find(name.c_str(), match)) {
  284. return false;
  285. }
  286. }
  287. for (auto const& regex : this->PreExcludeRegexes) {
  288. if (regex.find(name.c_str(), match)) {
  289. return true;
  290. }
  291. }
  292. return false;
  293. }
  294. bool cmRuntimeDependencyArchive::IsPostExcluded(const std::string& name)
  295. {
  296. cmsys::RegularExpressionMatch match;
  297. for (auto const& regex : this->PostIncludeRegexes) {
  298. if (regex.find(name.c_str(), match)) {
  299. return false;
  300. }
  301. }
  302. for (auto const& regex : this->PostExcludeRegexes) {
  303. if (regex.find(name.c_str(), match)) {
  304. return true;
  305. }
  306. }
  307. return false;
  308. }
  309. void cmRuntimeDependencyArchive::AddResolvedPath(const std::string& name,
  310. const std::string& path,
  311. bool& unique)
  312. {
  313. auto it = this->ResolvedPaths.emplace(name, std::set<std::string>{}).first;
  314. unique = true;
  315. for (auto const& other : it->second) {
  316. if (cmSystemTools::SameFile(path, other)) {
  317. unique = false;
  318. break;
  319. }
  320. }
  321. it->second.insert(path);
  322. }
  323. void cmRuntimeDependencyArchive::AddUnresolvedPath(const std::string& name)
  324. {
  325. this->UnresolvedPaths.insert(name);
  326. }
  327. cmMakefile* cmRuntimeDependencyArchive::GetMakefile()
  328. {
  329. return &this->Status.GetMakefile();
  330. }
  331. const std::map<std::string, std::set<std::string>>&
  332. cmRuntimeDependencyArchive::GetResolvedPaths()
  333. {
  334. return this->ResolvedPaths;
  335. }
  336. const std::set<std::string>& cmRuntimeDependencyArchive::GetUnresolvedPaths()
  337. {
  338. return this->UnresolvedPaths;
  339. }