How to create a makefile for a Fortran program using modules - module

The challenge is to create a makefile which takes a list of modules and does not require me to sort out precendence. For example, the modules are
mod allocations.f08 mod precision definitions.f08 mod unit values.f08
mod blocks.f08 mod shared.f08 mod parameters.f08
mod timers.f08
The main program is characterize.f08. The error message is
Fatal Error: Can't open module file ‘mprecisiondefinitions.mod’ for reading at (1): No such file or directory
The first statement in the main program is use mPrecisionDefinitions, the module defined in mod precision definitions.f08.
The following makefile, based upon Creating a FORTRAN makefile, is:
# compiler
FC := /usr/local/bin/gfortran
# compile flags
FCFLAGS = -g -c -Wall -Wextra -Wconversion -Og -pedantic -fcheck=bounds -fmax-errors=5
# link flags
FLFLAGS =
# source files and objects
SRCS = $(patsubst %.f08, %.o, $(wildcard *.f08))
# program name
PROGRAM = a.out
all: $(PROGRAM)
$(PROGRAM): $(SRCS)
$(FC) $(FLFLAGS) -o $# $^
%.mod: %.f08
$(FC) $(FCFLAGS) -o $# $<
%.o: %.f08
$(FC) $(FCFLAGS) -o $# $<
clean:
rm -f *.o *.mod

For starters, I recommend to replace all spaces in your file names with underscores or something similar.
Spaces are almost universally used as separators, and any program that is started with something like
gfortran -c -o mod precision definitions.o mod precision definitions.f08
would interpret this line as 'create an object file called mod from the source files precision, definitions.o, mod, precision, and definitions.f08. And while there are ways to do it, with increasing automation, you have to jump more and more hoops.
In contrast, this works well:
gfortran -c -o mod_precision_definitions.o mod_precision_definitions.f08
I would use this command to change all the spaces into underscores:
rename 's/ /_/g' *.f08
If that doesn't work, use this command:
for f in *.f08; do mv "$f" ${f// /_}; done
Next, I wouldn't worry about .mod files. They get generated together with the object files when you compile a module. So while technically some routine that uses a module requires the .mod file for that module, you might as well claim in your Makefile that it depends on the object file itself.
So with that said, here's the Makefile I would use (with some assumed inter-module dependencies added):
# Find all source files, create a list of corresponding object files
SRCS=$(wildcard *.f08)
OBJS=$(patsubst %.f08,%.o,$(SRCS))
# Ditto for mods (They will be in both lists)
MODS=$(wildcard mod*.f08)
MOD_OBJS=$(patsubst %.f08,%.o,$(MODS))
# Compiler/Linker settings
FC = gfortran
FLFLAGS = -g
FCFLAGS = -g -c -Wall -Wextra -Wconversion -Og -pedantic -fcheck=bounds -fmax-errors=5
PROGRAM = characterize
PRG_OBJ = $(PROGRAM).o
# make without parameters will make first target found.
default : $(PROGRAM)
# Compiler steps for all objects
$(OBJS) : %.o : %.f08
$(FC) $(FCFLAGS) -o $# $<
# Linker
$(PROGRAM) : $(OBJS)
$(FC) $(FLFLAGS) -o $# $^
# If something doesn't work right, have a 'make debug' to
# show what each variable contains.
debug:
#echo "SRCS = $(SRCS)"
#echo "OBJS = $(OBJS)"
#echo "MODS = $(MODS)"
#echo "MOD_OBJS = $(MOD_OBJS)"
#echo "PROGRAM = $(PROGRAM)"
#echo "PRG_OBJ = $(PRG_OBJ)"
clean:
rm -rf $(OBJS) $(PROGRAM) $(patsubst %.o,%.mod,$(MOD_OBJS))
.PHONY: debug default clean
# Dependencies
# Main program depends on all modules
$(PRG_OBJ) : $(MOD_OBJS)
# Blocks and allocations depends on shared
mod_blocks.o mod_allocations.o : mod_shared.o

Related

MakeFile: Link a library - mingw

I have a C program with a path like this :
pgrmusinglib.c
pgrmusinglib.h
main.c
libfolder
libmylibrary.dll
I am trying to compile it on windows using mingw64.
I built this Makefile
CC = gcc
CFLAGS = -O3
DEPS = pgrmusinglib.h
LDFLAGS = -L/$(LIB) -lmylibrary
LIB = libfolder
SRC=$(wildcard *.c)
OBJ = $(SRC:.c=.o)
all: pgrm
pgrm : $(OBJ)
$(CC) -o $^ $(LDFLAGS)
%.o: %.c $(DEPS)
$(CC) -c $^ $(CFLAGS)
The pgrm rule fails with error :
c:/programdata/chocolatey/lib/mingw/tools/install/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe:
cannot find -lmylibrary
I believe it is'nt working because of how you wrote the LDFLAGS, just a little typo I assume, you put a '/' in front of the directory name , so its looking for libfolder in your root directory. Try either removing the '/' or putting a period '.' In front of it

makefile with debug option

I am kinda rookie in makefile field but trying to write makefile that would go in two modes: normal mode make outputing executable file called say bingo depending on some files and a mode make debug outputing executable file called bingo.debug that shall be compiled with debug option. I'm trying to use target variable with the following result:
PROGRAM = bingo
SUFIX = .debug
CC = gcc
CFLAGS = -Wall -O2
DEBUG = -g -D DEBUG
all: $(PROGRAM)
debug: CFLAGS += $(DEBUG)
debug: PROGRAM += $(SUFIX)
debug: all
file1.o: file1.c file1.h
$(CC) -c $(CFLAGS) -o $# $<
file2.o: file2.c file2.h
$(CC) -c $(CFLAGS) -o $# $<
$(PROGRAM).o: $(PROGRAM).c
$(CC) -c $(CFLAGS) -o $# $<
$(PROGRAM): file1.o file2.o ($PROGRAM).o
$(CC) -o $# $^
.PHONY: all clean
clean:
rm -rf $(PROGRAM) *.o
It looks like make debug correctly compiles the file with debug flags but it does not change the file name (i.e. both modes outputs the same bingo file). Any help much appriciated!
You cannot use target-specific variables in targets. The documentation is very clear that they are available only in recipes.
In general it's problematic to do things this way, because make has no idea which objects were built with debug and which weren't. If you forget to do a complete clean and/or run make the wrong way then you'll get a mix of different object files: some compiled with debug and some not.
Instead, you should put your debug object files in a different directory from your non-debug object files so you don't have to worry about that.

Error in including homemade Fortran modules and libraries in Makefile

I am trying to build a very simple Makefile, that intends to use a homemade library (libf904QC.a) made of Fortran modules. The library is in /usr/local/lib64 whereas the corresponding .mod files are in /usr/local/include/f904QC
Here is the Makefile
# Makefile
NAME=NPManip
FFLAGS= -ffpe-trap=overflow -c -O3
LFLAGS=
PATH2LIB=/usr/local/lib64/
INCLUDEDIR=/usr/local/include/f904QC/
#
LIB=-L$(PATH2LIB) -I$(INCLUDEDIR) -lf904QC.a
OBJS = \
tools_NPManip.o\
NPManip.o
%.o: %.f90
gfortran $(LIB) $(FFLAGS) $*.f90
NPM: $(OBJS)
gfortran $(LFLAGS) $(OBJS) $(LIB) -o $(NAME)
clean:
#if test -e $$HOME/bin/$(NAME); then \
rm $$HOME/bin/$(NAME); \
fi
rm *.o *.mod
mrproper: clean
rm $(NAME)
install:
ln -s $(shell pwd)/$(NAME) $$HOME/bin/.
I get the following error message :
gfortran tools_NPManip.o NPManip.o -L/usr/local/lib64/ -I/usr/local/include/f904QC/ -lf904QC.a -o NPManip
/usr/lib64/gcc/x86_64-suse-linux/4.7/../../../../x86_64-suse-linux/bin/ld: cannot find -lf904QC.a
collect2: error: ld returned 1 exit status
make: * [NPM] Erreur 1
Where is the mistake? It is not obvious to me since libf904QC.o is actually located in /usr/local/lib64, which is defined by the -L option.
Thnak you for your help
You should specify either the full path to the library /usr/local/lib64/libf904QC.a or alternatively -L/usr/local/lib64 -lf90QC, without the .a in that case. From man ld:
-l namespec
--library=namespec
Add the archive or object file specified by namespec to the list of files to link. This option may be used any number of
times. If namespec is of the form :filename, ld will search the library path for a file called filename, otherwise it
will search the library path for a file called libnamespec.a.
-L searchdir
--library-path=searchdir
Add path searchdir to the list of paths that ld will search for archive libraries and ld control scripts. You may use
this option any number of times. The directories are searched in the order in which they are specified on the command
line. Directories specified on the command line are searched before the default directories. All -L options apply to
all -l options, regardless of the order in which the options appear. -L options do not affect how ld searches for a
linker script unless -T option is specified.

how to compile multi-folder Fortran Project having interfaces, modules and subroutines

I am new to Fortran. I am working on a research project where I am using an open source project that has several files distributed in multiple folders. i found the dependency of each programs but could not figure out how to compile them.
I have source code distributed in three folders.
a)modules
b)interfaces
c)subroutines
I would like to run a program named as 'Main.f90' in subroutines folder, this program has dependency of source codes from modules and interfaces folders.
I am using eclipse for folder structure and makefile to compile.
Any help with this is appreciated.
UPDATE:
I followed the answer posted by #MBR and #Stefan, for some reason VPATH did not able to find programs in source code so I explicitly gave path to those source folder in my Makefile. below is my make file script.
.PHONY: Mopac_exe clean
# Change this line if you are using a different Fortran compiler
FORTRAN_COMPILER = gfortran
SRC = src
#make main program
Mopac_exe: subroutines mopac.o
$(FORTRAN_COMPILER) mopac.o *.o -O2 -g -o bin/Mopac_exe -I Modules/
#compile all the subroutines
subroutines: interfaces
$(FORTRAN_COMPILER) -c $(SRC)/subroutines/*.F90 -J Modules/Subroutines/ -I Modules/
#compiles all the interfaces
interfaces: modules
$(FORTRAN_COMPILER) -c $(SRC)/interfaces/*.f90 -J Modules/
# build all the modules and generate .mod file in Modules directory
modules: build_vast_kind
$(FORTRAN_COMPILER) -c $(SRC)/modules/*.f90 -J Modules/
$(FORTRAN_COMPILER) -c $(SRC)/modules/*.F90 -J Modules/
# compile vastkind.f90 files and generates the .mod file in Modules directory.Every other Modules and interfaces are dependent on this.
build_vast_kind:clean
$(FORTRAN_COMPILER) -c $(SRC)/modules/vastkind.f90 -J Modules/
clean:
rm -f bin/Mopac_exe *.mod
rm -f Modules/*.mod
rm -f *.o
I compiled all the modules and placed in Modules directory of root Folder.
All compilation goes well. I get error when I build the executable. I get following error.
gfortran mopac.o *.o -O2 -g -o bin/Mopac_exe -I Modules/
mopac.o: In function `main':
mopac.F90:(.text+0x27c1): multiple definition of `main'
mopac.o:mopac.F90:(.text+0x27c1): first defined here
getdat.o: In function `getdat_':
getdat.F90:(.text+0x22): undefined reference to `iargc_'
getdat.F90:(.text+0xf2): undefined reference to `getarg_'
symr.o: In function `symr_':
symr.F90:(.text+0xd3f): undefined reference to `symp_'
writmo.o: In function `writmo_':
writmo.F90:(.text+0x20c2): undefined reference to `volume_'
collect2: error: ld returned 1 exit status
make: *** [Mopac_exe] Error 1
`iargc_' is being used in 'getdat file and iargc is already compiled. why there is error while making the executable saying undefined reference? what am I missing?
You can do a Makefile which looks like that
F90=gfortran
FFLAGS = -O0
VPATH = modules:interfaces:subroutines:
MODOBJ = module1.o module2.o ...
your_executable: $(MODOBJ) main.o
$(F90) main.o -o your_executable
%.o:%.f90
$(F90) $(FFLAGS) -c $^ -o $#
VPATH is the paths of the directories where your Makefile will look for source files, so if you compile your source in the root directory of modules/, interfaces/ and subroutines/, you just have to set up VPATH like that.
If you have many objects and you don't want to write everything by hand, you can retrieve them using the following trick
F90 = gfortran
FFLAGS = -O0
VPATH = modules:interfaces:subroutines
SRCOBJ = $(wildcard modules/*f90)
MODOBJ = $(SRCOBJ:.f90=.o)
your_executable: $(MODOBJ) main.o
$(F90) main.o -o your_executable
%.o:%.f90
$(F90) $(FFLAGS) -c $^ -o $#
The wildcard command in a Makefile allows you to use a joker *; then you just have to say that in the strings you will retrieve in $(SRCOBJ), you want to substitute .f90 by .o to get the filenames of your modules.
You can create your Makefiles as usual. The biggest problem should be the .mod files. The easiest solution to this problem is to create a separate folder, where these files are stored and searched for.
This can be achieved with the -J and the -module flags for gfortran and ifort, respectively.

Makefile rule using the automatic variable $^ without dependencies

I learnt from the GNU Make manual that the sign $^ is an automatic variable which represents the names of all the prerequisites. However I fell upon a makefile like this one:
SVR_OBJECT_FILES = server.o\
server_func.o
CLT_OBJECT_FILES = client.o
CFLAGS = -Wall -Werror -W
CC = gcc
all: client/client server/serveur
client/client: $(CLT_OBJECT_FILES)
server/serveur: $(SVR_OBJECT_FILES)
client/client server/serveur:
#mkdir -p $(dir $#)
$(CC) $(CFLAGS) $^ -o $#
%.o: %.c
$(CC) -c $<
clean:
rm -f client/client server/serveur *.o
Which works fine so my question is :
How can the command below can link the right object files while the $^ variable is refering no preprerequisites at all. (the rule has no prerequisites)
$(CC) $(CFLAGS) $^ -o $#
$^ contains all the prerequisites of the target, not just the ones that are mentioned with the rule itself. The same file can appear as a target several times in rules with no commands:
sometarget: dependency1
…
sometarget: dependency2
assemble -o $# $^
…
sometarget: dependency3
The dependencies of sometarget are dependency1, dependency2 and dependency3, and when the assemble command is invoked by make sometarget, it will receive all three as arguments.
Here, $^ will contain all $(CLT_OBJECT_FILES) or $(SRV_OBJECT_FILES) depending on which target the command is executed for.