1
0
mirror of synced 2024-11-04 20:18:54 +01:00
modern-cmake/chapters/basics/comms.md
Jesse Bollinger 2c90f7cf67 Fixed a missing parenthesis typo.
(PS: I created a GitLab account just to submit this typo fix. The signup process required a lot of needless stuff that wasted a bunch of my time and which has no current relevance whatsoever to what I'm doing e.g. creating a group and project when I have no interest in doing so etc. Perhaps you should switch to a site that has much better understanding of basic user interface/experience design. The experience has definitely left a negative initial impression of GitLab's sense of judgement and taste compared to e.g. GitHub etc.)
2020-10-23 16:29:55 +00:00

2.5 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 installing).

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.