gmake compile and link source files in different directories - makefile

I'm trying to compile and link several files in different folders using gfortran, and GNU Make 3.81 on a windows machine. I learned how to use wildcards from this reference:
gmake compile all files in a directory
And I want to do something similar to this reference:
Makefiles with source files in different directories
But the difference is that I want to build only one executable in my root directory from the source files in several other directories. I tried reading the make manual:
http://www.gnu.org/software/make/manual/make.html
But it seems primarily directed towards c/c++ programming and non-windows syntax.
My current makefile looks like this:
FC = gfortran
MOD_DIR = "bin"
FCFLAGS = -O0 -Og -Wall -pedantic -fbacktrace -fcheck=all
FCFLAGS += -J$(MOD_DIR) -fopenmp -fimplicit-none -Wuninitialized
TARGET = test
SRCS_C = $(wildcard *.f90) $(TARGET).f90
OBJS_C = $(patsubst %.f90,%.o,$(SRCS_C))
all: $(TARGET)
$(TARGET): $(OBJS_C)
$(FC) -o $# $(FCFLAGS) $(OBJS_C)
$(OBJS_C): $(SRCS_C)
$(FC) $(FCFLAGS) -c $(SRCS_C)
clean:
del *.o $(MOD_DIR)\*.mod
Which works fine when all of my source files are in the root directory. And so I thought this would work:
FC = gfortran
MOD_DIR = "bin"
FCFLAGS = -O0 -Og -Wall -pedantic -fbacktrace -fcheck=all
# FCFLAGS += -J$(MOD_DIR) -I$(INCLUDE_DIR) -fopenmp -fimplicit-none -Wuninitialized
FCFLAGS += -J$(MOD_DIR) -fopenmp -fimplicit-none -Wuninitialized
TARGET = test
SRCS_C =\
"solvers/"$(wildcard *.f90) \
"user/"$(wildcard *.f90) \
$(wildcard *.f90) $(TARGET).f90
OBJS_C = $(patsubst %.f90,%.o,$(SRCS_C))
all: $(TARGET)
$(TARGET): $(OBJS_C)
$(FC) -o $# $(FCFLAGS) $(OBJS_C)
$(OBJS_C): $(SRCS_C)
$(FC) $(FCFLAGS) -c $(SRCS_C)
clean:
del *.o $(MOD_DIR)\*.mod
Where I don't mind just entering the names of the folders where a list of source files can be taken from. I've also tried using -I$(INCLUDE_DIR), but this didn't work either. The error from what I have above is:
gmake: *** No rule to make target `"user/"gridFun.f90', needed by `"user/"gridFu
n.o'. Stop.
Any help is greatly appreciated!

To accomplish what you want with SRCS_C, consider using:
SRCS_C =\
$(wildcard solvers/*.f90) \
$(wildcard user/*.f90) \
$(wildcard *.f90) $(TARGET).f90
Also note that (TARGET).f90 will also be matched by $(wildcard *.f90), in your cases causing test.f90 to be included twice in SRCS_C. You can safely omit $(TARGET).f90 in this example.

Related

Simplifying a makefile

I have written a scary-looking Makefile by copy/pasting suggestions from Stack Overflow. However, I have read that it might not be necessary to provide explicit compiler invocations so many times (for example, the -O3 flag is everywhere). How can I simplify this Makefile?
CFLAGS = -Weverything -Wno-padded -Wno-unused-parameter -Wno-unused-variable -Wno-sign-conversion
all: fianchetto.o util.o ttable.o movegen.o
clang -O3 $(CFLAGS) -D NDEBUG $^ -o fianchetto
debugf: fianchetto.o ttable.o movegen.o
clang -O3 $(CFLAGS) -g3 $^ -o fianchetto
clean:
rm *.o && rm *.gch & rm fianchetto && rm -rf fianchetto.dSYM
%.o: %.c
clang -O3 -c $(CFLAGS) $< -o $#
fianchetto.o: fianchetto.c
ttable.o: ttable.h ttable.c
movegen.o: movegen.h movegen.c
util.o: util.h util.c
I am mystified by a lot of the syntax, and would appreciate links or explanations of why simplifications work!
CFLAGS and defines (which should be in CPPFLAGS anyway) are useless when linking
You're reinventing make's built-in rules, make will automatically link a target if one of its dependencies is "target.o" (in this case fianchetto: fianchetto.o). Make also knows how to compile C source files (as long as the source and object path match), so your pattern rule is superfluous too.
The object prerequisites aren't necessary as both clang and GCC can generate dependencies for you with the -M set of flags.
Compiling release and debug builds in the same dir makes for a more simple makefile, although you will need to remember to clean the object files when switching.
By default make assigns cc to CC, and cc should be a link to your system's default compiler, so you might not even need the first line below
CC := clang
CPPFLAGS := -MMD -MP
CFLAGS := -Weverything -Wno-padded -Wno-unused-parameter -Wno-unused-variable -Wno-sign-conversion -O3
objs := fianchetto.o util.o ttable.o movegen.o
deps := $(objs:.o=.d)
.PHONY: all debugf clean
all: CPPFLAGS += -DNDEBUG
debugf: CFLAGS += -g3
all debugf: fianchetto
fianchetto: $(objs)
clean: ; $(RM) $(objs) $(deps) fianchetto fianchetto.dSYM
-include $(deps)

Fortran: makefile with multiple directories

I have a large fortran project like this:
project
|-\bin
|-\obj
|-\src
|--\fortran
|---\common
|---\prePro
I am trying to build a makefile like this one:
F90 = gfortran
FFLAGS = -O3
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 $#
that lies on the bin directory. For now I came up with this:
FC = gfortran
FFLAGS = -O3
VPATH = ../src/fortran/common:../src/fortran/prePro:
SRCOBJ = $(wildcard ../src/fortran/common/*.f90) $(wildcard ../src/fortran/prePro/*.f90)
MODOBJ = $(SRCOBJ:.f90=.o)
all: prePro
prePro: $(MODOBJ) prePro.o
$(FC) prePro.o -o prePro
%.o %.mod:%.f90
$(FC) $(FFLAGS) -c $^ -o $#
However this don't work because most of my files are modules and they depend on each other.
Adding the dependencies manually fix the issue, i.e.:
../src/fortran/common/common_routines.o: ../src/fortran/common/types.o ../src/fortran/common/global.o
../src/fortran/common/global.o: ../src/fortran/common/types.o
etc...
Is there any easier (shorter) way to fix the dependency issues?
Bonus question: How can I trow the objects and modules in a obj folder and link the program from there?

The function of the "ifneq ($(MAKECMDGOALS),clean)" part in the Makefile

I really don't know the function of the following part:
ifneq ($(MAKECMDGOALS),clean)
-include $(DFILES)
endif
Here is the possible explanation I get from the GNU make manual:
to avoid including ‘.d’ files during clean rules, so make won’t create
them only to immediately remove them again:
But I don't fully understand "won’t create them only to immediately remove them again".
Here is the Makefile from derivative.tar.bz2 from http://www.dirac.org/linux/gdb/03-Initialization,_Listing,_And_Running.php#wherearewegoingtogo:
TARGET = driver
# CC = colorgcc
CC = gcc
CFILES = $(wildcard *.c)
OFILES = $(patsubst %.c, %.o, $(CFILES))
DFILES = $(patsubst %.c, .deps/%.d, $(CFILES))
WARN = -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Waggregate-return \
-Wpointer-arith -Wcast-qual -Wcast-align -Wmissing-declarations -pedantic \
-Wnested-externs -Wredundant-decls -Wwrite-strings -Winline -Werror
CFLAGS = -std=c99 $(WARN) -g3
LDLIBS = -lm
all: $(TARGET)
ctags *.c *.h
$(TARGET): $(OFILES)
$(CC) -o $(TARGET) $(OFILES) $(LDLIBS)
.deps/%.d: %.c
#mkdir -p .deps
#$(CC) -MM $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; $(RM) -rf $#.$$$$
ifneq ($(MAKECMDGOALS),clean)
-include $(DFILES)
endif
.PHONY: clean nuke
clean:
$(RM) -rf $(TARGET) *.o core .deps tags
Let's suppose you've just untarred the archive, and for whatever reason you want to run make clean before anything else. Presumably, it is already clean. Now, without the ifneq, make would:
Execute the include $(DFILES) line. Before doing the include proper, it would...
Run the recipe for .deps/%.d: %.c because the $(DFILES) variable contains files with names that match .deps/%.d. This means running $(CC) (which is gcc by default), which is a rather expensive operation. Once the recipe is run as many times as there are .d files to generate, then...
Run the recipe for clean.
All the work done in 2 is pointless since at step 3 it will be deleted. The reason 2 exists is that when you include a file, make first checks whether it has a recipe to generate the file to be included an runs the recipe if the file does not exist or is out of date.
The ifneq bit allows the Makefile to avoid doing the work in step 2 if the goal is clean.

Multiple targets and libraries in Makefile

I have this folder/files structure:
./libs/
helpers.c
helpers.h
./a_app.c
./b_app.c
./c_app.c
Each app depends on helpers lib and GStreamer, so I need to compile helpers.o (inside libs/ folder) and then link each app.
Currently I have this Makefile:
CC = gcc
CFLAGS = -g -Wall -w
LFLAGS = -g -Wall -w -c
CFLAGS += `pkg-config --cflags gstreamer-app-0.10`
LFLAGS += `pkg-config --cflags gstreamer-app-0.10`
LDFLAGS =
LDFLAGS += `pkg-config --libs gstreamer-app-0.10`
all: examples
examples: helpers.o a_app
$(info *** examples ***)
helpers.o:
$(info *** helpers.o ***)
$(CC) $(LFLAGS) libs/helpers.c -o libs/helpers.o $(LDFLAGS)
a_app: a_app.o
$(CC) $(CFLAGS) libs/helpers.o a_app.o -o a_app $(LDFLAGS)
a_app.o: a_app.c
$(info *** a_app.o ***)
$(CC) $(LFLAGS) a_app.c $(LDFLAGS)
While I could add b_appand c_app I'm looking for another (more elegant) way of doing it. Can't I just say that I have a, b and c _app and let Makefile compile them all and link them against GStreamer and helpers?
Also, is there any way to make Makefile compile files without needing to tell it -o name_of_file (and perhaps make it compile them in the folder that they are, because of the helpers library).
Okay, so - as we discussed in the comments, make can figure out how to make the .o files, so those rules are unnecessary. To make a generalized rule for all your *_app files (assuming they all have the same dependency on helpers.h, you can do this:
%_app: %_app.o libs/helpers.o
Make uses the % as a wildcard, and in the rule/dependency line the wildcard will expand to the same thing in the dependencies as it did in the rule. In the actual execution, you can use $* to get the same string. So a single rule for all your *_app executables winds up looking a bit like this:
%_app: %_app.o libs/helpers.o
$(CC) $(CFLAGS) libs/helpers.o $*_app.o -o $*_app $(LDFLAGS)
I was testing this on my machine (hence comments instead of answers, and wound up writing this Makefile:
CC = gcc
CFLAGS = -g -Wall -w
LFLAGS = -g -Wall -w -c
CFLAGS += `pkg-config --cflags gstreamer-app-0.10`
LFLAGS += `pkg-config --cflags gstreamer-app-0.10`
LDFLAGS =
LDFLAGS += `pkg-config --libs gstreamer-app-0.10`
new: clean all
clean:
rm -rf *.o */*.o *_app
all: examples
examples: a_app b_app
%_app: %_app.o libs/helpers.o
$(CC) $(CFLAGS) libs/helpers.o $*_app.o -o $*_app $(LDFLAGS)
Does that all make sense?
EDIT: It occurs to me that GNU Make can run some commands on the command line and store the string for its own purposes.
$(shell ls *_app.c | sed 's/.c//') will expand into all the apps you have in the current directory. so you can say:
examples: $(shell ls *_app.c | sed 's/\.c//')
Or, as I think is a little better:
...
ALLAPPS = $(shell ls *_app.c | sed 's/\.c//')
...
all: $(ALLAPPS)
That way make can be used to make everything, and make ?_app can be used to compile one app at a time.
Super ultra mega double EDIT:
Using a bald % operator as a target will bust up Make's ability to auto generate .o files. Here's the solution we worked out in chat:
CC = gcc
CFLAGS = -g -Wall -w
LFLAGS = -g -Wall -w -c
CFLAGS += $(shell pkg-config --cflags gstreamer-app-0.10)
LFLAGS += $(shell pkg-config --cflags gstreamer-app-0.10)
LDFLAGS =
LDFLAGS += $(shell pkg-config --libs gstreamer-app-0.10)
TARGETS = $(shell ls *.c | sed 's/\.c//')
new: clean all
clean:
rm -rf *.o */*.o *_app
all: examples
examples: $(TARGETS)
.SECONDEXPANSION:
$(TARGETS): libs/helpers.o $$#.o
$(CC) $(CFLAGS) libs/helpers.o $#.o -o $# $(LDFLAGS)

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