-
Notifications
You must be signed in to change notification settings - Fork 2
/
Makefile.mk
1374 lines (1188 loc) · 63.1 KB
/
Makefile.mk
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
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#
# Makefile.mk - version 2.6 (2024/2/16)
# Copyright (C) 2024 Richard Bradley
#
# Additional contributions from:
# Stafford Horne (github:stffrdhrn)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# In addition, the following restrictions apply:
#
# 1. The Software and any modifications made to it may not be used for the
# purpose of training or improving machine learning algorithms, including but
# not limited to artificial intelligence, natural language processing, or data
# mining. This condition applies to any derivatives, modifications, or updates
# based on the Software code. Any usage of the Software in an AI-training
# dataset is considered a breach of this License.
#
# 2. The Software may not be included in any dataset used for training or
# improving machine learning algorithms, including but not limited to
# artificial intelligence, natural language processing, or data mining.
#
# 3. Any person or organization found to be in violation of these restrictions
# will be subject to legal action and may be held liable for any damages
# resulting from such use.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
#
# Makefile assistant for C/C++ projects
#
# Include this file at the end of your makefile to create basic make targets
# and allow the definition of binary/library builds by parameter assignment.
#
# Make Targets:
# all executes DEFAULT_ENV (defaults to 'release')
# release makes all optimized binaries/libraries/tests
# debug builds debug versions of all binaries/libraries/tests
# profile builds gprof versions of all binaries/libraries/tests
# clean deletes build directory & test binaries
# clobber deletes build directory & built binaries/libraries/files
# tests run all tests for DEFAULT_ENV
# info prints summary of defined build targets
# .gitignore prints a sample .gitignore file for all targets
# help prints command summary
#
# Makefile Parameters:
# BIN<1-99> name of binary to build
# BIN1.SRC source files for binary 1
# (C++/C/Assembly/WindowsRC source files, no headers)
# BIN1.OBJS additional binary 1 object dependencies (.o/.a files)
# BIN1.DEPS additional dependencies for building all binary 1 objects
#
# LIB<1-99> name of library to build (without .a/.so/.dll extension)
# LIB1.TYPE type of library to build: static(default) and/or shared
# LIB1.SRC source files for library 1
# LIB1.OBJS additional library 1 object dependencies
# LIB1.DEPS additional dependencies for building all library 1 objects
# LIB1.VERSION major(.minor(.patch)) version of shared library 1
#
# FILE<1-999> file to generate (i.e. generated source code)
# FILE1.DEPS file dependencies to trigger a rebuild for file 1
# FILE1.CMD command to execute to create file 1
# for CMD, these variables can be used in the definition:
# DEPS - same as FILE1.DEPS
# DEP1 - first DEPS value only
# OUT - same as FILE1
#
# TEMPLATE<1-99> file to generate (w/ template variables)
# TEMPLATE1.DEPS used to create 'FILE1.DEPS'
# TEMPLATE1.CMD used to create 'FILE1.CMD'
# use of other vars (BUILD_TMP,DEP1,OUT,etc.) must be escaped
# TEMPLATE1.FILE1 values used for 'FILE1' creation
# referenced by $(VALS) or $(VAL1),$(VAL2),etc. in template
#
# TEST<1-999> unit test description (optional)
# TEST1.ARGS arguments for running test 1 binary
# TEST1.SRC source files for unit test 1
# TEST1.OBJS additional unit test 1 object dependencies
# TEST1.DEPS additional dependencies for building all test 1 objects
#
# COMPILER compiler to use (gcc/clang)
# LINKER linker to use instead of default (bfd/gold/lld/mold)
# CROSS_COMPILE binutils and gcc toolchain prefix (i.e. arm-linux-gnueabi-)
# STANDARD language standard(s) of source code
# OPT_LEVEL optimization level for release & profile builds
# OPT_LEVEL_DEBUG optimization level for debug builds
# SUBSYSTEM subsystem value for Windows binary builds
# WARN C/C++ compile warning flags (-W optional)
# WARN_C C specific warnings (defaults to WARN or C specific list)
# WARN_CXX C++ specific warnings (defaults to WARN or C++ specific list)
# PACKAGES list of packages for pkg-config
# PACKAGES_TEST additional packages for all tests
# INCLUDE includes needed not covered by pkg-config (-I optional)
# INCLUDE_TEST additional includes for all tests (-I optional)
# LIBS libraries needed not covered by pkg-config (-l optional)
# LIBS_TEST additional libs for all tests (-l optional)
# DEFINE defines for compilation (-D optional)
# DEFINE_TEST additional defines for all tests (-D optional)
# OPTIONS list of options to enable - use instead of specific flags
# warn_error make all compiler warnings into errors
# pthread compile with pthreads support
# lto enable link-time optimization
# modern_c++ enable warnings for some old-style C++ syntax (pre C++11)
# no_rtti disable C++ RTTI
# no_except disable C++ exceptions
# pedantic enforces strict ISO C/C++ compliance
# static_rtlib statically link with runtime library (libgcc usually)
# static_stdlib statically link with C++ standard library (libstdc++ usually)
# mapfile generate a link map file for binaries & shared libraries
# OPTIONS_TEST additional options for all tests
# FLAGS additional compiler flags not otherwise specified
# FLAGS_TEST additional compiler flags for all tests
# FLAGS_RELEASE additional compiler flags for release builds
# FLAGS_DEBUG additional compiler flags for debug builds
# FLAGS_PROFILE additional compiler flags for profile builds
# RPATH directories to search for shared library loading
# LINK_FLAGS additional linking flags not otherwise specified
# *_EXTRA available for most settings to provide additional values
#
# <OS>.<VAR> set WINDOWS/LINUX specific value for any setting
# (overrides non-OS specified value)
#
# BUILD_DIR directory for generated object/prerequisite files
# DEFAULT_ENV default environment to build (release/debug/profile)
# OUTPUT_DIR default output directory (defaults to current directory)
# OUTPUT_BIN_DIR directory for generated binaries (defaults to OUTPUT_DIR)
# OUTPUT_LIB_DIR directory for generated libraries (defaults to OUTPUT_DIR)
# CLEAN_EXTRA extra files to delete for 'clean' target
# CLOBBER_EXTRA extra files to delete for 'clobber' target
# SUBDIRS sub-directories to also make with base targets
# SYMLINKS symlinks to create for building
# (list of <name> OR <name>=<target>; default target is '.')
# SOURCE_DIR source files base directory
# EXCLUDE_TARGETS labels/files not built by default (wildcard '*' allowed)
#
# Settings STANDARD/OPT_LEVEL/OPT_LEVEL_DEBUG/SUBSYSTEM/PACKAGES/INCLUDE/
# LIBS/DEFINE/OPTIONS/FLAGS/RPATH/LINKER/LINK_FLAGS/SOURCE_DIR/
# WARN/WARN_C/WARN_CXX can be set for specific targets to override global
# values (ex.: BIN1.FLAGS = -pthread).
# A value of '-' can be used to clear the setting for the target
# (note that FLAGS_RELEASE/FLAGS_DEBUG/FLAGS_PROFILE are always applied)
#
# Filename wildcards '*' or '**'(directory hierarchy search) supported
# for .SRC/.DEPS/.OBJS/CLEAN_EXTRA/CLOBBER_EXTRA settings
#
# <X>.LIBS/<X>.OBJS can accept LIB labels of library targets. Library
# LIBS/PACKAGES/binary will automatically be used in target building.
# LIBS will perfer shared library for linking if available, OBJS will only
# allow linking with static libraries.
# ex.: BIN1.LIBS = LIB1
#
# <X>.DEPS can accept BIN labels of binary targets. This can be used to make
# sure a binary is built before a file target command (that requires the
# binary) is executed.
# ex.: FILE1.DEPS = BIN1 data_file.txt
# FILE1.CMD = ./$(DEP1) $(DEP2)
#
# <X>.SRC2 can be used where <X>.SRC is allowed to specify source for a target
# that doesn't use SOURCE_DIR for location.
#
# Output Variables:
# ENV current build environment
# SFX current build environment binary suffix
# BUILD_TMP build environment specific temporary directory
# ALL_FILES all FILEx targets (useful for .DEPS rule on specific targets)
# <X>.ALL_FILES all FILEx targets from a specific template
# LIBPREFIX name prefix for libraries (usually 'lib')
#
#### Make Version & Multi-include Check ####
_min_ver := 4.2
MAKE_VERSION ?= 1.0
ifeq ($(filter $(_min_ver),$(firstword $(sort $(MAKE_VERSION) $(_min_ver)))),)
$(error GNU make version $(_min_ver) or later required)
endif
ifdef _makefile_already_included
$(error $(lastword $(MAKEFILE_LIST)) included multiple times)
endif
override _makefile_already_included := 1
#### Shell Commands ####
SHELL = /bin/sh
PKGCONF ?= pkg-config
RM ?= rm -f --
#### Default Make Flags ####
ifneq ($(shell which nproc 2>/dev/null),)
override _threads := $(shell nproc)
override GNUMAKEFLAGS += --load-average=$(_threads)
endif
#### OS Specific Values ####
override _uname := $(shell uname -s | tr A-Z a-z)
override _windows := $(filter cygwin% mingw% msys%,$(_uname))
override _linux := $(filter linux%,$(_uname))
override _pic_flag := $(if $(_windows),,-fPIC)
override _libprefix := $(if $(filter cygwin%,$(_uname)),cyg,$(if $(filter msys%,$(_uname)),msys-,lib))
override _libext := .$(if $(_windows),dll,so)
override _binext := $(if $(_windows),.exe)
ifneq ($(_windows),)
$(foreach x,$(filter WINDOWS.%,$(.VARIABLES)),\
$(eval override $(patsubst WINDOWS.%,%,$x) = $(value $x)))
else ifneq ($(_linux),)
$(foreach x,$(filter LINUX.%,$(.VARIABLES)),\
$(eval override $(patsubst LINUX.%,%,$x) = $(value $x)))
endif
#### Basic Settings ####
OPT_LEVEL ?= 3
OPT_LEVEL_DEBUG ?= g
BUILD_DIR ?= build
ifneq ($(strip $(WARN)),-)
ifneq ($(strip $(WARN)),)
# override default warnings
WARN_C ?= $(WARN)
WARN_CXX ?= $(WARN)
else
# default warnings
override _common_warn := all extra missing-include-dirs no-unused-parameter
WARN_C ?= $(_common_warn) write-strings $(_$(_compiler)_warn)
WARN_CXX ?= $(_common_warn) non-virtual-dtor overloaded-virtual $(_$(_compiler)_warn)
endif
endif
# default values to be more obvious if used/handled improperly
override ENV := ENV_NOT_SET
override SFX := SFX_NOT_SET
override BUILD_TMP := BUILD_TMP_NOT_SET
override LIBPREFIX := lib
# apply *_EXTRA setting values
# (CLEAN_EXTRA/CLOBBER_EXTRA/WARN_EXTRA handled elsewhere)
$(foreach x,WARN_C WARN_CXX PACKAGES PACKAGES_TEST INCLUDE INCLUDE_TEST LIBS LIBS_TEST DEFINE DEFINE_TEST OPTIONS OPTIONS_TEST FLAGS FLAGS_TEST FLAGS_RELEASE FLAGS_DEBUG FLAGS_PROFILE RPATH LINK_FLAGS EXCLUDE_TARGETS,\
$(if $(strip $($x_EXTRA)),$(eval override $x += $($x_EXTRA))))
# prevent duplicate options being applied to tests
override OPTIONS_TEST := $(filter-out $(OPTIONS),$(OPTIONS_TEST))
#### Terminal Output ####
# _fg1 - binary/library built
# _fg2 - warning or removal notice
# _fg3 - test passed
# _fg4 - test failed or fatal error
ifneq ($(and $(MAKE_TERMOUT),$(MAKE_TERMERR)),)
ifneq ($(shell which setterm 2>/dev/null),)
override _bold := $(shell setterm --bold on)
override _fg0 := $(shell setterm --foreground default)
override _fg1 := $(shell setterm --foreground cyan)
override _fg2 := $(shell setterm --foreground magenta)
override _fg3 := $(shell setterm --foreground green)
override _fg4 := $(shell setterm --foreground red)
override _end := $(shell setterm --default)
else
override _bold := $(shell echo -e '\e[1m')
override _fg0 := $(shell echo -e '\e[39m')
override _fg1 := $(shell echo -e '\e[36m')
override _fg2 := $(shell echo -e '\e[35m')
override _fg3 := $(shell echo -e '\e[32m')
override _fg4 := $(shell echo -e '\e[31m')
override _end := $(shell echo -e '\e[m')
endif
override _msgInfo := $(_bold)$(_fg1)
override _msgWarn := $(_bold)$(_fg2)
override _msgErr := $(_bold)$(_fg4)
endif
#### Environment Details ####
override _env_names := release debug profile
override _default_env := $(or $(strip $(DEFAULT_ENV)),$(firstword $(_env_names)))
ifeq ($(filter $(_default_env),$(_env_names)),)
$(error $(_msgErr)DEFAULT_ENV: invalid value$(_end))
endif
MAKECMDGOALS ?= $(_default_env)
override _opt_lvl = $(or $(strip $($1.OPT_LEVEL)),$(strip $(OPT_LEVEL)))
override _debug_opt_lvl = $(or $(strip $($1.OPT_LEVEL_DEBUG)),$(strip $(OPT_LEVEL_DEBUG)))
override _release_uc := RELEASE
override _release_sfx :=
override _release_opt = $(if $(_opt_lvl),-O$(_opt_lvl))
override _debug_uc := DEBUG
override _debug_sfx := -g
override _debug_opt = -g $(if $(_debug_opt_lvl),-O$(_debug_opt_lvl))
override _profile_uc := PROFILE
override _profile_sfx := -pg
override _profile_opt = -pg $(if $(_opt_lvl),-O$(_opt_lvl))
#### Compiler Details ####
override _compiler_names := gcc clang
override _modern_flags := -Wzero-as-null-pointer-constant -Wregister -Wold-style-cast
override _gcc_cxx := g++
override _gcc_cc := gcc
override _gcc_as := gcc -x assembler-with-cpp
override _gcc_ar := gcc-ar
override _gcc_warn := shadow=local
override _gcc_modern := $(_modern_flags) -Wsuggest-override
override _clang_cxx := clang++
override _clang_cc := clang
override _clang_as := clang -x assembler-with-cpp
override _clang_ar := llvm-ar
override _clang_ld := lld
override _clang_warn := shadow
override _clang_modern := $(_modern_flags) -Winconsistent-missing-override
# compiler source file patterns
override _cxx_ptrn := %.cc %.cp %.cxx %.cpp %.CPP %.c++ %.C
override _c_ptrn := %.c
override _asm_ptrn := %.s %.S %.sx
override _rc_ptrn := %.rc
# source files to ignore
override _src_filter := $(if $(_windows),,$(_rc_ptrn))\
%.h %.hh %.H %.hp %.hxx %.hpp %.HPP %.h++ %.tcc
# compiler allowed standards
override _c_stds := c90 gnu90 c99 gnu99 c11 gnu11 c17 gnu17 c18 gnu18 c2x gnu2x c23 gnu23
override _cxx_stds := c++98 gnu++98 c++03 gnu++03 c++11 gnu++11 c++14 gnu++14 c++17 gnu++17 c++2a gnu++2a c++20 gnu++20 c++2b gnu++2b c++23 gnu++23 c++2c gnu++2c c++26 gnu++26
# compiler functions
override define _check_compiler # <1:compiler name var>
ifneq ($$(strip $$($1)),)
ifeq ($$(filter $$($1),$$(_compiler_names)),)
$$(error $$(_msgErr)$1: unsupported compiler '$$($1)'$$(_end))
endif
endif
endef
override define _check_standard # <1:standard var> <2:set prefix>
override $2_cxx_std := $$(addprefix -std=,$$(filter $$($1),$$(_cxx_stds)))
ifeq ($$(filter 0 1,$$(words $$($2_cxx_std))),)
$$(error $$(_msgErr)$1: multiple C++ standards not allowed$$(_end))
endif
override $2_c_std := $$(addprefix -std=,$$(filter $$($1),$$(_c_stds)))
ifeq ($$(filter 0 1,$$(words $$($2_c_std))),)
$$(error $$(_msgErr)$1: multiple C standards not allowed$$(_end))
endif
ifneq ($$(filter-out $$(_cxx_stds) $$(_c_stds),$$($1)),)
$$(error $$(_msgErr)$1: unknown '$$(filter-out $$(_cxx_stds) $$(_c_stds),$$($1))'$$(_end))
endif
endef
#### Package Handling ####
# syntax: (<target>.)PACKAGES = <pkg name>(:<min version>) ...
override _pkg_n = $(word 1,$(subst :, ,$1))
override _pkg_v = $(word 2,$(subst :, ,$1))
override _check_pkgs =\
$(foreach x,$($1),\
$(if $(shell $(PKGCONF) $(call _pkg_n,$x) $(if $(call _pkg_v,$x),--atleast-version=$(call _pkg_v,$x),--exists) && echo '1'),\
$(call _pkg_n,$x),\
$(warning $(_msgWarn)$1: package '$(call _pkg_n,$x)'$(if $(call _pkg_v,$x), [version >= $(call _pkg_v,$x)]) not found$(_end))))
override _get_pkg_flags = $(if $1,$(shell $(PKGCONF) $1 --cflags))
override _get_pkg_libs = $(if $1,$(shell $(PKGCONF) $1 --libs))
override define _verify_pkgs # <1:config pkgs var> <2:valid pkgs>
ifeq ($$(strip $$($1)),)
else ifeq ($$(strip $$($1)),-)
else ifneq ($$(words $$($1)),$$(words $$($2)))
$$(error $$(_msgErr)Cannot build because of package error$$(_end))
endif
endef
#### OPTIONS handling ####
override _op_list := warn_error pthread lto modern_c++ no_rtti no_except pedantic static_rtlib static_stdlib mapfile
override define _check_options # <1:options var> <2:set prefix>
ifneq ($$(strip $$($1)),)
ifneq ($$(filter-out $$(_op_list),$$($1)),)
$$(error $$(_msgErr)$1: unknown '$$(filter-out $$(_op_list),$$($1))'$$(_end))
endif
override $2_warn :=\
$$(if $$(filter warn_error,$$($1)),-Werror)\
$$(if $$(filter pedantic,$$($1)),-Wpedantic)
override $2_flags :=\
$$(if $$(filter pthread,$$($1)),-pthread)\
$$(if $$(filter lto,$$($1)),-flto=auto)\
$$(if $$(filter pedantic,$$($1)),-pedantic-errors)
override $2_link :=\
$$(if $$(filter static_rtlib,$$($1)),-static-libgcc)
override $2_cxx_warn := $$($2_warn)\
$$(if $$(filter modern_c++,$$($1)),$$(_$(_compiler)_modern))
override $2_cxx_flags := $$($2_flags)\
$$(if $$(filter no_rtti,$$($1)),-fno-rtti)\
$$(if $$(filter no_except,$$($1)),-fno-exceptions)
override $2_cxx_link := $$($2_link)\
$$(if $$(filter static_stdlib,$$($1)),-static-libstdc++)
endif
endef
#### Internal Calculated Values ####
override _comma := ,
override _1-9 := 1 2 3 4 5 6 7 8 9
override _10-99 := $(foreach x,$(_1-9),$(addprefix $x,0 $(_1-9)))
override _1-99 := $(_1-9) $(_10-99)
override _1-999 := $(_1-99) $(foreach x,$(_1-9),$(addprefix $x,$(addprefix 0,0 $(_1-9)) $(_10-99)))
# TEMPLATE<1-99>, TEMPLATE_<id> labels
override _template_labels1 := $(filter $(sort $(foreach x,$(filter TEMPLATE%,$(.VARIABLES)),$(word 1,$(subst ., ,$x)))),$(addprefix TEMPLATE,$(_1-99)))
override _template_labels2 := $(sort $(foreach x,$(filter TEMPLATE_%,$(.VARIABLES)),$(if $(findstring .,$x),$(word 1,$(subst ., ,$x)))))
override _template_labels := $(strip $(_template_labels1) $(_template_labels2))
# verify template configs
override define _check_template_entry # <1:label>
override _$1_labels := $$(subst $1.,,$$(filter $1.FILE%,$$(.VARIABLES)))
ifeq ($$(_$1_labels),)
$$(error $$(_msgErr)$1: no FILE entries$$(_end))
else ifeq ($$(strip $$($1)),)
$$(error $$(_msgErr)$1 required$$(_end))
else ifeq ($$(strip $$($1.CMD)),)
$$(error $$(_msgErr)$1.CMD required$$(_end))
endif
endef
$(foreach x,$(_template_labels),$(eval $(call _check_template_entry,$x)))
ifneq ($(words $(foreach t,$(_template_labels),$($t_labels))),$(words $(sort $(foreach t,$(_template_labels),$($t_labels)))))
$(error $(_msgErr)Multiple templates contain the same FILE entry$(_end))
endif
# create file entries from templates
$(foreach t,$(_template_labels),\
$(foreach x,$(_$t_labels),\
$(eval override VALS := $$($t.$x))\
$(foreach n,$(wordlist 1,$(words $(VALS)),$(_1-99)),\
$(eval override VAL$n := $$(word $n,$$(VALS))))\
$(eval override $x = $($t))\
$(eval override $x.DEPS = $($t.DEPS))\
$(eval override $x.CMD = $($t.CMD))))
# LIB<1-99>, LIB_<id> labels (<id> is the default target)
override _lib_labels1 := $(filter $(sort $(foreach x,$(filter LIB%,$(.VARIABLES)),$(word 1,$(subst ., ,$x)))),$(addprefix LIB,$(_1-99)))
override _lib_labels2 := $(sort $(foreach x,$(filter LIB_%,$(.VARIABLES)),$(if $(findstring .,$x),$(word 1,$(subst ., ,$x)))))
$(foreach x,$(_lib_labels2),$(eval $x ?= $(subst LIB_,,$x)))
override _lib_labels := $(strip $(_lib_labels1) $(_lib_labels2))
override _static_lib_labels := $(strip $(foreach x,$(_lib_labels),$(if $($x.TYPE),$(if $(filter static,$($x.TYPE)),$x),$x)))
override _shared_lib_labels := $(strip $(foreach x,$(_lib_labels),$(if $(filter shared,$($x.TYPE)),$x)))
# BIN<1-99>, BIN_<id> labels (<id> is the default target)
override _bin_labels1 := $(filter $(sort $(foreach x,$(filter BIN%,$(.VARIABLES)),$(word 1,$(subst ., ,$x)))),$(addprefix BIN,$(_1-99)))
override _bin_labels2 := $(sort $(foreach x,$(filter BIN_%,$(.VARIABLES)),$(if $(findstring .,$x),$(word 1,$(subst ., ,$x)))))
$(foreach x,$(_bin_labels2),$(eval $x ?= $(subst BIN_,,$x)))
override _bin_labels := $(strip $(_bin_labels1) $(_bin_labels2))
# FILE<1-999>, FILE_<id> labels
override _file_labels1 := $(filter $(sort $(foreach x,$(filter FILE%,$(.VARIABLES)),$(word 1,$(subst ., ,$x)))),$(addprefix FILE,$(_1-999)))
override _file_labels2 := $(sort $(foreach x,$(filter FILE_%,$(.VARIABLES)),$(if $(findstring .,$x),$(word 1,$(subst ., ,$x)))))
override _file_labels := $(strip $(_file_labels1) $(_file_labels2))
# TEST<1-999>, TEST_<id> labels
override _test_labels1 := $(filter $(sort $(foreach x,$(filter TEST%,$(.VARIABLES)),$(word 1,$(subst ., ,$x)))),$(addprefix TEST,$(_1-999)))
override _test_labels2 := $(sort $(foreach x,$(filter TEST_%,$(.VARIABLES)),$(if $(findstring .,$x),$(word 1,$(subst ., ,$x)))))
override _test_labels := $(strip $(_test_labels1) $(_test_labels2))
override _src_labels := $(strip $(_lib_labels) $(_bin_labels) $(_test_labels))
override _all_labels := $(strip $(_src_labels) $(_file_labels))
override _subdir_targets := $(foreach e,$(_env_names),$e tests_$e clean_$e) clobber install install-strip
override _base_targets := all tests info help .gitignore clean $(_subdir_targets)
# strip extra spaces from all names
$(foreach x,$(_all_labels),$(if $($x),$(eval override $x = $(strip $(value $x)))))
# output name check
override define _check_name # <1:label>
ifeq ($$($1),)
$$(error $$(_msgErr)$1 required$$(_end))
else ifneq ($$(words $$($1)),1)
$$(error $$(_msgErr)$1: spaces not allowed$$(_end))
else ifneq ($$(findstring *,$$($1)),)
$$(error $$(_msgErr)$1: wildcard '*' not allowed$$(_end))
else ifneq ($$(filter $$($1),$$(_base_targets) $$(foreach e,$$(_env_names),$1$$(_$$e_sfx))),)
$$(error $$(_msgErr)$1: name conflicts with existing target$$(_end))
endif
endef
$(foreach x,$(_lib_labels) $(_bin_labels) $(_file_labels),$(eval $(call _check_name,$x)))
# target setting patterns
override _bin_ptrn := %.SRC %.SRC2 %.OBJS %.LIBS %.STANDARD %.OPT_LEVEL %.OPT_LEVEL_DEBUG %.DEFINE %.INCLUDE %.FLAGS %.RPATH %.LINKER %.LINK_FLAGS %.PACKAGES %.OPTIONS %.DEPS %.SUBSYSTEM %.SOURCE_DIR %.WARN %.WARN_C %.WARN_CXX
override _lib_ptrn := %.TYPE %.VERSION $(_bin_ptrn)
override _test_ptrn := %.ARGS $(_bin_ptrn)
# binary entry check
override define _check_bin_entry # <1:bin label>
$$(foreach x,$$(filter-out $$(_bin_ptrn),$$(filter $1.%,$$(.VARIABLES))),\
$$(warning $$(_msgWarn)Unknown binary parameter '$$x'$$(_end)))
ifneq ($$(filter %.exe,$$($1)),)
$$(error $$(_msgErr)$1: binary name should not be specified with an extension$$(_end))
endif
endef
$(foreach x,$(_bin_labels),$(eval $(call _check_bin_entry,$x)))
# library entry check
override define _check_lib_entry # <1:lib label>
$$(foreach x,$$(filter-out $$(_lib_ptrn),$$(filter $1.%,$$(.VARIABLES))),\
$$(warning $$(_msgWarn)Unknown library parameter '$$x'$$(_end)))
ifneq ($$(filter %.a %.so %.dll,$$($1)),)
$$(error $$(_msgErr)$1: library name should not be specified with an extension$$(_end))
else ifneq ($$(filter-out static shared,$$($1.TYPE)),)
$$(error $$(_msgErr)$1.TYPE: only 'static' and/or 'shared' allowed$$(_end))
endif
override _$1_version := $$(strip $$($1.VERSION))
ifeq ($$(filter 0 1,$$(words $$(_$1_version))),)
$$(error $$(_msgErr)$1.VERSION: bad value$$(_end))
endif
override _$1_major_ver := $$(word 1,$$(subst ., ,$$(_$1_version)))
override _$1_minor_ver := $$(word 2,$$(subst ., ,$$(_$1_version)))
endef
$(foreach x,$(_lib_labels),$(eval $(call _check_lib_entry,$x)))
# test entry check
override define _check_test_entry # <1:test label>
$$(foreach x,$$(filter-out $$(_test_ptrn),$$(filter $1.%,$$(.VARIABLES))),\
$$(warning $$(_msgWarn)Unknown test parameter '$$x'$$(_end)))
endef
$(foreach x,$(_test_labels),$(eval $(call _check_test_entry,$x)))
# file entry check
override define _check_file_entry # <1:file label>
$$(foreach x,$$(filter-out %.DEPS %.CMD,$$(filter $1.%,$$(.VARIABLES))),\
$$(warning $$(_msgWarn)Unknown file parameter '$$x'$$(_end)))
ifeq ($$(strip $$($1.CMD)),)
$$(error $$(_msgErr)$1.CMD required$$(_end))
endif
endef
$(foreach x,$(_file_labels),$(eval $(call _check_file_entry,$x)))
# macro to create object file name from source file (w/paths)
override _src_oname = $(foreach x,$1,$(addsuffix $(if $(filter $(_rc_ptrn),$x),.res,.o),$(subst /,__,$(subst ../,,$(basename $x)))))
# macro to get values that appear multiple times in a list (for error messages)
override _find_dups = $(strip $(foreach x,$(sort $1),$(if $(filter 1,$(words $(filter $x,$1))),,$x)))
# duplicate name check
override _all_names := $(foreach x,$(_lib_labels) $(_bin_labels) $(_file_labels),$($x))
ifneq ($(words $(_all_names)),$(words $(sort $(_all_names))))
$(error $(_msgErr)Duplicate binary/library/file names [$(_msgWarn)$(call _find_dups,$(_all_names))$(_msgErr)]$(_end))
endif
override define _check_dir # <1:dir var>
ifeq ($$(filter 0 1,$$(words $$($1))),)
$$(error $$(_msgErr)$1: spaces not allowed$$(_end))
else ifneq ($$(findstring *,$$($1)),)
$$(error $$(_msgErr)$1: wildcard '*' not allowed$$(_end))
else ifeq ($$(strip $$($1)),-)
$$(error $$(_msgErr)$1: invalid value$$(_end))
endif
endef
$(eval $(call _check_dir,BUILD_DIR))
override _build_dir := $(filter-out .,$(strip $(BUILD_DIR:%/=%)))
ifeq ($(_build_dir),)
$(error $(_msgErr)BUILD_DIR: invalid value$(_end))
endif
$(eval $(call _check_dir,OUTPUT_DIR))
$(eval $(call _check_dir,OUTPUT_BIN_DIR))
$(eval $(call _check_dir,OUTPUT_LIB_DIR))
override _output_bin_dir = $(patsubst %/,%,$(or $(strip $(OUTPUT_BIN_DIR)),$(strip $(OUTPUT_DIR))))
override _output_lib_dir = $(patsubst %/,%,$(or $(strip $(OUTPUT_LIB_DIR)),$(strip $(OUTPUT_DIR))))
# output dirs can contain variables like '$(ENV)'
$(eval $(call _check_dir,SOURCE_DIR))
override _source_dir = $(if $(SOURCE_DIR),$(filter-out ./,$(SOURCE_DIR:%/=%)/))
override _symlink_name = $(word 1,$(subst =, ,$1))
override _symlink_target = $(or $(word 2,$(subst =, ,$1)),.)
override _symlinks := $(sort $(SYMLINKS))
override _symlinks_names := $(sort $(foreach s,$(_symlinks),$(call _symlink_name,$s)))
ifneq ($(words $(_symlinks)),$(words $(_symlinks_names)))
$(error $(_msgErr)SYMLINKS: conflicting values$(_end))
endif
override _dir = $(filter-out ./,$(dir $1))
# output target name generation macros - <1:build env> <2:label>
override _gen_bin_name =\
$(if $(call _dir,$($2)),$($2)$(_$1_sfx),$(_$1_bdir)$(notdir $($2))$(_$1_bsfx))
override _gen_bin_aliases =\
$(if $(or $(_$1_bdir),$(call _dir,$($2))),$(notdir $($2))$(_$1_sfx)) \
$(if $(_binext),$(call _gen_bin_name,$1,$2)$(_binext))
override _base_lib_name=\
$(if $(call _dir,$($2)),$($2)$(_$1_sfx),$(_$1_ldir)$(notdir $($2))$(_$1_lsfx))
override _gen_static_lib_name =\
$(call _base_lib_name,$1,$2).a
override _gen_static_lib_aliases =\
$(sort $(notdir $($2))$(_$1_sfx) $(call _base_lib_name,$1,$2)) \
$(if $(or $(_$1_ldir),$(call _dir,$($2))),$(notdir $($2))$(_$1_sfx).a)
override _gen_implib_name =\
$(call _base_lib_name,$1,$2).dll.a
override _gen_shared_lib_name =\
$(if $(_windows),\
$(call _gen_bin_name,$1,$2)$(if $(_$2_major_ver),-$(_$2_major_ver)).dll,\
$(call _base_lib_name,$1,$2).so$(if $(_$2_version),.$(_$2_version)))
override _gen_shared_lib_linkname =\
$(if $(_windows),\
$(call _gen_bin_name,$1,$2)$(if $(_$2_major_ver),-$(_$2_major_ver)).dll,\
$(call _base_lib_name,$1,$2).so$(if $(_$2_major_ver),.$(_$2_major_ver)))
override _gen_shared_lib_aliases =\
$(sort $(notdir $($2))$(_$1_sfx) $(if $(_windows),$(call _gen_bin_name,$1,$2),$(call _base_lib_name,$1,$2))) \
$(if $(or $(if $(_windows),$(_$1_bdir),$(_$1_ldir)),$(call _dir,$($2)),$(_$2_version)),$(notdir $($2))$(_$1_sfx)$(_libext))
override _gen_shared_lib_links =\
$(if $(_windows),,\
$(if $(_$2_version),$(call _base_lib_name,$1,$2).so \
$(if $(_$2_minor_ver),$(call _base_lib_name,$1,$2).so.$(_$2_major_ver))))
# environment specific setup
override define _setup_env0 # <1:build env>
override ENV := $1
override SFX := $$(_$1_sfx)
override BUILD_TMP := $$(_build_dir)/$1_tmp
override _$1_bdir := $$(if $$(_output_bin_dir),$$(_output_bin_dir)/)
override _$1_ldir := $$(if $$(_output_lib_dir),$$(_output_lib_dir)/)
endef
$(foreach e,$(_env_names),$(eval $(call _setup_env0,$e)))
# <1:build env> <2:label/file pattern>
override _gen_filter_targets =\
$(foreach x,$(filter $2,$(_bin_labels)),$(call _gen_bin_name,$1,$x) $(call _gen_bin_aliases,$1,$x))\
$(foreach x,$(filter $2,$(_static_lib_labels)),$(call _gen_static_lib_name,$1,$x) $(call _gen_static_lib_aliases,$1,$x))\
$(foreach x,$(filter $2,$(_shared_lib_labels)),$(call _gen_shared_lib_name,$1,$x) $(call _gen_shared_lib_aliases,$1,$x))\
$(foreach x,$(filter $2,$(_file_labels)),$($x))\
$(foreach x,$(filter $2,$(_test_labels)),$x$(_$1_sfx)) $2
override define _setup_env1 # <1:build env>
override ENV := $1
override SFX := $$(_$1_sfx)
override BUILD_TMP := $$(_build_dir)/$1_tmp
override _$1_lsfx := $$(if $$(filter 1,$$(words $$(filter $$(_$1_ldir),$$(foreach e,$$(_env_names),$$(_$$e_ldir))))),,$$(_$1_sfx))
override _$1_bsfx := $$(if $$(filter 1,$$(words $$(filter $$(_$1_bdir),$$(foreach e,$$(_env_names),$$(_$$e_bdir))))),,$$(_$1_sfx))
ifneq ($(_libprefix),lib)
override LIBPREFIX := $(_libprefix)
endif
override _$1_shared_libs := $$(foreach x,$$(_shared_lib_labels),$$(call _gen_shared_lib_name,$1,$$x))
override _$1_shared_aliases := $$(foreach x,$$(_shared_lib_labels),$$(call _gen_shared_lib_aliases,$1,$$x))
override _$1_links := $$(foreach x,$$(_shared_lib_labels),$$(call _gen_shared_lib_links,$1,$$x))
ifneq ($(_libprefix),lib)
override LIBPREFIX := lib
endif
ifneq ($(_windows),)
override _$1_implibs := $$(foreach x,$$(_shared_lib_labels),$$(call _gen_implib_name,$1,$$x))
endif
override _$1_lib_targets :=\
$$(_$1_shared_libs) $$(_$1_implibs)\
$$(foreach x,$$(_static_lib_labels),$$(call _gen_static_lib_name,$1,$$x))
override _$1_bin_targets :=\
$$(foreach x,$$(_bin_labels),$$(call _gen_bin_name,$1,$$x))
override _$1_file_targets := $$(foreach x,$$(_file_labels),$$($$x))
override _$1_test_targets := $$(foreach x,$$(_test_labels),$$x$$(_$1_sfx))
override _$1_build_targets := $$(_$1_file_targets) $$(_$1_lib_targets) $$(_$1_bin_targets) $$(_$1_test_targets)
override _$1_filter_targets :=\
$$(foreach x,$$(EXCLUDE_TARGETS),$$(call _gen_filter_targets,$1,$$(subst *,%,$$x)))
override _$1_aliases :=\
$$(foreach x,$$(_all_labels),$$x$$(_$1_sfx))\
$$(foreach x,$$(_bin_labels),$$(call _gen_bin_aliases,$1,$$x))\
$$(foreach x,$$(_static_lib_labels),$$(call _gen_static_lib_aliases,$1,$$x))\
$$(_$1_shared_aliases)
endef
$(foreach e,$(_env_names),$(eval $(call _setup_env1,$e)))
override _filter_targets := $(sort $(foreach e,$(_env_names),$(_$e_filter_targets)))
override define _setup_env2 # <1:build env>
override _$1_build2_targets := $$(filter-out $$(_filter_targets),$$(_$1_build_targets))
override _$1_test2_targets := $$(filter-out $$(_filter_targets),$$(_$1_test_targets))
override _$1_goals := $$(sort\
$$(if $$(filter $$(if $$(filter $1,$$(_default_env)),all) $1,$$(MAKECMDGOALS)),$$(_$1_build2_targets))\
$$(if $$(filter $$(if $$(filter $1,$$(_default_env)),tests) tests_$1,$$(MAKECMDGOALS)),$$(_$1_test2_targets))\
$$(filter $$(_$1_build_targets) $$(sort $$(_$1_aliases)),$$(MAKECMDGOALS)))
endef
$(foreach e,$(_env_names),$(eval $(call _setup_env2,$e)))
# setting value processing functions
override _format_warn = $(foreach x,$1,$(if $(filter -%,$x),$x,-W$x))
override _format_include = $(foreach x,$1,$(if $(filter -%,$x),$x,-I$x))
override _format_define = $(foreach x,$1,$(if $(filter -%,$x),$x,-D'$x'))
override _format_lib_arg =\
$(if $(filter -% %.a,$1),$1,\
$(if $(filter ./,$(dir $1)),,-L$(patsubst %/,%,$(dir $1))) -l$(if $(or $(filter %.so %.dll,$1),$(findstring .so.,$1)),:)$(notdir $1))
override _format_libs = $(foreach x,$1,\
$(call _format_lib_arg,$(if $(filter $x,$(_lib_labels)),$(or $(_$x_shared_linkname),$(_$x_name)),$x)))
# _do_wildcard: <1:file> <2:basedir>
override _do_wildcard =\
$(if $(filter %/**/ **/,$(dir $1)),$(patsubst $(or $2,./)%,%,$(shell find $2$(patsubst %**/,%,$(dir $1)) -name '$(notdir $1)')),\
$(if $(findstring **,$(notdir $1)),$(patsubst $(or $2,./)%,%,$(shell find $2$(call _dir,$1) -name '$(notdir $1)')),\
$(if $(findstring *,$1),$(patsubst $2%,%,$(wildcard $2$1)),$1)))
# build environment detection
override _build_env := $(strip $(foreach e,$(_env_names),$(if $(_$e_goals),$e)))
ifeq ($(filter 0 1,$(words $(_build_env))),)
$(error $(_msgErr)Targets in multiple environments not allowed$(_end))
else ifneq ($(_build_env),)
# setup build targets/variables for selected environment
override ENV := $(_build_env)
override SFX := $(_$(ENV)_sfx)
override BUILD_TMP := $(_build_dir)/$(ENV)_tmp
override ALL_FILES := $(foreach x,$(_file_labels),$($x))
$(foreach t,$(_template_labels),\
$(eval override $t.ALL_FILES := $(foreach x,$(_$t_labels),$($x))))
# compiler command setup
$(eval $(call _check_compiler,COMPILER))
override _compiler := $(or $(strip $(COMPILER)),$(firstword $(_compiler_names)))
override _cross_compile := $(strip $(CROSS_COMPILE))
override _cxx := $(_cross_compile)$(or $(_$(_compiler)_cxx),c++)
override _cc := $(_cross_compile)$(or $(_$(_compiler)_cc),cc)
override _as := $(_cross_compile)$(or $(_$(_compiler)_as),as)
override _ar := $(_cross_compile)$(or $(_$(_compiler)_ar),ar)
ifneq ($(strip $(LINKER)),-)
ifneq ($(strip $(LINKER)),ld)
override _linker := $(or $(strip $(LINKER)),$(_$(_compiler)_ld))
endif
endif
$(eval $(call _check_standard,STANDARD,))
$(eval $(call _check_options,OPTIONS,_op))
$(eval $(call _check_options,OPTIONS_TEST,_op_test))
override _pkgs := $(call _check_pkgs,PACKAGES)
override _pkgs_test := $(call _check_pkgs,PACKAGES_TEST)
override _define := $(call _format_define,$(DEFINE))
override _define_test := $(call _format_define,$(DEFINE_TEST))
override _include := $(call _format_include,$(INCLUDE))
override _include_test := $(call _format_include,$(INCLUDE_TEST))
override _warn_cxx := $(call _format_warn,$(WARN_CXX) $(WARN_EXTRA))
override _warn_c := $(call _format_warn,$(WARN_C) $(WARN_EXTRA))
# setup compile flags for each build path
override _pkg_flags := $(call _get_pkg_flags,$(sort $(_pkgs)))
override _xflags := $(_pkg_flags) $(FLAGS_$(_$(ENV)_uc)) $(FLAGS)
override _cxxflags_$(ENV) := $(strip $(_cxx_std) $(_$(ENV)_opt) $(_warn_cxx) $(_op_cxx_warn) $(_define) $(_include) $(_op_cxx_flags) $(_xflags))
override _cflags_$(ENV) := $(strip $(_c_std) $(_$(ENV)_opt) $(_warn_c) $(_op_warn) $(_define) $(_include) $(_op_flags) $(_xflags))
override _asflags_$(ENV) := $(strip $(_$(ENV)_opt) $(_op_warn) $(_define) $(_include) $(_op_flags) $(_xflags))
override _rcflags_$(ENV) := $(filter -D% -U% -I%,$(_define) $(_include) $(_op_flags) $(_xflags))
override _src_path_$(ENV) := $(_source_dir)
ifneq ($(_test_labels),)
override _test_xflags := $(if $(_pkgs_test),$(call _get_pkg_flags,$(sort $(_pkgs) $(_pkgs_test))),$(_pkg_flags)) $(FLAGS_$(_$(ENV)_uc)) $(FLAGS) $(FLAGS_TEST)
override _cxxflags_$(ENV)-tests := $(strip $(_cxx_std) $(_$(ENV)_opt) $(_warn_cxx) $(_op_cxx_warn) $(_op_test_cxx_warn) $(_define) $(_define_test) $(_include) $(_include_test) $(_op_cxx_flags) $(_op_test_cxx_flags) $(_test_xflags))
override _cflags_$(ENV)-tests := $(strip $(_c_std) $(_$(ENV)_opt) $(_warn_c) $(_op_warn) $(_op_test_warn) $(_define) $(_define_test) $(_include) $(_include_test) $(_op_flags) $(_op_test_flags) $(_test_xflags))
override _asflags_$(ENV)-tests := $(strip $(_$(ENV)_opt) $(_op_warn) $(_op_test_warn) $(_define) $(_define_test) $(_include) $(_include_test) $(_op_flags) $(_op_test_flags) $(_test_xflags))
override _rcflags_$(ENV)-tests := $(filter -D% -U% -I%,$(_define) $(_define_test) $(_include) $(_include_test) $(_op_flags) $(_op_test_flags) $(_test_xflags))
override _src_path_$(ENV)-tests := $(_src_path_$(ENV))
endif
## entry name & alias target assignment
$(foreach x,$(_file_labels),\
$(eval override _$x_name := $($x))\
$(eval override _$x_aliases := $x$(SFX) $(if $(SFX),$x)))
$(foreach x,$(_bin_labels),\
$(eval override _$x_name := $(call _gen_bin_name,$(ENV),$x))\
$(eval override _$x_aliases := $x$(SFX) $(if $(SFX),$x $($x)) $(call _gen_bin_aliases,$(ENV),$x)))
$(foreach x,$(_static_lib_labels),\
$(eval override _$x_name := $(call _gen_static_lib_name,$(ENV),$x))\
$(eval override _$x_aliases := $x$(SFX) $(if $(SFX),$x $($x) $($x).a) $(call _gen_static_lib_aliases,$(ENV),$x)))
ifneq ($(_libprefix),lib)
override LIBPREFIX := $(_libprefix)
endif
$(foreach x,$(_shared_lib_labels),\
$(eval override _$x_shared_name := $(call _gen_shared_lib_name,$(ENV),$x))\
$(eval override _$x_shared_linkname := $(call _gen_shared_lib_linkname,$(ENV),$x))\
$(eval override _$x_shared_aliases := $x$(SFX) $(if $(SFX),$x $($x) $($x)$(_libext)) $(call _gen_shared_lib_aliases,$(ENV),$x))\
$(if $(_windows),,\
$(eval override _$x_soname := $(if $(_$x_major_ver),$(notdir $($x)).so.$(_$x_major_ver)))\
$(eval override _$x_shared_links := $(call _gen_shared_lib_links,$(ENV),$x))))
ifneq ($(_libprefix),lib)
override LIBPREFIX := lib
endif
$(if $(_windows),$(foreach x,$(_shared_lib_labels),\
$(eval override _$x_implib := $(call _gen_implib_name,$(ENV),$x))))
# .DEPS wildcard & BIN/FILE label translation
$(foreach x,$(_all_labels),$(eval override _$x_deps := $(foreach d,$($x.DEPS),\
$(if $(filter $d,$(_bin_labels) $(_file_labels)),$(_$d_name),$(call _do_wildcard,$d,)))))
## general entry setting parsing (pre)
override define _build_entry1 # <1:label> <2:test flag>
ifneq ($$(strip $$($1.SOURCE_DIR)),-)
$$(eval $$(call _check_dir,$1.SOURCE_DIR))
override _$1_source_dir := $$(if $$($1.SOURCE_DIR),$$(filter-out ./,$$($1.SOURCE_DIR:%/=%)/))
override _src_path_$$(ENV)-$1 := $$(or $$(_$1_source_dir),$$(_src_path_$$(ENV)))
endif
override _$1_src := $$(strip $$(filter-out $(_src_filter),$$(foreach x,$$($1.SRC),$$(call _do_wildcard,$$x,$$(_src_path_$$(ENV)-$1)))))
override _$1_src2 := $$(strip $$(filter-out $(_src_filter),$$(foreach x,$$($1.SRC2),$$(call _do_wildcard,$$x,))))
ifneq ($$(words $$(_$1_src) $$(_$1_src2)),$$(words $$(sort $$(_$1_src) $$(_$1_src2))))
$$(error $$(_msgErr)$1: duplicate source files [$$(_msgWarn)$$(call _find_dups,$$(_$1_src))$$(_msgErr)]$$(_end))
else ifneq ($$(filter-out $(_cxx_ptrn) $(_c_ptrn) $(_asm_ptrn) $(_rc_ptrn),$$(_$1_src) $$(_$1_src2)),)
$$(error $$(_msgErr)$1: invalid source files [$$(_msgWarn)$$(filter-out $(_cxx_ptrn) $(_c_ptrn) $(_asm_ptrn) $(_rc_ptrn),$$(_$1_src) $$(_$1_src2))$$(_msgErr)]$$(_end))
endif
ifneq ($$(findstring *,$$(filter-out $(_src_filter),$$($1.SRC))),)
ifeq ($$(_$1_src),)
$$(warning $$(_msgWarn)$1.SRC: no source files match pattern$$(_end))
endif
endif
ifneq ($$(findstring *,$$(filter-out $(_src_filter),$$($1.SRC2))),)
ifeq ($$(_$1_src2),)
$$(warning $$(_msgWarn)$1.SRC2: no source files match pattern$$(_end))
endif
endif
ifeq ($$(strip $$(_$1_src) $$(_$1_src2)),)
$$(error $$(_msgErr)$1: nothing to compile$$(_end))
endif
override _$1_lang :=\
$$(if $$(filter $(_cxx_ptrn),$$(_$1_src) $$(_$1_src2)),cxx)\
$$(if $$(filter $(_c_ptrn),$$(_$1_src) $$(_$1_src2)),c)\
$$(if $$(filter $(_asm_ptrn),$$(_$1_src) $$(_$1_src2)),asm)\
$$(if $$(filter $(_rc_ptrn),$$(_$1_src) $$(_$1_src2)),rc)
override _$1_src_objs := $$(call _src_oname,$$(_$1_src) $$(_$1_src2))
ifneq ($$(strip $$($1.OBJS)),-)
override _$1_objs := $$(filter-out $1,$$($1.OBJS))
override _$1_other_objs := $$(foreach x,$$(_$1_objs),$$(if $$(filter $$x,$$(_lib_labels)),\
$$(or $$(_$$x_name),$$(error $$(_msgErr)$1.OBJS: static type required for library '$$x'$$(_end))),$$(call _do_wildcard,$$x,)))
endif
ifneq ($$(strip $$($1.SUBSYSTEM)),-)
override _$1_subsystem := $(if $(_windows),$$(or $$($1.SUBSYSTEM),$$(SUBSYSTEM)))
endif
ifeq ($$(strip $$($1.LINKER)),)
override _$1_linker := $$(_linker)
else ifneq ($$(strip $$($1.LINKER)),-)
ifneq ($$(strip $$($1.LINKER)),ld)
override _$1_linker := $$(or $$(strip $$($1.LINKER)),$$(_$$(_compiler)_ld))
endif
endif
override _$1_link_flags := $$(if $$(_$1_linker),-fuse-ld=$$(_$1_linker))
ifneq ($$(strip $$($1.RPATH)),-)
override _$1_link_flags += $$(foreach x,$$(or $$($1.RPATH),$$(RPATH)),-Wl,-rpath=$$x)
endif
ifneq ($$(strip $$($1.LINK_FLAGS)),-)
override _$1_link_flags += $$(or $$($1.LINK_FLAGS),$$(LINK_FLAGS))
endif
ifeq ($$(strip $$($1.STANDARD)),)
override _$1_cxx_std := $$(_cxx_std)
override _$1_c_std := $$(_c_std)
else ifneq ($$(strip $$($1.STANDARD)),-)
$$(eval $$(call _check_standard,$1.STANDARD,_$1))
endif
ifeq ($$(strip $$($1.OPTIONS)),)
override _$1_options := $$(OPTIONS) $(if $2,$$(OPTIONS_TEST))
override _$1_op_warn := $$(_op_warn) $(if $2,$$(_op_test_warn))
override _$1_op_flags := $$(_op_flags) $(if $2,$$(_op_test_flags))
override _$1_op_link := $$(_op_link) $(if $2,$$(_op_test_link))
override _$1_op_cxx_warn := $$(_op_cxx_warn) $(if $2,$$(_op_test_cxx_warn))
override _$1_op_cxx_flags := $$(_op_cxx_flags) $(if $2,$$(_op_test_cxx_flags))
override _$1_op_cxx_link := $$(_op_cxx_link) $(if $2,$$(_op_test_cxx_link))
else ifneq ($$(strip $$($1.OPTIONS)),-)
override _$1_options := $$($1.OPTIONS)
$$(eval $$(call _check_options,$1.OPTIONS,_$1_op))
endif
ifneq ($$(strip $$($1.PACKAGES)),-)
override _$1_pkgs := $$(or $$(call _check_pkgs,$1.PACKAGES),$$(_pkgs) $(if $2,$$(_pkgs_test)))
endif
ifneq ($$(strip $$($1.LIBS)),-)
override _$1_libs := $$(filter-out $1,$$(or $$($1.LIBS),$$(LIBS) $(if $2,$$(LIBS_TEST))))
endif
ifneq ($$(strip $$($1.DEFINE)),-)
override _$1_define := $$(or $$(call _format_define,$$($1.DEFINE)),$$(_define) $(if $2,$$(_define_test)))
endif
ifneq ($$(strip $$($1.INCLUDE)),-)
override _$1_include := $$(or $$(call _format_include,$$($1.INCLUDE)),$$(_include) $(if $2,$$(_include_test)))
endif
ifneq ($$(strip $$($1.FLAGS)),-)
override _$1_flags := $$(or $$($1.FLAGS),$$(FLAGS) $(if $2,$$(FLAGS_TEST)))
endif
ifeq ($$(strip $$($1.WARN_C)),)
ifeq ($$(strip $$($1.WARN)),)
override _$1_warn_c := $$(_warn_c)
else ifneq ($$(strip $$($1.WARN)),-)
override _$1_warn_c := $$(call _format_warn,$$($1.WARN))
endif
else ifneq ($$(strip $$($1.WARN_C)),-)
override _$1_warn_c := $$(call _format_warn,$$($1.WARN_C))
endif
ifeq ($$(strip $$($1.WARN_CXX)),)
ifeq ($$(strip $$($1.WARN)),)
override _$1_warn_cxx := $$(_warn_cxx)
else ifneq ($$(strip $$($1.WARN)),-)
override _$1_warn_cxx := $$(call _format_warn,$$($1.WARN))
endif
else ifneq ($$(strip $$($1.WARN_CXX)),-)
override _$1_warn_cxx := $$(call _format_warn,$$($1.WARN_CXX))
endif
endef
$(foreach x,$(_lib_labels) $(_bin_labels),$(eval $(call _build_entry1,$x,)))
$(foreach x,$(_test_labels),$(eval $(call _build_entry1,$x,test)))
## general entry setting parsing (post)
override define _build_entry2 # <1:label>
override _$1_req_pkgs := $$(foreach x,$$(_$1_libs) $$(_$1_objs),$$(if $$(filter $$x,$$(_lib_labels)),$$(_$$x_pkgs)))
override _$1_req_libs := $$(filter-out $1,$$(foreach x,$$(_$1_libs) $$(_$1_objs),$$(if $$(filter $$x,$$(_lib_labels)),$$(_$$x_libs))))
override _$1_link_deps := $$(foreach x,$$(_$1_libs),$$(if $$(filter $$x,$$(_lib_labels)),$$(or $$(_$$x_shared_name),$$(_$$x_name))))
override _$1_xpkgs := $$(sort $$(_$1_pkgs) $$(_$1_req_pkgs))
ifneq ($$(_$1_xpkgs),)
override _$1_pkg_libs := $$(call _get_pkg_libs,$$(_$1_xpkgs))
override _$1_pkg_flags := $$(call _get_pkg_flags,$$(_$1_xpkgs))
endif
override _$1_xlibs := $$(call _format_libs,$$(_$1_libs) $$(_$1_req_libs))
# NOTE: PACKAGES libs after LIBS in case included static lib requires package
override _$1_xflags := $$(_$1_pkg_flags) $$(FLAGS_$$(_$$(ENV)_uc)) $$(_$1_flags)
override _cxxflags_$$(ENV)-$1 := $$(strip $$(_$1_cxx_std) $$(call _$$(ENV)_opt,$1) $$(_$1_warn_cxx) $$(_$1_op_cxx_warn) $$(_$1_define) $$(_$1_include) $$(_$1_op_cxx_flags) $$(_$1_xflags))
override _cflags_$$(ENV)-$1 := $$(strip $$(_$1_c_std) $$(call _$$(ENV)_opt,$1) $$(_$1_warn_c) $$(_$1_op_warn) $$(_$1_define) $$(_$1_include) $$(_$1_op_flags) $$(_$1_xflags))
override _asflags_$$(ENV)-$1 := $$(strip $$(call _$$(ENV)_opt,$1) $$(_$1_op_warn) $$(_$1_define) $$(_$1_include) $$(_$1_op_flags) $$(_$1_xflags))
override _rcflags_$$(ENV)-$1 := $$(filter -D% -U% -I%,$$(_$1_define) $$(_$1_include) $$(_$1_op_flags) $$(_$1_xflags))
override _$1_build := $$(ENV)-$1
ifeq ($$(_src_path_$$(ENV)-$1),$$(_src_path_$$(ENV)))
ifeq ($$(_$1_deps),)
# if compile flags match then use a shared build path
ifeq ($$(_cxxflags_$$(ENV)-$1),$$(_cxxflags_$$(ENV)-tests))
ifeq ($$(_cflags_$$(ENV)-$1),$$(_cflags_$$(ENV)-tests))
override _$1_build := $$(ENV)-tests
endif
endif
ifeq ($$(_cxxflags_$$(ENV)-$1),$$(_cxxflags_$$(ENV)))
ifeq ($$(_cflags_$$(ENV)-$1),$$(_cflags_$$(ENV)))
override _$1_build := $$(ENV)
endif
endif
endif
endif
override _$1_build_dir := $$(_build_dir)/$$(_$1_build)
override _$1_all_objs := $$(addprefix $$(_$1_build_dir)/,$$(_$1_src_objs))
endef
$(foreach x,$(_src_labels),$(eval $(call _build_entry2,$x)))
# NOTES:
# - <label>.DEPS can cause an isolated build even though there are no compile
# flag changes (target 'source.o : | dep' rules would affect other builds
# without isolation)
$(foreach x,$(_test_labels),\
$(eval override _$x_name := __$x)\
$(eval override _$x_aliases := $x$(SFX))\
$(eval override _$x_run := $(_$x_build_dir)/$(_$x_name)))
# halt build for package errors on non-test entries
$(eval $(call _verify_pkgs,PACKAGES,_pkgs))
$(foreach x,$(_bin_labels) $(_lib_labels),$(eval $(call _verify_pkgs,$x.PACKAGES,_$x_pkgs)))