This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake".
The branch, next has been updated via 1a99eb71ed71060d4152fd4deca7edffee197d61 (commit) via 3787c8703cdf5ac481b3d4aaa8dedc5d5ac9790c (commit) from ac81846d83a3fffc007ef6043b004bbb7a244a1f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1a99eb71ed71060d4152fd4deca7edffee197d61 commit 1a99eb71ed71060d4152fd4deca7edffee197d61 Merge: ac81846 3787c87 Author: Bill Hoffman <bill.hoff...@kitware.com> AuthorDate: Thu Jun 25 14:29:26 2015 -0400 Commit: CMake Topic Stage <kwro...@kitware.com> CommitDate: Thu Jun 25 14:29:26 2015 -0400 Merge topic 'auto_export_dll_symbols' into next 3787c870 This commit introduces the ability to export all symbols in a Windows dll. http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3787c8703cdf5ac481b3d4aaa8dedc5d5ac9790c commit 3787c8703cdf5ac481b3d4aaa8dedc5d5ac9790c Author: Bill Hoffman <bill.hoff...@kitware.com> AuthorDate: Fri Jun 19 16:12:43 2015 -0400 Commit: Bill Hoffman <bill.hoff...@kitware.com> CommitDate: Thu Jun 25 14:26:54 2015 -0400 This commit introduces the ability to export all symbols in a Windows dll. This creates the target property WINDOWS_EXPORT_ALL_SYMBOLS which when on will export all symbols in a dll. This is done by extracting the symbols from the object files prior to linking the dll. diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 9a60a10..b767ed6 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -251,6 +251,7 @@ Properties on Targets /prop_tgt/VS_WINRT_EXTENSIONS /prop_tgt/VS_WINRT_REFERENCES /prop_tgt/WIN32_EXECUTABLE + /prop_tgt/WINDOWS_EXPORT_ALL_SYMBOLS /prop_tgt/XCODE_ATTRIBUTE_an-attribute /prop_tgt/XCTEST diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 0e6222f..c90016d 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -275,6 +275,7 @@ Variables that Control the Build /variable/CMAKE_USE_RELATIVE_PATHS /variable/CMAKE_VISIBILITY_INLINES_HIDDEN /variable/CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD + /variable/WINDOWS_EXPORT_ALL_SYMBOLS /variable/CMAKE_WIN32_EXECUTABLE /variable/CMAKE_XCODE_ATTRIBUTE_an-attribute /variable/EXECUTABLE_OUTPUT_PATH diff --git a/Help/prop_tgt/WINDOWS_EXPORT_ALL_SYMBOLS.rst b/Help/prop_tgt/WINDOWS_EXPORT_ALL_SYMBOLS.rst new file mode 100644 index 0000000..1c37fd7 --- /dev/null +++ b/Help/prop_tgt/WINDOWS_EXPORT_ALL_SYMBOLS.rst @@ -0,0 +1,15 @@ +WINDOWS_EXPORT_ALL_SYMBOLS +-------------------------- + +This property is implemented only when the compiler supports it. + +This property will automatically create a .def file with all global +symbols found in the input .obj files for a dll on Windows. The def +file will be passed to the linker causing all symbols to be exported +from the dll. For any global data __declspec(dllimport) must still be +used when compiling against the code in the dll. All other function +symbols will be automatically exported and imported by callers. + +This property is initialized by the value of +the :variable:`CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS` variable if it is set +when a target is created. diff --git a/Help/variable/CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS.rst b/Help/variable/CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS.rst new file mode 100644 index 0000000..1636842 --- /dev/null +++ b/Help/variable/CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS.rst @@ -0,0 +1,6 @@ +CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS +-------------------------------- + +Default value for :prop_tgt:`WINDOWS_EXPORT_ALL_SYMBOLS` target property. +This variable is used to initialize the property on each target as it is +created. diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake index 13fe8bc..1e4ec84 100644 --- a/Modules/Platform/Windows-MSVC.cmake +++ b/Modules/Platform/Windows-MSVC.cmake @@ -45,9 +45,12 @@ else() set(CMAKE_CREATE_CONSOLE_EXE "/subsystem:console") set(_PLATFORM_LINK_FLAGS "") endif() - +# default support WINDOWS_EXPORT_ALL_SYMBOLS +set(CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS 1) if(CMAKE_GENERATOR MATCHES "Visual Studio 6") set (CMAKE_NO_BUILD_TYPE 1) + # WINDOWS_EXPORT_ALL_SYMBOLS not supported for VS6 IDE + set(CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS 0) endif() if(NOT CMAKE_NO_BUILD_TYPE AND CMAKE_GENERATOR MATCHES "Visual Studio") set (CMAKE_NO_BUILD_TYPE 1) diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 6d012fd..069f283 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -430,6 +430,7 @@ if (WIN32) set(SRCS ${SRCS} cmCallVisualStudioMacro.cxx cmCallVisualStudioMacro.h + bindexplib.cxx ) if(NOT UNIX) diff --git a/Source/bindexplib.cxx b/Source/bindexplib.cxx new file mode 100644 index 0000000..407a815 --- /dev/null +++ b/Source/bindexplib.cxx @@ -0,0 +1,404 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +/* permission to use BSD license from Pere Mato pere.m...@cern.ch + Header of original code from http://root.cern.ch follows: */ + +/* +*---------------------------------------------------------------------- +* Program: dumpexts.exe +* Author: Gordon Chaffee +* +* History: The real functionality of this file was written by +* Matt Pietrek in 1993 in his pedump utility. I've +* modified it to dump the externals in a bunch of object +* files to create a .def file. +* +* Notes: Visual C++ puts an underscore before each exported symbol. +* This file removes them. I don't know if this is a problem +* this other compilers. If _MSC_VER is defined, +* the underscore is removed. If not, it isn't. To get a +* full dump of an object file, use the -f option. This can +* help determine the something that may be different with a +* compiler other than Visual C++. +* ====================================== +* Corrections (Axel 2006-04-04): +* Conversion to C++. Mostly. +* + * Extension (Axel 2006-03-15) + * As soon as an object file contains an /EXPORT directive (which + * is generated by the compiler when a symbol is declared as + * declspec(dllexport)) no to-be-exported symbols are printed, + * as the linker will see these directives, and if those directives + * are present we only export selectively (i.e. we trust the + * programmer). + * + * ====================================== +* ====================================== +* Corrections (Valery Fine 23/02/98): +* +* The "(vector) deleting destructor" MUST not be exported +* To recognize it the following test are introduced: +* "@@UAEPAXI@Z" scalar deleting dtor +* "@@QAEPAXI@Z" vector deleting dtor +* "AEPAXI@Z" vector deleting dtor with thunk adjustor +* ====================================== +* Corrections (Valery Fine 12/02/97): +* +* It created a wrong EXPORTS for the global pointers and constants. +* The Section Header has been involved to discover the missing information +* Now the pointers are correctly supplied supplied with "DATA" descriptor +* the constants with no extra descriptor. +* +* Corrections (Valery Fine 16/09/96): +* +* It didn't work for C++ code with global variables and class definitons +* The DumpExternalObject function has been introduced to generate .DEF file +* +* Author: Valery Fine 16/09/96 (E-mail: f...@vxcern.cern.ch) +*---------------------------------------------------------------------- +*/ + +static char sccsid[] = "@(#) winDumpExts.c 1.2 95/10/03 15:27:34"; + +#include <windows.h> +#include <stdio.h> +#include <string> +#include <fstream> +#include <iostream> + +/* +* The names of the first group of possible symbol table storage classes +*/ +char * SzStorageClass1[] = { + "NULL","AUTOMATIC","EXTERNAL","STATIC","REGISTER","EXTERNAL_DEF","LABEL", + "UNDEFINED_LABEL","MEMBER_OF_STRUCT","ARGUMENT","STRUCT_TAG", + "MEMBER_OF_UNION","UNION_TAG","TYPE_DEFINITION","UNDEFINED_STATIC", + "ENUM_TAG","MEMBER_OF_ENUM","REGISTER_PARAM","BIT_FIELD" +}; + +/* +* The names of the second group of possible symbol table storage classes +*/ +char * SzStorageClass2[] = { + "BLOCK","FUNCTION","END_OF_STRUCT","FILE","SECTION","WEAK_EXTERNAL" +}; + +/* ++ * Utility func, strstr with size ++ */ +const char* StrNStr(const char* start, const char* find, size_t &size) { + size_t len; + const char* hint; + + if (!start || !find || !size) { + size = 0; + return 0; + } + len = strlen(find); + + while (hint = (const char*) memchr(start, find[0], size-len+1)) { + size -= (hint - start); + if (!strncmp(hint, find, len)) + return hint; + start = hint + 1; + } + + size = 0; + return 0; +} + +/* + *---------------------------------------------------------------------- + * HaveExportedObjects -- + * + * Returns >0 if export directives (declspec(dllexport)) exist. + * + *---------------------------------------------------------------------- + */ +int +HaveExportedObjects(PIMAGE_FILE_HEADER pImageFileHeader, + PIMAGE_SECTION_HEADER pSectionHeaders, FILE *fout) +{ + static int fImportFlag = 0; /* The status is nor defined yet */ + WORD i; + size_t size; + char foundExports; + const char * rawdata; + + PIMAGE_SECTION_HEADER pDirectivesSectionHeader; + + if (fImportFlag) return 1; + + i = 0; + foundExports = 0; + pDirectivesSectionHeader = 0; + for(i = 0; i < pImageFileHeader->NumberOfSections + && !pDirectivesSectionHeader; i++) + if (!strncmp((const char*)&pSectionHeaders[i].Name[0], ".drectve",8)) + pDirectivesSectionHeader = &pSectionHeaders[i]; + if (!pDirectivesSectionHeader) return 0; + + rawdata=(const char*) + pImageFileHeader+pDirectivesSectionHeader->PointerToRawData; + if (!pDirectivesSectionHeader->PointerToRawData || !rawdata) return 0; + + size = pDirectivesSectionHeader->SizeOfRawData; + const char* posImportFlag = rawdata; + while ((posImportFlag = StrNStr(posImportFlag, " /EXPORT:", size))) { + const char* lookingForDict = posImportFlag + 9; + if (!strncmp(lookingForDict, "_G__cpp_",8) || + !strncmp(lookingForDict, "_G__set_cpp_",12)) { + posImportFlag = lookingForDict; + continue; + } + + const char* lookingForDATA = posImportFlag + 9; + while (*(++lookingForDATA) && *lookingForDATA != ' '); + lookingForDATA -= 5; + // ignore DATA exports + if (strncmp(lookingForDATA, ",DATA", 5)) break; + posImportFlag = lookingForDATA + 5; + } + fImportFlag = (int)posImportFlag; + return fImportFlag; +} + + + +/* + *---------------------------------------------------------------------- +* DumpExternalsObjects -- +* +* Dumps a COFF symbol table from an EXE or OBJ. We only use +* it to dump tables from OBJs. +*---------------------------------------------------------------------- +*/ +void +DumpExternalsObjects(PIMAGE_SYMBOL pSymbolTable, + PIMAGE_SECTION_HEADER pSectionHeaders, + FILE *fout, unsigned cSymbols) +{ + unsigned i; + PSTR stringTable; + std::string symbol; + DWORD SectChar; + static int fImportFlag = -1; /* The status is nor defined yet */ + + /* + * The string table apparently starts right after the symbol table + */ + stringTable = (PSTR)&pSymbolTable[cSymbols]; + + for ( i=0; i < cSymbols; i++ ) + { + if (pSymbolTable->SectionNumber > 0 && + ( pSymbolTable->Type == 0x20 || pSymbolTable->Type == 0x0)) + { + if (pSymbolTable->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) + { + /* + * The name of the Function entry points + */ + if (pSymbolTable->N.Name.Short != 0) + { + symbol = ""; + symbol.insert(0, (const char *)pSymbolTable->N.ShortName, 8); + } + else + { + symbol = stringTable + pSymbolTable->N.Name.Long; + } + // clear out any leading spaces + while (isspace(symbol[0])) symbol.erase(0,1); + // if it starts with _ and has an @ then it is a __cdecl + // so remove the @ stuff for the export + if(symbol[0] == '_') + { + std::string::size_type posAt = symbol.find('@'); + if (posAt != std::string::npos) + { + symbol.erase(posAt); + } + } + if (symbol[0] == '_') symbol.erase(0,1); + if (fImportFlag) + { + fImportFlag = 0; + fprintf(fout,"EXPORTS \n"); + } + /* + Check whether it is "Scalar deleting destructor" and + "Vector deleting destructor" + */ + const char *scalarPrefix = "??_G"; + const char *vectorPrefix = "??_E"; + // original code had a check for + // symbol.find("real@") == std::string::npos) + // but if this disallows memmber functions with the name real + // if scalarPrefix and vectorPrefix are not found then print + //the symbol + if (symbol.compare(0, 4, scalarPrefix) && + symbol.compare(0, 4, vectorPrefix) ) + { + SectChar = + pSectionHeaders[pSymbolTable->SectionNumber-1].Characteristics; + if (!pSymbolTable->Type && (SectChar & IMAGE_SCN_MEM_WRITE)) + { + // Read only (i.e. constants) must be excluded + fprintf(fout, "\t%s \t DATA\n", symbol.c_str()); + } + else + { + if ( pSymbolTable->Type || !(SectChar & IMAGE_SCN_MEM_READ)) + { + fprintf(fout, "\t%s\n", symbol.c_str()); + } + else + { + //printf(" strange symbol: %s \n",symbol.c_str()); + } + } + } // not vector or scalar destructor + } + } + else if (pSymbolTable->SectionNumber + == IMAGE_SYM_UNDEFINED && !pSymbolTable->Type && 0) + { + /* + * The IMPORT global variable entry points + */ + if (pSymbolTable->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) + { + symbol = stringTable + pSymbolTable->N.Name.Long; + while (isspace(symbol[0])) symbol.erase(0,1); + if (symbol[0] == '_') + { + symbol.erase(0,1); + } + if (!fImportFlag) + { + fImportFlag = 1; + fprintf(fout,"IMPORTS \n"); + } + fprintf(fout, "\t%s DATA \n", symbol.c_str()+1); + } + } + + /* + * Take into account any aux symbols + */ + i += pSymbolTable->NumberOfAuxSymbols; + pSymbolTable += pSymbolTable->NumberOfAuxSymbols; + pSymbolTable++; + } +} + +/* +*---------------------------------------------------------------------- +* DumpObjFile -- +* +* Dump an object file--either a full listing or just the exported +* symbols. +*---------------------------------------------------------------------- +*/ +void +DumpObjFile(PIMAGE_FILE_HEADER pImageFileHeader, FILE *fout) +{ + PIMAGE_SYMBOL PCOFFSymbolTable; + PIMAGE_SECTION_HEADER PCOFFSectionHeaders; + DWORD_PTR COFFSymbolCount; + + PCOFFSymbolTable = (PIMAGE_SYMBOL) + ((DWORD_PTR)pImageFileHeader + pImageFileHeader->PointerToSymbolTable); + COFFSymbolCount = pImageFileHeader->NumberOfSymbols; + + PCOFFSectionHeaders = (PIMAGE_SECTION_HEADER) + ((DWORD_PTR)pImageFileHeader + + IMAGE_SIZEOF_FILE_HEADER + + pImageFileHeader->SizeOfOptionalHeader); + + + int haveExports = HaveExportedObjects(pImageFileHeader, + PCOFFSectionHeaders, fout); + if (!haveExports) + { + DumpExternalsObjects(PCOFFSymbolTable, PCOFFSectionHeaders, + fout, COFFSymbolCount); + } +} + +/* +*---------------------------------------------------------------------- +* DumpFile -- +* +* Open up a file, memory map it, and call the appropriate +* dumping routine +*---------------------------------------------------------------------- +*/ +void +DumpFile(const char* filename, FILE *fout) +{ + HANDLE hFile; + HANDLE hFileMapping; + LPVOID lpFileBase; + PIMAGE_DOS_HEADER dosHeader; + + hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + + if (hFile == INVALID_HANDLE_VALUE) + { + fprintf(stderr, "Couldn't open file [%s] with CreateFile()\n", filename); + return; + } + + hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); + if (hFileMapping == 0) { + CloseHandle(hFile); + fprintf(stderr, "Couldn't open file mapping with CreateFileMapping()\n"); + return; + } + + lpFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0); + if (lpFileBase == 0) { + CloseHandle(hFileMapping); + CloseHandle(hFile); + fprintf(stderr, "Couldn't map view of file with MapViewOfFile()\n"); + return; + } + + dosHeader = (PIMAGE_DOS_HEADER)lpFileBase; + if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE) + { + fprintf(stderr, "File is an executable. I don't dump those.\n"); + return; + } + /* Does it look like a i386 COFF OBJ file??? */ + else if ( + ((dosHeader->e_magic == IMAGE_FILE_MACHINE_I386) + || (dosHeader->e_magic == IMAGE_FILE_MACHINE_AMD64)) + && (dosHeader->e_sp == 0) + ) { + /* + * The two tests above aren't what they look like. They're + * really checking for IMAGE_FILE_HEADER.Machine == i386 (0x14C) + * and IMAGE_FILE_HEADER.SizeOfOptionalHeader == 0; + */ + DumpObjFile((PIMAGE_FILE_HEADER) lpFileBase, fout); + } else { + printf("unrecognized file format\n"); + } + UnmapViewOfFile(lpFileBase); + CloseHandle(hFileMapping); + CloseHandle(hFile); +} diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index 585d19a..61cec6c 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -887,3 +887,64 @@ 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 = "$(IntDir)/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 objs_file = gt->Target->GetName(); + objs_file += ".dir/" + configName; + cmSystemTools::MakeDirectory(objs_file.c_str()); + objs_file += "/exportall.def.objs"; + cmdl.push_back(objs_file); + std::ofstream 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()); + 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..020ef50 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -1081,6 +1081,16 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, this->ConvertToOutputFormat(this->ModuleDefinitionFile, SHELL); linkOptions.AddFlag("ModuleDefinitionFile", defFile.c_str()); } + if(this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") + &&target.GetType() == cmTarget::SHARED_LIBRARY) + { + std::string const autodef_prop = "WINDOWS_EXPORT_ALL_SYMBOLS"; + const char *autodef = target.GetProperty(autodef_prop); + if (autodef && *autodef) + { + linkOptions.AddFlag("ModuleDefinitionFile", "$(IntDir)/exportall.def"); + } + } switch(target.GetType()) { case cmTarget::UNKNOWN_LIBRARY: @@ -2015,7 +2025,30 @@ void cmLocalVisualStudio7Generator // Add pre-link event. tool = this->FortranProject? "VFPreLinkEventTool":"VCPreLinkEventTool"; event.Start(tool); - event.Write(target.GetPreLinkCommands()); + bool addedPrelink = false; + if(this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") + && target.GetType() == cmTarget::SHARED_LIBRARY) + { + std::string const autodef_prop = "WINDOWS_EXPORT_ALL_SYMBOLS"; + const char *autodef = target.GetProperty(autodef_prop); + if (autodef && *autodef) + { + 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..0511356 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -563,6 +563,58 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules useResponseFileForObjects, buildObjs, depends, useWatcomQuote); + // check for windows_auto_dll_export property here + // create .def file from list of objects + if(this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") + && this->Target->GetType() == cmTarget::SHARED_LIBRARY) + { + std::string const autodef_prop = "WINDOWS_EXPORT_ALL_SYMBOLS"; + const char *autodef = this->Target->GetProperty(autodef_prop); + if (autodef && *autodef) + { + 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 + std::ofstream fout(objlist_file.c_str()); + for(std::vector<std::string>::const_iterator i = this->Objects.begin(); + i != this->Objects.end(); ++i) + { + 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..a181f66 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -437,7 +437,6 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() this->OSXBundleGenerator->CreateCFBundle(this->TargetNameOut, target.GetDirectory(cfgName)); } - // Write comments. cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream()); const cmTarget::TargetType targetType = target.GetType(); @@ -486,6 +485,24 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() linkPath, &genTarget, useWatcomQuote); + if(this->GetMakefile()->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") + && target.GetType() == cmTarget::SHARED_LIBRARY) + { + std::string const autodef_prop = "WINDOWS_EXPORT_ALL_SYMBOLS"; + const char *autodef = target.GetProperty(autodef_prop); + if (autodef && *autodef) + { + 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); @@ -599,7 +616,44 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() std::back_inserter(byproducts), MapToNinjaPath()); } } - + // check for windows_auto_dll_export property here + // create .def file from list of objects + if(this->GetMakefile()->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") + && target.GetType() == cmTarget::SHARED_LIBRARY) + { + std::string const autodef_prop = "WINDOWS_EXPORT_ALL_SYMBOLS"; + const char *autodef = target.GetProperty(autodef_prop); + if (autodef && *autodef) + { + 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 + std::ofstream fout(obj_list_file.c_str()); + for(cmNinjaDeps::iterator i=objs.begin(); i != objs.end(); ++i) + { + 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..d84b7d0 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2465,7 +2465,16 @@ cmVisualStudio10TargetGenerator::ComputeLinkOptions(std::string const& config) linkOptions.AppendFlag("IgnoreSpecificDefaultLibraries", "%(IgnoreSpecificDefaultLibraries)"); } - + if(this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") + && this->Target->GetType() == cmTarget::SHARED_LIBRARY) + { + std::string const autodef_prop = "WINDOWS_EXPORT_ALL_SYMBOLS"; + const char *autodef = this->Target->GetProperty(autodef_prop); + if (autodef && *autodef) + { + linkOptions.AddFlag("ModuleDefinitionFile", "$(IntDir)/exportall.def"); + } + } this->LinkOptions[config] = pOptions.release(); return true; } @@ -2613,8 +2622,27 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups() void cmVisualStudio10TargetGenerator::WriteEvents(std::string const& configName) { - this->WriteEvent("PreLinkEvent", - this->Target->GetPreLinkCommands(), configName); + bool addedPrelink = false; + if(this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") + && this->Target->GetType() == cmTarget::SHARED_LIBRARY) + { + std::string const autodef_prop = "WINDOWS_EXPORT_ALL_SYMBOLS"; + const char *autodef = this->Target->GetProperty(autodef_prop); + if (autodef && *autodef) + { + 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..bdf3f41 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -210,7 +210,42 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) } return 0; } - +#ifdef _WIN32 + else if(args[1] == "__create_def") + { + // defined in binexplib.cxx + void + DumpFile(const char* filename, FILE *fout); + if(args.size() < 4) + { + std::cerr << + "__create_def Usage: -E __create_def outfile.def objlistfile\n"; + return 1; + } + FILE* fout = 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)) + { + // needed fort for bzip2 c code with WINAPI calls + DumpFile(objfile.c_str(), fout); + } + 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. diff --git a/Tests/RunCMake/AutoExportDll/AutoExport.cmake b/Tests/RunCMake/AutoExportDll/AutoExport.cmake new file mode 100644 index 0000000..c426f66 --- /dev/null +++ b/Tests/RunCMake/AutoExportDll/AutoExport.cmake @@ -0,0 +1,5 @@ +project(autoexport) +set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) +add_library(autoexport SHARED hello.cxx world.cxx foo.c) +add_executable(say say.cxx) +target_link_libraries(say autoexport) diff --git a/Tests/RunCMake/AutoExportDll/CMakeLists.txt b/Tests/RunCMake/AutoExportDll/CMakeLists.txt new file mode 100644 index 0000000..18dfd26 --- /dev/null +++ b/Tests/RunCMake/AutoExportDll/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.2) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/AutoExportDll/RunCMakeTest.cmake b/Tests/RunCMake/AutoExportDll/RunCMakeTest.cmake new file mode 100644 index 0000000..ee89023 --- /dev/null +++ b/Tests/RunCMake/AutoExportDll/RunCMakeTest.cmake @@ -0,0 +1,26 @@ +include(RunCMake) +set(RunCMake_TEST_NO_CLEAN TRUE) +set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/AutoExport-build") +# start by cleaning up because we don't clean up along the way +file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") +# configure the AutoExport test +run_cmake(AutoExport) +unset(RunCMake_TEST_OPTIONS) +# don't run this test on VS 6 as it is not supported +if("${RunCMake_GENERATOR}" MATCHES "Visual Studio 6") + return() +endif() +# we build debug so the say.exe will be found in Debug/say.exe for +# Visual Studio generators +if("${RunCMake_GENERATOR}" MATCHES "Visual Studio") + set(INTDIR "Debug/") +endif() +# build AutoExport +run_cmake_command(AutoExportBuild ${CMAKE_COMMAND} --build + ${RunCMake_TEST_BINARY_DIR} --config Debug) +# run the executable that uses symbols from the dll +if(WIN32) + set(EXE_EXT ".exe") +endif() +run_cmake_command(AutoExportRun + ${RunCMake_BINARY_DIR}/AutoExport-build/${INTDIR}say${EXE_EXT}) diff --git a/Tests/RunCMake/AutoExportDll/foo.c b/Tests/RunCMake/AutoExportDll/foo.c new file mode 100644 index 0000000..4b1318b --- /dev/null +++ b/Tests/RunCMake/AutoExportDll/foo.c @@ -0,0 +1,15 @@ +#ifdef _MSC_VER +#include "windows.h" +#else +#define WINAPI +#endif + +int WINAPI foo() +{ + return 10; +} + +int bar() +{ + return 5; +} diff --git a/Tests/RunCMake/AutoExportDll/hello.cxx b/Tests/RunCMake/AutoExportDll/hello.cxx new file mode 100644 index 0000000..807a811 --- /dev/null +++ b/Tests/RunCMake/AutoExportDll/hello.cxx @@ -0,0 +1,13 @@ +#include <iostream> +#include "hello.h" +int Hello::Data = 0; +void Hello::real() +{ + return; +} +void hello() +{ + std::cout << "hello"; +} +void Hello::operator delete[](void* ptr) {}; +void Hello::operator delete(void* ptr) {}; diff --git a/Tests/RunCMake/AutoExportDll/hello.h b/Tests/RunCMake/AutoExportDll/hello.h new file mode 100644 index 0000000..a151bd1 --- /dev/null +++ b/Tests/RunCMake/AutoExportDll/hello.h @@ -0,0 +1,18 @@ +#ifndef _MSC_VER +#define winexport +#else +#ifdef autoexport_EXPORTS +#define winexport +#else +#define winexport __declspec(dllimport) +#endif +#endif + +class Hello +{ +public: + static winexport int Data; + void real(); + static void operator delete[](void* ptr); + static void operator delete(void* ptr); +}; diff --git a/Tests/RunCMake/AutoExportDll/say.cxx b/Tests/RunCMake/AutoExportDll/say.cxx new file mode 100644 index 0000000..015c3a8 --- /dev/null +++ b/Tests/RunCMake/AutoExportDll/say.cxx @@ -0,0 +1,35 @@ +#include <iostream> +#include "hello.h" +#ifdef _MSC_VER +#include "windows.h" +#else +#define WINAPI +#endif + +extern "C" +{ +// test __cdecl stuff + int WINAPI foo(); +// test regular C + int bar(); +} + +// test c++ functions +// forward declare hello and world +void hello(); +void world(); + +int main() +{ + // test static data (needs declspec to work) + Hello::Data = 120; + Hello h; + h.real(); + hello(); + std::cout << " "; + world(); + std::cout << "\n" << foo() << "\n"; + std::cout << "\n" << bar() << "\n"; + std::cout << "\n"; + return 0; +} diff --git a/Tests/RunCMake/AutoExportDll/world.cxx b/Tests/RunCMake/AutoExportDll/world.cxx new file mode 100644 index 0000000..8107949 --- /dev/null +++ b/Tests/RunCMake/AutoExportDll/world.cxx @@ -0,0 +1,6 @@ +#include <iostream> + +void world() +{ + std::cout << "world"; +} diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index bc706d3..743ef4b 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -266,3 +266,6 @@ if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") endif() add_RunCMake_test_group(CPack "DEB;RPM") +# add a test to make sure symbols are exported from a shared library +# for MSVC compilers CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS property is used +add_RunCMake_test(AutoExportDll) ----------------------------------------------------------------------- Summary of changes: Help/manual/cmake-properties.7.rst | 1 + Help/manual/cmake-variables.7.rst | 1 + Help/prop_tgt/WINDOWS_EXPORT_ALL_SYMBOLS.rst | 15 + Help/variable/CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS.rst | 6 + Modules/Platform/Windows-MSVC.cmake | 5 +- Source/CMakeLists.txt | 1 + Source/bindexplib.cxx | 404 ++++++++++++++++++++ Source/cmGlobalVisualStudioGenerator.cxx | 61 +++ Source/cmGlobalVisualStudioGenerator.h | 4 + Source/cmLocalVisualStudio7Generator.cxx | 35 +- Source/cmMakefileLibraryTargetGenerator.cxx | 52 +++ Source/cmNinjaNormalTargetGenerator.cxx | 58 ++- Source/cmTarget.cxx | 5 + Source/cmVisualStudio10TargetGenerator.cxx | 34 +- Source/cmcmd.cxx | 37 +- Tests/RunCMake/AutoExportDll/AutoExport.cmake | 5 + .../{CMP0057 => AutoExportDll}/CMakeLists.txt | 0 Tests/RunCMake/AutoExportDll/RunCMakeTest.cmake | 26 ++ Tests/RunCMake/AutoExportDll/foo.c | 15 + Tests/RunCMake/AutoExportDll/hello.cxx | 13 + Tests/RunCMake/AutoExportDll/hello.h | 18 + Tests/RunCMake/AutoExportDll/say.cxx | 35 ++ Tests/RunCMake/AutoExportDll/world.cxx | 6 + Tests/RunCMake/CMakeLists.txt | 3 + 24 files changed, 832 insertions(+), 8 deletions(-) create mode 100644 Help/prop_tgt/WINDOWS_EXPORT_ALL_SYMBOLS.rst create mode 100644 Help/variable/CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS.rst create mode 100644 Source/bindexplib.cxx create mode 100644 Tests/RunCMake/AutoExportDll/AutoExport.cmake copy Tests/RunCMake/{CMP0057 => AutoExportDll}/CMakeLists.txt (100%) create mode 100644 Tests/RunCMake/AutoExportDll/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/AutoExportDll/foo.c create mode 100644 Tests/RunCMake/AutoExportDll/hello.cxx create mode 100644 Tests/RunCMake/AutoExportDll/hello.h create mode 100644 Tests/RunCMake/AutoExportDll/say.cxx create mode 100644 Tests/RunCMake/AutoExportDll/world.cxx hooks/post-receive -- CMake _______________________________________________ Cmake-commits mailing list Cmake-commits@cmake.org http://public.kitware.com/mailman/listinfo/cmake-commits