gray/Makefile
Michele Guerini Rocco c5a4b180bc
src/gray_params.f90: replace magic numbers with enums
1. Introduces enumerations (and some booleans) intended to replace all
   the magic numbers used throughout the code to represent multiple
   choices.

2. Replace the gray_params.sh script a new one that automatically
   generates code for all the GRAY parameters by parsing
   gray_params.f90.

3. Also generate extra code to accept the enum identifiers as valid
   values in the configuration files and command line arguments.

4. Set sensible default values for parameters that are rarely changes.
2024-02-09 11:16:18 +01:00

207 lines
5.2 KiB
Makefile

# Load the configure script variables
-include configure.mk
##
## Directories
##
# Structure:
# gray - top level
# ├── src - source code
# ├── doc - documentation
# ├── tests - integration tests
# └── build - build artifacts
# ├── bin - binaries
# ├── lib - libraries
# ├── obj - objects
# └── inc - files to #include
SRCDIR = src
BUILDDIR = build
SHAREDIR = build/share
BINDIR = build/bin
LIBDIR = build/lib
OBJDIR = build/obj
INCDIR = build/inc
PREFIX ?= /usr
# Directories that need to be created
DIRS = $(BINDIR) $(OBJDIR) $(INCDIR) $(LIBDIR) $(SHAREDIR)
##
## Files
##
# All Fortran source files
SOURCES = $(wildcard $(SRCDIR)/*.f90)
# All Fortran object
OBJECTS = $(patsubst $(SRCDIR)/%.f90,$(OBJDIR)/%.o,$(SOURCES))
# Generated makefiles describing object dependencies
DEPS = $(OBJECTS:o=d)
# Fortran modules to be bundled into libraries
MODULES = $(filter-out $(OBJDIR)/main%,$(OBJECTS))
# Build outputs
GRAY = $(BINDIR)/gray
LIBGRAY = $(LIBDIR)/libgray.so
BINARIES = $(GRAY)
LIBRARIES = $(LIBGRAY)
##
## Git information (used in the version string)
##
# Short hash of the latest commit
GIT_REV ?= $(shell git rev-parse --short HEAD)
# Whether the worktree and the latest commit differs
GIT_DIRTY ?= $(shell test -n "$$(git status --porcelain)" && echo "-dirty")
##
## Fortran compiler and flags
##
# Note: can't use ?= for FC because GNU Make defaults to f77
FC = gfortran
LD = gfortran
FFLAGS += -J$(OBJDIR) -I$(INCDIR) -ffree-line-length-none -fPIC -frecursive
LDFLAGS += -L$(LIBDIR)
CPPFLAGS += -DREVISION=\"$(GIT_REV)$(GIT_DIRTY)\" -DPREFIX=\"$(PREFIX)\"
ifndef DETERMINISTIC
ifdef AR_DEFAULT_DETERMINISTIC
# Write timestamps to allow partial updates
ARFLAGS = crU
endif
endif
# Static build options
ifdef STATIC
LIBGRAY := $(LIBGRAY:so=a)
LIBRARIES := $(LIBRARIES:so=a)
ifndef SEMISTATIC
LDFLAGS += -static
endif
else
LDFLAGS += -Wl,-rpath '$$ORIGIN/../lib/'
endif
# Debug build options
ifdef DEBUG
FFLAGS += -ggdb -O0 -Wall -Wunused-parameter
# Tricks to detect uninitialised memory
FFLAGS += -finit-integer=7777777 -finit-real=snan -ffpe-trap=invalid
else
# Optimization level 3
FFLAGS += -O3
endif
##
## Targets
##
.PHONY: all clean check install docs
# Don't update archives in parallel, it's unsupported
.NOTPARALLEL: $(LIBDIR)/libgray.a
all: $(BINARIES) $(LIBRARIES)
# Remove all generated files
clean:
rm -r $(BUILDDIR)
# Run tests
check: $(GRAY)
python -Bm tests --binary $^
# Install libraries, binaries and documentation
install: $(BINARIES) $(LIBRARIES) $(SHAREDIR)/doc $(SHAREDIR)/gray.1
mkdir -p $(PREFIX)/{bin,lib,share/{doc/res,man/man1}}
install -m555 -t $(PREFIX)/bin $(BINDIR)/*
install -m555 -t $(PREFIX)/lib $(LIBDIR)/*
install -m644 -t $(PREFIX)/share/doc $(SHAREDIR)/doc/manual.*
install -m644 -t $(PREFIX)/share/doc/res $(SHAREDIR)/doc/res/*
install -m644 -t $(PREFIX)/share/man/man1 $(SHAREDIR)/gray.1
# dependencies
$(OBJDIR)/%.o: $(OBJDIR)/%.d
# GRAY binary
$(GRAY): $(OBJDIR)/main.o $(LIBGRAY) | $(BINDIR)
$(LD) $(LDFLAGS) -o '$@' $< -lgray
# GRAY shared library
$(LIBDIR)/libgray.so: $(MODULES) | $(LIBDIR)
$(LD) -shared $(LDFLAGS) -o '$@' $^
# GRAY static library
$(LIBDIR)/libgray.a($(MODULES)): | $(LIBDIR)
$(LIBDIR)/libgray.a: $(LIBDIR)/libgray.a($(MODULES))
# GRAY static library when compiling from JETTO
-include ../include.mk
$(JLIBDIR)/libgray.a: $(LIBDIR)/libgray.a
mkdir -p $(LIBDIR)
install -m755 '$<' '$@'
# All documentation
docs: $(SHAREDIR)/gray.1 $(SHAREDIR)/doc
$(SHAREDIR)/doc: | $(SHAREDIR)
+make -C doc
cp -r doc/build/* $(SHAREDIR)
# Generated man pages
$(SHAREDIR)/gray.1: $(GRAY) doc/gray.1 | $(SHAREDIR)
help2man '$<' -i doc/gray.1 -N -n 'beam-tracing code for EC waves' > '$@'
# Visualise the dependency graph
# Note: requires makefile2graph and graphviz
graph.svg: Makefile
make -Bdn \
| make2graph -b \
| awk -F'( -> )| ;|[[]' ' \
(/label/ && !/(\.o|bin\/gray)/) {bad[$$1]=1; next} \
/->/ {if (bad[$$1] || bad[$$2]) next} \
{print $$0}' \
| sed 's/label/fontsize=30,label/g; s/\.o//' \
| dot -Tsvg -o '$@'
##
## Generic rules
##
# Rebuild everything if the makefile changed
.EXTRA_PREREQS += Makefile
# Automatic generation of the Fortran prerequisites
# Note 1: this is needed because gfortran -M flag doesn't properly work;
# Note 2: this assumes matching module/file names and no circular
# dependencies (ie. the dependency graph is a DAG);
$(OBJDIR)/%.d: $(SRCDIR)/%.f90 | $(OBJDIR)
@printf '$(@:d=o): $< \\\n' > '$@'
@grep -vE '^[[:blank:]]*use.*(intrinsic|iso_)' '$<' | \
sed -nE 's@^[[:blank:]]*use[[:blank:]]+'\
'([^,[:blank:]&]+).*@$(OBJDIR)/\1.o \\@p' | \
sort -u >> '$@'
@sed -nE 's@^#include "(.+)"@$(INCDIR)/\1@p' '$<' >> '$@'
# Load the generated rules
-include $(DEPS)
# Compile a generic Fortran source
$(OBJDIR)/%.o: $(SRCDIR)/%.f90 | $(OBJDIR) $(INCDIR)
$(FC) -cpp $(CPPFLAGS) $(FFLAGS) -c '$<' -o '$@'
# Generate Fortran code from awk script
$(INCDIR)/%.inc: $(SRCDIR)/%.awk | $(INCDIR)
awk -f '$<' > '$@'
# Create directories
$(DIRS):
mkdir -p '$@'