[CMake] CMake link order

Andreas Naumann Andreas-Naumann at gmx.net
Fri Oct 18 16:15:21 EDT 2019


Hey all,

I face a similar problem when constructing a correct (and predictable)
link order for Linux and Cygwin. It would be of great help, if there is
some documentation.

In particular, I would raise two question
     1) when does the link order change?
     2) when does a clean up happen and in which way?

I did also some experiments on linux with cmake 3.13.4 and ended up with
the appended (nearly) minimal example. The example consists of:

  * two "fake"-libraries A and B, whose paths are stored in two
    variables libA and libB respectively. (they serve just for
    demonstration, no real linking is required)
  * two interface libraries interfaceA and interfaceB. Each links to the
    corresponding fake library.
  * two imported libraries impA and impB, each has the location to the
    corresponding fake library.

Now I construct some combinations:

 1. An interface library interfaceA_B_vA, which links against the
    interface libraries "interfaceA interfaceB ${libA}" and an
    executable, which links only against interfaceA_B_vA. For that
    executable, I get the link order "B A"
 2. Suppose one tries to correct that and link explicitly against with
    the variable. Such an executable which links as "${libA}
    interfaceA_B_vA". In that case, I got the link order "A A B". So we
    have a changed order compared to the previous experiment.
 3. If I use the imported libraries instead of the variables from
    experiment 1, I get the link order A B A, as expected.

 From these experiments, I got the impression, that

 1. linking through variables remains a nightmare. That is nothing new.
 2. interface libraries might change their order
 3. imported libraries lead to a more stable link order?

I hope somebody could shed some light in this behavior.

Best regards,
Andreas


Am 18.10.19 um 18:24 schrieb Fred Baksik:
>
>
> On Fri, Oct 18, 2019, at 11:55 AM, Fred Baksik wrote:
>>
>> In target_link_libraries it states that "The library dependency graph
>> is normally acyclic (a DAG)".  I recall from my own experience that
>> the DAG is not always created the same way when generating the
>> project.  It has to do with the way with this part of CMake is
>> implemented (C++ containers and that sort of thing) so while all the
>> inputs are the same the order is Not the same so it produces a
>> different DAG which changed the ordering of the components build
>> order which also altered the link order.
>>
>> For the GHS Generator to ensure that the exact same project files are
>> output we sorted the components by name into a vector first (instead
>> of just using a set) before supplying it to this algorithm.  Then the
>> results were always the same.
>>
>
> Sorry, I wanted to clarify this a bit.  The DAG is correct. For
> example lets say A depends on B and C and then C on D.  This DAG
> always comes out the same.  But when you try to extract the dependents
> of A it sometimes returns something that will give you B then C or C
> then B when accessing them in a linear order. So there were
> differences if you inspected these items with the debugger.
>
> When I ran across these kinds of things with the GHS Generator we sort
> things in lexicographical order to produce the same results every time.
>
> Best regards,
> Fred
>

-------------- next part --------------
project(testLinkOrder)
cmake_minimum_required(VERSION 3.5)

file(WRITE "simpleProg.cc" "int main() { return 0; }")
set(libA "${CMAKE_BINARY_DIR}/A.a")
file(WRITE "${libA}" "i am not a library")

set(libB "${CMAKE_BINARY_DIR}/B.a")
file(WRITE "${libB}" "i am not a library")

add_library(impA IMPORTED STATIC)
set_target_properties(impA PROPERTIES IMPORTED_LOCATION ${libA})

add_library(impB IMPORTED STATIC)
set_target_properties(impB PROPERTIES IMPORTED_LOCATION ${libB})

add_library(interfaceA INTERFACE)
target_link_libraries(interfaceA INTERFACE ${libA})

add_library(interfaceB INTERFACE)
target_link_libraries(interfaceB INTERFACE ${libB})
#target_link_libraries(interfaceA INTERFACE ${libB})

add_library(interface_A_B_vA INTERFACE)
target_link_libraries(interface_A_B_vA INTERFACE interfaceA interfaceB ${libA})

add_executable(linkInterface_A_B_vA simpleProg.cc)
target_link_libraries(linkInterface_A_B_vA interface_A_B_vA)

add_executable(linkvA_IABAVA simpleProg.cc)
target_link_libraries(linkvA_IABAVA ${libA} interface_A_B_vA)

add_library(interface_impA_impB_vA INTERFACE)
target_link_libraries(interface_impA_impB_vA INTERFACE impA impB ${libA})

add_executable(linkInterface_impA_impB_vA simpleProg.cc)
target_link_libraries(linkInterface_impA_impB_vA interface_impA_impB_vA)


More information about the CMake mailing list