diff options
-rw-r--r-- | Modules/Platform/Windows-MSVC.cmake | 28 | ||||
-rw-r--r-- | Source/CMakeVersion.cmake | 2 | ||||
-rw-r--r-- | Source/cmGlobalVisualStudioGenerator.cxx | 34 | ||||
-rw-r--r-- | Source/cmMakefile.cxx | 12 | ||||
-rw-r--r-- | Source/cmMakefile.h | 3 | ||||
-rw-r--r-- | Source/cmVisualStudio10TargetGenerator.cxx | 99 | ||||
-rw-r--r-- | Source/cmVisualStudio10TargetGenerator.h | 2 | ||||
-rw-r--r-- | Source/cmVisualStudioGeneratorOptions.cxx | 48 | ||||
-rw-r--r-- | Source/cmVisualStudioGeneratorOptions.h | 2 | ||||
-rw-r--r-- | Tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Tests/CSharpLinkFromCxx/.gitattributes | 1 | ||||
-rw-r--r-- | Tests/CSharpLinkFromCxx/CMakeLists.txt | 19 | ||||
-rw-r--r-- | Tests/CSharpLinkFromCxx/CSharpLinkFromCxx.cs | 16 | ||||
-rw-r--r-- | Tests/CSharpLinkFromCxx/UsefulCSharpClass.cs | 12 | ||||
-rw-r--r-- | Tests/CSharpLinkFromCxx/UsefulManagedCppClass.cpp | 15 | ||||
-rw-r--r-- | Tests/CSharpLinkFromCxx/UsefulManagedCppClass.hpp | 16 |
16 files changed, 209 insertions, 101 deletions
diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake index 0737c12..a1f54c0 100644 --- a/Modules/Platform/Windows-MSVC.cmake +++ b/Modules/Platform/Windows-MSVC.cmake @@ -293,6 +293,34 @@ macro(__windows_compiler_msvc lang) set(CMAKE_${lang}_LINK_EXECUTABLE "${_CMAKE_VS_LINK_EXE}<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}") + if("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xMSVC") + set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES) + set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES) + + set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "/GL") + set(CMAKE_${lang}_LINK_OPTIONS_IPO "/INCREMENTAL:NO" "/LTCG") + string(REPLACE "<LINK_FLAGS> " "/LTCG <LINK_FLAGS> " + CMAKE_${lang}_CREATE_STATIC_LIBRARY_IPO "${CMAKE_${lang}_CREATE_STATIC_LIBRARY}") + elseif("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xClang" OR + "x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xFlang") + set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES) + set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES) + + # '-flto=thin' available since Clang 3.9 and Xcode 8 + # * http://clang.llvm.org/docs/ThinLTO.html#clang-llvm + # * https://trac.macports.org/wiki/XcodeVersionInfo + set(_CMAKE_LTO_THIN TRUE) + if(CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 3.9) + set(_CMAKE_LTO_THIN FALSE) + endif() + + if(_CMAKE_LTO_THIN) + set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "-flto=thin") + else() + set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "-flto") + endif() + endif() + if("x${lang}" STREQUAL "xC" OR "x${lang}" STREQUAL "xCXX") if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*") diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index b2684f3..f1fdb60 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 11) -set(CMake_VERSION_PATCH 20180223) +set(CMake_VERSION_PATCH 20180226) #set(CMake_VERSION_RC 1) diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index a4570e1..fa7dc51 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -737,26 +737,24 @@ bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly( bool cmGlobalVisualStudioGenerator::TargetIsCSharpOnly( cmGeneratorTarget const* gt) { - // check to see if this is a C# build - std::set<std::string> languages; - { - // Issue diagnostic if the source files depend on the config. - std::vector<cmSourceFile*> sources; - if (!gt->GetConfigCommonSourceFiles(sources)) { - return false; - } - // Only "real" targets are allowed to be C# targets. - if (gt->Target->GetType() > cmStateEnums::OBJECT_LIBRARY) { - return false; - } + // 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; } - gt->GetLanguages(languages, ""); - if (languages.size() == 1) { - if (*languages.begin() == "CSharp") { - return true; - } + + // Issue diagnostic if the source files depend on the config. + std::vector<cmSourceFile*> sources; + if (!gt->GetConfigCommonSourceFiles(sources)) { + return false; } - return false; + + std::set<std::string> languages; + gt->GetLanguages(languages, ""); + return languages.size() == 1 && languages.count("CSharp") > 0; } bool cmGlobalVisualStudioGenerator::TargetCanBeReferenced( diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 82c6e81..47d75af 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -3138,6 +3138,14 @@ void cmMakefile::SetArgcArgv(const std::vector<std::string>& args) cmSourceFile* cmMakefile::GetSource(const std::string& sourceName, cmSourceFileLocationKind kind) const { + // First check "Known" paths (avoids the creation of cmSourceFileLocation) + if (kind == cmSourceFileLocationKind::Known) { + auto sfsi = this->KnownFileSearchIndex.find(sourceName); + if (sfsi != this->KnownFileSearchIndex.end()) { + return sfsi->second; + } + } + cmSourceFileLocation sfl(this, sourceName, kind); auto name = this->GetCMakeInstance()->StripExtension(sfl.GetName()); #if defined(_WIN32) || defined(__APPLE__) @@ -3170,6 +3178,10 @@ cmSourceFile* cmMakefile::CreateSource(const std::string& sourceName, name = cmSystemTools::LowerCase(name); #endif this->SourceFileSearchIndex[name].push_back(sf); + // for "Known" paths add direct lookup (used for faster lookup in GetSource) + if (kind == cmSourceFileLocationKind::Known) { + this->KnownFileSearchIndex[sourceName] = sf; + } return sf; } diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 5a30790..95ba53a 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -861,6 +861,9 @@ protected: typedef std::unordered_map<std::string, SourceFileVec> SourceFileMap; SourceFileMap SourceFileSearchIndex; + // For "Known" paths we can store a direct filename to cmSourceFile map + std::unordered_map<std::string, cmSourceFile*> KnownFileSearchIndex; + // Tests std::map<std::string, cmTest*> Tests; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 92d67db..c7b60b9 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -856,10 +856,7 @@ void cmVisualStudio10TargetGenerator::WriteTargetSpecificReferences() void cmVisualStudio10TargetGenerator::WriteTargetsFileReferences() { - for (std::vector<TargetsFileAndConfigs>::iterator i = - this->TargetsFileAndConfigsVec.begin(); - i != this->TargetsFileAndConfigsVec.end(); ++i) { - TargetsFileAndConfigs const& tac = *i; + for (TargetsFileAndConfigs const& tac : this->TargetsFileAndConfigsVec) { this->WriteString("<Import Project=\"", 3); (*this->BuildFileStream) << tac.File << "\" "; (*this->BuildFileStream) << "Condition=\""; @@ -894,10 +891,9 @@ void cmVisualStudio10TargetGenerator::WriteWinRTReferences() } if (!references.empty()) { this->WriteString("<ItemGroup>\n", 1); - for (std::vector<std::string>::iterator ri = references.begin(); - ri != references.end(); ++ri) { + for (std::string const& ri : references) { this->WriteString("<Reference Include=\"", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(*ri) << "\">\n"; + (*this->BuildFileStream) << cmVS10EscapeXML(ri) << "\">\n"; this->WriteString("<IsWinMDFile>true</IsWinMDFile>\n", 3); this->WriteString("</Reference>\n", 2); } @@ -910,13 +906,11 @@ void cmVisualStudio10TargetGenerator::WriteWinRTReferences() void cmVisualStudio10TargetGenerator::WriteProjectConfigurations() { this->WriteString("<ItemGroup Label=\"ProjectConfigurations\">\n", 1); - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { + for (std::string const& c : this->Configurations) { this->WriteString("<ProjectConfiguration Include=\"", 2); - (*this->BuildFileStream) << *i << "|" << this->Platform << "\">\n"; + (*this->BuildFileStream) << c << "|" << this->Platform << "\">\n"; this->WriteString("<Configuration>", 3); - (*this->BuildFileStream) << *i << "</Configuration>\n"; + (*this->BuildFileStream) << c << "</Configuration>\n"; this->WriteString("<Platform>", 3); (*this->BuildFileStream) << cmVS10EscapeXML(this->Platform) << "</Platform>\n"; @@ -927,10 +921,8 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurations() void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues() { - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { - this->WritePlatformConfigTag("PropertyGroup", *i, 1, + for (std::string const& c : this->Configurations) { + this->WritePlatformConfigTag("PropertyGroup", c, 1, " Label=\"Configuration\"", "\n"); if (this->ProjectType != csproj) { @@ -977,12 +969,12 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues() if (this->MSTools) { if (!this->Managed) { - this->WriteMSToolConfigurationValues(*i); + this->WriteMSToolConfigurationValues(c); } else { - this->WriteMSToolConfigurationValuesManaged(*i); + this->WriteMSToolConfigurationValuesManaged(c); } } else if (this->NsightTegra) { - this->WriteNsightTegraConfigurationValues(*i); + this->WriteNsightTegraConfigurationValues(c); } this->WriteString("</PropertyGroup>\n", 1); @@ -1132,10 +1124,8 @@ void cmVisualStudio10TargetGenerator::WriteCustomCommands() this->CSharpCustomCommandNames.clear(); std::vector<cmSourceFile const*> customCommands; this->GeneratorTarget->GetCustomCommands(customCommands, ""); - for (std::vector<cmSourceFile const*>::const_iterator si = - customCommands.begin(); - si != customCommands.end(); ++si) { - this->WriteCustomCommand(*si); + for (cmSourceFile const* si : customCommands) { + this->WriteCustomCommand(si); } // Add CMakeLists.txt file with rule to re-run CMake for user convenience. @@ -1154,9 +1144,8 @@ void cmVisualStudio10TargetGenerator::WriteCustomCommand( if (this->SourcesVisited.insert(sf).second) { if (std::vector<cmSourceFile*> const* depends = this->GeneratorTarget->GetSourceDepends(sf)) { - for (std::vector<cmSourceFile*>::const_iterator di = depends->begin(); - di != depends->end(); ++di) { - this->WriteCustomCommand(*di); + for (cmSourceFile const* di : *depends) { + this->WriteCustomCommand(di); } } if (cmCustomCommand const* command = sf->GetCustomCommand()) { @@ -1179,10 +1168,10 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( // VS 10 will always rebuild a custom command attached to a .rule // file that doesn't exist so create the file explicitly. if (source->GetPropertyAsBool("__CMAKE_RULE")) { - if (!cmSystemTools::FileExists(sourcePath.c_str())) { + if (!cmSystemTools::FileExists(sourcePath)) { // Make sure the path exists for the file std::string path = cmSystemTools::GetFilenamePath(sourcePath); - cmSystemTools::MakeDirectory(path.c_str()); + cmSystemTools::MakeDirectory(path); cmsys::ofstream fout(sourcePath.c_str()); if (fout) { fout << "# generated from CMake\n"; @@ -1216,20 +1205,17 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( this->WriteString("</None>\n", 2); this->WriteString("</ItemGroup>\n", 1); } - for (std::vector<std::string>::const_iterator i = - this->Configurations.begin(); - i != this->Configurations.end(); ++i) { - cmCustomCommandGenerator ccg(command, *i, lg); + for (std::string const& c : this->Configurations) { + cmCustomCommandGenerator ccg(command, c, lg); std::string comment = lg->ConstructComment(ccg); comment = cmVS10EscapeComment(comment); std::string script = cmVS10EscapeXML(lg->ConstructScript(ccg)); // input files for custom command std::stringstream inputs; inputs << cmVS10EscapeXML(source->GetFullPath()); - for (std::vector<std::string>::const_iterator d = ccg.GetDepends().begin(); - d != ccg.GetDepends().end(); ++d) { + for (std::string const& d : ccg.GetDepends()) { std::string dep; - if (lg->GetRealDependency(*d, *i, dep)) { + if (lg->GetRealDependency(d, c, dep)) { ConvertToWindowsSlash(dep); inputs << ";" << cmVS10EscapeXML(dep); } @@ -1237,15 +1223,14 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( // output files for custom command std::stringstream outputs; const char* sep = ""; - for (std::vector<std::string>::const_iterator o = ccg.GetOutputs().begin(); - o != ccg.GetOutputs().end(); ++o) { - std::string out = *o; + for (std::string const& o : ccg.GetOutputs()) { + std::string out = o; ConvertToWindowsSlash(out); outputs << sep << cmVS10EscapeXML(out); sep = ";"; } if (this->ProjectType == csproj) { - std::string name = "CustomCommand_" + *i + "_" + + std::string name = "CustomCommand_" + c + "_" + cmSystemTools::ComputeStringMD5(sourcePath); std::string inputs_s = inputs.str(); std::string outputs_s = outputs.str(); @@ -1253,10 +1238,10 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( script = cmVS10EscapeQuotes(script); inputs_s = cmVS10EscapeQuotes(inputs_s); outputs_s = cmVS10EscapeQuotes(outputs_s); - this->WriteCustomRuleCSharp(*i, name, script, inputs_s, outputs_s, + this->WriteCustomRuleCSharp(c, name, script, inputs_s, outputs_s, comment); } else { - this->WriteCustomRuleCpp(*i, script, inputs.str(), outputs.str(), + this->WriteCustomRuleCpp(c, script, inputs.str(), outputs.str(), comment); } } @@ -1314,8 +1299,8 @@ std::string cmVisualStudio10TargetGenerator::ConvertPath( { return forceRelative ? cmSystemTools::RelativePath( - this->LocalGenerator->GetCurrentBinaryDirectory(), path.c_str()) - : path.c_str(); + this->LocalGenerator->GetCurrentBinaryDirectory(), path) + : path; } static void ConvertToWindowsSlash(std::string& s) @@ -1341,10 +1326,8 @@ void cmVisualStudio10TargetGenerator::WriteGroups() this->GeneratorTarget->GetAllConfigSources(); std::set<cmSourceGroup*> groupsUsed; - for (std::vector<cmGeneratorTarget::AllConfigSource>::const_iterator si = - sources.begin(); - si != sources.end(); ++si) { - std::string const& source = si->Source->GetFullPath(); + for (cmGeneratorTarget::AllConfigSource const& si : sources) { + std::string const& source = si.Source->GetFullPath(); cmSourceGroup* sourceGroup = this->Makefile->FindSourceGroup(source, sourceGroups); groupsUsed.insert(sourceGroup); @@ -1376,9 +1359,8 @@ void cmVisualStudio10TargetGenerator::WriteGroups() "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"); this->WriteString(project_defaults.c_str(), 0); - for (ToolSourceMap::const_iterator ti = this->Tools.begin(); - ti != this->Tools.end(); ++ti) { - this->WriteGroupSources(ti->first.c_str(), ti->second, sourceGroups); + for (auto const& ti : this->Tools) { + this->WriteGroupSources(ti.first.c_str(), ti.second, sourceGroups); } // Added files are images and the manifest. @@ -1510,7 +1492,7 @@ void cmVisualStudio10TargetGenerator::AddMissingSourceGroups( } void cmVisualStudio10TargetGenerator::WriteGroupSources( - const char* name, ToolSources const& sources, + std::string const& name, ToolSources const& sources, std::vector<cmSourceGroup>& sourceGroups) { this->WriteString("<ItemGroup>\n", 1); @@ -1847,7 +1829,7 @@ void cmVisualStudio10TargetGenerator::WriteSource(std::string const& tool, std::string sourceFile = this->ConvertPath(sf->GetFullPath(), forceRelative); if (this->LocalGenerator->GetVersion() == cmGlobalVisualStudioGenerator::VS10 && - cmSystemTools::FileIsFullPath(sourceFile.c_str())) { + cmSystemTools::FileIsFullPath(sourceFile)) { // Normal path conversion resulted in a full path. VS 10 (but not 11) // refuses to show the property page in the IDE for a source file with a // full path (not starting in a '.' or '/' AFAICT). CMake <= 2.8.4 used a @@ -2168,7 +2150,7 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( *source); } clOptions.AddIncludes(includeList); - clOptions.SetConfiguration(config.c_str()); + clOptions.SetConfiguration(config); clOptions.PrependInheritedString("AdditionalOptions"); clOptions.OutputAdditionalIncludeDirectories(*this->BuildFileStream, " ", "\n", lang); @@ -3451,6 +3433,17 @@ void cmVisualStudio10TargetGenerator::AddLibraries( 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.IsPath) { std::string path = this->LocalGenerator->ConvertToRelativePath(currentBinDir, l.Value); diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index adef127..124db4e 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -153,7 +153,7 @@ private: void WriteEvent(const char* name, std::vector<cmCustomCommand> const& commands, std::string const& configName); - void WriteGroupSources(const char* name, ToolSources const& sources, + void WriteGroupSources(std::string const& name, ToolSources const& sources, std::vector<cmSourceGroup>&); void AddMissingSourceGroups(std::set<cmSourceGroup*>& groupsUsed, const std::vector<cmSourceGroup>& allGroups); diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index ccbff83..fb74fda 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -152,9 +152,8 @@ bool cmVisualStudioGeneratorOptions::IsManaged() const bool cmVisualStudioGeneratorOptions::UsingUnicode() const { // Look for the a _UNICODE definition. - for (std::vector<std::string>::const_iterator di = this->Defines.begin(); - di != this->Defines.end(); ++di) { - if (*di == "_UNICODE") { + for (std::string const& di : this->Defines) { + if (di == "_UNICODE") { return true; } } @@ -163,9 +162,8 @@ bool cmVisualStudioGeneratorOptions::UsingUnicode() const bool cmVisualStudioGeneratorOptions::UsingSBCS() const { // Look for the a _SBCS definition. - for (std::vector<std::string>::const_iterator di = this->Defines.begin(); - di != this->Defines.end(); ++di) { - if (*di == "_SBCS") { + for (std::string const& di : this->Defines) { + if (di == "_SBCS") { return true; } } @@ -227,7 +225,7 @@ void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration() // It translates to -arch=<virtual> -code=<real>. cmSystemTools::ReplaceString(arch_name, "sm_", "compute_"); } - for (auto const& c : codes) { + for (std::string const& c : codes) { std::string entry = arch_name + "," + c; result.push_back(entry); } @@ -237,7 +235,7 @@ void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration() // -gencode=<arch>,<code> // -gencode=<arch>,[<code1>,<code2>] // -gencode=<arch>,"<code1>,<code2>" - for (auto const& e : gencode) { + for (std::string const& e : gencode) { std::string entry = e; cmSystemTools::ReplaceString(entry, "arch=", ""); cmSystemTools::ReplaceString(entry, "code=", ""); @@ -285,7 +283,7 @@ void cmVisualStudioGeneratorOptions::FixManifestUACFlags() uacExecuteLevelMap["highestAvailable"] = "HighestAvailable"; uacExecuteLevelMap["requireAdministrator"] = "RequireAdministrator"; - for (auto const& subopt : subOptions) { + for (std::string const& subopt : subOptions) { std::vector<std::string> keyValue; cmsys::SystemTools::Split(subopt, keyValue, '='); if (keyValue.size() != 2 || (uacMap.find(keyValue[0]) == uacMap.end())) { @@ -332,9 +330,8 @@ void cmVisualStudioGeneratorOptions::Parse(const char* flags) // Process flags that need to be represented specially in the IDE // project file. - for (std::vector<std::string>::iterator ai = args.begin(); ai != args.end(); - ++ai) { - this->HandleFlag(ai->c_str()); + for (std::string const& ai : args) { + this->HandleFlag(ai.c_str()); } } @@ -437,7 +434,8 @@ cmIDEOptions::FlagValue cmVisualStudioGeneratorOptions::TakeFlag( return value; } -void cmVisualStudioGeneratorOptions::SetConfiguration(const char* config) +void cmVisualStudioGeneratorOptions::SetConfiguration( + const std::string& config) { this->Configuration = config; } @@ -566,31 +564,27 @@ void cmVisualStudioGeneratorOptions::OutputFlagMap(std::ostream& fout, const char* indent) { if (this->Version >= cmGlobalVisualStudioGenerator::VS10) { - for (std::map<std::string, FlagValue>::iterator m = this->FlagMap.begin(); - m != this->FlagMap.end(); ++m) { + for (auto const& m : this->FlagMap) { fout << indent; if (!this->Configuration.empty()) { this->TargetGenerator->WritePlatformConfigTag( - m->first.c_str(), this->Configuration.c_str(), 0, 0, 0, &fout); + m.first.c_str(), this->Configuration.c_str(), 0, 0, 0, &fout); } else { - fout << "<" << m->first << ">"; + fout << "<" << m.first << ">"; } const char* sep = ""; - for (std::vector<std::string>::iterator i = m->second.begin(); - i != m->second.end(); ++i) { - fout << sep << cmVisualStudio10GeneratorOptionsEscapeForXML(*i); + for (std::string const& i : m.second) { + fout << sep << cmVisualStudio10GeneratorOptionsEscapeForXML(i); sep = ";"; } - fout << "</" << m->first << ">\n"; + fout << "</" << m.first << ">\n"; } } else { - for (std::map<std::string, FlagValue>::iterator m = this->FlagMap.begin(); - m != this->FlagMap.end(); ++m) { - fout << indent << m->first << "=\""; + for (auto const& m : this->FlagMap) { + fout << indent << m.first << "=\""; const char* sep = ""; - for (std::vector<std::string>::iterator i = m->second.begin(); - i != m->second.end(); ++i) { - fout << sep << cmVisualStudioGeneratorOptionsEscapeForXML(*i); + for (std::string const& i : m.second) { + fout << sep << cmVisualStudioGeneratorOptionsEscapeForXML(i); sep = ";"; } fout << "\"\n"; diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h index 2dffe9b..2c56d42 100644 --- a/Source/cmVisualStudioGeneratorOptions.h +++ b/Source/cmVisualStudioGeneratorOptions.h @@ -91,7 +91,7 @@ public: const char* suffix, const std::string& lang); void OutputFlagMap(std::ostream& fout, const char* indent); - void SetConfiguration(const char* config); + void SetConfiguration(const std::string& config); private: cmLocalVisualStudioGenerator* LocalGenerator; diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 93837dd..0ce6d72 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -348,6 +348,7 @@ if(BUILD_TESTING) if(${CMAKE_GENERATOR} MATCHES "Visual Studio ([^89]|[89][0-9])") ADD_TEST_MACRO(CSharpOnly CSharpOnly) ADD_TEST_MACRO(CSharpLinkToCxx CSharpLinkToCxx) + ADD_TEST_MACRO(CSharpLinkFromCxx CSharpLinkFromCxx) endif() ADD_TEST_MACRO(COnly COnly) diff --git a/Tests/CSharpLinkFromCxx/.gitattributes b/Tests/CSharpLinkFromCxx/.gitattributes new file mode 100644 index 0000000..57a39049 --- /dev/null +++ b/Tests/CSharpLinkFromCxx/.gitattributes @@ -0,0 +1 @@ +UsefulManagedCppClass.* -format.clang-format diff --git a/Tests/CSharpLinkFromCxx/CMakeLists.txt b/Tests/CSharpLinkFromCxx/CMakeLists.txt new file mode 100644 index 0000000..9a1a993 --- /dev/null +++ b/Tests/CSharpLinkFromCxx/CMakeLists.txt @@ -0,0 +1,19 @@ +# Take a C# shared library and link it to a managed C++ shared library +cmake_minimum_required(VERSION 3.10) +project (CSharpLinkFromCxx CXX CSharp) + +add_library(CSharpLibrary SHARED UsefulCSharpClass.cs) + +# we have to change the default flags for the +# managed C++ project to build +string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) +string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) + +# The C# project is a dependency of the C++/CLI project +add_library(ManagedCppLibrary SHARED UsefulManagedCppClass.cpp UsefulManagedCppClass.hpp) +target_compile_options(ManagedCppLibrary PRIVATE "/clr") +target_link_libraries(ManagedCppLibrary PUBLIC CSharpLibrary) + +# Main executable for the test framework +add_executable(CSharpLinkFromCxx CSharpLinkFromCxx.cs) +target_link_libraries(CSharpLinkFromCxx PRIVATE ManagedCppLibrary) diff --git a/Tests/CSharpLinkFromCxx/CSharpLinkFromCxx.cs b/Tests/CSharpLinkFromCxx/CSharpLinkFromCxx.cs new file mode 100644 index 0000000..31a74eb --- /dev/null +++ b/Tests/CSharpLinkFromCxx/CSharpLinkFromCxx.cs @@ -0,0 +1,16 @@ +using System; +using CSharpLibrary; + +namespace CSharpLinkFromCxx +{ + internal class CSharpLinkFromCxx + { + public static void Main(string[] args) + { + Console.WriteLine("Starting test for CSharpLinkFromCxx"); + + var useful = new UsefulManagedCppClass(); + useful.RunTest(); + } + } +} diff --git a/Tests/CSharpLinkFromCxx/UsefulCSharpClass.cs b/Tests/CSharpLinkFromCxx/UsefulCSharpClass.cs new file mode 100644 index 0000000..749e57d --- /dev/null +++ b/Tests/CSharpLinkFromCxx/UsefulCSharpClass.cs @@ -0,0 +1,12 @@ +using System; + +namespace CSharpLibrary +{ + public class UsefulCSharpClass + { + public string GetSomethingUseful() + { + return "Something Useful"; + } + } +} diff --git a/Tests/CSharpLinkFromCxx/UsefulManagedCppClass.cpp b/Tests/CSharpLinkFromCxx/UsefulManagedCppClass.cpp new file mode 100644 index 0000000..9468812 --- /dev/null +++ b/Tests/CSharpLinkFromCxx/UsefulManagedCppClass.cpp @@ -0,0 +1,15 @@ +#include "UsefulManagedCppClass.hpp" + +namespace CSharpLibrary +{ + UsefulManagedCppClass::UsefulManagedCppClass() + { + auto useful = gcnew UsefulCSharpClass(); + m_usefulString = useful->GetSomethingUseful(); + } + + void UsefulManagedCppClass::RunTest() + { + Console::WriteLine("Printing from Managed CPP Class: " + m_usefulString); + } +} diff --git a/Tests/CSharpLinkFromCxx/UsefulManagedCppClass.hpp b/Tests/CSharpLinkFromCxx/UsefulManagedCppClass.hpp new file mode 100644 index 0000000..def7cea --- /dev/null +++ b/Tests/CSharpLinkFromCxx/UsefulManagedCppClass.hpp @@ -0,0 +1,16 @@ +using namespace System; + +namespace CSharpLibrary +{ + public ref class UsefulManagedCppClass + { + public: + + UsefulManagedCppClass(); + void RunTest(); + + private: + + String^ m_usefulString; + }; +} |