From ad7852d9c233e1f4c0358802c30880bf12ac845f Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Thu, 18 Nov 2021 15:02:53 +0000 Subject: [PATCH] rework the build system - unify the three makefiles into a single generic one - automatically generate link targets (via the `depend` script) and object dependencies (via a make rule) - move all build artifacts under the build/ directory - replace svn with git for the version information - add a `static` variable to toggle between static/shared builds - add a target to build the dependency graph of GRAY modules --- .gitignore | 2 + Makefile | 198 +++++++++++++++++++++++++++++++------------------ Makefile.jetto | 132 --------------------------------- Makefile.sum | 75 ------------------- depend | 28 +++++++ 5 files changed, 157 insertions(+), 278 deletions(-) create mode 100755 .gitignore delete mode 100644 Makefile.jetto delete mode 100644 Makefile.sum create mode 100755 depend diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..1add2e3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_store +build diff --git a/Makefile b/Makefile index d31cf5b..37a6e60 100644 --- a/Makefile +++ b/Makefile @@ -1,81 +1,137 @@ -# Executable name -EXE=gray +## +## Directories +## -# Objects list -MAINOBJ=main.o -OTHOBJ= beamdata.o beams.o conical.o const_and_precisions.o coreprofiles.o \ - dierckx.o dispersion.o eccd.o eierf.o errcodes.o graycore.o \ - gray_params.o equilibrium.o limiter.o magsurf_data.o math.o minpack.o multipass.o \ - numint.o pec.o polarization.o quadpack.o reflections.o simplespline.o units.o utils.o - -# Alternative search paths -vpath %.f90 src -vpath %.f src +# Structure: +# gray - top level +# ├── src - source code +# └── build - build artifacts +# ├── bin - binaries +# ├── lib - libraries +# └── obj - objects +SRCDIR = src +BUILDDIR = build +BINDIR = build/bin +LIBDIR = build/lib +OBJDIR = build/obj +DIRS = $(BINDIR) $(OBJDIR) $(LIBDIR) -# Fortran compiler name and flags -FC=gfortran -LD=gfortran -FFLAGS=-O3 -fPIC -LDFLAGS= -static-libgfortran -static-libgcc -# LDFLAGS= -static-libgfortran -lgfortran -lgcc -lSystem -nodefaultlibs -LIBS= /usr/local/lib/libquadmath.a -# FFLAGS=-Wall -g -finit-real=nan -ffpe-trap=invalid -fcheck=all -fbounds-check +## +## Files +## -DIRECTIVES = -DREVISION="'$(shell svnversion src)'" +# All Fortran source files +SOURCES = $(wildcard $(SRCDIR)/*.f90) -all: $(EXE) +# All Generated makefiles describing object dependencies +OBJECTS = $(patsubst $(SRCDIR)/%.f90,$(OBJDIR)/%.o,$(SOURCES)) -# Build executable from object files -$(EXE): $(MAINOBJ) $(OTHOBJ) - $(LD) $(LDFLAGS) -o $@ $^ $(LIBS) +# Generated makefiles describing object dependencies +DEPS = $(OBJECTS:o=d) -# Dependencies on modules -main.o: const_and_precisions.o beams.o coreprofiles.o equilibrium.o \ - graycore.o gray_params.o reflections.o -graycore.o: const_and_precisions.o beamdata.o beams.o coreprofiles.o \ - dispersion.o eccd.o equilibrium.o errcodes.o gray_params.o \ - pec.o polarization.o limiter.o units.o utils.o reflections.o multipass.o -beams.o: const_and_precisions.o dierckx.o reflections.o simplespline.o utils.o -beamdata.o: const_and_precisions.o gray_params.o -conical.o: const_and_precisions.o -coreprofiles.o: const_and_precisions.o dierckx.o gray_params.o simplespline.o \ - utils.o -dierckx.o: const_and_precisions.o -dispersion.o: const_and_precisions.o eierf.o errcodes.o math.o quadpack.o -eccd.o: const_and_precisions.o conical.o dierckx.o errcodes.o magsurf_data.o \ - numint.o -eierf.o: const_and_precisions.o -errcodes.o: const_and_precisions.o -gray_params.o: const_and_precisions.o utils.o -equilibrium.o: const_and_precisions.o dierckx.o limiter.o minpack.o \ - reflections.o simplespline.o utils.o gray_params.o -magsurf_data.o: const_and_precisions.o gray_params.o equilibrium.o dierckx.o \ - reflections.o simplespline.o units.o utils.o -math.o: const_and_precisions.o -minpack.o: const_and_precisions.o -multipass.o: const_and_precisions.o beamdata.o equilibrium.o gray_params.o \ - polarization.o reflections.o -numint.o: const_and_precisions.o -pec.o: const_and_precisions.o beamdata.o equilibrium.o gray_params.o \ - magsurf_data.o utils.o -polarization.o: const_and_precisions.o -quadpack.o: const_and_precisions.o -reflections.o: const_and_precisions.o limiter.o utils.o -simplespline.o: const_and_precisions.o -utils.o: const_and_precisions.o +# Fortran modules to be bundled into libraries +MODULES = $(filter-out $(OBJDIR)/main%,$(OBJECTS)) -# General object compilation command -%.o: %.f90 - $(FC) -cpp $(DIRECTIVES) $(FFLAGS) -c $< +# Build outputs +GRAY = $(BINDIR)/gray +LIBGRAY = $(LIBDIR)/libgray +BINARIES = $(GRAY) $(GRAY)sum +LIBRARIES = $(LIBGRAY).so -.PHONY: clean install -# Remove output files +## +## 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) +CPPFLAGS += -DREVISION=\"$(GIT_REV)$(GIT_DIRTY)\" + +# Static build options +ifdef STATIC +LIBRARIES := $(LIBRARIES:so=a) +LDFLAGS += -static +endif + +## +## Targets +## + +.PHONY: all clean install + +all: $(BINARIES) $(LIBRARIES) + +# Remove all generated files clean: - rm -rf *.o *.mod $(EXE) + rm -r $(BUILDDIR) -install: - @if [ -f $(EXE) ]; then \ - cp $(EXE) ~/bin/; \ - else \ - echo File $(EXE) does not exist. Run \'make\' first; \ - fi +# Install libraries, binaries and man pages +install: $(BINARIES) $(LIBRARIES) gray.1 + install -Dm555 -t $(PREFIX)/bin $(BINDIR)/* + install -Dm555 -t $(PREFIX)/lib $(LIBDIR)/* + install -Dm644 -t $(PREFIX)/share/man/man1 gray.1 + +# GRAY binary +$(GRAY): $(shell ./depend $(OBJDIR)/main.o) | $(BINDIR) + $(LD) $(LDFLAGS) -o $@ $^ + +# sum variant +$(GRAY)sum: $(shell ./depend $(OBJDIR)/main-sum.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)) + +# 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' > $@ + @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 $@ diff --git a/Makefile.jetto b/Makefile.jetto deleted file mode 100644 index a6f312a..0000000 --- a/Makefile.jetto +++ /dev/null @@ -1,132 +0,0 @@ -# Makefile for JETTO fortran 90 library 'gray' -# Author: Lorenzo Figini (figini@ifp.cnr.it) -# -# Derived from -# Makefile for JETTO fortran 77 library 'frantic' -# Author: Derek Harting (d.harting@fz-juelich.de) -# and -# Makefile for ITCequ Fortran 90 library - definitions -# P. Strand, elfps@chalmers.se -# G. Corrigan, gcor@jet.uk -# D. Harting, d.harting@fz-juelich.de -# Set the environment from the top-level Makefile of JETTO -# -------------------------------------------------------- -include ../include.mk - -# Alternative search paths -vpath %.f90 src - -DIRECTIVES = -DEXTBES -DREVISION="rev.166 JETTO" #'$(shell svnversion src)'" - -# library name -# ------------ -LIBNAME=$(JLIBDIR)/libgray.a - -# List source and object files -# ---------------------------- -FSRC=$(wildcard src/*.f90) -FOBJ0=$(subst src/,,$(FSRC)) -FOBJ=$(FOBJ0:.f90=.o) - -######################################## -# Set up compiler specific environment # -######################################## -# set default compiler -# -------------------- -FC=$(F90) - -# Set compiler debug and optimization flags -# ----------------------------------------- -ifeq ("$(DBG)","") - FFLAGS= $(AUTO) -O3 -Mpreprocess -# FFLAGS=-O3 -cpp -else - FFLAGS= $(AUTO) -O0 -Mpreprocess -g -Minform=inform -Mbounds -Mchkptr -# FFLAGS=-Wall -g -finit-real=nan -ffpe-trap=invalid -fcheck=all -fbounds-check -endif - -# Set include directories -# ----------------------- -#INC=-I$(JCOMMON_STD) -INC= - -##################################### -# Set up RULES specific environment # -##################################### - -# suffixes -# -------- -.SUFFIXES: .f90 .o .mod - -# PHONY targets -# ------------- -.PHONY: all clean realclean $(MASTER_RULES) gray - -# default target -# -------------- -all: - @($(MAKE) -C ../ all) || exit $$? - -# Set rules passed to top-level Makefile -# -------------------------------------- -$(MASTER_RULES): - @($(MAKE) -C ../ $@) || exit $$? - -# rule for libgray.a -# -------------------- -$(LIBNAME): $(FOBJ) - ar vr $(LIBNAME) $? - -# synonym for libgray.a -# ----------------------- -gray: $(LIBNAME) - -# create rule for compiling f90 files -# ----------------------------------- -%.o: %.f90 - $(FC) -c $(DIRECTIVES) $(FFLAGS) $(INC) $< - -# make 'realclean' option -# ----------------------- -realclean: - rm -f *.o *.mod $(LIBNAME) - -# make 'clean' option -# ------------------- -clean: - rm -f *.o - -# Dependencies -# ------------ -gray_jetto1beam.o: const_and_precisions.o beams.o graycore.o gray_params.o \ - reflections.o units.o - -graycore.o: const_and_precisions.o beamdata.o beams.o coreprofiles.o \ - dispersion.o eccd.o equilibrium.o errcodes.o gray_params.o \ - pec.o polarization.o limiter.o units.o utils.o -beams.o: const_and_precisions.o dierckx.o reflections.o simplespline.o utils.o -beamdata.o: const_and_precisions.o gray_params.o -conical.o: const_and_precisions.o -coreprofiles.o: const_and_precisions.o dierckx.o gray_params.o simplespline.o \ - utils.o -dierckx.o: const_and_precisions.o -dispersion.o: const_and_precisions.o eierf.o errcodes.o math.o quadpack.o -eccd.o: const_and_precisions.o conical.o dierckx.o errcodes.o magsurf_data.o \ - numint.o -eierf.o: const_and_precisions.o -errcodes.o: const_and_precisions.o -gray_params.o: const_and_precisions.o utils.o -equilibrium.o: const_and_precisions.o dierckx.o limiter.o minpack.o \ - reflections.o simplespline.o utils.o gray_params.o -magsurf_data.o: const_and_precisions.o gray_params.o equilibrium.o dierckx.o \ - reflections.o simplespline.o units.o utils.o -math.o: const_and_precisions.o -minpack.o: const_and_precisions.o -numint.o: const_and_precisions.o -pec.o: const_and_precisions.o beamdata.o equilibrium.o gray_params.o \ - magsurf_data.o utils.o -polarization.o: const_and_precisions.o -quadpack.o: const_and_precisions.o -reflections.o: const_and_precisions.o limiter.o utils.o -simplespline.o: const_and_precisions.o -utils.o: const_and_precisions.o diff --git a/Makefile.sum b/Makefile.sum deleted file mode 100644 index c9d8f58..0000000 --- a/Makefile.sum +++ /dev/null @@ -1,75 +0,0 @@ -# Executable name -EXE=sumgray - -# Objects list -MAINOBJ=main-sum.o -OTHOBJ= beamdata.o beams.o conical.o const_and_precisions.o coreprofiles.o \ - dierckx.o dispersion.o eccd.o eierf.o errcodes.o sumcore.o \ - gray_params.o equilibrium.o limiter.o magsurf_data.o math.o minpack.o numint.o \ - pec.o polarization.o quadpack.o reflections.o simplespline.o units.o utils.o - -# Alternative search paths -vpath %.f90 src -vpath %.f src - -# Fortran compiler name and flags -FC=gfortran -FFLAGS=-O3 -#FFLAGS=-Wall -g -finit-real=nan -ffpe-trap=invalid -fcheck=all -fbounds-check - -DIRECTIVES = -DREVISION="'$(shell svnversion src)'" - -all: $(EXE) - -# Build executable from object files -$(EXE): $(MAINOBJ) $(OTHOBJ) - $(FC) $(FFLAGS) -o $@ $^ - -# Dependencies on modules -main-sum.o: const_and_precisions.o beams.o coreprofiles.o equilibrium.o \ - sumcore.o gray_params.o reflections.o -sumcore.o: const_and_precisions.o beamdata.o beams.o coreprofiles.o \ - dispersion.o eccd.o equilibrium.o errcodes.o gray_params.o \ - pec.o polarization.o limiter.o units.o utils.o -beams.o: const_and_precisions.o dierckx.o reflections.o simplespline.o utils.o -beamdata.o: const_and_precisions.o gray_params.o -conical.o: const_and_precisions.o -coreprofiles.o: const_and_precisions.o dierckx.o gray_params.o simplespline.o \ - utils.o -dierckx.o: const_and_precisions.o -dispersion.o: const_and_precisions.o eierf.o errcodes.o math.o quadpack.o -eccd.o: const_and_precisions.o conical.o dierckx.o errcodes.o magsurf_data.o \ - numint.o -eierf.o: const_and_precisions.o -errcodes.o: const_and_precisions.o -gray_params.o: const_and_precisions.o utils.o -equilibrium.o: const_and_precisions.o dierckx.o limiter.o minpack.o \ - reflections.o simplespline.o utils.o gray_params.o -magsurf_data.o: const_and_precisions.o gray_params.o equilibrium.o dierckx.o \ - reflections.o simplespline.o units.o utils.o -math.o: const_and_precisions.o -minpack.o: const_and_precisions.o -numint.o: const_and_precisions.o -pec.o: const_and_precisions.o beamdata.o equilibrium.o gray_params.o \ - magsurf_data.o utils.o -polarization.o: const_and_precisions.o -quadpack.o: const_and_precisions.o -reflections.o: const_and_precisions.o limiter.o utils.o -simplespline.o: const_and_precisions.o -utils.o: const_and_precisions.o - -# General object compilation command -%.o: %.f90 - $(FC) -cpp $(DIRECTIVES) $(FFLAGS) -c $< - -.PHONY: clean install -# Remove output files -clean: - rm -rf *.o *.mod $(EXE) - -install: - @if [ -f $(EXE) ]; then \ - cp $(EXE) ~/bin/; \ - else \ - echo File $(EXE) does not exist. Run \'make\' first; \ - fi diff --git a/depend b/depend new file mode 100755 index 0000000..e098be2 --- /dev/null +++ b/depend @@ -0,0 +1,28 @@ +#!/bin/sh + +# Compute the dependencies (direct and transitive) of an object +# This is used to collect all objects needed to link a program. + +# Bail out when .d files are missing +test -f "${1%.o}.d" || exit 1 + +# Check whether $1 contains substring $2 +contains(){ test "${1#*$2}" != "$1"; } + +# Walk the dependency graph (consinting of the set of all .d files) +# and output the visited nodes (objects). +walk_dag(){ + while read -r line; do + # skip the first line (file own name) + contains "$line" ': ' && continue + line="${line% \\}" + contains "$visited" "$line" && continue + visited="$line:$visited" + printf '%s ' "$line" + # whether the node is a leaf + test "$(wc -l < "${line%.o}.d")" -gt 1 && walk_dag < "${line%.o}.d" + done +} + +printf '%s ' "$1" # the object itself +walk_dag < "${1%.o}.d"