cmRuntimeDependencyArchive.cxx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  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 "cmVSSetupHelper.h"
  18. # include "cmsys/Glob.hxx"
  19. #endif
  20. #include <algorithm>
  21. #include <sstream>
  22. #include <string>
  23. #include <utility>
  24. #include <vector>
  25. #include "cm_memory.hxx"
  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 (gg->GetName().find(prefix) == 0) {
  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()) {
  198. cmExpandList(toolCommand, command);
  199. return true;
  200. }
  201. // Now go searching for it
  202. std::vector<std::string> paths;
  203. #ifdef _WIN32
  204. cmGlobalGenerator* gg = this->GetMakefile()->GetGlobalGenerator();
  205. // Add newer Visual Studio paths
  206. AddVisualStudioPath(paths, "Visual Studio 16 ", 16, gg);
  207. AddVisualStudioPath(paths, "Visual Studio 15 ", 15, gg);
  208. // Add older Visual Studio paths
  209. AddRegistryPath(
  210. paths,
  211. "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\14.0;InstallDir]/"
  212. "../../VC/bin",
  213. this->GetMakefile());
  214. AddEnvPath(paths, "VS140COMNTOOLS", "/../../VC/bin");
  215. paths.push_back(
  216. "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin");
  217. AddRegistryPath(
  218. paths,
  219. "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\12.0;InstallDir]/"
  220. "../../VC/bin",
  221. this->GetMakefile());
  222. AddEnvPath(paths, "VS120COMNTOOLS", "/../../VC/bin");
  223. paths.push_back(
  224. "C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin");
  225. AddRegistryPath(
  226. paths,
  227. "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\11.0;InstallDir]/"
  228. "../../VC/bin",
  229. this->GetMakefile());
  230. AddEnvPath(paths, "VS110COMNTOOLS", "/../../VC/bin");
  231. paths.push_back(
  232. "C:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/bin");
  233. AddRegistryPath(
  234. paths,
  235. "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;InstallDir]/"
  236. "../../VC/bin",
  237. this->GetMakefile());
  238. AddEnvPath(paths, "VS100COMNTOOLS", "/../../VC/bin");
  239. paths.push_back(
  240. "C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/bin");
  241. AddRegistryPath(
  242. paths,
  243. "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0;InstallDir]/"
  244. "../../VC/bin",
  245. this->GetMakefile());
  246. AddEnvPath(paths, "VS90COMNTOOLS", "/../../VC/bin");
  247. paths.push_back("C:/Program Files/Microsoft Visual Studio 9.0/VC/bin");
  248. paths.push_back("C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin");
  249. AddRegistryPath(
  250. paths,
  251. "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0;InstallDir]/"
  252. "../../VC/bin",
  253. this->GetMakefile());
  254. AddEnvPath(paths, "VS80COMNTOOLS", "/../../VC/bin");
  255. paths.push_back("C:/Program Files/Microsoft Visual Studio 8/VC/BIN");
  256. paths.push_back("C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN");
  257. AddRegistryPath(
  258. paths,
  259. "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.1;InstallDir]/"
  260. "../../VC7/bin",
  261. this->GetMakefile());
  262. AddEnvPath(paths, "VS71COMNTOOLS", "/../../VC7/bin");
  263. paths.push_back(
  264. "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN");
  265. paths.push_back(
  266. "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN");
  267. #endif
  268. std::string program = cmSystemTools::FindProgram(search, paths);
  269. if (!program.empty()) {
  270. command = { program };
  271. return true;
  272. }
  273. // Couldn't find it
  274. return false;
  275. }
  276. bool cmRuntimeDependencyArchive::IsPreExcluded(const std::string& name)
  277. {
  278. cmsys::RegularExpressionMatch match;
  279. for (auto const& regex : this->PreIncludeRegexes) {
  280. if (regex.find(name.c_str(), match)) {
  281. return false;
  282. }
  283. }
  284. for (auto const& regex : this->PreExcludeRegexes) {
  285. if (regex.find(name.c_str(), match)) {
  286. return true;
  287. }
  288. }
  289. return false;
  290. }
  291. bool cmRuntimeDependencyArchive::IsPostExcluded(const std::string& name)
  292. {
  293. cmsys::RegularExpressionMatch match;
  294. for (auto const& regex : this->PostIncludeRegexes) {
  295. if (regex.find(name.c_str(), match)) {
  296. return false;
  297. }
  298. }
  299. for (auto const& regex : this->PostExcludeRegexes) {
  300. if (regex.find(name.c_str(), match)) {
  301. return true;
  302. }
  303. }
  304. return false;
  305. }
  306. void cmRuntimeDependencyArchive::AddResolvedPath(const std::string& name,
  307. const std::string& path,
  308. bool& unique)
  309. {
  310. auto it = this->ResolvedPaths.emplace(name, std::set<std::string>{}).first;
  311. unique = true;
  312. for (auto const& other : it->second) {
  313. if (cmSystemTools::SameFile(path, other)) {
  314. unique = false;
  315. break;
  316. }
  317. }
  318. it->second.insert(path);
  319. }
  320. void cmRuntimeDependencyArchive::AddUnresolvedPath(const std::string& name)
  321. {
  322. this->UnresolvedPaths.insert(name);
  323. }
  324. cmMakefile* cmRuntimeDependencyArchive::GetMakefile()
  325. {
  326. return &this->Status.GetMakefile();
  327. }
  328. const std::map<std::string, std::set<std::string>>&
  329. cmRuntimeDependencyArchive::GetResolvedPaths()
  330. {
  331. return this->ResolvedPaths;
  332. }
  333. const std::set<std::string>& cmRuntimeDependencyArchive::GetUnresolvedPaths()
  334. {
  335. return this->UnresolvedPaths;
  336. }