I have created a Makefile like this
CC = sdcc
SRCS = $(PNAME).c\
../../src/gpio.c
../../src/timers.c
../../src/i2c.c
$HDRS = -I../../headers
all:
mkdir -p ./output
$(CC) $(SRCS) -lstm8 -mstm8 $(HDRS)
The problem is, sdcc can only compile one source at a time. So I need to perform something like a foreach on each source I have defined in SRCS variable. How to do this in gnu-make?
According to the docs, you must compile the files other than the one containing main() separately, to produce .rel files, then include those in the compilation command for the main file. There are several variations on how you could do that. The following avoids features specific to GNU make:
# We're assuming POSIX conformance
.POSIX:
CC = sdcc
# In case you ever want a different name for the main source file
MAINSRC = $(PMAIN).c
# These are the sources that must be compiled to .rel files:
EXTRASRCS = \
../../src/gpio.c \
../../src/timers.c \
../../src/i2c.c
# The list of .rel files can be derived from the list of their source files
RELS = $(EXTRASRCS:.c=.rel)
INCLUDES = -I../../headers
CFLAGS = -mstm8
LIBS = -lstm8
# This just provides the conventional target name "all"; it is optional
# Note: I assume you set PNAME via some means not exhibited in your original file
all: $(PNAME)
# How to build the overall program
$(PNAME): $(MAINSRC) $(RELS)
$(CC) $(INCLUDES) $(CFLAGS) $(MAINSRC) $(RELS) $(LIBS)
# How to build any .rel file from its corresponding .c file
# GNU would have you use a pattern rule for this, but that's GNU-specific
.c.rel:
$(CC) -c $(INCLUDES) $(CFLAGS) $<
# Suffixes appearing in suffix rules we care about.
# Necessary because .rel is not one of the standard suffixes.
.SUFFIXES: .c .rel
If you look carefully, by the way, you will see that the file does not explicitly perform any looping over the source files, or any such thing. It just describes how to build each target, including intermediate targets. make figures out on its own how to combine those rules to go from sources to final program (or to any other target you specify from among those you've taught it to build).
Use patsubst. Typically it is something like:
SOURCES := $(wildcard *.c)
OBJECTS := $(patsubst %.c,%.o,${SOURCES})
prog: ${OBJECTS}
cc $^ -o $#
%.o: %.c
cc $< -c -o $#
Related
I've been learning C++ for a few months now by just using an editor and my terminal to compile and run my programs. But I saw a need to be a bit more formal with my projects, so I'm trying to learn how to build a proper project file structure and also how to use Make.
Currently, I am using GNU Make 4.1. But I am having trouble to creating object files with Make, receiving the error:
make: *** No rule to make target 'build/%.o', needed by 'main'. Stop.
I've been looking all over for a solution, but none have worked so far.
Here is my makefile:
# Specify compiler
CC=gcc
# Specify linker
LINK=gcc
# Specify flags
CPPFLAGS = -Wall -g
# Specify directories
SRCDIR = ./src
OBJDIR = ./build
# Compile object files
$(OBJDIR)/%.o : $(SRCDIR)/%.cpp
$(CC) -c -o $# $< $(CPPFLAGS)
# Compile object files into binary
main : $(OBJDIR)/%.o
$(CC) -o $# $^
Consider the final rule...
# Compile object files into binary
main : $(OBJDIR)/%.o
$(CC) -o $# $^
Unfortunately $(OBJDIR)/%.o isn't expanded in the way in which you require. Assuming all of your source files are in $(SRCDIR) you can create a variable containing their names...
SRCFILES := $(wildcard $(SRCDIR)/*.cpp)
Now create a variable containing the corresponding object file paths...
OBJFILES := $(patsubst $(SRCDIR)/%.cpp,$(OBJDIR)/%.o,$(SRCFILES))
Now $(OBJFILES) should contain the list of object file paths on which main is dependent. So the final rule becomes...
main: $(OBJFILES)
$(CC) -o $# $^
Please forgive me if this is a repeat question. I am fairly new to writing Makefiles, and so I was not really sure how to find what I am looking for.
I am getting acquainted with Boost.Test and am writing unit tests on a file-per-file basis.
This is my directory structure:
- cpp
- sim
- Makefile
- bin
- src
- ExampleClass.cpp
- tests
- Makefile
- bin
- src
-ExampleClass_T.cpp
Essentially, I would like to write individual *.cpp test case files using Boost, as displayed above.
Here is the content of my tests/Makefile:
CC = g++
CPPFLAGS = -g -v -Wall -I$(ODIR_TEST) -I$(SDIR_TEST) \
-I$(SDIR) -I$(ODIR) -I$(BOOST_ROOT)
ODIR_TEST = ./bin
SDIR_TEST = ./src
ODIR = ../sim/bin
SDIR = ../sim/src
%.out : $(SDIR_TEST)/%.cpp
$(CC) $(CPPFLAGS) -o $< $#
executing make generates a No targets. Stop. error message. Any ideas as to why make thinks there is no target? Wouldn't %.out act as the target here, or can a wildcard not act in that manner?
I recognize that in the Makefile above, I am attempting to generate a *.out file for each *.cpp file; in addition, I would like to generate a final executable that is a culmination of all generated *.out files. Is this possible, or am I approaching this incorrectly?
Any other advice or Makefile best practices, especially with regards to test automation, would be highly appreciated.
I have seemed to have found a workaround, though it can likely be optimized.
PROG = main
CC = g++
CPPFLAGS = -g -Wall -I$(ODIR_TEST) -I$(SDIR_TEST) \
-I$(SDIR) -I$(ODIR) -I$(BOOST_ROOT)
ODIR_TEST = ./bin
SDIR_TEST = ./src
OUTDIR = ./execs
ODIR = ../sim/bin
SDIR = ../sim/src
TEST_EXEC_NAMES = $(notdir $(basename $(wildcard $(SDIR_TEST)/*.cpp)))
# default rule (main.cpp)
$(OUTDIR)/$(PROG) : $(SDIR_TEST)/main.cpp $(TEST_EXEC_NAMES)
$(CC) $(CPPFLAGS) -o $# $<
% : $(SDIR_TEST)/%.cpp
$(CC) $(CPPFLAGS) -o $(OUTDIR)/$# $<
I specify a default target in my first rule. I include $(TEST_EXEC_NAMES) as a prereq to make sure that all of my individual test executables are built using the pattern rule.
Specifying my executable filenames from their .cpp counterparts is done with a series of function calls (wildcard, basename, and notdir).
Again, this is surely not the fastest way I could accomplish my task, but it has gotten me onto compilation errors.
This question is different from the one at makefiles - compile all c files at once in the sense that I have one extra requirement: I want to redirect all the object files in a separate directory.
Here is the setup:
I have multiple sources in a directory say src/mylib.
I want the objects files to end up in build/mylib.
Please note also that under mylib there are subdirectories.
The first attempt was as follows:
sources = $(shell find src/ -name ".c")
objects_dirs = $(subst src/, build/, $(dir $(sources)) # This variable is used by the build rule to create directories for objects files prior to compilation
objects = $(subst src/, build/, $(patsubst %.c, %.o, $(sources))) # This variable has the paths to the objects files that will be generated in the build directory
# This is where things aren't working as expected
$(objects): build $(sources)
$(cc) $(cflags) -o $# $(word 2, $^))
build:
$(foreach dir, $(objects_dirs), $(shell mkdir -p $(dir)))
For the makefile above, only one object file was being generated. I guessed this might have something to do with GCC only being able to generate one object file at a time. Regardless of that, checking the values of $# and $(word 2, $^) in the $(objects) target shows that only one file is being considered even though I have multiple files.
So I changed my makefile to the following:
sources = $(shell find src/ -name ".c")
objects = $(subst src/, build/, $(patsubst %.c, %.o, $(sources))) # This variable has the paths to the objects files that will be generated in the build directory
# This works as expected but it appears to me like make is generating all the objects files even though source files did not change. This can be seen by checking the timestamps on new object files after running make again.
$(objects): build $(sources)
$(foreach source, $(sources), $(shell $(cc) $(cflags) -o $(subst src/,build/, $(patsubst %.o,%.c,$(source))) $(source)))
build:
$(foreach dir, $(objects_dirs), $(shell mkdir -p $(dir)))
The second makefile works as expected but objects files are being rebuilt again which defeats another purpose of using make: only recompile those source files that changed from the last compilation.
Hence my question: how does one generate all object files in a separate directory at once (by this I mean perform the compilation of all sources files in one rule) while making sure that if a source file didn't change the associated object file should not be regenerated.
I am not after speeding up compilation. What I seek is one rule that will generate all objects files such that only updated source files should be recompiled.
The last makefile does the job but there is a recompiling of all source files which defeats another purpose of using make: only changed source files should be recompiled.
EDIT
After reading comments, it appears I have not phrased my question properly. As the details of what I have are already present, I leave the question as it is with additional details below.
The second makefile in the source code above does work. But it does only half the job. The build directory effectively mirrors the src directory.
So if I have say a file as src/mylib/point/point.c, I get build/mylib/point/point.o generated. This is the first part.
The second part is that if point.c does not changes, point.o in the build/mylib/point/ directory must not be regenerated. But after checking timestamps on the object file, I can tell that a new object file replaced the old one after running make again. This is not good because for large projects, compilation time remains O(n) with n being the number of source files to compile.
So this question is about how to preserve the second makefile without make regenerating object files.
From what I can gather from comments, I am asking too much from make. But if anyone knows how to make this happen, I leave the question open.
Makefile:
all:
clean:
src_root := src
src_subdirs := foo foo/bar foo/bar/buz
build_root := build
o_suffix := .o
# Build list of sources. Iterate every subfolder from $(src_subdirs) list
# and fetch all existing files with suffixes matching the list.
source_suffixes := .c .cpp .cxx
sources := $(foreach d,$(addprefix $(src_root)/,$(src_subdirs)),$(wildcard $(addprefix $d/*,$(source_suffixes))))
# If src_subdirs make variable is unset, use 'find' command to build list of sources.
# Note that we use the same list of suffixes but tweak them for use with 'find'
ifeq ($(src_subdirs),)
sources := $(shell find $(src_root) -type f $(foreach s,$(source_suffixes),$(if $(findstring $s,$(firstword $(source_suffixes))),,-o) -name '*$s'))
endif
$(info sources=$(sources))
# Build source -> object file mapping.
# We want map $(src_root) -> $(build_root) and copy directory structure
# of source tree but populated with object files.
objects := $(addsuffix $(o_suffix),$(basename $(patsubst $(src_root)%,$(build_root)%,$(sources))))
$(info objects=$(objects))
# Generate rules for every .o file to depend exactly on corresponding source file.
$(foreach s,$(sources),$(foreach o,$(filter %$(basename $(notdir $s)).o,$(objects)),$(info New rule: $o: $s)$(eval $o: $s)))
# This is how we compile sources:
# First check if directory for the target file exists.
# If it doesn't run 'mkdir' command.
$(objects): ; $(if $(wildcard $(#D)),,mkdir -p $(#D) &&) g++ -c $< -o $#
# Compile all sources.
all: $(objects)
clean: ; rm -rf $(build_root)
.PHONY: clean all
Environment:
$ find
.
./src
./src/foo
./src/foo/bar
./src/foo/bar/bar.cxx
./src/foo/bar/buz
./src/foo/bar/buz/buz.c
./src/foo/bar/foo.c
./src/foo/foo.cpp
Run makefile:
$ make -f /cygdrive/c/stackoverflow/Makefile.sample -j
sources=src/foo/bar/bar.cxx src/foo/bar/buz/buz.c src/foo/bar/foo.c src/foo/foo.cpp
objects=build/foo/bar/bar.o build/foo/bar/buz/buz.o build/foo/bar/foo.o build/foo/foo.o
New rule: build/foo/bar/bar.o: src/foo/bar/bar.cxx
New rule: build/foo/bar/buz/buz.o: src/foo/bar/buz/buz.c
New rule: build/foo/bar/foo.o: src/foo/bar/foo.c
New rule: build/foo/foo.o: src/foo/bar/foo.c
New rule: build/foo/bar/foo.o: src/foo/foo.cpp
New rule: build/foo/foo.o: src/foo/foo.cpp
mkdir -p build/foo/bar && g++ -c src/foo/bar/bar.cxx -o build/foo/bar/bar.o
mkdir -p build/foo/bar/buz && g++ -c src/foo/bar/buz/buz.c -o build/foo/bar/buz/buz.o
mkdir -p build/foo/bar && g++ -c src/foo/bar/foo.c -o build/foo/bar/foo.o
mkdir -p build/foo && g++ -c src/foo/bar/foo.c -o build/foo/foo.o
Environment again:
$ find
.
./build
./build/foo
./build/foo/bar
./build/foo/bar/bar.o
./build/foo/bar/buz
./build/foo/bar/buz/buz.o
./build/foo/bar/foo.o
./build/foo/foo.o
./src
./src/foo
./src/foo/bar
./src/foo/bar/bar.cxx
./src/foo/bar/buz
./src/foo/bar/buz/buz.c
./src/foo/bar/foo.c
./src/foo/foo.cpp
Try running this Makefile with 'src_subdirs=' to exercise another approach to locate sources. Output should be the same.
I finally had some time to experiment with this, so here is what I came up with:
BUILD_DIR = build
SRC_DIR = src
SOURCES = $(shell find $(SRC_DIR)/ -name "*.c")
TARGET = program
OBJECTS = $(SOURCES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
default: $(TARGET)
.SECONDEXPANSION:
$(OBJECTS) : $$(patsubst $(BUILD_DIR)/%.o,$(SRC_DIR)/%.c,$$#)
mkdir -p $(#D)
$(CC) -c -o $# $(CFLAGS) $<
$(TARGET): $(OBJECTS)
$(CC) -o $# $(CFLAGS) $^
.PHONY: default
Points of interest:
I had to change the sources find pattern from ".c" to "*.c", I'm not sure if it depends on the exact shell used, but if you want to stay portable, be sure to use a widely accepted pattern.
The .SECONDEXPANSION: is needed to enable the $$ rules for GNU Make. It is needed to allow target based substitution rules in the prerequisites for the $(OBJECTS).
The prerequisite $$(patsubst $(BUILD_DIR)/%.o,$(SRC_DIR)/%.c,$$#) is saying, that the current target depends on a specific source file with the same folder structure and name.
The command mkdir -p $(#D) is ensuring, that the path of the current target is created if it's missing.
If all you want is a single rule to handle all object files, without necessarily needing to "compile all at once" then you could have something like this:
BUILD_DIR = build
SOURCES = ...
TARGET = ...
OBJECTS = $(SOURCES:%.c=$(BUILD_DIR)/%.o)
default: target
target: $(TARGET)
$(TARGET): $(OBJECTS)
$(LD) -o $# $(LDFLAGS) $^ $(LIBS)
$(BUILD_DIR)/%.o: %.c
$(CC) -c -o $# $< $(CFLAGS)
$(BUILD_DIR):
-mkdir $#
[Note: This is written from memory and without testing.]
After reading the GNU make manual again, here is a solution that solves the second problem.
The first attempt was the correct path. And the second attempt has the $(sources) in the prerequisites but does not use it in the commands and this is silly.
So the working makefile follows. It puts object files in a separate directory and it only compiles files that have changed.
sources = $(shell find src/ -name ".c")
$objects_dirs = $(subst src/, build/, $(dir $(sources)) # This variable is used by the build rule to create directories for objects files prior to compilation
objects = $(subst src/, build/, $(patsubst %.c, %.o, $(sources))) # This variable has the paths to the objects files that will be generated in the build directory
# This should now work as expected: object files go into their designated directories under "build/" and only updated files will be recompiled.
$(objects): build $(sources)
# After running say "make clean", make will figure out the need to run the first prerequisite.
# If we are doing a clean build, the number of prerequisites will equal the number of new prerequisites.
ifeq ($(words $?), $(words $^))
# Note the use of "$?" instead of "$^". $? is used since it holds prerequisites that are newer than the target while $^ will holds all prerequisites whether they are new or not.
$(foreach source, $(wordlist 2, $(words $?), $?), $(shell $(cc) $(cflags) -o $(subst src/,build, $(patsubst %.c,%.o, $(source))) $(source)))
else
# If we have a few new targets, no need to exclude "build" from prerequisites because the first prerequisite will be a file that changed.
$(foreach source, $?, $(shell $(cc) $(cflags) -o $(subst src/,build, $(patsubst %.c,%.o, $(source))) $(source)))
endif
.PHONY: build
build:
$(foreach dir, $(objects_dirs), $(shell mkdir -p $(dir)))
.PHONY: clean
clean:
#rm -rf build/
The makefile is heavily commented with changes that made it work. The most important changes were:
Use of $(foreach) to compile each file individually as required by GCC
Use of $? to work only with prerequisites that are newer than the target
Use of conditional to detected whether the first prerequisite has changed depending on circumstances. If we have a clean build (running make for the first time or after running make clean), the number of updated prerequisites will be the same as the number of newer prerequisites compared to the target. In other words $(words $?) == $(words $^) will be true. So we use this fact to exclude the firs prerequisite listed (build in our case) from the list of files to pass to GCC.
Also, when building the executable from the objects files, make sure to use $^ and not $? when selecting prerequisites else you will end up with only newer files in the executable and it will not run.
target = bin/mylib.a
.PHONY: all
all: $(target)
$(target): $(objects)
ar -cvq $# $^ # Notice that we're not using $? else only updated object files will end up in the archive.
My makefile looks like this:
SRCS = $(wildcard *.asm)
OBJS = ${SRCS:.asm=.o}
# define a suffix rule for .asm -> .o
.asm.o : $(SRCS)
nasm -f elf $<
all: $(OBJS)
gcc -o ?? $<
^need the name of the target without file extension here ($* is blank)
However, $* is working within .asm.o but is blank within all.
How would I go about setting the gcc output filename to the filename of the object file without any extension?
For example, I want it to execute the following (after the .o file is generated by nasm)
gcc filename filename.o
I think you are looking for
.PHONY: all
all: $(patsubst %.o,%,$(OBJS))
%: %.o
gcc -o $# $<
Your attempt would define a target all which depended on all the object files as if it contained them all; I presume you really want each object file to be independent, and for the all target to depend on them all being made.
(Technically you could now use $* because it is identical to $# in this case, but that's just obscure.)
This is by and large isomorphic to your existing nasm rule, except when there is no suffix, you cannot use the suffix syntax. In other words, your rule is equivalent to
OBJS = $(patsubst %.asm,%.o,$(SRCS))
%.o: %.asm
nasm -f elf $<
The only remaining difference is the .PHONY declaration which just documents that all isn't a file name.
Use VAR = $(basename your_file.ext) <=> $(VAR) = your_file
Let's say that you want to remove .o from test.o
VAR = $(basename test.o)
resulting in $VAR containing "test"
See More Functions Here
just for quick terminology:
#basic makefile rule
target: dependencies
recipe
The Problem: I want to generate the dependencies automatically.
For example, I am hoping to turn this:
#one of my targets
file.o: file.cpp 1.h 2.h 3.h 4.h 5.h 6.h 7.h 8.h another.h lots.h evenMore.h
$(COMPILE)
Into this:
#one of my targets
file.o: $(GENERATE)
$(COMPILE)
and I'm not too sure if it's possible..
What I do know:
I can use this compiler flag:
g++ -MM file.cpp
and it will return the proper target and dependency.
so from the example, it would return:
file.o: file.cpp 1.h 2.h 3.h 4.h 5.h 6.h 7.h 8.h another.h lots.h evenMore.h
however, 'make' does NOT allow me to explicitly write shell code in the target or dependency section of a rule :(
I know there is a 'make' function called shell
but I can't quite plug this in as dependency and do parsing magic because it relies on the macro $# which represents the target.. or at least I think that’s what the problem is
I've even tried just replacing the "file.cpp" dependency with this makefile function and that won't work either..
#it's suppose to turn the $# (file.o) into file.cpp
THE_CPP := $(addsuffix $(.cpp),$(basename $#))
#one of my targets
file.o: $(THE_CPP) 1.h 2.h 3.h 4.h 5.h 6.h 7.h 8.h another.h lots.h evenMore.h
$(COMPILE)
#this does not work
So all over google, there appear to be two solutions. both of which I don't fully grasp.
From GNU Make Manual
Some Site that says the GNU Make Manual one is out-of-date
So my ultimate question is: Is it possible to do it the way I want to do it,
and if not, can somebody break down the code from one of these sites and explain to me in detail how they work. I'll implement it one of these ways if I have to, but I'm weary to just paste a chunk of code into my makefile before understanding it
Newer versions of GCC have an -MP option which can be used with -MD. I simply added -MP and -MD to the CPPFLAGS variable for my project (I did not write a custom recipe for compiling C++) and added an "-include $(SRC:.cpp=.d)" line.
Using -MD and -MP gives a dependency file which includes both the dependencies (without having to use some weird sed) and dummy targets (so that deleting header files will not cause errors).
To manipulate the filenames when you already know what the dependencies should be, you can use a pattern rule:
file.o: %.o : %.cpp 1.h 2.h 3.h 4.h 5.h 6.h 7.h 8.h another.h lots.h evenMore.h
$(COMPILE)
And you can reuse the rule for other targets:
# Note these two rules without recipes:
file.o: 1.h 2.h 3.h 4.h 5.h 6.h 7.h 8.h another.h lots.h evenMore.h
anotherFile.o: 4.h 9.h yetAnother.h
file.o anotherFile.o: %.o : %.cpp
$(COMPILE)
But if you want Make to figure out the list of dependencies automatically, the best way (that I know of) is Advanced Auto-Dependency Generation. It looks like this:
%.o : %.cc
#g++ -MD -c -o $# $<
#cp $*.d $*.P; \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
rm -f $*.d
-include *.P
Basically, when it builds file.o, it also builds file.d. Then it runs file.d through a bewildering sed command that turns the list of dependencies into a rule with no recipes. The last line is an instruction to include any such rules that exist. The logic here is subtle and ingenious: you don't actually need the dependencies the first time you build foo.o, because Make already knows that foo.o must be built, because it doesn't exist. The next time you run Make, it will use the dependency list it created last time. If you change one of the files so that there is actually a new dependency which is not in the list, Make will still rebuild foo.o because you changed a file which was a dependency. Try it, it really works!
Excellent answers but in my build I put the .obj files in a subdirectory based on build type (ie: debug vs. release). So for example, if I'm building debug, I put all the object files in a build/debug folder. It was a mind-numbing task to try to get the multiline sed command above to use the correct destination folder, but after some experimentation, I stumbled on a solution that works great for my build. Hopefully it'll help someone else as well.
Here's a snippet:
# List my sources
CPP_SOURCES := foo.cpp bar.cpp
# If I'm debugging, change my output location
ifeq (1,$(DEBUG))
OBJ_DIR:=./obj/debug
CXXFLAGS+= -g -DDEBUG -O0 -std=c++0x
else
CXXFLAGS+= -s -O2
OBJ_DIR:=./obj/release
endif
# destination path macro we'll use below
df = $(OBJ_DIR)/$(*F)
# create a list of auto dependencies
AUTODEPS:= $(patsubst %.cpp,$(OBJ_DIR)/%.d,$(CPP_SOURCES))
# include by auto dependencies
-include $(AUTODEPS)
.... other rules
# and last but not least my generic compiler rule
$(OBJ_DIR)/%.o: %.cpp
## Build the dependency file
#$(CXX) -MM -MP -MT $(df).o -MT $(df).d $(CXXFLAGS) $< > $(df).d
## Compile the object file
#echo " C++ : " $< " => " $#
#$(CXX) -c $< $(CXXFLAGS) -o $#
Now for the details:
The first execution of CXX in my generic build rule is the interesting one. Note that I'm not using any "sed" commands. Newer versions of gcc do everything I needed (I'm using gcc 4.7.2).
-MM builds the main dependency rule including project headers but not system headers. If I left it like this, my .obj file would NOT have the correct path. So I use the -MT option to specify the "real" path to my .obj destination. (using the "df" macro I created).
I also use a second -MT option to make sure the resulting dependency file (ie: .d file) has the correct path, and that it is included in the target list and therefor has the same dependencies as the source file.
Last but not least is the inclusion of the -MP option. This tell gcc to also make stubbed rules for each header solving the problem that occurs if I delete a header causing make to generate an error.
I suspect that since I'm using gcc for all the dependency generation instead of piping out to sed, my build is faster (although I've yet to prove that since my build is relatively small at this point). If you see ways I can improve upon this, I'm always open to suggestions. Enjoy
For the record, this is how I generate dependencies automatically now:
CPPFLAGS = -std=c++1y -MD -MP
SRC = $(wildcard *.cpp)
all: main
main: $(SRC:%.cpp=%.o)
g++ $(CPPFLAGS) -o $# $^
-include $(SRC:%.cpp=%.d)
The compiler flags -MD and -MP help do the trick.
First, you can have THE_CPP=$(patsubst %.o,%.cpp,$#)
Then you can run make -p to understand the builtin rules of make
A usual way of doing could be to generate the makefile dependencies into *.md files:
%.o: %.c
$(COMPILE.c) $(OUTPUT_OPTION) $< -MMD -MF $(patsubst %.c,%.md,$#)
and later in your Makefile including them with something like
-include $(wildcard *.md)
But you can also consider using other builders like omake and many many others
WOOO! I did manage to get the code in Beta's post to work on a small test project.
I should note, for anyone else who may come across this,
If you're using the bash shell(which I was), you will need to add an escape character in front of the pound sign to escape from making the rest of the expression a comment. (see 4th line of code)
%.o : %.cpp
g++ -c -MD -o $# $<
cp $*.d $*.P; \
sed -e 's/\#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
rm -f $*.d
-include *.P
Now I want to share information that I found in Managing Projects with GNU Make, 3rd Edition. because it's points out some important issues on this matter, and supplies code that I still don't fully grasp yet.
A method appears in the book that is similar to the method found on the Make manual page.
It looks like this:
include $(subst .c,.d,$(SOURCES))
%.d: %.c
$(CC) -M $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\).o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
This is what I believe is happening.
Right away, 'make' wants to include a ".d" file for every source file.
Because no .d files initially exist, the chunk of code is ran again and again in order to create all the missing .d files.
This means make will start over again and again until every .d file is created and included in the makefile.
Each ".d" file is what Beta said: a target with a set of dependencies and NO recipe.
If a header file is ever changed, those rules that are included in, will need the dependencies updated first. This is what throws me off a bit, how is it that the chunk of code is able to be called again? It is used to update .d files, so if a .h file changes how does it get called? Aside from this, I realize that the default rule is used to compile the object. Any clarifications/misconceptions to this explanation are appreciated.
Later in the book it points out problems with this method, and problems that I believe also exist in the Advanced Auto-Dependency Generation implementation.
Problem 1: It's inefficient. 'make' must restart every time it makes a .d file
Problem 2: make generates warning messages for all the missing .d files- Which is mostly just a nuisance and can be hidden by adding a "-" in front of the include statement.
Problem 3: If you delete a src file because it's no longer needed, 'make' will crash the next time you try to compile because some .d file has the missing src as a dependency, and because there is no rule to recreate that src, make will refuse to go any further.
They say a fix to these issues is Tromey's method, but the code looks very different from the code on the website. Perhaps it's just because they used some macros, made it a function call, and wrote it slightly different. I'm still looking into it, but wanted to share some discoveries I've made so far. Hopefully this opens up a little bit more discussion, and gets me closer to the bottom of all this.
A simple and elegant solution, inclusive of a detailed explanation of how it works, is available here.
DEPDIR := .deps
DEPFLAGS = -MT $# -MMD -MP -MF $(DEPDIR)/$*.d
%.o : %.cpp
%.o : %.cpp $(DEPDIR)/%.d | $(DEPDIR)
g++ -c $(DEPFLAGS) $(CFLAGS) $<
$(DEPDIR): ; #mkdir -p $#
DEPFILES := $(SRCS:%.c=$(DEPDIR)/%.d)
$(DEPFILES):
include $(wildcard $(DEPFILES))
I prefer to use $(shell ...) function with find. Here is a sample of one of my Makefiles:
SRCDIR = src
OBJDIR = obj
LIBDIR = lib
DOCDIR = doc
# Get Only the Internal Structure of Directories from SRCDIR
STRUCTURE := $(shell find $(SRCDIR) -type d)
#Filter-out hidden directories
STRUCTURE := $(filter-out $(shell find $(SRCDIR)/.* -type d),$(STRUCTURE))
# Get All Files From STRUCTURE
CODEFILES := $(addsuffix /*,$(STRUCTURE))
CODEFILES := $(wildcard $(CODEFILES))
## Filter Only Specific Files
SRCFILES := $(filter %.c,$(CODEFILES))
HDRFILES := $(filter %.h,$(CODEFILES))
OBJFILES := $(subst $(SRCDIR),$(OBJDIR),$(SRCFILES:%.c=%.o))
DOCFILES := $(addprefix $(DOCDIR)/, \
$(addsuffix .md, \
$(basename $(SRCFILES))))
# Filter Out Function main for Libraries
LIBDEPS := $(filter-out $(OBJDIR)/main.o,$(OBJFILES))
In this approach, I first get all the internal directory structure, with any depth. Then I get all files inside the Structure. At this time, I can use filter, filter-out, addsuffix, etc, to get exactly what I need at each time.
This example covers *.c files, but you can change it to *.cpp as well.
Building on the content of the Auto-Dependency Generation article referenced in comments on a previous post at I've created an annotated makefile project which includes a generic Makefile annotated with comments and implemented for a simple project with 3 .c files and 2 .h files. See full Makefile content below. Simple projects should be able to just customize the TODO section
# See http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/
# for the template used to start this file
# -- TODO: customize the list below for your project ---
# List of source .c files used with the project
SRCS := main.c file1.c file2.c
# The aplication generated
APPNAME = depend-generation-test
# -- End of customization section ---
# Replace .c extension on SRCS to get objfiles using gnu make pattern rules and substitution references.
# See https://www.gnu.org/software/make/manual/html_node/Pattern-Intro.html#Pattern-Intro for pattern rules and
# https://www.gnu.org/software/make/manual/html_node/Substitution-Refs.html#Substitution-Refs for substitution references overview
OBJFILES := $(SRCS:%.c=%.o)
# Build the app you've specified in APPNAME for the "all" or "default" target
all : $(APPNAME)
default : $(APPNAME)
# Remove all build intermediates and output file
clean : ; #rm -rf $(APPNAME) *.o
# Build the application by running the link step with all objfile inputs
$(APPNAME) : $(OBJFILES)
$(CC) $(LDFLAGS) $^ -o $(APPNAME)
# Add all warnings/errors to cflags default. This is not required but is a best practice
CFLAGS += -Wall -Werror
# The below content is from http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/
# with the following changes:
# 1) Added comments
# 2) Removed TARGET_ARCH from COMPILE.c since it's no longer listed in the [default rules](https://www.gnu.org/software/make/manual/html_node/Catalogue-of-Rules.html#Catalogue-of-Rules) and [isn't documented](https://lists.gnu.org/archive/html/help-make/2010-06/msg00005.html)
# Original content below is:
# Copyright © 1997-2019 Paul D. Smith Verbatim copying and distribution is permitted in any medium, provided this notice is preserved.
# The directory (hidden) where dependency files will be stored
DEPDIR := .deps
# Flags passed to gcc to automatically build dependencies when compiling
# See https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html for detail about variable names
# $# references the target file of the rule and will be "main.o" when compiling "main.c"
# $* references the stem of the rule, and will be "main" when target is "main.o"
DEPFLAGS = -MT $# -MMD -MP -MF $(DEPDIR)/$*.d
# Rules for compiling a C file, including DEPFLAGS along with Implicit GCC variables.
# See https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html
# and see https://www.gnu.org/software/make/manual/html_node/Catalogue-of-Rules.html#Catalogue-of-Rules
# for the default c rule
COMPILE.c = $(CC) $(DEPFLAGS) $(CFLAGS) $(CPPFLAGS) -c
# Delete the built-in rules for building object files from .c files
%.o : %.c
# Define a rule to build object files based on .c or dependency files by making the associated dependency file
# a prerequisite of the target. Make the DEPDIR an order only prerequisite of the target, so it will be created when needed, meaning
# the targets won't get rebuilt when the timestamp on DEPDIR changes
# See https://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html for order only prerequesites overview.
%.o : %.c $(DEPDIR)/%.d | $(DEPDIR)
$(COMPILE.c) $(OUTPUT_OPTION) $<
# Create the DEPDIR when it doesn't exist
$(DEPDIR): ; #mkdir -p $#
# Use pattern rules to build a list of DEPFILES
DEPFILES := $(SRCS:%.c=$(DEPDIR)/%.d)
# Mention each of the dependency files as a target, so make won't fail if the file doesn't exist
$(DEPFILES):
# Include all dependency files which exist, to include the relevant targets.
# See https://www.gnu.org/software/make/manual/html_node/Wildcard-Function.html for wildcard function documentation
include $(wildcard $(DEPFILES))