Sometimes I need my project to use plain makefile, although it's a dated building technology not recommended for any use, but since make is available almost everywhere it sometimes makes sense.
However I want my Makefile to look something like
Include "../buildexec.mk"
TARG = my_exec
CPPFILES = file1.cpp \
file2.cpp \
and have all the generic (and horrible) dependency tracking code being in buildexec.mk.
Is there such a "Make library"?
In Go, there's a standard Makefile you can include, and your Makefile looks as beautiful like this:
include $(GOROOT)/src/Make.inc
TARG=irc
GOFILES=irc.go irc_struct.go irc_callback.go
include $(GOROOT)/src/Make.pkg
Anything similar for C++?
clarification: I know of tup, cmake and scons/ I know of waf and bjam and so on/ but I want my deps to so small/ so that compilation is no trouble at all. I specifically asked for Make support, not for Make alternative.
I would suggest generating the makefile with automake instead. Cmake also generates makefiles, while also being able to generate project files for several IDEs.
The problem is there is no one make. The very basic syntax is always the same, but anything slightly more complex (which you need for such includes) is not compatible even between GNU make and BSD make (not trying to mention nmake). Automake can however deal with several versions of make and provide automatic dependency rules where available (only some compilers support them).
You probably want to look at CMake or Premake.
With large C/C++ projects you tend to have additional requirements such as platform specific APIs or libraries that need customization.
This will do what you're asking for (at least in GNUMake).
makelib.mk:
$(TARG): $(CPPFILES:.cc=.o)
$(CC) $^ -o $#
%.o : %.cc
$(CC) -MD -o $# $<
#cp $*.d $*.P; \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
rm -f $*.d
-include $(CPPFILES:.cc=.P)
Makefile:
CPPFILES = foo.cc bar.cc
TARG = someTarget
include makelib.mk # Note lower-case "i"
CPPFILES = baz.cc quartz.cc quince.cc
TARG = anotherTarget
include makelib.mk
...
But a word of advice: don't curse your tools so much. It's energy you could be using to either learn how to use them or switch to ones you like better.
There's a googlecode project doing exactly what I wanted:
http://code.google.com/p/nonrec-make/
There is none of my knowledge. There are really a lot of problems with make, but it is still the most available tool around, and once you get it running properly you should just focus on your development.
Until there, you will have to write makefiles. But instead of looking for a 'make library', a really simple solution (if you're actually initiated in Make language), often overlooked for being too obvious, is to implement your own. Create a make script containing a set of default pattern rules and variables for communication with the project makefile, and just include this script in every project's makefile. It's not hard, maybe a little time-consuming, but it often pays off really well, specially if you have lots of small projects to manage.
I work with such a design. I have a couple of GNU make scripts carefully designed to offer an almost trivial mechanism to create rather complex build systems: automatic dependency generation, handling of different languages, generation of language parsers, different build configurations (debug or release), build log generation, and so on. And the script is not cumbersome: the current version contains just about 250 lines of makefile code, excluding comments.
I will leave you with a sample of an older version of such system, handling C source code only, which contained a few features. It should handle the compilation of binaries and libraries (both static and dynamic). It also should help you track inter-project dependencies through the DEPS variable.
Call this $(ROOT)/project.mk:
# Remove the default suffix rules.
.SUFFIXES:
# Turn on the delete-on-error feature.
.DELETE_ON_ERROR:
# Set up additional command variables.
STRIP ?= strip
# Set up a global search path to locate prerequisites.
VPATH := $(VPATH) $(shell find -type d)
# Locate all source files from the default locations in the project tree.
SRC := $(SRC) $(shell find src -name '*.c')
# Set up the default dependency files.
DEP := $(DEP) $(addprefix dep/,$(addsuffix .d,$(basename $(notdir $(filter %.c,$(SRC))))))
# Set up the default object files.
OBJ := $(OBJ) $(addprefix obj/,$(addsuffix .o,$(basename $(notdir $(filter %.c,$(SRC))))))
# Set up a set of default flags for all commands used.
STRIPFLAGS ?= -p
CPPFLAGS ?= -DNDEBUG
CFLAGS ?= -Wall -Wextra -Werror -pedantic -O3 -march=native -fomit-frame-pointer -ffast-math
LDFLAGS ?= --as-needed -O1
ARFLAGS ?= -scr
# Set up the default include and library search paths.
override INCLUDES := \
$(addprefix $(ROOT)/,$(addsuffix /include,$(DEPS))) \
$(INCLUDES)
override LIBRARIES := \
$(addprefix $(ROOT)/,$(addsuffix /lib,$(DEPS))) \
$(LIBRARIES) lib
# The default rule to build every target in the project.
.PHONY: all
all: deps $(DEP) $(OBJ) $(BIN) $(LIB)
# Phony rule to recursively build the library dependencies.
.PHONY: deps
deps:
#for dep in $(DEPS); do cd $(ROOT)/lib/$$dep && $(MAKE); done
# Secondary expansion is used to properly locate prerequisites.
.SECONDEXPANSION:
# Rule for dependency file generation.
%.d: $$(notdir $$*).c
$(CC) -M $(CPPFLAGS) $(CFLAGS) -iquote include $(addprefix -I ,$(INCLUDES)) $< -MM -MG -MP -MT '$# $(filter %/$(notdir $*).o,$(OBJ))' > $#
# Rule for compiling object files.
%.o: $$(notdir $$*).c
$(CC) -c $(CPPFLAGS) $(CFLAGS) -iquote include $(addprefix -I ,$(INCLUDES)) $< -o $#
# Rule for linking binaries.
%: $$(notdir $$*).c
$(CC) $(CPPFLAGS) $(CFLAGS) $(addprefix -Xlinker ,$(LDFLAGS)) -iquote include $(addprefix -I ,$(INCLUDES)) $(addprefix -L ,$(LIBRARIES)) $(filter-out $<,$^) -o $# $(addprefix -l,$(LDLIBS))
$(STRIP) $(STRIPFLAGS) $#
# Rule for linking shared libraries.
%.so: $$(notdir $$*).c
$(CC) $(CPPFLAGS) $(CFLAGS) $(addprefix -Xlinker ,$(LDFLAGS)) -iquote include $(addprefix -I ,$(INCLUDES)) $(addprefix -L ,$(LIBRARIES)) $(filter-out $<,$^) -o $# -fpic -shared -Wl,-h,$(notdir $#) $(addprefix -l,$(LDLIBS))
$(STRIP) $(STRIPFLAGS) $#
# Rule for generating static libraries.
%.a:
$(AR) $(ARFLAGS) $# $?
# Include all dependency files and remake them if necessary.
ifneq ($(MAKECMDGOALS),clean)
include $(DEP)
endif
# Phony rule to clean the entire build tree.
.PHONY: clean
clean:
#for dep in $(DEPS); do cd $(ROOT)/lib/$$dep && $(MAKE) clean; done
$(RM) $(DEP) $(OBJ) $(BIN) $(LIB) $(CLEAN)
ROOT contains the path for your projects' directory (working copy of repository, for example), typically exported as an environment variable. You will also need a couple of directories (bin, dep, obj and src) in your projects.
An example Makefile using this system could be:
DEPS := mylib
BIN := bin/test
LIB := lib/libtest.a
include $(ROOT)/project.mk
bin/test: $(OBJ)
lib/libtest.a: obj/test1.o obj/test2.o
That is, you just write the minimum necessary about your project, and let the build system do the rest. You can always explicitly specify the value for a given variable (SRC, for example, or CFLAGS), but if you don't, then it gets a reasonable default.
The above was tailored to my needs, but it should be simple to adapt to yours, while keep things as easy as the examples you've mentioned.
Related
I want to create a Makefile for a project with the following layout:
Source files (.cpp, potentially .c) in /src, with potential subdirectories
Header files (.h, .hpp...) in /inc, with potential subdirectories
Object files (.o) in /obj, with potential subdirectories
External libraries in /lib
Compiled program in /bin
So far, I've managed to write together this Makefile, but with some issues:
SRC_DIR := src
BIN_DIR := bin
LIB_DIR := lib
INC_DIR := inc
OBJ_DIR := obj
SRCEXTS := .c .C .cc .cpp .CPP .c++ .cxx .cp
HDREXTS := .h .H .hh .hpp .HPP .h++ .hxx .hp
TARGETS := $(BIN_DIR)/program
SOURCES := $(wildcard $(addprefix $(SRC_DIR)/*,$(SRCEXTS)))
HEADERS := $(wildcard $(addprefix $(LIB_DIR)/*,$(HDREXTS)))
OBJECTS := $(addsuffix .o, $(basename $(SOURCES)))
CXX = g++
CXXFLAGS = -std=c++17 -c -g -Wall
.PHONY: all clean
all: $(TARGETS)
$(TARGETS): $(OBJECTS)
$(CXX) $^ -o $#
$(OBJ_DIR)%$(OBJECTS): $(SRC_DIR)%$(SOURCES)
$(CXX) $(CXXFLAGS) $< -o $#
clean:
rm -f $(OBJECTS) $(TARGETS)
I've tried to make it as "generic" as possible, so future projects could be started with this layout and makefile as a template. Currently, it creates the .o-files inside the src-directory alongisde the source code. It also fails when trying to compile the program with
g++ src/main.o -o bin/program
/usr/bin/ld: src/main.o: _ZSt4cout: invalid version 3 (max 0)
/usr/bin/ld: src/main.o: error adding symbols: bad value
collect2: error: ld returned 1 exit status
make: *** [Makefile:23: bin/program] Error 1
Very new to C++ development. Been on a wild goose-chase for a while, trying to get a clear image of how it all works. My code is basically a weird Frankenstein monster of several code snippets I've stumbled upon. Hopefully my intentions are clear enough, this is my last ditch effort! Thanks in advance :)
As #JohnBollinger points out, you are attempting too much at once. I will suggest a few changes to get your makefile off the ground.
I can't explain the error you get when you try to build the executable (you haven't given us enough information to reproduce the error), but it doesn't look like a Make problem. I suggest you try to build it without Make, using the command line, and see what happens.
I will assume that the names of your sources end in ".cpp" (such as src/sailboat/foo.cpp), the names of your headers end in ".hpp", and the directory tree under obj/ is already present and correct. These restrictions are temporary training wheels; you can remove them when you have more skill.
First, finding the source files. This:
SOURCES := $(wildcard $(addprefix $(SRC_DIR)/*,$(SRCEXTS)))
will not work if src/ has subdirectories. To recurse into subdirectories, we will use find. (There is a shortcut available to GNUMake, but for now we'll do things the slow and careful way).
SOURCES := $(shell find src -name "*.cpp")
Now to construct the names of the desired object files, such as obj/sailboat/foo.o. This:
OBJECTS := $(addsuffix .o, $(basename $(SOURCES)))
will give you src/sailboat/foo.o. We need a different command to change the leading directory as well as the suffix:
OBJECTS := $(patsubst src/%.cpp,obj/%.o,$(SOURCES))
Some of the source files refer to header files, so before we can start building objects, we must be able to supply them. The compiler can find the needed headers, but we must tell it where to search. So we need the directories, not the full paths:
HEADERS := $(shell find inc -name "*.hpp")
HEADERDIRS := $(sort $(dir $(HEADERS)))
(The sort is just to remove duplicates. Not necessary, but tidy.)
Now the rule to build the objects. This is incorrect:
$(OBJ_DIR)%$(OBJECTS): $(SRC_DIR)%$(SOURCES)
$(CXX) $(CXXFLAGS) $< -o $#
Remember that OBJECTS can contain several space-separated words. So if it contains foo bar, the target will be obj/%foo bar, which is clearly not what you intended. Likewise the prerequisite list is wrong, and the recipe too. Junk it and start over.
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $< -c -o $#
Then remember the header files, and add flags to tell the compiler where to look for them:
INCLUDEFLAGS := $(addprefix -I,$(HEADERDIRS))
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $< -c $(INCLUDEFLAGS) -o $#
That should be enough to get your makefile working; further refinements can wait.
I'm not mastering makefiles but one thing for sure : target "all" is definitively not a PHONY target because it often depends on other targets (in fact, it always depends on other targets, by definition !).
Also, as said John Bollinger, it is obviously possible to have only one makefile at the root.
"all" target is not mandatory : make will look for the first target fisrt.
The folder structure is like this :
----root
----src
----inc
----obj
----lib
Here's a simple one of mine (rules to build static libraries have been commented out) :
CC=g++
SRCDIR=./src/
INCDIR=./inc/
INCFLAG=-I$(INCDIR)
OBJDIR=./obj/
LIB=./lib/
LIBFLAG=-lstdc++
#-lmystaticlibrary -lmyclasses
#$(LIBFLAG) -L$(LIB)
#STATICLIBRARIES= mystaticlibrary myclasses
OBJECTS = $(OBJDIR)apprendre.o $(OBJDIR)myfunctions.o $(OBJDIR)myclasses.o
apprendre: $(OBJECTS)
# echo
# echo --------------------- Edition des liens
$(CC) $(OBJECTS) -o $# $(INCFLAG)
# mystaticlibrary: mystaticlibrary.o
# # echo
# # echo --------------------- Compilation librairie statique $#
# ar cr $(LIB)lib$#.a $(OBJ)$#.o
# ranlib $(LIB)lib$#.a
# myclasses: myclasses.o
# # echo
# # echo --------------------- Compilation librairie statique $#
# ar cr $(LIB)lib$#.a $(OBJ)$#.o
# ranlib $(LIB)lib$#.a
$(OBJDIR)%.o: $(SRCDIR)%.cpp $(INCDIR)myfunctions.h $(INCDIR)myclasses.h
# echo
# echo --------------------- Compilation $<
$(CC) -c $< $(INCFLAG) -o $#
run:
# echo
# echo "-----------------------> GO !!! : apprendre"
# ./apprendre
I have a simple makefile which finds the CPP files relative to it and builds the target from there. How could I modify this to also precompile the header files relative to it when building the target?
TARGET ?= application
CXXFLAGS += -Os -I. -MMD -MP -std=c++11
SOURCES := $(shell find -L . -name '*.cpp')
OBJECTS := $(SOURCES:.cpp=.o)
DEPENDS := $(SOURCES:.cpp=.d)
$(TARGET): $(OBJECTS)
$(CXX) $(OBJECTS) -o $# $(LDLIBS)
.PHONY: clean
clean :
$(RM) $(TARGET) $(OBJECTS) $(DEPENDS)
-include $(DEPENDS)
Looks like I'm not able to do what I had in mind. The solution here is to follow #Rup's advice and include the major dependencies in a single compiled header.
GCC - 3.21 Using Precompiled Headers
A precompiled header file can be used only when these conditions apply:
Only one precompiled header can be used in a particular compilation.
I'm currently trying to build a proper Makefile.
What I want is full control of what's happening, so I don't want any third party software.
My current attempt seems logic to me, but since the dependency generation is not valid, I'm kind of stuck.
For better readabilty, the full Makefile is broken into little pieces. I would appreciate any comment on any section if there's something to improve.
First of all, I have the following static definitions
CXX = g++
CXXFLAGS = -Wall \
-Wextra \
-Wuninitialized \
-Wmissing-declarations \
-pedantic \
-O3 \
-p -g -pg
LDFLAGS = -p -g -pg
DEPFLAGS = -MM
Afaik this should be fine. It would be perfect to make the profiling flags optional but that's not important.
SRC_DIR = ./src
OBJ_DIR = ./obj
SRC_EXT = .cpp
OBJ_EXT = .o
TARGET = ./bin/my_target
SRCS = $(wildcard $(SRC_DIR)/*$(SRC_EXT))
OBJS = $(subst $(SRC_DIR), $(OBJ_DIR), $(SRCS:$(SRC_EXT)=$(OBJ_EXT)))
DEP = depend.main
Basically, this should just extract all the *.cpp files out of the subfolder src and additionally replace ./src with ./obj and .cpp with .o as names of the objects.
.PHONY: clean all depend
all: $(TARGET)
$(TARGET): $(OBJS)
#echo "-> linking $#"
#$(CXX) $^ $(LDFLAGS) -o $#
$(OBJ_DIR)/%.$(EXT_OBJ):
#echo "-> compiling $#"
#$(CXX) $(CXXFLAGS) -c $< -o $#
Afaik, this block - provided a valid dependency file exists - should do all necessary compiling and linking.
clean:
#echo "removing objects and main file"
#rm -f $(OBJS) $(TARGET)
Should be self-explanatory and correct, or am I missing something here?
$(SRC_DIR)/%.$(SRC_EXT):
$(CXX) $(DEPFLAGS) -MT \
"$(subst $(SRC_DIR),$(OBJ_DIR),$(subst $(SRC_EXT),$(OBJ_EXT),$#))" \
$(addprefix ,$#) >> $(DEP);
clear_dependencies:
#echo "-> (re-)building dependencies";
#$(RM) $(DEP)
depend: clear_dependencies $(SRCS)
This is the non-functional part. What I intend to do is using the g++ Compiler flag -MM to auto-create dependencies and using -MT to use a different path than the default one.
The resulting dependency should look like
./obj/main.o: ./src/main.cpp ./src/some_header_file.h
Unfortunately, this will never be called and I lack the knowledge why this is the case.
In a similar question, user Beta gladly provided a temporary solution by adding a .Phony but this has the side effect on rebuilding every object without any change.
Finally, there is just the one line
-include $(DEP)
to include the dependency file, once created.
Any answer providing some hints about any part are very welcome.
So my question is: What can I do better or maybe "cleaner" and why doesn't the dependency generation work?
Here goes.
Assign simply expanded variables where possible:
SRCS := $(wildcard $(SRC_DIR)/*$(SRC_EXT))
From GNU Make manual:
Another disadvantage [of recursively expanded variables] is that any functions referenced in the definition will be executed every time the variable is expanded. This makes make run slower; worse, it causes the wildcard and shell functions to give unpredictable results because you cannot easily control when they are called, or even how many times.
Use substitution references or patsubst function to convert sources into objects:
OBJS := $(SRCS:$(SRC_DIR)/%$(SRC_EXT)=$(OBJ_DIR)/%$(OBJ_EXT))
Specify proper prerequisites in compilation pattern rule. This is mandatory to get Make keeping your object files up to date and updating them on source changes.
$(OBJ_DIR)/%$(OBJ_EXT) : $(SRC_DIR)/%$(SRC_EXT)
#echo "-> compiling $#"
#$(CXX) $(CXXFLAGS) -o $# -c $<
Compile sources and generate dependency files for them at the same time. Use -MMD -MP flags to get things work (just append them to CXXFLAGS).
CXXFLAGS += -MMD -MP
-include $(OBJS:$(OBJ_EXT)=.d)
From GCC manual:
-MD
-MD is equivalent to -M -MF file, except that -E is not implied. The driver determines file based on whether an -o option is given. If it is, the driver uses its argument but with a suffix of .d, otherwise it takes the name of the input file, removes any directory components and suffix, and applies a .d suffix.
-MMD
Like -MD except mention only user header files, not system header files.
-MP
This option instructs CPP to add a phony target for each dependency other than the main file, causing each to depend on nothing. These dummy rules work around errors make gives if you remove header files without updating the Makefile to match.
Also consider studying this article of Paul Smith (he is a maintainer of GNU Make). It gives a rather good overview of different autodep-generation approaches.
What approach do C++ programmers on Unix platform use to create and manage Makefiles?
I was using hand made Makefiles for my projects but they don't handle header file changes and other dependencies. I googled around and found a good solution here.
But I ran into a problem here in the sed command -
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
The problem is with the 3rd expression "-e 's/ *\$$//'.
It doesn't work. Its supposed to remove trailing backslashes. I understand that there has to be double dollar there since this is part of a Makefile. Can someone tell me what wrong here?
Here's the complete Makefile -
CC=g++
CFLAGS=-g -Wall
LIBS=-lpthread
OBJS=file1.o file2.o
TARGET=testProg
$(TARGET) : $(OBJS)
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
%.o : %.cpp
$(CC) -MMD -c -o $# $< $(CFLAGS)
#cp $*.d $*.P; \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
rm -f $*.d
-include $(OBJS:%.o=%.P)
clean :
rm -f $(TARGET) $(OBJS)
all : $(TARGET)
Apart from the solution to this problem, I would also like some tips/pointers to my 1st question.
gcc/g++ can generate dependencies for you with the -M family of options.
The following works by specifying how to generate .depends files given a source file. By doing -include $(DEPS) $(DEPS) is recognized as a target and will be built/rebuilt when the source files change.
CXX = g++
CXXFLAGS = -Wall -O3
LDFLAGS =
TARGET = testcpp
SRCS = main.cc x.cc foo.cc
OBJS = $(SRCS:.cc=.o)
DEPS = $(SRCS:.cc=.depends)
.PHONY: clean all
all: $(TARGET)
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $(TARGET)
.cc.o:
$(CXX) $(CXXFLAGS) -c $< -o $#
%.depends: %.cc
$(CXX) -M $(CXXFLAGS) $< > $#
clean:
rm -f $(OBJS) $(DEPS) $(TARGET)
-include $(DEPS)
I use that approach too and can't praise it highly enough. And I write my makefiles by hand and reuse them a lot on new projects.
.The expression "s/ *\\$//" will work outside the context of Make. Within a makefile it doesn't work because Make tries to interpret "$/" before handing the result to the shell. So you must use "s/ *\\$$//" (note the extra $) within the makefile, but this won't work outside the context of Make (so testing it is a slight pain).
EDIT:
I've tried your makefile, and that sed statement seems to remove trailing backslashes just fine. Try something simpler, like this:
backslash:
#echo " \\" > $#
test: backslash
#echo without sed:
#cat backslash
#echo with sed:
#sed -e 's/ *\\$$//' < backslash
EDIT:
All right, now I'm hooked. Could you try these experiments and tell us the results?
Change the last character to 'z' : s/.$/z/
Change a trailing backslash to 'z' : s/\\$/z/
Change a trailing backslash to 'z' : sm\\$mzm
Delete a trailing backslash : s/\\$//
Delete spaces and a trailing backslash: s/ *\\$//
Try all of these inside and outside of Make, with '$' and '$$'.
In a make file anything you list on the dependency line is a dependency header files or other files included.
BSD tutorial on make Note: you can auto generate header dependency info with the -MM switch of GCC.
I must be missing something. Why doesn't generating dependency files work for you?
I prefer to use CMake, even though it's not strictly the solution to your problem.
It's a project description language that'll generate your Makefiles, Visual Studio Project, Eclipse Project, KDevelop, etc for you. All the dependencies are done for you:
CMakeLists.txt
add_executable(my_exe file1.c file2.c)
target_link_libraries(my_exe my_library)
add_subdirectory(lib)
In lib/CMakeLists.txt
add_library(my_library file3.c file4.c)
This creates a my_exe from file1.c file2.c linked against my_library. I find this much simpler. It also has things like package discovery:
find_package(Qt4)
The makedepend utility is installed on many systems and can be quite useful for generating dependency information.
Here is an example Makefile that uses the include directive (plus a little Perl magic) to incorporate the output from makedepend:
# the name of the executable that we'll build
TARGET = foo_prog
# our .cc source files
SRCS = foo.cc main.cc
# the .o versions of our source files
OBJS := $(patsubst %.cc, %.o, $(filter %.cc, $(SRCS)))
# some flags for compiling
CXXFLAGS = -Wall -Werror
# In order to build $(TARGET), we first build each of the $(OBJS).
# Then we use the given command to link those $(OBJS) into our
# $(TARGET) executable. $^ is a shortcut for $(OBJS). $# is a
# shortcut for $(TARGET).
#
# The default compile rule will compile each of the $(OBJS) for us.
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) $^ -o $#
# Use "make clean" to remove all of the support files.
clean:
rm -f $(OBJS) $(TARGET) Makefile.depend *~
# This automatically uses the 'makedepend' utility to add any
# dependencies that our source files have, namely .h files. This way,
# if the .h files change, the code will be re-compiled.
include Makefile.depend
Makefile.depend: $(SRCS)
makedepend -f- -Y $(SRCS) 2> /dev/null | \
perl -p -e "s/(^.*?:)/Makefile.depend \1/" > Makefile.depend
If both foo.cc and main.cc depend on foo.h, then the contents of Makefile.depend would be:
Makefile.depend foo.o: foo.h
Makefile.depend main.o: foo.h
The end result is that the dependency information from makedepend is injected into the Makefile as a series of rules. It's similar to the approach of using a .d file for each .cc file, but keeps the dependency information in one file instead of scattered all over the place.
In Mozilla's build system, we use GCC's -MD switch to generate the dependency files:
http://mxr.mozilla.org/mozilla-central/source/configure.in#7134
and then we use a script called mddepend.pl to check for removed header files, such that
removing a header simply causes a rebuild, not an error:
http://mxr.mozilla.org/mozilla-central/source/config/rules.mk#2066
http://mxr.mozilla.org/mozilla-central/source/build/unix/mddepend.pl
That script generates an .all.pp file containing all the dependencies, with extra foo.o: FORCE dependencies stuck in for missing header files. We then simply -include the .all.pp file in rules.mk right below there.
You can use qmake to generate Makefiles for a project even if that project is not using Qt.
I use BSD make (pmake?) which does lot of work for me (my lang is C, but I think no difference here). This is my common 'local.prog.mk', I never change it:
.PHONY: tags .depend
# .depend depends only on $(SRCS) in bsd.dep.mk, so we can't track changes of
# header's own dependencies properly. so .depend is .PHONY target here.
CSTD ?=c99
WARNS ?=9
.if !empty(PC_LIST)
PC_CF !=pkg-config --cflags $(PC_LIST)
PC_LD !=pkg-config --libs $(PC_LIST)
.endif
CFLAGS +=$(PC_CF) -fgnu89-inline
.if !defined(NO_DEBUG)
CFLAGS +=-O0 -ggdb3
.endif
LDFLAGS +=$(PC_LD)
CTAGS =exctags
NO_MAN=
NO_OBJ=
CLEANFILES+=$(PROG).core
.include <bsd.prog.mk>
$(PROG): $(SUBDIR)
build: clean cleandepend depend all
run: $(PROG)
./$(PROG)
Note 'bsd.prog.mk' inclusion -- this handles all, build, depend, clean targets. Project-specific BSDmakefiles are simple:
.SILENT:
PROG =hello
SRCS =hello.c world.c
PC_LIST =gtk+-2.0 gnet-2.0
.include "../local.prog.mk"
proto:
cproto -siv `pkg-config --cflags $(PC_LIST)` $(SRCS) > prototypes
CLEANFILES+=prototypes
I just make depend every time I insert/remove any #include directives.
Instead of the sed scripts, use gcc's -MT option to modify the target of the generated dependency rules. This blog post has more info.
With a more modern version of GCC, you can add the -MP flag to have GCC generate empty rules for the headers itself.
I top tip that I have found useful when building dependency files is to include the dependency file as a target in the generated rule:
file.d file.o : file.c header.h header2.h ...
Thus make will regenerate the dependencies if the source or any of the headers change. Including phony targets for the headers (GCC -MP) should then allow stable builds when headers are removed - the absense of required header remains a compilation error, not a make dependency error.
Assuming that dependency files are generated into the same directory as the object files, the following should work for GCC on Unix:
-include $(OBJ:.o=.d)
$(OBJDIR)/%d : $(SRCDIR)/%.cpp
mkdir -p $(#D)
echo -n "$# " > $#.tmp
$(CXX) $(CPPFLAGS) -MM -MP -MT $(#:.d=.o) $< >> $#.tmp
mv $#.tmp $#
(from memory)
I've looking to find a simple recommended "minimal" c++ makefile for linux which will use g++ to compile and link a single file and h file. Ideally the make file will not even have the physical file names in it and only have a .cpp to .o transform. What is the best way to generate such a makefile without diving into the horrors of autoconf?
The current dir contains, for example
t.cpp
t.h
and I want a makefile for that to be created. I tried autoconf but its assuming .h is gcc instead of g++. Yes, while not a beginner, I am relearning from years ago best approaches to project manipulation and hence am looking for automated ways to create and maintain makefiles for small projects.
If it is a single file, you can type
make t
And it will invoke
g++ t.cpp -o t
This doesn't even require a Makefile in the directory, although it will get confused if you have a t.cpp and a t.c and a t.java, etc etc.
Also a real Makefile:
SOURCES := t.cpp
# Objs are all the sources, with .cpp replaced by .o
OBJS := $(SOURCES:.cpp=.o)
all: t
# Compile the binary 't' by calling the compiler with cflags, lflags, and any libs (if defined) and the list of objects.
t: $(OBJS)
$(CC) $(CFLAGS) -o t $(OBJS) $(LFLAGS) $(LIBS)
# Get a .o from a .cpp by calling compiler with cflags and includes (if defined)
.cpp.o:
$(CC) $(CFLAGS) $(INCLUDES) -c $<
Here is a generic makefile from my code snippets directory:
SOURCES=$(wildcard *.cpp)
OBJECTS=$(SOURCES:.cpp=.o)
DEPS=$(SOURCES:.cpp=.d)
BINS=$(SOURCES:.cpp=)
CFLAGS+=-MMD
CXXFLAGS+=-MMD
all: $(BINS)
.PHONY: clean
clean:
$(RM) $(OBJECTS) $(DEPS) $(BINS)
-include $(DEPS)
As long as you have one .cpp source producing one binary, you don't need anything more. I have only used it with GNU make, and the dependency generation uses gcc syntax (also supported by icc). If you are using the SUN compilers, you need to change "-MMD" to "-xMMD". Also, ensure that the tab on the start of the line after clean: does not get changed to spaces when you paste this code or make will give you a missing separator error.
Have you looked at SCons?
Simply create a SConstruct file with the following:
Program("t.cpp")
Then type:
scons
Done!
Assuming no preconfigured system-wide make settings:
CXX = g++
CPPFLAGS = # put pre-processor settings (-I, -D, etc) here
CXXFLAGS = -Wall # put compiler settings here
LDFLAGS = # put linker settings here
test: test.o
$(CXX) -o $# $(CXXFLAGS) $(LDFLAGS) test.o
.cpp.o:
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $<
test.cpp: test.h
a fairly small GNU Makefile, using predefined rules and auto-deps:
CC=c++
CXXFLAGS=-g -Wall -Wextra -MMD
LDLIBS=-lm
program: program.o sub.o
clean:
$(RM) *.o *.d program
-include $(wildcard *.d)
Have you looked at OMake ?
OMakeroot
open build/C
DefineCommandVars()
.SUBDIRS: .
OMakefile
.DEFAULT: $(CXXProgram test, test)
Then on Linux or Windows, simply type:
omake
As a bonus, you automatically get:
parallel builds with the -j option (same as make).
MD5 checksums instead of timestamps (build becomes resilient to time synchronization failures).
Automatic and accurate C/C++ header dependencies.
Accurate inter-directory dependencies (something that recursive make does not offer).
Portability (1 build chain to rule them all, immune to path style issues).
A real programming language (better than GNU make).
Some good references on creating a basic Makefile
http://en.wikipedia.org/wiki/Make_(software)
http://mrbook.org/tutorials/make/
http://www.opussoftware.com/tutorial/TutMakefile.htm
http://www.hsrl.rutgers.edu/ug/make_help.html
The first couple in particular have minimal example Makefiles like you were describing. Hope that helps.
SConstruct with debug option:
env = Environment()
if ARGUMENTS.get('debug', 0):
env.Append(CCFLAGS = ' -g')
env.Program( source = "template.cpp" )
florin has a good starting point. I didn't like gnu autoconf so I started there and took the concept further and called it the MagicMakefile. I have 3 versions of it from simple to more complex. The latest is now on github: https://github.com/jdkoftinoff/magicmake
Basically, it assumes you have a standard layout for the source files of your project and uses the wildcard function to create the makefile rules on the fly which are then eval'd, handling header file dependancies, cross compiling, unit tests, install, and packaging.
[edit] At this point I use cmake for all my projects since it generates useful project files for many build systems.
jeff koftinoff
I was hunting around for what a minimal Makefile might look like other than
some_stuff:
#echo "Hello World"
I know I am late for this party, but I thought I would toss my hat into the ring as well. The following is my one directory project Makefile I have used for years. With a little modification it scales to use multiple directories (e.g. src, obj, bin, header, test, etc). Assumes all headers and source files are in the current directory. And, have to give the project a name which is used for the output binary name.
NAME = my_project
FILES = $(shell basename -a $$(ls *.cpp) | sed 's/\.cpp//g')
SRC = $(patsubst %, %.cpp, $(FILES))
OBJ = $(patsubst %, %.o, $(FILES))
HDR = $(patsubst %, -include %.h, $(FILES))
CXX = g++ -Wall
%.o : %.cpp
$(CXX) $(HDR) -c -o $# $<
build: $(OBJ)
$(CXX) -o $(NAME) $(OBJ)
clean:
rm -vf $(NAME) $(OBJ)
If your issues are because autoconf thinks the .h file is a c file, try renaming it to .hpp or .h++