Benefits of CMake Object Libraries

CMake Object Libraries can be used to keep build directories less cluttered and speed up the build process. The traditional workflow for Makefile was to create lots of object files (targets) with the relevant compile options, definitions and link flags. Then the final executable or library targets would be linked from all the object files.

CMake add_library() defaults to creating static libraries. The following stanza creates “libfoo.a” or similar:

add_library(foo src.f90)

With numerous targets, there are a lot of “lib*.a” that may be cluttering the build directory. Also, there is a finite time consumed in creating all those archive .a files from the object files. For projects that use Visual Studio, using Object Libraries can help avoid complications with exporting symbols for MSVC.

CMake object libraries: a cleaner option for most cases where the “lib*.a” artifact is not needed is to create CMake Object Libraries instead:

add_library(foo OBJECT src1.f90 src2.f90)
add_library(bar OBJECT src3.c src4.c)

add_executable(baz main.cpp $<TARGET_OBJECTS:foo> $<TARGET_OBJECTS:bar>)

instead of having files under build/ like “libfoo.a, libbar.a” there will be only “baz.exe”. The object files will be tucked away under build/CMakeFiles/foo/*.o and build/CMakeFiles/bar/*.o. The generator expressions expand to all the object files of “foo” and “bar” like a legacy Makefile.

The INTERFACE target properties of object libraries propagate up to targets linking them as usual. You may need to modify the PUBLIC / PRIVATE / INTERFACE of object libraries or add them to the “target_link_libraries()” of the top-level targets when going from static or shared libraries to object libraries.

Caveats: object libraries with duplicate symbols can cause conflicts that need to be manually resolved. When linking non-object libraries, the linker typically just uses the first instance seen of a symbol.