# Load the configure script variables -include configure.mk ## ## Directories ## # Structure: # gray - top level # ├── src - source code # ├── doc - documentation # └── build - build artifacts # ├── bin - binaries # ├── lib - libraries # └── obj - objects SRCDIR = src BUILDDIR = build SHAREDIR = build/share BINDIR = build/bin LIBDIR = build/lib OBJDIR = build/obj PREFIX ?= /usr/bin # Directories that need to be created DIRS = $(BINDIR) $(OBJDIR) $(LIBDIR) $(SHAREDIR) ## ## Files ## # All Fortran source files SOURCES = $(wildcard $(SRCDIR)/*.f90) # All Generated makefiles describing object dependencies 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 BINARIES = $(GRAY) LIBRARIES = $(LIBGRAY).so ## ## 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 += -O3 -J$(OBJDIR) -ffree-line-length-none CPPFLAGS += -DREVISION=\"$(GIT_REV)$(GIT_DIRTY)\" -DPREFIX=\"$(PREFIX)\" # Static build options ifdef STATIC LIBRARIES := $(LIBRARIES:so=a) LDFLAGS += -static 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 endif ## ## Targets ## .PHONY: all clean install docs all: $(BINARIES) $(LIBRARIES) docs # Remove all generated files clean: rm -r $(BUILDDIR) # Install libraries, binaries and documentation install: $(BINARIES) $(LIBRARIES) $(SHAREDIR)/gray.1 install -Dm555 -t $(PREFIX)/bin $(BINDIR)/* install -Dm555 -t $(PREFIX)/lib $(LIBDIR)/* install -Dm644 -t $(PREFIX)/share/doc $(SHAREDIR)/doc/manual.* install -Dm644 -t $(PREFIX)/share/doc/res $(SHAREDIR)/doc/res/* install -Dm644 -t $(PREFIX)/share/man/man1 $(SHAREDIR)/*.1 # GRAY binary $(GRAY): $(shell ./depend $(OBJDIR)/main.o) | $(BINDIR) $(LD) $(LDFLAGS) -o '$@' $^ # GRAY shared library $(LIBGRAY).so: $(MODULES) | $(LIBDIR) $(LD) -shared $(LDFLAGS) -o '$@' $^ # GRAY static library $(LIBGRAY).a($(MODULES)): | $(LIBDIR) $(LIBGRAY).a: $(LIBGRAY).a($(MODULES)) # All documentation docs: | $(SHAREDIR) +make -C doc cp -t $(SHAREDIR) -r doc/build/* # 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 -v 'use iso_' '$<' | \ sed -n 's@^[^!].*use \([^,]\+\),.*@$(OBJDIR)/\1.o \\@p' | \ sort -u >> '$@' # Load the generated rules include $(DEPS) # Compile a generic Fortran source $(OBJDIR)/%.o: $(SRCDIR)/%.f90 | $(OBJDIR) $(FC) -cpp $(CPPFLAGS) $(FFLAGS) -c '$<' -o '$@' # Create directories $(DIRS): mkdir -p '$@'