[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