target_link_libraries appears to link libraries twice

Hi, I have a CMakeLists.txt file that builds a static library using gcc 12. We need to link in many Intel DPDK libraries, which we do as follows:

target_link_libraries(${_kernel_lib_name}
    -Wl,--as-needed 
    -Wl,--no-undefined 
    -Wl,-O1 
    -Wl,--whole-archive 
    -Wl,--start-group 
    ${DpdkBuildPath}/lib/librte_node.so
    ${DpdkBuildPath}/lib/librte_graph.so
    ${DpdkBuildPath}/lib/librte_pipeline.so
    <snip>
    ${DpdkBuildPath}/drivers/librte_baseband_la12xx.so
    ${DpdkBuildPath}/drivers/librte_baseband_null.so
    ${DpdkBuildPath}/drivers/librte_baseband_turbo_sw.so
    -Wl,--no-whole-archive 
    -Wl,--no-as-needed 
    -pthread -lm -ldl -lnuma -Wl,--export-dynamic 
    /usr/lib/x86_64-linux-gnu/libelf.so
    /usr/lib/x86_64-linux-gnu/libz.so
    -latomic 
    -Wl,--end-group
)

My problem is that this list of libraries appears twice in the link command, leading to errors such as:

/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/12/libgcc.a(_muldi3.o): in function `__multi3':
(.text+0x0): multiple definition of `__multi3'; /usr/lib/gcc/x86_64-linux-gnu/12/libgcc.a(_muldi3.o):(.text+0x0): first defined here
/

I can work around it by specifying:

-Wl,--allow-multiple-definition

but is there a better solution?

hi @DavidA ,

It’s okay for the library to be linked twice. In fact this is necessary at times when there are circular dependencies.

However, your particular error typically happens when the libraries are linked twice and they are different version with different symbol signatures.

It might be helpful to see the complete entry for target_link_libraries. Your output implies that that some of it was omitted ala <snip>

Also, this stackoverflow entry seems to be extremely similar to your scenario. While it doesn’t have an answer, the comments seem to imply the found the culprit is the -Wl, --whole-archive option that is being used.

I’m not used to adding link options via target_link_libraries. This might be something that should be done using the target_link_options interface?

Additionally, you might want to also include the actual link output.

During the compile you can build using make VERBOSE=1 and then you can see exactly what is passed to the the linker and the order of the flags, etc.