Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CMake: how best to build multiple (optional) subprojects?

Imagine an overall project with several components:

  • basic
  • io
  • web
  • app-a
  • app-b
  • app-c

Now, let's say web depends on io which depends on basic, and all those things are in one repo and have a CMakeLists.txt to build them as shared libraries.

How should I set things up so that I can build the three apps, if each of them is optional and may not be present at build time?

One idea is to have an empty "apps" directory in the main repo and we can clone whichever app repos we want into that. Our main CMakeLists.txt file can use GLOB to find all the app directories and build them (not knowing in advance how many there will be). Issues with this approach include:

  • Apparently CMake doesn't re-glob when you just say make, so if you add a new app you must run cmake again.
  • It imposes a specific structure on the person doing the build.
  • It's not obvious how one could make two clones of a single app and build them both separately against the same library build.

The general concept is like a traditional recursive CMake project, but where the lower-level modules don't necessarily know in advance which higher-level ones will be using them. Yet, I don't want to require the user to install the lower-level libraries in a fixed location (e.g. /usr/local/lib). I do however want a single invocation of make to notice changed dependencies across the entire project, so that if I'm building an app but have changed one of the low-level libraries, everything will recompile appropriately.

like image 452
John Zwinck Avatar asked Jun 23 '11 19:06

John Zwinck


4 Answers

My first thought was to use the CMake import/export target feature.

Have a CMakeLists.txt for basic, io and web and one CMakeLists.txt that references those. You could then use the CMake export feature to export those targets and the application projects could then import the CMake targets.

When you build the library project first the application projects should be able to find the compiled libraries automatically (without the libraries having to be installed to /usr/local/lib) otherwise one can always set up the proper CMake variable to indicate the correct directory.

When doing it this way a make in the application project won't do a make in the library project, you would have to take care of this yourself.

like image 149
trenki Avatar answered Oct 03 '22 05:10

trenki


Have multiple CMakeLists.txt.

Many open-source projects take this appraoch (LibOpenJPEG, LibPNG, poppler &etc). Take a look at their CMakeLists.txt to find out how they've done this.

Basically allowing you to just toggle features as required.

like image 26
A T Avatar answered Oct 01 '22 05:10

A T


I see two additional approaches. One is to simply have basic, io, and web be submodules of each app. Yes, there is duplication of code and wasted disk space, but it is very simple to implement and guarantees that different compiler settings for each app will not interfere with each other across the shared libraries. I suppose this makes the libraries not be shared anymore, but maybe that doesn't need to be a big deal in 2011. RAM and disk have gotten cheaper, but engineering time has not, and sharing of source is arguably more portable than sharing of binaries.

Another approach is to have the layout specified in the question, and have CMakeLists.txt files in each subdirectory. The CMakeLists.txt files in basic, io, and web generate standalone shared libraries. The CMakeLists.txt files in each app directory pull in each shared library with the add_subdirectory() command. You could then pull down all the library directories and whichever app(s) you wanted and initiate the build from within each app directory.

like image 32
Randall Cook Avatar answered Oct 04 '22 05:10

Randall Cook


You can use ADD_SUBDIRECTORY for this!

https://cmake.org/cmake/help/v3.11/command/add_subdirectory.html

like image 1
monokrome Avatar answered Oct 01 '22 05:10

monokrome