Export all symbols when creating a DLL
With VS2005, I want to create a DLL and automatically export all symbols without adding __declspec(dllexport) everywhere and without hand-creating .def files. Is threre a way to do this?
7 Answers 7
The way we do it here is to use the /DEF option of the linker to pass a «module definition file» containing a list of our exports. I see from your question that you know about these files. However, we do not do it by hand. The list of exports itself is created by the dumpbin /LINKERMEMBER command, and manipulating the output via a simple script to the format of a module definition file.
It is a lot of work to setup, but it allows us to compile code created without dllexport declarations for Unix on Windows.
Short answer
You can do it with help of the new version of the CMake (any version cmake-3.3.20150721-g9cd2f-win32-x86.exe or higher).
Currently it’s in the dev branch. Later, the feature will be added in the release version of the cmake-3.4.
Link to the cmake dev:
Link to an article which describe the technic:
Link to an example project:
Long answer
Caution: All information below is related to the MSVC compiler or Visual Studio.
If you use other compilers like gcc on Linux or MinGW gcc compiler on Windows you don’t have linking errors due to not exported symbols, because gcc compiler export all symbols in a dynamic library (dll) by default instead of MSVC or Intel windows compilers.
In windows you have to explicitly export symbol from a dll.
More info about this is provided by links:
So if you want to export all symbols from dll with MSVC (Visual Studio compiler) you have two options:
- Use the keyword __declspec(dllexport) in the class/function’s definition.
- Create a module definition (.def) file and use the .def file when building the DLL.
1. Use the keyword __declspec(dllexport) in the class/function’s definition
1.1. Add «__declspec(dllexport) / __declspec(dllimport)» macros to a class or method you want to use. So if you want to export all classes you should add this macros to all of them
More info about this is provided by link:
Example of usage (replace «Project» by real project name):
Then add «PROJECTAPI» to all classes. Define «USEPROJECTLIBRARY» only if you want export/import symbols from dll. Define «PROJECTLIBRARY_EXPORTS» for the dll.
Example of class export:
Example of function export:
Caution: don’t forget to include «ProjectExport.h» file.
1.2. Export as C functions. If you use C++ compiler for compilation code is written on C, you could add extern «C» in front of a function to eliminate name mangling
More info about C++ name mangling is provided by link:
More info about this is provided by link:
2. Create a module definition (.def) file and use the .def file when building the DLL
More info about this is provided by link:
Further I describe three approach about how to create .def file.
2.1. Export C functions
In this case you could simple add function declarations in the .def file by hand.
Example of .def file (__cdecl naming convention):
2.2. Export symbols from static library
I tried approach suggested by «user72260».
- Firstly, you could create static library.
- Then use «dumpbin /LINKERMEMBER» to export all symbols from static library.
- Parse the output.
- Put all results in a .def file.
- Create dll with the .def file.
I used this approach, but it’s not very convinient to always create two builds (one as a static and the other as a dynamic library). However, I have to admit, this approach really works.
2.3. Export symbols from .obj files or with help of the CMake
2.3.1. With CMake usage
Important notice: You don’t need any export macros to a classes or functions!
Important notice: You can’t use /GL (Whole Program Optimization) when use this approach!
- Create CMake project based on the «CMakeLists.txt» file.
- Add the following line to the «CMakeLists.txt» file: set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
- Then create Visual Studio project with help of «CMake (cmake-gui)».
- Compile the project.
CMakeLists.txt (Root folder)
main.cpp (Root folder)
Foo folder (Root folder / Foo folder)
CMakeLists.txt (Foo folder)
Link to the example project again:
CMake uses the different from «2.2. Export symbols from static library» approach.
It does the following:
1) Create «objects.txt» file in the build directory with information of .obj files are used in a dll.
2) Compile the dll, that is create .obj files.
3) Based on «objects.txt» file information extract all symbols from .obj file.
More info about this is provided by link:
4) Parse extracted from .obj file information.
In my opinion I would use calling convection, for example «__cdecl/__fastcall», «SECTx/UNDEF» symbol field (the third column), «External/Static» symbol field (the fifth column), «??», «?» information for parsing an .obj files.
I don’t know how exactly CMake parse an .obj file. However, CMake is open source, so you could find out if it’s interested for you.
Link to the CMake project:
5) Put all exported symbols in a .def file.
6) Link a dll with usage of a .def created file.
Steps 4)-5), that is parse .obj files and create a .def file before linking and using the .def file CMake does with help of «Pre-Link event». While «Pre-Link event» fires you could call any program you want. So in case of «CMake usage» «Pre-Link event» call the CMake with the following information about where to put the .def file and where the «objects.txt» file and with argument «-E __create_def». You could check this information by creating CMake Visusal Studio project with «set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)» and then check the «.vcxproj» project file for dll.
If you try to compile a project without «set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)» or with «set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS OFF)» you will get linking errors, due to the fact that symbols are not exported from a dll.
More info about this is provided by link:
2.3.2. Without CMake usage
You simple could create a small program for parsing .obj file by youself without CMake usege. Hovewer, I have to admit that CMake is very usefull program especially for cross-platform development.
Create dlls on Windows without declspec() using new CMake export all feature
CMake 3.4 will have a new feature to simplify porting C and C++ software using shared libraries from Linux/UNIX to Windows. Linux/UNIX developers are often surprised to learn that creating a shared library on Windows known as a DLL (dynamic linked library) requires changes to the source code or an explicit listing of all the symbols that the dll will export. The compilers on Linux/UNIX have the ability to export all symbols in a shared library automatically. On Windows, you must either use compiler directives __declspec(import) and __declspec(export) to declare which symbols are exported/imported from a shared library, or you must create a module definition text file (.def) with a list of all the symbols you want to export and pass that file to the linker.
With C libraries, creating a .def file by hand or automatically is not very difficult since you just have to list the names of all the functions in the library. However, with C++ code, name mangling and the sheer number of functions make crafting a .def file by hand nearly impossible. The standard workaround uses the preprocessor to conditionally insert __declspec(import) and __declspec(export) into the code. However, with a large existing C++ code base, it can be difficult and time consuming to edit all of the source code. CMake now has a feature which allows it to query .obj files that will make up a DLL and create a .def file automatically, in most cases without needing to modify the original source code.
The feature is implemented in CMake via a new target property, WINDOWS_EXPORT_ALL_SYMBOLS. When enabled, this property causes CMake to automatically create a .def file with all symbols found in the input .obj files for a SHARED library on Windows. The .def file will be passed to the linker causing all symbols to be exported from the DLL. For global data symbols, __declspec(dllimport) must still be used when compiling against the code in the DLL. The symbol is exported from the DLL correctly and automatically, but the compiler needs to know that it is being imported from a DLL at compile time. All other function symbols will be automatically exported and imported by callers. This simplifies porting projects to Windows by reducing the need for explicit dllexport markup, even in C++ classes. This property is initialized by the value of the CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS variable when a target is created.
To try this out on an existing project, run
cmake windows shared builds do not export symbols #72
Comments
Copy link Quote reply
sigmoidal commented Feb 18, 2018
When building shared libs on windows, using cmake and -DBUILD_SHARED_LIBS=On , no .lib file is produced, which in turn doesn’t allow a consumer to link against cctz.
Ideally, symbols should be properly exported (see https://msdn.microsoft.com/en-us/library/a90k134d.aspx), then a lib file will be generated.
A not-so-elegant, but working solution may be to enable: CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS , which I had success with, however for optimal results you should only export what should be exported.
This workaround is as simple as adding:
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS YES CACHE BOOL «Export all symbols»)
or running the cmake config command with -DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=True
Sarcasm commented Feb 18, 2018
Until this is officially supported by cctz in general, I think the correct way is to use the CMake command line option: -DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=True .
Overriding the cache from the CMakeLists.txt should be avoided, if the CMakeLists.txt needs to be touched, it would be slightly cleaner to specify the target property WINDOWS_EXPORT_ALL_SYMBOLS to the targets.
I think the real fix is to introduce some export macros so that cctz is a better Windows citizen.
I expect the Bazel build could also benefit from this.
Maybe something along these lines (though I’m not Windows expert):
By the way, do you have a minimal example to test what is not working here?
sigmoidal commented Feb 19, 2018
I think the solution to export symbols is the right way to go, just like most libraries.
I don’t have an example project to offer as I use upstream’s example1.cc with a conan recipe, since I am helping package cctz for the conan package manager (https://github.com/bincrafters/conan-cctz), thus we run libs through CI and use them as dependencies for other projects, so problems become quickly apparent.
There isn’t anything special I am doing, if you try to compile cctz on windows with -DBUILD_SHARED_LIBS=On you will notice no lib is created, thus one cannot link against it.
I’d be happy to help if necessary.
devbww commented Feb 21, 2018
This «declspec» question has come up before, but perhaps this time there is enough expertise out there to be able to come to some conclusion.
So, my question is, «where would this CCTZ_EXPORT be applied?»
It seems to me that every current external symbol would need to be exported, so I’m not sure why we shouldn’t just make that the default, like it is for non-Windows platforms.
sigmoidal commented Feb 21, 2018
I want to clarify that I don’t use cctz currently, so I don’t have a clear picture of the use cases and respective functions that may be candidates for the exported symbol table.
You can do something like have this in a header file:
a) decorate classes/functions to be exported with CCTZ_API: e.g. class CCTZ_API time_zone < . >;
b) When building the library using CCTZ_EXPORTS the dll export table will be generated.
c) consumers won’t have to do anything (they don’t specify CCTZ_EXPORTS usually), thus functions will be imported.
Sarcasm commented Feb 21, 2018
IIUC, Bradley basically suggested we use WINDOWS_EXPORT_ALL_SYMBOLS .
Maybe it makes sense to do that now and use something a finer grained method later if needed.
devbww commented Feb 22, 2018
IIUC, Bradley basically suggested we use WINDOWS_EXPORT_ALL_SYMBOLS.
Right. The direction to «decorate classes/functions to be exported with CCTZ_API» seems brittle and noisy when every external symbol should be, well, external.
I’m also unsure why shared libraries and «non-shared» libraries should be different.
sigmoidal commented Feb 22, 2018
I consider this a solved issue as far as the original problem is concerned which was that no symbols were exported at all.
I don’t however agree that we are discussing external symbols here and I also disagree that what I am proposing is brittle and noisy . We are talking about exported symbols .
The discussion as far as I understand is about (a) exporting every single function and class in the library (which the cmake approach offers for simplicity) vs (b) a clean set of functions/classes intended for use by consumer end-user software.
As far as the end users are concerned I doubt what I am proposing will produce libs that are different in functionality between their shared and static versions. Is there something specific about cctz that would cause this?
Since include/cctz is the public interface of cctz, why would the exports table include all the internal functionality from src/*.h , especially when these internal headers are not distributed with the generated lib.
I understand this may be low priority or unnecessary at this point for cctz, but thanks for discussing it.
devbww commented Apr 17, 2018
Sorry for being slow to respond.
I’m happy to admit that my «every external symbol should be, well, external» assertion was incorrect. There are plenty of «internal» symbols that are only external because they are defined-in and referenced-from different translation units. Having them appear to be internal to the final library, be it shared or not, would be fine.
So, your suggestion stands as (given a suitable definition for CCTZ_API) «decorate classes/functions to be exported with CCTZ_API». OK. I’ll revamp a previous question then as to whether anyone knows exactly where those decorations need to go.
sigmoidal commented Apr 22, 2018
Thanks for responding and especially for taking this positive look at my suggestion.