Having CMake build, but not install, an external project - build

I'm trying to use this external project in a CMake project of mine; the external project is also a CMake project.
Now, the external project produces static libraries and a bunch of headers; but - I don't want those to be installed anywhere, I just need them to build stuff as part of my main project (and the files are not necessary after build and/or install of the main project).
How do I get CMake to "fetch, build, but not install" an external project? I was thinking I might hackishly do this by forcing an empty install command, but I'm sure there's a better, more elegant way.

As mentioned by #Tsyvarev, to skip the install of an external project, you can simply pass the argument INSTALL_COMMAND "", this is definitively the recommended approach.
For example:
ExternalProject_Add(Foo
GIT_REPOSITORY "git://github.com/Foo/Foo"
GIT_TAG "123456"
SOURCE_DIR ${CMAKE_BINARY_DIR}/Foo
BINARY_DIR ${CMAKE_BINARY_DIR}/Foo-build
CMAKE_CACHE_ARGS
-DFOO_ENABLE_BAR:BOOL=1
INSTALL_COMMAND ""
)
Then you would configured the dependent external project with -DFoo_DIR:PATH=${CMAKE_BINARY_DIR}/Foo so that find_package(Foo REQUIRED) works as excepted. For this to work, the assumption is that the external project provide a working config file for the build tree.
To learn more about config files, see Correct way to use third-party libraries in cmake project

Related

cmake doesn't recognize dependency on static lz4 [duplicate]

I have a program that depends on an external library (SDL for example). I want CMake to take care of that dependency for me, so I was looking into FetchContent. As far as I understand, this module simply downloads the source code so that information on the external library is available at configure time. For example:
include(FetchContent)
FetchContent_Declare(sdl
GIT_REPOSITORY <...>
)
FetchContent_GetProperties(sdl)
# sdl_POPULATED, sdl_SOURCE_DIR and sdl_BINARY_DIR are ready now
if(NOT sdl_POPULATED)
FetchContent_Populate(sdl)
endif()
At some point, however, I want to build that source code and link it to my main executable. How to do it the "modern CMake way"?
The recommended way to build external libraries from source as part of your build depends on what the external lib provides build-wise.
External lib builds with cmake
If the external lib builds with cmake then you could add the lib to your build via a add_subdirectory(${libname_SOURCE_DIR}) call. That way cmake will build the external lib as a subfolder ("subproject"). The CMakeLists.txt file of the external lib will have some add_library(ext_lib_name ...) statements in it. In order to then use the external lib in your targets (an application or library that depends on the external lib) you can simply call target_link_libraries(your_application <PRIVATE|PUBLIC|INTERFACE> ext_lib_name) https://cmake.org/cmake/help/latest/command/target_link_libraries.html
I had a quick look at this github repo https://github.com/rantoniello/sdl - (let me know if you are referring to another library) and it actually looks like it is building with cmake and that it allows clients to statically or dynamically link against it: https://github.com/rantoniello/sdl/blob/master/CMakeLists.txt#L1688-L1740
So, ideally your applicaiton should be able to do
add_executable(myapp ...)
target_link_libraries(myapp PRIVATE SDL2-static) // Statically link againt SDL2
Due to their CMakeLists.txt file the SDL2-static comes with properties (include directories, linker flags/commands) that will automatically propergate to myapp.
External lib does not build with cmake
If a external lib doesn't build with cmake then one can try to use add_custom_target https://cmake.org/cmake/help/latest/command/add_custom_target.html to build the library. Something along the lines of:
add_custom_target(myExternalTarget COMMAND <invoke the repo's build system>)
You'd then need to set the target properties that are important for clients yourself via the the proper cmake functions set_target_properties, target_include_directories ... A great writeup how to get started with these kinds of things: https://pabloariasal.github.io/2018/02/19/its-time-to-do-cmake-right/

How to setup a new C++ project with restbed?

I am trying to write a web service in C++ (I am very new to the language) using restbed for HTTP handling. Both projects seem to be using cmake to do build configuration and dependency management, so I figured I would do so as well. But I am confused about how to go about it.
Here is my minimal CMakeLists.txt
cmake_minimum_required(VERSION 3.7)
project(WebService)
set (WebService_VERSION_MAJOR 1)
set (WebService_VERSION_MAJOR 0)
set(CMAKE_CXX_STANDARD 11)
add_executable(${PROJECT_NAME} main.cpp)
I understand that there are a few ways to add dependencies in cmake. I have tried doing things like find_package(restbed), but obviously it doesn't know where to find the package I want and keeps asking for extra cmake files to help it. I am not sure where I am supposed to find these. Am I supposed to write one myself?
I have tried using the ExternalProject_Add directive. I added the following.
ExternalProject_Add(
restbed
GIT_REPOSITORY "git#github.com:Corvusoft/restbed.git"
SOURCE_DIR "${CMAKE_SOURCE_DIR}/deps/restbed"
CMAKE_ARGS -DBUILD_SSL=OFF
)
set (restbed_INCLUDE ${CMAKE_SOURCE_DIR}/deps/restbed/distribution/include/)
set (restbed_LIB ${CMAKE_SOURCE_DIR}/deps/restbed/distribution/library/librestbed.a)
add_dependencies(${PROJECT_NAME} restbed)
include_directories(${restbed_INCLUDE})
target_link_libraries(${PROJECT_NAME} ${restbed_LIB})
The problem I am having is that apparently all the steps for setting up an external project are performed during the build and not during cmake configuration. This means that every external project rebuilds and reinstalls everything every time I run make. My service is small and this seems very wasteful.
Is there a better way to deal with dependencies? Is there an easier tool than cmake? Is there something for C++ that is similar to Rust's cargo or Haskell's stack maybe?

Avoid path problems at runtime when using cmake's ExternalProject_Add

I'm pretty new to cmake, but I am stuck with an odd behaviour that I'd like to understand and overcome.
I'm creating an executable that uses the Paho MQTT C library. The content of this executable is irrelevant, let's say it just connects to a broker for now, nothing fancy.
To compile my program, I use cmake with a CMakeLists.txt file, which does a few things:
use an ExternalProject block to pull the MQTT C lib from Github
declare the executables and the linked libs
Here it is :
project(myproject)
include(ExternalProject)
########## CMAKE VERSION AND FLAGS ##########
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
########## MQTT EXTERNAL LIB ##########
set(MQTT_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/mqtt)
ExternalProject_Add(
project_mqtt
GIT_REPOSITORY https://github.com/eclipse/paho.mqtt.c
GIT_TAG v1.2.0
PREFIX ${MQTT_BUILD_DIR}
CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}"
)
add_library(mqtt STATIC IMPORTED)
set(MQTT_LIB ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/lib/libpaho-mqtt3a.1.2.0.dylib)
set_property(TARGET mqtt PROPERTY IMPORTED_LOCATION ${MQTT_LIB})
add_dependencies(mqtt project_mqtt)
include_directories(${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/include)
link_directories(${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/lib)
########## EXECUTABLE ##########
add_executable(myproject ../src/main.cpp)
target_link_libraries(myproject mqtt)
Note that in the file I especially compile for Mac and I hardcoded the .dylib suffix but this is not a problem here
My folder structure is as follows :
myproject/
-- CMakeLists.txt
-- bin/
-- build/
-- src/
- main.cpp
My compilation workflow is very standard : cd build && cmake ../ && make.
My sources are in /src, I build everything in /build and my executable is written in /bin. The *.dylib are explicitely built locally in the project folder (in bin/lib) since I don't want to install them in the system (I want my project to be self-contained in a way).
It works well (I mean, it compiles).
But when I run the program, I get a dyld: Library not loaded: libpaho-mqtt3a.1.dylib error.
.. which is quite "normal", because my lib has been installed in bin/lib and my executable searches for them in its own folder (which is bin/). So for instance if I run : cd bin/lib && ../myproject it works perfectly well.
So, now here are my questions :
[Philosophically,] Is it a good way of doing this ? I want to use this external lib but I don't want to include the Paho lib sources in my code obviously, so I though ExternalProject was a good way to go. It compiles the lib at compile time before compiling my project and I find the process quite handy. I looked for a "package manager" for C++ but there does not seem to be a strong consensus (I'm looking at something like *composer* or *npm* for web apps), so I did not go this route.
Why, oh why, does my executable look for the library file in its own directory ./ ? Can I change that ? Is it some cmake configuration that I missed ? I guess that I could just use a cmake custom command to copy the library file into the /bin folder, but this looks like a hack to me. Isn't it ?
To be honest, I'd like to have no "path dependencies" in my executable, it's to say that the executable, when compiled on a specific system, could be put anywhere on this system and work flawlessly afterwards. I understand that means that the compiled Paho MQTT lib should be statically in my executable, but I wonder how to do that (or even what that really means, in fact). Is it possible ?
I may miss a whole part of how the C/C++ compile and external lib workflow works but I think I'm close to something quite robust, it's just this lib path thing at runtime that I would like to properly understand and fix.
I'm really open to suggestions on this
Thanks a lot !

Depending on the INSTALL target of a CMake External Project

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.

Compile other external libraries (without CMakeLists.txt) with CMake

short -- Is it possible to build a external binary/library out of a project with CMake, when the binary/library only has a makefile given?
So you have your own project, a bunch of CMakeLists.txt in your src-tree and this external library with its source-files. Your sources depend on this library and some binaries/libraries want to link against it. How would one compile this external library if it has only a makefile or Visual Studio project file and no given CMakeLists.txt?
Is there a chance to call configure/make out of CMake? Or run an batch-compile with VS under Windows? Or anything else?
Thanks for your help with this one...
It sounds like you want CMake's external project. I have worked with it quite extensively when developing the Titan build system, and it provides a way of managing multiple out of source builds. You can include ExternalProject, and then something like the following would build the project:
ExternalProject_Add(Qt
DOWNLOAD_DIR ${CMAKE_CURRENT_BINARY_DIR}
URL ${qt_file}
UPDATE_COMMAND ""
SOURCE_DIR ${qt_source}
BUILD_IN_SOURCE 1
CONFIGURE_COMMAND ${qt_configure}
BUILD_COMMAND ${qt_build}
INSTALL_COMMAND "${qt_install}"
)
There is an article about external projects in the October 2009 issue of the source too. Using external project you can call any make commands available on the host system, we build Qt using their supplied configure command on Windows, Mac and Linux.