mirror of
https://github.com/Kitware/CMake.git
synced 2026-05-24 09:09:43 -05:00
MSVC: Always define a character set
When targeting the MSVC ABI, define `_MBCS` by default if the project does not define `_SBCS` or `_UNICODE`. Visual Studio has long defined one of the three character set macros automatically. For consistency, define it when compiling for the MSVC ABI with other generators. Add policy CMP0204 for compatibility. Fixes: #27275
This commit is contained in:
@@ -1538,6 +1538,17 @@ public:
|
||||
std::string BuildDatabasePath(std::string const& lang,
|
||||
std::string const& config) const;
|
||||
|
||||
enum class MsvcCharSet
|
||||
{
|
||||
None,
|
||||
Unicode,
|
||||
MultiByte,
|
||||
SingleByte,
|
||||
};
|
||||
|
||||
// Detect if the current define selects any known charset entry or not
|
||||
static MsvcCharSet GetMsvcCharSet(std::string const& singleDefine);
|
||||
|
||||
private:
|
||||
void BuildFileSetInfoCache(std::string const& config) const;
|
||||
struct InfoByConfig
|
||||
|
||||
@@ -38,6 +38,12 @@ enum class OptionsParse
|
||||
Shell
|
||||
};
|
||||
|
||||
struct MsvcCharSetInfo
|
||||
{
|
||||
cmGeneratorTarget::MsvcCharSet CharSet;
|
||||
bool IsNeedToAddDefine;
|
||||
};
|
||||
|
||||
namespace {
|
||||
auto const DL_BEGIN = "<DEVICE_LINK>"_s;
|
||||
auto const DL_END = "</DEVICE_LINK>"_s;
|
||||
@@ -205,6 +211,45 @@ std::vector<BT<std::string>> wrapOptions(
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
cm::string_view const UNICODE_DEFINITION = "_UNICODE"_s;
|
||||
cm::string_view const MBCS_DEFINITION = "_MBCS"_s;
|
||||
cm::string_view const SBCS_DEFINITION = "_SBCS"_s;
|
||||
|
||||
constexpr char UNICODE_DEFINITION_PREFIX[] = "_UNICODE=";
|
||||
constexpr char MBCS_DEFINITION_PREFIX[] = "_MBCS=";
|
||||
constexpr char SBCS_DEFINITION_PREFIX[] = "_SBCS=";
|
||||
|
||||
MsvcCharSetInfo GetMsvcCharSetInfo(
|
||||
cmGeneratorTarget const& tgt, std::string const& lang,
|
||||
EvaluatedTargetPropertyEntries const& entries)
|
||||
{
|
||||
using MsvcCharSet = cmGeneratorTarget::MsvcCharSet;
|
||||
|
||||
if (tgt.Makefile->GetSafeDefinition(
|
||||
cmStrCat("CMAKE_", lang, "_COMPILER_ID")) != "MSVC"_s &&
|
||||
tgt.Makefile->GetSafeDefinition(
|
||||
cmStrCat("CMAKE_", lang, "_SIMULATE_ID")) != "MSVC"_s) {
|
||||
|
||||
// Only MSVC ABI uses this feature
|
||||
return { MsvcCharSet::None, false };
|
||||
}
|
||||
|
||||
for (EvaluatedTargetPropertyEntry const& entry : entries.Entries) {
|
||||
for (std::string const& value : entry.Values) {
|
||||
MsvcCharSet charSet = cmGeneratorTarget::GetMsvcCharSet(value);
|
||||
if (charSet != MsvcCharSet::None) {
|
||||
return { charSet, false };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default to multi-byte, similar to the Visual Studio generator
|
||||
// Define the default charset for Visual Studio too:
|
||||
// it should filter it out if need
|
||||
return { MsvcCharSet::MultiByte, true };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result,
|
||||
@@ -343,6 +388,34 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions(
|
||||
AddInterfaceEntries(this, "INTERFACE_COMPILE_DEFINITIONS", context,
|
||||
&dagChecker, entries, IncludeRuntimeInterface::Yes);
|
||||
|
||||
// Add the character set definition
|
||||
MsvcCharSetInfo charSetInfo = GetMsvcCharSetInfo(*this, language, entries);
|
||||
if (charSetInfo.IsNeedToAddDefine &&
|
||||
this->GetPolicyStatusCMP0204() == cmPolicies::NEW) {
|
||||
cm::string_view define;
|
||||
switch (charSetInfo.CharSet) {
|
||||
case MsvcCharSet::None:
|
||||
// Nothing to set
|
||||
break;
|
||||
case MsvcCharSet::Unicode:
|
||||
define = UNICODE_DEFINITION;
|
||||
break;
|
||||
case MsvcCharSet::MultiByte:
|
||||
define = MBCS_DEFINITION;
|
||||
break;
|
||||
case MsvcCharSet::SingleByte:
|
||||
define = SBCS_DEFINITION;
|
||||
break;
|
||||
}
|
||||
if (!define.empty()) {
|
||||
std::unique_ptr<TargetPropertyEntry> property =
|
||||
TargetPropertyEntry::Create(*this->LocalGenerator->GetCMakeInstance(),
|
||||
std::string{ define });
|
||||
entries.Entries.emplace_back(
|
||||
EvaluateTargetPropertyEntry(this, context, &dagChecker, *property));
|
||||
}
|
||||
}
|
||||
|
||||
processOptions(this, entries, list, uniqueOptions, debugDefines,
|
||||
"compile definitions", OptionsParse::None);
|
||||
|
||||
@@ -677,3 +750,24 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends(
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cmGeneratorTarget::MsvcCharSet cmGeneratorTarget::GetMsvcCharSet(
|
||||
std::string const& singleDefine)
|
||||
{
|
||||
if (singleDefine == UNICODE_DEFINITION ||
|
||||
cmHasLiteralPrefix(singleDefine, UNICODE_DEFINITION_PREFIX)) {
|
||||
return MsvcCharSet::Unicode;
|
||||
}
|
||||
|
||||
if (singleDefine == MBCS_DEFINITION ||
|
||||
cmHasLiteralPrefix(singleDefine, MBCS_DEFINITION_PREFIX)) {
|
||||
return MsvcCharSet::MultiByte;
|
||||
}
|
||||
|
||||
if (singleDefine == SBCS_DEFINITION ||
|
||||
cmHasLiteralPrefix(singleDefine, SBCS_DEFINITION_PREFIX)) {
|
||||
return MsvcCharSet::SingleByte;
|
||||
}
|
||||
|
||||
return MsvcCharSet::None;
|
||||
}
|
||||
|
||||
@@ -4193,6 +4193,11 @@ bool cmLocalGenerator::IsNinjaMulti() const
|
||||
return this->GetState()->UseNinjaMulti();
|
||||
}
|
||||
|
||||
bool cmLocalGenerator::IsWindowsVSIDE() const
|
||||
{
|
||||
return this->GetState()->UseWindowsVSIDE();
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::string relativeIfUnder(std::string const& top, std::string const& cur,
|
||||
std::string const& path)
|
||||
|
||||
@@ -544,6 +544,7 @@ public:
|
||||
bool IsMinGWMake() const;
|
||||
bool IsNMake() const;
|
||||
bool IsNinjaMulti() const;
|
||||
bool IsWindowsVSIDE() const;
|
||||
|
||||
void IssueMessage(MessageType t, std::string const& text) const;
|
||||
|
||||
|
||||
+6
-2
@@ -609,7 +609,10 @@ class cmMakefile;
|
||||
4, 2, 0, WARN) \
|
||||
SELECT(POLICY, CMP0203, \
|
||||
"_WINDLL is defined for shared libraries targeting the MSVC ABI.", \
|
||||
4, 2, 0, WARN)
|
||||
4, 2, 0, WARN) \
|
||||
SELECT(POLICY, CMP0204, \
|
||||
"A character set is always defined when targeting the MSVC ABI.", 4, \
|
||||
2, 0, WARN)
|
||||
|
||||
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
|
||||
#define CM_FOR_EACH_POLICY_ID(POLICY) \
|
||||
@@ -661,7 +664,8 @@ class cmMakefile;
|
||||
F(CMP0199) \
|
||||
F(CMP0200) \
|
||||
F(CMP0202) \
|
||||
F(CMP0203)
|
||||
F(CMP0203) \
|
||||
F(CMP0204)
|
||||
|
||||
#define CM_FOR_EACH_CUSTOM_COMMAND_POLICY(F) \
|
||||
F(CMP0116) \
|
||||
|
||||
@@ -134,21 +134,44 @@ bool cmVisualStudioGeneratorOptions::IsManaged() const
|
||||
return this->FlagMap.find("CompileAsManaged") != this->FlagMap.end();
|
||||
}
|
||||
|
||||
void cmVisualStudioGeneratorOptions::CacheCharsetValue() const
|
||||
{
|
||||
using MsvcCharSet = cmGeneratorTarget::MsvcCharSet;
|
||||
|
||||
if (this->CachedCharset.has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MsvcCharSet newValue = MsvcCharSet::None;
|
||||
|
||||
// Look for a any charset definition.
|
||||
// Real charset will be updated if something is found.
|
||||
auto it = std::find_if(this->Defines.begin(), this->Defines.end(),
|
||||
[&newValue](std::string const& define) {
|
||||
newValue =
|
||||
cmGeneratorTarget::GetMsvcCharSet(define);
|
||||
return newValue != MsvcCharSet::None;
|
||||
});
|
||||
|
||||
if (it == this->Defines.end()) {
|
||||
// Default to multi-byte, as Visual Studio does
|
||||
newValue = MsvcCharSet::MultiByte;
|
||||
}
|
||||
|
||||
this->CachedCharset = newValue;
|
||||
}
|
||||
|
||||
bool cmVisualStudioGeneratorOptions::UsingUnicode() const
|
||||
{
|
||||
// Look for a _UNICODE definition.
|
||||
return std::any_of(
|
||||
this->Defines.begin(), this->Defines.end(), [](std::string const& di) {
|
||||
return di == "_UNICODE"_s || cmHasLiteralPrefix(di, "_UNICODE=");
|
||||
});
|
||||
this->CacheCharsetValue();
|
||||
return this->CachedCharset.value() ==
|
||||
cmGeneratorTarget::MsvcCharSet::Unicode;
|
||||
}
|
||||
bool cmVisualStudioGeneratorOptions::UsingSBCS() const
|
||||
{
|
||||
// Look for a _SBCS definition.
|
||||
return std::any_of(
|
||||
this->Defines.begin(), this->Defines.end(), [](std::string const& di) {
|
||||
return di == "_SBCS"_s || cmHasLiteralPrefix(di, "_SBCS=");
|
||||
});
|
||||
this->CacheCharsetValue();
|
||||
return this->CachedCharset.value() ==
|
||||
cmGeneratorTarget::MsvcCharSet::SingleByte;
|
||||
}
|
||||
|
||||
void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration()
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <cm/optional>
|
||||
|
||||
#include "cmGeneratorTarget.h"
|
||||
#include "cmGlobalVisualStudioGenerator.h"
|
||||
#include "cmIDEFlagTable.h"
|
||||
#include "cmIDEOptions.h"
|
||||
@@ -97,7 +98,11 @@ private:
|
||||
|
||||
std::string UnknownFlagField;
|
||||
|
||||
mutable cm::optional<cmGeneratorTarget::MsvcCharSet> CachedCharset;
|
||||
|
||||
void StoreUnknownFlag(std::string const& flag) override;
|
||||
|
||||
FlagValue TakeFlag(std::string const& key);
|
||||
|
||||
void CacheCharsetValue() const;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user