Building A Dependency List with GCC and Make - makefile

There appear to be multiple weird ways to do this, and it combines a lot of things in make that I don't quite understand. My folder structure is as follows.
src
| - utils
| - utils.h
| - utils.c
| - buffer.c
| - json.c
| - middleware
| - middleware.h
| - middleware.c
| - server
| - etc
tests
| - utils.c
| - middleware.c
| - server.c
Every folder under src is a library. and all files under that folder comprise the library.
For every library there is a respective .c file, under the tests dir, which will become an executable that can run each of those tests.
Any library can depend on other libraries, so I want to ensure that with make, when I make a change, the dependency tree is rebuilt, and each library retested that has a modification in a dependent file.
Here is what I have tried. I am leaving out quite obvious or irrelevant things for brevity.
OBJS := $(patsubst $(SRCDIR)/%.c,$(OBJDIR)/%.o,$(wildcard $(SRCDIR)/*/*.c))
INCS := $(patsubst $(SRCDIR)/%.h,$(INCDIR)/%.h,$(wildcard $(SRCDIR)/*/*.h))
IMMM := $(patsubst $(OBJDIR)/%.o,$(LIBDIR)/%.a,$(foreach LIB,$(LLIST),$(filter $(OBJDIR)/$(LIB)/$(LIB).o,$(OBJS))))
LIBS := $(foreach PRE,$(LLIST),$(subst $(PRE)/,lib,$(filter $(LIBDIR)/$(PRE)/$(PRE).a,$(IMMM))))
LINK := $(foreach LIB,$(LLIST),-l$(LIB))
TSTO := $(patsubst $(TSTDIR)/%.c,$(OBJDIR)/$(TSTDIR)/%.o, $(wildcard $(TSTDIR)/*.c))
TSTE := $(foreach LIB,$(LLIST),$(TGTDIR)/$(LIB).exe)
DEPS := $(OBJS:.o=.d)
DEPT := $(TSTO:.o=.d)
.PHONY: all
all: $(TGTDIR)/$(TGT)
$(TGTDIR)/$(TGT): $(LIBS) | tests
$(CC) -o $# bench/main.c $(LIBS)
tests: $(TSTE)
for test in $^ ; do \
chmod +x ./$${test} ; \
./$${test}; \
done
$(TSTE): $(TSTO) $(DEPT) | $(OBJS)
#mkdir -p $(#D)
$(CC) -o $# $(OBJS) $(filter $(OBJDIR)/$(TSTDIR)/$(basename $(notdir $#)).o, $(TSTO))
$(OBJDIR)/$(TSTDIR)/%.o: $(TSTDIR)/%.c
#mkdir -p $(#D)
$(CC) -o $# -c $<
$(OBJDIR)/$(TSTDIR)/%.d: $(TSTDIR)/%.c
#mkdir -p $(#D)
$(CC) -MM -MG $< $(CFLAGS)
$(LIBS): $(OBJS)
#mkdir -p $(#D)
$(AR) rcs $# $(filter $(subst lib,$(OBJDIR)/, $(basename $(notdir $#)))/%.o, $(OBJS))
$(OBJDIR)/%.o: $(SRCDIR)/%.c | folders
#mkdir -p $(#D)
$(CC) -o $# -c $<
$(OBJDIR)/%.d: $(SRCDIR)/%.c | folders
#mkdir -p $(#D)
$(CC) -MM -MG $< $(CFLAGS)
The output for deps and dept are:
deps => obj/middleware/middleware.d obj/utils/utils.d
dept => obj/tests/middleware.d obj/tests/utils.d
All of the test dependencies are getting listed correctly.
gcc -MM -MG tests/middleware.c -Wall -O0 -std=c11 -DDEBUG -g outputs
middleware.o: tests/middleware.c tests/../src/middleware/middleware.h
However, I don't see the bug, why my $(OBJDIR)/%.d `$(DEPS) dependencies are not being ran.
So,
I'm not sure what sed command I need to get the desired output from (CC) -MM -MG $< $(CFLAGS)
Do I need the -include: $(DEPS) and `-include: $(DEPT) where does that go?
Where is the bug not allowing $(DEPS) target to run?
Is there anything else I'm missing?

Related

How to create rule for .o files from 2 different folders with .c files using makefile

I want to have the possibility to build output files from different folders depending on the command.
./source_files/ - folder with *.c files for make build2 and make unit_test commands.
./source_files/unit_test/ - folder with *.c files for make unit_testcommands
I have 2 commands:
this works - command make build2 should take files ./source_files/*.c, make ./build/*.o from them and create <name.a> library;
this doesn't work - command make unit_test should take files ./source_files/*.c and also ./source_files/unit_tests/*.c make ./build/*.o from them and create test.out file.
make unit_test generates the output:
make: *** No rule to make target 'build/test_main.o', needed by 'unit_test'. Stop.
I have 2 rules for *.o files. I guess I have to combine them into one, but I have no idea how to do that. Can you help me with it, please?
$(BUILDDIR)/%.o: $(SRCDIR)/%.c | $(BUILDDIR)
$(CC) -c $< $(INCLDIR) -o $#
$(BUILDDIR)/%.o: $(UNITSRCS)/%.c | $(BUILDDIR)
$(CC) -c $< $(INCLDIR) -o $#
makefile:
#Compiler flags
CC := gcc
INCLDIR := -I./includes
LIBS := -lcunit
#Directories and files
BUILDDIR := build
SRCDIR := source_files
SRCS := $(wildcard $(SRCDIR)/*.c)
OBJS := $(SRCS:$(SRCDIR)/%.c=$(BUILDDIR)/%.o)
UNITDIR := $(SRCDIR)/unit_tests
UNITSRCS := $(wildcard $(UNITDIR)/*.c)
UNITOBJS := $(UNITSRCS:$(UNITDIR)/%.c=$(BUILDDIR)/%.o)
STLIB := $(BUILDDIR)/libbinary_tree.a
$(BUILDDIR):
mkdir $(BUILDDIR)
$(BUILDDIR)/%.o: $(SRCDIR)/%.c | $(BUILDDIR)
$(CC) -c $< $(INCLDIR) -o $#
$(BUILDDIR)/%.o: $(UNITSRCS)/%.c | $(BUILDDIR)
$(CC) -c $< $(INCLDIR) -o $#
.PHONY: unit_test
unit_test: $(OBJS) $(UNITOBJS)
$(CC) $(OBJS) $(UNITOBJS) $(INCLDIR) $(LIBS) -o $(BUILDDIR)/test_main.out
.PHONY: build2
build2: $(OBJS)
ar -rcs $(STLIB) $(OBJS)
.PHONY: clean
clean:
rm -r $(BUILDDIR)
This rule is OK:
$(BUILDDIR)/%.o: $(SRCDIR)/%.c | $(BUILDDIR)
$(CC) -c $< $(INCLDIR) -o $#
But this rule is wrong:
$(BUILDDIR)/%.o: $(UNITSRCS)/%.c | $(BUILDDIR)
$(CC) -c $< $(INCLDIR) -o $#
Just as in the first rule, you want to have $(UNITDIR)/%.c not $(UNITSRCS)/%.c. After make expands the variable the latter will clearly be wrong.

How to compile source objects into another directory and then build an executable?

Good day. I am in a directory, where is Makefile and folders src and bin. How can I compile object files into bin folder and then build an executable file?
I read some instructions and added $(BIN) before %.o, but it didn't helped, object files appear in folder with makefile. Where is the problem?
CC = arm-linux-gnueabihf-gcc
CXX = arm-linux-gnueabihf-g++
CPPFLAGS = -I .
CFLAGS =-g -std=gnu99 -O1 -Wall
CXXFLAGS = -g -std=gnu++11 -O1 -Wall
LDFLAGS = -lrt -lpthread
SRCDIR = src
BIN = bin
SOURCES = $(wildcard $(SRCDIR)/*.cpp) $(wildcard $(SRCDIR)/*.c)*
...
OBJECTS += $(filter %.o,$(SOURCES:%.c=%.o))
OBJECTS += $(filter %.o,$(SOURCES:%.cpp=%.o))
#$(warning OBJECTS=$(OBJECTS))
ifeq ($(filter %.cpp,$(SOURCES)),)
LINKER = $(CC)
LDFLAGS += $(CFLAGS) $(CPPFLAGS)
else
LINKER = $(CXX)
LDFLAGS += $(CXXFLAGS) $(CPPFLAGS)
endif
$(BIN)/%.o:%.c
$(CC) $(CFLAGS) -c $<
$(BIN)/%.o:%.cpp
$(CXX) $(CXXFLAGS) -c $<
all: $(TARGET_EXE)
$(TARGET_EXE): $(OBJECTS)
$(LINKER) $(LDFLAGS) -L. $^ -o $#
.PHONY : dep all run copy-executable debug
dep: depend
depend: $(SOURCES) *.h
echo '# autogenerat`enter code here`ed dependencies' > depend
ifneq ($(filter %.c,$(SOURCES)),)
$(CC) $(CFLAGS) $(CPPFLAGS) -w -E -M $(filter %.c,$(SOURCES)) \
>> depend
endif
ifneq ($(filter %.cpp,$(SOURCES)),)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -w -E -M $(filter %.cpp,$(SOURCES)) \
>> depend
endif
clean:
rm -f *.o *.a $(OBJECTS) $(TARGET_EXE) connect.gdb depend
...
It's not clear to me how this makefile can works as well as it does, given that you haven't told it where to find the source files (unless you do so in one of the elided sections).
In these rules:
$(BIN)/%.o:%.c
$(CC) $(CFLAGS) -c $<
$(BIN)/%.o:%.cpp
$(CXX) $(CXXFLAGS) -c $<
you tell the compiler to build object files, but you don't specify where to build them, and the default is to build them in the working directory. You can override that with the -o option:
$(BIN)/%.o:%.c
$(CC) $(CFLAGS) -c $< -o $#
$(BIN)/%.o:%.cpp
$(CXX) $(CXXFLAGS) -c $< -o $#
Once you have the object files where you want them (bin/), you must ensure that the linking rule:
$(TARGET_EXE):$(OBJECTS)
$(LINKER) $(LDFLAGS) -L. $^ -o $#
can find them. The best way to do that is to ensure that OBJECTS contains the correct paths to the object files. I'm not sure how to advise you to do that, since from the look of your makefile that variable might not contain what you think it does.
EDIT:
Let's take this in stages.
Suppose we have on source file, src/foo.c. What we want is:
src/foo.c -> bin/foo.o
bin/foo.o -> foo
This requires two rules, which we can write like this:
$(BIN)/%.o: src/%.c
$(CC) $(CFLAGS) -c $< -o $#
$(TARGET_EXE): bin/foo.o
$(LINKER) $(LDFLAGS) -L. $^ -o $#
We actually have many source files, some of which are C++ files. So we must have a rule for them:
$(BIN)/%.o: src/%.cpp
$(CXX) $(CXXFLAGS) -c $< -o $#
and construct a longer list of objects:
OBJECTS := bin/foo.o bin/bar.o bin/baz.o bin/quartz.o...
$(TARGET_EXE): $(OBJECTS)
$(LINKER) $(LDFLAGS) -L. $^ -o $#
(Mixing C and C++ seems unhealthy to me, but never mind.)
And how do we construct that list of objects? We must start with the list of sources which wildcard can produce:
SRC := src
C_SOURCES := $(wildcard $(SRC/*.c)
# this is src/foo.c src/bar.c
SRC := src
CPP_SOURCES := $(wildcard $(SRC/*.cpp)
# this is src/baz.cpp src/quartz.cpp
and then convert them to the object file names we actually want:
BIN := bin
OBJECTS := $(patsubst $(SRC)/%.cpp,$(BIN)/%.o, $(CPP_SOURCES))
OBJECTS += $(patsubst $(SRC)/%.c,$(BIN)/%.o, $(C_SOURCES))
# this is bin/foo.o bin/bar.o bin/baz.o bin/quartz.o
That should give you the effect you want, and if you understand it you will understan why your old makefile did not.

makefile parse target to define dependencies

I have source files in several directories and I want to compile them in a one unique temporary directory, currently I use this target to create my object files :
$(BUILD_DIR)/%.o :
#echo "Compiling $#"
$(VERBOSE) $(CC) $(CFLAGS) -c $(DEFINES) $(INCLUDES) -o $# $(shell echo "$(SOURCES)" | sed 's/ /\n/g' | sed -nr '/\/$(*F)\.c/p')
It is working well but when I modify a source file, the object one is not recompiled. So I have to add the source file to the dependencies.
But this target doesn't work :
$(BUILD_DIR)/%.o : $(shell echo "$(SOURCES)" | sed 's/ /\n/g' | sed -nr '/\/$(*F)\.c/p')
#echo "Compiling $#"
$(VERBOSE) $(CC) $(CFLAGS) -c $(DEFINES) $(INCLUDES) -o $# $^
Is there any way to use target name in dependencies ?
Assuming you are using GNU Make...
Use a pattern rule like:
obj/%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
to tell make that an object file obj/<name>.o is to be compiled from a source file
<name>.c
In conjunction with this, use the VPATH special variable
to inform make of directories in which it should look for any <name>.c, if it is not
in the current directory.
Also, add an order-only prerequisite
to the pattern rule to ensure that the directory (obj) to which your object files are compiled
exists when needed:
obj/%.o: %.c | obj
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
So for example, with project structure:
./
-- Makefile
-- aa/
-- main.c
-- bb/
-- foo.c
-- obj/ #<-- Compile object files in here
-- prog #<- program to be built
And:
Makefile
VPATH := aa:bb
SRCS := foo.c main.c
OBJS := $(addprefix obj/, $(SRCS:.c=.o))
.PHONY: all clean
all: prog
prog: $(OBJS)
$(CC) $(LDFLAGS) -o $# $^ $(LDLIBS)
obj/%.o: %.c | obj
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
obj:
mkdir $#
clean:
$(RM) $(OBJS) prog
the build runs like:
$ make
cc -c -o obj/foo.o bb/foo.c
cc -c -o obj/main.o aa/main.c
cc -o prog obj/foo.o obj/main.o

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)"
...

Automatic dependency list not generated in a different setting of directory structure

I have the following directory structure:
root-----Makefile
|-----src #all source files here.
|-----obj #all object files here.
|-----bin #the final target.
The contents of Makefile is given below:
TARGET = exec
CC = gcc
CFLAGS = -g -I.
LINKER = gcc -o
LFLAGS = -I. -lm -lpthread
BINDIR = bin
OBJDIR = obj
SRCDIR = src
INTERFACE = interface
STD = -std=c99
PROGRAMSOURCES := $(wildcard $(SRCDIR)/*.c)
PROGRAMINTERFACE:= $(wildcard $(INTERFACE)/*.h)
OBJECTS := $(PROGRAMSOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
$(BINDIR)/$(TARGET) : $(OBJECTS)
$(LINKER) $# $(LFLAGS) $(OBJECTS) $(STD)
#pull the dependencies to the .o files
-include $(OBJECTS:.o=.d)
$(OBJECTS) : $(OBJDIR)/%.o :$(SRCDIR)/%.c
$(CC) $(CFLAGS) -c $< -o $# $(STD)
$(CC) $(CFLAGS) -MM $< > $*.d
#mv -f $*.d $*.d.tmp
#sed -e 's|.*:|$(OBJDIR)/$*.o:|' < $*.d.tmp > $*.d
#sed -e 's/.*://' -e 's/\\$$//' < $*.d.tmp | fmt -1 | \
sed -e 's/^ *//' -e 's/$$/:/' >> $*.d`
#rm -f $*.d.tmp`
.PHONY : run
run :`
./$(BINDIR)/$(TARGET) ${TYPE} ${INP_FILE}
I have used the tutorial here have been modified to suit the corresponding directory structure. But something has got wrong in the modification and I cannot understand what. The dependency list generated in the .d files is not taken into account i.e. if I change a .h the rules are not compiling.
You appear to be producing the dependency files in root/, but looking for them in obj/.
Try changing this:
-include $(OBJECTS:.o=.d)
to this:
-include *.d
There are other improvements you can make, once the makefile is working.
EDIT: further improvements
1) The choice of where to put the dependency files is mainly arbitrary, but if we put them in obj/, we can simplify the $(OBJECTS) rule quite a lot:
-include $(OBJDIR)/*.d
$(OBJECTS): $(OBJDIR)/%.o :$(SRCDIR)/%.c
$(CC) $(CFLAGS) -MMD -MP -c $< -o $# $(STD)
2) PROGRAMINTERFACE and INTERFACE aren't used, so we can remove them.
3) Putting -o in LINKER like that is dangerous. And don't forget the automatic variable $^:
LINKER = gcc
$(BINDIR)/$(TARGET) : $(OBJECTS)
$(LINKER) $# $(LFLAGS) $^ $(STD)
4) It would be wise to give run a prerequisite:
run: $(BINDIR)/$(TARGET)
./$< ${TYPE} ${INP_FILE}

Resources