2

I have to merge one of my app's libs with the NVIDIA CUDA static lib using this horrific awful CMake code:

GET_TARGET_PROPERTY(OUTPUT_LIB ${LIBNAME} LOCATION)
add_custom_command (TARGET ${LIBNAME}
                    POST_BUILD
                    COMMAND mv ${OUTPUT_LIB} ${OUTPUT_LIB}.old
                    COMMAND echo "create ${OUTPUT_LIB}" > combineLibs.mri
                    COMMAND echo "addlib ${OUTPUT_LIB}.old" >> combineLibs.mri
                    COMMAND echo "addlib ${CUDA_LOCATION}"  >> combineLibs.mri
                    COMMAND echo "save"  >> combineLibs.mri
                    COMMAND echo "end" >> combineLibs.mri
                    COMMAND ar -M <combineLibs.mri
                    COMMAND rm ${OUTPUT_LIB}.old
                    COMMENT "Building merged library for ${LIBNAME} at ${OUTPUT_LIB}, including ${CUDA_LOCATION}"
)
target_link_libraries(${LIBNAME} -pthread -c)

This successfully produces a merged static library that has all the symbols in it. However, the NVIDIA CUDA static lib brought with it dependencies on libpthread and libc in the form of unresolved symbols. Now the merged library also has those unresolved symbols, and the target_link_libraries line doesn't seem to do what I seem to think it does, because the symbols don't get resolved at link-time. How do I get the merged static library to dynamically link against libpthread and libc?

iLikeDirt
  • 606
  • 5
  • 17

1 Answers1

1

The the target_link_libraries line does indeed not do what you think.

target_link_libraries(target,options) can have the desired effect of adding the linker options options to the linkage of target only if target is something that is produced by the linker. If no linkage happens in the production of target then this directive will have no effect.

Your target is a static library. A static library - unlike a program, and unlike a dynamic/shared library - is not produced by the linker. As your custom_command in fact illustrates, a static library is produced by the GNU general purpose archiver, ar. It is nothing but an archive of files which happen to be object files, but as far as ar is concerned they might as well be the contents of your Documents, Pictures and Music folders. Since no linkage is involved in the production of a static library, nothing can be linked with a static library.

An ar archive can be used as a linker input in the linkage of something that is produced by the linker - a program or a shared library. In that case the linker will look into the archive to see if contains any object files it needs to carry on the linkage. If it finds any, it will extract them from the archive and link them into the program. The linkage will be exactly the same as if you had listed the required object files in the linker commandline and not mentioned the archive at all.

But if any of the object files that the linker extracts from an archive bring with them undefined references, then to get them resolved you must link some library or libraries that define those references in the linkage of the program or shared library that you want the linker to produce - just as you must do to resolve undefined references in any other object files you input to the linkage.

So,

How do I get the merged static library to dynamically link against libpthread and libc?

You can't. It doesn't make sense. Any library dependencies of object files in a static library can be satisfied only in the linkage of a program or shared library that has acquired those dependencies by linking those object files.

Finally, -c is not a GCC linkage option that will have the effect of requesting linkage of libc. It is not a linkage option at all. It is an option that directs the GCC frontend not to invoke the linker. It is passed to GCC to request compilation without linkage, and the perverse effect of including it in a CMake target_link_libraries directive will be to stop any linkage of the target from happening.

If you want to explicitly request linkage of libc, use -lc, following the linker usage protocol that -lname requests linkage of libname.

Perhaps you inferred that -c requests linkage of libc from the assumption that -pthread requests linkage of libpthread. In fact, -lpthread would request linkage of libpthread. The option -pthread is a more abstract GCC option, for both compilation and linkage, that means do the right things, for this platform, to link with the Posix Threads library - which might entail passing -lpthead to the linker, and possibly not.

Thus -pthread is OK as an argument of target_link_libraries that will have the effect of requesting Posix Threads linkage, but see answers to cmake and libpthread for CMake-proper ways of doing this.

Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182