featherless biped
featherless biped

Reputation: 173

Incremental Linking with CMake (GCC/CLANG)

I am aware that incremental linking is not a compiler feature, but a linker feature. In the past, I have used MSVC's incremental linking (/INCREMENTAL) and now I want to use it in my project that compiles with clang (or gcc if need be). My project consists of three static libraries (A, B, and C) and one executable (D). As a side note, D depends B and C, while C depends on A and B.

From my understanding, all I have to do is pass -Wl,-i to the linker (CMake uses ld by default) as seen here. My CMakeLists.txt looks like this:

set(LINKER_FLAGS "-Wl,-i")

add_library(A)
target_link_options(A PRIVATE ${LINKER_FLAGS})
target_link_libraries(A PRIVATE libSomeLib.so)


add_library(B)
target_link_options(B PRIVATE ${LINKER_FLAGS})

add_library(C)
target_link_options(C PRIVATE ${LINKER_FLAGS})

add_executable(D)
target_link_libraries(D PRIVATE libSomeOtherLib.so C B A)
target_link_options(D PRIVATE ${LINKER_FLAGS})

However, I get this error:

/usr/bin/ld: -r and -pie may not be used together

I then decided to run /usr/bin/ld --help and search for these flags. I saw that -r, -i, --relocatable are explained as Generate relocatable output.

Changing to -Wl,-i,-nostdlib,-nostartfiles,-Wl,-i,-nostdlib,-nostartfiles,-no-pie or -Wl,-r (or any combination of these flags) does not change the error message.

However, if I remove -Wl and just use -r, I get /usr/bin/ld: attempted static link of dynamic object libSomeOtherLib.so.

My questions are:

  1. Is my understanding of incremental linking correct? Can I use it in CMake with ld?
  2. Why does the error message change when not using -Wl?
  3. I wrote a hello world program to eliminate all dependencies (static and shared libraries). When compiling with clang++ main.cpp -Wl,-i -o main I still get /usr/bin/ld: -r and -pie may not be used together. Why?
  4. Is it possible to use incremental linking in my case, especially with may chain of static and shared dependencies?
  5. Do I need to pass -Wl flags to all targets or is it enough to set them just for my executable?

Edit:

The documentation says that target_link_libraries cannot be used to add options for static library targets, since they do not use a linker, so I have removed them from my CMakeLists.txt (the original code is still present in the question for clarity).

Removing all target_link_options (for the three static libraries as seen stated in the documentation) and target_link_options(D PRIVATE ${LINKER_FLAGS}) for the executable doesn't solve anything. My generator is ninja and I can see the build commands in build.ninja. When looking at the flags, I only see that -Wl,-i is only passed to the executable (LINK_FLAGS = -Wl,-i), while the three static libraries have no linker flags (explained in the documentation). So I need target_link_options(D PRIVATE ${LINKER_FLAGS}) to somehow pass -Wl,-i to the linker.

When passing -Wl,-i to set_property(TARGET A PROPERTY STATIC_LIBRARY_OPTIONS ${INCREMENTAL_LINKING}), I see that ar is called for each static library and it outputs /usr/bin/ar: invalid option -- 'W'.

Current CMakeLists.txt:

set(LINKER_FLAGS "-Wl,-i")

add_library(A)
set_property(TARGET A PROPERTY STATIC_LIBRARY_OPTIONS ${INCREMENTAL_LINKING})
target_link_libraries(A PRIVATE libSomeLib.so)

add_library(B)
set_property(TARGET B PROPERTY STATIC_LIBRARY_OPTIONS ${INCREMENTAL_LINKING})

add_library(C)
set_property(TARGET C PROPERTY STATIC_LIBRARY_OPTIONS ${INCREMENTAL_LINKING})

add_executable(D)
target_link_libraries(D PRIVATE libSomeOtherLib.so C B A)
target_link_options(D PRIVATE ${LINKER_FLAGS})

Upvotes: 0

Views: 809

Answers (0)

Related Questions