1 #include "cmVisualStudioGeneratorOptions.h"
11 #include "cmAlgorithms.h"
12 #include "cmLocalVisualStudioGenerator.h"
13 #include "cmOutputConverter.h"
15 #include "cmStringAlgorithms.h"
16 #include "cmSystemTools.h"
18 static void cmVS10EscapeForMSBuild(std::string& ret)
20 cmSystemTools::ReplaceString(ret, ";", "%3B");
23 cmVisualStudioGeneratorOptions::cmVisualStudioGeneratorOptions(
24 cmLocalVisualStudioGenerator* lg, Tool tool, cmVS7FlagTable const* table,
25 cmVS7FlagTable const* extraTable)
28 , Version(lg->GetVersion())
31 // Store the given flag tables.
32 this->AddTable(table);
33 this->AddTable(extraTable);
35 // Preprocessor definitions are not allowed for linker tools.
36 this->AllowDefine = (tool != Linker);
38 // include directories are not allowed for linker tools.
39 this->AllowInclude = (tool != Linker);
41 // Slash options are allowed for VS.
42 this->AllowSlash = true;
44 this->FortranRuntimeDebug = false;
45 this->FortranRuntimeDLL = false;
46 this->FortranRuntimeMT = false;
48 this->UnknownFlagField = "AdditionalOptions";
51 void cmVisualStudioGeneratorOptions::AddTable(cmVS7FlagTable const* table)
54 for (int i = 0; i < FlagTableCount; ++i) {
55 if (!this->FlagTable[i]) {
56 this->FlagTable[i] = table;
63 void cmVisualStudioGeneratorOptions::ClearTables()
65 for (int i = 0; i < FlagTableCount; ++i) {
66 this->FlagTable[i] = nullptr;
70 void cmVisualStudioGeneratorOptions::FixExceptionHandlingDefault()
72 // Exception handling is on by default because the platform file has
73 // "/EHsc" in the flags. Normally, that will override this
74 // initialization to off, but the user has the option of removing
75 // the flag to disable exception handling. When the user does
76 // remove the flag we need to override the IDE default of on.
77 switch (this->Version) {
78 case cmGlobalVisualStudioGenerator::VSVersion::VS11:
79 case cmGlobalVisualStudioGenerator::VSVersion::VS12:
80 case cmGlobalVisualStudioGenerator::VSVersion::VS14:
81 case cmGlobalVisualStudioGenerator::VSVersion::VS15:
82 case cmGlobalVisualStudioGenerator::VSVersion::VS16:
83 case cmGlobalVisualStudioGenerator::VSVersion::VS17:
84 // by default VS puts <ExceptionHandling></ExceptionHandling> empty
85 // for a project, to make our projects look the same put a new line
86 // and space over for the closing </ExceptionHandling> as the default
88 this->FlagMap["ExceptionHandling"] = "\n ";
91 this->FlagMap["ExceptionHandling"] = "0";
96 void cmVisualStudioGeneratorOptions::SetVerboseMakefile(bool verbose)
98 // If verbose makefiles have been requested and the /nologo option
99 // was not given explicitly in the flags we want to add an attribute
100 // to the generated project to disable logo suppression. Otherwise
101 // the GUI default is to enable suppression.
103 // On Visual Studio 9, the value of this attribute should be
104 // "FALSE", instead of an empty string.
106 this->FlagMap.find("SuppressStartupBanner") == this->FlagMap.end()) {
107 this->FlagMap["SuppressStartupBanner"] =
108 this->Version == cmGlobalVisualStudioGenerator::VSVersion::VS9 ? "FALSE"
113 bool cmVisualStudioGeneratorOptions::IsDebug() const
115 if (this->CurrentTool != CSharpCompiler) {
116 return this->FlagMap.find("DebugInformationFormat") != this->FlagMap.end();
118 std::map<std::string, FlagValue>::const_iterator i =
119 this->FlagMap.find("DebugType");
120 if (i != this->FlagMap.end()) {
121 if (i->second.size() == 1) {
122 return i->second[0] != "none";
128 bool cmVisualStudioGeneratorOptions::IsWinRt() const
130 return this->FlagMap.find("CompileAsWinRT") != this->FlagMap.end();
133 bool cmVisualStudioGeneratorOptions::IsManaged() const
135 return this->FlagMap.find("CompileAsManaged") != this->FlagMap.end();
138 bool cmVisualStudioGeneratorOptions::UsingUnicode() const
140 // Look for a _UNICODE definition.
141 for (std::string const& di : this->Defines) {
142 if (di == "_UNICODE") {
148 bool cmVisualStudioGeneratorOptions::UsingSBCS() const
150 // Look for a _SBCS definition.
151 for (std::string const& di : this->Defines) {
159 void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration()
161 // Create an empty CodeGeneration field, and pass the the actual
162 // compile flags via additional options so that we have consistent
163 // behavior and avoid issues with MSBuild extensions injecting
164 // virtual code when we request real only.
165 FlagValue& code_gen_flag = this->FlagMap["CodeGeneration"];
169 void cmVisualStudioGeneratorOptions::FixManifestUACFlags()
171 static std::string const ENABLE_UAC = "EnableUAC";
172 if (!HasFlag(ENABLE_UAC)) {
176 const std::string uacFlag = GetFlag(ENABLE_UAC);
177 std::vector<std::string> subOptions;
178 cmsys::SystemTools::Split(uacFlag, subOptions, ' ');
179 if (subOptions.empty()) {
180 AddFlag(ENABLE_UAC, "true");
184 if (subOptions.size() == 1 && subOptions[0] == "NO") {
185 AddFlag(ENABLE_UAC, "false");
189 std::map<std::string, std::string> uacMap;
190 uacMap["level"] = "UACExecutionLevel";
191 uacMap["uiAccess"] = "UACUIAccess";
193 std::map<std::string, std::string> uacExecuteLevelMap;
194 uacExecuteLevelMap["asInvoker"] = "AsInvoker";
195 uacExecuteLevelMap["highestAvailable"] = "HighestAvailable";
196 uacExecuteLevelMap["requireAdministrator"] = "RequireAdministrator";
198 for (std::string const& subopt : subOptions) {
199 std::vector<std::string> keyValue;
200 cmsys::SystemTools::Split(subopt, keyValue, '=');
201 if (keyValue.size() != 2 || (uacMap.find(keyValue[0]) == uacMap.end())) {
202 // ignore none key=value option or unknown flags
206 if (keyValue[1].front() == '\'' && keyValue[1].back() == '\'') {
207 keyValue[1] = keyValue[1].substr(
208 1, std::max(std::string::size_type(0), keyValue[1].length() - 2));
211 if (keyValue[0] == "level") {
212 if (uacExecuteLevelMap.find(keyValue[1]) == uacExecuteLevelMap.end()) {
213 // unknown level value
217 AddFlag(uacMap[keyValue[0]], uacExecuteLevelMap[keyValue[1]]);
221 if (keyValue[0] == "uiAccess") {
222 if (keyValue[1] != "true" && keyValue[1] != "false") {
223 // unknown uiAccess value
226 AddFlag(uacMap[keyValue[0]], keyValue[1]);
230 // unknown sub option
233 AddFlag(ENABLE_UAC, "true");
236 void cmVisualStudioGeneratorOptions::Parse(const std::string& flags)
238 // Parse the input string as a windows command line since the string
239 // is intended for writing directly into the build files.
240 std::vector<std::string> args;
241 cmSystemTools::ParseWindowsCommandLine(flags.c_str(), args);
243 // Process flags that need to be represented specially in the IDE
245 for (std::string const& ai : args) {
246 this->HandleFlag(ai);
250 void cmVisualStudioGeneratorOptions::ParseFinish()
252 if (this->CurrentTool == FortranCompiler) {
253 // "RuntimeLibrary" attribute values:
254 // "rtMultiThreaded", "0", /threads /libs:static
255 // "rtMultiThreadedDLL", "2", /threads /libs:dll
256 // "rtMultiThreadedDebug", "1", /threads /dbglibs /libs:static
257 // "rtMultiThreadedDebugDLL", "3", /threads /dbglibs /libs:dll
258 // These seem unimplemented by the IDE:
259 // "rtSingleThreaded", "4", /libs:static
260 // "rtSingleThreadedDLL", "10", /libs:dll
261 // "rtSingleThreadedDebug", "5", /dbglibs /libs:static
262 // "rtSingleThreadedDebugDLL", "11", /dbglibs /libs:dll
264 cmStrCat("rtMultiThreaded", this->FortranRuntimeDebug ? "Debug" : "",
265 this->FortranRuntimeDLL ? "DLL" : "");
266 this->FlagMap["RuntimeLibrary"] = rl;
269 if (this->CurrentTool == CudaCompiler) {
270 std::map<std::string, FlagValue>::iterator i =
271 this->FlagMap.find("CudaRuntime");
272 if (i != this->FlagMap.end() && i->second.size() == 1) {
273 std::string& cudaRuntime = i->second[0];
274 if (cudaRuntime == "static") {
275 cudaRuntime = "Static";
276 } else if (cudaRuntime == "shared") {
277 cudaRuntime = "Shared";
278 } else if (cudaRuntime == "none") {
279 cudaRuntime = "None";
285 void cmVisualStudioGeneratorOptions::PrependInheritedString(
286 std::string const& key)
288 std::map<std::string, FlagValue>::iterator i = this->FlagMap.find(key);
289 if (i == this->FlagMap.end() || i->second.size() != 1) {
292 std::string& value = i->second[0];
293 value = "%(" + key + ") " + value;
296 void cmVisualStudioGeneratorOptions::Reparse(std::string const& key)
298 std::map<std::string, FlagValue>::iterator i = this->FlagMap.find(key);
299 if (i == this->FlagMap.end() || i->second.size() != 1) {
302 std::string const original = i->second[0];
304 this->UnknownFlagField = key;
305 this->Parse(original);
308 void cmVisualStudioGeneratorOptions::StoreUnknownFlag(std::string const& flag)
310 // Look for Intel Fortran flags that do not map well in the flag table.
311 if (this->CurrentTool == FortranCompiler) {
312 if (flag == "/dbglibs" || flag == "-dbglibs") {
313 this->FortranRuntimeDebug = true;
316 if (flag == "/threads" || flag == "-threads") {
317 this->FortranRuntimeMT = true;
320 if (flag == "/libs:dll" || flag == "-libs:dll") {
321 this->FortranRuntimeDLL = true;
324 if (flag == "/libs:static" || flag == "-libs:static") {
325 this->FortranRuntimeDLL = false;
330 // This option is not known. Store it in the output flags.
331 std::string const opts = cmOutputConverter::EscapeWindowsShellArgument(
333 cmOutputConverter::Shell_Flag_AllowMakeVariables |
334 cmOutputConverter::Shell_Flag_VSIDE);
335 this->AppendFlagString(this->UnknownFlagField, opts);
338 cmIDEOptions::FlagValue cmVisualStudioGeneratorOptions::TakeFlag(
339 std::string const& key)
342 std::map<std::string, FlagValue>::iterator i = this->FlagMap.find(key);
343 if (i != this->FlagMap.end()) {
345 this->FlagMap.erase(i);
350 void cmVisualStudioGeneratorOptions::SetConfiguration(
351 const std::string& config)
353 this->Configuration = config;
356 const std::string& cmVisualStudioGeneratorOptions::GetConfiguration() const
358 return this->Configuration;
361 void cmVisualStudioGeneratorOptions::OutputPreprocessorDefinitions(
362 std::ostream& fout, int indent, const std::string& lang)
364 if (this->Defines.empty()) {
367 std::string tag = "PreprocessorDefinitions";
368 if (lang == "CUDA") {
372 std::ostringstream oss;
373 if (this->Version != cmGlobalVisualStudioGenerator::VSVersion::VS9) {
374 oss << "%(" << tag << ")";
376 std::vector<std::string>::const_iterator de =
377 cmRemoveDuplicates(this->Defines);
378 for (std::string const& di : cmMakeRange(this->Defines.cbegin(), de)) {
379 // Escape the definition for the compiler.
381 if (this->Version == cmGlobalVisualStudioGenerator::VSVersion::VS9) {
382 define = this->LocalGenerator->EscapeForShell(di, true);
386 // Escape this flag for the MSBuild.
387 if (this->Version != cmGlobalVisualStudioGenerator::VSVersion::VS9) {
388 cmVS10EscapeForMSBuild(define);
390 cmSystemTools::ReplaceString(define, "\"", "\\\"");
393 // Store the flag in the project file.
394 oss << ';' << define;
397 this->OutputFlag(fout, indent, tag, oss.str());
400 void cmVisualStudioGeneratorOptions::OutputAdditionalIncludeDirectories(
401 std::ostream& fout, int indent, const std::string& lang)
403 if (this->Includes.empty()) {
407 std::string tag = "AdditionalIncludeDirectories";
408 if (lang == "CUDA") {
410 } else if (lang == "ASM_MASM" || lang == "ASM_NASM") {
411 tag = "IncludePaths";
414 std::ostringstream oss;
415 const char* sep = "";
416 for (std::string include : this->Includes) {
417 // first convert all of the slashes
418 std::string::size_type pos = 0;
419 while ((pos = include.find('/', pos)) != std::string::npos) {
424 if (lang == "ASM_NASM") {
428 // Escape this include for the MSBuild.
429 if (this->Version != cmGlobalVisualStudioGenerator::VSVersion::VS9) {
430 cmVS10EscapeForMSBuild(include);
432 oss << sep << include;
435 if (lang == "Fortran") {
436 include += "/$(ConfigurationName)";
437 oss << sep << include;
441 if (this->Version != cmGlobalVisualStudioGenerator::VSVersion::VS9) {
442 oss << sep << "%(" << tag << ")";
445 this->OutputFlag(fout, indent, tag, oss.str());
448 void cmVisualStudioGeneratorOptions::OutputFlagMap(std::ostream& fout,
451 for (auto const& m : this->FlagMap) {
452 std::ostringstream oss;
453 const char* sep = "";
454 for (std::string i : m.second) {
455 if (this->Version != cmGlobalVisualStudioGenerator::VSVersion::VS9) {
456 cmVS10EscapeForMSBuild(i);
462 this->OutputFlag(fout, indent, m.first, oss.str());