Why isn't make detecting changes in header dependencies - makefile

I'm not sure what I'm doing wrong here. I'm trying to get make to figure out what dependencies my project has for, not only source files, but non-system included header files. I've many resources from this very site related to this subject.
Such as: Makefile header dependencies and Makefile, header dependencies
However, when I do
touch MyHeader.h
as a test to see if this works, my make process fails to rebuild the source files that include this header. So, here's what I have in my makefile (of relevance that is)
CPP=g++
CPPFLAGS=-Iadditional/includes -MMD
CXXFLAGS=-std=c++0x -c
# not every source file in this directory needs to be included in this build
# this is because of shared code with Windows
SOURCESFILTER = File1.cpp File2.cpp
OBJ_DIR=obj
SOURCES = $(filter-out $(SOURCEFILTER),$(wildcard *.cpp))
OBJECTS = $(addprefix $(OBJ_DIR)/,$(SOURCES:.cpp=.o))
DEPENDENCIES = $(OBJECTS:.o=.d)
.PHONY: archive
archive : $(OBJECTS)
ar mylib.a obj/*.o
-include $(DEPENDENCIES)
$(OBJ_DIR)/%.o: $(SOURCES) $(DEPENDENCIES)
$(CPP) $(CPPFLAGS) $(CXXFLAGS) $< -o $#
I've verified that the above process does indeed generate the expected *.d files. I assume that I'm including them correctly. However, as mentioned, as a test I do:
touch MyHeader.h
which is in the same directory as the sources, and rerun the make, none of the source files which include this header are remade. What am I missing?
Andy

First, you cannot include prerequisites in a suffix rule. Even if you could, you certainly would not want to include $(SOURCES) or $(DEPENDENCIES), because that would cause every object to rebuild whenever any source or dependency file changed.
Second, you cannot create the target file in a different directory from where make expects it to be. Make will put the place where it wants to find the target in the variable $#, and you must write the output into that location exactly. If you ever see a rule that modifies the target, such as above where you use obj/$#, that won't work.
Most likely GCC is writing the files as obj/foo.d, but your include is trying to include foo.d but that doesn't exist... but since you used -include make doesn't complain.
I recommend you first write the object files into the local directory and get that working with dependencies. Once that works, then read up on how to write targets to a different directory and/or ask again.
ETA:
Try something like this:
CXX := g++
CPPFLAGS := -Iadditional/includes -MMD
CXXFLAGS := -std=c++0x
# not every source file in this directory needs to be included in this build
# this is because of shared code with Windows
SOURCESFILTER := File1.cpp File2.cpp
OBJ_DIR := obj
SOURCES := $(filter-out $(SOURCEFILTER),$(wildcard *.cpp))
OBJECTS := $(addprefix $(OBJ_DIR)/,$(SOURCES:.cpp=.o))
DEPENDENCIES := $(OBJECTS:.o=.d)
.PHONY: archive
archive: mylib.a
mylib.a: $(OBJECTS)
$(AR) $# $^
-include $(DEPENDENCIES)
$(OBJ_DIR)/%.o: %.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $# $<

Related

Evolving a Makefile From Flat Directory Structure to Sub-Directory Structure

SEE UPDATES BELOW
Research Done: I'm finding learning how to evolve Makefiles from one situation to another is difficult. There are a ton of questions and answers out there but few of them actually show how a Makefile can evolve as your project changes. They also all seem to use various different techniques and idioms of Makefiles so translating between one question and another can be tricky when you are learning Makefiles for the first time, as I am.
Problem: My problem is that I have a project that started at as a flat directory structure but then is migrating to a structure with sub-directories. What I can't do is get my Makefile to along for the ride.
First I'll show what I created that works and then I show how I want it to evolve and how that doesn't work.
Flat Directory Structure, Working Makefile
I have project directory that has all my C files and one header file plus my Makefile:
project
Makefile
c8_asm.c
c8_dasm.c
c8_terp.c
chip8.h
Here is my Makefile (which works just fine):
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
# Targets
all: c8_dasm c8_asm c8_terp
c8_dasm: c8_dasm.o
$(CC) $(LDLIBS) c8_dasm.o -o $#
c8_asm: c8_asm.o
$(CC) $(LDLIBS) c8_asm.o -o $#
c8_terp: c8_terp.o
$(CC) $(LDLIBS) c8_terp.o -o $#
# Using implicit rules for updating an '.o' file from a correspondingly
# named '.c' file.
c8_dasm.o: chip8.h
c8_asm.o: chip8.h
c8_terp.o: chip8.h
.PHONY: clean
clean:
rm c8_dasm c8_asm c8_terp c8_dasm.o c8_asm.o c8_terp.o
I get all my .o files and my executables are created in the project directory.
Evolving The Project
But what I wanted to do is have my sources files (all .c and .h) in a src directory. I wanted to build into an obj directory and have the executables go in a bin directory. So my project would look like this:
project
src
c8_asm.c
c8_dasm.c
c8_terp.c
chip8.h
Makefile
Sub-Directory Structure, Makefile NOT Working
To accommodate the above, I changed my Makefile accordingly:
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
MKDIR_P ?= mkdir -p
# Targets
all: $(BIN_DIR)/c8_dasm $(BIN_DIR)/c8_asm $(BIN_DIR)/c8_terp
$(BIN_DIR)/c8_dasm: $(OBJ_DIR)/c8_dasm.o
$(CC) $(LDLIBS) $(OBJ_DIR)/c8_dasm.o -o $#
$(BIN_DIR)/c8_asm: $(OBJ_DIR)/c8_asm.o
$(CC) $(LDLIBS) $(OBJ_DIR)/c8_asm.o -o $#
$(BIN_DIR)/c8_terp: $(OBJ_DIR)/c8_terp.o
$(MKDIR_P) $(dir $#)
$(CC) $(LDLIBS) $(OBJ_DIR)/c8_terp.o -o $#
$(OBJECTS): $(OBJ_DIR)/%.o : $(SRC_DIR)/%.c
$(MKDIR_P) $(dir $#)
$(CC) $< -o $(OBJ_DIR)/$#
# Using implicit rules for updating an '.o' file from a correspondingly
# named '.c' file.
$(OBJ_DIR)/c8_dasm.o: $(SRC_DIR)/chip8.h
$(OBJ_DIR)/c8_asm.o: $(SRC_DIR)/chip8.h
$(OBJ_DIR)/c8_terp.o: $(SRC_DIR)/chip8.h
.PHONY: clean
clean:
rm -r $(BUILD_DIR)
rm $(OBJECTS)
Upon running this I get the following:
mkdir -p obj/obj/
gcc src/c8_dasm.c -o obj/c8_dasm.o
gcc -lm obj/c8_dasm.o -o bin/c8_dasm
ld: can't link with a main executable file 'obj/c8_dasm.o' for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [bin/c8_dasm] Error 1
I wanted to stop here and get some assistance because I fear I'm making this Makefile for complicated than it need be and I'm trying to avoid getting into bad habits.
I'm hoping to hear opinions about what I'm not conceptualizing correctly here.
FIRST UPDATE
I managed to take it bit by bit and get it mostly working. Here is what I ended up with:
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
# Directories.
SRC_DIR = src
BIN_DIR = bin
$(shell mkdir -p $(BIN_DIR))
# Patterns for files.
SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(SRC_DIR)/%.o)
EXECUTABLES := c8_dasm c8_asm c8_terp
# Targets
all: $(EXECUTABLES)
c8_dasm: $(SRC_DIR)/c8_dasm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Disassembler Built"
c8_asm: $(SRC_DIR)/c8_asm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Assembler Built"
c8_terp: $(SRC_DIR)/c8_terp.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Interpreter Built"
# Using implicit rules for updating an '.o' file from a correspondingly
# named '.c' file.
c8_dasm.o: $(SRC_DIR)/chip8.h
c8_asm.o: $(SRC_DIR)/chip8.h
c8_terp.o: $(SRC_DIR)/chip8.h
.PHONY: clean
clean:
rm $(OBJECTS)
rm -r $(BIN_DIR)
Of course, as I'm finding with Make this leads to other obscure problems. For example doing this:
make
make clean
works fine. Meaning all files are generated and the files are cleaned, including the bin directory.
However, if I do this:
make c8_dasm
make clean
This builds fine. But the clean fails to delete the bin directory (although it does delete the object files). This happens regardless of what individual executable I try to build.
No amount of searching is helping me find out why that is.
SECOND UPDATE
I found that problem was solved as well. It just required using the "-f" for the rm statements in the clean target.
THIRD UPDATE
To get the object file directory part working, I tried (from this: path include and src directory makefile) to construct my Makefile as follows:
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
$(shell mkdir -p $(BIN_DIR))
$(shell mkdir -p $(OBJ_DIR))
SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
EXECUTABLES := c8_dasm c8_asm c8_terp
all: $(EXECUTABLES)
c8_dasm: $(SRC_DIR)/c8_dasm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Disassembler Built"
c8_asm: $(SRC_DIR)/c8_asm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Assembler Built"
c8_terp: $(SRC_DIR)/c8_terp.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Interpreter Built"
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) -c $< -o $(BIN_DIR)/$#
.PHONY: clean
clean:
rm -rf $(BIN_DIR)
rm -f $(OBJECTS)
I was able to condense the original three lines using chip8.h into one target but I have no way to know if that's correct. It compiles at least. I also changed the OBJECTS line to reflect the new OBJ_DIR I created.
However, this doesn't put the object files in the right place. It still puts them in the src directory rather than the obj directory.
This is why it makes sense to not do anything complicated with Makefiles. Just put the actual directory names in your commands. Never rely on wildcards.
People using C and C++ and using Makefiles spend too much time trying to get those to work rather than just actually getting things done. That's why you see so many of the questions that you see and why the answers vary so much.
In your specific case, your targets don't always have to contain the directory and that's part of the problem. The rules getting generated don't have an actual target in your file because of the directories you are prepending to everything. You have to think in terms of what is getting generated by each target: meaning, the output. So if c8_dasm is getting output, that's your target. The directory has nothing to do with that. So you need to remove all of your directory substitutions where they aren't needed.
But before doing that, ask yourself this: if your first solution was working, why change it? It's better to not even do directories when you're using Make. Just have everything in the same directory as you started off with. You can even see that this allows your Makefile to be much cleaner.
I believe I may have figured this out. Below is my Makefile. It seems to do what I want. It does the following:
Compiles all object files into the obj directory.
Compiles and links so that executables are generated in the bin directory.
Recognizes if any .c files are changed and recompiles accordingly.
Recognizes if the .h file is changed and recompiles all C files that reference it.
This seems to satisfy all the criteria but I can't tell if I've painted myself into some corner that I can't see yet.
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
$(shell mkdir -p $(BIN_DIR))
$(shell mkdir -p $(OBJ_DIR))
SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
EXECUTABLES := c8_dasm c8_asm c8_terp
all: $(EXECUTABLES)
c8_dasm: $(OBJ_DIR)/c8_dasm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Disassembler Built"
c8_asm: $(OBJ_DIR)/c8_asm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Assembler Built"
c8_terp: $(OBJ_DIR)/c8_terp.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Interpreter Built"
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(SRC_DIR)/chip8.h
$(CC) $(CFLAGS) -c $< -o $#
.PHONY: clean
clean:
rm -rf $(BIN_DIR)
rm -rf $(OBJ_DIR)
Stackoverflow is whining about too many comments, so I'll make this another "answer." After our back-and-forth to my original comment, your last comment is correct. That's what I wanted you to see.
Understand that you can't use Make to do what you want to do exactly.
So here's really the answer: You can't create multiple executables AND with only some of the object files applying to each one AND while using a directory structure. Make is in no way capable of handling that.
Right now you're trying to use Make in a way that it wasn't intended for which is why you're running into so many problems. If you keep playing around you're going to run into is a series of errors that say "duplicate symbol" because you will be compiling each of your files multiple times for each executable, assuming you follow most of the advice you'll find.
Check out this How can I create a Makefile for C projects with SRC, OBJ, and BIN subdirectories? to see what I mean. That one works because all object files are being used to create a single executable. But as you've stated, that's not going to be the case for you. And that's what Make can't handle. That's why you're not finding an answer to that.
And while your chip8.h file is now not going to cause problems in terms of allowing you to compile, your Makefile with that third update would not recognize when the chip8.h file itself has changed. You would have to change a .c file to force a recompile so that changes to your .h were recognized. So you either have to stick with your second update or use something other than Make.

Makefile -- compile only modified C++ files

This is my current makefile
CFLAGS = -Iheaders/
CC = g++
PROGRAM_NAME = sportsmanager
rwildcard = $(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))
SOURCES = $(call rwildcard,sources/,*.cpp)
OFILES = $(call rwildcard,obj-tmp/,*.o)
OBJDIR = obj-tmp/
compileAndRun:
make -s compile && make -s $(PROGRAM_NAME)
./$(PROGRAM_NAME)
compile: $(SOURCES)
mkdir -p $(OBJDIR)
$(CC) $(CFLAGS) -c $(SOURCES) && mv *.o $(OBJDIR)
$(PROGRAM_NAME): $(OFILES)
$(CC) $(CFLAGS) $(OFILES) -o $(PROGRAM_NAME)
Whenever I run $ make, target compile is triggered which compiles all .cpp files in directory sources/ to .o files which are then moved to obj-tmp/. Then the target $(PROGRAM_NAME) is triggered, which links all the .o files and outputs the executable file.
The problem is that all files are compiled each time I run make. What ideally should happen if I run 'make' twice in succession is that make should know that the program is up to date the second time. If I modify only one file, only that file should be compiled.
Heads up: I know that there exists similar questions regarding this, but I've yet to see a solution which works in conjunction with the above makefile.
Any input is greatly appreciated.
The whole point of make is to compile only those files which have been modified since the last build. The problem in your makefile is that your compile recipe has the $(SOURCES) variable as a dependency. As in, all the source files.
I would use vpath to organize the project folder like so:
vpath %.cpp src
vpath %.h include
This will tell make to look for c++ files in ./src and header files in ./include. Then, you can simplify your recipe for individual files like this:
%.o: %.cpp
$(CC) $(CFLAGS) -c -o $# $<
Having done this, you can now define an $(OBJECTS) variable with a wildcard that matches .o files and continue from there. As an aside, moving your object files into a separate folder is considered bad practice and I agree; it really adds nothing substantial of value but complicates recipes.
Remember that object files represent a dependency for the $(PROGRAM) recipe. So naturally, make looks for the necessary object files to see if they need to be rebuilt. If they've been moved, one of two things happens. Either make will determine that they don't exist and will rebuild all the object files again from scratch, thereby invalidating the very reason we use make in the first place, or you'll have to define a folder where the object files will live, and every time you handle wildcards, searches, etc., literally anything that has to do with the object files, you'll have to take this added complexity into account.
I agree that having a ton of object files in the project folder can be a little annoying, but it definitely beats waiting forever for the project to compile. Just remember to add *.o to your .gitignore or whatever source control platform you use and they'll be nothing more than an eyesore, while make will be that much easier to use.
To answer your question on handling subdirectories in the source folder, the answer is a little more complicated.
Rather than using the specific vpath <pattern> <folder> directive as above, you could just outright use the VPATH variable like this:
VPATH = include src src/sub
This would handle the job, but the first method is usually preferred because when using VPATH, make searches every directory every time when looking for a file, rather than being location-constrained by file extension.
It is possible to use make to conveniently manage large projects though, and it involves calling make itself recursively, writing makefiles for each module in the build process. This process is obviously much more complicated, and I would strongly recommend considering whether the project genuinely necessitates this, as any potential gains in build-process modularization may not be recuperated due to the complexity involved in implementation.
I'd like to point you to this and this, both of which are phenomenal resources on makefiles.
Change the dependency of compile to be the object files.
Add a pattern rule for the object files.
compile: $(OFILES)
$(OBJDIR)/%.o: sources/%.cpp
mkdir -p $(OBJDIR)
$(CC) $(CFLAGS) -c $< -o $#
Ok, a lot of good input in this thread! Here's a follow up. I've now updated the script to the following:
CC = g++
CFLAGS = -Iheaders/
PROGRAM_NAME = sportsmanager
OFILES = $(patsubst %.cpp,%.o,$(wildcard sources/*.cpp))
vpath %.cpp sources
compileAndRun:
#make -s $(PROGRAM_NAME)
#./$(PROGRAM_NAME)
$(PROGRAM_NAME): $(OFILES)
$(CC) $(CFLAGS) -o $(PROGRAM_NAME) $(OFILES)
%.o: %.cpp
$(CC) $(CFLAGS) -c -o $# $<
clean:
rm -rf $(PROGRAM_NAME) $(OFILES)
Any suggestions for further improvements are very welcome!

MakeFiles and dependencies

I'm writing a makefile and I can't figure out how to include all my source files without having to write all source file I want to use. Here is the makefile I'm currently using:
GCC = $(GNUARM_HOME)\bin\arm-elf-gcc.exe
SOURCES=ShapeApp.cpp Square.cpp Circle.cpp Shape.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=hello
all: $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
#$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
$(GCC) -c $< -o $#
How do I automatically add new source file without having to add it to the sources line?
Here is something I have used in an examples/ directory where each file is mapped one-to-one to an executable:
sources := $(wildcard *.cpp)
programs := $(sources:.cpp=)
[ more settings about compiler flags, linker options, ...]
all : $(programs)
That can be enough as make knows how to turn a .cpp file into an object file and then into an executable. Note that this is on Linux so for Windoze you'd probably need to do
programs := $(sources:.cpp=.exe)
to append the .exe.

Problem generating dependencies in Makefile using -MM

I am new to Makefiles and g++ and i am struck with a problem while generating dependencies of the project files using -MM flag. I'm posting the Makefile i am using for your consideration. Please take a look.
OUTPUT_ROOT := output/
SOURCE_ROOT := source/
TITLE_NAME := TestProj
SOURCES := \
MyFile.cpp \
stdAfx.cpp \
Main.cpp \
OUT_DIR := $(OUTPUT_ROOT)
OUT_O_DIR := $(OUT_DIR)
OBJS = $(SOURCES:%.cpp=$(OUT_O_DIR)%.o)
DEPS = $(OBJS:%.o=%.d)
DIRS = $(subst /,/,$(sort $(dir $(OBJS))))
SOURCE_TARGET = $(SOURCES:%.cpp=$(SOURCE_ROOT)%.cpp)
OUTPUT_TARGET = $(OUT_DIR)$(TITLE_NAME)
#---------------------------------------------------------------------
# executables
#---------------------------------------------------------------------
MD := mkdir -p
RM := rm
CC := g++
#---------------------------------------------------------------------
# rules
#---------------------------------------------------------------------
.PHONY: clean directories objects title
all: directories objects title
directories:
#$(MD) $(DIRS)
clean:
$(RM) -rf $(OUT_DIR)
$(OBJS): $(SOURCE_TARGET)
#$(CC) -c $< -o $#
$(DEPS): $(SOURCE_TARGET)
#$(CC) -c -MM $< > $(DEPS)
-include $(DEPS)
objects:$(OBJS) $(DEPS)
title: $(OBJS)
#$(CC) $< -o $#
I tried several options and sooo many times. I googled for the solution but couldn't find any.
Is using "-MM" flag to generate dependencies the right option?? If not please suggest me the right way to generate the dependencies. I wanted to generated dependencies automatically because my project will have sooo many files. I thought it is the better option than to write down evey dependency manually.
These are the errors i am getting
g++: stdAfx.d: No such file or directory
g++: Main.d: No such file or directory
make: *** No rule to make target `stdAfx.d', needed by `objects'. Stop.
Thanks in advance.
It looks like you are trying to generate a dependency file (called *.d, by your makefile rules) for each .cpp file. This is not my understanding of how a dependencies file is used.
Use the -M option to generate a single dependencies file for your project and then include the dependencies file.
DEPS = $(OUR_DIR)/make.dep
$(DEPS): $(SOURCE_TARGET)
#$(CC) -M $(SOURCE_TARGET) > $(DEPS)
include $(DEPS)
edit Your dependency file should also depend on your headers
$(DEPS): $(SOURCE_TARGET) $(HEADER_TARGET)
#$(CC) -M $(SOURCE_TARGET) > $(DEPS)
where HEADER_TARGET is defined the same as SOURCE_TARGET. That way, when a header file is changed the dependency file is rebuilt.
For a beginner, you are doing some exotic stuff. You should start simple and only use code in your Makefile that you 100% understand and trust. Even on a large project with hundreds of files you will not spend much time maintaining the Makefile.
Variables assigned with := are immediately expanded--all the $(VAR) values are substituted into the variable's value during assignment. Variables assigned with = are expanded when they are used, so they can do things like refer to variables that aren't defined yet.
The -MM flag for g++ will generate a Makefile dependency line, e.g. foo.o: foo.cc foo.hh, but I've never found it useful. I had a phony "dependency" target that generated a single dependency file. Your idea of making a bunch of *.d files with those one line dependencies might work, but you'll end up with a lot of those files.
The error you are getting is from g++, not from make. It's because you are using $(DEPS) as if it were a single file when it's the entire list of *.d files. What happens is this line:
#$(CC) -c -MM $< > $(DEPS)
gets expanded to:
g++ -c -MM MyFile.cpp > MyFile.d stdAfx.d Main.cpp
mcdave just posted the code I have used to generate a dependency file. You can either switch to the single dependency file style, or change your -MM command to this:
#$(CC) -MM $< > $#
You may also have to fix the -include statement because I don't think it supports a list of files to include.

How can I have a Makefile automatically rebuild source files that include a modified header file? (In C/C++)

I have the following makefile that I use to build a program (a kernel, actually) that I'm working on. Its from scratch and I'm learning about the process, so its not perfect, but I think its powerful enough at this point for my level of experience writing makefiles.
AS = nasm
CC = gcc
LD = ld
TARGET = core
BUILD = build
SOURCES = source
INCLUDE = include
ASM = assembly
VPATH = $(SOURCES)
CFLAGS = -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \
-nostdinc -fno-builtin -I $(INCLUDE)
ASFLAGS = -f elf
#CFILES = core.c consoleio.c system.c
CFILES = $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
SFILES = assembly/start.asm
SOBJS = $(SFILES:.asm=.o)
COBJS = $(CFILES:.c=.o)
OBJS = $(SOBJS) $(COBJS)
build : $(TARGET).img
$(TARGET).img : $(TARGET).elf
c:/python26/python.exe concat.py stage1 stage2 pad.bin core.elf floppy.img
$(TARGET).elf : $(OBJS)
$(LD) -T link.ld -o $# $^
$(SOBJS) : $(SFILES)
$(AS) $(ASFLAGS) $< -o $#
%.o: %.c
#echo Compiling $<...
$(CC) $(CFLAGS) -c -o $# $<
#Clean Script - Should clear out all .o files everywhere and all that.
clean:
-del *.img
-del *.o
-del assembly\*.o
-del core.elf
My main issue with this makefile is that when I modify a header file that one or more C files include, the C files aren't rebuilt. I can fix this quite easily by having all of my header files be dependencies for all of my C files, but that would effectively cause a complete rebuild of the project any time I changed/added a header file, which would not be very graceful.
What I want is for only the C files that include the header file I change to be rebuilt, and for the entire project to be linked again. I can do the linking by causing all header files to be dependencies of the target, but I cannot figure out how to make the C files be invalidated when their included header files are newer.
I've heard that GCC has some commands to make this possible (so the makefile can somehow figure out which files need to be rebuilt) but I can't for the life of me find an actual implementation example to look at. Can someone post a solution that will enable this behavior in a makefile?
EDIT: I should clarify, I'm familiar with the concept of putting the individual targets in and having each target.o require the header files. That requires me to be editing the makefile every time I include a header file somewhere, which is a bit of a pain. I'm looking for a solution that can derive the header file dependencies on its own, which I'm fairly certain I've seen in other projects.
As already pointed out elsewhere on this site, see this page:
Auto-Dependency Generation
In short, gcc can automatically create .d dependency files for you, which are mini makefile fragments containing the dependencies of the .c file you compiled.
Every time you change the .c file and compile it, the .d file will be updated.
Besides adding the -M flag to gcc, you'll need to include the .d files in the makefile (like Chris wrote above).
There are some more complicated issues in the page which are solved using sed, but you can ignore them and do a "make clean" to clear away the .d files whenever make complains about not being able to build a header file that no longer exists.
You could add a 'make depend' command as others have stated but why not get gcc to create dependencies and compile at the same time:
DEPS := $(COBJS:.o=.d)
-include $(DEPS)
%.o: %.c
$(CC) -c $(CFLAGS) -MM -MF $(patsubst %.o,%.d,$#) -o $# $<
The '-MF' parameter specifies a file to store the dependencies in.
The dash at the start of '-include' tells Make to continue when the .d file doesn't exist (e.g. on first compilation).
Note there seems to be a bug in gcc regarding the -o option. If you set the object filename to say obj/_file__c.o then the generated _file_.d will still contain _file_.o, not obj/_file_c.o.
This is equivalent to Chris Dodd's answer, but uses a different naming convention (and coincidentally doesn't require the sed magic. Copied from a later duplicate.
If you are using a GNU compiler, the compiler can assemble a list of dependencies for you. Makefile fragment:
depend: .depend
.depend: $(SOURCES)
rm -f ./.depend
$(CC) $(CFLAGS) -MM $^>>./.depend;
include .depend
There is also the tool makedepend, but I never liked it as much as gcc -MM
You'll have to make individual targets for each C file, and then list the header file as a dependency. You can still use your generic targets, and just place the .h dependencies afterwards, like so:
%.o: %.c
#echo Compiling $<...
$(CC) $(CFLAGS) -c -o $# $<
foo.c: bar.h
# And so on...
Basically, you need to dynamically create the makefile rules to rebuild the object files when the header files change. If you use gcc and gnumake, this is fairly easy; just put something like:
$(OBJDIR)/%.d: %.c
$(CC) -MM -MG $(CPPFLAGS) $< | sed -e 's,^\([^:]*\)\.o[ ]*:,$(#D)/\1.o $(#D)/\1.d:,' >$#
ifneq ($(MAKECMDGOALS),clean)
include $(SRCS:%.c=$(OBJDIR)/%.d)
endif
in your makefile.
Over and above what #mipadi said, you can also explore the use of the '-M' option to generate a record of the dependencies. You might even generate those into a separate file (perhaps 'depend.mk') which you then include in the makefile. Or you can find a 'make depend' rule which edits the makefile with the correct dependencies (Google terms: "do not remove this line" and depend).
Simpler solution: Just use the Makefile to have the .c to .o compilation rule be dependent on the header file(s) and whatever else is relevant in your project as a dependency.
E.g., in the Makefile somewhere:
DEPENDENCIES=mydefs.h yourdefs.h Makefile GameOfThrones.S07E01.mkv
::: (your other Makefile statements like rules
::: for constructing executables or libraries)
# Compile any .c to the corresponding .o file:
%.o: %.c $(DEPENDENCIES)
$(CC) $(CFLAGS) -c -o $# $<
None of the answers worked for me. E.g. Martin Fido's answer suggests gcc can create dependency file, but when I tried that it was generating empty (zero bytes) object files for me without any warnings or errors. It might be a gcc bug. I am on
$ gcc --version gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-16)
So here's my complete Makefile that works for me; it's a combination of solutions + something that wasn't mentioned by anyone else (e.g. "suffix replacement rule" specified as .cc.o:):
CC = g++
CFLAGS = -Wall -g -std=c++0x
INCLUDES = -I./includes/
# LFLAGS = -L../lib
# LIBS = -lmylib -lm
# List of all source files
SRCS = main.cc cache.cc
# Object files defined from source files
OBJS = $(SRCS:.cc=.o)
# # define the executable file
MAIN = cache_test
#List of non-file based targets:
.PHONY: depend clean all
## .DEFAULT_GOAL := all
# List of dependencies defined from list of object files
DEPS := $(OBJS:.o=.d)
all: $(MAIN)
-include $(DEPS)
$(MAIN): $(OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS)
#suffix replacement rule for building .o's from .cc's
#build dependency files first, second line actually compiles into .o
.cc.o:
$(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,$#) $<
$(CC) $(CFLAGS) $(INCLUDES) -c -o $# $<
clean:
$(RM) *.o *~ $(MAIN) *.d
Notice I used .cc .. The above Makefile is easy to adjust for .c files.
Also notice importance of these two lines :
$(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,$#) $<
$(CC) $(CFLAGS) $(INCLUDES) -c -o $# $<
so gcc is called once to build a dependency file first, and then actually compiles a .cc file. And so on for each source file.
I believe the mkdep command is what you want. It actually scans .c files for #include lines and creates a dependency tree for them. I believe Automake/Autoconf projects use this by default.

Resources