cmGlobalVisualStudio7Generator.cxx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file LICENSE.rst or https://cmake.org/licensing for details. */
  3. #include "cmGlobalVisualStudio7Generator.h"
  4. #include <algorithm>
  5. #include <cstdio>
  6. #include <ostream>
  7. #include <utility>
  8. #include <vector>
  9. #include <cm/memory>
  10. #include <cm/string_view>
  11. #include <windows.h>
  12. #include "cmGeneratedFileStream.h"
  13. #include "cmGeneratorExpression.h"
  14. #include "cmGeneratorTarget.h"
  15. #include "cmGlobalGenerator.h"
  16. #include "cmList.h"
  17. #include "cmLocalGenerator.h"
  18. #include "cmLocalVisualStudio7Generator.h"
  19. #include "cmMakefile.h"
  20. #include "cmMessageType.h"
  21. #include "cmState.h"
  22. #include "cmStateTypes.h"
  23. #include "cmStringAlgorithms.h"
  24. #include "cmSystemTools.h"
  25. #include "cmTarget.h"
  26. #include "cmTargetDepend.h"
  27. #include "cmVisualStudioGeneratorOptions.h"
  28. #include "cmake.h"
  29. static cmVS7FlagTable cmVS7ExtraFlagTable[] = {
  30. // Precompiled header and related options. Note that the
  31. // UsePrecompiledHeader entries are marked as "Continue" so that the
  32. // corresponding PrecompiledHeaderThrough entry can be found.
  33. { "UsePrecompiledHeader", "YX", "Automatically Generate", "2",
  34. cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
  35. { "PrecompiledHeaderThrough", "YX", "Precompiled Header Name", "",
  36. cmVS7FlagTable::UserValueRequired },
  37. { "UsePrecompiledHeader", "Yu", "Use Precompiled Header", "3",
  38. cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
  39. { "PrecompiledHeaderThrough", "Yu", "Precompiled Header Name", "",
  40. cmVS7FlagTable::UserValueRequired },
  41. { "UsePrecompiledHeader", "Y-", "Don't use precompiled header", "0", 0 },
  42. { "WholeProgramOptimization", "LTCG", "WholeProgramOptimization", "true",
  43. 0 },
  44. // Exception handling mode. If no entries match, it will be FALSE.
  45. { "ExceptionHandling", "GX", "enable c++ exceptions", "true", 0 },
  46. { "ExceptionHandling", "EHsc", "enable c++ exceptions", "true", 0 },
  47. // The EHa option does not have an IDE setting. Let it go to false,
  48. // and have EHa passed on the command line by leaving out the table
  49. // entry.
  50. { "", "", "", "", 0 }
  51. };
  52. cmGlobalVisualStudio7Generator::cmGlobalVisualStudio7Generator(cmake* cm)
  53. : cmGlobalVisualStudioGenerator(cm)
  54. {
  55. this->DevEnvCommandInitialized = false;
  56. this->MarmasmEnabled = false;
  57. this->MasmEnabled = false;
  58. this->NasmEnabled = false;
  59. this->ExtraFlagTable = cmVS7ExtraFlagTable;
  60. }
  61. cmGlobalVisualStudio7Generator::~cmGlobalVisualStudio7Generator() = default;
  62. // Package GUID of Intel Visual Fortran plugin to VS IDE
  63. #define CM_INTEL_PLUGIN_GUID "{B68A201D-CB9B-47AF-A52F-7EEC72E217E4}"
  64. std::string const& cmGlobalVisualStudio7Generator::GetIntelProjectVersion()
  65. {
  66. if (this->IntelProjectVersion.empty()) {
  67. // Compute the version of the Intel plugin to the VS IDE.
  68. // If the key does not exist then use a default guess.
  69. std::string intelVersion;
  70. std::string vskey =
  71. cmStrCat(this->GetRegistryBase(),
  72. "\\Packages\\" CM_INTEL_PLUGIN_GUID ";ProductVersion");
  73. cmSystemTools::ReadRegistryValue(vskey, intelVersion,
  74. cmSystemTools::KeyWOW64_32);
  75. unsigned int intelVersionNumber = ~0u;
  76. if (sscanf(intelVersion.c_str(), "%u", &intelVersionNumber) != 1 ||
  77. intelVersionNumber >= 11) {
  78. // Default to latest known project file version.
  79. intelVersion = "11.0";
  80. } else if (intelVersionNumber == 10) {
  81. // Version 10.x actually uses 9.10 in project files!
  82. intelVersion = "9.10";
  83. } else {
  84. // Version <= 9: use ProductVersion from registry.
  85. }
  86. this->IntelProjectVersion = intelVersion;
  87. }
  88. return this->IntelProjectVersion;
  89. }
  90. void cmGlobalVisualStudio7Generator::EnableLanguage(
  91. std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
  92. {
  93. mf->AddDefinition("CMAKE_GENERATOR_RC", "rc");
  94. mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1");
  95. mf->InitCMAKE_CONFIGURATION_TYPES("Debug;Release;MinSizeRel;RelWithDebInfo");
  96. // Create list of configurations requested by user's cache, if any.
  97. this->cmGlobalVisualStudioGenerator::EnableLanguage(lang, mf, optional);
  98. // if this environment variable is set, then copy it to
  99. // a static cache entry. It will be used by
  100. // cmLocalGenerator::ConstructScript, to add an extra PATH
  101. // to all custom commands. This is because the VS IDE
  102. // does not use the environment it is run in, and this allows
  103. // for running commands and using dll's that the IDE environment
  104. // does not know about.
  105. std::string extraPath;
  106. if (cmSystemTools::GetEnv("CMAKE_MSVCIDE_RUN_PATH", extraPath)) {
  107. mf->AddCacheDefinition("CMAKE_MSVCIDE_RUN_PATH", extraPath,
  108. "Saved environment variable CMAKE_MSVCIDE_RUN_PATH",
  109. cmStateEnums::STATIC);
  110. }
  111. }
  112. bool cmGlobalVisualStudio7Generator::FindMakeProgram(cmMakefile* mf)
  113. {
  114. if (!this->cmGlobalVisualStudioGenerator::FindMakeProgram(mf)) {
  115. return false;
  116. }
  117. mf->AddDefinition("CMAKE_VS_DEVENV_COMMAND", this->GetDevEnvCommand());
  118. return true;
  119. }
  120. std::string const& cmGlobalVisualStudio7Generator::GetDevEnvCommand()
  121. {
  122. if (!this->DevEnvCommandInitialized) {
  123. this->DevEnvCommandInitialized = true;
  124. this->DevEnvCommand = this->FindDevEnvCommand();
  125. }
  126. return this->DevEnvCommand;
  127. }
  128. std::string cmGlobalVisualStudio7Generator::FindDevEnvCommand()
  129. {
  130. std::string vscmd;
  131. std::string vskey;
  132. // Search in standard location.
  133. vskey = cmStrCat(this->GetRegistryBase(), ";InstallDir");
  134. if (cmSystemTools::ReadRegistryValue(vskey, vscmd,
  135. cmSystemTools::KeyWOW64_32)) {
  136. cmSystemTools::ConvertToUnixSlashes(vscmd);
  137. vscmd += "/devenv.com";
  138. if (cmSystemTools::FileExists(vscmd, true)) {
  139. return vscmd;
  140. }
  141. }
  142. // Search where VS15Preview places it.
  143. vskey =
  144. cmStrCat(R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\SxS\VS7;)",
  145. this->GetIDEVersion());
  146. if (cmSystemTools::ReadRegistryValue(vskey, vscmd,
  147. cmSystemTools::KeyWOW64_32)) {
  148. cmSystemTools::ConvertToUnixSlashes(vscmd);
  149. vscmd += "/Common7/IDE/devenv.com";
  150. if (cmSystemTools::FileExists(vscmd, true)) {
  151. return vscmd;
  152. }
  153. }
  154. vscmd = "devenv.com";
  155. return vscmd;
  156. }
  157. char const* cmGlobalVisualStudio7Generator::ExternalProjectType(
  158. std::string const& location)
  159. {
  160. std::string extension = cmSystemTools::GetFilenameLastExtension(location);
  161. if (extension == ".vbproj"_s) {
  162. return "F184B08F-C81C-45F6-A57F-5ABD9991F28F";
  163. }
  164. if (extension == ".csproj"_s) {
  165. return "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC";
  166. }
  167. if (extension == ".fsproj"_s) {
  168. return "F2A71F9B-5D33-465A-A702-920D77279786";
  169. }
  170. if (extension == ".vdproj"_s) {
  171. return "54435603-DBB4-11D2-8724-00A0C9A8B90C";
  172. }
  173. if (extension == ".dbproj"_s) {
  174. return "C8D11400-126E-41CD-887F-60BD40844F9E";
  175. }
  176. if (extension == ".wixproj"_s) {
  177. return "930C7802-8A8C-48F9-8165-68863BCCD9DD";
  178. }
  179. if (extension == ".pyproj"_s) {
  180. return "888888A0-9F3D-457C-B088-3A5042F75D52";
  181. }
  182. return "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942";
  183. }
  184. std::vector<cmGlobalGenerator::GeneratedMakeCommand>
  185. cmGlobalVisualStudio7Generator::GenerateBuildCommand(
  186. std::string const& makeProgram, std::string const& projectName,
  187. std::string const& /*projectDir*/,
  188. std::vector<std::string> const& targetNames, std::string const& config,
  189. int /*jobs*/, bool /*verbose*/, cmBuildOptions /*buildOptions*/,
  190. std::vector<std::string> const& makeOptions)
  191. {
  192. // Select the caller- or user-preferred make program, else devenv.
  193. std::string makeProgramSelected =
  194. this->SelectMakeProgram(makeProgram, this->GetDevEnvCommand());
  195. // Ignore the above preference if it is msbuild.
  196. // Assume any other value is either a devenv or
  197. // command-line compatible with devenv.
  198. std::string makeProgramLower = makeProgramSelected;
  199. cmSystemTools::LowerCase(makeProgramLower);
  200. if (makeProgramLower.find("msbuild") != std::string::npos) {
  201. makeProgramSelected = this->GetDevEnvCommand();
  202. }
  203. // Workaround to convince VCExpress.exe to produce output.
  204. bool const requiresOutputForward =
  205. (makeProgramLower.find("vcexpress") != std::string::npos);
  206. std::vector<GeneratedMakeCommand> makeCommands;
  207. std::vector<std::string> realTargetNames = targetNames;
  208. if (targetNames.empty() ||
  209. ((targetNames.size() == 1) && targetNames.front().empty())) {
  210. realTargetNames = { "ALL_BUILD" };
  211. }
  212. for (auto const& tname : realTargetNames) {
  213. std::string realTarget;
  214. if (!tname.empty()) {
  215. realTarget = tname;
  216. } else {
  217. continue;
  218. }
  219. bool clean = false;
  220. if (realTarget == "clean"_s) {
  221. clean = true;
  222. realTarget = "ALL_BUILD";
  223. }
  224. GeneratedMakeCommand makeCommand;
  225. makeCommand.RequiresOutputForward = requiresOutputForward;
  226. makeCommand.Add(makeProgramSelected);
  227. makeCommand.Add(cmStrCat(projectName, ".sln"));
  228. makeCommand.Add((clean ? "/clean" : "/build"));
  229. makeCommand.Add((config.empty() ? "Debug" : config));
  230. makeCommand.Add("/project");
  231. makeCommand.Add(realTarget);
  232. makeCommand.Add(makeOptions.begin(), makeOptions.end());
  233. makeCommands.emplace_back(std::move(makeCommand));
  234. }
  235. return makeCommands;
  236. }
  237. //! Create a local generator appropriate to this Global Generator
  238. std::unique_ptr<cmLocalGenerator>
  239. cmGlobalVisualStudio7Generator::CreateLocalGenerator(cmMakefile* mf)
  240. {
  241. auto lg = cm::make_unique<cmLocalVisualStudio7Generator>(this, mf);
  242. return std::unique_ptr<cmLocalGenerator>(std::move(lg));
  243. }
  244. #if !defined(CMAKE_BOOTSTRAP)
  245. Json::Value cmGlobalVisualStudio7Generator::GetJson() const
  246. {
  247. Json::Value generator = this->cmGlobalVisualStudioGenerator::GetJson();
  248. generator["platform"] = this->GetPlatformName();
  249. return generator;
  250. }
  251. #endif
  252. bool cmGlobalVisualStudio7Generator::SetSystemName(std::string const& s,
  253. cmMakefile* mf)
  254. {
  255. mf->AddDefinition("CMAKE_VS_INTEL_Fortran_PROJECT_VERSION",
  256. this->GetIntelProjectVersion());
  257. return this->cmGlobalVisualStudioGenerator::SetSystemName(s, mf);
  258. }
  259. void cmGlobalVisualStudio7Generator::AppendDirectoryForConfig(
  260. std::string const& prefix, std::string const& config,
  261. std::string const& suffix, std::string& dir)
  262. {
  263. if (!config.empty()) {
  264. dir += cmStrCat(prefix, config, suffix);
  265. }
  266. }
  267. std::string cmGlobalVisualStudio7Generator::Encoding()
  268. {
  269. return "UTF-8";
  270. }