In expansion to my previous question how to write a makefile for structured file system:
The file structure:
.
├── Headers
│ ├── function.h
│ └── test.h
├── makefile
├── README.md
└── Sources
├── function.c
├── main.c
└── test.c
I'm trying to write a makefile that reads the #include<...> on any given source file and compile as required.
Originally I used to have a make file that looked like this:
INC_DIR = Headers
SRC_DIR = Sources
OBJ_DIR = Objects
#CXXFLAGS = -c -Wall -I. -IHeaders
CXXFLAGS = -c -Wall -I. -IHeaders
CC = gcc
SRCS = $(SRC_DIR)/*.c
OBJS = $(OBJ_DIR)/*.o
#The wildcard and patsubt commads will come handy
DEPS = $(INC_DIR)/*.h
#need to use an automatic dependency generator
output: $(OBJ_DIR)/main.o $(OBJ_DIR)/function.o
$(CC) $^ -o $#
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(DEPS)
$(CC) $(CXXFLAGS) $< -o $#
run: output
./output
clean:
rm $(OBJ_DIR)/*.o
rm output
-#echo "Clean completed"
That meant that for every source file that output was dependent on i had to add that object to this line.
output: $(OBJ_DIR)/main.o $(OBJ_DIR)/function.o $(OBJ_DIR)/test.o
$(CC) $^ -o $#
And is any other source file was dependent on one or more sources additional rules had to be added.
To solve this:
here is what I have gathered from Auto-Dependency Generation and 4.14 Generating Prerequisites Automatically
As mentioned by the community members, I have a mixed understanding of dependency generation and how to make use of the files generated.
DEP_DIR = .d
$(shell mkdir -p $(DEP_DIR) >/dev/null)
DEPFLAGS = -MT $# -MMD -MP -MF $(DEP_DIR)/$*.Td
INC_DIR = Headers
SRC_DIR = Sources
OBJ_DIR = Objects
$(shell mkdir -p $(OBJ_DIR) >/dev/null)
CXXFLAGS = -c -Wall -I. -IHeaders
CC = gcc
SRCS = $(SRC_DIR)/*.c
OBJS = $(OBJ_DIR)/*.o
#The wildcard and patsubt commads will come handy
#DEPS = $(INC_DIR)/*.h
MAKEDEPEND = $(CC) $(CXXFLAGS) $< \
| sed -n 's/^\# *[0-9][0-9]* *"\([^"]*\)".*/$*.o: \1/p' \
| sort | uniq > $*.Td
COMPILE.c = $(CC) $(DEPFLAGS) $(CXXFLAGS)
#need to use an automatic dependency generator
#%.d: %.c
# #set -e; rm -f $#; \
# $(CC) -MP -MD $(CXXFLAGS) $< > $#.$$$$; \
# sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
# rm -f $#.$$$$
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(DEP_DIR)/%.d
#$(MAKEDEPEND); \
cp $*.Td $*.d; \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $*.Td >> $*.d; \
rm -f $*.Td
#$(COMPILE.c) -o $# $<
$(CC) $(CXXFLAGS) $(DEPFLAGS) $< -o $#
-include $(SRCS:.c=.d)
$(DEP_DIR)/%.d: ;
.PRECIOUS: $(DEP_DIR)/%.d
output: $(OBJS)
$(CC) $^ -o $#
run: output
./output
clean:
rm -r $(OBJ_DIR)
rm -r $(DEP_DIR)
rm output
-#echo "Clean completed"
The error when make is executed is:
$ make
gcc -c -Wall -I. -IHeaders -MT Objects/*.o -MMD -MP -MF .d/*.Td Sources/function.c -o Objects/*.o
gcc Objects/*.o -o output
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
makefile:48: recipe for target 'output' failed
make: *** [output] Error 1
So, I'm hoping to achieve the auto dependency detection and compilation. I think the error is in the way that the dependencies are detected and the way they are generated for a given source file.
It looks to me like you're trying to combine multiple different ways of generating dependency info, and that can't work. The advanced post talks about multiple ways to solve the problem: you need to pick one not try to use them all together.
If you want to use the advanced method then use it as described in the "TL;DR" section at the top, or else in the "Combining Compilation and Dependency Generation" section at the bottom. If you're using GCC there's no need for MAKEDEPEND, sed, etc.
The advanced post says that your rule should look like this:
COMPILE.c = $(CC) $(DEPFLAGS) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
POSTCOMPILE = mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d
%.o : %.c
%.o : %.c $(DEPDIR)/%.d
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(POSTCOMPILE)
That's it.
Related
I have this makefile:
IDIR = include
SDIR = src
ODIR = obj
BDIR = build
DEPS = $(shell find $(IDIR)/ -name '*.hpp')
SRCS = $(shell find $(SDIR)/ -name '*.cpp')
OBJS = $(patsubst %.cpp,$(ODIR)/%.o,$(notdir $(SRCS)))
BIN = main
CPPC = g++
CFLAGS = -Wall -c
all: dir $(BDIR)/$(BIN)
#echo Finished compiling $(BIN)
dir:
mkdir -p $(BDIR)
mkdir -p $(ODIR)
$(BDIR)/$(BIN): $(OBJS)
$(CPPC) $^ -o $#
$(OBJS): $(SRCS)
$(CPPC) $(CFLAGS) $^ -o $#
clean:
rm -rf $(BDIR) $(ODIR)
When I try to make, I get the following error:
mkdir -p build
mkdir -p obj
g++ -Wall -c src/sdk/tcp/Tcp.cpp src/sdk/socket/Socket.cpp src/Main.cpp -o obj/Tcp.o
g++: fatal error: cannot specify ‘-o’ with ‘-c’, ‘-S’ or ‘-E’ with multiple files
compilation terminated.
make: *** [Makefile:27: obj/Tcp.o] Error 1
My question is, is it possible to achieve what I am trying with this makefile? Going through each source file in $(SRCS), and compile the object file directly inside the obj directory with just the basename. An example of obj directory after a successful compilation:
obj
/ | \
/ | \
Tcp.o Socket.o Main.o
Your $(OBJS) rule is wrong.
There are (at least) two ways to do this.
You could write a pattern rule and use vpath to locate the sources:
vpath %.cpp $(dir $(SRCS))
$(OBJS): obj/%.o: %.cpp
$(CPPC) $(CFLAGS) $^ -o $#
Or you could generate a rule for each object:
define template
$(patsubst %,obj/%.o,$(notdir $(1))): $(addsuffix .cpp,$(1))
echo $(CPPC) $(CFLAGS) $$^ -o $$#
endef
$(foreach src,$(SRCS),$(eval $(call template,$(basename $(src)))))
I have a really strange issue with the Makefile in one of my off-time projects.
I have a Makefile (shown below) that generates dependency information in .d files following https://www.gnu.org/software/make/manual/html_node/Automatic-Prerequisites.html.
The problem is that a change in one of my header files (shader.h) does not trigger the recompilation of shader.o (out of shader.cpp).
The problem started happening recently when I re-organized the directory structure in my project so I suspect it is related to that.
The strange thing is that if I do make --print-data-base it does seem like it has found the correct prerequisites matching the shader.d file.
The diretory structure is as follows:
|-src
|-engine
|-shader.h
|-shader.cpp
|-bin
|-Debug
|-OpenGLTest
|-obj
|-Debug
|-engine
|-shader.o
|-dep
|-engine
|-shader.d
Makefile:
WORKDIR = `pwd`
CC = gcc
CXX = g++
AR = ar
LD = g++
WINDRES = windres
INC = -I/usr/local/include
CFLAGS = -Wall -Werror
CXX_FLAGS = -std=c++11
RESINC =
LIBDIR = -L/usr/local/lib
LIB = -lSDL2 -lGLEW -framework OpenGL
LDFLAGS =
DEPDIR = dep
SRCDIR = src
INC_DEBUG = $(INC)
CFLAGS_DEBUG = $(CFLAGS) -g
RESINC_DEBUG = $(RESINC)
RCFLAGS_DEBUG = $(RCFLAGS)
LIBDIR_DEBUG = $(LIBDIR)
LIB_DEBUG = $(LIB)
LDFLAGS_DEBUG = $(LDFLAGS)
OBJDIR_DEBUG = obj/Debug
DEP_DEBUG =
OUT_DEBUG = bin/Debug/OpenGLTest
CXX_SRCS = $(wildcard $(SRCDIR)/*.cpp) $(wildcard $(SRCDIR)/**/*.cpp)
CXX_REL_SRCS = $(subst $(SRCDIR)/,,$(CXX_SRCS))
OBJS = $(CXX_REL_SRCS:%.cpp=%.o)
OBJ_DEBUG = $(addprefix $(OBJDIR_DEBUG)/,$(OBJS))
# ----------------------------- debug -----------------------------
clean: clean_debug clean_release
rm -rf $(DEPDIR)
before_debug:
#test -d bin/Debug || mkdir -p bin/Debug
#test -d $(OBJDIR_DEBUG) || mkdir -p $(OBJDIR_DEBUG)
#mkdir -p $(dir $(OBJ_DEBUG))
after_debug:
debug: before_debug out_debug after_debug
out_debug: before_debug $(OBJ_DEBUG) $(DEP_DEBUG)
$(LD) $(LIBDIR_DEBUG) -o $(OUT_DEBUG) $(OBJ_DEBUG) $(LDFLAGS_DEBUG) $(LIB_DEBUG)
$(OBJDIR_DEBUG)/%.o: $(SRCDIR)/%.cpp
$(CXX) $(CFLAGS_DEBUG) $(CXX_FLAGS) $(INC_DEBUG) -c $< -o $#
clean_debug:
rm -f $(OBJ_DEBUG) $(OUT_DEBUG)
rm -rf bin/Debug
rm -rf $(OBJDIR_DEBUG)
# ----------------------------- dependencies -----------------------------
# Generate dependencies in *.d files
$(DEPDIR)/%.d: $(SRCDIR)/%.cpp
#test -d $(DEPDIR) || mkdir -p $(DEPDIR)
#mkdir -p $(dir $#)
#set -e; rm -f $#; \
$(CXX) -MM $(CFLAGS) $(CXX_FLAGS) $(INC) $< > $#.$$$$; \
sed 's,\(.*\)\.o[ :]*,$(OBJDIR_RELEASE)/\1.o $(OBJDIR_DEBUG)/\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
# Include the *.d files
include $(patsubst %,$(DEPDIR)/%.d,$(basename $(CXX_REL_SRCS)))
# ----------------------------- targets -----------------------------
.PHONY: before_debug after_debug clean_debug
all: debug
shader.d:
obj/Debug/shader.o dep/engine/shader.d : src/engine/shader.cpp src/engine/shader.h \
src/engine/transform.h src/engine/camera.h src/engine/constants.h
I'll answer this since the issue has been found by #G.M. in the comments.
Turns out that the dependency generation was flawed.
In shader.d obj/Debug/shader.o should really be obj/Debug/engine/shader.o. Modifying the sed command as shown below fixes this.
sed 's,\(.*\)\.o[ :]*,$(OBJDIR_RELEASE)/$(subst $(SRCDIR)/,,$(dir $<))\1.o $(OBJDIR_DEBUG)/$(subst $(SRCDIR)/,,$(dir $<))\1.o $# : ,g' < $#.$$$$ > $#;
I have written below Makefile and as per answer to this question added rules for header file dependencies but it is not working. I did a clean and then build. After that I modified Parse.h using touch command and ran "make all" it says Test.exe is up to date. I got same output with just "make" command too.
Can anyone please let me know where am I gone wrong.
RM := rm -rf
MKDIR := mkdir -p
FIND := find
CPIO := cpio
CD := cd
MV := mv
# Set compiler flags
ifeq ($(BUILD_TYPE),DEBUG)
COMPILE_FLAGS= -c -fpic -DDBG=1 -g -DUSE_UTLPATMAT=1 -Wall
else ifeq ($(BUILD_TYPE),RELEASE)
COMPILE_FLAGS= -c -fpic -O3 -DUSE_UTLPATMAT=1 -Wall
else ifeq ($(BUILD_TYPE),PERF)
COMPILE_FLAGS= -c -fpic -O3 -DUSE_UTLPATMAT=1 -DPERF_COMPONENT -Wall
else
COMPILE_FLAGS= -c -fpic -O3 -DUSE_UTLPATMAT=1 -Wall
endif
export STFP_HOME = $(shell cd "$(CURDIR)/.."; pwd)
STFP_LIB = $(STFP_HOME)/lib
STFP_BIN = $(STFP_HOME)/bin
$(shell mkdir -p ${STFP_LIB})
$(shell mkdir -p ${STFP_BIN})
STFP_INC = $(CURDIR)/SP
SPTEST_SRC = $(CURDIR)/SPTest
SPTEST_INC = $(CURDIR)/SPTest
STFP_SRC = $(CURDIR)/SP
STFP_INC = $(CURDIR)/SP
UTILITIES_SRC_DIR = $(CURDIR)/../utilities
LIBS= -L${CLIENT_LIB}
INCS_DIRS= -I${CLIENT_INC}
#Subdivision Publisher Test
SPTESTSRCS=\
$(SPTEST_SRC)/Parse.cpp \
$(SPTEST_SRC)/Main.cpp
SPTESTOBJS=$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SPTESTSRCS)))
all := $(STFP_BIN)/Test.exe
#################### Main targets #####################################
all:$(all)
clean:
find $(STFP_SRC)/ -name "*.o" | xargs rm -rf
find $(SPTEST_SRC)/ -name "*.o" | xargs rm -rf
rm -rf $(STFP_LIB)
rm -rf $(STFP_BIN)
#######################################################################
$(STFP_BIN)/Test.exe: $(SPTESTOBJS)
$(CXX) -g $(INCS_DIRS) \
$(SPTESTOBJS) -o $# \
$(LIBS) -lmodpbase64 -lboost_regex -lboost_filesystem -lboost_system -lboost_serialization \
-lutility
%.o : %.cpp
$(CXX) -DPROVIDE_LOG_UTILITIES $(COMPILE_FLAGS) $(INCS_DIRS) -o $# $<
%.o : %.c
$(CC) -DPROVIDE_LOG_UTILITIES $(COMPILE_FLAGS) $(INCS_DIRS) -o $# $<
################# Dependencies #########################
depend: .depend
.depend: $(SPTESTSRCS)
rm -f .depend
$(CXX) -DPROVIDE_LOG_UTILITIES $(COMPILE_FLAGS) $(INCS_DIRS) -MM -$(SPTESTSRCS) > .depend
-include .depend
########################################################
Thanks
You seem to expect .o files in SPTest. You could do so by using:
SPTest/%.o: SPTest/%.cpp
$(CXX) -DPROVIDE_LOG_UTILITIES $(COMPILE_FLAGS) $(INCS_DIRS) -o $# $<
OR by using (where #D is directory and #F is filename):
%.o : %.cpp
$(CXX) -DPROVIDE_LOG_UTILITIES $(COMPILE_FLAGS) $(INCS_DIRS) -o $(#D)/$(#F) $<
Let me know if you still get errors.
I am trying to create a makefile for a project with the following structure:
├──bin/
├──build/
│ ├──foo.d
│ └──bar.d
├──include/
│ └──foo.h
│
├──lib/
├──src/
│ ├──foo.cc
│ └──bar.cc
│
├──Makefile
Here is the makefile:
# Define the compiler and the linker.
CXX = g++
CC = g++
# Folders
srcdir = src
builddir = build
out = bin
# Define preprocessor, compiler, and linker flags.
CPPFLAGS = -I include -std=c++11
LDFLAGS = -g -Llib
# Phony targets
.PHONY: all clean test
# Targets
all : $(out)/bar
$(out)/bar : $(addprefix $(builddir)/,bar.o foo.o)
# Standard clean
clean :
rm -f $(builddir)/*.o $(builddir)/*.d
# Generate dependencies in *.d files
$(builddir)/%.d: $(srcdir)/%.cc
#set -e; rm -f $#; \
$(CPP) -MM $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,$(builddir)/\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$;
deps = $(patsubst $(srcdir)/%.cc,$(builddir)/%.d,$(wildcard $(srcdir)/*.cc))
include $(deps)
The dependency files contain the following:
foo.d
build/foo.o build/foo.d : src/foo.cc include/foo.h
bar.d (depends on foo)
build/bar.o build/bar.d : src/bar.cc include/foo.h
Is there any way to generate the .d files in the build/ directory, compile the object files into the very same folder then compile the bin/bar program? Any help appreciated.
EDIT:
The problem was that I was expecting
all : $(out)/foo
$(out)/foo : $(addprefix $(builddir)/,foo.o bar.o)
$(builddir)/%.o : $(srcdir)/%.cc
$(CXX) -c $< -o $# -MP -MMD -MF $(#:.o=.d)
to magically compile the program foo (it works when all files are in the same folder).
Instead I had to specify the recipe:
all : $(out)/foo
$(out)/foo : $(builddir)/foo.o $(builddir)/bar.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $#
$(builddir)/%.o : $(srcdir)/%.cc
$(CXX) -c $< -o $# -MP -MMD -MF $(#:.o=.d)
Drop all of the sed nonsense. gcc can generate everything in one go:
$(builddir)/%.o : $(srcdir)/%.cc
$(CPP) -c $< -o $# -MP -MMD -MF $(#:.o=.d)
That will in one go build build/foo.o and build/foo.d, where build/foo.d will have the autogenerated dependencies for build/foo.o.
Hi I am using common makefile.inc for my project. For my src folders, I define a makefile which sets some variables and includes makefile.inc. I can also define DIRS= variable (sample #2) which will call make -C on each one of the directories specified there. This all works. However, I cannot get a "clean" or "cleanall" to work properly. If DIRS= is defined, I need a way to go through all the directories listed and call "make -C xxx clean". Any ideas?
Sample makefile #1
TYPE = exe
SOURCES = test.cpp
INCLUDES = -I. -I/usr/local/include -I../src
LIBS = -lpcre
OUT = test
include ../../makefile.inc
Sample makefile #2
DIRS = src test
include ../makefile.inc
makefile.inc
OBJS = $(SOURCES:.cpp=.o)
ifeq ($(CFG),)
CFG=debug
endif
ifeq ($(CFG),debug)
CXXFLAGS += -g -Wall -DNDEBUG
else
CXXFLAGS += -O2 -Wall
endif
all: dirs cfgcheck $(OUT)
.PHONY: clean cleanall all
cfgcheck:
ifneq ($(CFG),release)
ifneq ($(CFG),debug)
#echo "Error: Invalid CFG '$(CFG)'' (options: debug,release)"
#exit 1
endif
endif
#echo "Making '$(CURDIR)' CFG="$(CFG)
$(OUT): $(OBJS)
ifeq ($(TYPE),lib)
$(AR) rcs $(OUT) $(OBJS)
endif
ifeq ($(TYPE),exe)
$(CXX) -o $# $^ ${LDFLAGS} $(LIBS)
endif
-include $(OBJS:.o=.d)
%.o: %.cpp
$(CXX) -c $(INCLUDES) $(CXXFLAGS) $*.cpp -o $*.o
$(CXX) -MM $(CXXFLAGS) $*.cpp > $*.d
#cp -f $*.d $*.d.tmp
#sed -e 's/.*://' -e 's/\\$$//' < $*.d.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $*.d
#rm -f $*.d.tmp
dirs: $(DIRS)
$(DIRS):
$(MAKE) -C $#
clean:
rm -f $(OUT) *.o *.d
I'd do something like this:
DIRS = src test
clean: TARG:=clean
clean: $(DIRS)
.PHONY: $(DIRS)
$(DIRS):
#$(MAKE) -C $# $(TARG)
If you don't like using the names of directories as phony targets, there are alternatives that are slightly more complicated...