[CMake] Best practices question: Organizing a library project

Andrey Pokrovskiy wonder.mice at gmail.com
Fri Aug 14 17:49:45 EDT 2015


Hi,

What is best way to organize a library project that uses CMake as its
build system?
One advantage that I would expect from a library project with CMake
build system is easy integration with another projects that also use
CMake. In other words it should be very simple to include (add a
dependency on) such a library in any CMake based project.

However, more often than not, it's impossible to use library's
provided CMakeLists.txt without some modifications or without dreaded
ExternalProject_Add() invocation.

So, I want to collect some best practices on creating such library projects.

Bellow is my experience/observation about that.

I consider ExternalProject_Add() as a last resort when everything else
fails. It's clumsy to write and maintain and also it will not add
library source code to the generated IDE project (like Qt Creator).
Also forwarding toolchain settings and other options (like build type,
etc.) into ExternalProject is a pain.

Using library's main CMakeLists.txt is _often_ not a good option
either. Many of those will add tons of cache variables (options,
settings) that are not relevant for the main project. Also they add
many unnecessary targets (which also can have the same name as targets
in the main project, like "tags", "docs", etc). Also the common
problem is that they don't provide an easy way to control library's
dependencies. For example, library depends on OpenSSL, but I build
OpenSSL as part of my main project and want library to use it. Yes, if
it uses FindOpenSSL() than it's possible to fool FindOpenSSL() that
OpenSSL was already found by tampering with OPENSSL_FOUND and other
OPENSSL_XXX variables, but looks more like a hack to me.

Choosing shared/static version of a library could also be a pain,
especially when you need both.

>From my personal experience, the most practical scheme is when library
has two CMakeLists.txt files. One is for building the library as a
standalone project and another for inclusion with add_subdirectory().
Obviously, the first includes the second (with add_subdirectory) for
DRYness. That way the first script has cache option definitions,
manages all the tests, docs and other things that are of no interest
to the projects that depend on that library. The second one only
builds the library, providing minimal set of targets. A small example
to illustrate what I'm talking about:
https://github.com/wonder-mice/zf_log
This approach is not perfect in many ways, but was good enough in my
experiments.


More information about the CMake mailing list