CMake Tips: Managing dependency warnings
I belong to the tribe of people who think that CMake is a pretty good tool. I do
find myself needing to struggle due to the sheer amount of parallel API’s. One of
these struggles i’ve gone through lately was when i finally got to setup clang-tidy
.
Having static-analyzation is great - it catches many semantic issues before the build
is done and keeps your from some regressions. I’m also a big fan of using -Werror
and
-pedantic
to keep myself from checking in incorrect or failing commits.
This is where CMake comes back to play: Over the last couple years two modules have swept
the scene and support most to all needs you will have with your dependencies: FetchContent
and ExternalProject
.
Both include your dependencies in a way similar to add_subdirectory
and thus declare them
as techhnically your code. This can get extremely annoying with aforementioned settings
as you are not at the hands of the original developers to not break your rule-chains.
This can be avoided though!
CMake uses a nifty little feature called SYSTEM_INCLUDE_DIRECTORIES
that are being handled
slightly different to the normal kind of include directories we know. CMake assumes these are
provided by the system - thus not really of it’s concern in terms of formatting/static-analyzing.
We as developers can tell CMake to add a target’s include directories to this list so that we can
keep ignoring those upstream warnings.
FetchContent
If you use FetchContent it’s actually extremely easy. All you have to do is add SYSTEM
to the
Fetchconent_Declare
statement. For example the popular fmt
package would be declared like this:
FetchContent_Declare(fmt
SYSTEM
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_SHALLOW ON
GIT_TAG master
)
FetchContent_MakeAvailable(fmt)
ExternalProject
Here it gets a little harder, since ExternalProject
offers quite a verbose and customizable
API we need to first ExternalProject_Add
our project, then retrieve the include-directories as
setup by ExternalProject
and overwrite the target’s properties. This can be done like this: (using libjpeg-turbo as example)
ExternalProject_Add(extern-libjpeg
GIT_REPOSITORY "https://github.com/libjpeg-turbo/libjpeg-turbo"
GIT_TAG "3.0.3"
GIT_SHALLOW ON
PREFIX ${LIBJPEG_TURBO_PREFIX}
CMAKE_ARGS ${LIBJPEG_TURBO_CMAKE_ARGS}
BUILD_BYYPRODUCTS ${LIBJPEG_TURBO_INSTALL_PREFIX}/lib/libjpeg.a
)
add_library(jpeg STATIC IMPORTED GLOBAL)
add_dependencies(jpeg extern-libjpeg)
set(LIBJPEG_TURBO_INCLUDE_DIRS ${LIBJPEG_TURBO_INSTALL_PREFIX}/include)
file(MAKE_DIRECTORY ${LIBJPEG_TURBO_INCLUDE_DIRS})
set_target_properties(jpeg PROPERTIES
IMPORTED_LOCATION ${LIBJPEG_TURBO_INSTALL_PREFIX}/lib/libjpeg.a
INTERFACE_INCLUDE_DIRECTORIES ${LIBJPEG_TURBO_INCLUDE_DIRS}
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES ${LIBJPEG_TURBO_INCLUDE_DIRS}
)
The call to file
is needed since the include directory needs to exist at configuration time,
so we pre-create it.