Reputation: 987
I'm running a makefile using mingw on windows. I've seen a lot of SO links about this topic, but they all seem to be for C or c++. I'm not sure if the same rules apply, and since I'm using windows, syntax seems to be a bit different too. Here are some of the other references:
How to place object files in separate subdirectory (most promising, I think)
Using a make file to compile files in separate directories
Flat object file directory structure output with GNU Make
What I currently have is (verbatim)
VPATH =\
user \
static \
computations \
solvers\\steadyState \
solvers\\transient \
solvers\\transient\\momentum \
solvers\\transient\\induction
FC = gfortran
TOP_DIR = .
MOD_DIR = $(TOP_DIR)\\mod
OBJ_DIR = $(TOP_DIR)\\obj
FCFLAGS = -g
FCFLAGS += -J$(MOD_DIR) -fopenmp -fimplicit-none -Wuninitialized
TARGET = parametricStudy
SRCS_F =\
user\\constants.f90 \
static\\myExceptions.f90 \
static\\myDebug.f90 \
static\\scalarField.f90 \
static\\vectorField.f90 \
static\\myIO.f90 \
user\\simParams.f90 \
static\\solverSettings.f90 \
static\\myTime.f90 \
computations\\myError.f90 \
static\\coordinates.f90 \
user\\griddata.f90 \
static\\myAllocate.f90 \
static\\BCs.f90 \
user\\rundata.f90 \
computations\\myDel.f90 \
computations\\vectorOps.f90 \
static\\myExport.f90 \
computations\\applyBCs.f90 \
solvers\\steadyState\\mySOR.f90 \
solvers\\steadyState\\myPoisson.f90 \
solvers\\transient\\induction\\initializeBBCs.f90 \
solvers\\transient\\induction\\initializeBfield.f90 \
solvers\\transient\\induction\\initializeSigmaMu.f90 \
solvers\\transient\\momentum\\initializeUBCs.f90 \
solvers\\transient\\momentum\\initializeUfield.f90 \
solvers\\transient\\inductionSolver.f90 \
solvers\\transient\\momentumSolver.f90 \
solvers\\transient\\MHDSolver.f90 \
user\\MOONS.f90 \
parametricStudy.f90
OBJS_F = $(patsubst %.f90,$(OBJ_DIR)\\%.o,$(notdir $(SRCS_F)))
all: $(TARGET)
$(TARGET): $(OBJS_F)
$(FC) -o $@ $(FCFLAGS) $(OBJS_F)
$(OBJ_DIR)\\%.o: %.f90
$(FC) $(FCFLAGS) -c -o $@ $<
clean:
del $(OBJ_DIR)\\*.o $(MOD_DIR)\\*.mod parametricStudy.exe
list:; @echo " "
@echo " "
@echo "Source files:"
@echo $(SRCS_F)
@echo " "
@echo "Object files:"
@echo $(OBJS_F)
@echo " "
@echo "Compiler : $(FC)"
@echo "Include directory : $(INC_DIR)"
@echo "Root directory : $(ROOT_DIR)"
@echo "Bin directory : $(BIN_DIR)"
@echo "Modules directory : $(MOD_DIR)"
@echo "Modules directory : $(MOD_DIR)"
@echo "Object directory : $(OBJ_DIR)"
@echo " "
Using this, I can execute the following (again, verbatim)
C:\Users\Charlie\Desktop\development\FORTRAN_LIB>gmake
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\const
ants.o user/constants.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\myExc
eptions.o static/myExceptions.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\myDeb
ug.o static/myDebug.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\scala
rField.o static/scalarField.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\vecto
rField.o static/vectorField.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\myIO.
o static/myIO.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\simPa
rams.o user/simParams.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\solve
rSettings.o static/solverSettings.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\myTim
e.o static/myTime.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\myErr
or.o computations/myError.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\coord
inates.o static/coordinates.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\gridd
ata.o user/griddata.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\myAll
ocate.o static/myAllocate.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\BCs.o
static/BCs.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\runda
ta.o user/rundata.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\myDel
.o computations/myDel.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\vecto
rOps.o computations/vectorOps.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\myExp
ort.o static/myExport.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\apply
BCs.o computations/applyBCs.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\mySOR
.o solvers\\steadyState/mySOR.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\myPoi
sson.o solvers\\steadyState/myPoisson.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\initi
alizeBBCs.o solvers\\transient\\induction/initializeBBCs.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\initi
alizeBfield.o solvers\\transient\\induction/initializeBfield.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\initi
alizeSigmaMu.o solvers\\transient\\induction/initializeSigmaMu.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\initi
alizeUBCs.o solvers\\transient\\momentum/initializeUBCs.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\initi
alizeUfield.o solvers\\transient\\momentum/initializeUfield.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\induc
tionSolver.o solvers\\transient\\induction/inductionSolver.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\momen
tumSolver.o solvers\\transient\\momentum/momentumSolver.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\MHDSo
lver.o solvers\\transient/MHDSolver.f90
gfortran -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized -c -o .\\obj\MOONS
.o user/MOONS.f90
gmake: *** No rule to make target `.\\obj\parametricStudy.o', needed by `paramet
ricStudy'. Stop.
C:\Users\Charlie\Desktop\development\FORTRAN_LIB>gfortran -g -J.\\mod -fopenmp -
c -o .\\obj\parametricStudy.o parametricStudy.f90
C:\Users\Charlie\Desktop\development\FORTRAN_LIB>gmake
gfortran -o parametricStudy -g -J.\\mod -fopenmp -fimplicit-none -Wuninitialized
.\\obj\constants.o .\\obj\myExceptions.o .\\obj\myDebug.o .\\obj\scalarField.o
.\\obj\vectorField.o .\\obj\myIO.o .\\obj\simParams.o .\\obj\solverSettings.o .\
\obj\myTime.o .\\obj\myError.o .\\obj\coordinates.o .\\obj\griddata.o .\\obj\myA
llocate.o .\\obj\BCs.o .\\obj\rundata.o .\\obj\myDel.o .\\obj\vectorOps.o .\\obj
\myExport.o .\\obj\applyBCs.o .\\obj\mySOR.o .\\obj\myPoisson.o .\\obj\initializ
eBBCs.o .\\obj\initializeBfield.o .\\obj\initializeSigmaMu.o .\\obj\initializeUB
Cs.o .\\obj\initializeUfield.o .\\obj\inductionSolver.o .\\obj\momentumSolver.o
.\\obj\MHDSolver.o .\\obj\MOONS.o .\\obj\parametricStudy.o
Note that after I receive the error, I can explicitly compile the parametricStudy.f90 after the error with:
gfortran -g -J.\\mod -fopenmp -c -o .\\obj\parametricStudy.o parametricStudy.f90
and then type
gmake
Again, which results in no errors. I'm very puzzled.
Here is a screenshot of my directory:
Maybe it has something to do with TARGET? It seems like the path of the last file is somehow wrong. Any help is greatly appreciated!
Upvotes: 2
Views: 2284
Reputation: 61397
I think the following style of makefile solves the problems. I tested it with a specimen C
project, not fortran, but that is immaterial to the make
problem and solution.
# VPATH: Tell `make` to look for in `user` for prerequisites it can't find here
VPATH = user
# If e.g. you also want `make` to look for for prerequisites in `../include`, then:
# VPATH = user:../include
FC = gfortran
TOP_DIR = .
MOD_DIR = $(TOP_DIR)\\mod
OBJ_DIR = $(TOP_DIR)\\obj
FCFLAGS = -g
FCFLAGS += -J$(MOD_DIR) -fopenmp -fimplicit-none -Wuninitialized
TARGET = parametricStudy
SRCS_F =\
user\\constants.f90 \
...
parametricStudy.f90
OBJS_T1 = $(patsubst %.f90,%.o,$(SRCS_F))
OBJS_T2 = $(notdir $(OBJS_T1))
# The object files are all to be obj\<name>.o
OBJS_F = $(patsubst %.o,$(OBJ_DIR)\\%.o,$(OBJS_T2))
all: $(TARGET)
$(TARGET): $(OBJS_F)
$(FC) -o $@ $(FCFLAGS) $(OBJS_F)
# How to make an obj\*.o from the matching *.f90. `make` considers the VPATH
$(OBJ_DIR)\\%.o: %.f90
$(FC) $(FCFLAGS) -c -o $@ $<
clean:
del $(OBJ_DIR)\\*.o $(MOD_DIR)\\*.mod parametricStudy.exe
Using a relative path TOP_DIR = .
rather than an absolute ROOT_DIR
is good advice already offered
by @Wintermute.
To enable the required pattern rule:
$(OBJ_DIR)\\%.o: %.f90
to kick in, you must make it appear to make
that any prerequisite *.f90
is right here, as per the pattern,
not in some other directory like, e.g. user\constants.f90
That is what the VPATH
achieves.
Continued for later developments
Not yet having seen a listing of the directory where the makefile resides I can only venture a hypothesis, but the hypothesis suggested by what I do see is:
The directory does not actually contain a file called parametricStudy.f90
,
but a file called parametricStudy.F90
, and if it is renamed to parametricStudy.f90
,
then the makefile will find and compile it.
Is that right?
How this explains the facts: The pattern rule:
$(OBJ_DIR)\\%.o: %.f90
is failing to match any parametricStudy.f90
, so there is no such file. You say however that:
gfortran -g -J.\\mod -fopenmp -c -o .\\obj\parametricStudy.o parametricStudy.f90
successfully compiles.
You are building on Windows, so the toolchain subscribes to Windows' file-handling protocols.
Filenames are case-insentive: parametricStudy.f90
will identify parametricStudy.F90
, if it exists,
and .F90
will be interpreted by gfortran
(on Windows or anywhere else) as denoting a
Fortran 90 source file. Thus the successful commandline compile.
But the pattern rule is indifferent to file-handling protocols. It is just a pattern
matching rule, and the invariant .f90
is not matched by .F90
.
Upvotes: 3
Reputation: 44043
The problem you're facing is that with
ROOT_DIR = "C:\Users\Charlie\"
OBJ_DIR = $(ROOT_DIR)\obj
the rule
$(OBJ_DIR)/%.o: %.f90
expands to
"C:\Users\Charlie\"obj/%.o: %.f90
which is parsed as the static pattern rule
"C: \Users\Charlie\"obj/%.o: %.f90
That is to say, with target "C
, target pattern \Users\Charlie\"obj/%.o
and prerequisite pattern %.f90
. make complains that "C
does not match the pattern \Users\Charlie\"obj/%.o
.
There is some hacky code in GNU make (at least in MinGW; I think Cygwin behaves differently because it expects you to work with its unix-ish directory structure) to recognize absolute Windows paths, but it does not handle quoting. As long as your OBJ_DIR
does not contain spaces, using
ROOT_DIR = C:\Users\Charlie\
should make the Windows path recognition kick in.
However...it is rather unusual to see absolute paths in handcrafted Makefiles. Are you sure you want to do it this way? A more common approach would be to work with relative paths so that the Makefile does not have to be changed if the source code is copied to a different directory. Assuming the Makefile is in the root directory, that would be
ROOT_DIR = .
or just nixing the ROOT_DIR
variable altogether and saying
MOD_DIR = mod
OBJ_DIR = obj
Oh, and to answer the next question that's going to crop up: In order to make make
use the
$(OBJ_DIR)/%.o: %.f90
rule, you'll need to make $(TARGET)
have prerequisites that match the $(OBJ_DIR)/%.o
pattern. That could be
OBJS_F = $(patsubst %.f90,$(OBJ_DIR)/%.o,$(notdir $(SRCS_F)))
Upvotes: 3