-
Notifications
You must be signed in to change notification settings - Fork 0
/
Makefile
executable file
·668 lines (551 loc) · 23.3 KB
/
Makefile
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
#!/usr/bin/make -f
# fMakefile - Ready to use Makefile for simple Fortran projects,
# featuring automatic targets and prerequisites
#
# Copyright (c) 2019 André Chalella
# MIT License - see file LICENSE for full text
#
# fMakefile needs no modification to work with any simple Fortran project.
#
# As long as your project abides to the rules that define "simple" (explained
# below), you can just put this Makefile in your project root and run
#
# $ make
#
# to compile and link all your programs. You can also run
#
# $ make myprog
#
# to compile and link a program defined in a source file called 'myprog.f90'
# that resides anywhere in your source tree.
#
# fMakefile ground rules:
#
# 1) Each source file must contain one complete program or module.
# 2) Module names must be the same as their source file names.
# 3) Directory structure:
#
# PROJECT ROOT MAKEFILE VARIABLE DESCRIPTION
# ├── Makefile - This file (or its parent)
# ├── src SRCDIR Program sources
# │ └── mod MODDIR_SUFFIX Module sources
# ├── build BUILDDIR_PREFIX Binaries and .mod files
# └── dep DEPDIR Dependency Makefiles (.d)
#
# - 'build' and 'dep' are autogenerated.
# - All modules must be in 'mod', without subdirectories.
# - Programs may be in subdirectories in 'src' (except 'mod').
# - All names are customizable (vars above).
#
# Other minor rules:
#
# - You must call 'make' from the project root.
# - No spaces in file or directory names that fMakefile refers to.
# - That means no spaces in:
# - Source file names ('src/my program.f90');
# - Source tree subdirectories ('src/test programs/');
# - Variables SRCDIR, BUILDDIR_PREFIX, DEPDIR.
# - You CAN have spaces in your project root path, like this:
# /home/user/this is my project root/ <-- is okay
# /cygdrive/c/Documents and Settings/user/project <-- is okay
# - This is not a limitation of fMakefile, but of GNU make.
# - All source files must use the same suffix (extension), by default .f90
# (customizable in the FEXT variable).
# - Yes, suffix-based preprocessing cannot work. Use an appropriate
# compiler flag to enable it unconditionally (-cpp in gfortran).
#
# Features:
#
# - Dependency lookup through static source scan, with support for
# chained dependencies (a.mod uses b.mod uses c.mod...).
# - Automatic targets for fully building each individual source file.
# Examples: 'make main_prog', 'make mod_calculate', 'make test_fourier_8'
# - Colorized output for each build step.
# - Two sets of build configs (compiler/linker flags): DEBUG and RELEASE.
# - Customizable build flags, directory names etc.
#
# Feel free to customize this file. Most variables you'll want to change have
# UPPERCASE names. If you wish to modify the file further, make sure you
# understand where each thing fits first.
#
# Run "make stripmakefile" if you grow sick of these comments.
#####################
### CONFIGURATION ###
#####################
MAKEFLAGS += --no-builtin-rules
# We need bash since we use "-o pipefail" in .SHELLFLAGS
SHELL := /bin/bash
.SHELLFLAGS += -e -o pipefail
FC := gfortran
FEXT := f90
# ENV: BUILD=debug|release
BUILD ?= debug
AWK := awk
MKDIR := mkdir -p
RMDIR := rm -rf
# Colors for distinguishing the build steps from the myriad of build commands.
# Google "shell colors" for complete reference of color codes.
# Default is: HI Blue, HI Green, Yellow, HI White (HI = High Intensity).
COLOR_COMPILE := \e[94m
COLOR_LINK := \e[92m
COLOR_COPY := \e[33m
COLOR_DONE := \e[97m
COLOR_NONE := \e[0m
MSG_DONE = 'Finished making $@'
# DIRECTORY STRUCTURE VARIABLES
#
# . CUSTOMIZABLE VAR FULL PATH VARIABLE AUTOGENERATED?
# ├─ build BUILDDIR_PREFIX - yes
# │ └─ debug|release BUILD [env] builddir yes
# │ └─ mod see 'src' tree moddir yes
# ├─ dep DEPDIR - yes
# │ └─ mod see 'src' tree depmoddir yes
# └─ src SRCDIR - -
# └─ mod MODDIR_SUFFIX srcmoddir -
SRCDIR := src
DEPDIR := dep
BUILDDIR_PREFIX := build
MODDIR_SUFFIX := mod
srcmoddir := $(SRCDIR)/$(MODDIR_SUFFIX)
depmoddir := $(DEPDIR)/$(MODDIR_SUFFIX)
builddir := $(BUILDDIR_PREFIX)/$(BUILD)
moddir := $(builddir)/$(MODDIR_SUFFIX)
# All source files, with directories and extensions.
src_all := $(shell find $(SRCDIR) -type f -name '*.$(FEXT)')
src_progs := $(filter-out $(srcmoddir)/%,$(src_all))
src_mods := $(filter $(srcmoddir)/%,$(src_all))
# All source files, without directories or extensions ("basenames")
#
# "Basename" here means "filename without directories or suffixes (extensions)",
# that is: 'dir/dir/dir/basename.suffix.suffix' => 'basename'.
#
# I make that clear because the word has different meanings in different Unix
# contexts. For instance, in GNU make, the $(basename args) function only strips
# the last suffix, while in GNU coreutils the basename command by default strips
# only directories.
real_basename = $(basename $(notdir $(1)))
basename_progs := $(call real_basename,$(src_progs))
basename_progs_o := $(addsuffix .o,$(basename_progs))
basename_mods_o := $(addsuffix .o,$(call real_basename,$(src_mods)))
basename_all := $(basename_progs) $(basename_progs_o) $(basename_mods_o)
relpaths_progs_o := $(filter-out $(srcmoddir)/%,$(src_all:.$(FEXT)=.o))
relpaths_progs_o := $(patsubst $(SRCDIR)/%,%,$(relpaths_progs_o))
relpaths_mods_o := $(filter $(srcmoddir)/%,$(src_all:.$(FEXT)=.o))
relpaths_mods_o := $(patsubst $(SRCDIR)/%,%,$(relpaths_mods_o))
relpaths_progs := $(relpaths_progs_o:.o=)
relpaths_all := $(relpaths_progs) $(relpaths_progs_o) $(relpaths_mods_o)
dep_progs_d := $(patsubst $(SRCDIR)/%,$(DEPDIR)/%,$(src_progs:.$(FEXT)=.d))
dep_mods_d := $(patsubst $(SRCDIR)/%,$(DEPDIR)/%,$(src_mods:.$(FEXT)=.d))
dep_progs_d_d := $(addsuffix .d,$(dep_progs_d))
# reldirs shall contain the relative path (SRCDIR removed) of every subdir that
# has a source file somewhere, however deep, inside it.
#
# Note: sort in GNU make removes duplicates.
reldirs := $(sort $(dir $(patsubst $(SRCDIR)/%,%,$(src_all))))
reldirs := $(filter-out ./,$(reldirs))
reldirs := $(reldirs:/=)
reldirs := $(shell for reldir in $(reldirs); do \
IFS=/ i=; \
for j in $$reldir; do \
i=$$i/$$j; \
echo "$${i#/}"; \
done; \
done)
reldirs := $(sort $(reldirs))
dep_dir_dd := $(addsuffix /dir.dd,. $(reldirs))
dep_dir_dd := $(addprefix $(DEPDIR)/,$(dep_dir_dd))
dep_dir_dd := $(subst /./,/,$(dep_dir_dd))
# IMPORTANT: the list below (deps_right_order) must have its order preserved.
# dep_mods_d and dep_progs_d_d MUST be rebuilt BEFORE dep_progs_d. Else, the
# guard system will not work, because the former will be rebuilt as a
# side-effect (prerequisite) of rebuilding dep_progs_d and make won't trigger a
# restart in this case.
#
# GNU make only restarts when a makefile is rebuilt as a goal, and the goal (a
# member of dep_progs_d) won't be rebuilt, despite having its recipe run,
# because of the guard.
#
# Note: GNU make rebuilds makefiles in the reversed order in which they were
# loaded. This is an understandable but unspecified implementation detail, so we
# don't like to rely on it. Since the non-restarting behavior described above is
# in conflict with the manual, I opened a bug.
#
# https://savannah.gnu.org/bugs/index.php?60595
deps_right_order := $(dep_progs_d) $(dep_progs_d_d) $(dep_mods_d) $(dep_dir_dd)
targets_in_root := $(notdir $(wildcard $(SRCDIR)/*.$(FEXT)))
targets_in_root := $(targets_in_root:.$(FEXT)=)
targets_in_root += $(addsuffix .o,$(targets_in_root))
# ENV: FFLAGS = flags to give to the compiler (e.g -g, -O, -std, -fdec)
# LDFLAGS = flags to give to the linker (e.g -L, -r)
# LDLIBS = library flags to give to the linker (i.e -l...)
#
# These flags are built in such a way that the user can either ADD TO THEM or
# OVERRIDE THEM without editing the Makefile, if that is desired.
#
# - To ADD to them, have the desired variables exported to make.
# - To OVERRIDE them, put them in the make command as the first argument.
#
# Examples:
#
# - Add to: $ FFLAGS='-g -O' make progs
# - Override them: $ make FFLAGS='-g -O' progs
FFLAGS_ := -Wall -Wextra -Wconversion-extra -pedantic \
-std=f2018 -fimplicit-none -J$(moddir)
FFLAGS.debug := -g3 -Og -fcheck=all \
-ffpe-trap=invalid,zero,overflow,underflow,denormal
FFLAGS.release := -O2
FFLAGS := $(FFLAGS_) $(FFLAGS.$(BUILD)) $(FFLAGS)
LDFLAGS_ :=
LDLIBS_ :=
LDFLAGS := $(LDFLAGS_) $(LDFLAGS)
LDLIBS := $(LDLIBS_) $(LDLIBS)
# Final command lines.
compile_cmd = $(FC) $(CFLAGS) $(FFLAGS) -c $< -o $@
link_cmd = $(FC) $(CFLAGS) $(FFLAGS) -o $@ $(LDFLAGS) $^ $(LDLIBS)
copy_cmd = cp -f $< $@
copy_cmd_echo = $(COLOR_COPY)cp$(COLOR_NONE) -f $< $@
done_cmd = echo -e '$(COLOR_DONE)$(MSG_DONE)$(COLOR_NONE)'
basename_done_cmd = echo -e '$(copy_cmd_echo)' && $(copy_cmd) && $(done_cmd)
mkdir_this = $(MKDIR) $(@D)
#####################
### RULES ###
#####################
# Main phony rules.
.DEFAULT_GOAL := all
all: progs
progs: $(basename_progs)
deps: $(deps_right_order)
# Pattern rule for linking program binaries.
$(builddir)/% : $(builddir)/%.o
@ echo -en '$(COLOR_LINK)Linking $*:$(COLOR_NONE) '
$(mkdir_this)
echo '$(link_cmd)' && $(link_cmd)
# Pattern rule for compiling.
# Applies to all sources (programs and modules).
# When compiling modules, gfortran automatically puts the resulting .mod file
# (byproduct) in the correct directory (specified with -J).
$(builddir)/%.o : $(SRCDIR)/%.$(FEXT)
@ echo -en '$(COLOR_COMPILE)Compiling $*.$(FEXT):$(COLOR_NONE) '
$(MKDIR) $(moddir)
$(mkdir_this)
echo '$(compile_cmd)' && $(compile_cmd)
# Rule for "building" targets called by their basenames.
# Building in this case means simply copying the goal file, which will be in
# the build tree. The prerequisites to each basename shall be populated in each
# dir.dd makefile.
$(basename_all) : ; @ $(basename_done_cmd)
# Pattern rules for the dependency (.d) Makefiles.
#
# Each source file shall have one corresponding .d file. They go in DEPDIR
# ('dep' dir in project root). The recipes below run the source file through our
# awk script to extract the module dependencies from its USE statements.
#
# The awk script is embedded in this Makefile, at the very end.
#
# Program source files have one additional dependency Makefile with extension
# .d.d. This file ensures all chain dependencies are ready before making the .d
# file.
#
# Module source files have one additional intermediate file with extension
# .chain. This file contains all dependencies (direct and chained) of the
# module, and is built by recursively traversing all the dependencies .use
# files.
#
# Examples:
#
# For src/program.f90:
# - dep/program.use <= output of AWK with USE statements
# - dep/program.d.d <= program.d as target and .chains as prereqs
# - dep/program.d <= prereqs for compiling* and linking**
#
# For src/mod/mod1.f90:
# - dep/mod/mod1.use <= same as above
# - dep/mod/mod1.chain <= all direct and chained deps of mod1
# - dep/mod/mod1.d <= prerequisites for compiling* mod1
#
# * only direct dependencies
# ** direct and chained dependencies
#
# Guard file is used to force waiting until all included Makefiles are rebuilt
# and reread before proceeding to chain resolution. Every time a dependency
# Makefile that may affect other Makefiles is modified, the guard is put up so
# that the affected Makefiles forfeit the execution of their recipes, deferring
# until the next restart of make (which always occurs when Makefiles change).
#
# I don't expect this section to be easy to understand, although I did my best
# to tidy it up.
guardfile := $(DEPDIR)/guard
ifneq ($(MAKE_RESTARTS),)
$(info $(shell \
echo -en "$(COLOR_DONE)Restarting make" \
"($(MAKE_RESTARTS))$(COLOR_NONE)" && \
[[ -n "$$(rm -fv $(guardfile))" ]] && \
echo -n ' (removed guard)'; \
echo \
))
else ifneq "$(shell rm -fv $(guardfile))" ""
$(info Warning: leftover guard found (removed).)
endif
$(dep_mods_d) : %.d : %.use
$(dr_start)
$(dr_truncate_target)
# $(moddir)/mod1.o : $(moddir)/mod2.o [...]
$(call dr_rule_from_use,$(patsubst \
$(depmoddir)/%,$$(moddir)/%,$(@:.d=.o)),$$(moddir),.o)
# dep/mod/mod1.chain : dep/mod/mod2.chain [...]
# Submodules must not have this line, since
# they are never part of a USE chain.
if [[ $@ =~ ^$(depmoddir)/[^/]+$$ ]]; then
$(call dr_rule_from_use,$(@:.d=.chain),$(depmoddir),.chain)
fi
$(dr_create_guard)
$(dep_progs_d) : %.d : %.use | %.d.d
$(dr_start)
$(dr_check_guard)
$(dr_truncate_target)
target='$(patsubst $(DEPDIR)/%,$$(builddir)/%,$(@:.d=))'
# $(builddir)/program.o : $(moddir)/mod1.o [...]
$(call dr_rule_from_use,'"$$target.o"',$$(moddir),.o)
# $(builddir)/program : $(moddir)/mod1.o [...]
echo -n "$$target :" >> $@
for dep in $$(cat $<); do
echo $$dep
cat $(depmoddir)/$$dep.chain
done | sort | uniq | $(call dr_sed_tr,$$(moddir),.o) >> $@
echo >> $@
echo
$(dep_progs_d_d) : %.d.d : %.use
$(dr_start)
$(dr_truncate_target)
$(call dr_rule_from_use,$(basename $@),$(depmoddir),.chain)
$(dr_create_guard)
$(DEPDIR)/%.use : $(SRCDIR)/%.$(FEXT)
$(dr_start)
echo -n " => "
$(AWK) '$(call awk_make_dep)' $< > $@
$(depmoddir)/%.chain : $(srcmoddir)/%.$(FEXT) | $(depmoddir)/%.d
$(dr_start)
$(dr_check_guard)
depchains="$(filter %.chain,$^)"
basenames="$$(sed -E 's/[^ ]*\/([^.]*)[^ ]*/\1/g' <<< $$depchains)"
{ echo $$basenames; cat $$depchains /dev/null; } | sed '/^$$/d' |
tr ' ' '\n' | sort | uniq > $@
echo -n ', '
# Static pattern rules for directly making individual programs and modules.
# Also, rules for building entire directories or subtrees of the source tree.
#
# This below creates one dir.dd for each directory that has source files.
# Examples:
#
# dep/dir.dd
# dep/mod/dir.dd
# dep/test/date/dir.dd
#
# fMakefile builds things into the BUILDDIR_PREFIX directory, but we like to use
# 'make mytest2' better than 'make build/debug/test/mytest2'. This is what the
# rules in each dir.dd do. By copying the binary into the project root in the
# end, 'myprog2' becomes a real, updatable target.
#
# This enables the following examples:
#
# make myprog => build/debug/dir1/dir2/myprog => ./myprog
# make myprog.o => build/debug/dir1/dir2/myprog.o => ./myprog.o
# make mymod.o => build/debug/mod/mymod.o => ./mymod.o
# make mysubmod.o => build/debug/mod/somemod/mysubmod.o => ./mysubmod.o
#
# 'make cleancopies' removes these copies from the project root. All (relevant)
# cleaning targets include it though, so you'll rarely need to call it directly.
#
# Another functionality provided by dir.dd is building all targets in a
# subdirectory or an entire subtree of the source tree. Suppose we have:
#
# src
# ├── main.f90
# └── test
# ├── special_case
# │ └── test_special.f90
# ├── test1.f90
# └── test2.f90
#
# In this case, running 'make test/' (mind the slash) will put 'test1' and
# 'test2' in your project root. Running 'make test//' (two slashes) will do so
# recursively (i.e 'test_special' will be there too).
#
# Note: the dot ('make .') is provided to make only the src/ directory.
$(dep_dir_dd) : $(DEPDIR)/%dir.dd : $(SRCDIR)/%
$(dr_start)
# Functions that return only files that are directly under this dir.
# generic_filter does the filtering according to the rule above, and hands
# each resulting path for a specific function (first arg) to transform.
generic_filter() {
declare -g ret=
filter=$$1; shift
for f in $$*; do
if [[ $$f =~ ^$*[^/]*$$ ]]; then
$$filter $$f
fi
done
echo $$ret
}
# filter_f is for target file basenames: strip basedir, don't append slash.
# filter_d is for target subdirs: don't strip basedir, append slash.
filter_f() { declare -g ret="$$ret $${1##*/}"; }
filter_d() { declare -g ret="$$ret $$1/"; }
{
echo targets_basename := $$(generic_filter filter_f $(relpaths_all))
echo '$$(targets_basename) : % : $$(builddir)/$*%'
echo
echo targets_makedir := \
$$(generic_filter filter_f $(relpaths_progs) $(relpaths_mods_o))
if [[ -n '$*' ]]; then
echo subdirs := $$(generic_filter filter_d $(reldirs))
echo '$* : $$(targets_makedir)'
echo '$*/ : $$(targets_makedir) $$(subdirs)'
else
echo '. : $$(targets_makedir)'
fi
} > $@
echo
# Of course, the above will only work well for globally unambiguous names. For
# ambiguous names, the line below allows you to build like:
#
# make test/date/my_date_test => build/debug/test/date/my_date_test
# make test/date/my_date_test.o => build/debug/test/date/my_date_test.o
# make mod/mymod/mysubmod.o => build/debug/mod/mymod/mysubmod.o
#
# Note: this is phony and does not make a link in the project root.
$(relpaths_all) : % : $(builddir)/%
# Helper functions for dep recipes
dr_start = @ $(mkdir_this); echo -n $@
dr_truncate_target = : > $@
dr_create_guard = : > $(guardfile); echo ' (created guard)'
dr_sed_tr = { sed 's|.*| $(1)/&$(2)|' | tr -d '\n'; }
define dr_check_guard
if [[ -e $(guardfile) ]]; then
echo ' skipped (guard found)'
exit
fi
endef
define dr_rule_from_use
{
echo -n '$(1) :'
$(call dr_sed_tr,$(2),$(3)) < $<
echo
} >> $@
endef
# Cleaning rules.
#
# Cleaning targets are:
# - clean: entire build dir (BUILDDIR_PREFIX) plus binary copies in
# project root (see note below).
# - cleanbuild: individual build dir (build/debug or build/release).
# - cleandeps: dependency directory ('dep' dir containing .d files).
# - distclean: everything, that is, 'clean' + 'cleandeps'.
clean_targets := clean cleanbuild cleandeps cleancopies finalclean distclean
clean: cleancopies ; $(RMDIR) $(BUILDDIR_PREFIX)
cleanbuild: cleancopies ; $(RMDIR) $(builddir)
cleandeps: ; $(RMDIR) $(DEPDIR)
finalclean: cleandeps ; $(RMDIR) $(BUILDDIR_PREFIX)
distclean: clean cleandeps
cleancopies:
@ for copy in $(basename_all); do
if [[ -f $$copy ]]; then echo "rm $$copy" && rm $$copy; fi; done
# Current Makefile invocation path. This is a deferred variable, so any Makefile
# can use it -- but this only works until an 'include' directive is executed.
THIS_MAKEFILE = $(lastword $(MAKEFILE_LIST))
# Target to remove all the comments from this Makefile.
#
# We use a target-specific variable to fix the THIS_MAKEFILE value, since inside
# the recipe its expansion is deferred.
stripmakefile : THIS_MAKEFILE := $(THIS_MAKEFILE)
stripmakefile :
sed -i -E '/^#($$|[^!])/d' $(THIS_MAKEFILE)
.PHONY: all progs deps $(clean_targets) stripmakefile . \
$(addsuffix /,$(reldirs)) $(filter-out $(targets_in_root),$(relpaths_all))
# Optimize by telling make it doesn't know how to make our original files --
# that is, it's not supposed to search for implicit rules for them.
$(THIS_MAKEFILE) $(src_all) : ;
# Prevent deletion of .use, .chain and any other intermediate file.
.SECONDARY:
# Have each recipe run entirely in one shell, as opposed to launching each line
# in a different shell, which would force us to join all commands with &&.
.ONESHELL:
# "So generally the right thing to do is to delete the target file if the
# recipe fails after beginning to change the file. make will do this if
# .DELETE_ON_ERROR appears as a target. This is almost always what you want make
# to do, but it is not historical practice; so for compatibility, you must
# explicitly request it." -- GNU make manual
.DELETE_ON_ERROR:
# Include all dependency Makefiles (.d files)
#
# The complicated logical test prevents the inclusion when make's goal is not
# about building. That is, when goal is one of: clean*, deps and stripmakefile.
# 'deps' is in that list only because, if it isn't, when 'make deps' is called,
# all deps will already be built when make gets to the deps target, prompting a
# strange "Nothing to be done for 'deps'" to show right after building all deps.
#
# However, when making the 'deps' goal, some deps are needed, thus those are
# included (in the 'else ifeq' clause). They are the .d files of the mods and
# the .d.d files of the programs.
ifneq "$(or \
$(if $(MAKECMDGOALS),,true),$(filter-out \
$(clean_targets) deps stripmakefile,$(MAKECMDGOALS)))" ""
include $(deps_right_order)
else ifeq "$(filter deps,$(MAKECMDGOALS))" "deps"
include $(dep_progs_d_d) $(dep_mods_d)
endif
####################
### AWK SCRIPT ###
####################
# awk script for generating dependency prerequisites.
#
# This scans a Fortran source file looking for USE statements. Both Fortran's
# valid forms are considered:
#
# USE [::] <mod-name>[, only: ...] (first block)
# USE, NON_INTRINSIC :: <mod-name>[, only: ...] (second block)
#
# "USE, INTRINSIC" is ignored since it's the compiler's job to provide for it.
#
# Submodules are considered too:
#
# SUBMODULE ( mod1[:mod2[...]] ) submod
#
# Upon finding a match, it returns only the module name. For submodules,
# "mod1/mod2/mod3" is returned (colons become slashes), matching fMakefile
# source directory structure.
#
# Obvious limitations of this tool:
# - This tool needs the statement to be in one line up until <mod-name>.
# - This tool will be fooled by a matching statement that's part of a
# multi-line string, or something as contrived.
define awk_make_dep
BEGIN { \
intrinsics["ISO_C_BINDING"]; \
intrinsics["ISO_FORTRAN_ENV"]; \
intrinsics["IEEE_EXCEPTIONS"]; \
intrinsics["IEEE_ARITHMETIC"]; \
intrinsics["IEEE_FEATURES"]; \
}; \
\
{ U = toupper($$0); } \
\
U ~ /^\s*USE[: \t]+[A-Z]/ { \
gsub(/[,:]/, " "); \
if ( ! (toupper($$2) in intrinsics) ) { \
print $$2; \
} \
}; \
\
U ~ /^\s*USE\s*,\s*NON_INTRINSIC/ { \
gsub(/[,:]/, " "); \
print $$3; \
} \
\
U ~ /^\s*SUBMODULE\s+\(.*\)\s+[A-Z]/ { \
match($$0, /\(.*\)/, s); \
gsub(/[() ]/, "", s[0]); \
gsub(/:/, "/", s[0]); \
print s[0]; \
}
endef