I have a project which depends on the Boost library (and others). I created a CMakeLists to automatically download and compile dependencies with ExternalProject_Add.
I want to support multi-configuration (Release and Debug). So, for my other libraries I defined a CMAKE_BUILD_TYPE at the beginning of my CMakeLists. I propagate it by dependencies with -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} in the ExternalProject_Add command.
It works well on Windows and Linux.
For Boost however, based on the configuration I need to compile with variant=debug or variant=release. I created a if(${CMAKE_BUILD_TYPE) MATCHES Debug) statement and set the variant based on that requirement.
For Linux this works well but on Windows it works only if I change the CMAKE_BUILD_TYPE variable during the cmake. When I try to change the configuration in VS it doesn't change the CMAKE_BUILD_TYPE variable.
Is it possible to detect the configuration selected in VS in my CMakeLists ?
Thank you.
#-----------------------------------------------------------------------------
# Boost
#-----------------------------------------------------------------------------
message(STATUS "Installing Boost library.")
set(BOOST_BOOTSTRAP_COMMAND)
if(WIN32)
set(BOOST_BOOTSTRAP_COMMAND bootstrap.bat)
set(BOOST_B2_COMMAND b2.exe)
elseif(UNIX )
set(BOOST_BOOTSTRAP_COMMAND ./bootstrap.sh)
set(BOOST_B2_COMMAND ./b2)
else()
# MacOSX
set(BOOST_BOOTSTRAP_COMMAND ./bootstrap.sh)
set(BOOST_B2_COMMAND ./b2)
endif()
set(BOOST_BUILD_TYPE variant=release)
if (${CMAKE_BUILD_TYPE} MATCHES Debug)
set(BOOST_BUILD_TYPE variant=debug)
endif(${CMAKE_BUILD_TYPE} MATCHES Debug)
set(BOOST_INSTALL_DIR ${PROJECT_BINARY_DIR}/deps/boost-install)
ExternalProject_Add(boost
SOURCE_DIR "${PROJECT_BINARY_DIR}/deps/boost"
BUILD_IN_SOURCE 1
GIT_REPOSITORY "${git_protocol}://github.com/boostorg/boost"
GIT_TAG "5ec478a570bdc71c5d4854e7165a8b3f4fa82ad9"
CONFIGURE_COMMAND ${BOOST_BOOTSTRAP_COMMAND}
BUILD_COMMAND ${BOOST_B2_COMMAND} headers COMMAND ${BOOST_B2_COMMAND} install
link=static
${BOOST_BUILD_TYPE}
--prefix=${BOOST_INSTALL_DIR}
--with-filesystem
--with-program_options
--with-system
--with-thread
-j8
INSTALL_COMMAND ""
)
When CMake is being run, it is not possible to know what build type the user will choose at build time when using a multi-configuration generator (Visual Studio or Xcode). The user makes that choice after CMake has finished the configure and generate stage (i.e. after the cmake command completes). The user can build more than one build type too, so there is not a concept of a single build type with those generators.
One option may be to define a custom command which does the relevant build of boost as a build-time task rather than using ExternalProject. This is probably the closest to what you seem to be wanting to achieve. You can still have the source downloaded at configure time during the CMake run, a technique that is mentioned here with googletest as the example. That answer provides a link to an article which goes into more detail as well as a fully general implementation available on github which would potentially be suitable for your situation.
Related
I am using Cmake to build my C++ project and I am using conan to maintain my boost libraries.
My conanfile.txt is very simple,
[requires]
boost/1.71.0#conan/stable
[generators]
cmake
When I install boost from conan, I can use following commands,
conan install ..
Or,
conan install .. -s build_type=Debug
Both command install bost libraries in two different folders in my C:/.conan foler.
In CMakeLists.txt I have following lines to find boost
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_DEBUG_LIBS ON)
set(Boost_USE_RELEASE_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost REQUIRED COMPONENTS program_options)
However, When I configure cmake,
cmake .. -DBoost_DEBUG=ON
it doesn't find the debug version of boost library. It always shows that it it pointing to release version. So naturally, the following command works,
cmake --build . --config Release
However, following command failed,
cmake --build . --config Debug
as it is still trying to link ot release version.
How can I reconfigure my cmake and conan setup so that I can easily switch between debug and release version? Any suggestion?
Cheers,
M
If you want to consume the libraries with find_package(Boost) you need to generate the corresponding files. Use the cmake_find_package generator (you need different folders for Debug and Release) or the cmake_find_package_multi one (both Debug and Release can live in the same folder). Just add them to your conanfile.txt:
[requires]
boost/1.71.0
[generators]
cmake_find_package_multi
Now, you can call CMake from the command line, but you need to tell where to find the generated FindBoost.cmake files (or the BoostConfig.cmake if you are using the multi generator):
cmake .. -DCMAKE_MODULE_PATH=<path/to/dir/with/findcmake> [...more arguments]
Take into account that, if you are not using the cmake generator and the call to conan_basic_setup, you need to be sure that the configuration used to build the Boost binaries you are getting from Conan matches the one you are using to build your project (otherwise you might get linker errors).
If you aren't already I'd recommend using https://github.com/conan-io/cmake-conan it makes life easier in some areas.
Unless you want to be able to build your project without conan there is no real need to use find_package with conan. See https://docs.conan.io/en/latest/integrations/build_system/cmake/cmake_generator.html. You can either use:
conan_basic_setup()
target_link_libraries(<target> ${CONAN_LIBS})
Or:
conan_basic_setup(TARGETS)
target_link_libraries(<target> CONAN_PKG::boost)
If you want to use find_package you need to use the cmake_find_package generator and add the following to your conanfile.txt:
[generators]
cmake_find_package
cmake_paths
I am trying to download precompiled binaries from a webserver within cmake. So is there something similar like ExternalProject_Add but without the actual build step?
The downloaded file is a tar.gz and would need to be extracted. It contains /bin /include and /lib and especially also /lib/cmake which should be found by the calling CMake project.
If I ExternalProject_Add results in an error that the build folder does not contain a CMakeLists.txt file.
The minium example is something like
cmake_minimum_required(VERSION 3.0)
project(Foo)
if (TARGET Bar)
message(STATUS "Foo and Bar are unified - how beautiful is that")
else()
include (ExternalProject)
ExternalProject_Add ( Bar # <------ This doesn't work
URL "http://THE-INTERNET"
)
endif()
find_package(Bar REQUIRED)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} Bar::Bar)
Ok, I figured out two things:
The command CONFIGURE_COMMAND "" can be provided to ExternalProject to not build anything.
The find_package() will never work like this. The ExternalProject is executed during compile time, while the find_package needs to find the target at configure time.
In the meantime I found this: https://cmake.org/cmake/help/latest/module/FetchContent.html - this might help to get targets ready during configure time and not just during compile time. However it is only supported from CMake 3.11 on :(
I've built and make installed opencv on my mac with SHARED_LIBS.
I want to be able to choose for each project if I built with or without shared libs.
When I compile an additional OpenCV build with -DBUILD_SHARED_LIBS=OFF how can I reference it in my project's CMakeLists and chose the build type I want?
I have the source with shared libs in my ~/opencv and I've already compiled it in ~/opencv/build followed by make install.
When I create another dir like ~/opencv/static_build how would I have to adapt my CMakeLists in order to make a static build app? So far I've used:
find_package( OpenCV REQUIRED )
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(test ${OpenCV_LIBS})
But if I'm not mistaken, these lines all depend variables which have been added to cmake during my inital make install.
It works by configuring a different install location with the cmake flag -D CMAKE_INSTALL_PREFIX for each build and make install will then install them to their respective locations.
In order to distinguish between the specific builds and to allow cmake to find the library if it not in its path, one has to add the following line to the project's CMakeLists.txt:
set(OpenCV_DIR /path/to/build/lib/cmake)
before:
find_package( OpenCV REQUIRED )
i would like to build TBB to use it in another CMake project. I tried to build TBB from the Github source using the makefile (upgraded with VisualStudio 2015). This failed due to a mysterious error:
LINK : fatal error LNK1181: cannot open input file 'opencv_core300.lib'
Where does this error could originate from?
My second try was is to build TBB using another repository that allows a build using CMake. This build produces an tbb.lib, tbb.dll, etc. file.
Now I am stuck how to incorporate is in my other cmake files. There is no TBBConfig.cmake or similar.
My CMakeLists.txt for my project looks like this:
cmake_minimum_required(VERSION 3.10)
project(IntrafraktionelleRegistrierung)
find_package(ITK REQUIRED
COMPONENTS
ITKRegistrationCommon
ITKRegistrationMethodsv4
)
include(${ITK_USE_FILE})
set(SRC
${CMAKE_PROJECT_NAME}.cxx
)
if (DEFINED ENV{TBBROOT})
message(STATUS "TBBROOT: $ENV{TBBROOT}")
else()
message(STATUS "TBBROOT not defined!")
endif()
find_package(TBB REQUIRED)
add_executable(${CMAKE_PROJECT_NAME} ${SRC})
target_link_libraries( ${CMAKE_PROJECT_NAME}
${ITK_LIBRARIES}
tbb
)'
TBBROOT is the build directory of tbb. The FindTBB.cmake I have available is borrowed from here and copied to the modules directory of cmake.
The latest version of the binaries of TBB have a CMake folder with TBBConfig.cmake inside. I used this to link the TBB to my project but somehow I ended up by an error stating: "tbb-NOTFOUND.obj cannot be found". (This way is still under investigation.
Has someone used this repository to configure and build a cmake project?
About CMake related questions
Basically you have two options:
Integration of pre-built TBB binaries into your project
You can use the binaries of TBB (just as you did) according to the following example. After invocation of find_package(TBB REQUIRED) you will get TBB targets in a format TBB::<component> (e.g. TBB::tbb, TBB::tbbmalloc, etc). Also TBB_IMPORTED_TARGETS variable will contain all imported TBB targets.
So, you need to slightly modify your target_link_libraries:
target_link_libraries( ${CMAKE_PROJECT_NAME}
${ITK_LIBRARIES}
${TBB_IMPORTED_TARGETS}
)
or
target_link_libraries( ${CMAKE_PROJECT_NAME}
${ITK_LIBRARIES}
TBB::tbb
)
Also you can update your find_package if you need only TBB::tbb component in your project: find_package(TBB REQUIRED tbb)
Integration of TBB source code into your project
You can use tbb_build (it is a CMake wrapper using GNU Make on TBB Makefiles), but to run it on Windows under Visual Studio you will need to have GNU Make in your environment.
If you'd like to integrate this TBB (with CMake support) you can use add_subdirectory(<YOUR-TBB-ROOT>) (replace <YOUR-TBB-ROOT> with actual location of TBB) instead of find_package(TBB REQUIRED).
Is there a way to identify dependencies of the installation-step of a target in cmake? Here's my situation:
My goal is to be able to download the source code of this project and build it without first installing the dependencies. In other words, I'd like the dependencies to be recognized and installed prior to trying to build the main target. For example, I'm working on including Leptonica as an external project:
set(leptonica_build "${CMAKE_CURRENT_BINARY_DIR}/leptonica")
ExternalProject_Add(
leptonica
DOWNLOAD_DIR ${download_dir}
BINARY_DIR ${leptonica_build}
GIT_REPOSITORY ${OpenCV_git_repository}
GIT_TAG ${OpenCV_git_tag}
TLS_VERIFY true
CONFIGURE_COMMAND <SOURCE_DIR>/configure --prefix=${DOC_READER_INSTALL_PREFIX}
)
Running the target leptonica correctly builds and installs the library into a temporary directory, making itself available to other targets to consume:
add_dependencies(myProgram leptonica)
find_library(LEPT_LIB lept)
target_link_libraries(myProgram ${LEPT_LIB})
The problem is that, when /tmp is cleared and cmake is first executed with the target of myProgram, liblept.so isn't found because it hasn't yet been installed, and consequently an upstream dependency of myProgram hasn't been met until after make install has been run.
In other words, I'd like the build script to first download and install then dependencies, then try to lookup the location of the libraries needed by downstream build steps. Is this possible to do with cmake or should I be accomplishing this goal some other way?
Build and install leptonica from a separate CMakeLists.txt. Alternatively, you can use the same CMakeLists and selectively enable either the ExternalProject-section or the main section of your CMakeLists with a control variable (-DMYPROJECT_INSTALL_DEPS=1)
You can trigger the configure/build steps of leptonica from shell script, or call cmake from the main CMakeLists with execute_process:
execute_process(
COMMAND ${CMAKE_COMMAND} -H... -B...
COMMAND ${CMAKE_COMMAND} --build ... --target install ...
)
That way the entire configuration/build/install steps will get executed in the configuration step of your main project.