Vero
Vero

Reputation: 331

How to idiomatically add external library dependencies that use git and CMake to a git and CMake project?

I would like to know how to add external libraries into my project. Is there a standard way of doing so?

The way I do it and that I don't like is:

  1. Have a folder called vendors where I add submodules e.g. boost, openssl...
  2. I build the external libraries (as they come with a cmake to build in general).
  3. I add a premake (I could have used a cmake) to each external library and I configure so I can see the project in VS as well as the cpp and the hpp files.

I don't like this because I do copy the binaries of the external libraries manually, hence if I delete the bin folder I can't build my solution just by clicking build but I have to build the external libraries first using there cmake and then I copy the binaries manually to the bin/ folder of my solution.

Could you please give me a "standard" way I can do this? I feel like there could be better ways by just using to the max the CMake that comes with the external library. Also, I don't like changing the external libs too much, I just want to be able to update them anytime and everything works without me touching stuff.

How can this be done?

Upvotes: 4

Views: 3406

Answers (1)

starball
starball

Reputation: 51274

One approach is to use CMake's FetchContent functionality.

The FetchContent module allows specifying Git repositories of CMake projects to fetch at configure time. The default setting assumes that that repository has a CMakeLists.txt file at the repo's root directory. It clones the repo to a default (but configurable) location, and then just calls add_subdirectory() on the cloned directory.

You can read about how to use it in the reference documentation, and you can read about how that approach compares with some other CMake-supported approaches for using dependencies in the official Using Dependencies Guide. Do brace yourself when reading the reference docs, though. They're not designed to be like a beginner-friendly tutorial, and since FetchContent is built upon another module called ExternalProject, some of the docs for FetchContent just point you to go read sections from the ExternalProject docs. Be prepared to do a bit of digging.

Here's a basic example I used in a project at one point.

include(FetchContent)

FetchContent_Declare(
  range-v3
  GIT_REPOSITORY [email protected]:ericniebler/range-v3.git
  GIT_TAG "0.12.0" # https://github.com/ericniebler/range-v3/releases
  GIT_SHALLOW TRUE
  GIT_PROGRESS ON
  SYSTEM
)
# more `FetchContent_Declare`s (if any). They should all be declared
# before any calls to FetchContent_Make_available (see docs for why).

FetchContent_MakeAvailable(range-v3)
# more `FetchContent_MakeAvailable`s (if any).

FetchContent in some ways is designed to be a little bit "low level". It has a lot of machinery and customization points. If your project is super simple, you might find it useful to try out a CMake-external wrapper module called "CPM" (CMake Package Manager) that attempts to cater to sensible defaults for more common, simple use-cases.

If you use FetchContent or CPM, be aware that since they eventually just call add_subdirectory, you might need to take some steps to avoid naming conflicts of target names and CMake variable names between your CMake configs and the CMake configs of the dependencies you pull in. For more info, see How can I avoid clashes with targets "imported" with FetchContent_MakeAvailable?.

As others have mentioned, you can also look into using package managers like vcpkg or Conan. I don't know much about those so I can't comment.

If you want some approach comparison, see also How can I compose separate git+CMake projects together for ease of building while allowing mixed build configurations?.

Upvotes: 3

Related Questions