Include Boost library in C++ cross platform project using CMake - c++

I need to include a Boost library (specifically Context) in a C++ project that uses CMAKE as build management system.
Since, given the source code of the repository, the project needs to be built using cmake and make without any other software or library installation in the target system (unix,windows or whatever), I need to configure Cmake to take the source of Boost from my repository, compile it, and link it to my project without installing Boost library in the target system in a separated step.
Is this feasible?

CMake has a specific module for handling boost` libraries, see FindBoost.
The CMakeLists.txt file normally includes something like this to link to a boost library:
find_package(Boost REQUIRED COMPONENTS context )
if(Boost_FOUND)
target_include_directories(${PROJECT_NAME} PRIVATE ${Boost_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} INTERFACE Boost::context)
endif(Boost_FOUND)
This will just link the boost::context library. You must either build the boost::context lib files as suggested in #Hugo's answer, download them from somewhere like here or use a package manager to install them on linux.
If Context was header only, you would only require:
find_package(Boost REQUIRED COMPONENTS boost)
if(Boost_FOUND)
target_include_directories(${PROJECT_NAME} PRIVATE ${Boost_INCLUDE_DIRS})
endif(Boost_FOUND)
In either case you can include the boost::context files in your project and then set the variables BOOST_ROOT or BOOST_INCLUDEDIR as described in the FindBoost documentation.

Yes, you can use ExternalProject_Add, see the documentation at https://cmake.org/cmake/help/latest/module/ExternalProject.html
Take a look at the link below for an example of use which compiles boost
https://github.com/arnaudgelas/ExternalProject/blob/master/External-Boost.cmake
HTH

Related

What is the use of .cmake files in install function of CMakeLists.txt?

CMakeLists.txt
...
add_library( ${PROJECT_NAME} SHARED src/run_pipeline.cpp )
target_link_libraries( ${PROJECT_NAME} )
install( TARGETS ${PROJECT_NAME} DESTINATION lib )
install( FILES ${PROJECT_NAME}Config.cmake DESTINATION lib/cmake/${PROJECT_NAME} )
That ${PROJECT_NAME}Config.cmake file is:
add_library( pipeline_controller STATIC IMPORTED)
find_library( PIPELINE_CONTROLLER_LIBRARY_PATH pipeline_controller HINTS "${CMAKE_CURRENT_LIST_DIR}/install/lib/")
set_target_properties( pipeline_controller PROPERTIES IMPORTED_LOCATION "${PIPELINE_CONTROLLER_LIBRARY_PATH}")
In which cases do we require a separate .cmake file? What does .cmake provide which CMakeLists.txt doesn't? Why is it used in the above case?
You may find the introductory description here helpful.
The <Package>Config.cmake files are package configuration files. They are useful for providing a minimal set of information about an installed package, so the consumer of the package can easily use it in their CMake project. As a package maintainer of a CMake-based project, you are highly encouraged (and frankly, expected) to provide such a file, as this is the most efficient way for others to integrate your library into their project.
The consumer of your package will typically use find_package to find the installed package:
find_package(SomePackage REQUIRED)
The search procedure for find_package Config Mode will look for one of the following package configuration files to pull SomePackage into a CMake project:
SomePackageConfig.cmake
somepackage-config.cmake
By providing one of these files (as the install command supports), you make it easy for others to use your package in their own CMake project.
Craig Scott, a CMake co-maintainer, gave an in-depth presentation at CppCon 2019 providing a wealth of information about this topic.
<name>Config.cmake or <lower-case-name>-config.cmake files are used by find_package to find the library and its meta information.
When someone wants to link pipeline_controller library in their application or library, it is done by using find_package(pipeline_controller). Internally find_package searches for and uses pipeline_controllerConfig.cmake or pipeline_controller-config.cmake

How do I use cmake to build external libraries as well as my own application?

I am trying to build a cross platform OpenGL application, which means building and including multiple libraries (glfw, glbinding, glm, etc.) Because my application is cross platform, it makes sense to use cmake to generate all the build scripts and not have to muck about with them myself. I am attempting to target Windows and Linux specifically.
A main feature that I need is that the libraries I need are not installed on the host system. Furthermore, they cannot be installed (due to administrative reasons). What I need is to build these libraries and then build my application.
I am mostly working on Windows using Visual Studio 2017, which has cmake support included. Currently, I have attempted to build these libraries myself, however I am having many issues getting find_package to do the right thing.
My directory structure looks like this:
project/
|-src/
|- my sources for my application
|-include/
|- my header files
|-external/
|-glfw-3.2.1/
|-glbinding-2.1.4/
|-glfw-build/
|-glbinidng-build/
So I am attempting to build the external libraries and use them in my application. I am also attempting to follow cmake best practices. My CMakeLists.txt currently looks like this:
cmake_minimum_required(VERSION 3.5)
project(glTestProj)
set(CMAKE_PREFIX_PATH "external/")
find_package(glfw3 3.2 REQUIRED)
find_package(glbinding REQUIRED)
add_executable(glTest src/main.cpp)
target_compile_features(glTest PRIVATE cxx_std_17)
target_compile_options(glTest PRIVATE -Wall -Wextra)
target_link_libraries(
glTest
glfw
glbinding::glbinding
)
The libraries in question (glfw and glbinding) both have instructions on including them via cmake, however I am running into this issue:
CMake Error at CMakeLists.txt:6 (find_package):
By not providing "Findglfw3.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "glfw3", but
CMake did not find one.
Could not find a package configuration file provided by "glfw3" (requested
version 3.2) with any of the following names:
glfw3Config.cmake
glfw3-config.cmake
Add the installation prefix of "glfw3" to CMAKE_PREFIX_PATH or set
"glfw3_DIR" to a directory containing one of the above files. If "glfw3"
provides a separate development package or SDK, be sure it has been
installed.

CMake exports targets with absolute path

I am developing a static library and I am using CMake. This library needs Boost. So I did the following:
set(LIBRARY_NAME "MyLib")
set(LIBRARY_VERSION 1.0.0)
project(${LIBRARY_NAME} VERSION ${LIBRARY_VERSION})
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
find_package(Boost COMPONENTS system filesystem regex thread date_time log log_setup REQUIRED)
include_directories(${Boost_INCLUDE_DIR})
link_directories(${Boost_LIBRARY_DIR})
add_library(${LIBRARY_NAME} STATIC xx.cpp)
target_link_libraries(${LIBRARY_NAME} PUBLIC ${Boost_LIBRARIES})
Everything is fine till now.
Now, I need to make this library install-able. So, I follow this tutorial https://cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html
Everything looks fine on my machine. However, when I moved the installed files (The files that are generated by calling make-install) into another machine and tried to use it using find_package(MyLib), problem raised saying that it could find boost in the in a place supposed to be on my original machine. I dig into the file MyLibTargets.cmake and I saw absolute paths of Boost library!
Why this is happining? how can I prevent this?
If you took the cmake build directory and used it from another machine, this won't work. cmake is not intended to support different platforms from the same working directory.
You need to use out of source builds for this purpose. But once you did an in place build with cmake the directory is burned and out of source builds no longer work for this source tree. You need to delete all cmake temporary files and folders to get the source tree working again in this case.

How to stop cmake add wxjpeg.lib to visual studio project?

I have a project that uses both OpenCv and wxWidgets in a static library. These two libraries have definitions for jpeg and hence are generating conflicts during compilation.
As I am not using jpeg which is inside wxwidget, I would like to remove this library from my application. I tested my application and if I remove this library manually from MSVC poroject, it works well.
In cmake I have this line to add wxwidgets to my project:
set(wxWidgets_CONFIGURATION msvc)
find_package(wxWidgets COMPONENTS core base adv REQUIRED)
include(${wxWidgets_USE_FILE})
How can I instruct cmake not to add wxjpeg.lib to the requested linked libraries?
Based on the documentation to this cmake module (link) I would say that adding
set(wxWidgets_EXCLUDE_COMMON_LIBRARIES TRUE)
before using the find_package command would be enough to exclude wxjpeg.lib. Since this also excludes other common libraries (e.g. png), you may have to explicitly include more in your call to find_package
find_package(wxWidgets COMPONENTS core base adv png REQUIRED)

"No rule to make target" error in cmake when linking to shared library

In Ubuntu, I have downloaded a third-party shared library, mylibrary.so, which I have placed in the directory /home/karnivaurus/Libraries. I have also placed the associated header file, myheader.h, in the directory /home/karnivaurus/Headers. I now want to link to this library in my C++ code, using CMake. Here is my CMakeLists.txt file:
cmake_minimum_required(VERSION 2.0.0)
project(DemoProject)
include_directories(/home/karnivaurus/Headers)
add_executable(demo demo.cpp)
target_link_libraries(demo /home/karnivaurus/Libraries/mylibrary)
However, this gives me the error message:
:-1: error: No rule to make target `/home/karnivaurus/Libraries/mylibrary', needed by `demo'. Stop.
What's going on?
While the other answer posted here is valid, it is out-dated. CMake now provides better solutions for using a pre-built external library in your code. In fact, CMake itself even discourages the use of link_directories() in its documentation.
The target_link_libraries() command takes very specific syntax for linking to an external library. A more modern solution is to create an IMPORTED CMake target for your external library:
add_library(MyExternalLib SHARED IMPORTED)
# Provide the full path to the library, so CMake knows where to find it.
set_target_properties(MyExternalLib PROPERTIES IMPORTED_LOCATION /home/karnivaurus/Libraries/mylibrary.so)
You can then use this imported CMake target later on in your code, and link it to your other targets:
target_link_libraries(demo PRIVATE MyExternalLib)
For other ways to use an external third-party library in your CMake code, see the responses here.
You may use a full path to the static library. To link w/ dynamic one, better to use link_directories() like this:
cmake_minimum_required(VERSION 2.0.0)
project(DemoProject)
include_directories(/home/karnivaurus/Headers)
link_directories(/home/karnivaurus/Libraries)
add_executable(demo demo.cpp)
target_link_libraries(demo mylibrary)
and make sure mylibrary has prefix lib and suffix .so in file name (i.e. full name is /home/karnivaurus/Libraries/libmylibrary.so).
To make you project more flexible, you'd better to write a finder module and avoid hardcode paths like /home/karnivaurus/*