Makefile with automatic dependency generation - makefile

I'm reading Managing Projects with GNU Make while trying to write a slim and general Makefile for my Fortran project. I'm lost at the point where the following code is presented,
define make-depend
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M $1 | \
$(SED) 's,\($$(notdir $2)\) *:,$$(dir $2) $3: ,' > $3.tmp
$(MV) $3.tmp $3
endef
%.o: %.c
$(call make-depend,$<,$#,$(subst .o,.d,$#))
$(COMPILE.c) -o $# $<
about which I read
Now, the object file and dependency file are logically linked: if one
exists the other must exist. Therefore, we don’t really care if a
dependency file is missing. If it is, the object file is also missing
and both will be updated by the next build.
Well, I don't understand the part in bold; how is it possible to compile a source file ($(COMPILE.c) -o $# $<) and generate its dependency file ($(call make-depend,$<,$#,$(subst .o,.d,$#))) at the same time? I mean, how can it work?
Maybe my Fortran experience misleads me, since I'm used to the fact that I can look in one source file to find which other source files it depends upon (looking for USE statements), then compile those source files (or repeating the process) and only after I can compile that one source file.
If needed, I can upload the short Makefile I'm trying to write, but it's obviously non-working. Specifically,
make pick one of the .f90 files, say some.f90, creates its associated dependency file some.d with $(call make-depend,$<,$#,$(subst .o,.d,$#)), then fails when trying to compile some.f90 with $(COMPILE.c) -o $# $<, since some.o depends on someother.o, which is indeed listed in some.d at this point.
Running make again will result in an attempt to compile someother.f90, which will end in either
2.1) success, if someother.o does not depend on any other .o file, in which case make would go back to step 1., picking another .f90 file.
2.2) or in error, but with someother.d being produced, and I should go manually to step 2.
Brutally, I keep on running make several times by for ((i = 1; i <= 10; i++)); do make; done, if ten times is enough.
This is the non-yet-working attempt:
# ====================================================================================================
FC = mpifort
FLIBS = -llapack -lblas
FCFLAGS = -ffree-form -ffree-line-length-0 -fimplicit-none -fdefault-real-8
# ====================================================================================================
PROGRAM := main
SRCDIR := src
OBJDIR := obj
MODDIR := mod
DEPDIR := dep
SRC := $(wildcard $(SRCDIR)/*.f90)
OBJ := $(patsubst $(SRCDIR)/%,$(OBJDIR)/%,$(SRC:.f90=.o))
MOD := $(shell echo $(patsubst $(SRCDIR)/%,$(MODDIR)/%,$(SRC:.f90=.mod)) | tr '[:upper:]' '[:lower:]')
DEP := $(patsubst $(SRCDIR)/%,$(DEPDIR)/%,$(SRC:.f90=.d))
# ====================================================================================================
$(PROGRAM): $(OBJ)
$(FC) $(FCFLAGS) -o $# $^ $(LDFLAGS) $(FLIBS)
# ====================================================================================================
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif
# $(call make-depend,source-file,object-file,depend-file)
define make-depend
./dep-gen.sh < $1 | sed -e 's,\([^ ]*\),'"$(OBJDIR)"'/\1,g' \
-e 's,.*,'"$2 $3"': &,' > $(DEPDIR)/$(notdir $3)
endef
# ====================================================================================================
$(OBJDIR)/%.o: $(SRCDIR)/%.f90
#echo '************************************************************ target %.o'
$(call make-depend,$<,$#,$(DEPDIR)/$(subst .o,.d,$(notdir $#)))
$(FC) $(FCFLAGS) $(FLIBS) -c $< -J $(MODDIR) -o $#
# ====================================================================================================
.PHONY: clean veryclean
clean:
$(RM) $(OBJ) $(MOD) $(DEP)
veryclean: clean
$(RM) $(PROGRAM)
# ====================================================================================================
The bash script dep-gen.sh takes a file.f90 file from standard input and sends to standard output the space-separated list of files.o files from which the file.o file depends.

Related

Makefile with different source types doesn't notice make.depend

I want my Makefile to accept different source file types. It does, but it does not recompile when I alter an include file. Here's the Makefile:
C_SOURCES := $(wildcard *.c)
CPP_SOURCES := $(wildcard *.cpp)
CC_SOURCES := $(wildcard *.cc)
ALL_SOURCES := $(notdir $(C_SOURCES) $(CPP_SOURCES) $(CC_SOURCES))
C_OBJECTS := ${C_SOURCES:.c=.o}
CPP_OBJECTS := ${CPP_SOURCES:.cpp=.o}
CC_OBJECTS := ${CC_SOURCES:.cc=.o}
ALL_OBJECTS := $(notdir $(C_OBJECTS) $(CPP_OBJECTS) $(CC_OBJECTS))
#############################################################
all: a.out
a.out: $(ALL_OBJECTS)
g++ -o $# -g $^
%.o: %.cpp
g++ -c $# -g $^
%.o: %.cc
g++ -c $# -g $^
%.o: %.c
g++ -c $# -g $^
clean:
rm -f a.out
rm -f *.o
make.depend: $(ALL_SOURCES)
g++ -MM $^ > $#
-include make.depend
The lines starting with *.o: are a recent addition -- I wondered if it might help. No effect.
make.depend is doing its job: I checked it out, and its dependencies are correct. (For my MCVE I have one source file main.cpp which includes date.h.)
main.o: main.cpp date.h
The output of $(info $(ALL_OBJECTS)) is main.o.
So: how can I get it to recognize changes to includes?
It would be helpful, when asking questions, to show an example of running the commands and what is printed. Given the makefile you provide I'd be surprised of make actually ran any commands at all, other than generating the depend file.
That's because this:
C_OBJECTS := ${C_SOURCES: .c =.o}
is invalid syntax. Or more precisely, it doesn't do what you want to do. It replaces the literal string _____.c__ (where the _ are whitespace... SO won't let me just use spaces) at the end of each word in C_SOURCES with .o. Of course you don't have any of those, so basically your ALL_OBJECTS variable contains just your source files (since no changes are made by the substitution).
You can use:
$(info $(ALL_OBJECTS))
to see what happens here.
This needs to be written:
C_OBJECTS := ${C_SOURCES:.c=.o}
CPP_OBJECTS := ${CPP_SOURCES:.cpp=.o}
CC_OBJECTS := ${CC_SOURCES:.cc=.o}
Whitespace in makefiles is very tricky. You definitely have to be careful where you put it and you can't add it anywhere you like.
Also I have no idea why you're using notdir since all your files are in the current directory.
And technically it's incorrect to compile .c files with the g++ compiler front-end.
ETA also your pattern rules are incorrect: you're missing the -o option to the compiler; they should all be the equivalent of:
%.o: %.c
g++ -c -o $# -g $^
Better is to use the standard make variables, then you can customize the behavior without rewriting all the rules:
CFLAGS = -g
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
Update Just use the comprehensively enginerred automatic dependency file generation #MadScientist describes at http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/. This works with both GCC and clang (due to clang's explicit goal to be commandline compatible to GCC).
For completeness' sake, my original answer:
The generated dependency rules must depend on the sources determined by the dependeny rule generating rule. This requires the -MT parameter to gcc.
I have included this as an example in a slightly cleaned up version of your GNUmakefile:
#############################################################
ALL_CFLAGS = -g
ALL_CXXFLAGS = -g
#############################################################
.PHONY: all
all: all-local
#############################################################
bin_PROGRAMS += test-cxx
test_cxx_OBJECTS += main.o
test_cxx_OBJECTS += main-c.o
test-cxx: $(test_cxx_OBJECTS)
$(LINK.cc) $(ALL_CXXFLAGS) -o $# $^
ALL_OBJECTS += $(test_cxx_OBJECTS)
#############################################################
%.o: %.cpp
$(COMPILE.cpp) $(ALL_CXXFLAGS) -o $# -c $<
%.o: %.cc
$(COMPILE.cc) $(ALL_CXXFLAGS) -o $# -c $<
%.o: %.c
$(COMPILE.c) $(ALL_CFLAGS) -o $# -c $<
#############################################################
%.dep: %.cpp
$(COMPILE.cpp) -MM -MT "$*.o $# " $< > $#.tmp
mv -f $#.tmp $#
%.dep: %.cc
$(COMPILE.cc) -MM -MT "$*.o $# " $< > $#.tmp
mv -f $#.tmp $#
%.dep: %.c
$(COMPILE.c) -MM -MT "$*.o $# " $< > $#.tmp
mv -f $#.tmp $#
ALL_DEPS = $(ALL_OBJECTS:.o=.dep)
-include $(ALL_DEPS)
#############################################################
.PHONY: all-local
all-local: $(bin_PROGRAMS)
.PHONY: clean
clean:
rm -f $(bin_PROGRAMS)
rm -f *.dep
rm -f *.o
#############################################################
The *.dep generating rules will recursively examine all included source files, and list them all in the generated *.dep file.
Using a separate *.dep file for each object file means that if you change only one source file, only the *.dep files needing regeneration will actually be regenerated.
The *.dep generating rule creates a *.dep.tmp file first, and only moves that to *.dep if generating the *.dep.tmp file has been successful. So if for some reason generating the *.dep.tmp file fails (e.g. you might be including a non-existing header file), you will not have a newly generated (and thus considered up to date) empty *.dep file being included by make.

Makefile does not find rules despire of available files

Currently I am trying to get a rather big project of mine to work with a Makefile. I used Make before but in a rather crude way and not really "dynamic", this means I am pretty new to good Makefiles.
My Makefile looks like this:
INCLUDE_DIR = /inc
SOURCE_DIR = /src
BUILD_DIR = /build
BUILD_NAME = build
CC = arm-none-eabi-gcc
CFLAGS = -I$(INCLUDE_DIR)
_INCLUDES = main.h pfc.h
INCLUDES = $(patsubst %, $(INCLUDE_DIR)/%, $(_INCLUDES))
_OBJ = main.o pfc.o
OBJ = $(patsubst %, $(BUILD_DIR)/%, $(_OBJ))
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c $(INCLUDES)
$(CC) -c -o $# $< $(CFLAGS)
$(BUILD_NAME): $(OBJ)
$(CC) -o $# $^ $(CFLAGS)
all: $(BUILD_NAME)
.PHONY: clean
clean:
rm -rf $(BUILD_DIR)/*
When I make the file I get this:
make: *** No rule to make target '/build/main.o', needed by 'build'. Stop.
I guess it is an error in this recipe:
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c $(INCLUDES)
$(CC) -c -o $# $< $(CFLAGS)
Sadly I am not able to get this done on my own.
All files a available in the correct folders.
I really appreciate all the help!
Tristan
You have a few issues here that I can see. But first off - just check (just incase) that all your rules are only indented with tabs and not spaces..... this can be a real "silent" killer of makefiles as they give crap error messages.
Ok so - lets assume you have:
INCLUDE_DIR = inc
SOURCE_DIR = src
BUILD_DIR = build
instead of /src etc.. as mentioned in the comments.
Do you really have inc/main.h and inc/pfc.h?
I copied and pasted your makefile added your src and inc folders (but I used gcc instead of arm-none-eabi-gcc. It did the compile lines correctly, but failed at the linker stage because you are trying to build an output file called build when there is already a folder called build (not allowed in linux - maybe ok for windows but I don't recommend).
I made an answer for another question - but it might be a better start point then you have here in the case where you have nested src/inc directories and you want to be able to clean your output folders - ill put it here for convenience:
# Get your source list (use wildcard or what ever, but just for clarity you should end up with a list of files with full paths to start with):
# Output folders/targets
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
OUTPUT_FILE = output
# Generate list of source files - this is a linux command - but you can do this in pure make using wildcard and such).
SOURCES := $(shell find $(SOURCEDIR) -name '*.c')
# Create your objects list in the obj directory
OBJECTS = $(addprefix $(OBJ_DIR)/,$(addsuffix .o,$(basename $(SOURCES))))
# Create list of unique folders to create
DIRS = $(sort $(dir $(OBJECTS))) $(BIN_DIR)
# Create list of include paths
INCS = $(addprefix -I,$(sort $(dir $(SOURCES))))
# Main target rule
$(BIN_DIR)/$(OUTPUT_FILE): $(OBJECTS) | $(DIRS)
#echo linker: gcc $(OBJECTS) -o $#
#touch $#
# Rule to build your object file - ensure that the folders are created first (also create a dummy obj file) - note this works for parallel builds too (make -j
$(OBJ_DIR)/%.o: %.c | $(DIRS)
#echo compile: gcc $(INCS) -c $? -o $#
#touch $#
# Create your directories here
$(DIRS):
#echo Creating dir: $#
#mkdir -p $#
# Clean if needed
.PHONY: clean
clean:
rm -rf $(OBJ_DIR) $(BIN_DIR)
Note this is just a template, you still need to fill in the gcc/makefile flags - but its a decent start point...
Debugging
$(info ...) is your friend - for example you could do:
$(info OBJ = $(OBJ))
$(info objrule = $(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c $(INCLUDES))
To print our what make has expanded these variables / lines to be - this can yield useful debug.
Here is another version of your makefile with automatic dependency generation:
INCLUDE_DIR := inc
SOURCE_DIR := src
BUILD_DIR := build
CC := arm-none-eabi-gcc
CPPFLAGS := -I$(INCLUDE_DIR)
exes := build
build.obj := main.o pfc.o
all : ${exes:%=${BUILD_DIR}/%}
.SECONDEXPANSION:
${BUILD_DIR}:
mkdir -p $#
# Rule to link all exes.
${exes:%=${BUILD_DIR}/%} : ${BUILD_DIR}/% : $$(addprefix ${BUILD_DIR}/,$${$$*.obj}) | $${#D}
${CC} -o $# ${LDFLAGS} $^ ${LDLIBS}
# Rule to compile C sources. And generate header dependencies.
${BUILD_DIR}/%.o : ${SOURCE_DIR}/%.c | $${#D}
${CC} -o $# -c ${CPPFLAGS} ${CFLAGS} -MD -MP $<
# Include automatically generated header dependencies.
ifneq ($(MAKECMDGOALS),clean)
-include $(foreach exe,${exes},$(patsubst %.o,${BUILD_DIR}/%.d,${${exe}.obj}))
endif
clean:
rm -rf $(BUILD_DIR)
.PHONY: all clean
To add another executable target do:
exes += another
another.obj := another_main.o another_pfc.o

Makefile to auto compile, assemble and link many files in a directory

Sorry for repetition, but I could not find the solution.
Following is the sequence of the commands I want Makefile to accomplish.
gcc-elf-gcc -S -combine loadStoreByte.c string.c lib_uart.c bubble_uart.c -o bubble_uart.s
gcc-elf-as -o startup.o startup.s;
gcc-elf-as -o handler.o handler.s;
gcc-elf-as -o bubble_uart.o bubble_uart.s;
gcc-elf-ld -o bubble_uart -T browtb.x bubble_uart.o startup.o handler.o;
That is, I want to compile all C files into a single S file and then assemeble all s files into corresponding object files and the link all object files into one executable.
I tried the following makefile. The individual targets work fine, but could not run all the target at the same time using "make all".
Please guide how to fix it.
CC = brownie32-elf-gcc
AS = brownie32-elf-as
LK = brownie32-elf-ld
SFILE = $(wildcard *.s)
OFILE = $(patsubst %.s,%,$(SFILE))
CFILE = $(wildcard *.c)
OBJ = $(wildcard *.o)
APP = bubble_uart
all: compile assemble link
link: $(OBJ)
$(LK) -o $(APP) -T browtb.x $^
assemble: $(OFILE)
%: %.s compile
$(AS) -o $#.o $<
compile: $(CFILE)
$(CC) -S -combine $^ -o $(APP).s
clean:
rm -f $(OBJ) $(APP) $(APP).s *.o
Thanks
Your makefile is not written with "best practices" and because of that it was easy for you to make mistakes. I will re-write your makefile here, with best practices, which solves all your problems. Please study it with the aid of the GNU Make manual.
The biggest single problem is that you have "procedures/actions", such as "assemble" as make targets. This makes the makefile into a kind of "procedural" program. GNU Make is not designed to be a procedural language, instead, it is a declarative language. The "targets" should not be actions, but actual files, or "phony" files, which should be collections of actual files.
The use of wildcard in makefiles is a bad idea - it is best to list your files explicitly, as I have shown.
Please consult my answer
makefile enforce library dependency ordering
for a discussion of good practices, including phony and real targets.
MAKEFILE := $(lastword $(MAKEFILE_LIST))
CFILES := \
loadStoreByte.c \
string.c \
lib_uart.c \
bubble_uart.c
SFILE_OUTPUT := bubble_uart.s
SFILES := $(SFILE_OUTPUT) \
startup.s \
handler.s
OFILES := $(SFILES:s=o)
APP := bubble_uart
.PHONY: all
all: $(APP)
$(APP): browtb.x $(OFILES) $(MAKEFILE)
gcc-elf-ld -o $# -T $< $(OFILES)
$(OFILES): %o : %s $(MAKEFILE)
gcc-elf-as -o $# $<
$(SFILE_OUTPUT): $(CFILES) $(MAKEFILE)
gcc-elf-gcc -S -combine $(CFILES) -o $#
It is usually best if the target of a rule is the name of the file the rule produces.
So the compile rule:
compile: $(CFILE)
$(CC) -S -combine $^ -o $(APP).s
should be this:
$(APP).s: $(CFILE)
$(CC) -S -combine $^ -o $#
Likewise the object rule:
%: %.s compile
$(AS) -o $#.o $<
should be this:
%.o: %.s
$(AS) -o $# $<
(There's no reason for it to depend on compile or $(APP).s, since bubble_uart.s is irrelevant to most object files.)
Then the list of object files should include bubble_uart.o:
SFILES = $(sort $(wildcard *.s) $(APP).s)
OFILES = $(patsubst %.s,%.o,$(SFILES))
(The sort is to remove duplicates.) Note that this is the list of object files needed for construction of the executable, not the list of object files that happen to exist at the beginning of the build process.
Finally, the executable:
$(APP): $(OFILES)
$(LK) -o $# -T browtb.x $^

How to place object files in separate subdirectory

I'm having trouble with trying to use make to place object files in a separate subdirectory, probably a very basic technique. I have tried to use the information in this page:
http://www.gnu.org/software/hello/manual/make/Prerequisite-Types.html#Prerequisite-Types
I get the following output from make:
make: *** No rule to make target `ku.h', needed by `obj/kumain.o'. Stop.
However ku.h is a dependency not a target (although it's obviously #included within the c source files). When I don't try to use a subdirectory for object files (i.e. miss out the OBJDIR parts) it works fine. Why does make think ku.h is a target?
my makefile is this: (the style is after reading various sources of information)
.SUFFIXES:
.SUFFIXES: .c .o
CC=gcc
CPPFLAGS=-Wall
LDLIBS=-lhpdf
VPATH=%.c src
VPATH=%.h src
VPATH=%.o obj
OBJDIR=obj
objects= $(addprefix $(OBJDIR)/, kumain.o kudlx.o kusolvesk.o kugetpuz.o kuutils.o \
kurand.o kuASCboard.o kuPDFs.o kupuzstrings.o kugensud.o \
kushapes.o )
ku : $(objects)
$(CC) $(CPPFLAGS) -o ku $(objects) $(LDLIBS)
$(objects) : ku.h kudefines.h kuglobals.h kufns.h | $(OBJDIR)
$(OBJDIR):
mkdir $(OBJDIR)
.PHONY: clean
clean :
rm $(objects)
Edit:
I applied the change to use the vpath directive. My version was a bad mixture of VPATH=xxx and vpath %.c xxx. However I now get another problem (which was the original problem before I added the wrong vpath). This is now the output:
gcc -o ku -lhpdf obj/kumain.o obj/kudlx.o obj/kusolvesk.o ..etc
gcc: obj/kumain.o: No such file or directory
gcc: obj/kudlx.o: No such file or directory
gcc: obj/kusolvesk.o: No such file or directory
gcc: obj/kugetpuz.o: No such file or directory
gcc: obj/kuutils.o: No such file or directory
gcc: obj/kurand.o: No such file or directory
gcc: obj/kuASCboard.o: No such file or directory
gcc: obj/kuPDFs.o: No such file or directory
gcc: obj/kupuzstrings.o: No such file or directory
gcc: obj/kugensud.o: No such file or directory
gcc: obj/kushapes.o: No such file or directory
make: *** [ku] Error 1
It appears that make is not applying the implicit rule for an object file although the manual says
"Implicit rules tell make how to use customary techniques so that you do not have to specify them in detail when you want to use them. For example, there is an implicit rule for C compilation. File names determine which implicit rules are run. For example, C compilation typically takes a .c file and makes a .o file. So make applies the implicit rule for C compilation when it sees this combination of file name endings." and also "The search through the directories specified in VPATH or with vpath also happens during consideration of implicit rules (see Using Implicit Rules)."
Again here "For example, when a file foo.o has no explicit rule, make considers implicit rules, such as the built-in rule to compile foo.c if that file exists. If such a file is lacking in the current directory, the appropriate directories are searched for it. If foo.c exists (or is mentioned in the makefile) in any of the directories, the implicit rule for C compilation is applied."
Any assistance in getting implicit rules to work for my makefile would be greatly appreciated.
Edit no 2:
Thanks to Jack Kelly I have made an explicit rule to compile the .c files since I couldn't get anywhere trying to use implicit rules. Also thanks to al_miro for the vpath info.
Here is the working makfile:
.SUFFIXES:
.SUFFIXES: .c .o
CC=gcc
CPPFLAGS=-Wall
LDLIBS=-lhpdf
OBJDIR=obj
vpath %.c src
vpath %.h src
objects = $(addprefix $(OBJDIR)/, kumain.o kudlx.o kusolvesk.o kugetpuz.o kuutils.o \
kurand.o kuASCboard.o kuPDFs.o kupuzstrings.o kugensud.o \
kushapes.o )
ku : $(objects)
$(CC) $(CPPFLAGS) -o ku $(objects) $(LDLIBS)
$(OBJDIR) obj/%.o : %.c ku.h kudefines.h kuglobals.h kufns.h
$(CC) -c $(CPPFLAGS) $< -o $#
.PHONY : clean
clean :
rm $(objects)
Since you're using GNUmake, use a pattern rule for compiling object files:
$(OBJDIR)/%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $# $<
This is the makefile that I use for most of my projects,
It permits putting source files, headers and inline files in subfolders, and subfolders of subfolders and so-forth, and will automatically generate a dependency file for each object This means that modification of headers and inline files will trigger recompilation of files which are dependent.
Source files are detected via shell find command, so there is no need to explicitly specify, just keep coding to your hearts content.
It will also copy all files from a 'resources' folder, into the bin folder when the project is compiled, which I find handy most of the time.
To provide credit where it is due, the auto-dependencies feature was based largely off Scott McPeak's page that can be found HERE, with some additional modifications / tweaks for my needs.
Example Makefile
#Compiler and Linker
CC := g++-mp-4.7
#The Target Binary Program
TARGET := program
#The Directories, Source, Includes, Objects, Binary and Resources
SRCDIR := src
INCDIR := inc
BUILDDIR := obj
TARGETDIR := bin
RESDIR := res
SRCEXT := cpp
DEPEXT := d
OBJEXT := o
#Flags, Libraries and Includes
CFLAGS := -fopenmp -Wall -O3 -g
LIB := -fopenmp -lm -larmadillo
INC := -I$(INCDIR) -I/usr/local/include
INCDEP := -I$(INCDIR)
#---------------------------------------------------------------------------------
#DO NOT EDIT BELOW THIS LINE
#---------------------------------------------------------------------------------
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))
#Defauilt Make
all: resources $(TARGET)
#Remake
remake: cleaner all
#Copy Resources from Resources Directory to Target Directory
resources: directories
#cp $(RESDIR)/* $(TARGETDIR)/
#Make the Directories
directories:
#mkdir -p $(TARGETDIR)
#mkdir -p $(BUILDDIR)
#Clean only Objecst
clean:
#$(RM) -rf $(BUILDDIR)
#Full Clean, Objects and Binaries
cleaner: clean
#$(RM) -rf $(TARGETDIR)
#Pull in dependency info for *existing* .o files
-include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT))
#Link
$(TARGET): $(OBJECTS)
$(CC) -o $(TARGETDIR)/$(TARGET) $^ $(LIB)
#Compile
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
#mkdir -p $(dir $#)
$(CC) $(CFLAGS) $(INC) -c -o $# $<
#$(CC) $(CFLAGS) $(INCDEP) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT)
#cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp
#sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT)
#sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT)
#rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp
#Non-File Targets
.PHONY: all remake clean cleaner resources
The VPATH lines are wrong, they should be
vpath %.c src
vpath %.h src
i.e. not capital and without the = . As it is now, it doesn't find the .h file and thinks it is a target to be made.
In general, you either have to specify $(OBJDIR) on the left hand side of all the rules that place files in $(OBJDIR), or you can run make from $(OBJDIR).
VPATH is for sources, not for objects.
Take a look at these two links for more explanation, and a "clever" workaround.
http://mad-scientist.net/make/vpath.html
http://mad-scientist.net/make/multi-arch.html
Build from the output directory
Instead of building from the top-level directory, build from the output directory. You can access the source directories by setting the vpath. This option has the advantage that the built-in rules can be used.
build.sh
#!/bin/bash
mkdir -p obj
cp Makefile.template obj/Makefile
cd obj
make "$*"
Makefile
.SUFFIXES:
.SUFFIXES: .c .o
CC=gcc
CPPFLAGS=-Wall
LDLIBS=-lhpdf
VPATH=%.c ../src
VPATH=%.h ../src
objects=kumain.o kudlx.o kusolvesk.o kugetpuz.o kuutils.o \
kurand.o kuASCboard.o kuPDFs.o kupuzstrings.o kugensud.o \
kushapes.o
ku : $(objects)
$(objects) : ku.h kudefines.h kuglobals.h kufns.h
.PHONY: clean
clean :
rm $(objects)
The disadvantage is that error messages do not match the CWD. This can be solved by skipping build.sh and directly building from the obj directory.
Another advantage of this approach is that it's somewhat popular. cmake works in a similar fashion.
Create Rule based on output option
The following solution isn't nice in my opinion, as I really love the built-in rules. However, GNU make doesn't support something like vpath for output directories. And the built-in rules cannot match, as the % in %.o would match obj/foo of obj/foo.o, leaving make with a search in vpath %.c src/ for stuff like src/obj/foo.c, but not src/foo.c.
But this is as close to the built-in rules as you can get, and therefore to my best knowledge the nicest solution that's available.
$(OBJDIR)/%.o: %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
Explanation: $(COMPILE.c) $(OUTPUT_OPTION) $< actually is how .c.o is implemented, see http://git.savannah.gnu.org/cgit/make.git/tree/default.c (and it's even mentioned in the manual)
Besides, if $(OBJDIR) would only ever contain auto-gererated files, you could create it on-the-fly with an order-only prerequisite, making the clean rule slightly simpler:
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: %.c | $(OBJDIR)
$(COMPILE.c) $(OUTPUT_OPTION) $<
.PHONY: clean
clean:
$(RM) -r $(OBJDIR)
This requires that the feature order-only is available, which you can check using $(filter order-only, $(.FETAURES)). I've checked on Kubuntu 14.04 GNU make 3.81 and OpenSUSE 13.1 GNU make 3.82. Both were built with order-only enabled, and am now left puzzled why Kubuntu 14.04 comes with an older version of GNU make than OpenSUSE 13.1. Anyways, gonna download make 4.1 now :)
For anyone that is working with a directory style like this:
project
> src
> pkgA
> pkgB
...
> bin
> pkgA
> pkgB
...
The following worked very well for me. I made this myself, using
the GNU make manual as my main reference; this, in particular, was extremely helpful for my last rule, which ended up being the most important one for me.
My Makefile:
PROG := sim
CC := g++
ODIR := bin
SDIR := src
MAIN_OBJ := main.o
MAIN := main.cpp
PKG_DIRS := $(shell ls $(SDIR))
CXXFLAGS = -std=c++11 -Wall $(addprefix -I$(SDIR)/,$(PKG_DIRS)) -I$(BOOST_ROOT)
FIND_SRC_FILES = $(wildcard $(SDIR)/$(pkg)/*.cpp)
SRC_FILES = $(foreach pkg,$(PKG_DIRS),$(FIND_SRC_FILES))
OBJ_FILES = $(patsubst $(SDIR)/%,$(ODIR)/%,\
$(patsubst %.cpp,%.o,$(filter-out $(SDIR)/main/$(MAIN),$(SRC_FILES))))
vpath %.h $(addprefix $(SDIR)/,$(PKG_DIRS))
vpath %.cpp $(addprefix $(SDIR)/,$(PKG_DIRS))
vpath $(MAIN) $(addprefix $(SDIR)/,main)
# main target
#$(PROG) : all
$(PROG) : $(MAIN) $(OBJ_FILES)
$(CC) $(CXXFLAGS) -o $(PROG) $(SDIR)/main/$(MAIN)
# debugging
all : ; $(info $$PKG_DIRS is [${PKG_DIRS}])#echo Hello world
%.o : %.cpp
$(CC) $(CXXFLAGS) -c $< -o $#
# This one right here, folks. This is the one.
$(OBJ_FILES) : $(ODIR)/%.o : $(SDIR)/%.h
$(CC) $(CXXFLAGS) -c $< -o $#
# for whatever reason, clean is not being called...
# any ideas why???
.PHONY: clean
clean :
#echo Build done! Cleaning object files...
#rm -r $(ODIR)/*/*.o
By using $(SDIR)/%.h as a prerequisite for $(ODIR)/%.o, this forced make to look in source-package directories for source code instead of looking in the same folder as the object file.
I hope this helps some people. Let me know if you see anything wrong with what I've provided.
BTW: As you may see from my last comment, clean is not being called and I am not sure why. Any ideas?
For all those working with implicit rules (and GNU MAKE). Here is a simple makefile which supports different directories:
#Start of the makefile
VPATH = ./src:./header:./objects
OUTPUT_OPTION = -o objects/$#
CXXFLAGS += -Wall -g -I./header
Target = $(notdir $(CURDIR)).exe
Objects := $(notdir $(patsubst %.cpp,%.o,$(wildcard src/*.cpp)))
all: $(Target)
$(Target): $(Objects)
$(CXX) $(CXXFLAGS) -o $(Target) $(addprefix objects/,$(Objects))
#Beware of -f. It skips any confirmation/errors (e.g. file does not exist)
.PHONY: clean
clean:
rm -f $(addprefix objects/,$(Objects)) $(Target)
Lets have a closer look (I will refer to the current Directory with curdir):
This line is used to get a list of the used .o files which are in curdir/src.
Objects := $(notdir $(patsubst %.cpp,%.o,$(wildcard src/*.cpp)))
#expands to "foo.o myfoo.o otherfoo.o"
Via variable the output is set to a different directory (curdir/objects).
OUTPUT_OPTION = -o objects/$#
#OUTPUT_OPTION will insert the -o flag into the implicit rules
To make sure the compiler finds the objects in the new objects folder, the path is added to the filename.
$(Target): $(Objects)
$(CXX) $(CXXFLAGS) -o $(Target) $(addprefix objects/,$(Objects))
# ^^^^^^^^^^^^^^^^^^^^
This is meant as an example and there is definitly room for improvement.
For additional Information consult:
Make documetation. See chapter 10.2
Or:
Oracle: Programming Utilities Guide
You can specify the -o $# option to your compile command to force the output of the compile command to take on the name of the target. For example, if you have:
sources: cpp/class.cpp and cpp/driver.cpp
headers: headers/class.h
...and you want to place the object files in:
objects: obj/class.o obj/driver.o
...then you can compile cpp/class.cpp and cpp/driver.cpp separately into obj/class.o and obj/driver.o, and then link, with the following Makefile:
CC=c++
FLAGS=-std=gnu++11
INCS=-I./headers
SRC=./cpp
OBJ=./obj
EXE=./exe
${OBJ}/class.o: ${SRC}/class.cpp
${CC} ${FLAGS} ${INCS} -c $< -o $#
${OBJ}/driver.o: ${SRC}/driver.cpp ${SRC}/class.cpp
${CC} ${FLAGS} ${INCS} -c $< -o $#
driver: ${OBJ}/driver.o ${OBJ}/class.o
${CC} ${FLAGS} ${OBJ}/driver.o ${OBJ}/class.o -o ${EXE}/driver
None of these answers seemed simple enough - the crux of the problem is not having to rebuild:
makefile
OBJDIR=out
VPATH=$(OBJDIR)
# make will look in VPATH to see if the target needs to be rebuilt
test: moo
touch $(OBJDIR)/$#
example use
touch moo
# creates out/test
make test
# doesn't update out/test
make test
# will now update test
touch moo
make test

Generate all project dependencies in a single file using gcc -MM flag

I want to generate a single dependency file which consists of all the dependencies of source files using gcc -M flags through Makefile. I googled for this solution but, all the solutions mentioned are for generating multiple deps files for multiple objects.
DEPS = make.dep
$(OBJS): $(SOURCES)
#$(CC) -MM $(SOURCEs) > $(DEPS)
#mv -f $(DEPS) $(DEPS).tmp
#sed -e 's|.$#:|$#:|' < $(DEPS).tmp > $(DEPS)
#sed -e 's/.*://' -e 's/\\$$//' < $(DEPS).tmp | fmt -1 | \
sed -e 's/^ *//' -e 's/$$/:/' >> $(DEPS)
#rm -f $(DEPS).tmp
But it is not working properly. Please tell me where i'm making the mistake.
Something along these lines is what I use to get all my dependencies in a single file:
program_H_SRCS := $(wildcard *.h)
program_C_SRCS := $(wildcard *.c)
DEPS = make.deps
make.deps: $(program_C_SRCS) $(program_H_SRCS)
$(CC) $(CPPFLAGS) -MM $(program_C_SRCS) > make.deps
include $(DEPS)
This basically causes all the user ( as opposed to system ) dependencies to be rebuilt into a single file whenever any C or H file in the project is modified.
+++++++++ EDIT +++++++++++
I've since found a better way of doing things. I generate a separate dep file for each source file. Here is the basic makefile:
program_NAME := myprogram
program_SRCS := $(wildcard *.c)
program_OBJS := ${program_SRCS:.c=.o}
clean_list += $(program_OBJS) $(program_NAME)
# C Preprocessor Flags
CPPFLAGS +=
# compiler flags
CFLAGS += -ansi -Wall -Wextra -pedantic-errors
.PHONY: all clean distclean
all: $(program_NAME)
clean:
#- $(RM) $(clean_list)
distclean: clean
# Generate dependencies for all files in project
%.d: $(program_SRCS)
# $(CC) $(CPPFLAGS) -MM $*.c | sed -e 's#^\(.*\)\.o:#\1.d \1.o:#' > $#
clean_list += ${program_SRCS:.c=.d}
$(program_NAME): $(program_OBJS)
indent -linux -brf $(program_SRCS)
splint $(program_SRCS)
$(LINK.c) $(program_OBJS) -o $(program_NAME)
ifneq "$(MAKECMDGOALS)" "clean"
# Include the list of dependancies generated for each object file
-include ${program_SRCS:.c=.d}
endif
This does two things:
If any of the files that foo.c depend on change then foo.o is rebuilt without having to rebuild other files in the project.
The dep file itself has the same dependencies as the object file, so that if any of the deps are modified the dep file itself is also regenerated, before the object file deps are checked.
I think is is expected behaviour for gcc -M, where typically you'd do something like this:
FOO_SOURCES= \
src/foo.c \
src/bar.c
FOO_OBJECTS = $(FOO_SOURCES:.c=.o)
FOO_DEPS = $(FOO_OBJECTS:.o=.d)
(... lots of targets ...)
-include $(FOO_DEPS)
Note, -include not include as the dependencies will obviously not exist until at least one build has been run. Regardless, dependencies are generated on a per module basis.
Also note that gcc -M does not always work as you would expect it to work, broadly depending on what version of gcc you happen to be using.
I think what you want is something called makedep, which does what you want without sed hackery in the makefile.

Resources