I have a makefile like this:
default: exe
%.obj: %.src
# dummy compiler
#echo link $< to $#
cat $< > $#
exe: main.obj foo.obj bar.obj
# dummy linker
#echo link $^ to $#
cat $^ > $#
main.obj: main.src
foo.obj: /some/dir/1/foo.src
bar.obj: /some/dir/2/bar.src
Make can't compile foo.obj and bar.obj (and 20+ other objects), because it does not use the "%.obj: %.src" rule. The directories of foo.obj and foo.src resp. bar.obj and bar.src do not match, so the rule does not match.
Is there a way to specify a rule that ignores the directory part of the filenames?
Update:
To make that Makefile work, I copied the compiler lines from the pattern rule to the foo.obj and bar.obj rules (and the 20+ other object rules). That's anything but clean and maintainable. Essentially, I need a pattern rule that ignores the source and object directories when comparing.
I know of no such features (excepted macros, you could arrange for them to generate the makefile fragments you are writing manually). But GNU Make has a vpath feature which allows to specify a path where to look for files of a given extension and which interact with the automatic variables to make something close to what you want.
Your Makefile can be then written as:
default: exe
vpath %.src some/dir/1:some/dir/2
%.obj: %.src
# dummy compiler
#echo compiling $< to $#
cat $< > $#
exe: main.obj foo.obj bar.obj
# dummy linker
#echo linking $^ to $#
cat $^ > $#
Note that this is not exactly what you want: if there is a bar.src in both some/dir/1 and some/dir/2, the one from some/dir/1 will be used.
You can make a variable of all .src files in all subdirectories with $(shell find . -name '*.src'). Here's an example:
OBJS := $(shell find . -name '*.src')
default: exe
%.obj: %.src
#echo link $< to $#
cat $< > $#
exe: $(OBJS)
#echo link $^ to $#
cat $^ > $#
The macro way of doing this would be as follows:
define mymacro
$1: $2
#echo compiling $$< to $$#
cat $$< > $$#
endef
$(eval $(call mymacro,foo.obj,/some/dir/1/foo.src))
$(eval $(call mymacro,bar.obj,/some/dir/2/bar.src))
But be aware that macros make the makefile less maintainable (as it's harder to read, and introduces some sharp sticks inexperienced users might trip on). It also works on GNU make, but may fail on some other make systems.
I have written a build system which uses gmtt and which relies on explicit source elicitation. At the core is a beefed up version of wildcard named wildcard-rec which supports recursive descent akin to ** in other extended wildcard matchers (like git) - maybe it fits your taste and use case:
include gmtt.mk
default: exe
SOURCE_LOCATOR := $(call wildcard-rec,main.src some/dir/**/3/*.src some/**/1/foo.src some/dir/2/bar.src)
$(info Compiling these sources: $(SOURCE_LOCATOR))
OBJECTS := $(addsuffix .obj,$(basename $(notdir $(SOURCE_LOCATOR))))
$(info Building these objects: $(OBJECTS))
# Generate the source prerequisite for each object
TGT-PREREQ := $(join $(addsuffix :,$(OBJECTS)),$(SOURCE_LOCATOR))
# Introduce them as targets via eval:
$(foreach tp,$(TGT-PREREQ),$(info $(tp))$(eval $(tp)))
$(OBJECTS):
#echo compile $< to $#
exe: $(OBJECTS)
#echo link $^ to $#
Test:
Compiling these sources: main.src some/dir/foo/3/a.src some/dir/foo/3/b.src some/dir/bar/1/foo.src some/dir/2/bar.src
Building these objects: main.obj a.obj b.obj foo.obj bar.obj
main.obj:main.src
a.obj:some/dir/foo/3/a.src
b.obj:some/dir/foo/3/b.src
foo.obj:some/dir/bar/1/foo.src
bar.obj:some/dir/2/bar.src
compile main.src to main.obj
compile some/dir/foo/3/a.src to a.obj
compile some/dir/foo/3/b.src to b.obj
compile some/dir/bar/1/foo.src to foo.obj
compile some/dir/2/bar.src to bar.obj
link main.obj a.obj b.obj foo.obj bar.obj to exe
Related
In an effort to replace the mess of independent makefiles we inherited from another project with something that actually uses make as it should be (as noted in this question, I've come across a rather unusual situation in which gmake 3.81 ignores files it cannot generate nor can find.
Here's a short sample file that demonstrates the problem:
# Remove ALL default rules
.SUFFIXES:
(%): %
%.out: %
%.c: %.w %.ch
%.tex: %.w %.ch
%:: %.v
%:: RCS/%,v
%:: RCS/%
%:: s.%
%:: SCCS/s.%
SOURCES = a.c b.c
OBJS = $(SOURCES:%.c=%.o)
DEPFILES = $(SOURCES:%.c=%.c.d)
EXE = a
.PHONY: all
all: $(EXE)
$(DEPFILES): %.c.d : %.c
#echo "Determining dependencies for $(<F)"
#$(CC) -E -MM -MF$# -MP $<
$(OBJS): %.o: %.c
#echo "Compiling $(<F)"
#$(CC) -c $< -o $#
$(EXE): $(OBJS)
#echo "Linking $(#F)"
#$(CC) $+ -o $#
# This seems to be the troublemaking line!
-include $(DEPFILES)
If one or more of the source files is missing, the corresponding .d file is not made, as expected, but the source file is not flagged as missing. If I run this with a simple make command, nothing is output, and the exit status is 2.
Is there any way I can work around this?
Oh, although it seems silly in this example, I do have several restrictions in this project:
We must use gmake 3.81. No upgrading or patching allowed.
The full makefile builds both a debug & a release version, so dependencies are generated separately, once for all. It turned out to be simpler that way.
Using static pattern rules seems silly here, but in the large makefile it solves many problems.
The actual generation of dependencies is significantly more complex in the real system, using a Perl script I wrote to massage the equivalent output of the Intel compiler suite (again, a requirement) into something useful.
I've thought about pre-testing the existence of every file, but not all of them are known until the dependency files are generated. As it stands, with just this one file and nothing else in a directory, no shell commands get executed.
This appears to be a bug in gmake 3.81 and later, related to this bug. I've reported this specific bug, as it is slightly different.
The workaround I've chosen to use is inspired by the above link, is noted below:
# Remove ALL default rules
.SUFFIXES:
(%): %
%.out: %
%.c: %.w %.ch
%.tex: %.w %.ch
%:: %.v
%:: RCS/%,v
%:: RCS/%
%:: s.%
%:: SCCS/s.%
SOURCES = a.c b.c
# WORKAROUND: check for existence of files here
EXISTING_SOURCES = $(wildcard $(SOURCES))
MISSING_SOURCES = $(filter-out $(EXISTING_SOURCES),$(SOURCES))
ifneq "" "$(MISSING_SOURCES)"
$(error Missing source files: $(MISSING_SOURCES))
endif
# END WORKAROUND
OBJS = $(SOURCES:%.c=%.o)
DEPFILES = $(SOURCES:%.c=%.c.d)
EXE = a
.PHONY: all
all: $(EXE)
$(DEPFILES): %.c.d : %.c
#echo "Determining dependencies for $(<F)"
#$(CC) -E -MM -MF$# -MP $<
$(OBJS): %.o: %.c
#echo "Compiling $(<F)"
#$(CC) -c $< -o $#
$(EXE): $(OBJS)
#echo "Linking $(#F)"
#$(CC) $+ -o $#
# This seems to be the troublemaking line!
-include $(DEPFILES)
I have two files: assign1.c and ports.h.
FYI: I am using avr-gcc.
I built the following makefile, which I also use for another project (and other TARGET) where it works fine.
TARGET = assign2
LIB=
INCLUDE=ports.h
CFLAGS =-mmcu=atmega32 -Wall
CC = avr-gcc
SRC= $(TARGET).c
OBJ= $(SRC:.c=.o)
OBJCOPY = avr-objcopy
FORMAT = ihex
MSG_COMPILING = Compiling:
MSG_LINKING = Linking:
MSG_FLASH = Creating load file for flash:
all:elf hex
elf: $(TARGET).elf
hex: $(TARGET).hex
%.hex: %.elf
#echo $(MSG_FLASH) $#
#echo
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $#
$(RM) *.elf $(TARGET)
#echo
%.elf: $(OBJ) $(LIB)
#echo $(MSG_LINKING) $#
#echo
$(CC) $(CFLAGS) $^ -o $#
#echo
%.o: $(SRC) $(INCLUDE)
#echo $(MSG_COMPILING) $<
#echo
$(CC) $(CFLAGS) -c $<
#echo
.PHONY : clean
clean:
$(RM) *.o *.hex *.elf $(TARGET)
The terminal prints the following output.
C:\Project>make
Compiling: assign2.c
avr-gcc -mmcu=atmega32 -Wall -c assign2.c
In file included from assign2.c:8:
c:/winavr-20100110/lib/gcc/../../avr/include/util/delay.h:90:3: warning: #warnin
g "Compiler optimizations disabled; functions from <util/delay.h> won't work as
designed"
Linking: assign2.elf
avr-gcc -mmcu=atmega32 -Wall assign2.o -o assign2.elf
Compiling: assign2.c
avr-gcc -mmcu=atmega32 -Wall -c assign2.c
In file included from assign.c:8:
c:/winavr-20100110/lib/gcc/../../avr/include/util/delay.h:90:3: warning: #warnin
g "Compiler optimizations disabled; functions from <util/delay.h> won't work as
designed"
avr-gcc elf.o assign2.elf -o elf
avr-gcc: elf.o: No such file or directory
make: *** [elf] Error 1
rm assign2.o
C:\Project>
For some reason it seems to compile the first file, a second time and doing so crashes.
Can anyone correct me on my errors?
The problem is your pattern rules. You are writing pattern rules like this (after make expands the variables):
%.o: assign2.c ports.h
What this rule tells make is that ANY target it wants to build that matches the %.o pattern, can be built by compiling assign2.c. That's obviously not true: this rule build exactly one target: assign2.o.
So make reads your makefile and wants to build a file named elf. It sees that elf depends on $(TARGET).elf, so it builds that (that's the first compile and link, that works). Then make wants to build elf itself. You haven't declared it to be .PHONY, so make assumes it might be a real target.
Make looks through its built-in rules to find one that will let it build elf, and it finds a built-in rule: % : %.o which it can use to compile a program from a .o file with the same prefix. So now for target elf make wants to try to build a file elf.o. Oho! It sees there's a pattern rule that lets it build any .o file based on the assign2.c source file, so it runs that rule (that's the second compile) expecting it to build elf.o... which it doesn't, obviously.
Then make runs the built-in link recipe, using elf.o which doesn't exist, and fails.
The solution to your problem is two things:
First, you should always declare all your makefile targets that you don't actually want to build as .PHONY so make won't try to build them:
.PHONY: all elf hex
Second, you should never use pattern rules where the prerequisite is not also a pattern (this can be useful in certain very specific situations, but not in general). You should either change those pattern rules to explicit rules:
assign2.elf: $(OBJ) $(LIB)
...
$(OBJ): $(SRC) $(INCLUDE)
...
Or make them into full pattern rules by using the pattern in the prerequisites list as well:
%.elf : %.obj $(LIB)
...
%.o: %.c $(INCLUDE)
...
I'm having troubles with my Makefile :-(
I have a mix of assembly and C sourcecode that I need to link together. I need different build-instructions for those two types. Since both the assembler and C compiler output *.o files, I cannot use the general %.o:%.c construction often found in example Makefiles
This what I'm trying now:
Get a list of all C files and their resulting output files:
C_SRCFILES := $(shell find $(SRCDIRS) -type -f -name "*.c")
C_OBJFILES := $(patsub %.c,%.o,$(C_SRCFILES))
Get a list of all asm files and their resulting output files:
A_SRCFILES := $(shell find $(SRCDIRS) -type -f -name "*.asm")
A_OBJFILES := $(patsub %.asm,%.o,$(A_SRCFILES))
When I echo those vars to the screen, they seem to be correct, but how I do define my targets now?
I tried something like this
$(A_OBJFILES): ($A_SRCFILES)
$(AS) $(AFLAGS) -o $# $*
$(C_OBJFILES): ($C_SRCFILES)
$(CC) $(CFLAGS) -c -o $# $*
all: $(A_OBJFILES) $(C_OBJFILES)
$(LD) $(LDFLAGS) $(A_OBJFILES) $(C_OBJFILES) -o $(TARGET_OUTPUT)
but ofcourse, this doesn't work...
Any suggestions?
First problem: a misplaced parenthesis or two.
$(A_OBJFILES): ($A_SRCFILES)
Notice that you have the $ inside the ( in ($A_SRCFILES). Make expands $A, which is nothing, and things go downhill. I think you meant $(A_SRCFILES), and the same thing in the other rule.
Second problem: I don't know the syntax of the assembler, but the syntax of the compiler command is wrong:
$(CC) $(CFLAGS) -c -o $# $*
The variable $* is nothing if we're not in a pattern rule, which we're not (yet). And anyway, if we were in a pattern rule and you were trying to build foo.o, this command would look for the source file foo, and there's no such file. Do it this way:
$(CC) $(CFLAGS) -c -o $# $<
Third problem: each object file depends on all source files (in each rule). Try this instead:
$(A_OBJFILES): %.o : %.asm
...
$(C_OBJFILES): %.o : %.c
...
(Now it's a pattern rule.)
Fourth problem: a lot of redundancy in the last rule. Change it to this:
all: $(A_OBJFILES) $(C_OBJFILES)
$(LD) $(LDFLAGS) $^ -o $(TARGET_OUTPUT)
or better still:
all: $(TARGET_OUTPUT)
$(TARGET_OUTPUT): $(A_OBJFILES) $(C_OBJFILES)
$(LD) $(LDFLAGS) $^ -o $#
Since both the assembler and C compiler output *.o files, I cannot use the general %.o:%.c construction often found in example Makefiles
Sure you can:
%.o : %.c
# commands to make .o from a corresponding .c
%.o : %.asm
# commands to make .o from a corresponding .asm
I want to write a lot of tiny example programmes for one same library, each needs gcc $(OtherOpt) -o xxx -lthelibname xxx.c.
How to write a Makefile without dozens of tagret lines ?
Pattern rules are your friend for these situations. As long as your targets all match a predictable pattern -- and they do in this case, as they are all of the form "create foo from foo.c" -- you can write a single pattern rule that will be used for all of the targets:
OtherOpt=-Wall -g
all: $(patsubst %.c,%,$(wildcard *.c))
%: %.c
gcc $(OtherOpt) -o $# -lthelibname $<
Now you can either run simply make to build all your apps, or make appname to build a specific app. Here I've created a single pattern rule that will be used anytime you want to create something from something.c. I used the $# automatic variable, which will expand to the name of the output, and the $< variable, which will expand to the name of the first prerequisite, so that the command-line is correct regardless of the specific app being built. Technically you don't need the all line, but I figured you probably didn't want to always have to type in the name(s) of the apps you want to build.
Also, technically you can probably get away without having any of this makefile, because GNU make already has a built-in pattern rule for the %: %.c relationship! I mention this option only for completeness; personally, I prefer doing things the way I've shown here because it's a little bit more explicit what's going on.
%.o: %.c
gcc $(OtherOpt) -c -o $# -lthelibname $<
That compiles all .c files to their .o files (object code) of the same base name. Then in your actual target(s), you would include all necessary .o files as dependencies and use gcc $(OtherOpt) -o $# $^ -lthelibname, assuming I'm not misunderstanding how your build is set up.
Some versions of make also support the suffix rule .c.o to be ALMOST the same thing as %.o: %.c, but the suffix rules can't have any dependencies. Writing .c.o: foo.h tells make to compile "foo.h" to "foo.c.o" rather than requiring "foo.h" as a dependency of any file with a .c suffix as %.o: %.c foo.h would correctly do.
I learnd from http://sourceforge.net/projects/gcmakefile/
LDLIB = -lpthread
LDFLAGS = -Wl,-O1 -Wl,--sort-common -Wl,--enable-new-dtags -Wl,--hash-style=both $(LDLIB)
SRCDIRS =
SRCEXTS = .c .C .cc .cpp .CPP .c++ .cxx .cp
CFLAGS = -pipe -march=core2 -mtune=generic -Wfloat-equal \
#-Wall -pedantic
ifeq ($(SRCDIRS),)
SRCDIRS = .
endif
SOURCES = $(foreach d,$(SRCDIRS),$(wildcard $(addprefix $(d)/*,$(SRCEXTS))))
TARGET = $(addprefix bin/,$(basename $(SOURCES)))
all: $(TARGET)
ls -l $(TARGET)
bin/%: %.c dir
gcc $(CFLAGS) $(LDFLAGS) -o $# $<
dir:
#-mkdir bin
.PHONY : clean
clean:
-rm $(TARGET)
-rmdir bin
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