mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-04 12:49:36 -06:00
Merge topic 'add_support_for_clr_targets'
312527de47document COMMON_LANGUAGE_RUNTIME target properties4b7a82b4edcmVisualStudio10TargetGenerator: set /clr compiler flag from property20e31fb4c9cmExportFileGenerator: add target property for managed targets411a22706acmGeneratorTarget: add handling of managed assemblies to HasImportLibrary()fb433ff283cmGeneratorTarget: Make import library checks config-aware4c1f33961fcmGeneratorTarget: add GetManagedType() and CheckManagedType() methods6c517a9f8dcmGeneratorTarget: add HasLanguage() as wrapper for GetLanguages() Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !1916
This commit is contained in:
@@ -143,6 +143,7 @@ Properties on Targets
|
||||
/prop_tgt/C_EXTENSIONS
|
||||
/prop_tgt/C_STANDARD
|
||||
/prop_tgt/C_STANDARD_REQUIRED
|
||||
/prop_tgt/COMMON_LANGUAGE_RUNTIME
|
||||
/prop_tgt/COMPATIBLE_INTERFACE_BOOL
|
||||
/prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MAX
|
||||
/prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MIN
|
||||
@@ -186,6 +187,7 @@ Properties on Targets
|
||||
/prop_tgt/GNUtoMS
|
||||
/prop_tgt/HAS_CXX
|
||||
/prop_tgt/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM
|
||||
/prop_tgt/IMPORTED_COMMON_LANGUAGE_RUNTIME
|
||||
/prop_tgt/IMPORTED_CONFIGURATIONS
|
||||
/prop_tgt/IMPORTED_GLOBAL
|
||||
/prop_tgt/IMPORTED_IMPLIB_CONFIG
|
||||
|
||||
19
Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst
Normal file
19
Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst
Normal file
@@ -0,0 +1,19 @@
|
||||
COMMON_LANGUAGE_RUNTIME
|
||||
-----------------------
|
||||
|
||||
By setting this target property, the target is configured to build with
|
||||
``C++/CLI`` support.
|
||||
|
||||
The Visual Studio generator defines the ``clr`` parameter depending on
|
||||
the value of ``COMMON_LANGUAGE_RUNTIME``:
|
||||
|
||||
* property not set: native C++ (i.e. default)
|
||||
* property set but empty: mixed unmanaged/managed C++
|
||||
* property set to any non empty value: managed C++
|
||||
|
||||
Supported values: ``""``, ``"pure"``, ``"safe"``
|
||||
|
||||
This property is only evaluated :ref:`Visual Studio Generators` for
|
||||
VS 2010 and above.
|
||||
|
||||
See also :prop_tgt:`IMPORTED_COMMON_LANGUAGE_RUNTIME`
|
||||
8
Help/prop_tgt/IMPORTED_COMMON_LANGUAGE_RUNTIME.rst
Normal file
8
Help/prop_tgt/IMPORTED_COMMON_LANGUAGE_RUNTIME.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
IMPORTED_COMMON_LANGUAGE_RUNTIME
|
||||
--------------------------------
|
||||
|
||||
Property to define if the target uses ``C++/CLI``.
|
||||
|
||||
Ignored for non-imported targets.
|
||||
|
||||
See also the :prop_tgt:`COMMON_LANGUAGE_RUNTIME` target property.
|
||||
8
Help/release/dev/managed-target-property.rst
Normal file
8
Help/release/dev/managed-target-property.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
target property COMMON_LANGUAGE_RUNTIME
|
||||
---------------------------------------
|
||||
|
||||
* The :prop_tgt:`COMMON_LANGUAGE_RUNTIME` target property was introduced
|
||||
to configure the use of managed C++ for :ref:`Visual Studio Generators`
|
||||
for VS 2010 and above.
|
||||
* To support ``C++/CLI`` for imported targets, the
|
||||
:prop_tgt:`IMPORTED_COMMON_LANGUAGE_RUNTIME` was added.
|
||||
@@ -224,13 +224,14 @@ void cmExportBuildFileGenerator::SetImportLocationProperty(
|
||||
}
|
||||
|
||||
// Add the import library for windows DLLs.
|
||||
if (target->HasImportLibrary() &&
|
||||
if (target->HasImportLibrary(config) &&
|
||||
mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) {
|
||||
std::string prop = "IMPORTED_IMPLIB";
|
||||
prop += suffix;
|
||||
std::string value =
|
||||
target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact);
|
||||
target->GetImplibGNUtoMS(value, value, "${CMAKE_IMPORT_LIBRARY_SUFFIX}");
|
||||
target->GetImplibGNUtoMS(config, value, value,
|
||||
"${CMAKE_IMPORT_LIBRARY_SUFFIX}");
|
||||
properties[prop] = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -777,6 +777,20 @@ void cmExportFileGenerator::SetImportDetailProperties(
|
||||
properties[prop] = m.str();
|
||||
}
|
||||
}
|
||||
|
||||
// Add information if this target is a managed target
|
||||
if (target->GetManagedType(config) !=
|
||||
cmGeneratorTarget::ManagedType::Native) {
|
||||
std::string prop = "IMPORTED_COMMON_LANGUAGE_RUNTIME";
|
||||
prop += suffix;
|
||||
std::string propval;
|
||||
if (auto* p = target->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
|
||||
propval = p;
|
||||
}
|
||||
// TODO: make sure propval is set to non-empty string for
|
||||
// CSharp targets (i.e. force ManagedType::Managed).
|
||||
properties[prop] = propval;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -1675,7 +1675,8 @@ struct TargetFilesystemArtifactResultCreator<ArtifactLinkerTag>
|
||||
"executables with ENABLE_EXPORTS.");
|
||||
return std::string();
|
||||
}
|
||||
cmStateEnums::ArtifactType artifact = target->HasImportLibrary()
|
||||
cmStateEnums::ArtifactType artifact =
|
||||
target->HasImportLibrary(context->Config)
|
||||
? cmStateEnums::ImportLibraryArtifact
|
||||
: cmStateEnums::RuntimeBinaryArtifact;
|
||||
return target->GetFullPath(context->Config, artifact);
|
||||
|
||||
@@ -4978,6 +4978,16 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
|
||||
}
|
||||
}
|
||||
|
||||
// Get information if target is managed assembly.
|
||||
{
|
||||
std::string linkProp = "IMPORTED_COMMON_LANGUAGE_RUNTIME";
|
||||
if (auto pc = this->GetProperty(linkProp + suffix)) {
|
||||
info.Managed = this->CheckManagedType(pc);
|
||||
} else if (auto p = this->GetProperty(linkProp)) {
|
||||
info.Managed = this->CheckManagedType(p);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the cyclic repetition count.
|
||||
if (this->GetType() == cmStateEnums::STATIC_LIBRARY) {
|
||||
std::string linkProp = "IMPORTED_LINK_INTERFACE_MULTIPLICITY";
|
||||
@@ -5195,6 +5205,18 @@ void cmGeneratorTarget::GetLanguages(std::set<std::string>& languages,
|
||||
}
|
||||
}
|
||||
|
||||
bool cmGeneratorTarget::HasLanguage(std::string const& language,
|
||||
std::string const& config,
|
||||
bool exclusive) const
|
||||
{
|
||||
std::set<std::string> languages;
|
||||
this->GetLanguages(languages, config);
|
||||
// add linker language (if it is different from compiler languages)
|
||||
languages.insert(this->GetLinkerLanguage(config));
|
||||
return (languages.size() == 1 || !exclusive) &&
|
||||
languages.count(language) > 0;
|
||||
}
|
||||
|
||||
void cmGeneratorTarget::ComputeLinkImplementationLanguages(
|
||||
const std::string& config, cmOptionalLinkImplementation& impl) const
|
||||
{
|
||||
@@ -5381,16 +5403,17 @@ std::string cmGeneratorTarget::GetPDBDirectory(const std::string& config) const
|
||||
return "";
|
||||
}
|
||||
|
||||
bool cmGeneratorTarget::HasImplibGNUtoMS() const
|
||||
bool cmGeneratorTarget::HasImplibGNUtoMS(std::string const& config) const
|
||||
{
|
||||
return this->HasImportLibrary() && this->GetPropertyAsBool("GNUtoMS");
|
||||
return this->HasImportLibrary(config) && this->GetPropertyAsBool("GNUtoMS");
|
||||
}
|
||||
|
||||
bool cmGeneratorTarget::GetImplibGNUtoMS(std::string const& gnuName,
|
||||
bool cmGeneratorTarget::GetImplibGNUtoMS(std::string const& config,
|
||||
std::string const& gnuName,
|
||||
std::string& out,
|
||||
const char* newExt) const
|
||||
{
|
||||
if (this->HasImplibGNUtoMS() && gnuName.size() > 6 &&
|
||||
if (this->HasImplibGNUtoMS(config) && gnuName.size() > 6 &&
|
||||
gnuName.substr(gnuName.size() - 6) == ".dll.a") {
|
||||
out = gnuName.substr(0, gnuName.size() - 6);
|
||||
out += newExt ? newExt : ".lib";
|
||||
@@ -5405,11 +5428,14 @@ bool cmGeneratorTarget::IsExecutableWithExports() const
|
||||
this->GetPropertyAsBool("ENABLE_EXPORTS"));
|
||||
}
|
||||
|
||||
bool cmGeneratorTarget::HasImportLibrary() const
|
||||
bool cmGeneratorTarget::HasImportLibrary(std::string const& config) const
|
||||
{
|
||||
return (this->IsDLLPlatform() &&
|
||||
(this->GetType() == cmStateEnums::SHARED_LIBRARY ||
|
||||
this->IsExecutableWithExports()));
|
||||
this->IsExecutableWithExports()) &&
|
||||
// Assemblies which have only managed code do not have
|
||||
// import libraries.
|
||||
this->GetManagedType(config) != ManagedType::Managed);
|
||||
}
|
||||
|
||||
std::string cmGeneratorTarget::GetSupportDirectory() const
|
||||
@@ -5462,3 +5488,49 @@ bool cmGeneratorTarget::IsCFBundleOnApple() const
|
||||
return (this->GetType() == cmStateEnums::MODULE_LIBRARY &&
|
||||
this->Makefile->IsOn("APPLE") && this->GetPropertyAsBool("BUNDLE"));
|
||||
}
|
||||
|
||||
cmGeneratorTarget::ManagedType cmGeneratorTarget::CheckManagedType(
|
||||
std::string const& propval) const
|
||||
{
|
||||
// The type of the managed assembly (mixed unmanaged C++ and C++/CLI,
|
||||
// or only C++/CLI) does only depend on whether the property is an empty
|
||||
// string or contains any value at all. In Visual Studio generators
|
||||
// this propval is prepended with /clr[:] which results in:
|
||||
//
|
||||
// 1. propval does not exist: no /clr flag, unmanaged target, has import
|
||||
// lib
|
||||
// 2. empty propval: add /clr as flag, mixed unmanaged/managed
|
||||
// target, has import lib
|
||||
// 3. any value (safe,pure): add /clr:[propval] as flag, target with
|
||||
// managed code only, no import lib
|
||||
return propval.empty() ? ManagedType::Mixed : ManagedType::Managed;
|
||||
}
|
||||
|
||||
cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType(
|
||||
const std::string& config) const
|
||||
{
|
||||
// Only libraries and executables can be managed targets.
|
||||
if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
|
||||
this->GetType() != cmStateEnums::STATIC_LIBRARY &&
|
||||
this->GetType() != cmStateEnums::EXECUTABLE) {
|
||||
return ManagedType::Undefined;
|
||||
}
|
||||
|
||||
// Check imported target.
|
||||
if (this->IsImported()) {
|
||||
if (cmGeneratorTarget::ImportInfo const* info =
|
||||
this->GetImportInfo(config)) {
|
||||
return info->Managed;
|
||||
}
|
||||
return ManagedType::Undefined;
|
||||
}
|
||||
|
||||
// Check for explicitly set clr target property.
|
||||
if (auto* clr = this->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
|
||||
return this->CheckManagedType(clr);
|
||||
}
|
||||
|
||||
// TODO: need to check if target is a CSharp target here.
|
||||
// If yes: return ManagedType::Managed.
|
||||
return ManagedType::Native;
|
||||
}
|
||||
|
||||
@@ -364,6 +364,12 @@ public:
|
||||
void GetLanguages(std::set<std::string>& languages,
|
||||
std::string const& config) const;
|
||||
|
||||
// Evaluate if the target uses the given language for compilation
|
||||
// and/or linking. If 'exclusive' is true, 'language' is expected
|
||||
// to be the only language used for the target.
|
||||
bool HasLanguage(std::string const& language, std::string const& config,
|
||||
bool exclusive = true) const;
|
||||
|
||||
void GetObjectLibrariesCMP0026(
|
||||
std::vector<cmGeneratorTarget*>& objlibs) const;
|
||||
|
||||
@@ -566,17 +572,17 @@ public:
|
||||
std::string GetLinkerLanguage(const std::string& config) const;
|
||||
|
||||
/** Does this target have a GNU implib to convert to MS format? */
|
||||
bool HasImplibGNUtoMS() const;
|
||||
bool HasImplibGNUtoMS(std::string const& config) const;
|
||||
|
||||
/** Convert the given GNU import library name (.dll.a) to a name with a new
|
||||
extension (.lib or ${CMAKE_IMPORT_LIBRARY_SUFFIX}). */
|
||||
bool GetImplibGNUtoMS(std::string const& gnuName, std::string& out,
|
||||
const char* newExt = nullptr) const;
|
||||
bool GetImplibGNUtoMS(std::string const& config, std::string const& gnuName,
|
||||
std::string& out, const char* newExt = nullptr) const;
|
||||
|
||||
bool IsExecutableWithExports() const;
|
||||
|
||||
/** Return whether or not the target has a DLL import library. */
|
||||
bool HasImportLibrary() const;
|
||||
bool HasImportLibrary(std::string const& config) const;
|
||||
|
||||
/** Get a build-tree directory in which to place target support files. */
|
||||
std::string GetSupportDirectory() const;
|
||||
@@ -597,6 +603,19 @@ public:
|
||||
/** Return whether this target is a CFBundle (plugin) on Apple. */
|
||||
bool IsCFBundleOnApple() const;
|
||||
|
||||
/** Assembly types. The order of the values of this enum is relevant
|
||||
because of smaller/larger comparison operations! */
|
||||
enum ManagedType
|
||||
{
|
||||
Undefined = 0, // target is no lib or executable
|
||||
Native, // target compiles to unmanaged binary.
|
||||
Mixed, // target compiles to mixed (managed and unmanaged) binary.
|
||||
Managed // target compiles to managed binary.
|
||||
};
|
||||
|
||||
/** Return the type of assembly this target compiles to. */
|
||||
ManagedType GetManagedType(const std::string& config) const;
|
||||
|
||||
struct SourceFileFlags GetTargetSourceFileFlags(
|
||||
const cmSourceFile* sf) const;
|
||||
|
||||
@@ -741,10 +760,12 @@ private:
|
||||
{
|
||||
ImportInfo()
|
||||
: NoSOName(false)
|
||||
, Managed(Native)
|
||||
, Multiplicity(0)
|
||||
{
|
||||
}
|
||||
bool NoSOName;
|
||||
ManagedType Managed;
|
||||
unsigned int Multiplicity;
|
||||
std::string Location;
|
||||
std::string SOName;
|
||||
@@ -838,6 +859,8 @@ private:
|
||||
bool ComputePDBOutputDir(const std::string& kind, const std::string& config,
|
||||
std::string& out) const;
|
||||
|
||||
ManagedType CheckManagedType(std::string const& propval) const;
|
||||
|
||||
public:
|
||||
const std::vector<const cmGeneratorTarget*>& GetLinkImplementationClosure(
|
||||
const std::string& config) const;
|
||||
|
||||
@@ -135,7 +135,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
|
||||
filesFrom.push_back(std::move(from1));
|
||||
filesTo.push_back(std::move(to1));
|
||||
std::string targetNameImportLib;
|
||||
if (this->Target->GetImplibGNUtoMS(targetNameImport,
|
||||
if (this->Target->GetImplibGNUtoMS(config, targetNameImport,
|
||||
targetNameImportLib)) {
|
||||
filesFrom.push_back(fromDirConfig + targetNameImportLib);
|
||||
filesTo.push_back(toDir + targetNameImportLib);
|
||||
@@ -201,7 +201,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(
|
||||
filesFrom.push_back(std::move(from1));
|
||||
filesTo.push_back(std::move(to1));
|
||||
std::string targetNameImportLib;
|
||||
if (this->Target->GetImplibGNUtoMS(targetNameImport,
|
||||
if (this->Target->GetImplibGNUtoMS(config, targetNameImport,
|
||||
targetNameImportLib)) {
|
||||
filesFrom.push_back(fromDirConfig + targetNameImportLib);
|
||||
filesTo.push_back(toDir + targetNameImportLib);
|
||||
@@ -398,7 +398,7 @@ std::string cmInstallTargetGenerator::GetInstallFilename(
|
||||
targetNamePDB, config);
|
||||
if (nameType == NameImplib) {
|
||||
// Use the import library name.
|
||||
if (!target->GetImplibGNUtoMS(targetNameImport, fname,
|
||||
if (!target->GetImplibGNUtoMS(config, targetNameImport, fname,
|
||||
"${CMAKE_IMPORT_LIBRARY_SUFFIX}")) {
|
||||
fname = targetNameImport;
|
||||
}
|
||||
@@ -419,7 +419,7 @@ std::string cmInstallTargetGenerator::GetInstallFilename(
|
||||
targetNameImport, targetNamePDB, config);
|
||||
if (nameType == NameImplib) {
|
||||
// Use the import library name.
|
||||
if (!target->GetImplibGNUtoMS(targetNameImport, fname,
|
||||
if (!target->GetImplibGNUtoMS(config, targetNameImport, fname,
|
||||
"${CMAKE_IMPORT_LIBRARY_SUFFIX}")) {
|
||||
fname = targetNameImport;
|
||||
}
|
||||
|
||||
@@ -477,8 +477,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
|
||||
this->LocalGenerator->GetCurrentBinaryDirectory(),
|
||||
targetFullPathImport));
|
||||
std::string implib;
|
||||
if (this->GeneratorTarget->GetImplibGNUtoMS(targetFullPathImport,
|
||||
implib)) {
|
||||
if (this->GeneratorTarget->GetImplibGNUtoMS(
|
||||
this->ConfigName, targetFullPathImport, implib)) {
|
||||
exeCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
|
||||
this->LocalGenerator->GetCurrentBinaryDirectory(), implib));
|
||||
}
|
||||
|
||||
@@ -641,8 +641,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
|
||||
this->LocalGenerator->GetCurrentBinaryDirectory(),
|
||||
targetFullPathImport));
|
||||
std::string implib;
|
||||
if (this->GeneratorTarget->GetImplibGNUtoMS(targetFullPathImport,
|
||||
implib)) {
|
||||
if (this->GeneratorTarget->GetImplibGNUtoMS(
|
||||
this->ConfigName, targetFullPathImport, implib)) {
|
||||
libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
|
||||
this->LocalGenerator->GetCurrentBinaryDirectory(), implib));
|
||||
}
|
||||
|
||||
@@ -1402,7 +1402,7 @@ std::string cmMakefileTargetGenerator::GetLinkRule(
|
||||
const std::string& linkRuleVar)
|
||||
{
|
||||
std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar);
|
||||
if (this->GeneratorTarget->HasImplibGNUtoMS()) {
|
||||
if (this->GeneratorTarget->HasImplibGNUtoMS(this->ConfigName)) {
|
||||
std::string ruleVar = "CMAKE_";
|
||||
ruleVar += this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
|
||||
ruleVar += "_GNUtoMS_RULE";
|
||||
|
||||
@@ -482,7 +482,7 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd()
|
||||
const char* linkCmd = mf->GetDefinition(linkCmdVar);
|
||||
if (linkCmd) {
|
||||
std::string linkCmdStr = linkCmd;
|
||||
if (this->GetGeneratorTarget()->HasImplibGNUtoMS()) {
|
||||
if (this->GetGeneratorTarget()->HasImplibGNUtoMS(this->ConfigName)) {
|
||||
std::string ruleVar = "CMAKE_";
|
||||
ruleVar += this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
|
||||
ruleVar += "_GNUtoMS_RULE";
|
||||
@@ -881,7 +881,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
|
||||
targetOutputImplib, cmOutputConverter::SHELL);
|
||||
vars["TARGET_IMPLIB"] = impLibPath;
|
||||
EnsureParentDirectoryExists(impLibPath);
|
||||
if (genTarget.HasImportLibrary()) {
|
||||
if (genTarget.HasImportLibrary(cfgName)) {
|
||||
byproducts.push_back(targetOutputImplib);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2418,6 +2418,22 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
|
||||
clOptions.AddFlag("AssemblerListingLocation", asmLocation);
|
||||
}
|
||||
}
|
||||
|
||||
// check for managed C++ assembly compiler flag. This overrides any
|
||||
// /clr* compiler flags which may be defined in the flags variable(s).
|
||||
if (this->ProjectType != csproj) {
|
||||
// TODO: add check here, if /clr was defined manually and issue
|
||||
// warning that this is discouraged.
|
||||
if (auto* clr =
|
||||
this->GeneratorTarget->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
|
||||
std::string clrString = clr;
|
||||
if (!clrString.empty()) {
|
||||
clrString = ":" + clrString;
|
||||
}
|
||||
flags += " /clr" + clrString;
|
||||
}
|
||||
}
|
||||
|
||||
clOptions.Parse(flags.c_str());
|
||||
clOptions.Parse(defineFlags.c_str());
|
||||
std::vector<std::string> targetDefines;
|
||||
|
||||
Reference in New Issue
Block a user