From 2109f3ade9d6a202c413ed9ad3e3475caa944ae3 Mon Sep 17 00:00:00 2001 From: Charles BIENVENUE Date: Wed, 5 Nov 2025 22:47:07 +0000 Subject: Parallel Build, OpenMP Support with Fortran 90, and Improved Module Dependencies --- Donjon/src/Makefile | 49 ++++-- Dragon/data/TEST_GEO_hex_sect_tspc.access | 4 +- Dragon/data/TEST_GEO_latt_tspc_S30.access | 4 +- Dragon/data/fbr_colorset.access | 4 +- Dragon/data/fbr_tone.access | 4 +- Dragon/src/Makefile | 66 ++++--- Ganlib/src/Makefile | 67 ++++--- PyGan/src/Makefile | 41 +++-- PyGan/src/setup_cle2000.py | 56 ++++-- PyGan/src/setup_lcm.py | 19 +- Trivac/src/Makefile | 45 +++-- Utilib/src/Makefile | 49 ++++-- doc/IGE335/Section6.00.tex | 6 + script/make_depend.py | 279 ++++++++++++++++++++++++------ script/make_depend_py3.py | 58 ------- 15 files changed, 494 insertions(+), 257 deletions(-) delete mode 100755 script/make_depend_py3.py diff --git a/Donjon/src/Makefile b/Donjon/src/Makefile index f236c5e..b68f26a 100644 --- a/Donjon/src/Makefile +++ b/Donjon/src/Makefile @@ -1,7 +1,7 @@ #--------------------------------------------------------------------------- # # Makefile for building the Donjon library and load module -# Author : A. Hebert (2018-5-10) +# Author : A. Hebert (2018-5-10) and C. Bienvenue (2025-11-04) # #--------------------------------------------------------------------------- # @@ -20,6 +20,8 @@ DIRNAME = $(shell uname -sm | sed 's/[ ]/_/') OS = $(shell uname -s | cut -d"_" -f1) opt = -O -g PREPRO = cpp +DEFAULT_GOAL_PLACEHOLDER := +.DEFAULT_GOAL := all ifeq ($(openmp),1) COMP = -fopenmp PREPRO = cpp -D_OPENMP @@ -46,12 +48,11 @@ else endif ifeq ($(OS),AIX) - python_version_major := 2 + PY := python else - python_version_full := $(wordlist 2,4,$(subst ., ,$(shell python --version 2>&1))) - python_version_major := $(word 1,${python_version_full}) - ifneq ($(python_version_major),2) - python_version_major := 3 + PY := $(shell command -v python3 2>/dev/null) + ifeq ($(PY),) + PY := $(shell command -v python 2>/dev/null) endif endif @@ -161,7 +162,9 @@ else lib_module = ../lib/$(DIRNAME)_llvm/modules INCLUDE = -I../../Ganlib/lib/$(DIRNAME)_llvm/modules/ -I../../Utilib/lib/$(DIRNAME)_llvm/modules/ FFLAGS += -mmlir -fdynamic-heap-array - LFLAGS += -lclang_rt.osx + ifeq ($(OS),Darwin) + LFLAGS += -lclang_rt.osx + endif else lib = ../lib/$(DIRNAME) libUtl = ../../Utilib/lib/$(DIRNAME) @@ -181,18 +184,32 @@ ifeq ($(hdf5),1) LFLAGS += -L${HDF5_API} -lhdf5 endif -SRCC = $(shell ls *.c) -SRC77 = $(shell ls *.f) -SRCF77 = $(shell ls *.F) -ifeq ($(python_version_major),2) - SRC90 = $(shell python ../../script/make_depend.py *.f90) +SRCC = $(shell ls *.c 2>/dev/null) +SRC77 = $(shell ls *.f 2>/dev/null) +SRCF77 = $(shell ls *.F 2>/dev/null) +ifeq ($(PY),) + $(warning No Python interpreter found; Fortran dependency ordering may be suboptimal) + SRC90 = $(shell ls *.f90 2>/dev/null) else - SRC90 = $(shell python3 ../../script/make_depend_py3.py *.f90) + SRC90 = $(shell $(PY) ../../script/make_depend.py *.f90 *.F90) + endif OBJC = $(SRCC:.c=.o) -OBJ90 = $(SRC90:.f90=.o) +OBJ90 = $(patsubst %.f90,%.o,$(patsubst %.F90,%.o,$(SRC90))) OBJ77 = $(SRC77:.f=.o) OBJF77 = $(SRCF77:.F=.o) + +# Auto-generated dependency file capturing Fortran module and include deps +DEPS_MK := .donjon_deps.mk +-include $(DEPS_MK) +$(DEPS_MK): $(SRC90) $(SRC77) $(SRCF77) +ifeq ($(PY),) + @echo "# Dependencies not generated: no Python available" > $(DEPS_MK) +else + @echo "# Generating Fortran dependencies into $(DEPS_MK)"; \ + $(PY) ../../script/make_depend.py --make-deps $(SRC90) $(SRC77) $(SRCF77) > $(DEPS_MK) || { rm -f $(DEPS_MK); exit 1; } +endif + all : sub-make Donjon ifeq ($(openmp),1) @echo 'Donjon: openmp is defined' @@ -227,7 +244,7 @@ $(lib_module)/: $(lib)/: $(lib_module)/ mkdir -p $(lib)/ libDonjon.a: $(OBJC) $(OBJ90) $(OBJ77) $(OBJF77) $(lib)/ - ar r $@ $(OBJC) $(OBJ90) $(OBJ77) $(OBJF77) + ar rcs $@ $(OBJC) $(OBJ90) $(OBJ77) $(OBJF77) cp $@ $(lib)/$@ cp *.mod $(lib_module) $(bin)/: @@ -238,4 +255,4 @@ Donjon: libDonjon.a DONJON.o $(bin)/ sub-make cp $@ $(bin)/$@ clean: $(MAKE) -C ../../Dragon/src clean - /bin/rm -f *.o *.mod *.a sub-make temp.* Donjon + /bin/rm -f *.o *.mod *.a sub-make temp.* Donjon $(DEPS_MK) diff --git a/Dragon/data/TEST_GEO_hex_sect_tspc.access b/Dragon/data/TEST_GEO_hex_sect_tspc.access index aebf920..6c57516 100755 --- a/Dragon/data/TEST_GEO_hex_sect_tspc.access +++ b/Dragon/data/TEST_GEO_hex_sect_tspc.access @@ -27,7 +27,9 @@ if [ -f "$pos"/draglibendfb7r1SHEM315_v5p1.gz ] then echo 'gunzipping DLIB_315' chmod 755 "$pos" - gunzip "$pos"/draglibendfb7r1SHEM315_v5p1.gz + if [ ! -f "$pos"/draglibendfb7r1SHEM315_v5p1 ]; then + gunzip "$pos"/draglibendfb7r1SHEM315_v5p1.gz + fi fi if [ -f "$pos"/draglibendfb7r1SHEM315_v5p1 ] then diff --git a/Dragon/data/TEST_GEO_latt_tspc_S30.access b/Dragon/data/TEST_GEO_latt_tspc_S30.access index bb190e8..10c3098 100755 --- a/Dragon/data/TEST_GEO_latt_tspc_S30.access +++ b/Dragon/data/TEST_GEO_latt_tspc_S30.access @@ -27,7 +27,9 @@ if [ -f "$pos"/draglibendfb7r1SHEM315_v5p1.gz ] then echo 'gunzipping draglibendfb7r1SHEM315_v5p1' chmod 755 "$pos" - gunzip "$pos"/draglibendfb7r1SHEM315_v5p1.gz + if [ ! -f "$pos"/draglibendfb7r1SHEM315_v5p1 ]; then + gunzip "$pos"/draglibendfb7r1SHEM315_v5p1.gz + fi fi if [ -f "$pos"/draglibendfb7r1SHEM315_v5p1 ] then diff --git a/Dragon/data/fbr_colorset.access b/Dragon/data/fbr_colorset.access index 298d7b1..c25647b 100755 --- a/Dragon/data/fbr_colorset.access +++ b/Dragon/data/fbr_colorset.access @@ -27,7 +27,9 @@ if [ -f "$pos"/draglibendfb7r1SHEM315_v5p1.gz ] then echo 'gunzipping DLIB_315' chmod 755 "$pos" - gunzip "$pos"/draglibendfb7r1SHEM315_v5p1.gz + if [ ! -f "$pos"/draglibendfb7r1SHEM315_v5p1 ]; then + gunzip "$pos"/draglibendfb7r1SHEM315_v5p1.gz + fi fi if [ -f "$pos"/draglibendfb7r1SHEM315_v5p1 ] then diff --git a/Dragon/data/fbr_tone.access b/Dragon/data/fbr_tone.access index 396e3d6..fd8a33e 100755 --- a/Dragon/data/fbr_tone.access +++ b/Dragon/data/fbr_tone.access @@ -27,7 +27,9 @@ if [ -f "$pos"/draglibendfb7r1SHEM315_v5p1.gz ] then echo 'gunzipping DLIB_315' chmod 755 "$pos" - gunzip "$pos"/draglibendfb7r1SHEM315_v5p1.gz + if [ ! -f "$pos"/draglibendfb7r1SHEM315_v5p1 ]; then + gunzip "$pos"/draglibendfb7r1SHEM315_v5p1.gz + fi fi if [ -f "$pos"/draglibendfb7r1SHEM315_v5p1 ] then diff --git a/Dragon/src/Makefile b/Dragon/src/Makefile index c675c26..b423600 100644 --- a/Dragon/src/Makefile +++ b/Dragon/src/Makefile @@ -1,7 +1,7 @@ #--------------------------------------------------------------------------- # # Makefile for building the Dragon library and load module -# Author : A. Hebert (2018-5-10) +# Author : A. Hebert (2018-5-10) and C. Bienvenue (2025-11-04) # #--------------------------------------------------------------------------- # @@ -20,6 +20,7 @@ DIRNAME = $(shell uname -sm | sed 's/[ ]/_/') OS = $(shell uname -s | cut -d"_" -f1) opt = -O -g PREPRO = cpp +.DEFAULT_GOAL := all ifeq ($(openmp),1) COMP = -fopenmp PREPRO = cpp -D_OPENMP @@ -46,12 +47,11 @@ else endif ifeq ($(OS),AIX) - python_version_major := 2 + PY := python else - python_version_full := $(wordlist 2,4,$(subst ., ,$(shell python --version 2>&1))) - python_version_major := $(word 1,${python_version_full}) - ifneq ($(python_version_major),2) - python_version_major := 3 + PY := $(shell command -v python3 2>/dev/null) + ifeq ($(PY),) + PY := $(shell command -v python 2>/dev/null) endif endif @@ -158,7 +158,9 @@ else lib_module = ../lib/$(DIRNAME)_llvm/modules INCLUDE = -I../../Ganlib/lib/$(DIRNAME)_llvm/modules/ FFLAGS += -mmlir -fdynamic-heap-array - LFLAGS += -lclang_rt.osx + ifeq ($(OS),Darwin) + LFLAGS += -lclang_rt.osx + endif else lib = ../lib/$(DIRNAME) libUtl = ../../Utilib/lib/$(DIRNAME) @@ -177,18 +179,35 @@ ifeq ($(hdf5),1) LFLAGS += -L${HDF5_API} -lhdf5 endif -SRCC = $(shell ls *.c) -SRC77 = $(shell ls *.f) -SRCF77 = $(shell ls *.F) -ifeq ($(python_version_major),2) - SRC90 = $(shell python ../../script/make_depend.py *.f90) +FFLAGS += -cpp + +SRCC = $(shell ls *.c 2>/dev/null) +SRC77 = $(filter-out %.pp.f,$(shell ls *.f 2>/dev/null)) +SRCF77 = $(shell ls *.F 2>/dev/null) +ifeq ($(PY),) + $(warning No Python interpreter found; Fortran dependency ordering may be suboptimal) + SRC90_RAW = $(shell ls *.f90 *.F90 2>/dev/null) + SRC90 = $(filter-out %.pp.f90,$(SRC90_RAW)) else - SRC90 = $(shell python3 ../../script/make_depend_py3.py *.f90) + SRC90_RAW = $(shell $(PY) ../../script/make_depend.py *.f90 *.F90) + SRC90 = $(filter-out %.pp.f90,$(SRC90_RAW)) endif OBJC = $(SRCC:.c=.o) -OBJ90 = $(SRC90:.f90=.o) +OBJ90 = $(patsubst %.f90,%.o,$(patsubst %.F90,%.o,$(SRC90))) OBJ77 = $(SRC77:.f=.o) OBJF77 = $(SRCF77:.F=.o) + +# Auto-generated dependency file capturing Fortran module and include deps +DEPS_MK := .dragon_deps.mk +-include $(DEPS_MK) +$(DEPS_MK): $(SRC90) $(SRC77) $(SRCF77) +ifeq ($(PY),) + @echo "# Dependencies not generated: no Python available" > $(DEPS_MK) +else + @echo "# Generating Fortran dependencies into $(DEPS_MK)"; \ + $(PY) ../../script/make_depend.py --make-deps $(SRC90) $(SRC77) $(SRCF77) > $(DEPS_MK) || { rm -f $(DEPS_MK); exit 1; } +endif + all : sub-make Dragon ifeq ($(openmp),1) @echo 'Dragon: openmp is defined' @@ -206,26 +225,29 @@ ifeq ($(hdf5),1) @echo 'Dragon: hdf5 is defined' endif sub-make: + $(MAKE) openmp=$(openmp) intel=$(intel) nvidia=$(nvidia) llvm=$(llvm) hdf5=$(hdf5) -C ../../Utilib/src + $(MAKE) openmp=$(openmp) intel=$(intel) nvidia=$(nvidia) llvm=$(llvm) hdf5=$(hdf5) -C ../../Ganlib/src $(MAKE) openmp=$(openmp) intel=$(intel) nvidia=$(nvidia) llvm=$(llvm) hdf5=$(hdf5) -C ../../Trivac/src %.o : %.c $(C) $(CFLAGS) $(opt) $(COMP) -c $< -o $@ %.o : %.f90 $(F90) $(FFLAGS) $(opt) $(COMP) $(INCLUDE) -c $< -o $@ +%.o : %.F90 + # Use Fortran compiler's integrated preprocessor instead of cpp -traditional + $(F90) $(FFLAGS) $(opt) $(COMP) $(INCLUDE) $(FLAGS) -c $< -o $@ %.o : %.f - @/bin/rm -f temp.f $(F90) $(FFLAG77) $(opt) $(COMP) $(INCLUDE) -c $< -o $@ %.o : %.F - $(PREPRO) -P -W -traditional $(FLAGS) $< temp.f - $(F90) $(FFLAG77) $(opt) $(COMP) $(INCLUDE) -c temp.f -o $@ - /bin/rm temp.f + # Use Fortran compiler's integrated preprocessor only for .F (not for .f) + $(F90) $(FFLAG77) -cpp $(opt) $(COMP) $(INCLUDE) $(FLAGS) -c $< -o $@ $(lib_module)/: mkdir -p $(lib_module)/ $(lib)/: $(lib_module)/ mkdir -p $(lib)/ -libDragon.a: $(OBJC) $(OBJ90) $(OBJ77) $(OBJF77) $(lib)/ - ar r $@ $(OBJC) $(OBJ90) $(OBJ77) $(OBJF77) +libDragon.a: $(DEPS_MK) $(OBJC) $(OBJ90) $(OBJ77) $(OBJF77) $(lib)/ + ar rcs $@ $(OBJC) $(OBJ90) $(OBJ77) $(OBJF77) cp $@ $(lib)/$@ - cp *.mod $(lib_module) + if ls *.mod 1> /dev/null 2>&1; then cp *.mod $(lib_module); fi $(bin)/: mkdir -p $(bin)/ Dragon: libDragon.a DRAGON.o $(bin)/ sub-make @@ -234,4 +256,4 @@ Dragon: libDragon.a DRAGON.o $(bin)/ sub-make cp $@ $(bin)/$@ clean: $(MAKE) -C ../../Trivac/src clean - /bin/rm -f *.o *.mod *.a sub-make temp.* Dragon + /bin/rm -f *.o *.mod *.a sub-make temp.* Dragon $(DEPS_MK) *.pp.f *.pp.f90 diff --git a/Ganlib/src/Makefile b/Ganlib/src/Makefile index 0a4ad6f..4235f13 100644 --- a/Ganlib/src/Makefile +++ b/Ganlib/src/Makefile @@ -1,7 +1,7 @@ #--------------------------------------------------------------------------- # # Makefile for building the Ganlib library and load module -# Author : A. Hebert (2018-5-10) +# Author : A. Hebert (2018-5-10) and C. Bienvenue (2025-11-04) # #--------------------------------------------------------------------------- # @@ -19,6 +19,7 @@ endif DIRNAME = $(shell uname -sm | sed 's/[ ]/_/') OS = $(shell uname -s | cut -d"_" -f1) opt = -O -g +.DEFAULT_GOAL := all PREPRO = cpp ifeq ($(openmp),1) COMP = -fopenmp @@ -54,12 +55,11 @@ else endif ifeq ($(OS),AIX) - python_version_major := 2 + PY := python else - python_version_full := $(wordlist 2,4,$(subst ., ,$(shell python --version 2>&1))) - python_version_major := $(word 1,${python_version_full}) - ifneq ($(python_version_major),2) - python_version_major := 3 + PY := $(shell command -v python3 2>/dev/null) + ifeq ($(PY),) + PY := $(shell command -v python 2>/dev/null) endif endif @@ -152,7 +152,9 @@ else bin = ../bin/$(DIRNAME)_llvm lib_module = ../lib/$(DIRNAME)_llvm/modules FFLAGS += -mmlir -fdynamic-heap-array - LFLAGS += -lclang_rt.osx + ifeq ($(OS),Darwin) + LFLAGS += -lclang_rt.osx + endif else lib = ../lib/$(DIRNAME) bin = ../bin/$(DIRNAME) @@ -167,20 +169,34 @@ ifeq ($(hdf5),1) LFLAGS += -L${HDF5_API} -lhdf5 endif -SRCC = $(shell ls *.c) -SRC77 = $(shell ls *.f) -SRCF77 = $(shell ls *.F) -ifeq ($(python_version_major),2) - SRC90 = $(shell python ../../script/make_depend.py *.f90) +SRCC = $(shell ls *.c 2>/dev/null) +SRC77 = $(shell ls *.f 2>/dev/null) +SRCF77 = $(shell ls *.F 2>/dev/null) +ifeq ($(PY),) + $(warning No Python interpreter found; Fortran dependency ordering may be suboptimal) + SRC90 = $(shell ls *.f90 2>/dev/null) + SRCF90 = $(shell ls *.F90 2>/dev/null) else - SRC90 = $(shell python3 ../../script/make_depend_py3.py *.f90) + SRC90 = $(shell $(PY) ../../script/make_depend.py *.f90 *.F90) + SRCF90 = endif -SRCF90 = $(shell ls *.F90) OBJC = $(SRCC:.c=.o) -OBJ90 = $(SRC90:.f90=.o) +OBJ90 = $(patsubst %.f90,%.o,$(patsubst %.F90,%.o,$(SRC90))) OBJF90 = $(SRCF90:.F90=.o) OBJ77 = $(SRC77:.f=.o) OBJF77 = $(SRCF77:.F=.o) + +# Auto-generated dependency file capturing Fortran module and include deps +DEPS_MK := .ganlib_deps.mk +-include $(DEPS_MK) +$(DEPS_MK): $(SRC90) $(SRC77) $(SRCF77) +ifeq ($(PY),) + @echo "# Dependencies not generated: no Python available" > $(DEPS_MK) +else + @echo "# Generating Fortran dependencies into $(DEPS_MK)"; \ + $(PY) ../../script/make_depend.py --make-deps $(SRC90) $(SRC77) $(SRCF77) > $(DEPS_MK) || { rm -f $(DEPS_MK); exit 1; } +endif + all : sub-make Ganlib ifeq ($(mpi),1) @echo 'Ganlib: mpi is defined' @@ -200,27 +216,26 @@ endif ifeq ($(hdf5),1) @echo 'Ganlib: hdf5 is defined' endif - @echo 'Ganlib: python version=' $(python_version_major) + @echo 'Ganlib: python=' $(PY) sub-make: %.o : %.c $(C) $(CFLAGS) $(FLAGS) $(opt) $(COMP) -c $< -o $@ %.o : %.f90 $(F90) $(FFLAGS) $(opt) $(COMP) -c $< -o $@ %.o : %.F90 - $(PREPRO) -P -W -traditional $(FLAGS) $< temp.f90 - $(F90) $(FFLAGS) $(opt) $(COMP) -c temp.f90 -o $@ - /bin/rm temp.f90 + $(PREPRO) -P -W -traditional $(FLAGS) $< $(@:.o=.pp.f90) + $(F90) $(FFLAGS) $(opt) $(COMP) -c $(@:.o=.pp.f90) -o $@ + /bin/rm -f $(@:.o=.pp.f90) %.o : %.f - @/bin/rm -f temp.f $(F90) $(FFLAG77) $(opt) $(COMP) -c $< -o $@ %.o : %.F - $(PREPRO) -P -W -traditional $(FLAGS) $(FMPI) $< temp.f - $(F90) $(FFLAG77) $(opt) $(COMP) -c temp.f -o $@ - /bin/rm temp.f + $(PREPRO) -P -W -traditional $(FLAGS) $(FMPI) $< $(@:.o=.pp.f) + $(F90) $(FFLAG77) $(opt) $(COMP) -c $(@:.o=.pp.f) -o $@ + /bin/rm -f $(@:.o=.pp.f) $(lib_module)/: mkdir -p $(lib_module)/ -libGanlib.a: $(OBJC) $(OBJ90) $(OBJF90) $(OBJ77) $(OBJF77) $(lib_module)/ - ar r $@ $(OBJC) $(OBJ90) $(OBJF90) $(OBJ77) $(OBJF77) +libGanlib.a: $(DEPS_MK) $(OBJC) $(OBJ90) $(OBJF90) $(OBJ77) $(OBJF77) $(lib_module)/ + ar rcs $@ $(OBJC) $(OBJ90) $(OBJF90) $(OBJ77) $(OBJF77) cp $@ $(lib)/$@ cp *.mod $(lib_module) $(bin)/: @@ -229,4 +244,4 @@ Ganlib: libGanlib.a GANMAIN.o $(bin)/ $(F90) $(opt) $(COMP) GANMAIN.o $(lib)/libGanlib.a $(LFLAGS) -o Ganlib cp $@ $(bin)/$@ clean: - /bin/rm -f *.o *.mod *.a sub-make temp.* Ganlib* + /bin/rm -f *.o *.mod *.a sub-make temp.* Ganlib* $(DEPS_MK) *.pp.f *.pp.f90 diff --git a/PyGan/src/Makefile b/PyGan/src/Makefile index f48c98a..8520eef 100644 --- a/PyGan/src/Makefile +++ b/PyGan/src/Makefile @@ -16,6 +16,9 @@ PYTHONPATH = $(pylib)/python $(info set PYTHONPATH="$(PYTHONPATH)") export PYTHONPATH +# Build defaults and phony targets +.DEFAULT_GOAL := all + ifeq ($(intel),1) ifeq ($(INTELTOOLS),) $(error INTELTOOLS is not set) @@ -50,11 +53,11 @@ else endif endif export COMPILER +# export FORTRANPATH -all: - $(MAKE) donjon +all: donjon checkPython: ; @which python3 > /dev/null -ganlib: clean sub-make-ganlib pygan-ganlib +ganlib: sub-make-ganlib pygan-ganlib ifeq ($(openmp),1) @echo 'pygan_ganlib: openmp is defined' endif @@ -70,7 +73,7 @@ endif ifeq ($(hdf5),1) @echo 'pygan_ganlib: hdf5 is defined' endif -trivac: clean sub-make-trivac pygan-trivac +trivac: sub-make-trivac pygan-trivac ifeq ($(openmp),1) @echo 'pygan_trivac: openmp is defined' endif @@ -86,7 +89,7 @@ endif ifeq ($(hdf5),1) @echo 'pygan_trivac: hdf5 is defined' endif -dragon: clean sub-make-dragon pygan-dragon +dragon: sub-make-dragon pygan-dragon ifeq ($(openmp),1) @echo 'pygan_dragon: openmp is defined' endif @@ -102,7 +105,7 @@ endif ifeq ($(hdf5),1) @echo 'pygan_dragon: hdf5 is defined' endif -donjon: clean sub-make-donjon pygan-donjon +donjon: sub-make-donjon pygan-donjon ifeq ($(openmp),1) @echo 'pygan_donjon: openmp is defined' endif @@ -119,14 +122,14 @@ ifeq ($(hdf5),1) @echo 'pygan_donjon: hdf5 is defined' endif sub-make-ganlib: - $(MAKE) openmp=$(openmp) hdf5=$(hdf5) -C ../../Ganlib/src + $(MAKE) openmp=$(openmp) intel=$(intel) nvidia=$(nvidia) llvm=$(llvm) hdf5=$(hdf5) -C ../../Ganlib/src sub-make-trivac: sub-make-ganlib - $(MAKE) openmp=$(openmp) -C ../../Utilib/src - $(MAKE) openmp=$(openmp) hdf5=$(hdf5) -C ../../Trivac/src + $(MAKE) openmp=$(openmp) intel=$(intel) nvidia=$(nvidia) llvm=$(llvm) -C ../../Utilib/src + $(MAKE) openmp=$(openmp) intel=$(intel) nvidia=$(nvidia) llvm=$(llvm) hdf5=$(hdf5) -C ../../Trivac/src sub-make-dragon: sub-make-trivac - $(MAKE) openmp=$(openmp) hdf5=$(hdf5) -C ../../Dragon/src + $(MAKE) openmp=$(openmp) intel=$(intel) nvidia=$(nvidia) llvm=$(llvm) hdf5=$(hdf5) -C ../../Dragon/src sub-make-donjon: sub-make-dragon - $(MAKE) openmp=$(openmp) hdf5=$(hdf5) -C ../../Donjon/src + $(MAKE) openmp=$(openmp) intel=$(intel) nvidia=$(nvidia) llvm=$(llvm) hdf5=$(hdf5) -C ../../Donjon/src libGanlib.a: $(lib)/ sub-make-ganlib cp $(libGan)/libGanlib.a . ar -d libGanlib.a xabort_c.o @@ -144,8 +147,8 @@ ifeq ($(openmp),1) else export CODE_EMBEDDED=GANLIB; cd $(DIRNAME); python3 setup_cle2000.py install --home=. endif - mv $(DIRNAME)/$(pylib)/* $(lib)/ - /bin/rm -r $(DIRNAME) + cp -R $(DIRNAME)/$(pylib)/* $(lib)/ + /bin/rm -rf $(DIRNAME) pygan-trivac: libGanlib.a sub-make-trivac checkPython mkdir -p $(DIRNAME) cp *.[ch] $(DIRNAME) @@ -157,8 +160,8 @@ ifeq ($(openmp),1) else export CODE_EMBEDDED=TRIVAC; cd $(DIRNAME); python3 setup_cle2000.py install --home=. endif - mv $(DIRNAME)/$(pylib)/* $(lib)/ - /bin/rm -r $(DIRNAME) + cp -R $(DIRNAME)/$(pylib)/* $(lib)/ + /bin/rm -rf $(DIRNAME) pygan-dragon: libGanlib.a sub-make-dragon checkPython mkdir -p $(DIRNAME) cp *.[ch] $(DIRNAME) @@ -170,8 +173,8 @@ ifeq ($(openmp),1) else export CODE_EMBEDDED=DRAGON; cd $(DIRNAME); python3 setup_cle2000.py install --home=. endif - mv $(DIRNAME)/$(pylib)/* $(lib)/ - /bin/rm -r $(DIRNAME) + cp -R $(DIRNAME)/$(pylib)/* $(lib)/ + /bin/rm -rf $(DIRNAME) pygan-donjon: libGanlib.a sub-make-donjon checkPython mkdir -p $(DIRNAME) cp *.[ch] $(DIRNAME) @@ -183,8 +186,8 @@ ifeq ($(openmp),1) else export CODE_EMBEDDED=DONJON; cd $(DIRNAME); python3 setup_cle2000.py install --home=. endif - mv $(DIRNAME)/$(pylib)/* $(lib)/ - /bin/rm -r $(DIRNAME) + cp -R $(DIRNAME)/$(pylib)/* $(lib)/ + /bin/rm -rf $(DIRNAME) @echo 'makefile PYTHONPATH=' $(PYTHONPATH) clean: @echo 'clean PyGan' diff --git a/PyGan/src/setup_cle2000.py b/PyGan/src/setup_cle2000.py index d416245..c712b26 100644 --- a/PyGan/src/setup_cle2000.py +++ b/PyGan/src/setup_cle2000.py @@ -10,14 +10,26 @@ else: from distutils.core import setup, Extension import sysconfig +def _detect_gfortran_dir(): + import subprocess, os + try: + out = subprocess.check_output(['gfortran', '-print-file-name=libgfortran.dylib'], text=True).strip() + if out and out != 'libgfortran.dylib': + d = os.path.dirname(out) + if os.path.isdir(d): + return d + except Exception: + pass + return None + def main(): import os from sysconfig import get_config_var mach = os.path.basename(os.getcwd()) Code = os.environ.get("CODE_EMBEDDED", None) # Code selection Compiler = os.environ.get("COMPILER", None) # Compiler selection - FortranLib = os.environ.get(Compiler, None) # directory with libfortran.a - HDF5Lib = os.environ.get("HDF5_API", None) # directory with libhdf5.a + FortranLib = _detect_gfortran_dir() # directory with libfortran + HDF5Lib = os.environ.get("HDF5_API", None) # directory with libhdf5 pylib = os.path.basename(get_config_var("LIBDIR")) # get lib or lib64 print("install Cle2000 binding to", Code, "on directory",mach, "pylib=",pylib, "Compiler=",Compiler) if Compiler == "NVTOOLS": @@ -49,6 +61,14 @@ def main(): libDon="../../../Donjon/lib/"+mach extralink=["-lgfortran", ] print("debug Compiler=",Compiler,"libdir=",libdir,"Code=",Code) + if FortranLib: + print("debug FortranLib=", FortranLib) + if HDF5Lib: + print("debug HDF5Lib=", HDF5Lib) + + # Build helper lists with None filtered out + def _dirs(*args): + return [d for d in args if d] if Code == "GANLIB": setup (name="Cle2000", @@ -60,8 +80,8 @@ def main(): ext_modules=[Extension('cle2000',sources=['cle2000module.c'], extra_link_args = extralink, include_dirs=["../../../Ganlib/src"], - library_dirs=[libdir,FortranLib,HDF5Lib], - runtime_library_dirs=[FortranLib,HDF5Lib], + library_dirs=_dirs(libdir,FortranLib,HDF5Lib), + runtime_library_dirs=_dirs(FortranLib,HDF5Lib), libraries=["Ganlib","hdf5"] ) ]) elif Code == "TRIVAC": setup (name="Cle2000", @@ -74,8 +94,8 @@ def main(): define_macros=[('__trivac__', None)], extra_link_args = extralink, include_dirs=["../../../Ganlib/src"], - library_dirs=[libdir,FortranLib,HDF5Lib,libUtl,libTri], - runtime_library_dirs=[FortranLib,HDF5Lib], + library_dirs=_dirs(libdir,FortranLib,HDF5Lib,libUtl,libTri), + runtime_library_dirs=_dirs(FortranLib,HDF5Lib), libraries=["Trivac","Utilib","Ganlib","hdf5"] ) ]) elif Code == "DRAGON": setup (name="Cle2000", @@ -88,8 +108,8 @@ def main(): define_macros=[('__dragon__', None)], extra_link_args = extralink, include_dirs=["../../../Ganlib/src"], - library_dirs=[libdir,FortranLib,HDF5Lib,libUtl,libTri,libDra], - runtime_library_dirs=[FortranLib,HDF5Lib], + library_dirs=_dirs(libdir,FortranLib,HDF5Lib,libUtl,libTri,libDra), + runtime_library_dirs=_dirs(FortranLib,HDF5Lib), libraries=["Dragon","Trivac","Utilib","Ganlib","hdf5"] ) ]) elif Code == "DONJON": setup (name="Cle2000", @@ -102,8 +122,8 @@ def main(): define_macros=[('__donjon__', None)], extra_link_args = extralink, include_dirs=["../../../Ganlib/src"], - library_dirs=[libdir,FortranLib,HDF5Lib,libUtl,libTri,libDra,libDon], - runtime_library_dirs=[FortranLib,HDF5Lib], + library_dirs=_dirs(libdir,FortranLib,HDF5Lib,libUtl,libTri,libDra,libDon), + runtime_library_dirs=_dirs(FortranLib,HDF5Lib), libraries=["Donjon","Dragon","Trivac","Utilib","Ganlib","hdf5"] ) ]) elif Code == "GANLIB_OMP": setup (name="Cle2000", @@ -115,8 +135,8 @@ def main(): ext_modules=[Extension('cle2000',sources=['cle2000module.c'], extra_link_args = ["-lgomp"]+extralink, include_dirs=["../../../Ganlib/src"], - library_dirs=[libdir,FortranLib,HDF5Lib], - runtime_library_dirs=[FortranLib,HDF5Lib], + library_dirs=_dirs(libdir,FortranLib,HDF5Lib), + runtime_library_dirs=_dirs(FortranLib,HDF5Lib), libraries=["Ganlib","hdf5"] ) ]) elif Code == "TRIVAC_OMP": setup (name="Cle2000", @@ -129,8 +149,8 @@ def main(): define_macros=[('__trivac__', None)], extra_link_args = ["-lgomp"]+extralink, include_dirs=["../../../Ganlib/src"], - library_dirs=[libdir,FortranLib,HDF5Lib,libUtl,libTri], - runtime_library_dirs=[FortranLib,HDF5Lib], + library_dirs=_dirs(libdir,FortranLib,HDF5Lib,libUtl,libTri), + runtime_library_dirs=_dirs(FortranLib,HDF5Lib), libraries=["Trivac","Utilib","Ganlib","hdf5"] ) ]) elif Code == "DRAGON_OMP": setup (name="Cle2000", @@ -143,8 +163,8 @@ def main(): define_macros=[('__dragon__', None)], extra_link_args = ["-lgomp"]+extralink, include_dirs=["../../../Ganlib/src"], - library_dirs=[libdir,FortranLib,HDF5Lib,libUtl,libTri,libDra], - runtime_library_dirs=[FortranLib,HDF5Lib], + library_dirs=_dirs(libdir,FortranLib,HDF5Lib,libUtl,libTri,libDra), + runtime_library_dirs=_dirs(FortranLib,HDF5Lib), libraries=["Dragon","Trivac","Utilib","Ganlib","hdf5"] ) ]) elif Code == "DONJON_OMP": setup (name="Cle2000", @@ -157,8 +177,8 @@ def main(): define_macros=[('__donjon__', None)], extra_link_args = ["-lgomp"]+extralink, include_dirs=["../../../Ganlib/src"], - library_dirs=[libdir,FortranLib,HDF5Lib,libUtl,libTri,libDra,libDon], - runtime_library_dirs=[FortranLib,HDF5Lib], + library_dirs=_dirs(libdir,FortranLib,HDF5Lib,libUtl,libTri,libDra,libDon), + runtime_library_dirs=_dirs(FortranLib,HDF5Lib), libraries=["Donjon","Dragon","Trivac","Utilib","Ganlib","hdf5"] ) ]) else: raise ValueError(Code+" is not implemented for setup.py bindings") diff --git a/PyGan/src/setup_lcm.py b/PyGan/src/setup_lcm.py index 79e7891..76829b4 100644 --- a/PyGan/src/setup_lcm.py +++ b/PyGan/src/setup_lcm.py @@ -22,16 +22,25 @@ def main(): extralink=["-lnvc","-lnvcpumath"] elif Compiler == "LLVMTOOLS": libdir="../../lib/"+mach+"_llvm" - libNv=" " + libNv=None extralink=[ ] elif Compiler == "INTELTOOLS": libdir="../../lib/"+mach+"_intel" - libNv=" " + libNv=None extralink=[ ] else: libdir="../../lib/"+mach - libNv=" " + libNv=None extralink=[ ] + # Filter out missing/empty library dirs to avoid "-L " warnings + def _dirs(*paths): + out=[] + for p in paths: + if p and isinstance(p, str) and os.path.isdir(p): + out.append(p) + return out + lib_dirs = _dirs(libdir, libNv) + rpath_dirs = _dirs(libNv) setup(name="Lcm", version="5.0", description="Python interface for the lcm C library API", @@ -41,8 +50,8 @@ def main(): ext_modules=[Extension("lcm", ["lcmmodule.c"], extra_link_args = extralink, include_dirs=["../../../Ganlib/src",incdir], - library_dirs=[libdir,libNv], - runtime_library_dirs=[libNv], + library_dirs=lib_dirs, + runtime_library_dirs=rpath_dirs, libraries=["Ganlib"] ) ]) if __name__ == "__main__": diff --git a/Trivac/src/Makefile b/Trivac/src/Makefile index 6a70191..2ad728a 100644 --- a/Trivac/src/Makefile +++ b/Trivac/src/Makefile @@ -1,7 +1,7 @@ #--------------------------------------------------------------------------- # # Makefile for building the Trivac library and load module -# Author : A. Hebert (2018-5-10) +# Author : A. Hebert (2018-5-10) and C. Bienvenue (2025-11-04) # #--------------------------------------------------------------------------- # @@ -19,6 +19,7 @@ endif DIRNAME = $(shell uname -sm | sed 's/[ ]/_/') OS = $(shell uname -s | cut -d"_" -f1) opt = -O -g +.DEFAULT_GOAL := all ifeq ($(openmp),1) COMP = -fopenmp else @@ -44,12 +45,11 @@ else endif ifeq ($(OS),AIX) - python_version_major := 2 + PY := python else - python_version_full := $(wordlist 2,4,$(subst ., ,$(shell python --version 2>&1))) - python_version_major := $(word 1,${python_version_full}) - ifneq ($(python_version_major),2) - python_version_major := 3 + PY := $(shell command -v python3 2>/dev/null) + ifeq ($(PY),) + PY := $(shell command -v python 2>/dev/null) endif endif @@ -134,7 +134,9 @@ else bin = ../bin/$(DIRNAME)_llvm INCLUDE = -I../../Ganlib/lib/$(DIRNAME)_llvm/modules/ FFLAGS += -mmlir -fdynamic-heap-array - LFLAGS += -lclang_rt.osx + ifeq ($(OS),Darwin) + LFLAGS += -lclang_rt.osx + endif else lib = ../lib/$(DIRNAME) libUtl = ../../Utilib/lib/$(DIRNAME) @@ -151,14 +153,27 @@ ifeq ($(hdf5),1) LFLAGS += -L${HDF5_API} -lhdf5 endif -SRC77 = $(shell ls *.f) -ifeq ($(python_version_major),2) - SRC90 = $(shell python ../../script/make_depend.py *.f90) +SRC77 = $(shell ls *.f 2>/dev/null) +ifeq ($(PY),) + $(warning No Python interpreter found; Fortran dependency ordering may be suboptimal) + SRC90 = $(shell ls *.f90 2>/dev/null) else - SRC90 = $(shell python3 ../../script/make_depend_py3.py *.f90) + SRC90 = $(shell $(PY) ../../script/make_depend.py *.f90 *.F90) endif -OBJ90 = $(SRC90:.f90=.o) +OBJ90 = $(patsubst %.f90,%.o,$(patsubst %.F90,%.o,$(SRC90))) OBJ77 = $(SRC77:.f=.o) + +# Auto-generated dependency file capturing Fortran module and include deps +DEPS_MK := .trivac_deps.mk +-include $(DEPS_MK) +$(DEPS_MK): $(SRC90) $(SRC77) $(SRCF77) +ifeq ($(PY),) + @echo "# Dependencies not generated: no Python available" > $(DEPS_MK) +else + @echo "# Generating Fortran dependencies into $(DEPS_MK)"; \ + $(PY) ../../script/make_depend.py --make-deps $(SRC90) $(SRC77) $(SRCF77) > $(DEPS_MK) || { rm -f $(DEPS_MK); exit 1; } +endif + all : sub-make Trivac ifeq ($(openmp),1) @echo 'Trivac: openmp is defined' @@ -184,8 +199,8 @@ sub-make: $(F90) $(FFLAG77) $(opt) $(COMP) $(INCLUDE) -c $< -o $@ $(lib)/: mkdir -p $(lib)/ -libTrivac.a: $(OBJ90) $(OBJ77) $(lib)/ - ar r $@ $(OBJ90) $(OBJ77) +libTrivac.a: $(DEPS_MK) $(OBJ90) $(OBJ77) $(lib)/ + ar rcs $@ $(OBJ90) $(OBJ77) cp $@ $(lib)/$@ $(bin)/: mkdir -p $(bin)/ @@ -196,4 +211,4 @@ Trivac: libTrivac.a TRIVAC.o $(bin)/ sub-make clean: $(MAKE) -C ../../Utilib/src clean $(MAKE) -C ../../Ganlib/src clean - /bin/rm -f *.o *.a sub-make temp.* Trivac + /bin/rm -f *.o *.a sub-make temp.* Trivac $(DEPS_MK) diff --git a/Utilib/src/Makefile b/Utilib/src/Makefile index 2bb6d73..e56d213 100644 --- a/Utilib/src/Makefile +++ b/Utilib/src/Makefile @@ -1,7 +1,7 @@ #--------------------------------------------------------------------------- # # Makefile for building the Utilib library -# Author : A. Hebert (2018-5-10) +# Author : A. Hebert (2018-5-10) and C. Bienvenue (2025-11-04) # #--------------------------------------------------------------------------- # @@ -19,6 +19,7 @@ endif DIRNAME = $(shell uname -sm | sed 's/[ ]/_/') OS = $(shell uname -s | cut -d"_" -f1) opt = -O -g +.DEFAULT_GOAL := all ifeq ($(openmp),1) COMP = -fopenmp else @@ -44,12 +45,11 @@ else endif ifeq ($(OS),AIX) - python_version_major := 2 + PY := python else - python_version_full := $(wordlist 2,4,$(subst ., ,$(shell python --version 2>&1))) - python_version_major := $(word 1,${python_version_full}) - ifneq ($(python_version_major),2) - python_version_major := 3 + PY := $(shell command -v python3 2>/dev/null) + ifeq ($(PY),) + PY := $(shell command -v python 2>/dev/null) endif endif @@ -128,7 +128,9 @@ else lib = ../lib/$(DIRNAME)_llvm lib_module = ../lib/$(DIRNAME)_llvm/modules FFLAGS += -mmlir -fdynamic-heap-array - LFLAGS += -lclang_rt.osx + ifeq ($(OS),Darwin) + LFLAGS += -lclang_rt.osx + endif else lib = ../lib/$(DIRNAME) lib_module = ../lib/$(DIRNAME)/modules @@ -136,16 +138,29 @@ else endif endif -SRCC = $(shell ls *.c) -SRC77 = $(shell ls *.f) -ifeq ($(python_version_major),2) - SRC90 = $(shell python ../../script/make_depend.py *.f90) +SRCC = $(shell ls *.c 2>/dev/null) +SRC77 = $(shell ls *.f 2>/dev/null) +ifeq ($(PY),) + $(warning No Python interpreter found; Fortran dependency ordering may be suboptimal) + SRC90 = $(shell ls *.f90 2>/dev/null) else - SRC90 = $(shell python3 ../../script/make_depend_py3.py *.f90) + SRC90 = $(shell $(PY) ../../script/make_depend.py *.f90 *.F90) endif OBJC = $(SRCC:.c=.o) -OBJ90 = $(SRC90:.f90=.o) +OBJ90 = $(patsubst %.f90,%.o,$(patsubst %.F90,%.o,$(SRC90))) OBJ77 = $(SRC77:.f=.o) + + # Auto-generated dependency file capturing Fortran module and include deps +DEPS_MK := .utilib_deps.mk +-include $(DEPS_MK) +$(DEPS_MK): $(SRC90) $(SRC77) $(SRCF77) +ifeq ($(PY),) + @echo "# Dependencies not generated: no Python available" > $(DEPS_MK) +else + @echo "# Generating Fortran dependencies into $(DEPS_MK)"; \ + $(PY) ../../script/make_depend.py --make-deps $(SRC90) $(SRC77) $(SRCF77) > $(DEPS_MK) || { rm -f $(DEPS_MK); exit 1; } +endif + all : libUtilib.a @echo 'Utilib: fflags=' $(FFLAGS) ifeq ($(openmp),1) @@ -158,9 +173,9 @@ ifeq ($(nvidia),1) @echo 'Utilib: nvidia is defined' endif ifeq ($(llvm),1) -] @echo 'Utilib: llvm is defined' + @echo 'Utilib: llvm is defined' endif - @echo "Utilib: python version=" ${python_version_major} + @echo "Utilib: python=" $(PY) %.o : %.c $(C) $(CFLAGS) $(opt) $(COMP) -c $< -o $@ %.o : %.f90 @@ -173,8 +188,8 @@ $(lib_module)/: $(lib)/: $(lib_module)/ mkdir -p $(lib)/ libUtilib.a: $(OBJC) $(OBJ90) $(OBJ77) $(lib)/ - ar r $@ $(OBJC) $(OBJ90) $(OBJ77) + ar rcs $@ $(OBJC) $(OBJ90) $(OBJ77) cp $@ $(lib)/$@ cp *.mod $(lib_module) clean: - /bin/rm -f *.o *.mod *.a + /bin/rm -f *.o *.mod *.a $(DEPS_MK) diff --git a/doc/IGE335/Section6.00.tex b/doc/IGE335/Section6.00.tex index f49f89b..c26d277 100644 --- a/doc/IGE335/Section6.00.tex +++ b/doc/IGE335/Section6.00.tex @@ -42,6 +42,12 @@ make make clean \end{verbatim} +To speed up the build, run make with multiple jobs using the \texttt{-jN} option. For example, to run 8 parallel jobs: +\begin{verbatim} +make -j8 +make clean +\end{verbatim} + \noindent To build an OpenMP-enabled version, simply write \begin{verbatim} make openmp=1 diff --git a/script/make_depend.py b/script/make_depend.py index 15c656e..ce8f688 100755 --- a/script/make_depend.py +++ b/script/make_depend.py @@ -1,57 +1,222 @@ -#!/bin/env python -""" generation of module dependances for a xxx.f90 or xxx.F90 file """ - -import string,sys -from subprocess import Popen, PIPE - -def noComment(mot): - """ remove comment characters in a word """ - ind= string.find(mot,'!') - if ind != -1: - mot= mot[:ind] - return mot - -class md9: - """ a file, its module and its dependances """ - def __init__(self,fic): - self.name= fic - self.used= [] - #find all module dependances - listeLignes= open(self.name,'r').readlines() - self.module= "dummy" - for ligne in listeLignes: - ligne= string.lower(ligne) - if string.count(ligne,'use'): - ligne= string.replace(ligne,',',' ') - listeMots= string.split(ligne) - if listeMots[0] == 'use': - mod= noComment(listeMots[1]) - if mod not in self.used and mod != 'intrinsic': - self.used.append(mod) - elif string.count(ligne,'module'): - listeMots= string.split(ligne) - if listeMots[0] == 'module' and \ - noComment(listeMots[1]) != 'procedure': - self.module= listeMots[1] - def utilise(self,other): - return (other.module in self.used) - -listeClasse= list() -for x in sys.argv[1:]: - if x.endswith('.f90') or x.endswith('.F90') : listeClasse.append(md9(x)) -#sort the file list -listeRes= [] -while listeClasse: - lgav= len(listeClasse) - for fic in listeClasse: - if len(filter(lambda x,y=fic:y.utilise(x),listeClasse)) == 0: - listeRes.append(fic) - listeClasse.remove(fic) - lgap= len(listeClasse) - if lgav == lgap and lgap != 0: - raise RuntimeError("make_depend: cross-references found") -#result output -resstr='' -for fic in listeRes: - resstr=resstr+fic.name+' ' -print resstr +#!/usr/bin/env python +""" +Generate Fortran dependencies from sources (*.f90, *.F90). + +Usage: + - Default: prints a dependency-ordered list of source files. + - --make-deps: prints Makefile-style dependency rules. +""" + +from __future__ import print_function +import sys +import os +import io +import re +import glob + +def strip_comment(line): + idx = line.find('!') + return line if idx == -1 else line[:idx] + +class FortranUnit(object): + USE_RE = re.compile(r"^\s*use\s+([a-z0-9_]+)", re.IGNORECASE) + MODULE_RE = re.compile(r"^\s*module\s+([a-z0-9_]+)", re.IGNORECASE) + MODULE_PROC_RE = re.compile(r"^\s*module\s+procedure\b", re.IGNORECASE) + END_MODULE_RE = re.compile(r"^\s*end\s*module\b", re.IGNORECASE) + CONTAINS_RE = re.compile(r"^\s*contains\b", re.IGNORECASE) + INCLUDE_RE = re.compile(r"^\s*include\s*[\'\"]([^\'\"]+)[\'\"]", re.IGNORECASE) + + def __init__(self, path): + self.name = path + self.base = os.path.basename(path) + self.base_lc = self.base.lower() + self.module = None + self.uses = [] + self.includes_in_contains = [] + self._parse() + + def _parse(self): + in_module = False + in_contains = False + try: + with io.open(self.name, 'r') as f: + lines = f.readlines() + except IOError: + return + for raw in lines: + line = strip_comment(raw).strip('\n') + if not line: + continue + low = line.lower() + if self.MODULE_RE.match(low) and not self.MODULE_PROC_RE.match(low): + m = self.MODULE_RE.match(low) + if m: + self.module = m.group(1) + in_module = True + in_contains = False + continue + if in_module and self.CONTAINS_RE.match(low): + in_contains = True + continue + if in_module and self.END_MODULE_RE.match(low): + in_module = False + in_contains = False + continue + m_use = self.USE_RE.match(low) + if m_use: + mod = m_use.group(1) + if mod != 'intrinsic' and mod not in self.uses: + self.uses.append(mod) + continue + if in_module and in_contains: + m_inc = self.INCLUDE_RE.match(low) + if m_inc: + inc = m_inc.group(1).strip() + self.includes_in_contains.append(os.path.basename(inc)) + +def build_units(paths): + exts = (".f90", ".F90", ".f", ".F") + return [FortranUnit(p) for p in paths if p.lower().endswith(exts)] + +def build_dependency_order(paths): + units = build_units(paths) + by_base_lc = dict((u.base_lc, u) for u in units) + module_to_unit = dict((u.module, u) for u in units if u.module) + included_to_container = {} + for u in units: + if u.module and u.includes_in_contains: + for inc in u.includes_in_contains: + included_to_container.setdefault(inc.lower(), set()).add(u) + + edges = dict((u, set()) for u in units) + indeg = dict((u, 0) for u in units) + + def add_edge(src, dst): + if src is dst: + return + if dst not in edges[src]: + edges[src].add(dst) + indeg[dst] += 1 + + for u in units: + for mod in u.uses: + v = module_to_unit.get(mod) + if not v: + continue + included_containers = included_to_container.get(u.base_lc, set()) + if v in included_containers: + continue + add_edge(v, u) + + for container in units: + if container.module and container.includes_in_contains: + for inc in container.includes_in_contains: + inc_u = by_base_lc.get(inc.lower()) + if inc_u: + add_edge(inc_u, container) + + ordered = [] + zero = [u for u in units if indeg[u] == 0] + zero.sort(key=lambda x: x.base_lc) + while zero: + n = zero.pop(0) + ordered.append(n) + for m in list(edges[n]): + edges[n].remove(m) + indeg[m] -= 1 + if indeg[m] == 0: + zero.append(m) + zero.sort(key=lambda x: x.base_lc) + + remaining = [u for u in units if u not in ordered] + if remaining: + remaining.sort(key=lambda x: (0 if not x.module else 1, x.base_lc)) + ordered.extend(remaining) + + excluded_bases = set() + for u in units: + if u.module and u.includes_in_contains: + for inc in u.includes_in_contains: + excluded_bases.add(inc.lower()) + + return [u.name for u in ordered if u.base_lc not in excluded_bases] + +def make_obj_name(path): + base, ext = os.path.splitext(path) + return base + ".o" + +def generate_make_deps(paths): + units = build_units(paths) + if not units: + return "" + by_base_lc = dict((u.base_lc, u) for u in units) + module_to_unit = dict((u.module, u) for u in units if u.module) + included_to_container = {} + for u in units: + if u.module and u.includes_in_contains: + for inc in u.includes_in_contains: + included_to_container.setdefault(inc.lower(), set()).add(u) + + lines = [] + for u in units: + deps_objs = set() + deps_files = set() + + for mod in u.uses: + v = module_to_unit.get(mod) + if not v: + continue + included_containers = included_to_container.get(u.base_lc, set()) + if v in included_containers: + continue + if v is not u: + deps_objs.add(make_obj_name(v.name)) + + if u.includes_in_contains: + for inc in u.includes_in_contains: + inc_u = by_base_lc.get(os.path.basename(inc).lower()) + if inc_u: + deps_files.add(inc_u.name) + else: + deps_files.add(inc) + + if deps_objs or deps_files: + target = make_obj_name(u.name) + deps = sorted(deps_objs) + sorted(deps_files) + lines.append("{}: {}".format(target, ' '.join(deps))) + + return "\n".join(lines) + ("\n" if lines else "") + +def main(): + argv = sys.argv[1:] + if not argv: + print("") + return + + make_deps = False + if "--make-deps" in argv: + make_deps = True + argv = [a for a in argv if a != "--make-deps"] + + paths = [] + for a in argv: + if any(ch in a for ch in ['*', '?', '[']): + paths.extend(glob.glob(a)) + else: + paths.append(a) + + seen = set() + unique_paths = [] + for p in paths: + if p not in seen: + seen.add(p) + unique_paths.append(p) + + if make_deps: + sys.stdout.write(generate_make_deps(unique_paths)) + else: + result = build_dependency_order(unique_paths) + sys.stdout.write("%s\n" % (" ".join(result))) + +if __name__ == '__main__': + main() diff --git a/script/make_depend_py3.py b/script/make_depend_py3.py deleted file mode 100755 index a47d7fb..0000000 --- a/script/make_depend_py3.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/env python3 -""" generation of module dependances for a xxx.f90 or xxx.F90 file """ - -import string,sys -from subprocess import Popen, PIPE - -def noComment(mot): - """ remove comment characters in a word """ - ind= mot.find('!') - if ind != -1: - mot= mot[:ind] - return mot - -class md9: - """ a file, its module and its dependances """ - def __init__(self,fic): - self.name= fic - self.used= [] - #find all module dependances - listeLignes= open(self.name,'r',encoding='utf8',errors='ignore').readlines() - self.module= "dummy" - for ligne in listeLignes: - ligne= ligne.lower() - if ligne.count('use'): - ligne= ligne.replace(',',' ') - listeMots= ligne.split() - if listeMots[0] == 'use': - mod= noComment(listeMots[1]) - if mod not in self.used and mod != 'intrinsic': - self.used.append(mod) - elif ligne.count('module'): - listeMots= ligne.split() - if listeMots[0] == 'module' and \ - noComment(listeMots[1]) != 'procedure': - self.module= listeMots[1] - def utilise(self,other): - return (other.module in self.used) - -#list the file names -listeClasse= list() -for x in sys.argv[1:]: - if x.endswith('.f90') or x.endswith('.F90'): listeClasse.append(md9(x)) -#sort the file list -listeRes= [] -while listeClasse: - lgav= len(listeClasse) - for fic in listeClasse: - if len(list(filter(lambda x,y=fic:y.utilise(x),listeClasse))) == 0: - listeRes.append(fic) - listeClasse.remove(fic) - lgap= len(listeClasse) - if lgav == lgap and lgap != 0: - raise RuntimeError("make_depend: cross-references found") -#result output -resstr='' -for fic in listeRes: - resstr=resstr+fic.name+' ' -print(resstr) -- cgit v1.2.3