summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2018-04-26 12:55:06 (GMT)
committerKitware Robot <kwrobot@kitware.com>2018-04-26 12:55:19 (GMT)
commite52cf1034f1cb712dca28131fc113db0fb580db9 (patch)
tree69dd7745865841642522015ef1e96c2021355902 /Source
parent6fd60c6ef0053406b4a88fc2b79c00f49c5bac7a (diff)
parentde549083e34906e4778a709497adc99f7f0dccbb (diff)
downloadCMake-e52cf1034f1cb712dca28131fc113db0fb580db9.zip
CMake-e52cf1034f1cb712dca28131fc113db0fb580db9.tar.gz
CMake-e52cf1034f1cb712dca28131fc113db0fb580db9.tar.bz2
Merge topic 'csharp_reference_imported_targets'
de549083e3 cmVisualStudio10TargetGenerator: warn if /clr flag is set manually 59ec7d50bd cmVisualStudio10TargetGenerator: fix for backward compatibility 663f5120f4 cmGlobalVisualStudioGenerator: remove TargetCanBeReferenced() 359544a907 add tests for using target_link_libraries() with imported managed targets 43571073e0 cmVisualStudio10TargetGenerator: store managed reference information in maps 16fec7e2fc cmVisualStudio10TargetGenerator: make some methods config aware f3c6828876 cmVisualStudio10TargetGenerator: /clr compatible flags for managed tgt f9042d807d remove TargetIsCSharpOnly() and use methods from cmGeneratorTarget ... Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !1805
Diffstat (limited to 'Source')
-rw-r--r--Source/cmExportFileGenerator.cxx9
-rw-r--r--Source/cmGeneratorTarget.cxx8
-rw-r--r--Source/cmGlobalVisualStudio71Generator.cxx2
-rw-r--r--Source/cmGlobalVisualStudioGenerator.cxx36
-rw-r--r--Source/cmGlobalVisualStudioGenerator.h6
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx147
-rw-r--r--Source/cmVisualStudio10TargetGenerator.h17
7 files changed, 143 insertions, 82 deletions
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 8894d44..bf9d341 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -786,9 +786,14 @@ void cmExportFileGenerator::SetImportDetailProperties(
std::string propval;
if (auto* p = target->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
propval = p;
+ } else if (target->HasLanguage("CSharp", config)) {
+ // C# projects do not have the /clr flag, so we set the property
+ // here to mark the target as (only) managed (i.e. no .lib file
+ // to link to). Otherwise the COMMON_LANGUAGE_RUNTIME target
+ // property would have to be set manually for C# targets to make
+ // exporting/importing work.
+ propval = "CSharp";
}
- // TODO: make sure propval is set to non-empty string for
- // CSharp targets (i.e. force ManagedType::Managed).
properties[prop] = propval;
}
}
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 0cb299c..bf5ff65 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -5530,7 +5530,9 @@ cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType(
return this->CheckManagedType(clr);
}
- // TODO: need to check if target is a CSharp target here.
- // If yes: return ManagedType::Managed.
- return ManagedType::Native;
+ // C# targets are always managed. This language specific check
+ // is added to avoid that the COMMON_LANGUAGE_RUNTIME target property
+ // has to be set manually for C# targets.
+ return this->HasLanguage("CSharp", config) ? ManagedType::Managed
+ : ManagedType::Native;
}
diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx
index 45cc583..0b086b0 100644
--- a/Source/cmGlobalVisualStudio71Generator.cxx
+++ b/Source/cmGlobalVisualStudio71Generator.cxx
@@ -98,7 +98,7 @@ void cmGlobalVisualStudio71Generator::WriteProject(std::ostream& fout,
ext = ".vfproj";
project = "Project(\"{6989167D-11E4-40FE-8C1A-2192A86A7E90}\") = \"";
}
- if (this->TargetIsCSharpOnly(t)) {
+ if (t->HasLanguage("CSharp", "")) {
ext = ".csproj";
project = "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"";
}
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index fa7dc51..1175acf 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -734,42 +734,6 @@ bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly(
return false;
}
-bool cmGlobalVisualStudioGenerator::TargetIsCSharpOnly(
- cmGeneratorTarget const* gt)
-{
- // C# targets can be defined with add_library() (using SHARED or STATIC) and
- // also using add_executable(). We do not treat imported C# targets the same
- // (these come in as UTILITY)
- if (gt->GetType() != cmStateEnums::SHARED_LIBRARY &&
- gt->GetType() != cmStateEnums::STATIC_LIBRARY &&
- gt->GetType() != cmStateEnums::EXECUTABLE) {
- return false;
- }
-
- // Issue diagnostic if the source files depend on the config.
- std::vector<cmSourceFile*> sources;
- if (!gt->GetConfigCommonSourceFiles(sources)) {
- return false;
- }
-
- std::set<std::string> languages;
- gt->GetLanguages(languages, "");
- return languages.size() == 1 && languages.count("CSharp") > 0;
-}
-
-bool cmGlobalVisualStudioGenerator::TargetCanBeReferenced(
- cmGeneratorTarget const* gt)
-{
- if (this->TargetIsCSharpOnly(gt)) {
- return true;
- }
- if (gt->GetType() != cmStateEnums::SHARED_LIBRARY &&
- gt->GetType() != cmStateEnums::EXECUTABLE) {
- return false;
- }
- return true;
-}
-
bool cmGlobalVisualStudioGenerator::TargetCompare::operator()(
cmGeneratorTarget const* l, cmGeneratorTarget const* r) const
{
diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h
index f39dcca..07bc9a3 100644
--- a/Source/cmGlobalVisualStudioGenerator.h
+++ b/Source/cmGlobalVisualStudioGenerator.h
@@ -81,12 +81,6 @@ public:
// return true if target is fortran only
bool TargetIsFortranOnly(const cmGeneratorTarget* gt);
- // return true if target is C# only
- static bool TargetIsCSharpOnly(cmGeneratorTarget const* gt);
-
- // return true if target can be referenced by C# targets
- bool TargetCanBeReferenced(cmGeneratorTarget const* gt);
-
/** Get the top-level registry key for this VS version. */
std::string GetRegistryBase();
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 71fe300..5c3b134 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -208,9 +208,7 @@ static std::string computeProjectFileExtension(cmGeneratorTarget const* t,
{
std::string res;
res = ".vcxproj";
- std::string lang = t->GetLinkerLanguage(config);
- if (cmGlobalVisualStudioGenerator::TargetIsCSharpOnly(t) ||
- lang == "CSharp") {
+ if (t->HasLanguage("CSharp", config)) {
res = ".csproj";
}
return res;
@@ -350,6 +348,8 @@ void cmVisualStudio10TargetGenerator::Generate()
this->Name.c_str());
this->GeneratorTarget->Target->SetProperty(
"GENERATOR_FILE_NAME_EXT", this->ProjectFileExtension.c_str());
+ this->DotNetHintReferences.clear();
+ this->AdditionalUsingDirectories.clear();
if (this->GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY) {
if (!this->ComputeClOptions()) {
return;
@@ -710,8 +710,6 @@ void cmVisualStudio10TargetGenerator::Generate()
void cmVisualStudio10TargetGenerator::WriteDotNetReferences()
{
std::vector<std::string> references;
- typedef std::pair<std::string, std::string> HintReference;
- std::vector<HintReference> hintReferences;
if (const char* vsDotNetReferences =
this->GeneratorTarget->GetProperty("VS_DOTNET_REFERENCES")) {
cmSystemTools::ExpandListArgument(vsDotNetReferences, references);
@@ -727,11 +725,12 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferences()
"/" + path;
}
ConvertToWindowsSlash(path);
- hintReferences.push_back(HintReference(name, path));
+ this->DotNetHintReferences[""].push_back(
+ DotNetHintReference(name, path));
}
}
}
- if (!references.empty() || !hintReferences.empty()) {
+ if (!references.empty() || !this->DotNetHintReferences.empty()) {
this->WriteString("<ItemGroup>\n", 1);
for (std::string const& ri : references) {
// if the entry from VS_DOTNET_REFERENCES is an existing file, generate
@@ -740,23 +739,36 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferences()
std::string name = cmsys::SystemTools::GetFilenameWithoutExtension(ri);
std::string path = ri;
ConvertToWindowsSlash(path);
- hintReferences.push_back(HintReference(name, path));
+ this->DotNetHintReferences[""].push_back(
+ DotNetHintReference(name, path));
} else {
- this->WriteDotNetReference(ri, "");
+ this->WriteDotNetReference(ri, "", "");
}
}
- for (const auto& i : hintReferences) {
- this->WriteDotNetReference(i.first, i.second);
+ for (const auto& h : this->DotNetHintReferences) {
+ // DotNetHintReferences is also populated from AddLibraries().
+ // The configuration specific hint references are added there.
+ for (const auto& i : h.second) {
+ this->WriteDotNetReference(i.first, i.second, h.first);
+ }
}
this->WriteString("</ItemGroup>\n", 1);
}
}
void cmVisualStudio10TargetGenerator::WriteDotNetReference(
- std::string const& ref, std::string const& hint)
+ std::string const& ref, std::string const& hint, std::string const& config)
{
- this->WriteString("<Reference Include=\"", 2);
- (*this->BuildFileStream) << cmVS10EscapeAttr(ref) << "\">\n";
+ std::string attr = " Include=\"" + cmVS10EscapeAttr(ref) + "\"";
+ // If 'config' is not empty, the reference is only added for the given
+ // configuration. This is used when referencing imported managed assemblies.
+ // See also cmVisualStudio10TargetGenerator::AddLibraries().
+ if (!config.empty()) {
+ this->WritePlatformConfigTag("Reference", config, 2, attr.c_str());
+ } else {
+ this->WriteString("<Reference ", 2);
+ (*this->BuildFileStream) << attr << ">\n";
+ }
this->WriteElem("CopyLocalSatelliteAssemblies", "true", 3);
this->WriteElem("ReferenceOutputAssembly", "true", 3);
if (!hint.empty()) {
@@ -2510,8 +2522,20 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
// 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.
+ // Warn if /clr was added manually. This should not be done
+ // anymore, because cmGeneratorTarget may not be aware that the
+ // target uses C++/CLI.
+ if (flags.find("/clr") != std::string::npos ||
+ defineFlags.find("/clr") != std::string::npos) {
+ if (configName == this->Configurations[0]) {
+ std::string message = "For the target \"" +
+ this->GeneratorTarget->GetName() +
+ "\" the /clr compiler flag was added manually. " +
+ "Set usage of C++/CLI by setting COMMON_LANGUAGE_RUNTIME "
+ "target property.";
+ this->Makefile->IssueMessage(cmake::MessageType::WARNING, message);
+ }
+ }
if (auto* clr =
this->GeneratorTarget->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
std::string clrString = clr;
@@ -2584,10 +2608,15 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
if (this->ProjectType != csproj && clOptions.IsManaged()) {
this->Managed = true;
std::string managedType = clOptions.GetFlag("CompileAsManaged");
- if (managedType == "Safe") {
+ if (managedType == "Safe" || managedType == "Pure") {
// force empty calling convention if safe clr is used
clOptions.AddFlag("CallingConvention", "");
}
+ // The default values of these flags are incompatible to
+ // managed assemblies. We have to force valid values if
+ // the target is a managed C++ target.
+ clOptions.AddFlag("ExceptionHandling", "Async");
+ clOptions.AddFlag("BasicRuntimeChecks", "Default");
}
if (this->ProjectType == csproj) {
// /nowin32manifest overrides /win32manifest: parameter
@@ -2646,6 +2675,18 @@ void cmVisualStudio10TargetGenerator::WriteClOptions(
ConvertToWindowsSlash(pdb);
this->WriteElemEscapeXML("ProgramDataBaseFileName", pdb, 3);
}
+
+ // add AdditionalUsingDirectories
+ if (this->AdditionalUsingDirectories.count(configName) > 0) {
+ std::string dirs;
+ for (auto u : this->AdditionalUsingDirectories[configName]) {
+ if (!dirs.empty()) {
+ dirs.append(";");
+ }
+ dirs.append(u);
+ }
+ this->WriteElemEscapeXML("AdditionalUsingDirectories", dirs, 3);
+ }
}
this->WriteString("</ClCompile>\n", 2);
@@ -3289,7 +3330,7 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
std::vector<std::string> libVec;
std::vector<std::string> vsTargetVec;
- this->AddLibraries(cli, libVec, vsTargetVec);
+ this->AddLibraries(cli, libVec, vsTargetVec, config);
if (std::find(linkClosure->Languages.begin(), linkClosure->Languages.end(),
"CUDA") != linkClosure->Languages.end()) {
switch (this->CudaOptions[config]->GetCudaRuntime()) {
@@ -3505,23 +3546,51 @@ void cmVisualStudio10TargetGenerator::WriteLinkOptions(
}
void cmVisualStudio10TargetGenerator::AddLibraries(
- cmComputeLinkInformation& cli, std::vector<std::string>& libVec,
- std::vector<std::string>& vsTargetVec)
+ const cmComputeLinkInformation& cli, std::vector<std::string>& libVec,
+ std::vector<std::string>& vsTargetVec, const std::string& config)
{
typedef cmComputeLinkInformation::ItemVector ItemVector;
ItemVector const& libs = cli.GetItems();
std::string currentBinDir =
this->LocalGenerator->GetCurrentBinaryDirectory();
for (cmComputeLinkInformation::Item const& l : libs) {
- // Do not allow C# targets to be added to the LIB listing. LIB files are
- // used for linking C++ dependencies. C# libraries do not have lib files.
- // Instead, they compile down to C# reference libraries (DLL files). The
- // `<ProjectReference>` elements added to the vcxproj are enough for the
- // IDE to deduce the DLL file required by other C# projects that need its
- // reference library.
- if (l.Target &&
- cmGlobalVisualStudioGenerator::TargetIsCSharpOnly(l.Target)) {
- continue;
+ if (l.Target) {
+ auto managedType = l.Target->GetManagedType(config);
+ if (managedType != cmGeneratorTarget::ManagedType::Native &&
+ this->GeneratorTarget->GetManagedType(config) !=
+ cmGeneratorTarget::ManagedType::Native &&
+ l.Target->IsImported()) {
+ auto location = l.Target->GetFullPath(config);
+ if (!location.empty()) {
+ ConvertToWindowsSlash(location);
+ switch (this->ProjectType) {
+ case csproj:
+ // If the target we want to "link" to is an imported managed
+ // target and this is a C# project, we add a hint reference. This
+ // reference is written to project file in
+ // WriteDotNetReferences().
+ this->DotNetHintReferences[config].push_back(
+ DotNetHintReference(l.Target->GetName(), location));
+ break;
+ case vcxproj:
+ // Add path of assembly to list of using-directories, so the
+ // managed assembly can be used by '#using <assembly.dll>' in
+ // code.
+ this->AdditionalUsingDirectories[config].insert(
+ cmSystemTools::GetFilenamePath(location));
+ break;
+ }
+ }
+ }
+ // Do not allow C# targets to be added to the LIB listing. LIB files are
+ // used for linking C++ dependencies. C# libraries do not have lib files.
+ // Instead, they compile down to C# reference libraries (DLL files). The
+ // `<ProjectReference>` elements added to the vcxproj are enough for the
+ // IDE to deduce the DLL file required by other C# projects that need its
+ // reference library.
+ if (managedType == cmGeneratorTarget::ManagedType::Managed) {
+ continue;
+ }
}
if (l.IsPath) {
@@ -3746,8 +3815,24 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences()
"{" + this->GlobalGenerator->GetGUID(name) + "}", 3);
this->WriteElem("Name", name, 3);
this->WriteDotNetReferenceCustomTags(name);
- if (!this->GlobalGenerator->TargetCanBeReferenced(dt)) {
- this->WriteElem("ReferenceOutputAssembly", "false", 3);
+ if (this->Managed) {
+ // If the dependency target is not managed (compiled with /clr or
+ // C# target) we cannot reference it and have to set
+ // 'ReferenceOutputAssembly' to false.
+ cmGeneratorTarget::ManagedType check =
+ cmGeneratorTarget::ManagedType::Mixed;
+ // FIXME: These (5) lines should be removed. They are here to allow
+ // manual setting of the /clr flag in compiler options. Setting
+ // /clr manually makes cmGeneratorTarget::GetManagedType() return
+ // 'Native' instead of 'Mixed' or 'Managed'.
+ check = cmGeneratorTarget::ManagedType::Native;
+ bool unmanagedStatic = false;
+ if (dt->GetType() == cmStateEnums::STATIC_LIBRARY) {
+ unmanagedStatic = !dt->HasLanguage("CSharp", "");
+ }
+ if (dt->GetManagedType("") < check || unmanagedStatic) {
+ this->WriteElem("ReferenceOutputAssembly", "false", 3);
+ }
}
this->WriteString("</ProjectReference>\n", 2);
}
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 4d74afd..c8ca035 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -73,7 +73,8 @@ private:
std::vector<size_t> const& exclude_configs);
void WriteAllSources();
void WriteDotNetReferences();
- void WriteDotNetReference(std::string const& ref, std::string const& hint);
+ void WriteDotNetReference(std::string const& ref, std::string const& hint,
+ std::string const& config);
void WriteDotNetReferenceCustomTags(std::string const& ref);
void WriteEmbeddedResourceGroup();
void WriteWinRTReferences();
@@ -148,9 +149,10 @@ private:
void WriteProjectReferences();
void WriteApplicationTypeSettings();
void OutputSourceSpecificFlags(Elem&, cmSourceFile const* source);
- void AddLibraries(cmComputeLinkInformation& cli,
+ void AddLibraries(const cmComputeLinkInformation& cli,
std::vector<std::string>& libVec,
- std::vector<std::string>& vsTargetVec);
+ std::vector<std::string>& vsTargetVec,
+ const std::string& config);
void AddTargetsFileAndConfigPair(std::string const& targetsFile,
std::string const& config);
void WriteLibOptions(std::string const& config);
@@ -214,6 +216,15 @@ private:
bool IsMissingFiles;
std::vector<std::string> AddedFiles;
std::string DefaultArtifactDir;
+ // managed C++/C# relevant members
+ typedef std::pair<std::string, std::string> DotNetHintReference;
+ typedef std::vector<DotNetHintReference> DotNetHintReferenceList;
+ typedef std::map<std::string, DotNetHintReferenceList>
+ DotNetHintReferenceMap;
+ DotNetHintReferenceMap DotNetHintReferences;
+ typedef std::set<std::string> UsingDirectories;
+ typedef std::map<std::string, UsingDirectories> UsingDirectoriesMap;
+ UsingDirectoriesMap AdditionalUsingDirectories;
typedef std::map<std::string, ToolSources> ToolSourceMap;
ToolSourceMap Tools;