-
Notifications
You must be signed in to change notification settings - Fork 2
/
README
758 lines (566 loc) · 29.1 KB
/
README
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
=====
kmake
=====
.. contents::
kmake is an Automake replacement. It is based purely on GNU make and generates
rules and recipes dynamically during make time, avoiding the need to generate
Makefile files.
It is in many ways similar to kbuild of the Linux kernel, but it is designed to
build user space programs, static and shared libraries.
Goals
-----
kmake is targeted to replace Automake in an autotools-based build system.
It is not a drop-in replacement and it still depends on other components such
as libtool.
Global dependency tracking
^^^^^^^^^^^^^^^^^^^^^^^^^^
Automake uses recursive make by default, i.e. there are separate make
invocations for each directory (separate processes). Dependencies cannot be
tracked across those invocations, leading to incomplete builds if
one wants to update only subdirectories.
While it's possible to use a fully non-recursive setup with Automake,
it is very troublesome. Automake doesn't have directory-level CFLAGS.
Adding to AM_CFLAGS changes CFLAGS globally, so you have to fall back
to per-target CFLAGS which quickly requires lots of more lines of
Automake code and is hard to maintain in larger scale.
Additionally, each sub-Makefile.am needs to know it's exact location in the
project, unless you use %C% and %D% helpers which quickly render the
Makefile.am files unreadable for humans.
kmake on the other hand always uses a non-recursive setup. Sub-makefiles are
included recursively, forming one big Makefile (in memory) which has the
complete picture about everything that can be built. It adds directory-level
CFLAGS so you don't have to give up on modularity. Components can be separated
by directory and maintained individually, but of course components can
depend on other components and kmake ensures those dependencies
are applied properly.
If really needed, kmake provides a way to invoke a separate make process
for some directories, but this is meant as a fall back mostly for 3rd party
components.
Modularity
^^^^^^^^^^
kmake tries hard to allow projects to remain modular. Instead of one large
Makefile there are many sub-makfiles files. Each can specify its own programs,
libs and data files, its own CFLAGS and library dependencies. It goes further
by allowing to specify source files relative to the sub-makefile. Finally,
some directories may even require their own make invocation, kmake supports
this. All of this makes it usually harder to maintain modularity in a
non-recursive make setup. However, kmake goes great lengths to achieve this.
Avoid generating Makefiles
^^^^^^^^^^^^^^^^^^^^^^^^^^
One weakness of Automake is the fact that it generates files, and the
generated Makefiles contain rules to recreate themselves. When one manages
to introduce a syntax problem to the Makefiles, all hope is lost. Due
to the syntax problem, the Makefiles cannot be updated. Often enough
it's easier to wipe the build tree.
With kmake there is no such step to generate files. The sub-makefiles are
included at make-time so syntax errors can be corrected immediately. There is
no additional dependency since it's based on pure GNU make code.
Re-compile on compiler command line changes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Compiler options affect the build output in many ways, so naturally
a C file must be recompiled of a compiler option is added or removed.
This works for all possible ways to specify the options, including the ones
that you can pass on the make invocation (e.g. make CFLAGS=-g).
Concise sub-makefiles
^^^^^^^^^^^^^^^^^^^^^
Makefile.am files are mostly compact, unless you need lots per target
variables, then they can quickly become full of duplicate lines.
Because kmake supports directory-level CFLAGS (and other flags, including
custom flags that are not known to kmake initially), the sub-makefiles remain
concise.
To further aid compactness, kmake supports one-line ("inline") conditionals
similar to kbuild.
Extensibility
^^^^^^^^^^^^^
kmake can be extended at make-time by so called generators. These add rules
and recipes for custom targets that kmake doesn't support out of the box.
This can be used to tell kmake how to generate source files with the help of
external commands. If a build target depends on such a generated file kmake
introduces the proper dependency so that the file is generated as needed.
Additionally, if a target doesn't explicitly lists a generated file as
dependency, but instead lists its directory in the INCLUDES flag, kmake will
add a dependency as well. This is particularly useful for generated headers.
Those generators can benefit from the same mechanism that re-compiles C files
when CFLAGS changes. A properly implemented generator re-generates output
if any of the options to the external command changes.
Generators can be chained, which makes it possible teach kmake to generate
and build arbitrary file formats, without having to change kmake core itself.
Fundamental Concepts
--------------------
kmake uses terms for some concepts. Since these are used in the rest of the
document they shall be explained first.
Variables (vars)
^^^^^^^^^^^^^^^^
The key element in kmake are variables, or just short vars. kmake defines some
but also learns new ones dynamically (see `Adding vars`_). Vars generally have
a associated list via the -y suffix and may have properties (see
`Properties`_). via other suffixes. The associated list usually holds files,
but can also list options or other things. How the list is interpreted depends
on the variable.
Pre-defined variables include:
`subdir`
This one lists sub-directories where kmake looks for sub-makefiles,
see `Recursive inclusion of subdir.mk`_
`bin`, `sbin`
These list programs that must be built and installed.
`libs`
This one lists libraries, static or shared, libraries that must be built and
installed.
`data`, `sysconf`
These list data files that must be installed
`tests`
This one lists test programs.
These variable list files that must be installed (except for tests) and usually
they need to be built before. In fact, these files become targets.
subdir.mk add targets to the vars by assigning to their list (`var`-y):
``bin-y := program``
basically states that there is a target named program that must be built and
installed.
You may dynamically add more variables, for example if you need to install
in a non-standard location, see `customization and extensions`_ for
defining new vars and `Properties` on how to select the install directory.
Targets
^^^^^^^
Arguably, this is what kmake is about: defining targets and updating them as
necessary.
kmake learns about targets by listing them in one of the variables. Whenever
that is done, this implicitly creates target variables. The name matches
that of the target, and being a variable it has a file list (`target`-y)
and may have properties (see `Properties`_).
There are no predefined target variables, kmake learns about them dynamically.
For target variables, `target`-y usually lists source files. If no such list
exists and the target variable defines (or inherits) the suffix property, then
kmake attempts to find exactly one source file that matches the name of the
target plus its suffix property value. If the target has a suffix on its own,
it's replaced.
Additionally, `target`-y can list library targets that are defined in the same
subdir.mk file.
Here's an example for a target specification::
bin-y := tool
libs-y := libmy.a
libmy.a-y := libmy.c
tool-y := tool.c
tool-y += libmy.a
With the suffix property, this can be shortened a bit::
bin-suffix := .c
bin-y := tool # tool.c automatically picked up
Properties
^^^^^^^^^^
Variables (including target vars) can have properties.
Properties are inherited by targets. That means a target automatically gets
the property value of the var that the target is listed under. But targets
can be override suffixes with specific values.
Pre-defined properties include:
`-compiler`
The compiler program to use to build the targets, for example
to use clang on a per-var basis.
`-libtooltag`
When libtool is used to build shared libraries, this property overrides
the tag that libtool uses. By default kmake passes CXX or CC depending
on the source files. Use this to enforce, for example, CC.
See https://www.gnu.org/software/libtool/manual/html_node/Tags.html.
`-dir`
The installation directory used at `make install` time. The special value
`noinst` indicates that the target isn't meant to be installed at all.
`-driver`
The command that is used to run test targets. By default, this property
is not set and tests will execute within a shell spawned by make. But if
it's set then kmake will invoke this driver program with the test
as the first parameter.
`-suffix`
The suffix that is used to find the default source file if the target
does not list any source file in `target`-y. By default, this property
is not set. But if it's set then kmake assumes that the only
source file is named `target` plus the suffix. If the target has
a suffix it's replaced.
As you might see, not all properties make sense on all targets and therefore
some suffixes are simply ignored on some targets.
Flags
^^^^^
Another class of variables are flag variables. These are used to list
options that are passed to the compiler or other tools.
Predefined flag vars include:
`CPPFLAGS`, `CFLAGS`, `CXXFLAGS` and `LDFLAGS`
Options listed are passed to the preprocessor, compilers and the linker,
respectively.
`INCLUDES`
Include directories that are passed to the preprocessor. List only the
directory with a trailing slash, kmake will prepend -I itself. In addition
kmake will produce (order-only) dependencies on generated files located
in such directories. This automatically ensures that headers are generated
before any source file that includes such headers, although the
mechanism isn't strictly restricted to headers.
`LIBS`
Library path and link options that are passed last to the linker.
`DEPS`
Additional dependencies that used during compilation and linking stages,
depending on whether library our sources files are listed. The DEPS flag
behaves mostly the same as `var`-y except that the paths are not
relative to the current sub-makefile.
for a distinction between `var`-y).
One special property about flag variables is that they can be combined
with targets, effectively building *target-specific flags*. The values are
generally appended to the flag variables, allowing to override
some options for individual targets::
CFLAGS-y := -O1
mytool-CFLAGS-y := -O2
mytool-LIBS-y := -lz
Here, mytool will be compiled with both -O1 -O2, but the compiler generally
uses the last occurence.
Another special property is that for all flags there exists a subdir-XXX-y
flavor. This flavor sets the initial flags for targets defined in
sub-directories (see next section), and *only* for them. subdir-XXX-y
does not affect the targets of the current subdir.mk (this is different
to kbuild's subdir-ccflags-y). Therefore you probably want to initialize
them like this::
CFLAGS-y := -O1
subdir-CFLAGS-y := $(CFLAGS-y) -Werror
Recursive inclusion of subdir.mk
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Besides variables, one more fundamental concept is the recursive inclusion of
sub-makefiles, which must be named subdir.mk each. Instead of spelling out one
large Makefile, kmake reads many subdir.mk files in order to dynamically
generate that large Makefile only in memory. The subdir.mk files itself are
concise and specify only local targets.
Example ``subdir.mk``::
subdir-y := sub/ dir/
CFLAGS-y := -O2
bin-y := program1 program2
sbin-y := program3
libs-y := libmy.a
program2-suffix := .cpp
program3-y := othername.c
libmy.a-CPPFLAGS-y := -DHAVE_FOO
libmy.a-y := my.c
subdir.mk generally don't add to global variables. They assign to some var, and
then setup target vars. They also may set flag vars or target-specific flags as
required. Crucially, they also assign sub-directories to the subdir-y list.
This will cause kmake to recursively read subdir.mk files in a depth-first
fashion. Please be note that the trailing slash following the directory names
is mandatory.
Between including two subdir.mk, kmake resets all kinds of vars (except target
vars) to empty values, so no subdir.mk has the chance to accidentally delete
targets defined in another subdir.mk or otherwise affect them negatively. Note
that this is also true for subdir.mk files in a sub-directory. Flags,
such as CFLAGS and friends, do *not* affect sub-directories in any way.
To set flags for sub-directories, use subdir-CFLAGS-y. subdir-CFLAGS-y is
reset itself as well for sub-directory subdir.mk files, so they may add even
more compiler options by defining their own subdir-CFLAGS-y. kmake will
ensure leaf directories will see the concatenation of all subdir-CFLAGS-y
in the parent directiroes. Again, remember that subdir-CFLAGS-y does
only affect sub-directories but not the current one.
However, target vars not reset since other subdir.mk files shouldn't know about
them. This may be used to have multiple subdir.mk contribute to a global target
but it may be more appropriate to implement this with static libraries instead.
The var values provided by all subdir.mk contribute to a number of lists. For
example `all_bin` lists all programs that have been assigned to `bin`-y across
all subdir.mk files. Likewise, there are all_sbin and all_libs lists and many
more. This is how kmake remembers all possible targets in order to generate
rules after processing all subdir.mk files.
Generators
^^^^^^^^^^
So far we have covered targets that are built from C or C++ source files,
as kmake primarily targets those two languages. However, since one of kmake's
stated goes is extensibility, there is the concept of `generators`. That is,
a kind of plugins that enable kmake to build targets that it otherwise
doesn't know about.
Originally, this was designed to allow for running programs which in turn
generate source code files. Therefore, the output of generators can be input
of other targets and even other generators. In fact, generators can be changed
arbitrarily, for example to pre- and post-process files with sed.
Please note that the generators are not executed unless the output file
is a prerequisite of some other target or is to be installed itself.
kmake ships two real generators (for calling sed and cat) which are not
enabled by default. They are enabled by including the files `gen-sed.mk` and
`gen-cat.mk` respectively. Two pseudo generators, `byproduct` and `generated`,
are also included enabled by default.
gen-sed
The sed generator allows you to feed a file into sed in order to generate
a processed version of it. You can use for any number of output files,
and each output file can specify its own SED_SCRIPT that defines
the script that is passed to sed.
Here's an example::
sysconf-y := output.txt
sed-y := output.txt
output.txt-y := input.txt
output.txt-SED_SCRIPT-y := 's,foo,bar,'
This will generate out by running sed on the file input.txt to generate
output.txt. Since the file output.txt is to be installed, sed will be
executed if necessary: if output.txt doesn't exist, if input.txt is newer
or if SED_SCRIPT is changed since the last run.
gen-cat
The cat generator allows you to concat a number of input files in order to
generate a combined output file (using the cat program). Again, you can use
the cat generator for multiple output files, each with its own set of input
files. However it doesn't pass any special flag to cat.
Here's an example::
bin-y := program
cat-y := combined.c
program-y := combined.c
combined.c-y := file1.c file2.c
The cat generator will be executed since a program requires the output file.
The output file is generated as needed: if it doesn't exist or any
of its input files is newer.
byproduct
The byproduct pseudo generator helps managing dependencies for programs
that produce multiple output files. Because GNU make provides no universal
facility to manage those (except pattern rules which require uniform names
of all output files) this may be needed for race-free builds.
Example::
# mygen is an imaginary program that produces foo.c and bar.h
bin-y := program
program-y := foo.c baz.c bar.h
mygen-y := foo.c
byproduct-y := bar.h
bar.h-y := foo.c
As you can see, by listing bar.h in byproduct-y, kmake becomes aware
the file is generated as well (setting vpath if necessary among other things).
Additionally, by listing foo.c in bar.h-y, kmake will emit a rule (without
recipe) so that bar.h can be build explicitly as well, by generating foo.c.
This is especially useful if bar.h was to be included in other C files.
In this example, by listing bar.h in program-y, kmake can ensure
that bar.h will exist before any object of program is build.
generated
The generated pseudo generator marks files as generated that are
entirely generated using custom rules. By making kmake aware of such
generated files it can set vpath accordingly, among other things. The
custom rule will be run if any target build by kmake lists that file.
Example::
bin-y := program
program-y := foo.c myheader.h
generated-y := myheader.h
$(objdir)myheader.h: $(srcdir)myheader.h.in
generate -in $< -out $@
Always use $(srcdir) and $(objdir) to prepend the proper prefix to target
and prerequsite files in such custom rules, in case a
`separate output directory`_ is used.
You can see that generators are quite powerful. In fact, they make kmake truly
extensible since generators can be dynamically added to kmake if a project has
specific requirements. Details on how to create generators follow in section
`customization and extensions`_.
How to use kmake
----------------
Basic setup
^^^^^^^^^^^
In order to make use of kmake you must create a so-called stub-makefile that
includes kmake.mk. Usually this would be your Makefile that make uses by
default.
The stub-makefile is also the file where you include the shipped generators,
gen-sed.mk and gen-cat.mk, before including kmake.mk.
Besides including kmake.mk, the Makefile may set some default parameters for
kmake but it's not strictly required. The minimalistic setup looks like this,
assuming you have imported kmake's source tree into a subdirectory called
kmake.
`Makefile`::
include kmake.mk
`subdir.mk`::
bin-y := program
As you can see, the most minimalistic setup requires just the stub-makefile
and one subdir.mk file.
Parameterization
^^^^^^^^^^^^^^^^
kmake can be parameterized through defining some global variables, either
before including kmake.mk or simply by mentioning them on the make command
line.
Prefix
``````
Prefix refers to the installation directories. In a basic setup, kmake
uses the following defaults::
prefix = /usr/local/
bin-dir = /usr/local/bin
sbin-dir = /usr/local/sbin
libs-dir = /usr/local/lib
data-dir = /usr/local/share
sysconf-dir = /usr/local/etc
CROSS_COMPILE =
CC = cc
CXX = c++
AR = ar
STRIP = strip
LIBTOOL = libtool
INSTALL = install
If you want to override the above defaults, you can define ``prefix`` to
affects all directories, or define `bindir`, `sbinddir`, `libdir`, `datadir`
and `sysconfdir` to override individual ones.
Toolchain
`````````
Toolchain selection can also be parametrized. You can define `CROSS_COMPILE`
which is prefixed to the relevant toolchain programs (`CC`, `CXX`, `AR` and
`STRIP`). Additionally you can also change the individual programs, e.g. to use
`clang` instead of the usual system's default of `gcc`. However, be aware that
`CROSS_COMPILE` is applied regardless.
Tests
`````
Tests are are listed in the `tests` variable. Tests are compiled and executed
only on `make check`. kmake, by default, will simply execute via make recipies,
meaning that they are passed to the shell. The exit status is indicated by a
"PASS" or "FAIL" output. If you have lots of Python-based unit tests you may
want to pass them to the python interpreter directly. To do that, set the
driver property for the `tests` variables (or any custom tests variable added
via `extra-tests`) or set the driver property of each python test individually.
Silent / verbose output
````````````````````````
By default, kmake produces quiet and pretty output, like this::
GEN g/g.c
CC a/liba.a-a.o
CC a/libx.la-libx.lo
To get the command lines that are executed, set ``V=1``. Some tools output
even more details if you set ``V=2`` but that may produce really lots of
output.
Separate output directory
`````````````````````````
By default, kmake places output files, like objects, library files and programs
to the current directory. However, it is recommended to use a separate
directory for output files, since that allows you to retain a clean source
tree. Output directories are defined by setting `O=some/builddir`. Then,
kmake will place every output file under that sub-directory. The directory
structure of the source tree is reproduced, except if no outfile would be
produced in a given directory.
Partial build
`````````````
kmake can be told to build only targets in specific directories. These
directories are defined by setting M on the command line. For example,
``make M=foo`` builds only libraries and programs under foo/.
However, this is not quite the same as building only in a sub-directory
with Automake. Even with partial build, kmake will respect dependencies
of each target. This means any required dependency will be updated if
necessary, even if outside the selected directories. This is usually
exactly what you want, as you don't need to explicitly build dependency
libraries beforehand.
Multiple directories are supported (separated by spaces) but remember to
properly escape the space on the command line (e.g. ``M=foo\ bar``).
The partial build filter also applies to check, clean and install targets.
Customization and extensions
----------------------------
As has been mentioned before, kmake leaves room for extensions, because the
defaults usually don't fit anyone.
Adding vars
^^^^^^^^^^^
Besides overriding properties of pre-defined variables, like setting `bin-dir`
to something else, you can also add vars (vars as in `Variables (vars)`_). This
is helpful if you have custom installation directories but also need `bin` and
`sbin` as they are.
This is also useful if you build plugins for some other application and
you must put them into a directory where that application looks for plugins.
To add vars, define any one (or more) of the following variables,
ether in any subdir.mk or in the stub-makefile:
`extra-progs`
Vars mentioned here list programs
`extra-libs`
Vars mentioned here list libraries
`extra-data`
Vars mentioned here list data files
`extra-tests`
Vars mentioned here list test programs
Again, you add vars. Then you use these new vars to list targets and set
properties. The following example adds a data var `src` for source code
installed to /usr/src::
extra-data := src
src-dir := $(prefix)src
src-y := a.c b.c c.c
If multiple subdir.mk files add the same var, kmake will take care in the
following way: the list (`var`-y) is appended each time it is mentioned, so
targets are not lost. However, the last setter of a given property takes
precedence, so each subdir.mk should set the same property values.
Alternatively (and recommend), you can add the var and set its properties in
the stub-makefile and then only add to the var's list in the subdir.mk files
(which is exactly the same way for pre-defined variables).
The following ones are only relevant if you need to extend kmake with
`Generators`_.
`extra-gen`
Vars mentioned here list generators
`extra-flags`, `extra-append-flags`
These variables list flag vars. They differ in the way kmake
handles them vs. target-specific flags-
With `extra-flags` and `extra-append-flags` you can add flag vars that
behave much the same as the pre-defined ones like CFLAGS (see `Flags`). But
kmake wouldn't use them in any rule so they are only useful if you use them
in rules of custom generators.
Adding generators
^^^^^^^^^^^^^^^^^
Generators are powerful and make kmake truly extensible. Generators can add
arbitrary build rules to kmake, allowing to build just about anything. In
theory they are even capable of adding support for new programming languages,
though it hasn't been shown in practice.
Adding generators is done primarily by listing it in `extra-gen`, in the same
way as adding a var (see above). It is recommended to do this before including
`kmake.mk`, so that all subdir.mk can easily use it . However, it's also
perfectly OK if a generator is defined and used only in a single subdir.mk.
The name you chose for the generator is significant because kmake will call out
for two macros, named after the generator, when it builds up all build rules
after processing all subdir.mk files. So, if the generator is named `foo`, then
kmake will call the macros `foo_rule` and `foo_recipe`. The former will be
called once for every target (the target is passed as the first argument),
while the latter is called exactly once (the list of all targets is passed as
the first argument).
Optionally, you can assign the suffix property to your generator variable if
you want kmake to automatically find source files for targets.
Also optional is telling kmake about additional flags (see `Flags`_) that
kmake shall learn via `extra-flags`. Flag vars listed here will be recorded
in the same manner as CFLAGS. The flags can be used in the rule and recipe
parts of the generator to target pass specific options to the program.
As an example, let's look at the sed generator that ships with kmake and
then detail what to do in the rule and recipe parts of a generator::
extra-gen += sed
extra-flags += SED_SCRIPT
define sed_rule
$(OUTDIR)$(1): SED_SCRIPT = $(call getvar,$(1),SED_SCRIPT)
$(OUTDIR)$(1): CMD = $$(SED_SCRIPT)
$(OUTDIR)$(1): $(SRCDIR)$(call getsrc,$(1))
$(OUTDIR)$(1): $(OUTDIR)$(call getcmdfile,$(1))
endef
define sed_recipe
$(addprefix $(OUTDIR),$(1)):
$$(call printcmd,GEN,$$@)
$$(Q)sed $$(addprefix --expression=,$$(SED_SCRIPT)) $$< >[email protected] && ( mv [email protected] $$@ ; rm -f [email protected] )
endef
sed-suffix := .c.sed
Generator rule
``````````````
The rule part is more kmake-specific that the recipe part, and here kmake
offers some macros that it uses internally as well.
$(OUTDIR)
Evaluates to the output directory if it's set via ``make O=path``
Always prefix targets with $(OUTDIR), kmake doesn't do this before
passing them to your macros, because some other macros require
the non-prefixed version, in particular getsrc below.
$(SRCDIR)
Evaluates to the source directory if it's set via ``make S=path`` and
make's working directory is outside of it. Always prefix source files with
$(SRCDIR), getsrc (see below) doesn't do this because it would hurt other
users of that macro.
getsrc
Basically, this gets the list of files formed by `var`-y, `var`-DEPS-y and
directory-level DEPS (in that order). The value of `var`-y is subject
to the automatic source file detection if the generator has a suffix
property.
Pass the target name ($1) without $(OUTDIR) prefix.
Always add the source file list first to the prerequisites of the target.
getcmdfile
This is optional but it allows kmake to generate .cmd file
(see `Re-compile on compiler command line changes`_) so that the output
file will be regenerated when relevant flags change. kmake will
write the contents of the variable $(CMD) into the .cmd file, so usually
that variable is a target-specific one (in GNU make terms).
getvar
This macro retrieves the target-specific value of a flag/var. Usually
this is the concatenation of a directory-level flag and target-specific
flag.
The sed generator also tells kmake about a `SED_SCRIPT` flag that it should
record. kmake will automatically notice directory-level `SED_SCRIPT`-y vars
as well as target-specific target-`SED_SCRIPT`-y vars and store them.
The generator then uses the value as a script that is passed to sed. The
value of the `SED_SCRIPT` flag is also fed into the `$(CMD)` variable,
i.e. kmake will populate the .cmd file with the script. As a result,
changing the script will automatically force regeneration of output files.
Generator recipe
````````````````
In the the recipe part the generator must define a plain make recipe to
actually generate the output files. Usually it's best to take the list
of targets and generate a recipe for each as done in the sed generator. But
it may be necessary to define a pattern rule, especially if the generator
outputs more than one file.
Here kmake cannot aid much. You can reference target specific variables that
are setup in the rule part of the generator to pass options to the generating
program. Additionally, you can use kmake's `printcmd` macro to output a pretty
line in the absence of ``make V=1`` (see `Silent / verbose output`_).