diff options
author | Bill Hoffman <bill.hoffman@kitware.com> | 2015-06-19 20:12:43 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2015-07-06 15:11:02 (GMT) |
commit | 8f86407cfd4331dc1f2eb67f4f179ed8fe9dea06 (patch) | |
tree | 8d6670fe80a98055f6302241bb7177ea7d22b77d /Source | |
parent | 069aa93b555293679f4b8c07623133ba62a74ee4 (diff) | |
download | CMake-8f86407cfd4331dc1f2eb67f4f179ed8fe9dea06.zip CMake-8f86407cfd4331dc1f2eb67f4f179ed8fe9dea06.tar.gz CMake-8f86407cfd4331dc1f2eb67f4f179ed8fe9dea06.tar.bz2 |
Windows: Optionally generate DLL module definition files automatically
Create target property WINDOWS_EXPORT_ALL_SYMBOLS to automatically
generate a module definition file from MS-compatible .obj files and give
it to the linker in order to export all symbols from the .dll part of a
SHARED library.
Diffstat (limited to 'Source')
-rw-r--r-- | Source/cmGlobalVisualStudioGenerator.cxx | 70 | ||||
-rw-r--r-- | Source/cmGlobalVisualStudioGenerator.h | 4 | ||||
-rw-r--r-- | Source/cmLocalVisualStudio7Generator.cxx | 31 | ||||
-rw-r--r-- | Source/cmMakefileLibraryTargetGenerator.cxx | 53 | ||||
-rw-r--r-- | Source/cmNinjaNormalTargetGenerator.cxx | 54 | ||||
-rw-r--r-- | Source/cmTarget.cxx | 5 | ||||
-rw-r--r-- | Source/cmVisualStudio10TargetGenerator.cxx | 30 | ||||
-rw-r--r-- | Source/cmcmd.cxx | 39 |
8 files changed, 283 insertions, 3 deletions
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index 585d19a..bc134e1 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -13,12 +13,14 @@ #include "cmGlobalVisualStudioGenerator.h" #include "cmCallVisualStudioMacro.h" +#include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmLocalVisualStudioGenerator.h" #include "cmMakefile.h" #include "cmSourceFile.h" #include "cmTarget.h" #include <cmsys/Encoding.hxx> +#include "cmAlgorithms.h" //---------------------------------------------------------------------------- cmGlobalVisualStudioGenerator::cmGlobalVisualStudioGenerator(cmake* cm) @@ -887,3 +889,71 @@ std::string cmGlobalVisualStudioGenerator::ExpandCFGIntDir( } return tmp; } + +void cmGlobalVisualStudioGenerator::AddSymbolExportCommand( + cmGeneratorTarget* gt, std::vector<cmCustomCommand>& commands, + std::string const& configName) +{ + std::vector<std::string> outputs; + std::string deffile = gt->ObjectDirectory; + deffile += "/exportall.def"; + outputs.push_back(deffile); + std::vector<std::string> empty; + std::vector<cmSourceFile const*> objectSources; + gt->GetObjectSources(objectSources, configName); + std::map<cmSourceFile const*, std::string> mapping; + for(std::vector<cmSourceFile const*>::const_iterator it + = objectSources.begin(); it != objectSources.end(); ++it) + { + mapping[*it]; + } + gt->LocalGenerator-> + ComputeObjectFilenames(mapping, gt); + std::string obj_dir = gt->ObjectDirectory; + std::string cmakeCommand = cmSystemTools::GetCMakeCommand(); + cmSystemTools::ConvertToWindowsExtendedPath(cmakeCommand); + cmCustomCommandLine cmdl; + cmdl.push_back(cmakeCommand); + cmdl.push_back("-E"); + cmdl.push_back("__create_def"); + cmdl.push_back(deffile); + std::string obj_dir_expanded = obj_dir; + cmSystemTools::ReplaceString(obj_dir_expanded, + this->GetCMakeCFGIntDir(), + configName.c_str()); + std::string objs_file = obj_dir_expanded; + cmSystemTools::MakeDirectory(objs_file.c_str()); + objs_file += "/objects.txt"; + cmdl.push_back(objs_file); + cmGeneratedFileStream fout(objs_file.c_str()); + if(!fout) + { + cmSystemTools::Error("could not open ", objs_file.c_str()); + return; + } + for(std::vector<cmSourceFile const*>::const_iterator it + = objectSources.begin(); it != objectSources.end(); ++it) + { + // Find the object file name corresponding to this source file. + std::map<cmSourceFile const*, std::string>::const_iterator + map_it = mapping.find(*it); + // It must exist because we populated the mapping just above. + assert(!map_it->second.empty()); + std::string objFile = obj_dir + map_it->second; + // replace $(ConfigurationName) in the object names + cmSystemTools::ReplaceString(objFile, this->GetCMakeCFGIntDir(), + configName.c_str()); + if(cmHasLiteralSuffix(objFile, ".obj")) + { + fout << objFile << "\n"; + } + } + cmCustomCommandLines commandLines; + commandLines.push_back(cmdl); + cmCustomCommand command(gt->Target->GetMakefile(), + outputs, empty, empty, + commandLines, + "Auto build dll exports", + "."); + commands.push_back(command); +} diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index 69b4564..022e190 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -102,6 +102,10 @@ public: const std::string& config) const; void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const; + + void AddSymbolExportCommand( + cmGeneratorTarget*, std::vector<cmCustomCommand>& commands, + std::string const& configName); protected: virtual void Generate(); diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index dc3a16d..a0e9e4d 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -1081,6 +1081,14 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, this->ConvertToOutputFormat(this->ModuleDefinitionFile, SHELL); linkOptions.AddFlag("ModuleDefinitionFile", defFile.c_str()); } + if (target.GetType() == cmTarget::SHARED_LIBRARY && + this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS")) + { + if (target.GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS")) + { + linkOptions.AddFlag("ModuleDefinitionFile", "$(IntDir)/exportall.def"); + } + } switch(target.GetType()) { case cmTarget::UNKNOWN_LIBRARY: @@ -2015,7 +2023,28 @@ void cmLocalVisualStudio7Generator // Add pre-link event. tool = this->FortranProject? "VFPreLinkEventTool":"VCPreLinkEventTool"; event.Start(tool); - event.Write(target.GetPreLinkCommands()); + bool addedPrelink = false; + if (target.GetType() == cmTarget::SHARED_LIBRARY && + this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS")) + { + if (target.GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS")) + { + addedPrelink = true; + std::vector<cmCustomCommand> commands = + target.GetPreLinkCommands(); + cmGlobalVisualStudioGenerator* gg + = static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator); + cmGeneratorTarget* gt = + this->GlobalGenerator->GetGeneratorTarget(&target); + gg->AddSymbolExportCommand( + gt, commands, configName); + event.Write(commands); + } + } + if (!addedPrelink) + { + event.Write(target.GetPreLinkCommands()); + } cmsys::auto_ptr<cmCustomCommand> pcc( this->MaybeCreateImplibDir(target, configName, this->FortranProject)); if(pcc.get()) diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 660027c..696dcc4 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -18,6 +18,7 @@ #include "cmSourceFile.h" #include "cmTarget.h" #include "cmake.h" +#include "cmAlgorithms.h" //---------------------------------------------------------------------------- cmMakefileLibraryTargetGenerator @@ -563,6 +564,58 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules useResponseFileForObjects, buildObjs, depends, useWatcomQuote); + // maybe create .def file from list of objects + if (this->Target->GetType() == cmTarget::SHARED_LIBRARY && + this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS")) + { + if(this->Target->GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS")) + { + std::string name_of_def_file = + this->Target->GetSupportDirectory(); + name_of_def_file += std::string("/") + + this->Target->GetName(); + name_of_def_file += ".def"; + std::string cmd = cmSystemTools::GetCMakeCommand(); + cmd = this->Convert(cmd, cmLocalGenerator::NONE, + cmLocalGenerator::SHELL); + cmd += " -E __create_def "; + cmd += this->Convert(name_of_def_file, + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::SHELL); + cmd += " "; + std::string objlist_file = name_of_def_file; + objlist_file += ".objs"; + cmd += this->Convert(objlist_file, + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::SHELL); + real_link_commands.push_back(cmd); + // create a list of obj files for the -E __create_def to read + cmGeneratedFileStream fout(objlist_file.c_str()); + for(std::vector<std::string>::const_iterator i = this->Objects.begin(); + i != this->Objects.end(); ++i) + { + if(cmHasLiteralSuffix(*i, ".obj")) + { + fout << *i << "\n"; + } + } + for(std::vector<std::string>::const_iterator i = + this->ExternalObjects.begin(); + i != this->ExternalObjects.end(); ++i) + { + fout << *i << "\n"; + } + // now add the def file link flag + linkFlags += " "; + linkFlags += + this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG"); + linkFlags += this->Convert(name_of_def_file, + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::SHELL); + linkFlags += " "; + } + } + cmLocalGenerator::RuleVariables vars; vars.TargetPDB = targetOutPathPDB.c_str(); diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 2fe53bf..88da09b 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -486,6 +486,22 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() linkPath, &genTarget, useWatcomQuote); + if(this->GetMakefile()->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") + && target.GetType() == cmTarget::SHARED_LIBRARY) + { + if(target.GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS")) + { + std::string dllname = targetOutput; + std::string name_of_def_file + = target.GetSupportDirectory(); + name_of_def_file += "/" + target.GetName(); + name_of_def_file += ".def "; + vars["LINK_FLAGS"] += " /DEF:"; + vars["LINK_FLAGS"] += this->GetLocalGenerator() + ->ConvertToOutputFormat(name_of_def_file.c_str(), + cmLocalGenerator::SHELL); + } + } this->addPoolNinjaVariable("JOB_POOL_LINK", &target, vars); @@ -600,6 +616,44 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() } } + // maybe create .def file from list of objects + if (target.GetType() == cmTarget::SHARED_LIBRARY && + this->GetMakefile()->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS")) + { + if(target.GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS")) + { + std::string cmakeCommand = + this->GetLocalGenerator()->ConvertToOutputFormat( + cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); + std::string dllname = targetOutput; + std::string name_of_def_file + = target.GetSupportDirectory(); + name_of_def_file += "/" + target.GetName(); + name_of_def_file += ".def"; + std::string cmd = cmakeCommand; + cmd += " -E __create_def "; + cmd += this->GetLocalGenerator() + ->ConvertToOutputFormat(name_of_def_file.c_str(), + cmLocalGenerator::SHELL); + cmd += " "; + cmNinjaDeps objs = this->GetObjects(); + std::string obj_list_file = name_of_def_file; + obj_list_file += ".objs"; + cmd += this->GetLocalGenerator() + ->ConvertToOutputFormat(obj_list_file.c_str(), + cmLocalGenerator::SHELL); + preLinkCmdLines.push_back(cmd); + // create a list of obj files for the -E __create_def to read + cmGeneratedFileStream fout(obj_list_file.c_str()); + for(cmNinjaDeps::iterator i=objs.begin(); i != objs.end(); ++i) + { + if(cmHasLiteralSuffix(*i, ".obj")) + { + fout << *i << "\n"; + } + } + } + } // If we have any PRE_LINK commands, we need to go back to HOME_OUTPUT for // the link commands. if (!preLinkCmdLines.empty()) diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index c7a13bc..8448431 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -429,6 +429,11 @@ void cmTarget::SetMakefile(cmMakefile* mf) { this->SetProperty("POSITION_INDEPENDENT_CODE", "True"); } + if(this->TargetTypeValue == cmTarget::SHARED_LIBRARY) + { + this->SetPropertyDefault("WINDOWS_EXPORT_ALL_SYMBOLS", 0); + } + if (this->GetType() != INTERFACE_LIBRARY && this->GetType() != UTILITY) { this->SetPropertyDefault("POSITION_INDEPENDENT_CODE", 0); diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 12a1e42..57ec212 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2466,6 +2466,15 @@ cmVisualStudio10TargetGenerator::ComputeLinkOptions(std::string const& config) "%(IgnoreSpecificDefaultLibraries)"); } + if (this->Target->GetType() == cmTarget::SHARED_LIBRARY && + this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS")) + { + if (this->Target->GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS")) + { + linkOptions.AddFlag("ModuleDefinitionFile", "$(IntDir)exportall.def"); + } + } + this->LinkOptions[config] = pOptions.release(); return true; } @@ -2613,8 +2622,25 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups() void cmVisualStudio10TargetGenerator::WriteEvents(std::string const& configName) { - this->WriteEvent("PreLinkEvent", - this->Target->GetPreLinkCommands(), configName); + bool addedPrelink = false; + if (this->Target->GetType() == cmTarget::SHARED_LIBRARY && + this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS")) + { + if (this->Target->GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS")) + { + addedPrelink = true; + std::vector<cmCustomCommand> commands = + this->Target->GetPreLinkCommands(); + this->GlobalGenerator->AddSymbolExportCommand( + this->GeneratorTarget, commands, configName); + this->WriteEvent("PreLinkEvent", commands, configName); + } + } + if (!addedPrelink) + { + this->WriteEvent("PreLinkEvent", + this->Target->GetPreLinkCommands(), configName); + } this->WriteEvent("PreBuildEvent", this->Target->GetPreBuildCommands(), configName); this->WriteEvent("PostBuildEvent", diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 3ea2186..63838b4 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -34,6 +34,10 @@ #include <time.h> #include <stdlib.h> // required for atoi +#if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE) +// defined in binexplib.cxx +bool DumpFile(const char* filename, FILE *fout); +#endif void CMakeCommandUsage(const char* program) { @@ -211,6 +215,41 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) return 0; } +#if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE) + else if(args[1] == "__create_def") + { + if(args.size() < 4) + { + std::cerr << + "__create_def Usage: -E __create_def outfile.def objlistfile\n"; + return 1; + } + FILE* fout = cmsys::SystemTools::Fopen(args[2].c_str(), "w+"); + if(!fout) + { + std::cerr << "could not open output .def file: " << args[2].c_str() + << "\n"; + return 1; + } + cmsys::ifstream fin(args[3].c_str(), + std::ios::in | std::ios::binary); + if(!fin) + { + std::cerr << "could not open object list file: " << args[3].c_str() + << "\n"; + return 1; + } + std::string objfile; + while(cmSystemTools::GetLineFromStream(fin, objfile)) + { + if (!DumpFile(objfile.c_str(), fout)) + { + return 1; + } + } + return 0; + } +#endif // run include what you use command and then run the compile // command. This is an internal undocumented option and should // only be used by CMake itself when running iwyu. |