Search code examples
mergecmakecudastatic-librarieslibtool

How can I use CMake to merge my own .o files with a 3rd-party static library to create a new merged static library?


My company sells a commercial Linux app that depends on the NVIDIA CUDA toolkit. However many of our customers do not have root access on their boxes and can't install CUDA themselves, so we want to bundle the CUDA static libraries with our app.

Our legal department has indicated that we need to actually include the contents of the library inside one of our app's existing static libraries rather than just shipping the CUDA static library as a separate file. I can create such a merged library by hand, and it works fine:

libtool --mode=link gcc -static -o <my library>.a <my library's object files> /usr/local/cuda/lib64/libcudart_static.a

(I know this is not portable, but I'm only targeting Linux, so it's okay)

I'm having trouble doing this from within CMake and feel like I'm fighting the system. Is there a reasonably sane way to do this?

I've read a lot of SO answers on the subject but none that I've found concern how to create a merged static library from 3rd-party binaries from within CMake.


Solution

  • You can use add_custom_command to run libtool.

    It takes several options, notably OUTPUT, which is the output file generated by the command, and DEPENDS, which is the list of dependencies the command requires to be ready when it is run.

    You would specify OUTPUT as being the merged library (<my library>.a in your example), and DEPENDS as the object files being merged into the library (<my library's object files> in your example)

    add_custom_command(
        OUTPUT
            ${OUTPUT_LIB}
    
        COMMAND
            libtool --mode=link gcc -static -o ${OUTPUT_LIB} ${INPUT_OBJS} ${LIB_CUDA}
    
        COMMENT
            "Creating merged ${OUTPUT_LIB}"
    
        DEPENDS
            ${INPUT_OBJS}
        )
    

    To then actually run the command you need to add a new target (in makefile parlance, this will create a phony target. In order to do this you use add_custom_target.

    It takes several options, the ones we want are DEPENDS again, which we set to the output of the custom command, and ALL which adds it to the default ALL target.

    add_custom_target(${OUTPUT_LIB}.create
        ALL
        DEPENDS
            ${OUTPUT_LIB}
        )