Commit 498be66f authored by Brad King's avatar Brad King Committed by Kitware Robot
Browse files

Merge topic 'add_support_for_clr_targets'

312527de document COMMON_LANGUAGE_RUNTIME target properties
4b7a82b4 cmVisualStudio10TargetGenerator: set /clr compiler flag from property
20e31fb4 cmExportFileGenerator: add target property for managed targets
411a2270 cmGeneratorTarget: add handling of managed assemblies to HasImportLibrary()
fb433ff2 cmGeneratorTarget: Make import library checks config-aware
4c1f3396 cmGeneratorTarget: add GetManagedType() and CheckManagedType() methods
6c517a9f

 cmGeneratorTarget: add HasLanguage() as wrapper for GetLanguages()
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Merge-request: !1916
parents 2cdefcbe 312527de
Pipeline #98404 passed with stage
in 0 seconds
......@@ -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
......
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`
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.
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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment