Configuration dependent link

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Configuration dependent link

Stephan Menzel
Hello,

I am trying to have config dependent link. Basically, coming from a set of 3rd party location scripts I have a Visual Studio target which I would like to equip with imported libs rather than the existing "manual" scripts. With that I have a few trouble that maybe someone can help me with.

Configuration types are

set (CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo" CACHE STRING "..." FORCE)

Libs usually come in 2 flavors, Release and Debug.

So I create imported libs and put the configurations in:

 ... create imported lib
 set_property(TARGET ${name} PROPERTY IMPORTED_CONFIGURATIONS "")
 set_property(TARGET ${name} APPEND PROPERTY IMPORTED_CONFIGURATIONS "Debug")
 set_property(TARGET ${name} APPEND PROPERTY IMPORTED_CONFIGURATIONS "Release")
 set_property(TARGET ${name} APPEND PROPERTY IMPORTED_CONFIGURATIONS "RelWithDebInfo")
       
So my first question, what is the relation here? Do I have to do this? Is the configuration name case sensitive?

So then I worked my way through creating the imported libs and augmented the scripts in order to put locations and dependencies in the target's properties:

set_property(TARGET ${name} APPEND PROPERTY IMPORTED_IMPLIB_Release ${implib})
set_property(TARGET ${name} APPEND PROPERTY IMPORTED_IMPLIB_RelWithDebInfo ${implib})
set_property(TARGET ${name} APPEND PROPERTY IMPORTED_IMPLIB_Debug ${implib})
...and same for locations (DLLs)

"implib" is the configuration specific lib here. After the procedure the property  IMPORTED_IMPLIB_Debug and so on contain all the libs.

When all the imported libs are created I was hoping to be able to link against them like so:

target_link_libraries(${mylib} PUBLIC ${someimportedlib})

My problem is: Which Config is chosen? How can I tell target_link_libraries to link ${mylib} in Config Debug against ${someimportedlib} with the IMPORTED_IMPLIB_Debug properties? I was hoping this would be automatic as it is obvious information but that doesn't seem to work. Instead I usually get an additional linker dependency named my::lib.obj-NOTFOUND

Also when doing all this manually appending to the property multiple times (as for example boost or Qt libraries with lots of libs to link against) seems to cause errors eventually. They appear in Visual Studio's properties dialog as _one_ Linker Dependency. For example:

Like I add (resolved)

add_library(sys::boost SHARED GLOBAL)
... setup lib ...
set_property(TARGET sys::boost APPEND PROPERTY IMPORTED_IMPLIB_Release
    D:\3rd_party\boost_1_59_0\lib\vc110\x64\boost_atomic-vc110-mt-1_59.lib)
set_property(TARGET sys::boost APPEND PROPERTY IMPORTED_IMPLIB_Release
    D:\3rd_party\boost_1_59_0\lib\vc110\x64\boost_chrono-vc110-mt-1_59.lib)
set_property(TARGET sys::boost APPEND PROPERTY IMPORTED_IMPLIB_Release
    D:\3rd_party\boost_1_59_0\lib\vc110\x64\boost_date_time-vc110-mt-1_59.lib)
... and so on and the same for corresponding DLLs as location...

eventually yields _one_ linker dependency called:

D:\3rd_party\boost_1_59_0\lib\vc110\x64\boost_chrono-vc110-mt-1_59.lib%3BE:\3rd_party\boost_1_59_0\lib\vc110\x64\boost_date_time-vc110-mt-1_59.lib%3BE:\3rd_party\boost_1_59_0\lib\vc110\x64\boost_filesystem-vc110-mt-1_59.lib%3BE:\3rd_party\boost_1_59_0\lib\vc110
.... and so on.

Visual Studio seems to hate that and throws errors. So I thought about extracting this property, foreach() it and then add the tokens as linker dependencies one at a time. Can I do that somehow? Config specific? And if so: why? When I dive this deep into what I would hope CMake is all about, I might as well keep the old hand made script based system that doesn't use imported targets.

Sooo.....

TL;DR

1) How can I have config specifc imported targets with multiple IMPLIBs?
2) Why should I? Isn't there a better, more canonical way? Hasn't this wheel been invented hundreds of times?

Thanks a bunch for any hints here... I'm lost in properties.

Stephan






--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake
Reply | Threaded
Open this post in threaded view
|

Re: Configuration dependent link

Stephan Menzel
I have investigated further into this and still have no solution, but a hint, which anyone may be able to confirm.

It appears like I was led astray by a number of bugs in target_link_libraries() which I was mistaking for intentional behavior and so I started to re-create the behavior manually. Which was wrong in the first place.

So it boils down to the following:

I create an imported lib

add_library(my::imp SHARED IMPORTED GLOBAL)

and import libraries and dlls like so (for all 3 configurations):

set_property(TARGET my::imp APPEND PROPERTY IMPORTED_LOCATION_DEBUG some_debug.dll)
set_property(TARGET my::imp APPEND PROPERTY INTERFACE_LINK_LIBRARIES_DEBUG some_debug.lib)

and then link my own target to the imported:

target_link_libraries(mylib PUBLIC myimp)

When I do this without any .lib files being present in there, it will add an (implicit ?)  link dependency to "my::imp-NOTFOUND.obj" - rather than nothing at all - which will choke the linker. I have tried all possible combinations of properties, not using the config specifics, using the INTERFACE_ prefixed rather than IMPORTED_ prefixed but that doesn't seem to make much difference. I have however reason to believe that it does work with at least one lib present. Unfortunately with boost far down as base dependency I cannot set libs unless risk of interference with boost's autolink feature. Turning it off and linking myself yielded a different error.
It then adds something causing the linker to not find ".obj". This is however invisible in the MSVCs properties dialog. So I rather go with autolink on, as this at least gives me a visible faulty entry.

Maybe this sheds some light on this. Still hope someone has a hint where I could look for ways of removing the faulty obj entry.

Thanks,

Stephan





--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake
Reply | Threaded
Open this post in threaded view
|

Re: Configuration dependent link

Stephan Menzel
Hey all,

I have a few more findings about this before I finally give up and resort my old self made approach: It looks to me like the imported target mechanism is not propagating properties the way it could and probably should. Es specially not like it is described here: https://cmake.org/cmake/help/v3.4/command/target_link_libraries.html

As an example consider the following example in which I try to create an imported target out of boost, taking the FindBoost Module as import:

set(BOOST_REQUIRED_COMPONENTS
    atomic
    chrono
    date_time
    filesystem
    iostreams
    log
    math_tr1
    program_options
    random
    regex
    serialization
    signals
    system
    unit_test_framework
    thread
)

find_package(Boost ${Boost_REQUIRED_VERSION} REQUIRED COMPONENTS
    ${BOOST_REQUIRED_COMPONENTS}
)

add_library(sys::boost SHARED IMPORTED GLOBAL)

function(add_boost_imported_target component_name)
    if (NOT DEFINED component_name)
        message(SEND_ERROR "Error, the variable 'component_name' is not defined!")
    else()
        boost_target_name(${component_name} target prefix)
       
        add_library(${target} SHARED IMPORTED GLOBAL)

        set_property(TARGET ${target} PROPERTY INTERFACE_LINK_LIBRARIES_DEBUG ${${prefix}_LIBRARY_DEBUG})
        set_property(TARGET ${target} PROPERTY INTERFACE_LINK_LIBRARIES_RELEASE ${${prefix}_LIBRARY_RELEASE})
        set_property(TARGET ${target} PROPERTY INTERFACE_LINK_LIBRARIES_RELWITHDEBINFO ${${prefix}_LIBRARY_RELEASE})
        set_property(TARGET ${target} PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIR})
        set_property(TARGET ${target} PROPERTY INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIR})
       
        target_link_libraries(sys::boost INTERFACE ${target})
    endif()
endfunction(add_boost_imported_target)

foreach (comp ${BOOST_REQUIRED_COMPONENTS})
    add_boost_imported_target(${comp})
endforeach()


Now as far as I can tell this should give me an IMPORTED target called
sys::boost and create a number of sub-targets for each boost components. This appeared necessary to me as there is no way to have one sys::boost with multiple IMPLIBs on it.

Alas, the target doesn't contain any libs at all:

get_target_property(libs sys::boost LINK_LIBRARIES_DEBUG)
message ("boost link:  ${libs}")

will yield empty output. However the manual clearly states that

"Usage requirements are propagated by reading the INTERFACE_ variants of target properties from dependencies and appending the values to the non-INTERFACE_ variants of the operand."

So INTERFACE_LINK_LIBRARIES_DEBUG of, say, sys::boost_atomic should appear as LINK_LIBRARIES_DEBUG of sys::boost_atomic. Which is not the case and in my opinion a bug.

Which means I cannot have imported targets depending on each other (and propagating their libs) to create a structure with multiple implibs, nor can I put multiple implibs in one imported target. At least not for MSVC. As much as I liked the approach of IMPORTED libs, this forces me to go back to the self made scripts.
I just wanted to put it out here in case anybody attempts the same.

Cheers,
Stephan



--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake