CMake: link order of imported targets incorrect












0














I have the following scenario:




  • I import two prebuilt libraries into my project (libA, libB)


  • libB has a dependency on libA

  • The executable depends on both libA and libB


However, the relative linking order in my link.txt is incorrect



/usr/bin/c++     CMakeFiles/bin.dir/main.cpp.o  -o bin ../libA.a ../libB.a


I would expect libA.a to be listed after libB.a.
The CMakeLists.txt looks something along the following lines



cmake_minimum_required(VERSION 3.13)
project(cmake_test)
set(lib_dir ${CMAKE_CURRENT_SOURCE_DIR})

add_library(MY::libA IMPORTED INTERFACE)
set_target_properties(MY::libA PROPERTIES INTERFACE_LINK_LIBRARIES "${lib_dir}/libA.a")

add_library(MY::libB IMPORTED INTERFACE)
set_target_properties(MY::libB PROPERTIES INTERFACE_LINK_LIBRARIES "MY::libA;${lib_dir}/libB.a")

add_executable(bin ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
target_link_libraries(bin PUBLIC MY::libB MY::libA)




Below a description of my attempts to solve the problem. Some without success and some with sucecss but using modifications that render the code usless for the production environment.



Successful attempts:




  • Remove the depedency of bin on libA (i.e. replace the last line by target_link_libraries(bin PUBLIC MY::libB). This works but I cannot remove the dependency in real code.

  • Replace the target type IMPORTED INTERFACE by IMPORTED STATIC. Use IMPORTED_LOCATION instead of INTERFACE_LINK_LIBRARIES and use target_link_libraries to express the dependency of libB on libA. In this case the link.txt yields: [...] -o bin ../libA.a ../libB.a ../libA.a. As soon as I revert the target type for libB the link order breaks down again. In the production environment, however, one of the targets is created by conan as IMPORTED INTERFACE.


Attempts without success (same behaviour as described):




  • Create a separate IMPORTED target (use IMPORTED_LOCATION) for every lib and group them inside an INTERFACE target

  • Sprinkle the code with ADD_DEPENDENCIES

  • Remove libA from the INTERFACE_LINK_LIBRARIES in line 9 and use target_link_libraries(MY::libB INTERFACE MY::libA) instead. Same result.




Example code that shows the same failure using INTERFACES as a building block



cmake_minimum_required(VERSION 3.13)
project(cmake_test)
set(lib_dir ${CMAKE_CURRENT_SOURCE_DIR})

# libA
add_library(MY::libA_file1 IMPORTED STATIC)
set_target_properties(MY::libA_file1 PROPERTIES IMPORTED_LOCATION "${lib_dir}/libA.a")

add_library(libA INTERFACE)
target_link_libraries(libA INTERFACE MY::libA_file1)

# libB
add_library(MY::libB_file1 IMPORTED STATIC)
set_target_properties(MY::libB_file1 PROPERTIES IMPORTED_LOCATION "${lib_dir}/libB.a")

add_library(libB INTERFACE)
target_link_libraries(libB INTERFACE MY::libB_file1 libA)


add_executable(bin ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
target_link_libraries(bin PUBLIC libA libB)









share|improve this question
























  • @Tsyvarev thanks for sharing the thread but unless I miss the obvious it emphasizes my point. Quote "if library A depends on library B, then libA MUST appear before libB in the linker flags." In my example using A=libB and B=libA (unfortunate naming), I come to the conclusion: libB must appear before libA i.e. libA must come after libB.
    – user823255
    17 hours ago


















0














I have the following scenario:




  • I import two prebuilt libraries into my project (libA, libB)


  • libB has a dependency on libA

  • The executable depends on both libA and libB


However, the relative linking order in my link.txt is incorrect



/usr/bin/c++     CMakeFiles/bin.dir/main.cpp.o  -o bin ../libA.a ../libB.a


I would expect libA.a to be listed after libB.a.
The CMakeLists.txt looks something along the following lines



cmake_minimum_required(VERSION 3.13)
project(cmake_test)
set(lib_dir ${CMAKE_CURRENT_SOURCE_DIR})

add_library(MY::libA IMPORTED INTERFACE)
set_target_properties(MY::libA PROPERTIES INTERFACE_LINK_LIBRARIES "${lib_dir}/libA.a")

add_library(MY::libB IMPORTED INTERFACE)
set_target_properties(MY::libB PROPERTIES INTERFACE_LINK_LIBRARIES "MY::libA;${lib_dir}/libB.a")

add_executable(bin ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
target_link_libraries(bin PUBLIC MY::libB MY::libA)




Below a description of my attempts to solve the problem. Some without success and some with sucecss but using modifications that render the code usless for the production environment.



Successful attempts:




  • Remove the depedency of bin on libA (i.e. replace the last line by target_link_libraries(bin PUBLIC MY::libB). This works but I cannot remove the dependency in real code.

  • Replace the target type IMPORTED INTERFACE by IMPORTED STATIC. Use IMPORTED_LOCATION instead of INTERFACE_LINK_LIBRARIES and use target_link_libraries to express the dependency of libB on libA. In this case the link.txt yields: [...] -o bin ../libA.a ../libB.a ../libA.a. As soon as I revert the target type for libB the link order breaks down again. In the production environment, however, one of the targets is created by conan as IMPORTED INTERFACE.


Attempts without success (same behaviour as described):




  • Create a separate IMPORTED target (use IMPORTED_LOCATION) for every lib and group them inside an INTERFACE target

  • Sprinkle the code with ADD_DEPENDENCIES

  • Remove libA from the INTERFACE_LINK_LIBRARIES in line 9 and use target_link_libraries(MY::libB INTERFACE MY::libA) instead. Same result.




Example code that shows the same failure using INTERFACES as a building block



cmake_minimum_required(VERSION 3.13)
project(cmake_test)
set(lib_dir ${CMAKE_CURRENT_SOURCE_DIR})

# libA
add_library(MY::libA_file1 IMPORTED STATIC)
set_target_properties(MY::libA_file1 PROPERTIES IMPORTED_LOCATION "${lib_dir}/libA.a")

add_library(libA INTERFACE)
target_link_libraries(libA INTERFACE MY::libA_file1)

# libB
add_library(MY::libB_file1 IMPORTED STATIC)
set_target_properties(MY::libB_file1 PROPERTIES IMPORTED_LOCATION "${lib_dir}/libB.a")

add_library(libB INTERFACE)
target_link_libraries(libB INTERFACE MY::libB_file1 libA)


add_executable(bin ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
target_link_libraries(bin PUBLIC libA libB)









share|improve this question
























  • @Tsyvarev thanks for sharing the thread but unless I miss the obvious it emphasizes my point. Quote "if library A depends on library B, then libA MUST appear before libB in the linker flags." In my example using A=libB and B=libA (unfortunate naming), I come to the conclusion: libB must appear before libA i.e. libA must come after libB.
    – user823255
    17 hours ago
















0












0








0







I have the following scenario:




  • I import two prebuilt libraries into my project (libA, libB)


  • libB has a dependency on libA

  • The executable depends on both libA and libB


However, the relative linking order in my link.txt is incorrect



/usr/bin/c++     CMakeFiles/bin.dir/main.cpp.o  -o bin ../libA.a ../libB.a


I would expect libA.a to be listed after libB.a.
The CMakeLists.txt looks something along the following lines



cmake_minimum_required(VERSION 3.13)
project(cmake_test)
set(lib_dir ${CMAKE_CURRENT_SOURCE_DIR})

add_library(MY::libA IMPORTED INTERFACE)
set_target_properties(MY::libA PROPERTIES INTERFACE_LINK_LIBRARIES "${lib_dir}/libA.a")

add_library(MY::libB IMPORTED INTERFACE)
set_target_properties(MY::libB PROPERTIES INTERFACE_LINK_LIBRARIES "MY::libA;${lib_dir}/libB.a")

add_executable(bin ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
target_link_libraries(bin PUBLIC MY::libB MY::libA)




Below a description of my attempts to solve the problem. Some without success and some with sucecss but using modifications that render the code usless for the production environment.



Successful attempts:




  • Remove the depedency of bin on libA (i.e. replace the last line by target_link_libraries(bin PUBLIC MY::libB). This works but I cannot remove the dependency in real code.

  • Replace the target type IMPORTED INTERFACE by IMPORTED STATIC. Use IMPORTED_LOCATION instead of INTERFACE_LINK_LIBRARIES and use target_link_libraries to express the dependency of libB on libA. In this case the link.txt yields: [...] -o bin ../libA.a ../libB.a ../libA.a. As soon as I revert the target type for libB the link order breaks down again. In the production environment, however, one of the targets is created by conan as IMPORTED INTERFACE.


Attempts without success (same behaviour as described):




  • Create a separate IMPORTED target (use IMPORTED_LOCATION) for every lib and group them inside an INTERFACE target

  • Sprinkle the code with ADD_DEPENDENCIES

  • Remove libA from the INTERFACE_LINK_LIBRARIES in line 9 and use target_link_libraries(MY::libB INTERFACE MY::libA) instead. Same result.




Example code that shows the same failure using INTERFACES as a building block



cmake_minimum_required(VERSION 3.13)
project(cmake_test)
set(lib_dir ${CMAKE_CURRENT_SOURCE_DIR})

# libA
add_library(MY::libA_file1 IMPORTED STATIC)
set_target_properties(MY::libA_file1 PROPERTIES IMPORTED_LOCATION "${lib_dir}/libA.a")

add_library(libA INTERFACE)
target_link_libraries(libA INTERFACE MY::libA_file1)

# libB
add_library(MY::libB_file1 IMPORTED STATIC)
set_target_properties(MY::libB_file1 PROPERTIES IMPORTED_LOCATION "${lib_dir}/libB.a")

add_library(libB INTERFACE)
target_link_libraries(libB INTERFACE MY::libB_file1 libA)


add_executable(bin ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
target_link_libraries(bin PUBLIC libA libB)









share|improve this question















I have the following scenario:




  • I import two prebuilt libraries into my project (libA, libB)


  • libB has a dependency on libA

  • The executable depends on both libA and libB


However, the relative linking order in my link.txt is incorrect



/usr/bin/c++     CMakeFiles/bin.dir/main.cpp.o  -o bin ../libA.a ../libB.a


I would expect libA.a to be listed after libB.a.
The CMakeLists.txt looks something along the following lines



cmake_minimum_required(VERSION 3.13)
project(cmake_test)
set(lib_dir ${CMAKE_CURRENT_SOURCE_DIR})

add_library(MY::libA IMPORTED INTERFACE)
set_target_properties(MY::libA PROPERTIES INTERFACE_LINK_LIBRARIES "${lib_dir}/libA.a")

add_library(MY::libB IMPORTED INTERFACE)
set_target_properties(MY::libB PROPERTIES INTERFACE_LINK_LIBRARIES "MY::libA;${lib_dir}/libB.a")

add_executable(bin ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
target_link_libraries(bin PUBLIC MY::libB MY::libA)




Below a description of my attempts to solve the problem. Some without success and some with sucecss but using modifications that render the code usless for the production environment.



Successful attempts:




  • Remove the depedency of bin on libA (i.e. replace the last line by target_link_libraries(bin PUBLIC MY::libB). This works but I cannot remove the dependency in real code.

  • Replace the target type IMPORTED INTERFACE by IMPORTED STATIC. Use IMPORTED_LOCATION instead of INTERFACE_LINK_LIBRARIES and use target_link_libraries to express the dependency of libB on libA. In this case the link.txt yields: [...] -o bin ../libA.a ../libB.a ../libA.a. As soon as I revert the target type for libB the link order breaks down again. In the production environment, however, one of the targets is created by conan as IMPORTED INTERFACE.


Attempts without success (same behaviour as described):




  • Create a separate IMPORTED target (use IMPORTED_LOCATION) for every lib and group them inside an INTERFACE target

  • Sprinkle the code with ADD_DEPENDENCIES

  • Remove libA from the INTERFACE_LINK_LIBRARIES in line 9 and use target_link_libraries(MY::libB INTERFACE MY::libA) instead. Same result.




Example code that shows the same failure using INTERFACES as a building block



cmake_minimum_required(VERSION 3.13)
project(cmake_test)
set(lib_dir ${CMAKE_CURRENT_SOURCE_DIR})

# libA
add_library(MY::libA_file1 IMPORTED STATIC)
set_target_properties(MY::libA_file1 PROPERTIES IMPORTED_LOCATION "${lib_dir}/libA.a")

add_library(libA INTERFACE)
target_link_libraries(libA INTERFACE MY::libA_file1)

# libB
add_library(MY::libB_file1 IMPORTED STATIC)
set_target_properties(MY::libB_file1 PROPERTIES IMPORTED_LOCATION "${lib_dir}/libB.a")

add_library(libB INTERFACE)
target_link_libraries(libB INTERFACE MY::libB_file1 libA)


add_executable(bin ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
target_link_libraries(bin PUBLIC libA libB)






cmake






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 15 hours ago

























asked 21 hours ago









user823255

670514




670514












  • @Tsyvarev thanks for sharing the thread but unless I miss the obvious it emphasizes my point. Quote "if library A depends on library B, then libA MUST appear before libB in the linker flags." In my example using A=libB and B=libA (unfortunate naming), I come to the conclusion: libB must appear before libA i.e. libA must come after libB.
    – user823255
    17 hours ago




















  • @Tsyvarev thanks for sharing the thread but unless I miss the obvious it emphasizes my point. Quote "if library A depends on library B, then libA MUST appear before libB in the linker flags." In my example using A=libB and B=libA (unfortunate naming), I come to the conclusion: libB must appear before libA i.e. libA must come after libB.
    – user823255
    17 hours ago


















@Tsyvarev thanks for sharing the thread but unless I miss the obvious it emphasizes my point. Quote "if library A depends on library B, then libA MUST appear before libB in the linker flags." In my example using A=libB and B=libA (unfortunate naming), I come to the conclusion: libB must appear before libA i.e. libA must come after libB.
– user823255
17 hours ago






@Tsyvarev thanks for sharing the thread but unless I miss the obvious it emphasizes my point. Quote "if library A depends on library B, then libA MUST appear before libB in the linker flags." In my example using A=libB and B=libA (unfortunate naming), I come to the conclusion: libB must appear before libA i.e. libA must come after libB.
– user823255
17 hours ago














1 Answer
1






active

oldest

votes


















0














You incorrectly think about INTERFACE_LINK_LIBRARIES property as a "content" of the library's target, which is ordered by target_link_libraries call.



Using



target_link_libraries(MY::libB INTERFACE MY::libA)


you setup link dependency between library targets MY::libB and MY::libA. That is, "content" of MY::libB target should come before "content" of MY::libA target in the linking command line.



But INTERFACE_LINK_LIBRARIES property is NOT a "content" of the library target! It is just an additional link dependency.



As opposite, IMPORTED_LOCATION (for non-INTERFACE IMPORTED target) is a "content" of the library, and target_link_libraries affects on its ordering.



It seems that you cannot add link dependency for a library, using INTERFACE library target. You should use IMPORTED library target for that purpose:



# Collect libraries related to 'libA'
file(GLOB libs_A "${lib_dir}/libA*.a")
# For each library create IMPORTED target with IMPORTED_LOCATION property.
set(libs_A_targets)
foreach(lib_A ${libs_A})
# Form a unique name for the IMPORTED target: subtarget_A_*
string(REGEX REPLACE "^${lib_dir}/libA([^.]*).a$" "subtarget_A_\1" lib_A_target ${lib_A})
# Create a target with this name
add_library(${lib_A_target} STATIC IMPORTED)
set_target_properties(${lib_A_target} PROPERTIES IMPORTED_LOCATION ${lib_A})
# And add the target into the list
list(APPEND libs_A_targets ${lib_A_target})
endforeach()

# In a similar way collect libraries for libB.
set(lib_B_targets ...)

# Now link each libB* library with each libA*.
foreach(lib_B_target ${libs_B_targets})
target_link_libraries(${lib_B_target} INTERFACE ${libs_A_targets})
endforeach()

# Now interface libraries, which combine libA* and libB*, can be created
add_library(libA INTERFACE)
target_link_libraries(libA INTERFACE ${libs_A_targets})

add_library(libB INTERFACE)
target_link_libraries(libB INTERFACE ${libs_B_targets})

# Now these INTERFACE libraries can be linked into an executable in any order
add_executable(bin ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
target_link_libraries(bin PUBLIC libA libB)





share|improve this answer























  • Thanks a lot, I already had that suspicion. However, how can I solve the problem if I have multiple libs that I want to import? If I import a single lib using IMPORT_LOCATION I get indeed the correct result (point 2 of my success-list). In the real code, however, I have a usecase of importing multiple libs. I tried two approaches: 1) Putting one lib as IMPORTED_LOCATION and the rest in its INTERFACE_LINK_LIBRARIES. 2) Creating multiple IMPORTED targets and "grouping" them in a single INTERFACE target. Both approach fail me. Can this be solved without importing+linking each lib individually?
    – user823255
    16 hours ago










  • "Can this be solved without importing+linking each lib individually?" - As far as I understand, you cannot. If you need to link several libraries with a single one, you may use foreach loop. You still may wrap several IMPORTED library targets into INTERFACE one, so linking with that single library would automatically link with all IMPORTED libraries, and order of those IMPORTED libraries would be correct.
    – Tsyvarev
    16 hours ago










  • That is terrible news :( I cannot believe there is no mechanism for such an obvious use case. How can one 1) Grouping together multiple libs into a target and export them (as a library builder) 2) Or build higher level abstractions? I read all the time about modern CMake but if this simple building block cannot be realized then I don't understand how one can ever move past the terrifying usage of global variables and spreading them all over the place.
    – user823255
    15 hours ago










  • just for the sake of completeness I have attached a slightly altered example where I try to order dependencies in INTERFACES. However, as soon as I reach the point that one interface depends on another one, the logic starts to break down again. So in the above example I have a libA with multiple libs and libB with multiple libs (one of them could be CUDA, another one OpenCV). When I link two interfaces together, the order is not consistent anymore
    – user823255
    15 hours ago










  • Not sure that I understand your problem. If you are developer of CUDA, and know that your libraries should be linked with OpenCV, you need to link every your library with OpenCV separately. (You may use link_libraries or foreach commands for reduce copy-pasting). Then you may export your libraries. Additionally, you may create an INTERFACE library which combines your libraries together, and export it too. When a user imports your INTERFACE library and links with it, he/she will get desired effect.
    – Tsyvarev
    15 hours ago











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53942683%2fcmake-link-order-of-imported-targets-incorrect%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









0














You incorrectly think about INTERFACE_LINK_LIBRARIES property as a "content" of the library's target, which is ordered by target_link_libraries call.



Using



target_link_libraries(MY::libB INTERFACE MY::libA)


you setup link dependency between library targets MY::libB and MY::libA. That is, "content" of MY::libB target should come before "content" of MY::libA target in the linking command line.



But INTERFACE_LINK_LIBRARIES property is NOT a "content" of the library target! It is just an additional link dependency.



As opposite, IMPORTED_LOCATION (for non-INTERFACE IMPORTED target) is a "content" of the library, and target_link_libraries affects on its ordering.



It seems that you cannot add link dependency for a library, using INTERFACE library target. You should use IMPORTED library target for that purpose:



# Collect libraries related to 'libA'
file(GLOB libs_A "${lib_dir}/libA*.a")
# For each library create IMPORTED target with IMPORTED_LOCATION property.
set(libs_A_targets)
foreach(lib_A ${libs_A})
# Form a unique name for the IMPORTED target: subtarget_A_*
string(REGEX REPLACE "^${lib_dir}/libA([^.]*).a$" "subtarget_A_\1" lib_A_target ${lib_A})
# Create a target with this name
add_library(${lib_A_target} STATIC IMPORTED)
set_target_properties(${lib_A_target} PROPERTIES IMPORTED_LOCATION ${lib_A})
# And add the target into the list
list(APPEND libs_A_targets ${lib_A_target})
endforeach()

# In a similar way collect libraries for libB.
set(lib_B_targets ...)

# Now link each libB* library with each libA*.
foreach(lib_B_target ${libs_B_targets})
target_link_libraries(${lib_B_target} INTERFACE ${libs_A_targets})
endforeach()

# Now interface libraries, which combine libA* and libB*, can be created
add_library(libA INTERFACE)
target_link_libraries(libA INTERFACE ${libs_A_targets})

add_library(libB INTERFACE)
target_link_libraries(libB INTERFACE ${libs_B_targets})

# Now these INTERFACE libraries can be linked into an executable in any order
add_executable(bin ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
target_link_libraries(bin PUBLIC libA libB)





share|improve this answer























  • Thanks a lot, I already had that suspicion. However, how can I solve the problem if I have multiple libs that I want to import? If I import a single lib using IMPORT_LOCATION I get indeed the correct result (point 2 of my success-list). In the real code, however, I have a usecase of importing multiple libs. I tried two approaches: 1) Putting one lib as IMPORTED_LOCATION and the rest in its INTERFACE_LINK_LIBRARIES. 2) Creating multiple IMPORTED targets and "grouping" them in a single INTERFACE target. Both approach fail me. Can this be solved without importing+linking each lib individually?
    – user823255
    16 hours ago










  • "Can this be solved without importing+linking each lib individually?" - As far as I understand, you cannot. If you need to link several libraries with a single one, you may use foreach loop. You still may wrap several IMPORTED library targets into INTERFACE one, so linking with that single library would automatically link with all IMPORTED libraries, and order of those IMPORTED libraries would be correct.
    – Tsyvarev
    16 hours ago










  • That is terrible news :( I cannot believe there is no mechanism for such an obvious use case. How can one 1) Grouping together multiple libs into a target and export them (as a library builder) 2) Or build higher level abstractions? I read all the time about modern CMake but if this simple building block cannot be realized then I don't understand how one can ever move past the terrifying usage of global variables and spreading them all over the place.
    – user823255
    15 hours ago










  • just for the sake of completeness I have attached a slightly altered example where I try to order dependencies in INTERFACES. However, as soon as I reach the point that one interface depends on another one, the logic starts to break down again. So in the above example I have a libA with multiple libs and libB with multiple libs (one of them could be CUDA, another one OpenCV). When I link two interfaces together, the order is not consistent anymore
    – user823255
    15 hours ago










  • Not sure that I understand your problem. If you are developer of CUDA, and know that your libraries should be linked with OpenCV, you need to link every your library with OpenCV separately. (You may use link_libraries or foreach commands for reduce copy-pasting). Then you may export your libraries. Additionally, you may create an INTERFACE library which combines your libraries together, and export it too. When a user imports your INTERFACE library and links with it, he/she will get desired effect.
    – Tsyvarev
    15 hours ago
















0














You incorrectly think about INTERFACE_LINK_LIBRARIES property as a "content" of the library's target, which is ordered by target_link_libraries call.



Using



target_link_libraries(MY::libB INTERFACE MY::libA)


you setup link dependency between library targets MY::libB and MY::libA. That is, "content" of MY::libB target should come before "content" of MY::libA target in the linking command line.



But INTERFACE_LINK_LIBRARIES property is NOT a "content" of the library target! It is just an additional link dependency.



As opposite, IMPORTED_LOCATION (for non-INTERFACE IMPORTED target) is a "content" of the library, and target_link_libraries affects on its ordering.



It seems that you cannot add link dependency for a library, using INTERFACE library target. You should use IMPORTED library target for that purpose:



# Collect libraries related to 'libA'
file(GLOB libs_A "${lib_dir}/libA*.a")
# For each library create IMPORTED target with IMPORTED_LOCATION property.
set(libs_A_targets)
foreach(lib_A ${libs_A})
# Form a unique name for the IMPORTED target: subtarget_A_*
string(REGEX REPLACE "^${lib_dir}/libA([^.]*).a$" "subtarget_A_\1" lib_A_target ${lib_A})
# Create a target with this name
add_library(${lib_A_target} STATIC IMPORTED)
set_target_properties(${lib_A_target} PROPERTIES IMPORTED_LOCATION ${lib_A})
# And add the target into the list
list(APPEND libs_A_targets ${lib_A_target})
endforeach()

# In a similar way collect libraries for libB.
set(lib_B_targets ...)

# Now link each libB* library with each libA*.
foreach(lib_B_target ${libs_B_targets})
target_link_libraries(${lib_B_target} INTERFACE ${libs_A_targets})
endforeach()

# Now interface libraries, which combine libA* and libB*, can be created
add_library(libA INTERFACE)
target_link_libraries(libA INTERFACE ${libs_A_targets})

add_library(libB INTERFACE)
target_link_libraries(libB INTERFACE ${libs_B_targets})

# Now these INTERFACE libraries can be linked into an executable in any order
add_executable(bin ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
target_link_libraries(bin PUBLIC libA libB)





share|improve this answer























  • Thanks a lot, I already had that suspicion. However, how can I solve the problem if I have multiple libs that I want to import? If I import a single lib using IMPORT_LOCATION I get indeed the correct result (point 2 of my success-list). In the real code, however, I have a usecase of importing multiple libs. I tried two approaches: 1) Putting one lib as IMPORTED_LOCATION and the rest in its INTERFACE_LINK_LIBRARIES. 2) Creating multiple IMPORTED targets and "grouping" them in a single INTERFACE target. Both approach fail me. Can this be solved without importing+linking each lib individually?
    – user823255
    16 hours ago










  • "Can this be solved without importing+linking each lib individually?" - As far as I understand, you cannot. If you need to link several libraries with a single one, you may use foreach loop. You still may wrap several IMPORTED library targets into INTERFACE one, so linking with that single library would automatically link with all IMPORTED libraries, and order of those IMPORTED libraries would be correct.
    – Tsyvarev
    16 hours ago










  • That is terrible news :( I cannot believe there is no mechanism for such an obvious use case. How can one 1) Grouping together multiple libs into a target and export them (as a library builder) 2) Or build higher level abstractions? I read all the time about modern CMake but if this simple building block cannot be realized then I don't understand how one can ever move past the terrifying usage of global variables and spreading them all over the place.
    – user823255
    15 hours ago










  • just for the sake of completeness I have attached a slightly altered example where I try to order dependencies in INTERFACES. However, as soon as I reach the point that one interface depends on another one, the logic starts to break down again. So in the above example I have a libA with multiple libs and libB with multiple libs (one of them could be CUDA, another one OpenCV). When I link two interfaces together, the order is not consistent anymore
    – user823255
    15 hours ago










  • Not sure that I understand your problem. If you are developer of CUDA, and know that your libraries should be linked with OpenCV, you need to link every your library with OpenCV separately. (You may use link_libraries or foreach commands for reduce copy-pasting). Then you may export your libraries. Additionally, you may create an INTERFACE library which combines your libraries together, and export it too. When a user imports your INTERFACE library and links with it, he/she will get desired effect.
    – Tsyvarev
    15 hours ago














0












0








0






You incorrectly think about INTERFACE_LINK_LIBRARIES property as a "content" of the library's target, which is ordered by target_link_libraries call.



Using



target_link_libraries(MY::libB INTERFACE MY::libA)


you setup link dependency between library targets MY::libB and MY::libA. That is, "content" of MY::libB target should come before "content" of MY::libA target in the linking command line.



But INTERFACE_LINK_LIBRARIES property is NOT a "content" of the library target! It is just an additional link dependency.



As opposite, IMPORTED_LOCATION (for non-INTERFACE IMPORTED target) is a "content" of the library, and target_link_libraries affects on its ordering.



It seems that you cannot add link dependency for a library, using INTERFACE library target. You should use IMPORTED library target for that purpose:



# Collect libraries related to 'libA'
file(GLOB libs_A "${lib_dir}/libA*.a")
# For each library create IMPORTED target with IMPORTED_LOCATION property.
set(libs_A_targets)
foreach(lib_A ${libs_A})
# Form a unique name for the IMPORTED target: subtarget_A_*
string(REGEX REPLACE "^${lib_dir}/libA([^.]*).a$" "subtarget_A_\1" lib_A_target ${lib_A})
# Create a target with this name
add_library(${lib_A_target} STATIC IMPORTED)
set_target_properties(${lib_A_target} PROPERTIES IMPORTED_LOCATION ${lib_A})
# And add the target into the list
list(APPEND libs_A_targets ${lib_A_target})
endforeach()

# In a similar way collect libraries for libB.
set(lib_B_targets ...)

# Now link each libB* library with each libA*.
foreach(lib_B_target ${libs_B_targets})
target_link_libraries(${lib_B_target} INTERFACE ${libs_A_targets})
endforeach()

# Now interface libraries, which combine libA* and libB*, can be created
add_library(libA INTERFACE)
target_link_libraries(libA INTERFACE ${libs_A_targets})

add_library(libB INTERFACE)
target_link_libraries(libB INTERFACE ${libs_B_targets})

# Now these INTERFACE libraries can be linked into an executable in any order
add_executable(bin ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
target_link_libraries(bin PUBLIC libA libB)





share|improve this answer














You incorrectly think about INTERFACE_LINK_LIBRARIES property as a "content" of the library's target, which is ordered by target_link_libraries call.



Using



target_link_libraries(MY::libB INTERFACE MY::libA)


you setup link dependency between library targets MY::libB and MY::libA. That is, "content" of MY::libB target should come before "content" of MY::libA target in the linking command line.



But INTERFACE_LINK_LIBRARIES property is NOT a "content" of the library target! It is just an additional link dependency.



As opposite, IMPORTED_LOCATION (for non-INTERFACE IMPORTED target) is a "content" of the library, and target_link_libraries affects on its ordering.



It seems that you cannot add link dependency for a library, using INTERFACE library target. You should use IMPORTED library target for that purpose:



# Collect libraries related to 'libA'
file(GLOB libs_A "${lib_dir}/libA*.a")
# For each library create IMPORTED target with IMPORTED_LOCATION property.
set(libs_A_targets)
foreach(lib_A ${libs_A})
# Form a unique name for the IMPORTED target: subtarget_A_*
string(REGEX REPLACE "^${lib_dir}/libA([^.]*).a$" "subtarget_A_\1" lib_A_target ${lib_A})
# Create a target with this name
add_library(${lib_A_target} STATIC IMPORTED)
set_target_properties(${lib_A_target} PROPERTIES IMPORTED_LOCATION ${lib_A})
# And add the target into the list
list(APPEND libs_A_targets ${lib_A_target})
endforeach()

# In a similar way collect libraries for libB.
set(lib_B_targets ...)

# Now link each libB* library with each libA*.
foreach(lib_B_target ${libs_B_targets})
target_link_libraries(${lib_B_target} INTERFACE ${libs_A_targets})
endforeach()

# Now interface libraries, which combine libA* and libB*, can be created
add_library(libA INTERFACE)
target_link_libraries(libA INTERFACE ${libs_A_targets})

add_library(libB INTERFACE)
target_link_libraries(libB INTERFACE ${libs_B_targets})

# Now these INTERFACE libraries can be linked into an executable in any order
add_executable(bin ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
target_link_libraries(bin PUBLIC libA libB)






share|improve this answer














share|improve this answer



share|improve this answer








edited 10 hours ago

























answered 17 hours ago









Tsyvarev

25.6k42558




25.6k42558












  • Thanks a lot, I already had that suspicion. However, how can I solve the problem if I have multiple libs that I want to import? If I import a single lib using IMPORT_LOCATION I get indeed the correct result (point 2 of my success-list). In the real code, however, I have a usecase of importing multiple libs. I tried two approaches: 1) Putting one lib as IMPORTED_LOCATION and the rest in its INTERFACE_LINK_LIBRARIES. 2) Creating multiple IMPORTED targets and "grouping" them in a single INTERFACE target. Both approach fail me. Can this be solved without importing+linking each lib individually?
    – user823255
    16 hours ago










  • "Can this be solved without importing+linking each lib individually?" - As far as I understand, you cannot. If you need to link several libraries with a single one, you may use foreach loop. You still may wrap several IMPORTED library targets into INTERFACE one, so linking with that single library would automatically link with all IMPORTED libraries, and order of those IMPORTED libraries would be correct.
    – Tsyvarev
    16 hours ago










  • That is terrible news :( I cannot believe there is no mechanism for such an obvious use case. How can one 1) Grouping together multiple libs into a target and export them (as a library builder) 2) Or build higher level abstractions? I read all the time about modern CMake but if this simple building block cannot be realized then I don't understand how one can ever move past the terrifying usage of global variables and spreading them all over the place.
    – user823255
    15 hours ago










  • just for the sake of completeness I have attached a slightly altered example where I try to order dependencies in INTERFACES. However, as soon as I reach the point that one interface depends on another one, the logic starts to break down again. So in the above example I have a libA with multiple libs and libB with multiple libs (one of them could be CUDA, another one OpenCV). When I link two interfaces together, the order is not consistent anymore
    – user823255
    15 hours ago










  • Not sure that I understand your problem. If you are developer of CUDA, and know that your libraries should be linked with OpenCV, you need to link every your library with OpenCV separately. (You may use link_libraries or foreach commands for reduce copy-pasting). Then you may export your libraries. Additionally, you may create an INTERFACE library which combines your libraries together, and export it too. When a user imports your INTERFACE library and links with it, he/she will get desired effect.
    – Tsyvarev
    15 hours ago


















  • Thanks a lot, I already had that suspicion. However, how can I solve the problem if I have multiple libs that I want to import? If I import a single lib using IMPORT_LOCATION I get indeed the correct result (point 2 of my success-list). In the real code, however, I have a usecase of importing multiple libs. I tried two approaches: 1) Putting one lib as IMPORTED_LOCATION and the rest in its INTERFACE_LINK_LIBRARIES. 2) Creating multiple IMPORTED targets and "grouping" them in a single INTERFACE target. Both approach fail me. Can this be solved without importing+linking each lib individually?
    – user823255
    16 hours ago










  • "Can this be solved without importing+linking each lib individually?" - As far as I understand, you cannot. If you need to link several libraries with a single one, you may use foreach loop. You still may wrap several IMPORTED library targets into INTERFACE one, so linking with that single library would automatically link with all IMPORTED libraries, and order of those IMPORTED libraries would be correct.
    – Tsyvarev
    16 hours ago










  • That is terrible news :( I cannot believe there is no mechanism for such an obvious use case. How can one 1) Grouping together multiple libs into a target and export them (as a library builder) 2) Or build higher level abstractions? I read all the time about modern CMake but if this simple building block cannot be realized then I don't understand how one can ever move past the terrifying usage of global variables and spreading them all over the place.
    – user823255
    15 hours ago










  • just for the sake of completeness I have attached a slightly altered example where I try to order dependencies in INTERFACES. However, as soon as I reach the point that one interface depends on another one, the logic starts to break down again. So in the above example I have a libA with multiple libs and libB with multiple libs (one of them could be CUDA, another one OpenCV). When I link two interfaces together, the order is not consistent anymore
    – user823255
    15 hours ago










  • Not sure that I understand your problem. If you are developer of CUDA, and know that your libraries should be linked with OpenCV, you need to link every your library with OpenCV separately. (You may use link_libraries or foreach commands for reduce copy-pasting). Then you may export your libraries. Additionally, you may create an INTERFACE library which combines your libraries together, and export it too. When a user imports your INTERFACE library and links with it, he/she will get desired effect.
    – Tsyvarev
    15 hours ago
















Thanks a lot, I already had that suspicion. However, how can I solve the problem if I have multiple libs that I want to import? If I import a single lib using IMPORT_LOCATION I get indeed the correct result (point 2 of my success-list). In the real code, however, I have a usecase of importing multiple libs. I tried two approaches: 1) Putting one lib as IMPORTED_LOCATION and the rest in its INTERFACE_LINK_LIBRARIES. 2) Creating multiple IMPORTED targets and "grouping" them in a single INTERFACE target. Both approach fail me. Can this be solved without importing+linking each lib individually?
– user823255
16 hours ago




Thanks a lot, I already had that suspicion. However, how can I solve the problem if I have multiple libs that I want to import? If I import a single lib using IMPORT_LOCATION I get indeed the correct result (point 2 of my success-list). In the real code, however, I have a usecase of importing multiple libs. I tried two approaches: 1) Putting one lib as IMPORTED_LOCATION and the rest in its INTERFACE_LINK_LIBRARIES. 2) Creating multiple IMPORTED targets and "grouping" them in a single INTERFACE target. Both approach fail me. Can this be solved without importing+linking each lib individually?
– user823255
16 hours ago












"Can this be solved without importing+linking each lib individually?" - As far as I understand, you cannot. If you need to link several libraries with a single one, you may use foreach loop. You still may wrap several IMPORTED library targets into INTERFACE one, so linking with that single library would automatically link with all IMPORTED libraries, and order of those IMPORTED libraries would be correct.
– Tsyvarev
16 hours ago




"Can this be solved without importing+linking each lib individually?" - As far as I understand, you cannot. If you need to link several libraries with a single one, you may use foreach loop. You still may wrap several IMPORTED library targets into INTERFACE one, so linking with that single library would automatically link with all IMPORTED libraries, and order of those IMPORTED libraries would be correct.
– Tsyvarev
16 hours ago












That is terrible news :( I cannot believe there is no mechanism for such an obvious use case. How can one 1) Grouping together multiple libs into a target and export them (as a library builder) 2) Or build higher level abstractions? I read all the time about modern CMake but if this simple building block cannot be realized then I don't understand how one can ever move past the terrifying usage of global variables and spreading them all over the place.
– user823255
15 hours ago




That is terrible news :( I cannot believe there is no mechanism for such an obvious use case. How can one 1) Grouping together multiple libs into a target and export them (as a library builder) 2) Or build higher level abstractions? I read all the time about modern CMake but if this simple building block cannot be realized then I don't understand how one can ever move past the terrifying usage of global variables and spreading them all over the place.
– user823255
15 hours ago












just for the sake of completeness I have attached a slightly altered example where I try to order dependencies in INTERFACES. However, as soon as I reach the point that one interface depends on another one, the logic starts to break down again. So in the above example I have a libA with multiple libs and libB with multiple libs (one of them could be CUDA, another one OpenCV). When I link two interfaces together, the order is not consistent anymore
– user823255
15 hours ago




just for the sake of completeness I have attached a slightly altered example where I try to order dependencies in INTERFACES. However, as soon as I reach the point that one interface depends on another one, the logic starts to break down again. So in the above example I have a libA with multiple libs and libB with multiple libs (one of them could be CUDA, another one OpenCV). When I link two interfaces together, the order is not consistent anymore
– user823255
15 hours ago












Not sure that I understand your problem. If you are developer of CUDA, and know that your libraries should be linked with OpenCV, you need to link every your library with OpenCV separately. (You may use link_libraries or foreach commands for reduce copy-pasting). Then you may export your libraries. Additionally, you may create an INTERFACE library which combines your libraries together, and export it too. When a user imports your INTERFACE library and links with it, he/she will get desired effect.
– Tsyvarev
15 hours ago




Not sure that I understand your problem. If you are developer of CUDA, and know that your libraries should be linked with OpenCV, you need to link every your library with OpenCV separately. (You may use link_libraries or foreach commands for reduce copy-pasting). Then you may export your libraries. Additionally, you may create an INTERFACE library which combines your libraries together, and export it too. When a user imports your INTERFACE library and links with it, he/she will get desired effect.
– Tsyvarev
15 hours ago


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53942683%2fcmake-link-order-of-imported-targets-incorrect%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Monofisismo

Angular Downloading a file using contenturl with Basic Authentication

Olmecas