3

I am trying to follow the answer given here to combine multiple static libraries into a single archive under MinGW64. Specifically, I use CMake and specify the following command:

    add_custom_command(
        OUTPUT ${COMBINED_CORE_LIB_NAME}
        COMMAND ${AR} -crs ${COMBINED_CORE_LIB_NAME} ${CORE_LIB_TARGET_FILES}
        DEPENDS ${DILIGENT_CORE_INSTALL_LIBS_LIST}
        COMMENT "Combining core libraries..."
    )

Also, following the recommendation from here, I do not use stock ar, but rather cross ar:

find_program(AR NAMES x86_64-w64-mingw32-gcc-ar)

However, no matter what I do, ar refuses to generate index and every time I am trying to link against the produced library, I get this error:

error adding symbols: Archive has no index; run ranlib to add one

Running ranlib as suggested either stock one or x86_64-w64-mingw32-gcc-ranlib makes no difference.

I spent 15 minutes to make this work with MSVC and lib.exe and have been struggling for 8 hours with MinGW. Any suggestion would be highly appreciated.

[Edit]: It turned out that this problem is not really specific to MinGW and also happens on Linux in a very similar fashion.

Egor
  • 779
  • 5
  • 20
  • 1
    After you combine the archives you have to run `ranlib` to create the index. You should have another step in the custom command like `COMMAND ${RANLIB} ${COMBINED_CORE_LIB_NAME}`. (I've encountered a [similar problem on Android](https://stackoverflow.com/q/36340060/608639)). – jww Jan 18 '19 at 07:03
  • As I mentioned in the question, running ranlib either stock one or x86_64-w64-mingw32-gcc-ranlib makes no difference. Also s option should make the ar generate the index. – Egor Jan 18 '19 at 07:04
  • Well, I typically use `ranlib` as a separate step. Maybe you need to build the archive `COMMAND ${AR} cr ${COMBINED_CORE_LIB_NAME}` and then build the index as a separate step with `COMMAND ${AR} s ${COMBINED_CORE_LIB_NAME}`. – jww Jan 18 '19 at 07:10
  • @jww I tried that too. I also checked the make files and they definitely run the right commands, but still no index for some reason. – Egor Jan 18 '19 at 07:15
  • 1
    MinGW sounds broke. File a bug report and ask for a work around. (I avoid MinGW like the plague. It is nothing but problems). – jww Jan 18 '19 at 07:19
  • 1
    @jww Can't agree more, but for some reason quite a few users of my library prefer MinGW, so I am trying to support it. – Egor Jan 18 '19 at 07:22

1 Answers1

2

As it turned out, it is not possible to merge multiple .a files into a single .a library using ar utility: it refuses to generate index. A working solution is to unpack all object files from all static libraries and then repack them into a combined library.

Below is the CMake instructions I ended up with:

set(COMBINED_CORE_LIB_NAME "${CMAKE_STATIC_LIBRARY_PREFIX}DiligentCore${CMAKE_STATIC_LIBRARY_SUFFIX}")

foreach(CORE_LIB ${DILIGENT_CORE_INSTALL_LIBS_LIST})
    list(APPEND CORE_LIB_TARGET_FILES $<TARGET_FILE:${CORE_LIB}>)
endforeach(CORE_LIB)

if(MSVC)
    add_custom_command(
        OUTPUT ${COMBINED_CORE_LIB_NAME}
        COMMAND ${LIB_EXE} /OUT:${COMBINED_CORE_LIB_NAME} ${CORE_LIB_TARGET_FILES}
        DEPENDS ${DILIGENT_CORE_INSTALL_LIBS_LIST}
        COMMENT "Combining core libraries..."
    )
    add_custom_target(DiligentCore-static ALL DEPENDS ${COMBINED_CORE_LIB_NAME})
else()

    if(PLATFORM_WIN32)
        # do NOT use stock ar on MinGW
        find_program(AR NAMES x86_64-w64-mingw32-gcc-ar)
    else()
        set(AR ${CMAKE_AR})
    endif()

    if(AR)
        add_custom_command(
            OUTPUT ${COMBINED_CORE_LIB_NAME}
            # Delete all object files from current directory
            COMMAND ${CMAKE_COMMAND} -E remove "*${CMAKE_C_OUTPUT_EXTENSION}"
            DEPENDS ${DILIGENT_CORE_INSTALL_LIBS_LIST}
            COMMENT "Combining core libraries..."
        )

        # Unpack all object files from all targets to current directory
        foreach(CORE_LIB_TARGET ${CORE_LIB_TARGET_FILES})
            add_custom_command(
                OUTPUT ${COMBINED_CORE_LIB_NAME}
                COMMAND ${AR} -x ${CORE_LIB_TARGET}
                APPEND
            )
        endforeach()

        # Pack object files to a combined library and delete them
        add_custom_command(
            OUTPUT ${COMBINED_CORE_LIB_NAME}
            COMMAND ${AR} -crs ${COMBINED_CORE_LIB_NAME} "*${CMAKE_C_OUTPUT_EXTENSION}"
            COMMAND ${CMAKE_COMMAND} -E remove "*${CMAKE_C_OUTPUT_EXTENSION}"
            APPEND
        )

        add_custom_target(DiligentCore-static ALL DEPENDS ${COMBINED_CORE_LIB_NAME})
    else()
        message("ar command is not found")
    endif()
endif()

if(TARGET DiligentCore-static)
    install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${COMBINED_CORE_LIB_NAME}"
            DESTINATION "${DILIGENT_CORE_INSTALL_DIR}/lib/"
    )
    set_target_properties(DiligentCore-static PROPERTIES
        FOLDER Core
    )
else()
    message("Unable to find librarian tool. Combined DiligentCore static library will not be produced.")
endif()
Egor
  • 779
  • 5
  • 20