Auto generated exports are written even if up-to-date
The auto generated exports are written to exports.def even if they are already up-to-date causing the library to be re-linked. Auto export generation is implemented with a pre-link build event. When compiling from within Visual Studio this is often not an issue, because Visual Studio has fast update checks on top of MSBuild which cause a project not to be built when everything is up-to-date. On the command line MSBuild is executed directly which executes all targets including the pre-link build events on every build. The individual targets have to check if the output is already up-to-date. The command __create_def
does not perform any check and therefore unconditionally updates the time stamp of exports.def. This in turn causes the link target to call the linker again.
A minimal reproducer is the following CMakeLists.txt:
cmake_minimum_required(VERSION 3.15)
project(Lib)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
add_library(Lib SHARED dummy.cpp)
# Enable this to reproduce from inside Visual Studio
#set_target_properties(Lib PROPERTIES VS_GLOBAL_DisableFastUpToDateCheck true)
I used the following content for dummy.cpp:
int exported()
{
return 0;
}
First configure and build for the first time:
mkdir build
cd build
cmake -G "Visual Studio 16 2019" ../
cmake --build .
Then for each consecutive build using the command cmake --build .
the exports for target Lib are generated and the library is linked again. One possible solution could be to call devenv.exe
to build using Visual Studio rules including the fast up-to-date check, however when I tried this for such a small project it was slower to call devenv.exe
. I think this should be tackled at a lower level, because there might be other reasons why the build event is executed.
The command __create_def
gets a file with a list of obj and def files as input. If any of the obj and def files is older than an existing exports.def file, then the exports.def file should be considered up-to-date.