find_package() link path on target for pre-built cross compiled libraries

Hi there,

I am working on converting a embedded project which cross compiles for two different targets, and am trying to convert it to CMake (and also getting x86 host system builds working).

I have got this (somewhat) working, however there are some improvements I want to make for a more robust buildsystem.

The main issue that I have encountered is that we have some pre-built shared libraries which are downloaded before a build. Following how the Makefiles were written, the current way that this works is:

add_executable(init ${FOOBAR_SOURCES})
# below folder contains downloaded
target_link_directories(init PRIVATE ${PROJECT_SOURCE_DIR}/downloaded/lib) 
target_link_libraries(init PRIVATE downloaded)
target_include_directories(init PRIVATE ${PROJECT_SOURCE_DIR}/downloaded/include) is later installed on to the embedded target into /lib/

This seems to work for both the host and target system.

However, I would like to move away from using link_directories, and preferably use an interface target with find_package.

In other words, I was trying to do:

find_package(downloaded REQUIRED)
add_executable(init ${FOOBAR_SOURCES})
target_link_libraries(init PRIVATE downloaded::downloaded)

As expected, this works perfectly on the host system However, also as expected - my init process will crash on startup when trying to load downloaded lib on the system, as it is trying to load it in the same path for which it was compiled.

Does anyone have any thoughts on what the correct way forward for me is? I realize my approach may be in completely the wrong direction here.

After some more experimentation, I am trying to achieve this by changing my find_package for my downloaded library to an INTERFACE library rather than UNKNOWN IMPORTED

In other words, in my FindDownloaded.cmake, I am writing:

add_library(downloaded INTERFACE)
target_link_directories(target INTERFACE "${PROJECT_SOURCE_DIR}/downloaded/lib/")
target_link_libraries(target INTERFACE downloaded)

Which in a hacky way, I think might be achieving some of what I want - but still isn’t ideal.

I couldn’t get this working how I wanted by playing around with CMAKE_FIND_ROOT_PATH.

I’m still wondering though - is there a better way to achieve this than my hack? For example, is there some idiom for install target I can write for that type of thing?

I think you probably want to set the IMPORTED_LOCATION property on the UNKNOWN IMPORTED target:

add_library(downloaded::downloaded UNKNOWN IMPORTED)
    IMPORTED_LOCATION "${downloaddir}/lib/"
    INTERFACE_INCLUDE_DIRECTORIES "${downloaddir}/include")

Thanks for the reply Ben,

Oops! Yep, you’re correct! When trying to cut down my example for brevity, I accidentally forgot to include those lines.

My problem was the shared library path/value as given in readelf -d mybinary:

 Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [../downloaded/lib/]

This (expectantly) doesn’t work for the target as where the library is installed isn’t in exactly the same location as where it is built on the host.

I managed to hack out an ugly temporary solution as given in my last comment, which instead gives me:

 Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: []

Correct me if I’m wrong, but is the correct solution here (rather than this ugly hack), is to “install” these binaries to CMAKE_INSTALL_PREFIX beforehand to a layout which would match how everything would be installed on the target?

Yes, this is how I would do it (during the install step). CMake should be adding enough information to the build tree for it to Just Work.