cmake/Source/cmVisualStudioGeneratorOptions.cxx

454 lines
13 KiB
C++
Raw Normal View History

2009-10-04 10:30:41 +03:00
#include "cmVisualStudioGeneratorOptions.h"
2016-07-09 11:21:54 +02:00
2022-03-29 21:10:50 +02:00
#include <algorithm>
#include <map>
#include <sstream>
#include <utility>
#include <vector>
2020-02-01 23:06:01 +01:00
#include <cm/iterator>
2017-04-14 19:02:05 +02:00
#include "cmAlgorithms.h"
#include "cmLocalVisualStudioGenerator.h"
2015-11-17 17:22:37 +01:00
#include "cmOutputConverter.h"
2022-03-29 21:10:50 +02:00
#include "cmRange.h"
#include "cmStringAlgorithms.h"
2009-10-04 10:30:41 +03:00
#include "cmSystemTools.h"
2018-08-09 18:06:22 +02:00
static void cmVS10EscapeForMSBuild(std::string& ret)
2009-10-04 10:30:41 +03:00
{
2013-11-03 12:27:13 +02:00
cmSystemTools::ReplaceString(ret, ";", "%3B");
2015-04-27 22:25:09 +02:00
}
2016-07-09 11:21:54 +02:00
cmVisualStudioGeneratorOptions::cmVisualStudioGeneratorOptions(
cmLocalVisualStudioGenerator* lg, Tool tool, cmVS7FlagTable const* table,
2018-08-09 18:06:22 +02:00
cmVS7FlagTable const* extraTable)
2016-07-09 11:21:54 +02:00
: cmIDEOptions()
, LocalGenerator(lg)
, Version(lg->GetVersion())
, CurrentTool(tool)
2009-10-04 10:30:41 +03:00
{
// Store the given flag tables.
2015-04-27 22:25:09 +02:00
this->AddTable(table);
this->AddTable(extraTable);
2009-10-04 10:30:41 +03:00
// Preprocessor definitions are not allowed for linker tools.
this->AllowDefine = (tool != Linker);
2018-04-23 21:13:27 +02:00
// include directories are not allowed for linker tools.
this->AllowInclude = (tool != Linker);
2009-10-04 10:30:41 +03:00
// Slash options are allowed for VS.
this->AllowSlash = true;
2011-01-16 11:35:12 +01:00
this->FortranRuntimeDebug = false;
this->FortranRuntimeDLL = false;
this->FortranRuntimeMT = false;
2017-07-20 19:35:53 +02:00
this->UnknownFlagField = "AdditionalOptions";
2009-10-04 10:30:41 +03:00
}
2015-04-27 22:25:09 +02:00
void cmVisualStudioGeneratorOptions::AddTable(cmVS7FlagTable const* table)
{
2016-07-09 11:21:54 +02:00
if (table) {
2023-05-23 16:38:00 +02:00
for (auto& flag : this->FlagTable) {
if (!flag) {
flag = table;
2015-04-27 22:25:09 +02:00
break;
}
}
2016-07-09 11:21:54 +02:00
}
2015-04-27 22:25:09 +02:00
}
2017-07-20 19:35:53 +02:00
void cmVisualStudioGeneratorOptions::ClearTables()
{
2023-05-23 16:38:00 +02:00
for (auto& flag : this->FlagTable) {
flag = nullptr;
2017-07-20 19:35:53 +02:00
}
}
2009-10-04 10:30:41 +03:00
void cmVisualStudioGeneratorOptions::FixExceptionHandlingDefault()
{
// Exception handling is on by default because the platform file has
// "/EHsc" in the flags. Normally, that will override this
// initialization to off, but the user has the option of removing
// the flag to disable exception handling. When the user does
// remove the flag we need to override the IDE default of on.
2016-07-09 11:21:54 +02:00
switch (this->Version) {
2022-03-29 21:10:50 +02:00
case cmGlobalVisualStudioGenerator::VSVersion::VS11:
case cmGlobalVisualStudioGenerator::VSVersion::VS12:
case cmGlobalVisualStudioGenerator::VSVersion::VS14:
case cmGlobalVisualStudioGenerator::VSVersion::VS15:
case cmGlobalVisualStudioGenerator::VSVersion::VS16:
case cmGlobalVisualStudioGenerator::VSVersion::VS17:
2009-10-04 10:30:41 +03:00
// by default VS puts <ExceptionHandling></ExceptionHandling> empty
// for a project, to make our projects look the same put a new line
// and space over for the closing </ExceptionHandling> as the default
// value
this->FlagMap["ExceptionHandling"] = "\n ";
break;
default:
this->FlagMap["ExceptionHandling"] = "0";
2016-07-09 11:21:54 +02:00
break;
}
2009-10-04 10:30:41 +03:00
}
void cmVisualStudioGeneratorOptions::SetVerboseMakefile(bool verbose)
{
// If verbose makefiles have been requested and the /nologo option
// was not given explicitly in the flags we want to add an attribute
// to the generated project to disable logo suppression. Otherwise
// the GUI default is to enable suppression.
2011-01-16 11:35:12 +01:00
//
2022-11-16 20:14:03 +01:00
// On Visual Studio 9, the value of this attribute should be
// "FALSE", instead of an empty string.
2016-07-09 11:21:54 +02:00
if (verbose &&
this->FlagMap.find("SuppressStartupBanner") == this->FlagMap.end()) {
2012-02-18 12:40:36 +02:00
this->FlagMap["SuppressStartupBanner"] =
2022-11-16 20:14:03 +01:00
this->Version == cmGlobalVisualStudioGenerator::VSVersion::VS9 ? "FALSE"
2022-03-29 21:10:50 +02:00
: "";
2016-07-09 11:21:54 +02:00
}
2009-10-04 10:30:41 +03:00
}
2013-11-03 12:27:13 +02:00
bool cmVisualStudioGeneratorOptions::IsDebug() const
2009-10-04 10:30:41 +03:00
{
2017-04-14 19:02:05 +02:00
if (this->CurrentTool != CSharpCompiler) {
return this->FlagMap.find("DebugInformationFormat") != this->FlagMap.end();
}
2023-05-23 16:38:00 +02:00
auto i = this->FlagMap.find("DebugType");
2017-04-14 19:02:05 +02:00
if (i != this->FlagMap.end()) {
if (i->second.size() == 1) {
return i->second[0] != "none";
}
}
return false;
2009-10-04 10:30:41 +03:00
}
2015-04-27 22:25:09 +02:00
bool cmVisualStudioGeneratorOptions::IsWinRt() const
{
return this->FlagMap.find("CompileAsWinRT") != this->FlagMap.end();
}
2017-04-14 19:02:05 +02:00
bool cmVisualStudioGeneratorOptions::IsManaged() const
{
return this->FlagMap.find("CompileAsManaged") != this->FlagMap.end();
}
2013-11-03 12:27:13 +02:00
bool cmVisualStudioGeneratorOptions::UsingUnicode() const
2009-10-04 10:30:41 +03:00
{
2018-08-09 18:06:22 +02:00
// Look for a _UNICODE definition.
2023-05-23 16:38:00 +02:00
return std::any_of(this->Defines.begin(), this->Defines.end(),
[](std::string const& di) { return di == "_UNICODE"; });
2009-10-04 10:30:41 +03:00
}
2013-11-03 12:27:13 +02:00
bool cmVisualStudioGeneratorOptions::UsingSBCS() const
2012-04-19 19:04:21 +03:00
{
2018-08-09 18:06:22 +02:00
// Look for a _SBCS definition.
2023-05-23 16:38:00 +02:00
return std::any_of(this->Defines.begin(), this->Defines.end(),
[](std::string const& di) { return di == "_SBCS"; });
2012-04-19 19:04:21 +03:00
}
2009-10-04 10:30:41 +03:00
2017-07-20 19:35:53 +02:00
void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration()
{
2022-11-16 20:14:03 +01:00
// Create an empty CodeGeneration field, and pass the the actual
// compile flags via additional options so that we have consistent
// behavior and avoid issues with MSBuild extensions injecting
// virtual code when we request real only.
FlagValue& code_gen_flag = this->FlagMap["CodeGeneration"];
code_gen_flag = "";
2017-07-20 19:35:53 +02:00
}
2018-01-26 17:06:56 +01:00
void cmVisualStudioGeneratorOptions::FixManifestUACFlags()
{
2018-04-23 21:13:27 +02:00
static std::string const ENABLE_UAC = "EnableUAC";
2018-01-26 17:06:56 +01:00
if (!HasFlag(ENABLE_UAC)) {
return;
}
const std::string uacFlag = GetFlag(ENABLE_UAC);
std::vector<std::string> subOptions;
cmsys::SystemTools::Split(uacFlag, subOptions, ' ');
if (subOptions.empty()) {
AddFlag(ENABLE_UAC, "true");
return;
}
if (subOptions.size() == 1 && subOptions[0] == "NO") {
AddFlag(ENABLE_UAC, "false");
return;
}
std::map<std::string, std::string> uacMap;
uacMap["level"] = "UACExecutionLevel";
uacMap["uiAccess"] = "UACUIAccess";
std::map<std::string, std::string> uacExecuteLevelMap;
uacExecuteLevelMap["asInvoker"] = "AsInvoker";
uacExecuteLevelMap["highestAvailable"] = "HighestAvailable";
uacExecuteLevelMap["requireAdministrator"] = "RequireAdministrator";
2018-08-09 18:06:22 +02:00
for (std::string const& subopt : subOptions) {
2018-01-26 17:06:56 +01:00
std::vector<std::string> keyValue;
cmsys::SystemTools::Split(subopt, keyValue, '=');
if (keyValue.size() != 2 || (uacMap.find(keyValue[0]) == uacMap.end())) {
// ignore none key=value option or unknown flags
continue;
}
if (keyValue[1].front() == '\'' && keyValue[1].back() == '\'') {
2020-02-01 23:06:01 +01:00
keyValue[1] = keyValue[1].substr(
1, std::max(std::string::size_type(0), keyValue[1].length() - 2));
2018-01-26 17:06:56 +01:00
}
if (keyValue[0] == "level") {
if (uacExecuteLevelMap.find(keyValue[1]) == uacExecuteLevelMap.end()) {
// unknown level value
continue;
}
2018-04-23 21:13:27 +02:00
AddFlag(uacMap[keyValue[0]], uacExecuteLevelMap[keyValue[1]]);
2018-01-26 17:06:56 +01:00
continue;
}
if (keyValue[0] == "uiAccess") {
if (keyValue[1] != "true" && keyValue[1] != "false") {
// unknown uiAccess value
continue;
}
2018-04-23 21:13:27 +02:00
AddFlag(uacMap[keyValue[0]], keyValue[1]);
2018-01-26 17:06:56 +01:00
continue;
}
2018-04-23 21:13:27 +02:00
// unknown sub option
2018-01-26 17:06:56 +01:00
}
AddFlag(ENABLE_UAC, "true");
}
2018-10-28 12:09:07 +01:00
void cmVisualStudioGeneratorOptions::Parse(const std::string& flags)
2009-10-04 10:30:41 +03:00
{
// Parse the input string as a windows command line since the string
// is intended for writing directly into the build files.
std::vector<std::string> args;
2018-10-28 12:09:07 +01:00
cmSystemTools::ParseWindowsCommandLine(flags.c_str(), args);
2009-10-04 10:30:41 +03:00
// Process flags that need to be represented specially in the IDE
// project file.
2018-08-09 18:06:22 +02:00
for (std::string const& ai : args) {
this->HandleFlag(ai);
2016-07-09 11:21:54 +02:00
}
2009-10-04 10:30:41 +03:00
}
2011-01-16 11:35:12 +01:00
void cmVisualStudioGeneratorOptions::ParseFinish()
{
2016-07-09 11:21:54 +02:00
if (this->CurrentTool == FortranCompiler) {
2011-01-16 11:35:12 +01:00
// "RuntimeLibrary" attribute values:
// "rtMultiThreaded", "0", /threads /libs:static
// "rtMultiThreadedDLL", "2", /threads /libs:dll
// "rtMultiThreadedDebug", "1", /threads /dbglibs /libs:static
// "rtMultiThreadedDebugDLL", "3", /threads /dbglibs /libs:dll
// These seem unimplemented by the IDE:
// "rtSingleThreaded", "4", /libs:static
// "rtSingleThreadedDLL", "10", /libs:dll
// "rtSingleThreadedDebug", "5", /dbglibs /libs:static
// "rtSingleThreadedDebugDLL", "11", /dbglibs /libs:dll
2020-02-01 23:06:01 +01:00
std::string rl =
cmStrCat("rtMultiThreaded", this->FortranRuntimeDebug ? "Debug" : "",
this->FortranRuntimeDLL ? "DLL" : "");
2011-01-16 11:35:12 +01:00
this->FlagMap["RuntimeLibrary"] = rl;
2016-07-09 11:21:54 +02:00
}
2017-07-20 19:35:53 +02:00
if (this->CurrentTool == CudaCompiler) {
2023-05-23 16:38:00 +02:00
auto i = this->FlagMap.find("CudaRuntime");
2017-07-20 19:35:53 +02:00
if (i != this->FlagMap.end() && i->second.size() == 1) {
std::string& cudaRuntime = i->second[0];
if (cudaRuntime == "static") {
cudaRuntime = "Static";
} else if (cudaRuntime == "shared") {
cudaRuntime = "Shared";
} else if (cudaRuntime == "none") {
cudaRuntime = "None";
}
}
}
}
void cmVisualStudioGeneratorOptions::PrependInheritedString(
std::string const& key)
{
2023-05-23 16:38:00 +02:00
auto i = this->FlagMap.find(key);
2017-07-20 19:35:53 +02:00
if (i == this->FlagMap.end() || i->second.size() != 1) {
return;
}
std::string& value = i->second[0];
value = "%(" + key + ") " + value;
}
void cmVisualStudioGeneratorOptions::Reparse(std::string const& key)
{
2023-05-23 16:38:00 +02:00
auto i = this->FlagMap.find(key);
2017-07-20 19:35:53 +02:00
if (i == this->FlagMap.end() || i->second.size() != 1) {
return;
}
std::string const original = i->second[0];
i->second[0] = "";
this->UnknownFlagField = key;
2018-10-28 12:09:07 +01:00
this->Parse(original);
2011-01-16 11:35:12 +01:00
}
2018-08-09 18:06:22 +02:00
void cmVisualStudioGeneratorOptions::StoreUnknownFlag(std::string const& flag)
2009-10-04 10:30:41 +03:00
{
2011-01-16 11:35:12 +01:00
// Look for Intel Fortran flags that do not map well in the flag table.
2016-07-09 11:21:54 +02:00
if (this->CurrentTool == FortranCompiler) {
2019-11-11 23:01:05 +01:00
if (flag == "/dbglibs" || flag == "-dbglibs") {
2011-01-16 11:35:12 +01:00
this->FortranRuntimeDebug = true;
return;
2016-07-09 11:21:54 +02:00
}
2019-11-11 23:01:05 +01:00
if (flag == "/threads" || flag == "-threads") {
2011-01-16 11:35:12 +01:00
this->FortranRuntimeMT = true;
return;
2016-07-09 11:21:54 +02:00
}
2019-11-11 23:01:05 +01:00
if (flag == "/libs:dll" || flag == "-libs:dll") {
2011-01-16 11:35:12 +01:00
this->FortranRuntimeDLL = true;
return;
2016-07-09 11:21:54 +02:00
}
2019-11-11 23:01:05 +01:00
if (flag == "/libs:static" || flag == "-libs:static") {
2011-01-16 11:35:12 +01:00
this->FortranRuntimeDLL = false;
return;
}
2016-07-09 11:21:54 +02:00
}
2011-01-16 11:35:12 +01:00
2009-10-04 10:30:41 +03:00
// This option is not known. Store it in the output flags.
2017-07-20 19:35:53 +02:00
std::string const opts = cmOutputConverter::EscapeWindowsShellArgument(
2018-08-09 18:06:22 +02:00
flag.c_str(),
cmOutputConverter::Shell_Flag_AllowMakeVariables |
2015-11-17 17:22:37 +01:00
cmOutputConverter::Shell_Flag_VSIDE);
2017-07-20 19:35:53 +02:00
this->AppendFlagString(this->UnknownFlagField, opts);
}
cmIDEOptions::FlagValue cmVisualStudioGeneratorOptions::TakeFlag(
std::string const& key)
{
FlagValue value;
2023-05-23 16:38:00 +02:00
auto i = this->FlagMap.find(key);
2017-07-20 19:35:53 +02:00
if (i != this->FlagMap.end()) {
value = i->second;
this->FlagMap.erase(i);
}
return value;
2009-10-04 10:30:41 +03:00
}
2018-08-09 18:06:22 +02:00
void cmVisualStudioGeneratorOptions::SetConfiguration(
const std::string& config)
2009-10-04 10:30:41 +03:00
{
this->Configuration = config;
}
2018-08-09 18:06:22 +02:00
const std::string& cmVisualStudioGeneratorOptions::GetConfiguration() const
{
return this->Configuration;
}
2016-07-09 11:21:54 +02:00
void cmVisualStudioGeneratorOptions::OutputPreprocessorDefinitions(
2018-08-09 18:06:22 +02:00
std::ostream& fout, int indent, const std::string& lang)
2009-10-04 10:30:41 +03:00
{
2016-07-09 11:21:54 +02:00
if (this->Defines.empty()) {
2009-10-04 10:30:41 +03:00
return;
2016-07-09 11:21:54 +02:00
}
2020-08-30 11:54:41 +02:00
std::string tag = "PreprocessorDefinitions";
2017-07-20 19:35:53 +02:00
if (lang == "CUDA") {
tag = "Defines";
}
2018-08-09 18:06:22 +02:00
std::ostringstream oss;
2022-11-16 20:14:03 +01:00
if (this->Version != cmGlobalVisualStudioGenerator::VSVersion::VS9) {
2021-09-14 00:13:48 +02:00
oss << "%(" << tag << ")";
}
2023-05-23 16:38:00 +02:00
auto de = cmRemoveDuplicates(this->Defines);
2019-11-11 23:01:05 +01:00
for (std::string const& di : cmMakeRange(this->Defines.cbegin(), de)) {
2009-10-04 10:30:41 +03:00
// Escape the definition for the compiler.
std::string define;
2022-11-16 20:14:03 +01:00
if (this->Version == cmGlobalVisualStudioGenerator::VSVersion::VS9) {
2019-11-11 23:01:05 +01:00
define = this->LocalGenerator->EscapeForShell(di, true);
2016-07-09 11:21:54 +02:00
} else {
2019-11-11 23:01:05 +01:00
define = di;
2016-07-09 11:21:54 +02:00
}
2018-08-09 18:06:22 +02:00
// Escape this flag for the MSBuild.
2022-11-16 20:14:03 +01:00
if (this->Version != cmGlobalVisualStudioGenerator::VSVersion::VS9) {
2018-08-09 18:06:22 +02:00
cmVS10EscapeForMSBuild(define);
2016-07-09 11:21:54 +02:00
if (lang == "RC") {
2011-02-07 16:37:25 +01:00
cmSystemTools::ReplaceString(define, "\"", "\\\"");
2009-10-04 10:30:41 +03:00
}
2016-07-09 11:21:54 +02:00
}
2009-10-04 10:30:41 +03:00
// Store the flag in the project file.
2021-09-14 00:13:48 +02:00
oss << ';' << define;
2016-07-09 11:21:54 +02:00
}
2018-08-09 18:06:22 +02:00
this->OutputFlag(fout, indent, tag, oss.str());
2009-10-04 10:30:41 +03:00
}
2018-04-23 21:13:27 +02:00
void cmVisualStudioGeneratorOptions::OutputAdditionalIncludeDirectories(
2018-08-09 18:06:22 +02:00
std::ostream& fout, int indent, const std::string& lang)
2018-04-23 21:13:27 +02:00
{
if (this->Includes.empty()) {
return;
}
2020-08-30 11:54:41 +02:00
std::string tag = "AdditionalIncludeDirectories";
2018-04-23 21:13:27 +02:00
if (lang == "CUDA") {
tag = "Include";
} else if (lang == "ASM_MASM" || lang == "ASM_NASM") {
tag = "IncludePaths";
}
2018-08-09 18:06:22 +02:00
std::ostringstream oss;
2018-04-23 21:13:27 +02:00
const char* sep = "";
for (std::string include : this->Includes) {
// first convert all of the slashes
std::string::size_type pos = 0;
while ((pos = include.find('/', pos)) != std::string::npos) {
include[pos] = '\\';
pos++;
}
if (lang == "ASM_NASM") {
include += "\\";
}
2018-08-09 18:06:22 +02:00
// Escape this include for the MSBuild.
2022-11-16 20:14:03 +01:00
if (this->Version != cmGlobalVisualStudioGenerator::VSVersion::VS9) {
2018-08-09 18:06:22 +02:00
cmVS10EscapeForMSBuild(include);
}
oss << sep << include;
2018-04-23 21:13:27 +02:00
sep = ";";
if (lang == "Fortran") {
include += "/$(ConfigurationName)";
2018-08-09 18:06:22 +02:00
oss << sep << include;
2018-04-23 21:13:27 +02:00
}
}
2022-11-16 20:14:03 +01:00
if (this->Version != cmGlobalVisualStudioGenerator::VSVersion::VS9) {
2018-08-09 18:06:22 +02:00
oss << sep << "%(" << tag << ")";
2018-04-23 21:13:27 +02:00
}
2018-08-09 18:06:22 +02:00
this->OutputFlag(fout, indent, tag, oss.str());
2018-04-23 21:13:27 +02:00
}
2016-07-09 11:21:54 +02:00
void cmVisualStudioGeneratorOptions::OutputFlagMap(std::ostream& fout,
2018-08-09 18:06:22 +02:00
int indent)
2009-10-04 10:30:41 +03:00
{
2018-08-09 18:06:22 +02:00
for (auto const& m : this->FlagMap) {
std::ostringstream oss;
const char* sep = "";
for (std::string i : m.second) {
2022-11-16 20:14:03 +01:00
if (this->Version != cmGlobalVisualStudioGenerator::VSVersion::VS9) {
2018-08-09 18:06:22 +02:00
cmVS10EscapeForMSBuild(i);
2016-07-09 11:21:54 +02:00
}
2018-08-09 18:06:22 +02:00
oss << sep << i;
sep = ";";
2009-10-04 10:30:41 +03:00
}
2018-08-09 18:06:22 +02:00
2020-08-30 11:54:41 +02:00
this->OutputFlag(fout, indent, m.first, oss.str());
2016-07-09 11:21:54 +02:00
}
2009-10-04 10:30:41 +03:00
}