Search code examples
cbuildbuild-processcmake

Getting link errors with CMake


I'm getting multiple definition link errors after conditionally compiling platform-specific code.

My project is laid out like this:

/
|__+ include/
|  |__+ native/
|  |  |__ impl.h
|  |
|  |__ general.h
|
|__+ src/
   |__+ native/
   |  |__ impl.linux.c
   |  |__ impl.win32.c
   |
   |__ general.c

At the top of the general.c file:

#if defined(LIBRARY_PLATFORM_LINUX)
    #include "native/impl.linux.c"
#elsif defined(LIBRARY_PLATFORM_WIN32)
    #include "native/impl.win32.c"
#endif

I set up introspection in CMake in order to detect the operating system and define the corresponding constants. The thing is, I didn't want to maintain one CMakeLists.txt file in every directory, so I simply globbed all the .c files as suggested in this answer:

file(GLOB_RECURSE LIBRARY_SOURCE_FILES "${PROJECT_SOURCE_DIR}/src/*.c")

Apparently, this is what is causing the problem. It seems to be compiling the code #included in general.c as well as the individual src/native/impl.*.c files.

CMakeFiles/lib.dir/src/native/impl.linux.c.o: In function `declared_in_impl_h':
impl.linux.c:(.text+0x0): multiple definition of `declared_in_impl_h'
CMakeFiles/lib.dir/src/general.c.o:general.c:(.text+0x0): first defined here

How can I untangle this situation?


Solution

  • The best practice for that sort of cross-platform situation is to create two libraries, one for linux and one for windows and stop doing conditional includes. Each platform only compiles and links the relevant library.

    The recommended way to do that with cmake is to stop globbing and just include each file. There are some situations where it can get confused and not realize that it needs to recompile. You can make an argument that non-changing legacy code won't have that problem.

    If you really want to avoid doing either of these things, I would put the included code in a header instead of a c file. You don't really want the include guards so that people don't get it confused for something that should be used like a regular header. Put a bunch of comments in the file to warn them off of said behavior as well.