Integrate pre-compiled libraries into C++ codebase with CMake ExternalProject

628 views Asked by At

I want to integrate CasADi into a CMake-based C++ codebase as an ExternalProject. For this purpose, I would like to use pre-compiled libraries because building from source is not recommended. So far, I have only managed to write the following:

ExternalProject_Add(
  casadi-3.5.5
  URL https://github.com/casadi/casadi/releases/download/3.5.5/casadi-linux-py39-v3.5.5-64bit.tar.gz
  CONFIGURE_COMMAND ""
  BUILD_COMMAND ""
  INSTALL_COMMAND ""
  PREFIX ${CMAKE_BINARY_DIR}/external/casadi)

and I noticed that all the binaries are correctly downloaded in the specified folder. However, I do not know how to link my targets to CasADi, nor how to find the package.

1

There are 1 answers

10
image357 On BEST ANSWER

There is a natural problem with ExternalProject_Add:

ExternalProject_Add executes commands only on build.

Hence, download will not happen at the configure stage of your project which makes it difficult to use find_package, because the files cannot be found during your first configure run.

Take this CMakeLists.txt:

cmake_minimum_required(VERSION 3.21)
project(untitled)

set(CMAKE_CXX_STANDARD 17)

add_executable(untitled main.cpp)

include(ExternalProject)
ExternalProject_Add(
        casadi-3.5.5
        URL https://github.com/casadi/casadi/releases/download/3.5.5/casadi-linux-py39-v3.5.5-64bit.tar.gz
        CONFIGURE_COMMAND ""
        BUILD_COMMAND ""
        INSTALL_COMMAND ""
        PREFIX ${CMAKE_BINARY_DIR}/external/casadi)

find_package(casadi HINTS ${CMAKE_BINARY_DIR}/external/casadi/src/casadi-3.5.5/casadi)

target_link_libraries(untitled casadi)

In order to use it you have to do the following:

  1. Configure your project
mkdir build
cd build
cmake ..
  1. Build (download) casadi-3.5.5
cmake --build . --target casadi-3.5.5
  1. Reconfigure your project, because now find_package will find the needed files
cmake ..
  1. Build your targets
cmake --build .

If you want a one step build, there are ways to get around this problem


Here is an example for the second option, which might be better since FetchContent doesn't have the full functionality of ExternalProject.

  • main.cpp
#include <casadi/casadi.hpp>

int main()
{
    casadi_printf("This works!");
    return 0;
}
  • CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(untitled)

set(CMAKE_CXX_STANDARD 17)

# some default target
add_executable(untitled main.cpp)

# Configure and build external project
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/external)
execute_process(
        COMMAND ${CMAKE_COMMAND} ${CMAKE_SOURCE_DIR}/external
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/external
)
execute_process(
        COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}/external
)

# find and link externals
find_package(casadi REQUIRED HINTS ${CMAKE_BINARY_DIR}/external/external/casadi/src/casadi-3.5.5/casadi)
target_link_libraries(untitled casadi)
  • external/CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(external)

include(ExternalProject)
ExternalProject_Add(
        casadi-3.5.5
        URL https://github.com/casadi/casadi/releases/download/3.5.5/casadi-linux-py39-v3.5.5-64bit.tar.gz
        CONFIGURE_COMMAND ""
        BUILD_COMMAND ""
        INSTALL_COMMAND ""
        PREFIX ${CMAKE_BINARY_DIR}/external/casadi)

The point is to have another cmake project under external/CMakeLists.txt, which gets configured and build via execute_process calls from the main cmake project. Do note, that you can now have find_package(casadi REQUIRED ...) at configure stage, because the download will happen just before.