How to create rule for .o files from 2 different folders with .c files using makefile - 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.

Related

Building A Dependency List with GCC and Make

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?

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

Create Directory using MakeFile

I wrote a MakeFile, but I need it to create folder OBJ, so, for this, I tried a lot of things... based on this link:
https://stackoverflow.com/questions/ask
So, that is my makefile
IDIR =.
CC=gcc
CFLAGS=-I$(IDIR) -Wall -g
SRCDIR=src
ODIR=obj
LIBS=-ltest
_OBJ = main.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
OUTPUTDIR = ../bin
$(ODIR)/%.o: $(SRCDIR)/%.c
$(CC) -c -o $# $< $(CFLAGS)
$(OUTPUTDIR)/test: $(OBJ)
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
I need to create the obj folder, I tried that idea:
OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)
$(OBJDIR)/%.o : %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
all: $(OBJS)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
mkdir -p $(OBJDIR)
and this:
MKDIR_P = mkdir -p
.PHONY: directories
all: directories program
directories: ${OUT_DIR}
${OUT_DIR}:
${MKDIR_P} ${OUT_DIR}
But apparently every time I called the makefile, it ignored the command to create the directory OBJ and began compiling directly...
How I can make to makefile create the directory?
Another approach is to have a dummy variable that evaluates early in the parse of the Makefile and produces the required folder.
ODIR = obj_64
dummy_build_folder := $(shell mkdir -p $(ODIR))
Then the rest of the Makefile can safely assume that $(ODIR) exists.
I've used this on various Linux flavors, and Solaris, with GNU Make 3.81.
Try this:
OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)
$(OBJDIR)/%.o : %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
all: $(OBJS)
$(OBJS): | $(OBJDIR)
$(OBJDIR): FORCE
mkdir -p $(OBJDIR)
FORCE:

Why is makefile recompiling entire set of files if I only change one?

Here is my makefile... Why does it recompile all sources even if only one changes??
CC = g++
CFLAGS = -w -g -c
LIBS = -lm
EXEC = DFMS_PDS_L2_to_L3
.PHONY : clean tgz wdtgz
HOMEDIR = ../
BIN = bin
SRC = src
OBJ = obj
SRCFILES := $(wildcard $(SRC)/*.cc)
OBJFILES := $(patsubst %.cc, $(OBJ)/%.o, $(notdir $(SRCFILES)))
OBJS := $(patsubst %.cc, %.o, $(notdir $(SRCFILES)))
# Executable Targets
all: $(EXEC)
$(EXEC) : $(OBJS)
$(CC) $(LIBS) $(OBJFILES) -o $(BIN)/$(EXEC)
# Dependencies
%.o: $(SRC)/%.cc
$(CC) $< $(CFLAGS) -o $(OBJ)/$#
# Miscellaneous Targets
clean:
rm -rf $(BIN)/$(EXEC) obj/*.o *~
tgz:
tar cvzf $(HOMEDIR)cppbuild.tgz $(HOMEDIR)cppbuild --exclude=data
cp $(HOMEDIR)cppbuild.tgz $(HOMEDIR)cppbuild.tgz.allow
wdtgz:
tar cvzf $(HOMEDIR)cppbuild.tgz $(HOMEDIR)cppbuild
cp $(HOMEDIR)cppbuild.tgz $(HOMEDIR)cppbuild.tgz.allow
I'm running on Linux 3.0 with gnu make
Is it in the $(EXEC) definition?
My guess is that this recompiles all of the sources even if none changes.
Look at these two rules:
$(EXEC) : $(OBJS)
$(CC) $(LIBS) $(OBJFILES) -o $(BIN)/$(EXEC)
%.o: $(SRC)/%.cc
$(CC) $< $(CFLAGS) -o $(OBJ)/$#
Suppose foo.cc is the only source file. The first rule says that the target depends on foo.o, but actually builds it from obj/foo.o. The second can be invoked to build foo.o (which the first rule demands), but it actually builds obj/foo.o. So the first time you run Make it will build the executable correctly (and obj/foo.o). But every time thereafter, Make sees that foo.o does not exist and attempts to build it and rebuild the executable.
The solution is to rewrite the rules so that they build -- and depend on -- what they claim:
all: $(BIN)/$(EXEC)
$(BIN)/$(EXEC) : $(OBJFILES)
$(CC) $(LIBS) $^ -o $#
$(OBJ)/%.o: $(SRC)/%.cc
$(CC) $< $(CFLAGS) -o $#

Resources