Automatic variable doesn't loop through source files - makefile

My makefile builds every object from the first source file
SRCS := srcs/foo/a.c srcs/foo/b.c srcs/bar/c.c srcs/bar/d.c
OBJS := bin/a.o bin/b.o bin/c.o bin/d.o
$(OBJS) : $(SRCS)
gcc -c $< -o $#
Outputs:
gcc -c srcs/foo/a.c -o bin/a.o
gcc -c srcs/foo/a.c -o bin/b.o
gcc -c srcs/foo/a.c -o bin/c.o
gcc -c srcs/foo/a.c -o bin/d.o

This:
$(OBJS) : $(SRCS)
expands to this:
bin/a.o bin/b.o bin/c.o bin/d.o : srcs/foo/a.c srcs/foo/b.c srcs/bar/c.c srcs/bar/d.c
which is interpreted by make the same way as this:
bin/a.o : srcs/foo/a.c srcs/foo/b.c srcs/bar/c.c srcs/bar/d.c
bin/b.o : srcs/foo/a.c srcs/foo/b.c srcs/bar/c.c srcs/bar/d.c
bin/c.o : srcs/foo/a.c srcs/foo/b.c srcs/bar/c.c srcs/bar/d.c
bin/d.o : srcs/foo/a.c srcs/foo/b.c srcs/bar/c.c srcs/bar/d.c
so for every object file the list of source files is the same, and so the first source file (what $< expands to) is always the same file.
Make is not going to go through the targets and prerequisites and "match them up" one to one, somehow. That's not how it works, and such a thing would not be feasible anyway.
This is why pattern rules and VPATH were invented:
VPATH = srcs/foo srcs/bar
bin/%.o : %.c
gcc -c $< -o $#
Of course, this is quite dangerous since if you ever have the same source filename in two different directories, you'll get conflicts in the object files. Most people don't do this: they replicate the source directory in the object directory (so you'd have obj/foo/a.o and obj/bar/c.o). If you do that you don't need VPATH, you can just use:
bin/%.o : src/%.c
gcc -c $< -o $#
Maybe with a #mkdir -p $(#D) thrown in there to create the directories first.

Related

Makefile relinks everytime

I can't figure out why my Makefile relinks every time. Could someone explain to me?
Here is my Makefile :
SRCS = ${wildcard ./srcs/*.c}
OBJS = ${SRCS:.c=.o}
INCL = includes
CC = gcc
CFLAGS = -Wall -Wextra -Werror
NAME = BSQ
.c.o :
${CC} -I ${INCL} ${CFLAGS} -c $< -o ${<:.c=.o}
all : ${OBJS}
${CC} -o ${NAME} ${OBJS}
clean :
rm -f ${OBJS}
fclean : clean
rm -f ${NAME}
re : fclean all
Because the all target doesn't create a file named all, so make doesn't know that it has already been done.
You should make all depend on ${NAME}, and then add a target for ${NAME} that performs the linking.
all: ${NAME}
${NAME}: ${OBJS}
${CC} -o $# $^

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 wildcard rules for multiple file extensions

I have a number of assembly and C source files in a directory. I have mentioned a list of files to be compiled as C_OBJFILES and ASM_OBJFILES. I have added the rules as
%.o: %.S
$(AS) $(ASFLAGS) -o $# $<
%.o: %.c
$(CC) $(CFLAGS) -o $# $<
for generating the object files. Some of the assembly files has .s extension. Some has .S and remaining .asm. Is there a way to specify these different extensions in a single rule instead of separate %.o:%.asm and %.o:%.s?
Although it can be solved by a simple prename before make, I would like to explore the options with Makefile. Below is the complete Makefile I have written.
ASM_OBJLIST:=startup.o vectors.o lowlevel.o
C_OBJLIST:=test.o
LD_SCRIPT:=test.ld
CROSS_COMPILE:=arm-none-eabi-
AS:=$(CROSS_COMPILE)as
CC:=$(CROSS_COMPILE)gcc
LD:=$(CROSS_COMPILE)ld
OBJCOPY:=$(CROSS_COMPILE)objcopy
CFLAGS:= -c -mcpu=arm926ej-s -g
ASFLAGS:= -mcpu=arm926ej-s -g
BIN_TARGET:=test.bin
$(BIN_TARGET): $(C_OBJLIST) $(ASM_OBJLIST)
$(LD) -T $(LD_SCRIPT) -o $#.elf $^
$(OBJCOPY) -O binary $#.elf $#
%.o: %.S
$(AS) $(ASFLAGS) -o $# $<
%.o: %.c
$(CC) $(CFLAGS) -o $# $<
clean:
rm -f *.o *.elf *.bin
If handling multiple extensions in a single rule is possible, I can just use gcc for all source files instead of bothering to use as at all. (I guess)
Use static patterns and split the objects into two sets, there are a number of other improvements too
Make already has defaults for things like AS and CC, use them.
You're already using ASFLAGS and CFLAGS correctly (except for -c, see below), use the same pattern for other flags too
You missed a chance to express the bin->elf dependency
You can recycle the built-in recipes even if you need to redefine the rules (LINK.o, COMPILE.c which already has the -c flag), although the .c rule is currently superfluous as it's exactly the same as the built-in one.
clean should be PHONY
Never delete stuff with *, explicitly delete only the files you are responsible for.
I'd just use GCC to link but if you need to link with LD then you'll need to change the recipe.
ASM_OBJLIST := startup.o
S_OBLIST := vectors.o lowlevel.o
C_OBJLIST := test.o
LD_SCRIPT := test.ld
CROSS_COMPILE := arm-none-eabi-
AS := $(CROSS_COMPILE)$(AS)
CC := $(CROSS_COMPILE)$(CC)
OBJCOPY := $(CROSS_COMPILE)objcopy
CFLAGS := -mcpu=arm926ej-s -g
ASFLAGS := -mcpu=arm926ej-s -g
LDFLAGS := -Wl,-T $(LD_SCRIPT)
OBJFLAGS := -O binary
BIN_TARGET := test.bin
$(BIN_TARGET): $(BIN_TARGET).elf
$(OBJCOPY) $(OBJFLAGS) $< $#
$(BIN_TARGET).elf: $(C_OBJLIST) $(ASM_OBJLIST)
$(LINK.o) $^ $(LDLIBS) -o $#
$(ASM_OBJLIST): %.o: %.asm
$(S_OBJLIST): %.o: %.S
$(ASM_OBJLIST) $(S_OBJLIST):
$(COMPILE.S) -o $# $<
%.o: %.c
$(COMPILE.c) -o $# $<
.PHONY: clean
clean:
$(RM) $(C_OBJLIST) $(ASM_OBJLIST) $(BIN_TARGET).elf $(BIN_TARGET)

makefile automatic variable for corresponding c file

i hava a makefile something like this:
outdir = release
allsrc = aaa/a.c bbb/b.c ccc/c.c
allobjs = $(addprefix $(outdir), $(notdir $(allsrc:.c=.o))
...
test: $(allobjs)
$(allobjs): $(allsrc)
gcc -c -o $# $<
make test performs:
gcc -c -o release/a.o aaa/a.c
gcc -c -o release/b.o aaa/a.c
gcc -c -o release/c.o aaa/a.c
(automatic variable $< always takes first prerequisite)
but i want "corresponding one":
gcc -c -o release/a.o aaa/a.c
gcc -c -o release/b.o bbb/b.c
gcc -c -o release/c.o ccc/c.c
what should i change to accomplish desirable result?
i know that this will work for sure:
$(outdir)/a.o: aaa/a.c
gcc -c -o $# $<
$(outdir)/b.o: bbb/b.c
gcc -c -o $# $<
$(outdir)/c.o: ccc/c.c
gcc -c -o $# $<
and wondering how to accomplish the same in one receipe. (because in my real makefile i have ~20 different source files not just 3 like i made here for example)
You don't write your recipe like that. That's not how make works.
That recipe says that every item in $(allobjs) has every item in $(allsrc) as its prerequisite but that's not what you mean.
You mean that every .o file has the matching .c file as its prerequisite which is exactly what the built in %.o: %.c rule already does. You don't even need a makefile to do that.
Edit: Actually, you don't mean that. I had missed that the source files were in different directories. That changes and complicates things.
Chris Dodd wrote up two good solutions for this.
The usual way to do what you are asking would be something like:
outdir = release
allsrc = aaa/a.c bbb/b.c ccc/c.c
allobjs = $(addprefix $(outdir), $(notdir $(allsrc:.c=.o)))
VPATH = $(sort $(dir $(allsrc)))
...
test: $(allobjs)
$(outdir)/%.o: %.c
gcc -c -o $# $<
Of course, this will run into problems if you have a b.c in both aaa and bbb, but since you're trying to put all the object files in the same directory, you have that regardless. It might make more sense to get rid of the $(notdir and keep the same directory structure under $(outdir), in which case you don't need the VPATH
outdir = release
allsrc = aaa/a.c bbb/b.c ccc/c.c
allobjs = $(addprefix $(outdir), $(allsrc:.c=.o))
...
test: $(allobjs)
$(outdir)/%.o: %.c
mkdir -p `dirname $#`
gcc -c -o $# $<

Makefile with multiple wildcards in prerequisites

I have the following Makefile, and I am trying to simplify it. Any ideas?
PROG_NAME=a.out
all: $(PROG_NAME)
"\nBuilt all\n"
$(PROG_NAME): build/file1.o build/file2.o build/file3.o build/file4.0
gcc -o $# $^
#build file1.c and file2.c which are both in ../src directory
build/file%.o: ../src/file%.c
gcc -I ../inc -o $# $<
#build file3.c and file4.c which are both in ../src2 directory
build/file%.o: ../src2/file%.c
gcc -I ../inc -o $# $<
I tried this and it does not work:
PROG_NAME=a.out
all: $(PROG_NAME)
"\nBuilt all\n"
$(PROG_NAME): build/file1.o build/file2.o build/file3.o build/file4.0
gcc -o $# $^
#build ../src/file1.c, ../src/file2.c, ../src2/file3.c, and ../src2/file4.c
build/file%.o: ../src/file%.c ../src2/file%.c
gcc -I ../inc -o $# $<
You cannot simplify it. The only way would be to use makefile metaprogramming to generate the rules via eval or something.
Your attempt will clearly not work, because this:
build/file%.o: ../src/file%.c ../src2/file%.c
gcc -I ../inc -o $# $<
says "for any target build/fileXXX.o that you want to build, you can create it by running this gcc command on the file ../src/fileXXX.c if either of the files ../src/fileXXX.c or ../src2/fileXXX.c are older than the .o". That's obviously not what you want to do.
I was able to simplify it using the make variable VPATH.
http://www.gnu.org/software/make/manual/make.html#General-Search
PROG_NAME=a.out
VPATH=../src:../src2
all: $(PROG_NAME)
"\nBuilt all\n"
$(PROG_NAME): build/file1.o build/file2.o build/file3.o build/file4.0
gcc -o $# $^
build/file%.o: file%.c
gcc -I ../inc -o $# $<

Resources