gray/Makefile
Michele Guerini Rocco 6fad08ed7c
add tests
2024-02-09 11:16:17 +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
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 shell script
$(INCDIR)/%.inc: $(SRCDIR)/%.sh | $(INCDIR)
sh '$<' > '$@'
# Create directories
$(DIRS):
mkdir -p '$@'