CMake exports targets with absolute path - c++

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.

Related

Using CMake to create an executable that can run independently on other machines

I’m using LibTorch and OpenCV for a program in Cpp. The compilation and building is done on Linux using CMake. The program builds and runs as expected.
I want to use the executable that CMake created on another Linux machine.
The problem is that I don’t want to install either LibTorch nor OpenCV on the other machine. I’d rather supply the user with a single executable if possible.
How can CMake create a single independent executable?
If making just a single file is irrelevant, how can CMake copy all needed libraries to a single directory?
The current CMake file:
cmake_minimum_required(VERSION 2.8)
project(prediction)
list(APPEND CMAKE_PREFIX_PATH “libtorch”) # the folder where libtorch in found
set(CMAKE_BUILD_TYPE Release)
find_package( OpenCV REQUIRED )
find_package( Torch REQUIRED )
if(NOT Torch_FOUND)
message(FATAL_ERROR “Pytorch Not Found!”)
endif(NOT Torch_FOUND)
message(STATUS “Pytorch status:”)
message(STATUS " libraries: ${TORCH_LIBRARIES}")
message(STATUS “OpenCV library status:”)
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
file(GLOB SOURCES ".h" ".cpp") # Link all headers and sources in root dir
include_directories( ${OpenCV_INCLUDE_DIRS} )
add_executable(entrypoint ${SOURCES})
target_link_libraries(entrypoint ${TORCH_LIBRARIES} ${OpenCV_LIBS})
set_property(TARGET entrypoint PROPERTY CXX_STANDARD 14)
####### EDIT
Thanks for the answers.
Following Phesho_T answer bellow, I got the static compilation of LibTorch, but it won't compile with the set() instruction. It throws C10_LIBRARY NOTFOUND.
I think I'll try to use the shared libraries. How can CMake be instructed to copy the releveant shared libraries to the "build" folder, so I can pack everything in a .zip file and send it to the user.
Like another answer said, you need to link the static libs of Torch and OpenCV in your executable.
There are a few pre-requisites for this:
The two libraries need to have static (.a) libraries installed on your system. If they don't, you may have to manually build them. Steps for this differ between different packages.
You need to tell CMake to search for the static libraries ONLY. This is done via the CMAKE_FIND_LIBRARY_SUFFIXES variable. The chances are the default for this is .so;.a, meaning it will find the shared library first.
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
The fact that you're using variables in your target_link_libraries command, instead of imported libraries (the modern CMake way) makes me think that this should be enough - these variables should expand to full paths to the static libraries, which should then be added to your linker command.
Things are a bit more complicated to explain if imported targets were used, but this might be out-of-scope for this question.
Try it out and let us know how you get on.
To create a single executable you need to statically link the dependencies into your executable. Check your libraries to see if they provide static-libs else you need to recompile libtorch or opencv to make static libraries.

Cmake FindBoost.cmake MinGW-W64: searching for library with incorrect name

I have built Boost 1.68 (using instructions from https://gist.github.com/sim642/29caef3cc8afaa273ce6, and adding link=static,shared to the b2 command line to also build shared libraries.)
The libraries appear to build correctly, and I have set the BOOST_INCLUDEDIR and BOOST_LIBRARYDIR environment variables correctly.
However, when I add the following to a CMakeLists.txt:
find_package(Boost REQUIRED COMPONENTS system context coroutine thread random REQUIRED)
and generate with MinGW Makefiles, I get the following error:
CMake Error at C:/Users/pbelanger/AppData/Local/JetBrains/Toolbox/apps/CLion/ch-0/182.4129.15/bin/cmake/win/share/cmake-3.12/Modules/FindBoost.cmake:2044 (message):
Unable to find the requested Boost libraries.
Boost version: 1.68.0
Boost include path: C:/boost/install/include/boost-1_68
Could not find the following static Boost libraries:
boost_system
boost_context
boost_coroutine
boost_thread
boost_random
Some (but not all) of the required Boost libraries were found. You may
need to install these additional Boost libraries. Alternatively, set
BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT
to the location of Boost.
I have placed the output of adding set(Boost_DEBUG ON) before the find_package line here: https://pastebin.com/yRd5DPt4
According to the debug output, the find script is searching in the correct directory (c:\boost\install\lib), but is not finding the boost libraries since they have a different naming scheme. For example, the system library is named libboost_system-mgw81-mt-x64-1_68.dll, but the find script is passing he library name boost_system-mgw81-mt-1_68 to CMake's find_library. Notice that the addressing model (-x64)is not listed in the latter name.
My question is whether this is an issue with Boost, or the findCMake script? Can this be fixed by setting a specific cmake variable before the findCMake script?
After hours of research, the answer given by Paul Belanger saved my day.
Digging a bit more in the codebase, they added a new option to manage exactly this case, so with the latest version of CMAKE you can add the following option:
set (Boost_ARCHITECTURE "-x64")
Source: https://github.com/Kitware/CMake/commit/1e08b625c291e0bb57d253b6656e812dc8848bd8#diff-555801259d7df67368f7deab1f9deacd
Looking at the source of FindBoost.cmake, line 1478,
the script looks at the value of CMAKE_CXX_COMPILER_ARCHITECTURE_ID in order
to build the correct architecture tag. However, on my compiler (MinGW-W64 8.1
64-bit), this string is empty. Therefore, the architecture tag is omitted.
I have to set the value of this variable manually by putting the following
before my find_package line:
if(WIN32 AND "x${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "x")
message(WARNING "WIN32 compiler does not specify CMAKE_CXX_COMPILER_ARCHITECTURE_ID -- filling in manually")
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(CMAKE_CXX_COMPILER_ARCHITECTURE_ID "x64")
else()
set(CMAKE_CXX_COMPILER_ARCHITECTURE_ID "x86")
endif()
message(STATUS "Compiler architecture: ${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}")
endif()
# now we should be able to find boost correctly.
find_package(Boost REQUIRED COMPONENTS system context coroutine thread random REQUIRED)
This makes the find_package work correctly.

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

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

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.

C++ How to run programs in Clion when you need to include OpenGL libraries?

Hello I need to work with OpenGL and want to create my project in Clion. But Clion cannot compile and run my projects because of the libraries I need to include. I can create my own makefile and run the program in terminal, but I want to do it in the IDE. How can I make this happen?
First make sure you installed all libraries correctly using the compiler you configured in clion/cmake. Assuminf you have a fresh CMakeLists.txt like
cmake_minimum_required(VERSION 3.3.2)
project(MyGL CPP)
add_executable(demo-run main.cpp)
For linking your libraries you need two things. First tell the compiler where to find the include files and second which libraries to link. You could just hard code you local installation like
target_link_libraries(demo-run path/to/glfw.lib path/to/opengl.lib path/to/jpeg.lib ...)
target_include_directories(demo-run PRIVATE path/to/glfw/include path/to/opengl/include path/to/jpeg/include ...)
however this is not very portable and if you want to work with another compiler or on another machine your project file will fail. Instead you can use the package system of cmake
find_package(PkgConfig REQUIRED)
pkg_search_module(GLFW REQUIRED glfw3)
find_package(JPEG REQUIRED)
find_package(GLEW REQUIRED)
find_package (OpenGL REQUIRED)
find_package (GLM REQUIRED)
target_link_libraries(demo-run ${GLFW_LIBRARIES} ${GLEW_LIBRARIES} ${JPEG_LIBRARIES} ${OPENGL_LIBRARIES})
target_include_directories(demo-run PRIVATE ${GLFW_INCLUDE_DIRS} ${GLEW_INCLUDE_DIR} ${JPEG_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR} ${GLM_INCLUDE_DIR})
The glfw part is a bit tricky and works only on linux i guess see http://www.glfw.org/docs/3.0/build.html.
This code is not tested at all and you may need to specify some enviroment variables so cmake can find the packages or provide additional find scripts like https://github.com/lighttransport/nanogi/blob/master/cmake/FindGLM.cmake.
I would recommend to use the CMake build tool which does the work generating Makefiles for you and is also directly supported by clion. When you open the directory containing a CMakeLists.txt (CMake Project File) with clion, it should be automatically be loaded and compiled (if not just hit build)
A very simple example CMake project would look like this
cmake_minimum_required (VERSION 2.8.9)
project (OpenGl-Stuff)
include_directories(src)
add_executable(your-binary src/your-code.c src/your-code.h)
target_link_libraries(your-binary opengl)
# target_link_libraries will search for libopengl on standard system paths,
# maybe the library is not called libopengl, then you have to adjust the name above
this cmake project will generate the binary for you and link it against opengl