depending on directories in make [duplicate] - makefile

This question already has answers here:
how to prevent "directory already exists error" in a makefile when using mkdir
(12 answers)
Closed 9 years ago.
This is a followup to my earlier question: SO 4403861 because the suggested solutions broke the dependencies, making the makefile useless. I can't figure out why.
I am using gnu make 3.82
I have a rule that works if the obj directory has been created:
objdir:=../obj
$(objdir)/%.o: %.C
$(COMPILE) -MM -MT$(objdir)/$(notdir $#) $< -o $(DEPDIR)/$(notdir $(basename $<).d )
$(COMPILE) -o $(objdir)/$(notdir $# ) -c $<
However, if the obj directory isn't there, make fails. I wanted make to automatically create ../obj on demand, so I added what I thought was very simple:
$(objdir)/%.o: %.C $(objdir)
$(COMPILE) -MM -MT$(objdir)/$(notdir $#) $< -o $(DEPDIR)/$(notdir $(basename $<).d )
$(COMPILE) -o $(objdir)/$(notdir $# ) -c $<
$(objdir):
if [ ! -d $(objdir) ] ; then mkdir $(objdir) ; fi
When I do so, make always forces the compile, every time. Why? The mkdir should not happen unless there is no directory? Why are dependencies destroyed by this simple change?

You also can try with Order-only prerequisites.
There is a similar example, of your question, available.
OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)
$(OBJDIR)/%.o : %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
all: $(OBJS)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
mkdir $(OBJDIR)

As others have said, the problem is that a directory is considered "changed" whenever directory members are added or removed, so make sees your output directory changing all the time, and reruns all the compilations which you have told it depend on the output directory.
As an alternative to the workarounds described by others, recent GNU make versions have support for "order-only prerequisites". The description of order-only prerequisites in the manual includes an example of how to use them for directory creation.

Some sort of sentinel file will solve this quite nicely. Allows you to write a single pattern rule to create all folders, does not have any rogue recompilation issues, and is -j safe.
OBJDIR := objdir/
OBJS := $(addprefix ${OBJDIR},foo.o bar.o baz.o)
all: ${OBJS}
${OBJDIR}%.o : %.c ${OBJDIR}.sentinel
${COMPILE.c} ${OUTPUT_OPTION} $<
# A single pattern rule will create all appropriate folders as required
.PRECIOUS: %/.sentinel # otherwise make (annoyingly) deletes it
%/.sentinel:
mkdir -p ${#D}
touch $#

As answered already, you cannot put a directory with output files as a dependency, because it is updated every time.
One solution (stated above) is to put a mkdir -p before each build, like this:
objdir:=../obj
$(objdir)/%.o: %.C
#mkdir -p $(objdir) $(DEPDIR) ...
$(COMPILE) -MM -MT$(objdir)/$(notdir $#) $< -o $(DEPDIR)/$(notdir $(basename $<).d )
$(COMPILE) -o $(objdir)/$(notdir $# ) -c $<
But I don't love this solution, because it forces running an extra process lots and lots of times. However, knowing the reason for the error, there is another way:
exe: dirs $(OBJ)
In the primary target, the one building the executable, just insert a target dirs before the objects. Since it's hit in order:
dirs:
#mkdir -p $(objdir) $(DESTDIR) ...
and this is only done once for the entire build, rather than once per file.

Related

Makefile Syntax unclear

This is my first Makefile, and I am can't figure out some of the syntax used. The questions are marked below.
$(BUILD_DIR)/%.o: %.c $(BUILD_DIR)
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $#
What is the usage of "$(BUILD_DIR)" in the dependency?
What is the meaning of "$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $#" in the role?
As with most computer languages the syntax of make cannot be clear if you don't know it. If you are using GNU make the GNU make manual is your friend. In the following explanations I will assume that BUILD_DIR = build and that one of the source files is bar/foo.c.
$(BUILD_DIR) in the list of prerequisites (dependencies) tells make that the build directory (in which object files are supposed to go) must exist before the recipe is executed; logical. There must be another rule somewhere to create the directory if it does not exist yet. Something like:
$(BUILD_DIR):
mkdir -p $#
But unless you forgot to copy an important character, this dependency is terribly sub-optimal. As the last modification time of a directory changes each time its content changes (files or sub-directories added or removed), it will force the re-compilation of all source files every time the directory changes, which is not what you want. A better dependency would be order-only:
$(BUILD_DIR)/%.o: %.c | $(BUILD_DIR)
that tells make to consider only the existence of $(BUILD_DIR), not its last modification time, when deciding to re-build or not.
$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $# is just a combination of make automatic variables and functions.
$< and $# expand as the first prerequisite (bar/foo.c) and the target (build/bar/foo.o) respectively.
$(<:.c=.lst) replaces .c by .lst in $<: bar/foo.lst.
$(notdir $(<:.c=.lst)) removes the directory part: foo.lst.
All in all, for a bar/foo.c source file, and with BUILD_DIR = build, the pattern rule would be equivalent to:
build/bar/foo.o: bar/foo.c | build
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=build/foo.lst bar/foo.c -o build/bar/foo.o
Note that there are two different situations to consider:
All your source files are in the same directory as the Makefile (no bar/foo.c, just foo.c). Then you can simplify your recipe:
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(<:.c=.lst) $< -o $#
because the $(notdir...) is useless.
Your source files can be in sub-directories (bar/foo.c). Then you need the $(notdir...) in your recipe. But be warned that if you have two source files with the same base name (bar/foo.c and baz/foo.c) you will have a name conflict for $(BUILD_DIR)/foo.lst and your Makefile will not work as expected. Moreover, the order-only prerequisite of the rule should be equivalent to build/bar (or build/baz), not just build. And there should be a rule to create it if needed. If it is your case I suggest to change your pattern rule for:
$(BUILD_DIR)/%.o: %.c
mkdir -p $(dir $#)
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $#
There are other solutions (secondary expansion...) but there are a bit too complicated for this already too long answer.

Makefile - link input file from folder

I try to compile a project with generated object stored in a sub directory :
myproject:
|
src: .cpp, .cpp ...
|
release: .o, .o ...
Here's a part of Makefile:
SRC ?= src
OBJ_PATH = $(SRC)/Release
vpath %.o $(OBJ_PATH)
...
OBJS := $(addprefix $(OBJ_PATH)/,obj1.o obj2.o )
all: build
obj1.o: $(SRC)/Manager.cpp
$(EXEC) $(CC) $(INCLUDES) $(CCFLAGS) $(GNCD_FLGS) -c $(<) -o $(OBJ_PATH)/$# #-o $# -c $<
obj2.o: $(SRC)/Synth.cpp
$(EXEC) $(CC) $(INCLUDES) $(CCFLAGS) $(GNCD_FLGS) $(DEFS) -c $(<) -o $(OBJ_PATH)/$# #-o $# -c $<
myApp: obj1.o obj2.o
$(EXEC) $(CC) $(LDFLAGS) $(GNCD_FLGS) -o $# $(OBJS) $+ $(LIBS)
$(EXEC) mkdir -p $(OBJ_PATH)/$(TRGT_ARCH)/$(TRGT_OS)/$(BLD_TP)
$(EXEC) cp $# $(OBJ_PATH)/$(TRGT_ARCH)/$(TRGT_OS)/$(BLD_TP)
$(OBJECTS) : Stt.h
build: myApp
run: build
$(EXEC) ./myApp
..but i got an error link:
Could not open input file 'obj1.o'
Makefile:86: recipe for target 'myApp' failed
So it seems couldn't find object in src/Release dir;
any ideas ?
thank's
Your recipe for myApp use $+, which list the prerequisites. It expands in obj1.o obj2.o. But you build obj1.o and obj2.o in $(OBJ_PATH). So the linker try to find the objects in the root directory, but cannot find them, since they are in $(OBJ_PATH).
Since your recipe explicitely lists them (with $(OBJS)), you do not need the automatic variable.
Sidenote
According to Paul's Second rule of Makefiles, it is best that every rule updates a file corresponding exactly to the target name (including the path part) (in other words, always use $# in the recipe), in order to always know which is the exact file updated.
In your case, if you want to build the objects files in OBJ_PATH, you could use a rule of the form $(OBJ_PATH)/obj.o for each.
You could also replace the dependency of myApp by $(OBJS), and use the automatic variable (btw, is there a reason why you prefer $+ over $^ (does the same thing but do not conserv duplicates in the prerequisites list) ?).

Makefile: source files in a particular directory

What do I need to do if I want to compile several files (e.g. a.f90, b.f90, c.f90) in a given directory (say, MYDIR)?
My Makefile code is something like:
CC=gfortran
CFLAG=-g
HOME=MYDIR
SRC=$(HOME)/(a.f90,b.f90,c.f90)
OBJ=$(SRC:,=.o)
EXE=test.x
%.o: %.f90
$(CC) $(CFLAG) -c -o $# $<
$(EXE): $(OBJ)
$(CC) -o $# $^ $(CFLAG)
clean:
rm -f *.o
I think, the 4-th line is not correct. So what could be the replacement?
Another thought: Can I use a wildcard if I want to compile all .f90 file inside MYDIR?
There are lots of ways to do it. You can do something like:
SRC = $(addprefix $(HOME)/,a.f90 b.f90 c.f90)
Also your assignment of OBJ is wrong; there's no comma needed after the colon.
Yes you can use wildcard if you want.

Makefile as a dependency for a make target

Is it ever a bad idea to include a Makefile as a dependency for a make target?
Eg.
hello.o: hello.cxx Makefile
$(CXX) -c $(CFLAGS) $< -o $#
That way anytime the Makefile is modified the target is recompiled.
No its not a bad idea. Conventionally we never do that but if you have makefile calling other makefile then including it would be a great idea though.
I believe what you're trying to do is run clean (or other equivalent target) whenever the Makefile gets modified.
This can be achieved so. (I've been using this recipe in couple of my C/C++ projects).
CLEANUP_TRIGGER := .makefile
BASE_MAKEFILE := $(firstword $(MAKEFILE_LIST))
FINAL_TARGET := hello.o
all: $(CLEANUP_TRIGGER) $(FINAL_TARGET)
hello.o : hello.c
$(CXX) -c $(CFLAGS) $< -o $#
$(CLEANUP_TRIGGER): $(BASE_MAKEFILE)
if [ -f $(CLEANUP_TRIGGER) ]; then $(MAKE) clean; fi
touch $#
clean:
rm -rf *.o
rm -f $(CLEANUP_TRIGGER)
.PHONY: all clean
The essence is to make sure CLEANUP_TRIGGER is part of the rules which get invoked commonly, run make clean whenever Makefile is newer than CLEANUP_TRIGGER.

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

Resources