I'm trying to write a Makefile for my project that automatically generates the dependencies between my source files.
The Makefile is as follows:
CC = g++
CFLAGS = -std=c++11 -Wfatal-errors -fdiagnostics-color=always
LDFLAGS = -lm -lfftw3
SRCDIR = src
OBJDIR = obj
DEPDIR = dep
SRCS = $(wildcard $(SRCDIR)/*.cpp)
OBJS = $(patsubst $(SRCDIR)/%.cpp,$(OBJDIR)/%.o,$(SRCS))
DEPS = $(patsubst $(SRCDIR)/%.cpp,$(DEPDIR)/%.d,$(SRCS))
PROG = whistle_recognition
$(PROG): $(OBJS)
$(CC) $(CFLAGS) -o$(PROG) $(OBJS) $(LDFLAGS)
.PHONY: clean run
$(DEPS): $(DEPDIR)/%.d : $(SRCDIR)/%.cpp
$(CC) $(CFLAGS) -MM $< -MF $#
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
$(CC) $(CFLAGS) -c $< -o $#
clean:
rm -r $(OBJS) $(DEPS) $(PROG)
run: $(PROG)
./$(PROG)
-include $(DEPS)
Generating the dependencies works fine. However, Make ignores them.
Suppose I have a file foo.cpp that includes the header file quux.h .
If foo.cpp changes Make rebuilds foo.o. However if quux.h changes Make thinks that foo.o is up to date. How can I fix this?
Edit:
Heres more info: output of make -d whistle_recognition | grep signalscanner.d:
Reading makefile 'dep/signalscanner.d' (search path) (don't care) (no ~ expansion)...
Considering target file 'dep/signalscanner.d'.
File 'dep/signalscanner.d' does not exist.
Finished prerequisites of target file 'dep/signalscanner.d'.
Must remake target 'dep/signalscanner.d'.
g++ -std=c++11 -Wfatal-errors -fdiagnostics-color=always -MM src/signalscanner.cpp -MF dep/signalscanner.d
Putting child 0xcda970 (dep/signalscanner.d) PID 2404 on the chain.
Live child 0xcda970 (dep/signalscanner.d) PID 2404
Successfully remade target file 'dep/signalscanner.d'.
Reading makefile 'dep/signalscanner.d' (search path) (don't care) (no ~ expansion)...
Considering target file 'dep/signalscanner.d'.
Finished prerequisites of target file 'dep/signalscanner.d'.
Prerequisite 'src/signalscanner.cpp' is older than target 'dep/signalscanner.d'.
No need to remake target 'dep/signalscanner.d'.
output of make -p whistle_recognition | signalscanner.o(shortened):
[...]
obj/signalscanner.o: src/signalscanner.cpp
[...]
signalscanner.o: src/signalscanner.cpp src/signalscanner.h src/frequencyanalyzer.h src/freqanalyzer_test.h src/wav_file.h src/signalscanner_test.h
And theres the problem: g++ doesn't include the obj/-prefix to the targets... Is there a way to fix this via pattern substitution?
People often have such rules for dependency generation, but they are really unnecessary.
The first time a project is built no dependencies are necessary since it builds all sources anyway. It is only the subsequent builds that require the dependencies from the previous build to detect what needs to be rebuilt.
The dependencies are just a by-product of compilation.
The generated dependencies contain paths to corresponding .o files. Since .o output paths were not specified when generating dependencies, those paths are incorrect.
The following solution puts .d files along with corresponding .o files and those .d files contain the correct paths to .o. It also does compilation and dependencies in one pass.
Fixes:
Remove these lines:
$(DEPS): $(DEPDIR)/%.d : $(SRCDIR)/%.cpp
$(CC) $(CFLAGS) -MM $< -MF $#
-include $(DEPS)
Update these lines:
DEPS = $(OBJS:%.o=%.d)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
$(CC) -c $(CFLAGS) -MD -MP -o $# $<
Add these lines at the bottom:
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPS)
endif
Related
I have a simple project, whose folder structure is something like:
ls -R
.:
build include makefile src
./build:
./include:
myfunc.h
./src:
main.cpp myfunc.cpp
I want to compile the .cpp sources into .o object files, which should end into ./build folder. Using the GNUmake documentation and other sources (e.g. Proper method for wildcard targets in GNU Make), I wrote this makefile:
CXX := g++
CXXFLAGS += -I./include
CXXFLAGS += -Wall
OBJDIR := ./build
SRCDIR := ./src
PROGRAM = release
DEPS = myfunc.h
SRC = $(wildcard $(SRCDIR)/*.cpp)
OBJ = $(patsubst $(SRCDIR)/%.cpp, $(OBJDIR)/%.o, $(SRC))
all: $(PROGRAM)
$(PROGRAM): $(OBJ)
$(CXX) $(CXXFLAGS) -o $(PROGRAM) $(OBJ)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(DEPS)
$(CXX) $(CXXFLAGS) -c $< -o $#
.PHONY: clean
clean:
rm $(PROGRAM) $(OBJ)
But I get the error message: make: *** No rule to make target 'build/main.o', needed by 'release'. Stop.. I tried a lot of different ways but I cannot manage to have my .o files end up in the ./build directory. Instead, everything works if I put them in the root directory of the project. I can also make it work by specifying a rule for each object file, but I'd like to avoid that. What am I missing?
(I am using GNUmake version 4.3)
The problem is here:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(DEPS)
$(CXX) $(CXXFLAGS) -c $< -o $#
See the $(DEPS)? That expands to myfunc.h. The compiler knows where to find that file (or would if this recipe were executed), because you've given it -I./include, but Make doesn't know where to find it (so it passes over this rule).
Add this line:
vpath %.h include
P.S. If you want to be really clean, you can add a variable:
INCDIR := ./include
CXXFLAGS += -I$(INCDIR)
vpath %.h $(INCDIR)
I have the following project structure:
lib/
Makefile
src/...
inc/...
build/
inc/...
lib/libmylib.a
subproj1/
src/main.cpp
Makefile
The Makefile in the lib folder is designed to create the file libmylib.a and copy the relevant header files to the build/inc folder.
I want the Makefile in subproj1 to always call make -C ../lib, but only re-compile file if headers have changed, and re-link only if necessary (one object file or libmylib.a is newer).
I have the following (non-defined variables such as CC are defined in another file):
LIBDIR = ../lib
SRCDIR = src
OBJDIR = obj
SRCS = $(SRCDIR)/main.cpp
MAIN=myexe
OBJS = $(SRCS:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
DEPS = $(OBJS:.o=.d)
all: $(MAIN)
debug: CFLAGS += -g -DDEBUG
debug: LFLAGS += -g
debug: $(MAIN)
$(MAIN): $(OBJS) $(LIBDIR)/build/lib/libmylib.a
$(CC) $^ -o $# $(LIBS) $(LFLAGS)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(LIBDIR)/build/lib/libmylib.a
mkdir -p $(OBJDIR)
$(CC) -c -o $# $(CFLAGS) $(INCS) -MD -MF $(patsubst %.o, %.d, $#) $<
$(LIBDIR)/build/lib/libmylib.a:
make -C $(LIBDIR)
-include $(DEPS)
.PHONY: clean $(LIBDIR)/build/lib/libmylib.a
clean:
$(RM) obj/* $(MAIN)
The above will re-compile main.cpp even if nothing has changed in the lib folder. If I remove $(LIBDIR)/build/lib/libmylib.a from the $(OBJDIR)/%.o rule, the .cpp file will not be re-compiled if a header changed (I would need to run make twice).
Is there a way to have the .cpp files in subproj1 being compiled only if the header files in lib have changed (or if the .cpp files themselves have changed), and to get myexe built only if one of the .cpp has been re-compiled (newer .o) or if libmylib.a is newer?
With recursive makefiles you need to execute the sub-project makefiles in correct order because the dependency tree is incomplete (e.g. this makefile does not know that updating $(LIBDIR)/build/lib/libmylib.a also updates those headers). It is easy to do that with a shell script or a top-level makefile.
Alternatively, your makefile must execute the sub-makefiles unconditionally in correct order, which can be done with shell function, e.g.:
LIBDIR := ../lib
pid := $(shell ps -o ppid= $$$$)
$(shell ${MAKE} -C ${LIBDIR} >/proc/$(pid)/fd/1 2>/proc/$(pid)/fd/2)
That $(LIBDIR)/build/lib/libmylib.a rule should be removed, the object files should not depend on the .a and it should not be marked as .PHONY.
This makes sure that building in ${LIBDIR} happens before this makefile analyzes file timestamps in ${LIBDIR}.
Now your auto-generated header dependencies should just work.
This might be a bit cleaner.
LIBDIR = ../lib
SRCDIR = src
OBJDIR = obj
SRCS = $(SRCDIR)/main.cpp
MAIN=myexe
OBJS = $(SRCS:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
DEPS = $(OBJS:.o=.d)
all: makelib
$(MAKE) $(MAIN)
debug: CFLAGS += -g -DDEBUG
debug: LFLAGS += -g
debug: $(MAIN)
$(MAIN): $(OBJS)
$(CC) $^ -o $# $(LIBS) $(LFLAGS)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
mkdir -p $(OBJDIR)
$(CC) -c -o $# $(CFLAGS) $(INCS) -MD -MF $(patsubst %.o, %.d, $#) $<
makelib:
make -C $(LIBDIR)
-include $(DEPS)
.PHONY: clean makelib
clean:
$(RM) obj/* $(MAIN)
The main target all requires makelib to be built, and then it recursively calls itself for the target $(MAIN) (so all of $(MAIN)'s dependencies will be recalculated after makelib has finished building).
Edit
After writing this I noticed some things and went back over the file. I changed the line:
$(CXX) -MT $(BUILD_DIR)/$(#:.d=.o) -MM $(CXXFLAGS) $^ > $#
To the following:
$(CXX) -MM $(CXXFLAGS) $^ > $#
Since it seemed kind of redundant to first take the generated dependency files, name them into .o files and then turn them back into .d files.
Now the target actually makes, but it will still not remake when the header files are changed.
Original
I have this makefile I created as part of a course, and everything works fine when running make, building for both the host and target. The problem arises when a change occurs in a header file(example: part1.h), this implementation was made specifically to take this into account, and it seemed to work.
A few weeks on now, and I finally realised it doesn't work as intended, as it will not recompile after a change to any of the header files. (part1.h or part2.h).
I took a look into the dependency files generated by the target:
$(BUILD_DIR)/%.d: %.cpp
An example of part1.d has the following contents:
build/host/build/host/part1.o: part1.cpp part1.h
To me, the double directory listing is an error, but so I tried changing the line:
$(CXX) -MT $(BUILD_DIR)/$(#:.d=.o) -MM $(CXXFLAGS) $^ > $#
To the following, removing the BUILD_DIR variable:
$(CXX) -MT $(#:.d=.o) -MM $(CXXFLAGS) $^ > $#
Doing this solves the double directory listing problem, but gives me a linker error:
build/host/main.o: file not recognized: File format not recognized
I'm trying to find some solution to this, which will make sure that the program is recompiled when changes are made to the header files.
I'm trying to figure out what I'm missing, I've looked at the related literature and everything seems to match up.
SOURCES=main.cpp part1.cpp part2.cpp
OBJECTS=$(addprefix $(BUILD_DIR)/,$(SOURCES:.cpp=.o))
DEPS=$(addprefix $(BUILD_DIR)/,$(SOURCES:.cpp=.d))
EXE=prog
CXXFLAGS=-I.
#Make sure that default choice for make is the host
ifndef (${ARCH})
ARCH=host
endif
#Making for host
ifeq (${ARCH},host)
CXX=g++
BUILD_DIR=build/host
BIN_DIR=bin/host
endif
# Making for target
ifeq (${ARCH},target)
CXX=arm-devkit-g++
BUILD_DIR=build/target
BIN_DIR=bin/target
endif
$(BIN_DIR)/$(EXE): $(DEPS) $(OBJECTS)
$(CXX) $(CXXFLAGS) -o $# $(OBJECTS)
#Generate dependency files. Place them in build/host or build/target depending on choice
$(BUILD_DIR)/%.d: %.cpp
$(CXX) -MT $(BUILD_DIR)/$(#:.d=.o) -MM $(CXXFLAGS) $^ > $#
#Generate object files. Place them in build/host or build/target, depending on choice.
$(BUILD_DIR)/%.o: %.cpp
$(CXX) -o $# -c $^
#Create the build dir,
${BUILD_DIR}:
mkdir -p ${BUILD_DIR}
#Create the bin dir
${BIN_DIR}:
mkdir -p ${BIN_DIR}
.PHONY:clean
clean:
rm -f $(BUILD_DIR)/*.o $(BIN_DIR)/$(EXE) $(BUILD_DIR)/*.d
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPS)
endif
If you generate the dependencies as part of the compilation not only do you avoid having to take the extra step, you also rely on the compiler to generate the correct paths. This entails a few other changes to your makefile but I found it simpler to just rewrite it, make has a number of features to simplify some of the other operations.
arch ?= host
build_dir := build/$(arch)
bin_dir := bin/$(arch)
ifeq ($(arch),target)
prefix := arm-devkit-
endif
sources := main.cpp part1.cpp part2.cpp
objects := $(sources:%.cpp=$(build_dir)/%.o)
deps := $(objects:.o=.d)
target := $(bin_dir)/prog
CXX := $(prefix)$(CXX)
CPPFLAGS := -MMD -MP
$(target): CC := $(CXX)
$(target): $(objects) | $(bin_dir)
$(LINK.o) $^ $(LDLIBS) -o $#
$(build_dir)/%.o: %.cpp | $(build_dir)
$(COMPILE.cpp) $(OUTPUT_OPTION) $<
$(build_dir) $(bin_dir): ; mkdir -p $#
.PHONY: clean
clean: ; $(RM) $(target) $(objects) $(deps)
-include $(deps)
here is my .c and .o files hierarchy:
---/src/IRBuild/main.c
func1.c
func2.c
---/inclue/main.h
func1.h
func2.h
---/build/IRBuild/main.o
func1.o
func2.o
irbuild
Below is my Makefile under ~/src/IRBuild/, I had build compile dependency with .c and .h files, which means whenever .c or .h files are changed. "make" will rebuild the object files. BUT because I output .o files to ~/build/IRBuild/, instead of current directory, "make" will rebuild all the .o files everytime I do make.
How should I build dependencies with .o files in other directories? Only re-compile the particular file when it's .c, .h, or .o file changed?
Stuck here for two days, thanks a lot!
EXE=irbuild
# G++ as default compiler
CC=g++
# Compile time flags
CXXFLAGS = -g -Wall
# Library paths in addition to /usr/lib
LFLAGS=-std=c++0x
# Libraries to link into executable:
#LIBS = -lmylib -lm
# Include files directory other than /usr/include
INCLUDES=-I../../include/
SRC=$(wildcard *.cpp)
OBJ=$(SRC:.cpp=.o)
DEP=$(OBJ:.o=.d)
BUILD=../../build/IRBuild
TESTS=../../tests/
OBJS :=$(foreach obj, $(OBJ), $(BUILD)/$(obj))
.PHONY: depend clean
all: $(EXE)
cp $(EXE) $(TESTS)
$(EXE): $(OBJ)
$(CC) $(CXXFLAGS) $(LFLAGS) $(INCLUDES) -o $(EXE) $(OBJS)
.cpp.o:
$(CC) $(CXXFLAGS) $(LFLAGS) $(INCLUDES) -c $< -o $(BUILD)/$#
clean:
rm -f $(OBJS) $(DEP) $(EXE)
depend: .depend
.depend: $(SRC)
rm -f ./.depend
$(CC) $(CXXFLAGS) $(LFLAGS) $(INCLUDES) -MM $^ -MF ./.depend;
include .depend
You are violating rule 2 from http://make.mad-scientist.net/rules.html which is why it rebuilds them all the time it thinks they don't exist. (Listing $(OBJ) in the prereqs and $(OBJS) in the recipe linking line is also a bit of a makefile "smell".)
You need to use a rule that correctly maps from your target files to their prerequisites.
Either manually or using vpath.
There are a number of ways to make the manual method work depending on how much effort you want to put in to setting things up. The vpath method is likely to be a fair bit easier.
Using vpath should just require using $(OBJS) as the $(EXE) prereqs and then adding vpath %.cpp . and vpath %.h ../../include or something like that.
I have been creating a library. When I compile it as a static library, it works fine. Now I want to turn it into a shared library. The library is created and in the proper place, but when I try to compile the client code, the linking phase says that it can't find the library.
I already tried to rename it to al or dylib but that doesn't help either. When I put the -v flag on the linking, I can see that my library path is there. I also tried different paths. I used a relative path, but even with a full path it doesn't find it.
The Makefile from the library:
.SUFFIXES:
.SUFFIXES: .o .cpp
.SUFFIXES: .o .d
CC := g++
LNK:= g++
CXXFLAGS_RELEASE = -fPIC -shared -O2 -Wall -fmessage-length=0
CXXFLAGS_DEBUG = -fPIC -shared -g -Wall -fmessage-length=0 -D _DEBUG
CXXFLAGS = $(CXXFLAGS_DEBUG)
OBJDIR:= obj
SRCDIR:= src
HDIR:= include
INCLUDE_PATHS:= -Iinclude -Iinclude/interfaces -Iinclude/support
CPP_FILES := propertyfile/propertyfile.cpp \
propertyfile/propertyitem.cpp \
propertyfile/propertyfactory.cpp \
helper/string_helper.cpp
OBJ := $(patsubst %.cpp,$(OBJDIR)/%.o, $(CPP_FILES))
SRC := $(patsubst %.cpp,$(SRCDIR)/%.o, $(CPP_FILES))
LIBS:=
TARGET:= libsupport.so
all: $(TARGET)
$(TARGET): $(OBJ)
$(LNK) -o $(TARGET) $(OBJ) -shared
#cp $(TARGET) ../lib
#cp -r include ..
clean:
rm -f $(OBJ) $(ASM) $(TARGET)
-include $(patsubst %.cpp,$(OBJDIR)/%.d, $(CPP_FILES))
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(OBJDIR)/%.d
#mkdir -p `dirname $#`
$(CC) $(CXXFLAGS) -c $< -o $# $(INCLUDE_PATHS)
$(OBJDIR)/%.d: $(SRCDIR)/%.cpp
#mkdir -p `dirname $#`
$(CC) $(CXXFLAGS) -MM -MT $# -MF $(OBJDIR)/$*.d -c $< $(INCLUDE_PATHS)
And here is the Makefile for the application:
.SUFFIXES:
.SUFFIXES: .o .cpp
CC := g++
LD := g++
CXXFLAGS_RELEASE = -O2 -Wall -fmessage-length=0
CXXFLAGS_DEBUG = -g -Wall -fmessage-length=0 -D _DEBUG
CXXFLAGS = $(CXXFLAGS_DEBUG)
OBJDIR:= obj
SRCDIR:= src
INCLUDE_PATHS:= -Iinclude -I../include
LIBS:= -L /cygdrive/d/src/c/lib -lsupport
CPP_FILES := nohupshd.cpp \
daemon.cpp \
task.cpp
OBJ := $(patsubst %.cpp,$(OBJDIR)/%.o, $(CPP_FILES))
SRC := $(patsubst %.cpp,$(SRCDIR)/%.o, $(CPP_FILES))
TARGET:= nohupshd
all: $(TARGET)
$(TARGET): $(OBJ)
$(LD) -o $(TARGET) $(OBJ) $(LIBS)
clean:
rm -f $(OBJ) $(ASM) $(TARGET)
-include $(patsubst %.cpp,$(OBJDIR)/%.d, $(CPP_FILES))
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(OBJDIR)/%.d
#mkdir -p `dirname $#`
$(CC) $(CXXFLAGS) -c $< -o $# $(INCLUDE_PATHS)
$(OBJDIR)/%.d: $(SRCDIR)/%.cpp
#mkdir -p `dirname $#`
$(CC) $(CXXFLAGS) -MM -MT $# -MF $(OBJDIR)/$*.d -c $< $(INCLUDE_PATHS)
After some experimenting I found a solution on how to compile a shared library under cygwin.
Apparently the compiler is looking for a DLL file even though it is inside cygwin. so the first step is to add your path, where the library is going to be to the PATH variable.
export PATH=$PATH:/cygdrive/d/src/c/lib
Apparently when linking against a shared library, the linker seems to look for a DLL file by default. I don't know why, because inside cygwin I would expect it to look for a .so file just like on other UNIX systems.
However, there are two solutions to this, which both work.
First, you can create a link to your .so library with the name .dll
ln -s /cygdrive/d/src/lib/libsupport.so libsupport.dll
In this case the makefile doesn't have to be changed and -lsupport will find the library while linking. I prefer this solution.
Second, you can specify the linker option with the full name.
LIBS:= -L /cygdrive/d/src/c/lib -l:libsupport.so
then you don't have to create a link.
So the crucial thing seems to be that the shared library must be in the PATH under cygwin. Using LD_LIBRARY_PATH doesn't help in that case as you can link the executable, but when trying to run it, it will not find it.
ldd nohupshd.exe
libsupport.so => not found
UPDATE: For some reason when I checked with ldd, my library was suddenly gone from the list. I found out that cygwin uses the name to differentiate between MS Windows and Unix shared libraries. So in order to make it work, the name of the library must be cyg.so to make it work, otherwise the exectuable seems to be some Windows build. In this case you don't need to create the link named x.dll as the shared library stays inside the Unix environment.
$(LNK) -o cyg$(TARGET).so $(OBJ) -shared
When using eclipse for debugging, the path to the shared library must also be in the windows path environment variable. Otherwise the debug session immediately terminates without an error.