0
votes

I'm using CMake to facilitate cross-platform builds of a C++ project. Using the same CMakeLists.txt files, I'm successfully completing builds on Linux (generating Unix Makefiles to compile with g++), OSX (generating Unix Makefiles to compile with clang++), and Windows (generating for Visual Studio 16 2019).

Most recently, I've been testing the build process using the MinGW Makefiles generator on Windows. CMake generates the Makefile without any problems. When I call mingw32-make in the directory where the Makefile is generated, however, I start to run into problems. I'm able to compile several source files into an object library, but when I try to link the print_graphs executable to this object library, I get a flood of multiple definition errors for methods in the first source file of the object library, as follows:

Scanning dependencies of target print_graphs
[ 52%] Building CXX object src/CMakeFiles/print_graphs.dir/print_graphs.cpp.obj
[ 57%] Linking CXX executable print_graphs.exe
CMakeFiles\print_graphs.dir/objects.a(roaring.c.obj):roaring.c:(.text+0x6833): multiple definition of `roaring_bitmap_get_copy_on_write'
CMakeFiles\print_graphs.dir/objects.a(print_graphs.cpp.obj):print_graphs.cpp:(.text$roaring_bitmap_get_copy_on_write[roaring_bitmap_get_copy_on_write]+0x0): first defined here
CMakeFiles\print_graphs.dir/objects.a(roaring.c.obj):roaring.c:(.text+0x6850): multiple definition of `roaring_bitmap_set_copy_on_write'
CMakeFiles\print_graphs.dir/objects.a(print_graphs.cpp.obj):print_graphs.cpp:(.text$roaring_bitmap_set_copy_on_write[roaring_bitmap_set_copy_on_write]+0x0): first defined here
CMakeFiles\print_graphs.dir/objects.a(set_cover_solver.cpp.obj):set_cover_solver.cpp:(.text$ra_get_index[ra_get_index]+0x0): multiple definition of `ra_get_index'
CMakeFiles\print_graphs.dir/objects.a(roaring.c.obj):roaring.c:(.text+0x65a1): first defined here
CMakeFiles\print_graphs.dir/objects.a(set_cover_solver.cpp.obj):set_cover_solver.cpp:(.text$ra_get_container_at_index[ra_get_container_at_index]+0x0): multiple definition of `ra_get_container_at_index'
CMakeFiles\print_graphs.dir/objects.a(roaring.c.obj):roaring.c:(.text+0x660e): first defined here
CMakeFiles\print_graphs.dir/objects.a(set_cover_solver.cpp.obj):set_cover_solver.cpp:(.text$roaring_bitmap_add_range[roaring_bitmap_add_range]+0x0): multiple definition of `roaring_bitmap_add_range'
CMakeFiles\print_graphs.dir/objects.a(roaring.c.obj):roaring.c:(.text+0x688e): first defined here
CMakeFiles\print_graphs.dir/objects.a(set_cover_solver.cpp.obj):set_cover_solver.cpp:(.text$roaring_bitmap_contains[roaring_bitmap_contains]+0x0): multiple definition of `roaring_bitmap_contains'
CMakeFiles\print_graphs.dir/objects.a(roaring.c.obj):roaring.c:(.text+0x690a): first defined here
collect2.exe: error: ld returned 1 exit status
mingw32-make[2]: *** [src\CMakeFiles\print_graphs.dir\build.make:104: src/print_graphs.exe] Error 1
mingw32-make[1]: *** [CMakeFiles\Makefile2:933: src/CMakeFiles/print_graphs.dir/all] Error 2
mingw32-make: *** [Makefile:94: all] Error 2

In the CMakeLists.txt file in my src/ directory, I have the following basic code:

# Add header files:
set(HEADERS
    ${HEADERS_DIR}/cxxopts.h
    ${HEADERS_DIR}/roaring.h
    ${HEADERS_DIR}/roaring.hh
    ${HEADERS_DIR}/pugiconfig.h
    ${HEADERS_DIR}/pugixml.h
    ...
)

# Add object source files:
set(SOURCES 
    roaring.c
    pugixml.cpp
    ...
)

# Combine the object source files into an object library:
add_library(objects OBJECT ${SOURCES} ${HEADERS})

# Point the build targets to their include directories:
target_include_directories(objects PRIVATE ${HEADERS_DIR})

# Add all executable scripts to be generated:
add_executable(program1 $<TARGET_OBJECTS:objects> program1.cpp )

# Point the build targets to their include directories:
target_include_directories(program1 PRIVATE ${HEADERS_DIR})

# Make sure the build targets are compiled with C++11:
target_compile_features(program1 PRIVATE cxx_std_11)

I'm new to CMake, so I'm willing to bet that the issue is bad form on my part in the CMakeLists.txt file. But since CMake is able to build everything without problems when I use other generators, I'm not sure what the issue is. Does anyone know what might be causing the issue with the MinGW Makefiles generator in particular?

1
Shouldn't you use target_link_libraries(program1 objects) to link object files? - arrowd
"I get a flood of multiple definition errors for methods ..." - Do not describe the errors message, show that error message instead. Also, you may pass VERBOSE=1 option to mingw32-make for see actual command line used for linking. Check that this command line actually contains duplicate object files. - Tsyvarev
@Tsyvarev, thanks for the recommendation. I edited the post to include the error messages. I also ran mingw32-make with the VERBOSE=1 option, and I got the following commands before the multiple definition errors: - Joey McCollum
"C:\Program Files\CMake\bin\cmake.exe" -E remove -f CMakeFiles\print_graphs.dir/objects.a C:\ProgramData\chocolatey\bin\ar.exe cr CMakeFiles\print_graphs.dir/objects.a @CMakeFiles\print_graphs.dir\objects1.rsp C:\ProgramData\chocolatey\bin\g++.exe -Wl,--whole-archive CMakeFiles\print_graphs.dir/objects.a -Wl,--no-whole-archive -o print_graphs.exe -Wl,--out-implib,libprint_graphs.dll.a -Wl,--major-image-version,0,--minor-image-version,0 @CMakeFiles\print_graphs.dir\linklibs.rsp The only thing that strikes me is that the path to ar and g++ is through chocolatey, not mingw. - Joey McCollum
As far as I can tell, there are no duplicate files appearing in the commands. objects.a gets built, and then it is referenced for linking. - Joey McCollum

1 Answers

0
votes

Okay, I found the issue, and, as expected, it was bad form in CMake on my part. In the section of my code with

# Combine the object source files into an object library:
add_library(objects OBJECT ${SOURCES} ${HEADERS})

There was no need to reference ${HEADERS}, as that connection is made explicitly in the next couple lines:

# Point the build targets to their include directories:
target_include_directories(objects PRIVATE ${HEADERS_DIR})

Including a reference to the header files in the initial add_library call seems to result in a duplication of the header files (or at least of references to them).

I'm still not sure why other build tools weren't tripped up by this issue while mingw32-make was, but proper syntax is good to maintain in any event, and things are working as expected now.