How can I get the source directory from an imported target? - cmake

I'm working on a C++ game library. The game library is exporting a package from it's source tree like this:
set(GAMELIB_CONFIG_PATH "lib/cmake/gamelib")
# installation target
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/${GAMELIB_CONFIG_PATH}/gamelibConfig.cmake"
DESTINATION ${GAMELIB_CONFIG_PATH}
)
install(
EXPORT gamelibTargets FILE gamelibTargets.cmake
NAMESPACE gamelib::
DESTINATION ${GAMELIB_CONFIG_PATH}
)
# export package from build directory
export(
EXPORT gamelibTargets
FILE "${CMAKE_CURRENT_BINARY_DIR}/gamelibTargets.cmake"
NAMESPACE gamelib::
)
export(PACKAGE gamelib)
So then I got two choices to consume the game library: I can either install the game library and let other project use it from the installation, or I can import it directly from the built source tree, which makes it convenient to develop the engine while also developing a game.
Game are simply importing the package like that:
find_package(gamelib REQUIRED)
target_link_libraries(game PUBLIC gamelib::gamelib)
Here's my problem: How can I get the source path for an imported cmake package? And how can I get a different path when the package is actually installed? I want to ship predefined assets directly from the game lib instead of copying them manually into games. The game will need to read the files from the game library to load them. So I need thier paths either in the source tree, or in the installed path.
When importing, I have gamelib_DIR defined, but that point to the binary dir.
I am familiar with generator expression to set a different value in different contexts:
target_include_directories(gamelib-common INTERFACE
$<INSTALL_INTERFACE:${GAMELIB_INSTALL_INCLUDE_DIR}>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
)
Can something similar be done with source directory and installed path?

Related

How to access all libraries when use find_package(<package_name>)

I install multiple libraries and export with the same names(inside one component). like bellow
install(
TARGETS sip
EXPORT voip-protocols-config)
install(
TARGETS rtp
EXPORT voip-protocols-config)
install(
EXPORT voip-protocols-config
NAMESPACE voip)
In the App side use find_package(voip REQUIRED COMPONENTS voip-protocols) and then access to these libs but have a way to use some symbols like * or Cmake Generator Expression to list all libs inside the components?
With this approach, the details of the library side can be hidden in the program and for linking libs to app same as bellow:
find_package(voip REQUIRED COMPONENTS voip-protocols)
add_executable(${PROJECT_NAME})
target_link_libraries(${PROJECT_NAME} voip::*)
When export targets (with install(TARGETS .. EXPORT)) CMake doesn't create additional "useful" targets. Instead, you (as a project's developer) are free to add such targets explicitly.
First approach is to create additional INTERFACE target in the project's CMakeLists.txt and install it too:
# Create "all" library
add_library(voip INTERFACE)
# Link the library with those ones, which you want to represent.
target_link_libraries(voip INTERFACE sip rtp <list other targets here>)
# Install library, so it will be accessible to the user of the package
# via name voip::voip.
install(TARGETS voip
EXPORT voip-protocols-config)
The second approach would to add additional INTERFACE IMPORTED target to the he project config script.
It should be noted, that intended way for provide a config script is to write it manualy (or write its template and use configure_package_config_file). As for scripts generated by CMake with install(EXPORT), these files could be included into the handwritten file. CMake describes that process in documentation.
voip-protocols-config.cmake:
# Assume that install(EXPORT) creates file `voip-targets.cmake`
include (${CMAKE_CURRENT_LIST_DIR}/voip-targets.cmake)
# Create "all" library
add_library(voip::voip INTERFACE IMPORTED)
# Link the library with those ones, which you want to represent.
target_link_libraries(voip INTERFACE voip::sip voip::rtp <list other targets here>)
Note, that CMake doesn't automatically select libraries according to COMPONENTS parameter for find_package. It is a project's developer who should process that parameter in the package config script. CMake documentation provides example of such processing.

How to export CMake property and set it differently in install(EXPORT …)

I'm setting up a CMake based build system for an old framework, written in C. It consists of a single binary, some core libraries and many dynamically linked libraries, which are built against the core libraries. All the libraries require a custom code generation step, which generates C code from model files, written in a domain-specific language. The code generator reads the library's own model file as well as those of all dependency libraries.
My goal is to structure those libraries in several CMake projects ("base framework", "extension libraries" and application specific projects), supporting three scenarios (with the same code base):
Including base framework and extension libraries as sub-projects (i.e. git submodules) into an application specific project. In this case, those CMake projects are included via add_subdirectory() and are part of one single CMake project.
Building application specific projects against the base framework's build tree. Public library header files and model files for code generation should be read from the source tree.
This can be achieved by using export(EXPORT foo FILE FooFrameworkConfig.cmake) in the base framework's CMakeLists and find_package(FooFramework) (with an appropriate CMAKE_PREFIX_PATH) to include the CMake properties of the base framework's build targets into the application project.
Building application specific projects against the base framework's install tree (without having the sources available). All required public header files and model files for code generation are copied to the install tree via appropriate install(…) rules.
To include the CMake properties of the base framework's build targets into the application project, I tried to use install(EXPORT foo FILE FooFrameworkConfig.cmake) in the base framework's CMakeLists and the already mentioned find_package(FooFramework) (with an appropriate CMAKE_PREFIX_PATH).
To manage the model search paths for the code generator, I introduced a custom CMake property on the library targets (let's call it FOO_MODEL_PATHS). This property contains the paths to the model files of the library itself and all its dependency libraries. I made this custom property exportable via set_property(TARGET ${OV_LIBRARY_NAME} APPEND PROPERTY EXPORT_PROPERTIES FOO_MODEL_PATHS).
Unfortunately, I cannot get it working for the third scenario. In this case, I need this custom property to be set to different values in the install tree export file (generated by install(EXPORT …)) and the base framework's build system. For CMake's internal properties, one can use the $<BUILD_INTERFACE:…> and $<INSTALL_INTERFACE:…> generator expressions for this purpose. However, for custom exported properties, generator expressions are forbidden (see CMake documentation and this commit).
So, how can I manage the code generator's search paths in CMake and share them to the dependent projects via EXPORTs, but fix them in the generated install(EXPORT …) file?

linking shared libraries Scons

Can anybody suggest how to link shared libraries using SCons in this specific case.
I have 2 folder locations currently:
slib/ which contains only static libraries
dlib/ which contains only dynamic libraries
I can only add the prebuilt libraries to slib folder.
dlib folder is reserved for the dynamic libraries i create from source code.
My executable always links against this dlib folder.
Now in my case, I want to add some shared libraries (not built by me) into slib folder but I want those libraries to land in dlib folder so that my executable finds it when linking. In short i want my application (requiring those shared libraries) to use one folder when compiling and different folder when running.
Is there a way in SCons I can regenerate those libraries in a different folder ?
I am not allowed to manually copy from source to destination nor i can use
InstallAs( target = 'XYZ/dlib', source = 'ABC/slib' )

Creating a findable shared library with cmake

I am rewriting libraries from hand-written Makefiles to using cmake. I am getting stuck at the point where I need to library library A from library B.
I can find the libraries using find_package, but when they are being linked cmake complains about not having a rule for building the .so file because it is looking for it in the build directory instead of the installed directory.
This is explained if I look at the /usr/lib/cmake/library/libraryConfigVersion.cmake file, which contains this hardcoded path. This file was created with the following steps:
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/libraryConfigVersion.cmake"
VERSION ${LIBRARY_VERSION}
COMPATIBILITY AnyNewerVersion
)
export(EXPORT libraryTargets
FILE "${CMAKE_CURRENT_BINARY_DIR}/library/libraryConfigVersion.cmake"
NAMESPACE library::
)
(i have replaced my library name with 'library'). How can I get cmake to write the correct path so that I can easily link against my library from other cmake projects?
Command export actually exports build tree. This is explicitely written in the documentation.
For export install tree, use install(TARGETS ... EXPORT) plus install(EXPORT). Both flows are described in documentation for install command.
See also CMake tutorial Exporting and Importing Targets.

cmake "exporting" shared library on windows

I'm writing a small library.
I'd like to build it as shared library and generate "MyLibraryConfig.cmake" file which then can be used by my other projects to find my library.
The only problem I have is to figure out the name/path to file which is used for linking under Windows - there are two files being generated: mylibrary.dll and mylibrary.dll.a.
So I'd like to generate MyLibraryConfig.cmake file with something like:
"set(MYLIBRARY_LIBRARIES /blah/blah/mylibrary.dll.a)"
so then MYLIBRARY_LIBRARIES can be used with target_link_libraries for my other projects.
How can I get name for this linkable file? I'd be nice if the solution was platform independed (returning .so wile on Linux and .dll.a on Windows)
thanks in advance
If you're planning on making your library available to your other projects without installing it then you want the CMake command export. For example:
export(TARGETS MyLib FILE ${CMAKE_SOURCE_DIR}/MyLibraryConfig.cmake)
This creates the file MyLibraryConfig.cmake in the same directory as your top-level CMakeLists.txt, and can just be included in other CMake projects.
If you're planning on installing your library, then you want to make use of install(EXPORT ...) instead:
install(TARGETS MyLib EXPORT MyLibraryConfig
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/static)
install(EXPORT MyLibraryConfig DESTINATION cmake)
This will install the file MyLibraryConfig.cmake to <install path>/cmake, and can then be included by other projects.