target_link_directories for imported targets - cmake

In my project I am using MAP_IMPORTED_CONFIG_FINAL for an external library for a custom configuration FINAL. Is there some working example of how to set the target_link_directories for an imported target for the custom configuration FINAL using cmake.
So here are the steps :
The external library is boost-1.67.0 which I am installing using the following commands for Debug and Release respectively:
.\bootstrap.bat
.\b2 install --prefix=C:\Dev\third-party\vs2017\boost-1.67.0\Debug toolset=msvc-14.1 address-model=64 link=static -j8 variant=debug
.\b2 install --prefix=C:\Dev\third-party\vs2017\boost-1.67.0\Release toolset=msvc-14.1 address-model=64 link=static -j8 variant=release
Here is the example project with following structure
boost-example/
|
+-- main.cpp
|
+-- CMakeLists.txt
|
|
+-- CMake/
| |
| +-- AddConfiguration.cmake
| +-- mpIncludeBoost.cmake
| +-- mpSetupMSVCRuntime.cmake
| +-- SetupConfigurations.cmake
The files are found in this gitlab project: https://gitlab.com/sunayanag/boost-example.
For the sln file generated note that in Visual Studio in the Linker section in Additional Library Directories I get C:/Dev/third-party/boost-1_67_0/install/lib/$(Configuration) which evaluates to C:/Dev/third-party/boost-1_67_0/install/lib/Final but this directory does not exist since Final is not a valid configuration of boost, it should be C:/Dev/third-party/boost-1_67_0/install/lib/Release instead.
I was thinking a way of getting around this would be to use target_link_directories but how do I use this with cmake generator expressions in this case.
Thanks

Related

pkg_config_modules dependency fails because version in "Uncontrolled"

The Problem
I've got a CMakeLists.txt file with this content:
pkg_check_modules(FOO REQUIRED foo>=0.1.0.1)
When I run Cmake v3.17.2 with cmake3 -G Ninja . in that directory:
Checking for module 'foo>=0.1.0.1'
Requested 'foo >= 0.1.0.1' but version of foo is Uncontrolled
Details
This is running inside RHEL7
yum info foo | grep Version returns Version : 0.1.0.1.20200417git602d018
The foo module is created by the team I'm on
The Question
How can I tell CMake what version my foo library is so that it isn't "Uncontrolled"?
In the output of the foo project, inside of the generated lib64 directory, there's a pkgconfig directory which contains foo.pc.
Inside of that file, version info is as follows:
Version: HEAD
Change this to be the intended version. In my case this was automated by the build process of foo, so what was required was to add a git tag for the current version and rebuild.

CMake's find_package does not find library added with add_subdirectory

I'm building a test project to learn libraries zeromq with cppmq, and I want to include both libraries as subdirectories. I currently have the following structure:
|-- CMakeLists.txt
|-- deps
| |-- cppzmq-4.3.0
| | |-- CMakeLists.txt
| | `-- rest of files
| |-- zeromq-4.3.1
| | |-- CMakeLists.txt
| | `-- rest of files
`-- main.cpp
I've tried with the following CMakeLists:
cmake_minimum_required(VERSION 3.14)
project(PruebaZeroMQ)
set(CMAKE_CXX_STANDARD 11)
add_subdirectory(deps/zeromq-4.3.1)
add_subdirectory(deps/cppzmq-4.3.0)
add_executable(PruebaZeroMQ main.cpp)
target_link_libraries(PruebaZeroMQ
libzmq
cppzmq)
When I run cmake, I get the following error:
-- Detected CPPZMQ Version - 4.3.0
-- CMake libzmq package not found, trying again with pkg-config (normal install of zeromq)
CMake Error at deps/cppzmq-4.3.0/CMakeLists.txt:20 (message):
ZeroMQ was not found, neither as a CMake package nor via pkg-config
cppmq depends on zeromq, and looks like it tries to load it using find_package, so I tried to modify CMAKE_MODULE_PATH so it could find the ZeroMQConfig.cmake file, but it fails too, with the same error:
add_subdirectory(deps/zeromq-4.3.1)
list (APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_BINARY_DIR}/deps/zeromq-4.3.1 ")
add_subdirectory(deps/cppzmq-4.3.0)
Is there a way of achieving this? I'd rather not install the libraries system-wide.
After trying to manually find_package, CMake showed the following error message:
Add the installation prefix of "ZeroMQ" to CMAKE_PREFIX_PATH or set
"ZeroMQ_DIR" to a directory containing one of the above files.
So I tried that, using:
set(ZeroMQ_DIR ${CMAKE_CURRENT_BINARY_DIR}/deps/zeromq-4.3.1)
And it worked.

cmake not moving targets to install directory

My project is structured as follows
ProjDir
| - CMakeLists.txt
| - SubDir1
| | - CMakeLists.txt
| | - src
| | - inc
| - SubDir2
| | - CMakeLists.txt
| | - src
| | - inc
I have targets in each subdirectory and the subdirectories are included in the main CMakeLists.txt as follows.
add_subdirectory(${CMAKE_SOURCE_DIR}/SubDir1)
add_subdirectory(${CMAKE_SOURCE_DIR}/SubDir2)
My targets in each subdirectory are installed with the cmake function install. These commands are in the CMakeLists.txt of respective subdirectories and are specified per-target (see this post).
install(TARGETS exe1 DESTINATION ${CMAKE_INSTALL_PREFIX}/bin CONFIGURATIONS Release)
While I'm able to successfully compile, the install command doesn't move the binaries to ${CMAKE_INSTALL_PREFIX}/bin but rather finishes after generated the output:
Install the project...
-- Install configuration: ""
How could I resolve this?
On Linux, default build configuration is empty: neither debug, nor release, etc. It can be easily found from the CMake output:
-- Install configuration: ""
Because your install command is "tagged" with Release configuration, it is not triggered by default (with empty configuration).

CMake Export Package Not Working As Expected

I am working through learning CMake's install commands. I have it pretty much figured out for executables. For libraries there are few additional steps to build and install the required CMake scripts so the library can be used in the following scenarios.
Find and link the library from the local build generated by the current CMake project.
Find and link the library from a common installation location. This is required by 3rd party CMake projects that don't build the library.
I want to build a library called FooBar. FooBar is linked to an executable called App, that is defined in the same CMake project as FooBar.
Here are my CMake files and project structure.
<project-root>
|-app
| |-src
| | |-main.cpp
| |
| |-CMakeLists.txt
|
|-lib
| |-include
| | |-FooBar.h
| |
| |-src
| | |-FooBar.cpp
| |
| |-CMakeLists.txt
|
|-CMakeLists.txt
# File: <project-root>/CMakeLists.txt
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
project(SampleProject VERSION 0.0.1 LANGUAGES CXX)
add_subdirectory(lib)
add_subdirectory(app)
# File: <project-root>/app/CMakeLists.txt
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
set(TARGET_NAME "App")
find_package(FooBar REQUIRED)
set(IMPL_FILES
${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp
)
add_executable(
${TARGET_NAME}
${IMPL_FILES}
)
target_link_libraries(
${TARGET_NAME}
PRIVATE
FooBar
)
install(
TARGETS
${TARGET_NAME}
DESTINATION
bin
)
# File: <project-root>/lib/CMakeLists.txt
set(LIB_NAME FooBar)
set(CMAKE_CXX_VERSION 11)
set(IMPL_FILES
${CMAKE_CURRENT_SOURCE_DIR}/src/Lib.cpp
)
set(PUBLIC_DEFI_FILES
${CMAKE_CURRENT_SOURCE_DIR}/include/Lib.h
)
add_library(
${LIB_NAME}
STATIC
${IMPL_FILES}
)
target_include_directories(
${LIB_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
set_target_properties(
${LIB_NAME}
PROPERTIES
PUBLIC_HEADER
${PUBLIC_DEFI_FILES}
)
install(
TARGETS
${LIB_NAME}
EXPORT
${LIB_NAME}Targets
PUBLIC_HEADER DESTINATION include
ARCHIVE DESTINATION lib
)
install(
EXPORT
${LIB_NAME}Targets
FILE
${LIB_NAME}Config.cmake
DESTINATION
lib/cmake/${LIB_NAME}
)
# I am under the impression these are needed for other targets in the
# current project to be able to use "find_package(FooBar)". I also
# think that "CMAKE_EXPORT_NO_PACKAGE_REGISTRY" needs to not be set.
message(STATUS "CMAKE_EXPORT_NO_PACKAGE_REGISTRY: ${CMAKE_EXPORT_NO_PACKAGE_REGISTRY}")
export(
EXPORT
${LIB_NAME}Targets
FILE
${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}Config.cmake
)
export(PACKAGE ${LIB_NAME})
To generate build files I run
# Clean project directory.
mkdir _build
cd _build
cmake .. -DCMAKE_INSTALL_PREFIX=<project-root>/_dist
and I get the following error.
-- CMAKE_EXPORT_NO_PACKAGE_REGISTRY:
CMake Error at app/CMakeLists.txt:5 (find_package):
By not providing "FindFooBar.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "FooBar", but
CMake did not find one.
Could not find a package configuration file provided by "FooBar" with any
of the following names:
FooBarConfig.cmake
foobar-config.cmake
Add the installation prefix of "FooBar" to CMAKE_PREFIX_PATH or set
"FooBar_DIR" to a directory containing one of the above files. If "FooBar"
provides a separate development package or SDK, be sure it has been
installed.
-- Configuring incomplete, errors occurred!
Running the above command a second time yields the same error message. I should not see that message because these two lines
export(
EXPORT
${LIB_NAME}Targets
FILE
${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}Config.cmake
)
export(PACKAGE ${LIB_NAME})
should generate _build/FooBar/FooBarConfig.cmake and add it to the search path for packages seen by App.
If I remove the app sub-directory, build and install FooBar to _dist, and then re-add app, I do not get the error. Even if I clear out _build and generate build files from scratch, I don't get the error. How is CMake finding my local install config script, but not the one in the build directory? Am I doing something wrong or does anyone have any idea why this might not work?

Invoking make install on a subdirectory before make all

I am working on migrating a C++ project whose configuration currently is a combination of cmake (CMakeLists.txt) and Make (GNUmakefile), to using only cmake. The way it's currently set is:
myproject
| CMakeLists.txt (add_subdirectory(src))
| src/
| apps/
| myapp/
| [myapp source files]
| GNUmakefile
| ...
| libs/
| mylib/
| [mylib source files]
| GNUmakefile
| ...
| common/
| CMakeLists.txt (add_subdirectory(dir1, dir2, dir3...))
| ...
| include/
There are more apps and libs outside of myapp and mylib, but they all build and link in similar ways, so if I have one, I can get all.
The way the project builds right now, there is a script that essentially has 4 lines:
cmake path/to/myproject // with the necessary flags and variables passed
make all DESTDIR=$INSTALL_DIR install
cd src/libs ; make all
cd src/apps ; make all
This works because common, which has no dependencies, builds and installs first (include also gets installed here), then libs - which depends on common - builds, and then apps - which depends on both libs and common - builds.
My problem is, if I replace the GNUmakefiles in libs and apps, I don't know how to change the commands I run in the build script so that cmake and make are interwoven like so:
cmake configures common
make compiles & installs all the cmake targets from common (let's say those are libcommon.so and libcommonutils.so)
cmake configures libs
make compiles & installs all the cmake targets from libs (which uses the libraries from common to produce mylib.a)
cmake configures apps
make compiles & installs all the cmake targets from apps (which uses mylib.a and the common shared libraries)
Installing include will also have to happen at some point, early on, since common depends on the header files inside it.
An alternative solution might also work, of course, but this (interweaving cmake and make calls) is the only one I could think of.
You can use ExternalProject_add for common, libs and apps.
src/CMakeLists.txt:
ExternalProject_add(common
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/common
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/common
# Forward CMAKE_INSTALL_PREFIX to external project.
CMAKE_CACHE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_INSTALL_PREFIX}
)
ExternalProject_add(libs
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libs
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/libs
# Disable *install* step
INSTALL_COMMAND ""
)
ExternalProject_add(apps
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/apps
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/apps
# Disable *install* step
INSTALL_COMMAND ""
)
# Adjust dependencies between components
add_dependencies(libs common)
add_dependencies(apps libs common)
Usage of this script(out-of-source build; in-source build is also supported)
cmake -DCMAKE_INSTALL_PREFIX=<install-dir> <source-dir>
make
is equvalent to the following sequence of commands:
mkdir src/common && cd src/common \
&& cmake -DCMAKE_INSTALL_PREFIX=<install-dir> <source-dir>/src/common && make install
mkdir src/libs && cd src/libs && cmake <source-dir>/src/libs && make all
mkdir src/apps && cd src/apps && cmake <source-dir>/src/apps && make all
Processing of include is not implemented, but you may do that in similar way.