Static linking with IPO/LTO doesn't properly support object files with the same filename
The ARCHIVE variables used for IPO (e.g. CMAKE_CXX_ARCHIVE_CREATE_IPO
, CMAKE_CXX_ARCHIVE_APPEND_IPO
) use the "r", or "replace", option to combine the archives rather than the "q", or "quick append". Since the ar
tool only takes the object file's filename without taking into account the parent directory, any object files with the same filename in different directories (e.g. foo/Baz.cpp.o
and bar/Baz.cpp.o
) may be silently overwritten when using the "r" option. The replacement logic often only happens when the archiving needs to be split into multiple calls to ar
, such as with a large number of object files. (e.g. foo/Baz.cpp.o
appears in the first call to ar
, and bar/Baz.cpp.o
appears in the second call) When this situation occurs, the object files that were replaced result in undefined symbol errors when linking the final static library.
For example, under /usr/share/cmake/Modules/CMakeCXXInformation.cmake
, it will set the following values that do support multiple object files with the same filename when not using IPO:
set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_CXX_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
However, the compiler-specific IPO variables, such as /usr/share/cmake/Modules/Compiler/GNU.cmake
, use "r" in place of "q".
set(CMAKE_${lang}_ARCHIVE_CREATE_IPO
"\"${CMAKE_${lang}_COMPILER_AR}\" cr <TARGET> <LINK_FLAGS> <OBJECTS>"
)
set(CMAKE_${lang}_ARCHIVE_APPEND_IPO
"\"${CMAKE_${lang}_COMPILER_AR}\" r <TARGET> <LINK_FLAGS> <OBJECTS>"
)
In order to work around this issue, projects must manually set the CMAKE_${lang}_ARCHIVE_*_IPO
variables.