user9601767
user9601767

Reputation: 31

cmake add external already-built library

I would like to add a dependency to a target. This dependency is a precompiled lib. I would like to be able to get a external dependency just by specifing a name like add_dep(libName) in my CMakeLists.txt. The add_dep function should be reusable for different libraries.

I couldn't find any way to do this, only for libs which are compiled during build

how would I pass the target name in a generic form here?

would be fine, but the "consumer" shouldn't have to add inc/lib dirs etc.

Upvotes: 2

Views: 4211

Answers (2)

wu1meng2
wu1meng2

Reputation: 547

CMake gives an excellent tutorial about adding dependencies into a build. The good old find_package() is used to incorporate dependencies that have been built locally (by either CMake or other build systems), while the relatively new (since CMake 3.11) FetchContent is able to download source code with CMake support and build the dependencies within the build folder (more like npm install and package.json for JavaScript).

However, building from sources can be time-consuming, especially for some big libraries, such as Boost, and you may want to first search for locally built libraries before resorting to the source code. The good news is that you can have the best of both worlds by integrating FetchContent and find_package() with the FIND_PACKAGE_ARGS option of FetchContent_Declare(). This allows CMake to try calling find_packge() first to satisfy the dependency, and then build from the source if the target is absent. You can also enforce the build-from-source policy if you want to control the version (or a specific commit) of the dependency with the OVERRIDE_FIND_PACKAGE option.

Here is a small example project covering my frequently used third-party libraries: Eigen and fmt. If you have already built the libraries locally (e.g., via Homebrew on macOS), it will be as fast as using find_package().

Files

Within one folder:

  • CMakeLists.txt
cmake_minimum_required(VERSION 3.11)
set(PROJECT_NAME test)
project(${PROJECT_NAME})

# For FetchContent_Declare() and FetchContent_MakeAvailable()
include(FetchContent)

set(CMAKE_CXX_STANDARD 17)

# Eigen
FetchContent_Declare(Eigen
  GIT_REPOSITORY [email protected]:libeigen/eigen.git
  GIT_TAG 3147391d # Release 3.4.0
  FIND_PACKAGE_ARGS NAMES Eigen3
)

# fmt
FetchContent_Declare(fmt
  GIT_REPOSITORY https://github.com/fmtlib/fmt.git
  GIT_TAG f5e5435 # Release 10.1.1
  FIND_PACKAGE_ARGS NAMES fmt
)

FetchContent_MakeAvailable(Eigen fmt)

add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} Eigen3::Eigen fmt::fmt)
  • main.cpp
#include <Eigen/Dense>
#include <fmt/core.h>
#include <iostream>

int main() {
  // Eigen
  Eigen::Vector3d coords{1.0, 2.0, 3.0};
  std::cout << "Vec = " << coords << std::endl;
  // fmt
  fmt::print("Hello world and!\n");
}

Build

  1. Within the same folder, create a build subfolder:
mkdir build
cd build
  1. Run cmake
cmake ..
  1. Run make
make

Upvotes: 0

user9601767
user9601767

Reputation: 31

Based on Some programmer dude:

In the dir of the external lib CMakeList.txt:

find_library(lib libName dir/to)
add_library(libName SHARED IMPORTED GLOBAL) # GLOBAL -> if outside src tree
set_property(TARGET libName PROPERTY IMPORTED_LOCATION ${lib})
set_property(TARGET libName APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/include)

in the "root" CMakeList.txt:

add_subdirectory("$ENV{COMMON_ROOT}/libs/libName" "$ENV{COMMON_ROOT}/libs/libName") # usage for out of src ref

add target_link_libraries(target libName) to the CMakeLists.txt who needs it.

Upvotes: 1

Related Questions