When I build a shared library / DLL, I’d like to be able to selectively export only symbols that match certain pattern (e.g. the ‘public’ namespace for my library), excluding things that are internal, or brought in from other imported libraries.
GCC/Clang/XCode linkers support using glob-style patterns for exports (which is perfect for my use case), but MSVC’s .def file doesn’t, alas.
However: what WINDOWS_EXPORT_ALL_SYMBOLS is doing under the hood (building up a list of all known global symbols) is close enough (I just have to filter out the symbols that don’t match my pattern).
Before I reinvent the wheel by writing this tool from scratch, I thought I’d ask:
Is there a (legit) way to edit/modify the .def file that CMake creates internally for this purpose? (i.e., after the .def file is created, but before it is handed to the linker?)
Failing that, is there a (legit) way for me to just tell CMake to explicitly create that .def file as an ordinary build step, which I can build rules around?
For additional context: selectively exporting from a library (eg. via GenerateExportHeader) is insufficient when static-only dependencies do not selectively export. Either way, one requires linker-specific hackery to suppress the symbols from the static libraries (e.g. LINKER:-exclude-libs,ALL for GNU ld).
I don’t believe so. However, a feature to add include/exclude regexes might make sense, though the name of the property then gets a little wonky.
Hmm. I don’t think so. There’s no place for “after all .o files are built, but before linking” unless you use an intermediate OBJECT library. Something like:
add_library(foo-objects OBJECT ${sources})
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/foo.def"
DEPENDS $<TARGET_OBJECTS:foo-objects> # Might need 3.20; use `foo-objects` if this doesn't work.
create_def_file "${CMAKE_CURRENT_BINARY_DIR}/foo.def" $<TARGET_OBJECTS:foo-objects>)
add_library(foo SHARED # or STATIC?
"${CMAKE_CURRENT_BINARY_DIR}/foo.def")
target_link_libraries(foo PRIVATE foo-objects) # will add objects to the foo library.
That exists, but there’s no mechanism to change the link command from there (and, e.g., add a source file). CMake either needs to see a custom command making it or it already exist for it to be a source file.
On Visual Studio at least, yes. I don’t know how Xcode does it.
Well, could one not edit the CMake-generated exports.def in place from a PRE_LINK command? Maybe run cmake -P with a custom filtering script? The dependencies happen to be correct because exports.def has to be recreated if any object file changes, so the PRE_LINK trigger will always run because the link step depends on exports.def.
The key is whether or not exports.def gets created before or after user-supplied/custom PRE_LINK commands.
XCode supports linker scripts via LINKER:-exported_symbols_list,${linker_script}.
(nit nit: XCode doesn’t support linker scripts in the same way that GCC does; it’s strictly a list of “export these symbols and hide everything else”, but with glob expressions allowed. That’s all we happen to need, though.)