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

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.

Related

Makefile ignoring included rules

I'm trying to create a makefile for a very basic c++ program. I'm trying to implement the automatic generation of dependencies by running g++ with the -M flag, storing this output in a .d file, and then including those .d files in my main makefile. The makefile content is below
CC=g++
CPPFLAGS=-Wall -Wextra -g -std=c++11
SOURCEDIR=src
SOURCES = $(wildcard $(SOURCEDIR)/*.cpp)
BUILDDIR=build
OBJDIR=$(BUILDDIR)/objs
OBJS=$(SOURCES:$(SOURCEDIR)/%.cpp=$(OBJDIR)/%.o)
DEP_FILES = $(OBJS:.o=.d)
OUTFILE=hello.out
$(OUTFILE) : $(OBJS)
$(CC) -o $# $^ $(CPPFLAGS)
include $(DEP_FILES)
$(OBJDIR)/%.d : $(SOURCEDIR)/%.cpp
$(CC) $(CPPFLAGS) $< -MM -MT $(#:.d=.o) > $#
$(DEP_FILES) : | $(OBJDIR)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
mkdir -p $(OBJDIR)
.PHONY: clean
clean:
rm -f $(BUILDDIR) -r
rm -f *~
rm -f $(OUTFILE)
When I run make, the directory build/objs/ is generated and a .d file is generated with rules in it. Here's main.d file:
build/objs/main.o: src/main.cpp src/main.h
And here's the myfunc.d file:
build/objs/myfunc.o: src/myfunc.cpp src/main.h
Here's the issue
Since I'm calling include on these .d files, I'd expect the .o files which they specify to then be created, and then the main outfile to be created as the main rule. However, make creates the .d files, and then skips directly to the main compilation step without creating any .o files:
g++ -o hello.out build/objs/myfunc.o build/objs/main.o -Wall -Wextra -g -std=c++11
This fails with the following error, since the .o files are never created:
g++: error: build/objs/myfunc.o: No such file or directory
g++: error: build/objs/main.o: No such file or directory
g++: fatal error: no input files
How can I use this makefile to generate the .o files necessary for g++? Thank you for any help in advance!
I saw you got your makefile working but I just wanted to add a few things you might want to consider for future projects. I recommend using the vpath variable rather than specifying $(OBJDIR)/%.o in your makefile recipes. I actually read somewhere that it's not "cannon" to build object files in a separate directory, but in the cursory search I conducted before posting, I couldn't find the document.
That being said, I wrote a makefile that does what you wanted; it builds the output folder, generates the dependencies, and compiles the program. I specifically included the $(COMPILE.cpp) definition so you could see what it's composed of. $(CC) is specifically the C compiler, and $(CFLAGS) is specifically flags for the C compiler. They're just variables, obviously, so you can change them like you did and it will work fine, but the main think to keep in mind is that whoever uses your programs will expect to be able to configure the compilation as they see fit. This means they will set the $(CXX) and $(CXXFLAGS) expecting to set the C++ compiler and flags. $(CPPFLAGS) stands for C/C++ Preprocessor flags.
It's not the cleanest makefile, and if I was to change something, I would just compile the object files in place and save myself that headache. That cuts down on unnecessary make hacking, but for the purposes of answering your question, here it is. Anyways I hope this helps you somewhat, let me know if you have any questions.
Oh yea, I almost forgot; notice I changed your make clean script. I used $(RM) instead of simply rm -f. When you use utilities in your makefiles, you want to use them as variables. Again, this is to allow your users as much freedom and flexibility as possible when they're compiling your program.
vpath %.cpp src
vpath %.hpp include
vpath %.o build/objs
vpath %.d build/objs
.SUFFIXES:
.SUFFIXES: .cpp .hpp .o .d
SRCDIR = src
INCLUDESDIR = include
BUILDDIR = build
OBJDIR = $(BUILDDIR)/objs
SRCS = $(wildcard $(SRCDIR)/*.cpp)
OBJS = $(patsubst %.cpp, %.o, $(notdir $(SRCS)))
DEP_FILES = $(patsubst %.o, %.d, $(OBJS))
INCLUDE_DIRS = -I $(INCLUDESDIR)
CXX = g++
CPPFLAGS =
CXXFLAGS = -Wall -Wextra -g -std=c++11
PROGRAM = hello.out
COMPILE.cpp = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDE_DIRS) $(TARGET_ARCH)
all: $(PROGRAM)
$(PROGRAM): %: $(OBJS)
$(LINK.cpp) $(INCLUDE_DIRS) $(addprefix $(OBJDIR)/, $^) $(LOADLIBES) $(LDLIBS) -o $#
%.o: %.cpp
$(COMPILE.cpp) -c -o $(OBJDIR)/$# $<
%.d: %.cpp
mkdir -p $(OBJDIR)
$(COMPILE.cpp) $^ -MM -MT $(addprefix $(OBJDIR)/, $(#:.d=.o)) > $(OBJDIR)/$#
include $(DEP_FILES)
.PHONY: clean
clean:
#echo $(RM)
$(RM) $(BUILDDIR) -r
$(RM) *~
$(RM) $(PROGRAM)
For anyone having a similar issue, here's the correct solution is in the comments. Here for convenience: The included .d files generate dependencies but not a recipe for making the .o files, and since I'm putting things in various directories the default rule doesn't work here, so the .o files aren't created. The solution was to add in the following rule to my main makefile.
$(OBJDIR)/%.o :
$(CC) -c -o $# $< $(CPPFLAGS)
Thanks Matt and Renaud for your answers!

Attempt to link objects makes them recompile even if up-to-date

I have a recipe in my makefile that relies on several object files. I would like it to simply link the them, but they are always recompiling.
I've googled around and found information I did not know(marked with #) and changed it a bit, but the problem persisted.
I am led to believe make expects the name of the recipe be the name of the file, and I am failing to accomplish that. The problem is I do not what else to try and fix this. I would appreciate any help
CC = g++
#.PHONY: sfml-app
LIBS = -lsfml-graphics -lsfml-window -lsfml-system
APPLICATION = sfml-app
INCLUDE_DIR = -I include/
SOURCE_DIR = source
OUTPUT_DIR = bin
SOURCES = $(wildcard $(SOURCE_DIR)/*.cpp)
OBJECTS = $(notdir $(patsubst %.cpp, %.o, $(SOURCES)))
#$(OUTPUT_DIR)/$(APPLICATION): $(OBJECTS)
#bin/sfml-app: $(OBJECTS)
#sfml-app: $(OBJECTS)
#$(APPLICATION): $(OBJECTS)
$(CC) $(OUTPUT_DIR)/*.o $(LIBS) -o $(OUTPUT_DIR)/$(APPLICATION)
%.o: $(SOURCE_DIR)/%.cpp
$(CC) -c $< $(INCLUDE_DIR) -o $(OUTPUT_DIR)/$#
clean:
rm $(OUTPUT_DIR)/*
print-% : ; #echo $* = $($*)
This rule doesn't create the file it promises to:
%.o: $(SOURCE_DIR)/%.cpp
$(CC) -c $< $(INCLUDE_DIR) -o $(OUTPUT_DIR)/$#
See that -o $(OUTPUT_DIR)/$#? That's instructing the compiler to create a file in $(OUTPUT_DIR) instead of in the working directory.
If you really want your object files to go in $(OUTPUT_DIR), you need to make sure that your rule indicates that:
$(OUTPUT_DIR)/%.o: $(SOURCE_DIR)/%.cpp
$(CC) -c $< $(INCLUDE_DIR) -o $#
Or better, to act like the standard %.o: %.c rule (which will include CFLAGS etc):
$(OUTPUT_DIR)/%.o: $(SOURCE_DIR)/%.cpp
$(COMPILE.c) $(OUTPUT_OPTION) $<
I note your input files are named *.cpp - usually, that convention is for C++ files (i.e. to be compiled with $(COMPILE.cc), which will invoke $(CXX) rather than $(CC)). Check that you've not mixed up your C and C++ sources!

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

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

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 does not work properly

I've this folder structure
project
|_src
| |_test
| |_main.cpp
|_Makefile
This is my makefile (trying to adapt from this link):
CC = g++
RM = rm
WFLAGS = -c -Wall -W
LDFLAGS =
SRCTESTD = src/test
EXECUTABLE = test
OBJD = .obj
DEPD = .dep
SRCSTEST = $(SRCTESTD)/main.cpp
OBJECTSTEST = $(patsubst %.cpp, $(OBJD)/test/%.o, $(notdir $(SRCSTEST)))
DEPDSTEST = $(patsubst %.cpp, $(DEPD)/test/%.d, $(notdir $(SRCSTEST)))
all: $(SRCSTEST) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTSTEST)
$(CC) $(LDFLAGS) $(OBJECTSTEST) -o $#
.cpp.o:
$(CC) $(WFLAGS) $< -o $#
It does not work, and I've this error
make: *** No rule to make target `.obj/test/main.o', needed by `test'. Stop.
What I'm doing wrong? Sorry for trivial question, but I'm a make newbie.
The link shows outdated methods, such as suffix rules. Making dependencies can also be done during compilation by gcc/g++.
As for the rest, here is it :
EXE := test
SRCDIR := src
OBJDIR := .obj
SRC := $(shell find $(SRCDIR) -name "*.cpp")
OBJ := $(SRC:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
DEP := $(OBJ:.o=.d)
LDLIBS := # -l flags
LDFLAGS := # -L flags
CPPFLAGS := -MMD -MP # -I flags also
CXXFLAGS := -W -Wall # no -c flag here
.PHONY: all clean fclean re
all: $(EXE)
clean:
$(RM) -r $(OBJDIR)
fclean: clean
$(RM) $(EXE)
re: fclean all
-include $(DEP)
$(EXE): $(OBJ)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
#mkdir -p $(#D)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
No redefinition of internally defined variables, no suffix rules, correct linking step and dependencies generation.
Update: To avoid calling mkdir for every source file, one should use order-only prerequisites and the special target .SECONDEXPANSION.
Change this block:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
#mkdir -p $(#D)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
To this:
.SECONDEXPANSION:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp | $$(#D)/
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
%/:
mkdir $*
The error means make can't find a correct rule to build your object files. Your tree structure lacks some informations: only one file ? Where are the others ? Anyway, here are some hints:
In the last two lines, you are using an obsolete feature of make: suffix rules. I suggest you switch to a pattern rule, which is functionaly equivalent.
Say something like:
%.o: %.cpp
$(CXX) $(CXXFLAGS) $< -o $#
Another thing (that shouldn't be a problem here): you are using the variable CC which is internally defined as the default C compiler. It's okay because you redefine it, but as your sources seem to be C++ files, why not use the variable CXX, that is internally defined as the C++ compiler ?
Lastly, to make sure your set of files are correctly defined, you can print them with a dummy show target, see here.
show:
#echo "OBJECTSTEST=$(OBJECTSTEST)"
...

Resources