21

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.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • Good question. I'm searching solution for same problem. – kravemir Oct 15 '11 at 14:11
  • Check [this solution](http://stackoverflow.com/a/17201375/2436175). Does it get to the point? – Antonio Jun 19 '13 at 22:25
  • @Antonio: I don't know...I solved the problem myself using the solution explained in my answer below. That link of yours seems sort of related but maybe a little different to my original issue. Anyway it's long behind me now. :) – John Zwinck Jun 20 '13 at 11:12

6 Answers6

5

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.

trenki
  • 7,133
  • 7
  • 49
  • 61
  • So how do you import the exported targets if they haven't been installed yet? This is related to my question here: [CMake: How to build external projects and include their targets](http://stackoverflow.com/questions/15175318/cmake-how-to-build-external-projects-and-include-their-targets) – mirkokiefer Mar 02 '13 at 14:14
2

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.

A T
  • 13,008
  • 21
  • 97
  • 158
1

You can use ADD_SUBDIRECTORY for this!

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

monokrome
  • 1,377
  • 14
  • 21
1

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.

Randall Cook
  • 6,728
  • 6
  • 33
  • 68
  • I agree that sharing of source is important, so let's be clear: are you suggesting that the code be copy/pasted between repos? – John Zwinck Nov 24 '11 at 19:30
  • Far from it, @John Zwinck. I am suggesting that each app have three submodules, one for each library (basic, io, web), and each type of submodule pulls from its corresponding remote. In general, I think copying and pasting of source code violates the "don't repeat yourself" maxim, but if the replication is managed by a VCS like git, it becomes much safer because the VCS helps propagate changes. It's one of the main reasons we use version control systems in the first place. – Randall Cook Nov 24 '11 at 21:23
0

I ended up doing what I outlined in my question, which is to check in an empty directory (containing a .gitignore file which ignores everything) and tell CMake to GLOB any directories (which are put in there by the user). Then I can just say cmake myrootdir and it does find all the various components. This works more or less OK. It does have some side drawbacks though, such as that some third-party tools like BuildBot expect a more traditional project structure which makes integrating other tools with this sort of arrangement a little more work.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
-1

The CMake BASIS tool provides utilities where you can create independent modules of a project and selectively enable and disable them using the ccmake command.

Full disclosure: I'm a developer for the project.

Andrew Hundt
  • 2,551
  • 2
  • 32
  • 64
  • 1
    CMake already has tools for nesting projects, so this seems like maybe not the best solution – monokrome Jul 12 '18 at 07:34
  • @monokrome what tools for nesting projects? Did the tools exist in 2014 when I wrote the answer? If not, please just comment and don't downvote an answer that was accurate at the time of writing. Thanks! :-) – Andrew Hundt Jul 20 '18 at 17:43