*.c not rebult when dependency x.h changed, using auto-generated *.d file - makefile

I am facing one issue while handling dependency files during compilation. I am just giving you the scenario which I faced in my project.
I have two C source files called a.c, b.c which includes one header file called c.h. I ran makefile which has instructions to compile both files. I can successfully compile the a.c file, but I have seen some failures while comping b.c which requires to do some changes in c.h to fix that issue. After I made change in c.h and trigger build (incremental build) the a.c file should compile again, too, right? Because a.c also depends on the c.h file.
I followed all dependency mechanism (creating auto dependency files & including .d files, etc)
DEPSALL := $(wildcard $(patsubst %,%.d,$(basename $(TGTFILES)/*.c)))
-include $(DEPSALL)
$(TGTFILES)/%.o: $(TGTFILES)/%.c
mkdir -p $(#D)
$(CC64) -MT $# -MMD -MP -MF $(patsubst %,%.d,$(basename $#)) -o $(#) -c $(CFLAGS64) $<
...
...
Am I missing something here? I want to rebuild all the .c files which are including the particular header file which I changed.

Your question is incomplete: you do not really describe the problem you are facing (but we can probably guess that object files are not rebuilt while they should) and the part of the Makefile you show is not sufficient to understand what your goals are.
Anyway, first of all, this expression:
DEPSALL := $(wildcard $(patsubst %,%.d,$(basename $(TGTFILES)/*.c)))
is uselessly complex. It is equivalent to the much simpler and easier to understand:
DEPSALL := $(wildcard $(TGTFILES)/*.d))
Similarly, in your compilation recipe you can replace:
$(patsubst %,%.d,$(basename $#))
by:
$(TGTFILES)/$*.d
But let's go back to your main problem (at least what I guess is your main problem): when modifying your header file, some object files are not rebuilt while they should.
My guess is that you think:
DEPSALL := $(wildcard $(patsubst %,%.d,$(basename $(TGTFILES)/*.c)))
will assign to DEPSALL a list of dependency files, one per source file, like this other form would do:
DEPSALL := $(patsubst %.c,%.d,$(wildcard $(TGTFILES)/*.c))
If this is what you think, then you are wrong. Your version will assign to DEPSALL the list of dependency files that currently exist in $(TGTFILES) when you invoke make. If some (or all) are missing, some object files will not be rebuilt...
I suggest that you carefully read this excellent post about Auto-Dependency Generation. If you adapt it to your set-up, you should end up with something like:
TGTFILES := tgtfiles
SRCS := $(wildcard $(TGTFILES)/*.c)
OBJS := $(patsubst %.c,%.o,$(SRCS))
DEPS := $(patsubst %.c,%.d,$(SRCS))
INCLUDES := include
CFLAGS += -I$(INCLUDES)
.PHONY: objs clean
objs: $(OBJS)
%.o: %.c
%.o: %.c %.d
$(CC) -MT $# -MMD -MP -MF $*.Td $(CFLAGS) $(CPPFLAGS) -c -o $# $<
#mv -f $*.Td $*.d && touch $#
%.d: ;
.PRECIOUS: %.d
clean:
rm -f $(OBJS) $(DEPS)
include $(DEPS)
Several aspects may look strange, useless or even completely wrong. But if you carefully read the above mentioned post you will see that it perfectly makes sense. Demo:
$ tree
.
├── Makefile
├── include
│   └── c.h
└── tgtfiles
├── a.c
└── b.c
2 directories, 4 files
$ make
cc -MT tgtfiles/b.o -MMD -MP -MF tgtfiles/b.Td -Iinclude -c -o tgtfiles/b.o tgtfiles/b.c
cc -MT tgtfiles/a.o -MMD -MP -MF tgtfiles/a.Td -Iinclude -c -o tgtfiles/a.o tgtfiles/a.c
$ tree
.
├── Makefile
├── include
│   └── c.h
└── tgtfiles
├── a.c
├── a.d
├── a.o
├── b.c
├── b.d
└── b.o
2 directories, 8 files
$ cat tgtfiles/a.d
tgtfiles/a.o: tgtfiles/a.c include/c.h
include/c.h:
$ make
make: Nothing to be done for 'objs'.
$ touch include/c.h
$ make
cc -MT tgtfiles/b.o -MMD -MP -MF tgtfiles/b.Td -Iinclude -c -o tgtfiles/b.o tgtfiles/b.c
cc -MT tgtfiles/a.o -MMD -MP -MF tgtfiles/a.Td -Iinclude -c -o tgtfiles/a.o tgtfiles/a.c

wildcard function application doesn't look right. Should probably be:
DEPSALL := $(patsubst %,%.d,$(basename $(wildcard $(TGTFILES)/*.c)))

Related

How can I pass a rule pattern in a makefile to filter dependencies?

I have a rule in my project to generate libraries from sourcecode. I already have the function to compile %.c to %.o, but I split my library code in multiple source files that begin with the same prefix. I have two separate library code in the same directory, but their source files have different prefixes, that's why I am trying to build a single rule for both (or maybe more) libraries. But I can't pass the prefix of the codebase to the dependencies to filter the object files needed.
The rule I have is this in my Makefile:
# ...
BINDIR = bin
LIBDIR = lib
# ...
# These are all the libraries source files.
LIB_SOURCES = $(wildcard $(LIBDIR)/*.c)
# These are all the libraries "main" source files.
LIB_SRCS = $(filter-out $(wildcard $(LIBDIR)/*_*.c), $(LIB_SOURCES))
# These are all the source files to which I have exported some code from the "main" library source file.
LIB_CODE = $(filter-out $(LIB_SRCS), $(LIB_SOURCES))
# These are all the objects produced by compiling the c source files.
LIB_OBJS = $(patsubst %.c, %.o, $(LIB_CODE))
# ...
# These are all the libraries produced.
LIBS = $(patsubst $(LIBDIR)/%.c,$(BINDIR)/lib%.so,$(LIB_SRCS))
# ...
.PHONY: libs
# ...
%/:
mkdir -p $#
libs: $(BINDIR)/ $(LIBS)
.SECONDEXPANSION:
$(BINDIR)/lib%.so: $(LIBDIR)/%.o $(filter $(LIBDIR)/$*_%.o, $(LIB_OBJS))
#echo $(CC) $(CFLAGS) $(CLNKERFLAGS) -o $# $^
$(LIBDIR)/%.o: $(LIBDIR)/%.c $(LIBDIR)/%.h
#echo $(CC) $(CFLAGS) -o $# -c $<
For the moment I just print the (incomplete) command, but it still doesn't get the correct output with all the objects needed.
In the directory lib I have the following files:
$ tree lib
lib
├── app.c
├── app_db.c
├── app_db.h
├── app.h
├── app_logic.c
├── app_logic.h
├── app_net.c
├── app_net.h
├── server.c
├── server.h
├── server_queue.c
└── server_queue.h
But it never builds the dependencies correctly.
$ make libs
gcc -Wpedantic -O3 -o lib/app.o -c lib/app.c
gcc -Wpedantic -O3 -o bin/libapp.so lib/app.o
gcc -Wpedantic -O3 -o lib/server.o -c lib/server.c
gcc -Wpedantic -O3 -o bin/libserver.so lib/server.o
I have read the following question How to use pattern-dependent variables in dependencies in make pattern rules, which had a tip I thought it would help me, but it didn't.
Any idea how can I achive this?
EDIT 1:
I want the output of the last command to be:
$ make libs
gcc -Wpedantic -O3 -o lib/app.o -c lib/app.c
gcc -Wpedantic -O3 -o lib/app_db.o -c lib/app_db.c
gcc -Wpedantic -O3 -o lib/app_logic.o -c lib/app_logic.c
gcc -Wpedantic -O3 -o lib/app_net.o -c lib/app_net.c
gcc -Wpedantic -O3 -o bin/libapp.so lib/app.o lib/app_db.o lib/app_logic.o lib/app_net.o
gcc -Wpedantic -O3 -o lib/server.o -c lib/server.c
gcc -Wpedantic -O3 -o lib/server_queue.o -c lib/server_queue.c
gcc -Wpedantic -O3 -o bin/libserver.so lib/server.o lib/server_queue.o
Thanks for your attention.
You added .SECONDEXPANSION, but you didn't escape anything in the prerequisites list so it doesn't actually do anything:
$(BINDIR)/lib%.so: $(LIBDIR)/%.o $(filter $(LIBDIR)/$*_%.o, $(LIB_OBJS))
None of these variables/functions are escaped, so everything here is expanded during the initial read-in, so there's nothing for secondary expansion to do.
The secondary expansion feature consists of two parts: first, you enable it with the special target. Second, you escape the variables and/or functions you want to delay expansion of. So this could be:
getobjs = $(filter $(LIBDIR)/$*_%.o, $(LIB_OBJS))
$(BINDIR)/lib%.so: $(LIBDIR)/%.o $$(getobjs)
#echo $(CC) $(CFLAGS) $(CLNKERFLAGS) -o $# $^
Note how we escape the $(getobjs) as $$(getobjs) so that this variable is not expanded until the second pass.
Make isn't very deft with wildcards, and your approach requires it to handle two different wildcards in one line. If that's possible at all, it will be a terrible thing to see. I suggest a different approach.
First, your variables are wrong. It's not clear what your intention was, but here are the ones that fit your desired results:
LIB_SOURCES := $(wildcard $(LIBDIR)/*.c)
LIB_OBJS := $(patsubst %.c,%.o,$(LIB_SOURCES))
Now, you want your makefile to act as if it had these two rules:
$(BINDIR)/libapp.so: $(filter $(LIBDIR)/app%,$(NEW_LIB_OBJS))
#echo build $# somehow from $^
$(BINDIR)/libserver.so: $(filter $(LIBDIR)/server%,$(NEW_LIB_OBJS))
#echo build $# somehow from $^
But rather than spelling them out in the makefile, you want Make to build them at run time. So we'll use a "canned recipe":
define librule
$(BINDIR)/lib$(1).so: $(filter $(LIBDIR)/$(1)%,$(LIB_OBJS))
#echo building $$# somehow from $$^
endef
$(eval $(call librule,app))
$(eval $(call librule,server))
Then rather than writing those last two lines in the makefile, specifying app and server, we can have Make extract them from LIBS:
LIB_NAMES := $(patsubst $(BINDIR)/lib%.so,%,$(LIBS))
$(foreach libname,$(LIB_NAMES),$(eval $(call librule,$(libname))))

Make not setting correctly the location of the source code

Here is a little problem that I've encountered:
I have the following project layout:
.
├── Makefile
├── README.md
├── inc
│ └── include.hpp
├── out
│ ├── debug
│ └── release
└── src
└── main.cpp
And the following Makefile (which was copied from this post, and edited a little bit by me, to adequate to my project):
# Compiler flags
CXX := g++
CXXFLAGS := -Wall -Werror -Wextra
# Project files
SRC_DIR := src
SRCS := $(wildcard $(SRC_DIR)/*.cpp)
INC_DIR := inc
INCLUDES := -I $(INC_DIR)
OBJS := $(SRCS:.cpp:=.o)
EXE := <ProgramName>
BUILD_DIR := out
# Debug build settings
DBGDIR := $(BUILD_DIR)/debug
DBGEXE := $(DBGDIR)/$(EXE)
DBGOBJS := $(addprefix $(DBGDIR)/, $(OBJS))
DBGCXXFLAGS := -g -O0 -DDEBUG
# Release build settings
RELDIR := $(BUILD_DIR)/release
RELEXE := $(RELDIR)/$(EXE)
RELOBJS := $(addprefix $(RELDIR)/, $(OBJS))
RELCXXFLAGS := -O3 -DNDEBUG
.PHONY: all clean debug prep release remake
# Default build
all: prep release
# Debug rules
debug: $(DBGEXE)
$(DBGEXE): $(DBGOBJS)
$(CXX) $(CXXFLAGS) $(DBGCXXFLAGS) -o $(DBGEXE) $^
$(DBGDIR)/%.o: $(SRC_DIR)/%.cpp
#echo $#
$(CXX) -c $(CXXFLAGS) $(DBGCXXFLAGS) -o $# $<
# Release rules
release: $(RELEXE)
$(RELEXE): $(RELOBJS)
$(CXX) $(CXXFLAGS) $(RELCXXFLAGS) -o $(RELEXE) $^
$(RELDIR)/%.o: $(SRC_DIR)%.cpp
$(CXX) -c $(CXXFLAGS) $(RELCXXFLAGS) -o $# $<
# Other rules
prep:
#mkdir -p $(DBGDIR) $(RELDIR)
remake: clean all
clean:
#rm -rf $(RELEXE) $(RELOBJS) $(DBGEXE) $(DBGOBJS)
#echo "Cleaned!"
Produces the following error:
make: *** No rule to make target 'out/release/src/main.cpp', needed by 'out/release/<ProgramName>'. Stop.
Where is the issue? And when does make assume that the directory of the source files is in '/out/release'? I'm still a noob writing makefiles, I've always been a little bit lazy and used Visual Studio even when targeting linux.
Any help is vastly appreciated!!
You have a couple of small errors.
OBJS := $(SRCS:.cpp:=.o)
You have an extra colon. As written, you change all instances of .cc:, but there are none, so OBJS is src/main.cpp.
You probably meant this:
OBJS := $(SRCS:.cpp=.o)
But this gives src/main.o. You probably did not intend to keep the path. You can correct that with another line:
OBJS := $(notdir $(OBJS))
Then here:
$(RELDIR)/%.o: $(SRC_DIR)%.cpp
...
You are missing a slash. The correct line is
$(RELDIR)/%.o: $(SRC_DIR)/%.cpp
...
The rule as written searches for a file that doesn't exist.
You can detect such errors yourself -- and correct them as you develop the makefile -- with diagnostics like this:
$(info OBJS is $(OBJS))
$(info RELOBJS is $(RELOBJS))
Write a small makefile that works perfectly, then add complexity a little at a time, testing at every step, and never add to code that doesn't work.

C++ Makefile path include and src directory makefile

I'm trying to create a Makefile for my C++ project, which has the following structure:
root
├── include/
| └──external
| └── stb_image.h
│ └── all .h files here
├── src/
| └── main.cpp
│ └── all .cpp files here
└── Makefile
To compile this project, I'm trying to use the Makefile proposed in this answer, which is for gcc, but I have added CC:=g++ so it should work (I think):
SRC_DIR := src
OBJ_DIR := obj
BIN_DIR := bin
EXE := $(BIN_DIR)/color
SRC := $(wildcard $(SRC_DIR)/*.cpp)
OBJ := $(SRC:$(SRC_DIR)/%.cpp=$(OBJ_DIR)/%.o)
CPPFLAGS := -Iinclude -MMD -MP
CFLAGS := -g -std=c++2a -Wall
LDFLAGS := -Llib
LDLIBS := -lpthread
CC := g++
.PHONY: all clean
all: $(EXE)
$(EXE): $(OBJ) | $(BIN_DIR)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp | $(OBJ_DIR)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
$(BIN_DIR) $(OBJ_DIR):
mkdir -p $#
clean:
#$(RM) -rv $(BIN_DIR) $(OBJ_DIR)
-include $(OBJ:.o=.d)
But when running make I obtain a very long error which I do not understand. I do not know if this error comes from having main.cpp without a main.h.
I need this makefile because I want to separate the declarations and the implementations of my project. Before doing that, I had everything done in headers files and I could compile my project with the following command:
g++ -g -std=c++2a -Wall -Isrc/include -o bin/color.exe src/main.cc -lpthread
Any idea what am I doing wrong? I still do not know a lot about Makefiles, so maybe I'm doing something weird.

Generic Makefile build directory error

I have the following directory structure for a dummy C project.
.
├── inc
│   ├── getmsg.c
│   └── getmsg.h
├── makefile
└── src
└── main.c
My current generic Makefile is below,
TARGET = main
# finds all .c files, inc/getmsg.c src/main.c
SOURCES := $(shell find * -name *.c)
# converts all .c files to .o files, inc/getmsg.o src/main.o
OBJECTS := $(SOURCES:.c=.o)
# directories that contain .h files for gcc -I flag, inc/
HEADERS := $(dir $(shell find * -name *.h))
CC = gcc
CFLAGS = -Wall -std=c99 -iquote "$(HEADERS)"
all: $(TARGET)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
$(TARGET): $(OBJECTS)
$(CC) -o $# $^
clean:
rm -rf $(shell find * -name *.o) $(TARGET)
This all compiles fine however it just dumps the .o files into the same directory as its corresponding .c file.
What I would like to do is have all object files put into a build directory. To do this I change the OBJECTS to OBJECTS := $(patsubst %,build/%,$(notdir $(SOURCES:.c=.o))) which lists the files build/getmsg.o build/main.o. Then I set the %.o target to build/%.o: %.c.
This however returns No rule to make target 'build/getmsg.o'. So the make file is unable to build the .o files. What am I missing here?
Try changing
%.o: %.c
to
build/%.o: %.c

Makefile - move object files

After a bit of searching, I've managed to throw together the following Makefile:
CC = gcc
CFLAGS = -c -Wall
LDFLAGS =
SOURCEFILES = main.c
SOURCES = src/$(SOURCEFILES)
OBJECTS = $(SOURCES:.c=.o)
EXECUTABLE = netsim
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.c.o:
$(CC) $(CFLAGS) $< -o $#
clean:
rm -rf netsim $(OBJECTS)
I would like to be able to move my object files into another directory, but have been struggling with getting that to work. What am I missing?
The trick is to not move your objects.
You should build it and use it from where they are built.
For example you have the following directory structure:
$ tree .
├── Makefile
├── include
│   └── common_head.h
├── obj
└── src
├── foo.c
└── main.c
Manual execution:
$ gcc -o ./obj/foo.o -c ./src/foo.c -I ./include # Build Object #
$ gcc -o ./obj/main.o -c ./src/main.c -I ./include
$ gcc -o exe ./obj/foo.o ./obj/main.o # Build Executable #
Makefile to simulate the above
C_FLAGS := -g -Wall -Wextra
CC := gcc
RM := rm
LINKFLAGS := -lanylibrary
.PHONY: $(TARGET)
.PHONY: clean
VPATH:= ./src/ ./obj/ ./include/
# Path for .c , .h and .o Files
SRC_PATH := ./src/
OBJ_PATH := ./obj/
INC_PATH := -I ./include
# Executable Name
TARGET := exe
# Files to compile
OBJ1 := foo.o \
main.o
OBJ := $(patsubst %,$(OBJ_PATH)%,$(OBJ1))
# Build .o first
$(OBJ_PATH)%.o: $(SRC_PATH)%.c
#echo [CC] $<
#$(CC) $(C_FLAGS) -o $# -c $< $(INC_PATH)
# Build final Binary
$(TARGET): $(OBJ)
#echo [INFO] Creating Binary Executable [$(TARGET)]
#$(CC) -o $# $^ $(LINKFLAGS)
# Clean all the object files and the binary
clean:
#echo "[Cleaning]"
#$(RM) -rfv $(OBJ_PATH)*
#$(RM) -rfv $(TARGET)
So when you do a Make
$ make -B
[CC] src/foo.c
[CC] src/main.c
[INFO] Creating Binary Executable [exe]
To see a dry-run use make -n
$ make clean ; make -n
g++ -g -Wall -Wextra -o obj/foo.o -c src/foo.c -I ./include
g++ -g -Wall -Wextra -o obj/main.o -c src/main.c -I ./include
g++ -o exe obj/foo.o obj/main.o -lanylibrary
So after building your directory structure should look like this.
$ tree .
├── Makefile
├── exe
├── include
│   └── common_head.h
├── obj
│   ├── foo.o
│   └── main.o
└── src
├── foo.c
└── main.c
So from my previous answer.
You don't have to use any PHONY move and also no objects are recreated unnecessarily.
Something like this?
SOURCES = src/main.c
OBJECTS = obj/main.o
...
obj/%.o: src/%.c
$(CC) $(CFLAGS) $< -o $#
Once that's working, you can add further tricks, like this:
OBJECTS = $(patsubst src/%.c, obj/%.o, $(SOURCES)

Resources