Try Me¶
In the TCPM try me directory we provide a ready-made template so you can see how TCPM works for yourself.
Simply download this file into a new directory, cd
into the directory, and do:
tcpm
What just happened?¶
You should now have a, relatively large, CMakePresets.json
file in this directory. It was generated from
CMakePresetsVendorTemplate.json
which is the default name for TCPM templates. Let’s take a look at this file:
1{
2 "version": 9,
3 "cmakeMinimumRequired": {
4 "major": 3,
5 "minor": 30,
6 "patch": 0
7 },
8 "configurePresets": [
9 {
10 "name": "configure-common",
11 "hidden": true,
12 "generator": "Ninja Multi-Config",
13 "binaryDir": "${sourceDir}/build",
14 "warnings": {
15 "deprecated": true,
16 "uninitialized": true
17 },
18 "cacheVariables": {
19 "CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
20 "CMAKE_PREFIX_PATH": "${sourceParentDir}",
21 "CMAKE_CONFIGURATION_TYPES": "Release;RelSize;Debug;DebugAsan",
22 "CMAKE_CROSS_CONFIGS": "all",
23 "CMAKE_DEFAULT_BUILD_TYPE": "Debug",
24 "CMAKE_DEFAULT_CONFIGS": "Debug"
25 }
26 }
27 ],
28 "vendor": {
29 "tcpm": {
30 "version": 1,
31 "onload": [
32 "$('#preset-group-build parameters toolchain').json($('#preset-group-config parameters toolchain').json()).exp()",
33 "$('#preset-group-build parameters standard').json($('#preset-group-config parameters standard').json()).exp()",
34 "$('#preset-group-build parameters configuration').json($('#configure-common cacheVariables CMAKE_CONFIGURATION_TYPES').text().split(';')).exp()",
35 "$('#preset-group-workflow shape-parameters configuration').json($('#configure-common cacheVariables CMAKE_CONFIGURATION_TYPES').text().split(';')).exp()",
36 "$('#preset-group-workflow parameters toolchain').json($('#preset-group-config parameters toolchain').json()).exp()",
37 "$('#preset-group-workflow parameters standard').json($('#preset-group-config parameters standard').json()).exp()"
38 ],
39 "preset-groups": {
40 "configure": {
41 "name": "preset-group-config",
42 "common": [
43 "configure-common"
44 ],
45 "parameters": {
46 "toolchain": [
47 "gcc-native",
48 "gcc-native-32",
49 "clang-native"
50 ],
51 "standard": [
52 "cpp-14",
53 "cpp-17",
54 "cpp-20"
55 ]
56 },
57 "shape": {
58 "toolchain": {
59 "toolchainFile": "${{sourceParentDir}}/.devcontainer/cmake/toolchains/{parameter}.cmake",
60 "cacheVariables": {
61 "MY_TARGET_PLATFORM": "{pq}(this).if('{name}' $= 'gcc-native-32', 'm32', 'native')"
62 }
63 },
64 "standard": {
65 "cacheVariables": {
66 "CMAKE_CXX_STANDARD": "{pq}(this).literal('{parameter}').split('{sep}').get(1)"
67 }
68 }
69 }
70 },
71 "build": {
72 "name": "preset-group-build",
73 "parameters": {
74 "configuration": [],
75 "toolchain": [],
76 "standard": []
77 },
78 "shape": {
79 "configuration": {
80 "configurePreset": "{pq}(this).literal('{name}').replace('{prefix}{sep}{parameter}', '{groups[configure][prefix]}')",
81 "configuration": "{parameter}",
82 "targets": [
83 "build",
84 "build_examples",
85 "build_unittests",
86 "build_compile_tests",
87 "docs",
88 "lint",
89 "release"
90 ]
91 }
92 }
93 },
94 "workflow": {
95 "name": "preset-group-workflow",
96 "parameters": {
97 "toolchain": [],
98 "standard": []
99 },
100 "shape-parameters": {
101 "configuration": []
102 },
103 "shape": {
104 "toolchain": {
105 "displayName": "{pq}(this).literal('{name}').replace('{groups[workflow][prefix]}{sep}','').replace('{sep}', ' ')",
106 "description": "autogenerated workflow",
107 "steps": [
108 {
109 "type": "configure",
110 "name": "{pq}(this).literal('{name}').replace('{groups[workflow][prefix]}{sep}', '{groups[configure][prefix]}{sep}')"
111 }
112 ]
113 },
114 "configuration": {
115 "steps": [
116 {
117 "type": "build",
118 "name": "{pq}(this).literal('{name}').replace('{groups[workflow][prefix]}{sep}', '{groups[build][prefix]}{sep}{parameter}{sep}')"
119 }
120 ]
121 }
122 }
123 }
124 }
125 }
126 }
127}
The first thing you might notice is this is a valid CMakePresets.json file with a single "configurePresets"
entry, "configure-common"
. The template part of this file is found in the top-level "vendor"
section starting
with the tcpm
object on line 29. In this object the preset-groups
object should look a bit familiar having
objects named “configure”, “build”, and “workflow”. Each of these corresponds to preset groups by simple textual
concatenation of “Presets” to the end of the identifier (e.g. “configure” => “configurePresets”).
On line 41, the "configure"
object contains all of the information used to generate "configurePresets"
. Let’s
go over each item in this object:
Key |
Req’d? |
Type |
Description |
---|---|---|---|
|
no |
string |
A name for this object to allow direct addressing in pQuery statements as |
|
no |
array[string] |
A list of |
|
yes |
object[string, array[string]] |
This is where the magic happens. Parameters define each dimension of a matrix and it is the cartesian product of each of these parameter lists that TCPM uses to generate new presets. |
|
no |
object[string, array[string]] |
The same as parameters except these are not used to create presets but, for any presets created, are used to instatiate parameterized shapes for each preset. |
|
no |
object[string, object] |
Shapes act like templates for parameters and shape-parameters. Each shape is used when a given parameter is part
of a new preset definition to append additional data to the preset object. |
In our example we generated every posible configuration needed to build a project for three different toolchains using three different C++ standards. Let’s suppose we want to run these build presets using Github Actions. We’d find that this system supports a similar syntax for defining a matrix of build jobs:
jobs:
example_matrix:
strategy:
matrix:
toolchain: ["gcc-native", "gcc-native-32", "clang-native"]
standard: ["cpp-14", "cpp-17", "cpp-20"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: cmake --workflow --preset workflow-${{ matrix.toolchain }}-${{ matrix.standard }}
Let’s say we don’t want to build "cpp-20"
using the "gcc-native-32"
toolchain. Github actions allows pruning the
result set using exclude
. For example:
jobs:
example_matrix:
strategy:
matrix:
toolchain: ["gcc-native", "gcc-native-32", "clang-native"]
standard: ["cpp-14", "cpp-17", "cpp-20"]
exclude:
- toolchain: gcc-native-32
standard: cpp-20
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: cmake --workflow --preset workflow-${{ matrix.toolchain }}-${{ matrix.standard }}
TCPM supports a similar syntax in JSON form to prevent generation of this workflow:
"exclude": [
{
"toolchain": "gcc-native-32",
"standard": "cpp-20"
}
],
Try adding the above exclude to the CMakePresetsVendorTemplate.json
under
["vendor"]["tcpm"]["preset-groups"]["workflow"]
. Now do tcpm -f
(-f
to force overwrite of the existing
CMakePresets.json
file) and you’ll have a slightly smaller presets file that does not provide a workflow for this
combination of parameters.