Multiple Level of Dependencies in a Makefile - makefile

I am very new to makefiles. I have been able to write the script shown below by copying different examples found online. If I am doing something wrong, or not conventional, please point it out.
This is my (working) Makefile for a fortran code I have. The main program stored in main.f08 calls a module stored in file1.f08:
FC = gfortran
SRCS: main.f08
OBJS: $(SRCS:.f08=.o)
EXEC: $(SRCS:.f08=)
all: $(EXEC)
file1.o file1.mod: file1.f08
$(FC) -c $<
touch $*.o $*.mod
main.o: file1.mod
%.o: %.f08
$(FC) $(FFLAGS) -c $<
main: file1.o
%: %.o
$(FC) -o MainExe $^
clean:
rm -f MainExe *.o *.mod
I have tried to extrapolate that technique to write a makefile which has a ladder of dependencies. For example, main.f08 would be calling the module file1.f08, which in turn would be calling the module file2.f08. Here is what I have so far:
FC = gfortran
SRCS: main.f08
OBJS: $(SRCS:.f08=.o)
EXEC: $(SRCS:.f08=)
all: $(EXEC)
file2.o file2.mod: file2.f08
$(FC) -c $<
touch $*.o $*.mod
file1.o: file2.mod
file1.o file1.mod: file1.f08
$(FC) -c $<
touch $*.o $*.mod
main.o: file2.mod file1.mod
%.o: %.f08
$(FC) $(FFLAGS) -c $<
main: file1.o
%: %.o
$(FC) -o MainExe $^
clean:
rm -f MainExe *.o *.mod
The command line output consist of a few line showing that the code starts compiling the two modules and the main program and then several lines of errors that look like this:
Undefined symbols for architecture x86_64:
"___brownian_MOD_calcb", referenced from:
___integral_MOD_calcint in Integral.o

I've been working on this and I actually have figured it out.
The main executable should be linked to the module's object files in the correct order (an object file should not precede its dependency) followed by its object file, main.o. The module's object file should be linked to their dependency (if any) and their .f08 file. Finally, the touch command makes sure that the .mod files are up to dates with the .o files. Here is the corrected code showed in its simplest version:
FC = gfortran
all: main
main : file2.o file1.o main.o
$(FC) -o executable file2.o file1.o main.o
main.o: main.f08
$(FC) -c main.f08
file2.o : file2.f08
$(FC) -c file2.f08
touch file2.o file2.mod
file1.o : file2.o file1.f08
$(FC) -c file1.f08
touch file1.o file1.mod
A more advanced version of the makefile is shown below:
FC = gfortran
SRCS = main.f08
SOBJ = $(SRCS:.f08=.o)
EXEC = #(SRCS:.f08=)
FILE = file2.f08 file1.f08
FOBJ = $(SRCS:.f08=.o)
all: $(EXEC)
$(EXEC): $(FOBJ) $(SOBJ)
$(FC) -o executable $^
%.o: %.f08
$(FC) -c $<
touch $*.o $*.mod

Related

Explaining syntax of makefile

can anyone help me in interpreting the following makefile:
# compiler
FC = gfortran
# compile flags
FCFLAGS = -c -ffixed-line-length-72 -std=gnu -Wline-truncation -Wunused-variable
# link flags
FLFLAGS =
# module files
MODULES = Calculator.f
# object files
OBJS = Calculator.o
OBJS += Main.o Common.o Io.o
# program name
PROGRAM = calFap
all: $(PROGRAM)
$(PROGRAM): $(OBJS)
$(FC) $(FLFLAGS) -o $# $^
%.o: %.f
$(FC) $(FCFLAGS) -o $# $^
mod: $(MODULES)
$(FC) $(FCFLAGS) $# $^
clean:
rm -f *.o *.mod
What does this mean:
# module files
MODULES = Calculator.f
Is this just a kind of placeholder? So MODULES is "linked" to Calculator.f ? The file Calculator.f already exists.
# object files
OBJS = Calculator.o
OBJS += Main.o Common.o Io.o
So here I create a variable and I put in Calculator.o Main.o Common.o Io.o . But in my folder they do not exist up to now?
all: $(PROGRAM)
So the internet tells me, that "all" as a target is used in order to compile the whole program? But as far as I understand, makefiles are there for only compiling those parts of a programm which have changed?
$(PROGRAM): $(OBJS)
$(FC) $(FLFLAGS) -o $# $^
If there is a change in one of the OBJS files then something should be compiled. But I do not get the part with "-o $# $^" . Maybe all objects which have changed?
%.o: %.f
$(FC) $(FCFLAGS) -o $# $^
If there is a change in one of the .f files ...? I don't get this line.
For your help I would be really happy.
Thanks Helmut

How to use a makefile with gprof to recompile dependencies?

I have a makefile which compiles and links together objects to create an executable. In order to profile, I need to use an additional flag -pg before compiling. Here is my current makefile:
# objects required
OBJS = obj1.o obj2.o
# flags
FC = gfortran
FLAGS = -O3
PROFILEFLAG = -pg
# executable
EXE = program.exe
PROFEXE = program_prof.exe
# suffixes
.SUFFIXES: .o .f90
# rules
%.o: %.f90
$(FC) $(FLAGS) -c $<
default: $(OBJS)
$(FC) $(FLAGS) $(OBJS) -o $(EXE)
profile: $(OBJS)
$(FC) $(FLAGS) $(OBJS) -o $(PROFEXE) $(PROFILEFLAG)
clean:
rm *.o *.mod
Running make profile runs the rule associated with profile, which creates the executable program_prof.exe which can be profiled. However, since the individual dependencies obj1 and obj2 are not compiled with the -pg flag, I cannot profile the code running in those files.
Is there a way I can add a rule such that the individual objects are also recompiled with the -pg flag when I need to profile?
Currently I am editing the individual object dependencies manually to:
%.o: %.f90
$(FC) $(FLAGS) -c $< -pg
which works as expected, but is time consuming (my actual makefile has multiple dependencies in subfolders, all of which need to be edited). Ideally, I am looking for a rule which should recompile individual objects with the `-pg' flag.
You can do exactly what you want, with target-specific variables:
PROFILE :=
%.o : %.f90
$(FC) $(FLAGS) $(PROFILE) -c -o $# $<
default: $(OBJS)
....
profile: PROFILE := -pg
profile: $(OBJS)
....
However, this is not usually the preferred way. Unless you're really diligent about always doing a full clean when switching back and forth between profile and non-profile builds it's very easy to get confused and have some objects compiled with profiling and others compiled without.
As mentioned in the comments, it's better to build them into separate directories:
$(PDIR)/%.o : %.f90
#mkdir -p $(#D)
$(FC) $(FLAGS) -pg -c -o $# $<
$(ODIR)/%.o : %.f90
#mkdir -p $(#D)
$(FC) $(FLAGS) -c -o $# $<
default: $(addprefix $(ODIR)/,$(OBJS))
$(FC) $(FLAGS) $^ -o $#
profile: $(addprefix $(PDIR)/,$(OBJS))
$(FC) $(FLAGS) -pg $^ -o $#

Makefile for Fortran gives this error: make: don't know how to make datastructures.o

I am trying to prepare my first makefile for Fortran:
My code is so far separated in three object modules.
This is my makefile:
# Variables
OBJS=datastructures.o global.o main.o
FC=/usr/local/bin/gfortran8
FFLAGS=-Wl,-rpath=/usr/local/lib/gcc8
# Makefile
test1: $(OBJS)
$(FC) -o mktpro_a $(FFLAGS) $(OBJS)
%.o: %.f90
$(FC) -c $(FFLAGS) $<
clean:
rm $(OBJS)
rm test1
But I get the following error:
$ make test1
make: don't know how to make datastructures.o. Stop
make: stopped in /usr/home/user/marketprofile
I am using FreeBSD12 and gcc8 (gfortran8)
Instead of
%.o: %.f90
$(FC) -c $(FFLAGS) $<
change it to
.f90.o:
$(FC) -c $(FFLAGS) $<
You might need an explicit output too (I am not familiar with this compiler):
.f90.o:
$(FC) -c $(FFLAGS) -o $# $<
In case it helps other people, this seems the way to implement this in FreeBSD 12 make (which seems to be PMake).
.SUFFIXES : .o .f90
.f90.o :
$(FC) $(FFLAGS) -c $(.IMPSRC)
More info here: ftp.netbsd.org/pub/NetBSD/misc/lite2-docs/psd/12.make.ps.gz

How to move .o on project folder?

I wrote this Makefile to move all .o of the project inside a directory 'obj' in the main folder.
Directories
.:
actor/ lib/ Controller.cpp Controller.h Controller.o doc.txt main.cpp main.o Makefile uno VRP*
./actor:
Customer.cpp Customer.h Customer.o Depot.cpp Depot.h Depot.o Route.cpp Route.h Route.o Vehicle.cpp Vehicle.h Vehicle.o
./lib:
Search.cpp Search.h Search.o Utils.cpp Utils.h Utils.o VRP.cpp VRP.h VRP.o
Makefile
CXX=g++
RM=rm -rf
BIN_NAME=VRP
CPPFLAGS=-s -O2 -std=gnu++11 -Wall
SRCS=$(wildcard *.cpp actor/*.cpp lib/*.cpp)
OBJS=$(subst .cpp,.o,$(SRCS))
all: $(OBJS_DIR) $(BIN_NAME)
$(OBJS_DIR):
mkdir $(OBJS_DIR)
$OBJS_DIR)/%.o : $(SRCS)
$(CXX) $(CPPFLAGS) -c $< -o $#
$(BIN_NAME) : $(OBJS)
$(CXX) -o $# $^
debug:
$(CXX) -g $(CPPFLAGS) -o $(BIN_NAME) $(OBJS)
.PHONY : all clean
clean:
$(RM) $(OBJS) $(OBJS_DIR)
dist-clean: clean
$(RM) $(BIN_NAME)
How can I make it works?
This line $OBJS_DIR)/%.o : $(SRCS) sets the prerequisites of every file that matches $OBJS_DIR)/%.o to all the files in $(SRCS) that's not even close to what you want. (It is also a typo. You are missing the opening ().
You can't write a single rule for what you are trying to do here you need three pattern rules (or one with a vpath/VPATH setup).
$(OBJS_DIR)/%.o: %.cpp
$(CXX) $(CPPFLAGS) -c $< -o $#
$(OBJS_DIR)/%.o: actor/%.cpp
$(CXX) $(CPPFLAGS) -c $< -o $#
$(OBJS_DIR)/%.o: lib/%.cpp
$(CXX) $(CPPFLAGS) -c $< -o $#
That being said you don't actually have any targets that match $(OBJS_DIR)/%.o since the value of $(OBJS) is Controller.o ... actor/Customer.o ... lib/Search.o. To fix that you also need:
OBJS=$(addprefix $(OBJS_DIR)/,$(patsubst %.cpp,%.o,$(notdir $(SRCS))))
$(notdir) to get just the filename from the source files.
$(patsubst) instead of $(subst) just for correctness (subst would have modified a Bar.cpp.cpp file to Bar.o.o).
$(addprefix) to add the $(OBJS_DIR) prefix to the bare object file names.

Creating a FORTRAN makefile

I have a FORTRAN source code consisting of many different .F and .h files. I need to build an executable from it, but I'm having some problems. The makefile that I produced so far (which may have errors as I'm new to this) is:
# compiler
FC = /usr/bin/gfortran-4.5
# compile flags
FCFLAGS = -g -c -fdefault-real-8 -fbacktrace -fno-align-commons
# link flags
FLFLAGS = -g -fbacktrace
# source files and objects
SRCS = $(patsubst %.F, %.o, $(wildcard *.F)) \
$(patsubst %.h, %.mod, $(wildcard *.h))
# program name
PROGRAM = blah
all: $(PROGRAM)
$(PROGRAM): $(SRCS)
$(FC) $(FCFLAGS) $# $<
%.o: %.F
$(FC) $(FLFLAGS) -o $# $<
%.mod: %.h
$(FC) $(FLFLAGS) -o $# $<
clean:
rm -f *.o *.mod
When I try to make the program, however, I'm getting a slew of undefined reference errors. I mean, every function and subroutine call in the very first compiled .F file gives back an undefined reference error. I thought this was because gfortran was trying to link the files instead of just compiling them and then linking at the end, but I thought the '-c' option was supposed to prevent that.
UPDATE:
As commenters have pointed out, I mixed up the compile and link flags. Furthermore, you shouldn't compile *.h files. Here is the latest, corrected makefile:
# compiler
FC = /usr/bin/gfortran-4.4
# compile flags
FCFLAGS = -g -c -fdefault-real-8 -fbacktrace -fno-align-commons -fbounds-check -std=legacy
# link flags
FLFLAGS =
# source files and objects
SRCS = $(patsubst %.F, %.o, $(wildcard *.F))
# program name
PROGRAM = blah
all: $(PROGRAM)
$(PROGRAM): $(SRCS)
$(FC) $(FLFLAGS) -o $# $<
%.o: %.F
$(FC) $(FCFLAGS) -o $# $<
clean:
rm -f *.o *.mod
Now when I run make, it will compile each *.F file in the code, but it fails at the linking stage. I get a bunch of undefined reference errors in the very first *.F file. The compiler seems to be going over each *.F file individually in the linking stage, which I'm not sure is correct. Then I get an error:
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/libgfortranbegin.a(fmain.o): In function `main':
(.text+0x26): undefined reference to `MAIN__'
collect2: ld returned 1 exit status
However, if I type the command:
gfortran -o blah *.o
The executable will be built, so it seems like I did something wrong in the makefile for the linking stage.
UPDATE: 5/9/2011
Sverre pointed out the final problem with my makefile. In my first target that builds the program, I use the shortcut command for only the first dependency ($<), but I need to include all dependencies (i.e. all *.o files) using the ($^) shortcut. The final, working makefile is as follows:
# compiler
FC := /usr/bin/gfortran-4.5
# compile flags
FCFLAGS = -g -c -fdefault-real-8 -fbacktrace -fno-align-commons -fbounds-check
# link flags
FLFLAGS =
# source files and objects
SRCS = $(patsubst %.F, %.o, $(wildcard *.F))
# $(patsubst %.h, %.mod, $(wildcard *.h))
# program name
PROGRAM = vipre
all: $(PROGRAM)
$(PROGRAM): $(SRCS)
$(FC) $(FLFLAGS) -o $# $^
%.o: %.F
$(FC) $(FCFLAGS) -o $# $<
# %.mod: %.h
# $(FC) $(FCFLAGS) -o $# $<
clean:
rm -f *.o *.mod
Are you using GNU make? If so,
$(FC) $(FLFLAGS) -o $# $<
may be the culprit. $< is the name of the first prerequisite, but you want all the *.o files. Try using $^ instead.

Resources