1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
* Configuration
Targets describe abstract concepts like "library". Depending on
requirements, a library might manifest itself in different ways.
For example,
- it can be built for various target architectures,
- it can have the requirement to produce position-independent code,
- it can be a special build for debugging, profiling, etc.
So, a target (like a library described by header files, source files,
dependencies, etc) has some additional input. As those inputs are
typically of a global nature (e.g., a profiling build usually wants
all involved libraries to be built for profiling), this additional
input, called "configuration" follows the same approach as the
~UNIX~ environment: it is a global collection of key-value pairs
and every target picks, what it needs.
** Top-level configuration
The configuration is a ~JSON~ object. The configuration for the
target requested can be specified on the command line using the
~-c~ option; its argument is a file name and that file is supposed
to contain the ~JSON~ object.
** Propagation
Rules and target definitions have to declare which parts of the
configuration they want to have access to. The (essentially) full
configuration, however, is passed on to the dependencies; in this way,
a target not using a part of the configuration can still depend on
it, if one of its dependencies does.
*** Rules configuration and configuration transitions
As part of the definition of a rule, it specifies a set ~"config_vars"~
of variables. During the evaluation of the rule, the configuration
restricted to those variables (variables unset in the original
configuration are set to ~null~) is used as environment.
Additionally, the rule can request that certain targets be evaluated
in a modified configuration by specifying ~"config_transitions"~
accordingly. Typically, this is done when a tool is required during
the build; then this tool has to be built for the architecture on
which the build is carried out and not the target architecture. Those
tools often are ~"implicit"~ dependencies, i.e., dependencies that
every target defined by that rule has, without the need to specify
it in the target definition.
*** Target configuration
Additionally (and independently of the configuration-dependency
of the rule), the target definition itself can depend on the
configuration. This can happen, if a debug version of a library
has additional dependencies (e.g., for structured debug logs).
If such a configuration-dependency is needed, the reserved key
word ~"arguments_config"~ is used to specify a set of variables (if
unset, the empty set is assumed; this should be the usual case).
The environment in which all arguments of the target definition are
evaluated is the configuration restricted to those variables (again,
with values unset in the original configuration set to ~null~).
For example, a library where the debug version has an additional
dependency could look as follows.
#+BEGIN_SRC
{ "libfoo":
{ "type": ["@", "rules", "CC", "library"]
, "arguments_config": ["DEBUG"]
, "name": ["foo"]
, "hdrs": ["foo.hpp"]
, "srcs": ["foo.cpp"]
, "local defines":
{ "type": "if"
, "cond": {"type": "var", "name": "DEBUG"}
, "then": ["DEBUG"]
}
, "deps":
{ "type": "++"
, "$1":
[ ["libbar", "libbaz"]
, { "type": "if"
, "cond": {"type": "var", "name": "DEBUG"}
, "then": ["libdebuglog"]
}
]
}
}
}
#+END_SRC
** Effective configuration
A target is influenced by the configuration through
- the configuration dependency of target definition, as specified
in ~"arguments_config"~,
- the configuration dependency of the underlying rule, as specified
in the rule's ~"config_vars"~ field, and
- the configuration dependency of target dependencies, not taking
into account values explicitly set by a configuration transition.
Restricting the configuration to this collection of variables yields
the effective configuration for that target-configuration pair.
The ~--dump-targets~ option of the ~analyse~ subcommand allows to
inspect the effective configurations of all involved targets. Due to
configuration transitions, a target can be analyzed in more than one
configuration, e.g., if a library is used both, for a tool needed
during the build, as well as for the final binary cross-compiled
for a different target architecture.
|