1
0
mirror of synced 2024-11-05 04:28:54 +01:00
modern-cmake/chapters/basics/comms.md
2018-04-05 12:31:31 +02:00

2.4 KiB

Communication with your code

Configure File

CMake allows you to access CMake variables from your code using configure_file. This command copies a file (traditionally ending in .in from one place to another, substituting all CMake variables it finds. If you want to avoid replacing existing ${} syntax in your input file, use the @ONLY keyword. There's also a COPY_ONLY keyword if you are just using this as a replacement for file(COPY.

This functionality is used quite frequently; for example, on Version.h.in:

Version.h.in

#pragma once

#define MY_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define MY_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define MY_VERSION_PATCH @PROJECT_VERSION_PATCH@
#define MY_VERSION_TWEAK @PROJECT_VERSION_TWEAK@
#define MY_VERSION "@PROJECT_VERSION@"

CMake lines:

configure_file (
    "${PROJECT_SOURCE_DIR}/include/My/Version.h.in"
    "${PROJECT_BINARY_DIR}/include/My/Version.h"
)

You should include the binary include directory as well when building your project. If you want to put any true/false variables in a header, CMake has C specific #cmakedefine and #cmakedefine01 replacements to make appropriate define lines.

You can also (and often do) use this to produce .cmake files, such as the configure files (see the section on configuring).

Reading files

The other direction can be done too; you can read in something (like a version) from your source files. If you have a header only library that you'd like to make available with or without CMake, for example, then this would be the best way to handle a version. This would look something like this:

# Assuming the canonical version is listed in a single line
# This would be in several parts if picking up from MAJOR, MINOR, etc.
set(VERSION_REGEX "#define MY_VERSION[ \t]+\"(.+)\"")

# Read in the line containing the version
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/My/Version.hpp"
    VERSION_STRING REGEX ${VERSION_REGEX})

# Pick out just the version
string(REGEX REPLACE ${VERSION_REGEX} "\\1" VERSION_STRING "${VERSION_STRING}")

# Automatically getting PROJECT_VERSION_MAJOR, My_VERSION_MAJOR, etc.
project(My LANGUAGES CXX VERSION ${VERSION_STRING})

Above, file(STRINGS file_name variable_name REGEX regex) picks lines that match a regex; and the same regex is used to then pick out the parentheses capture group with the version part. Replace is used with back substitution to output only that one group.