basic GNU makefile for small c++ prog

This is under linux using GNU tools and in particular GNU make (I don't care about Makefile portability) What's the "best" makefile for a small c++ project made of 3 c++ files and using a third party module (with its includes and lib)?
Let's starting with this
MYINCDIR  = /usr/blabla/inc
MYLIBDIR  = /usr/blabla/lib

LDFLAGS = -L$(MYLIBDIR) -lmylib -lm -lpthread
CPPFLAGS = -m64 -O -fPIC -fexceptions -DNDEBUG -I$(MYINCDIR)

OBJS=a.o b.o c.o

$(PROG): $(OBJS)
        $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $@ $^ $(LDFLAGS)

        rm -f $(PROG) $(OBJS)
GNU make has several implicit rules and maybe tricks that I don't know. Can you make suggestions to improve this makefile with the following aims:
- keep it small and short, exploiting gnu make implicit rules and mechanisms (but keeping compilation and linking separate)
- avoid the explicit rule for linking. Note that by default gnu make use gcc (instead of g++) for linking .o files (but that wouldn't work on a c++ project) and also note that if the implicit rule passes the -l options before the OBJS list, that can also break the linking. That's why in the sample above here I had to use an explicit rule. But maybe there is a better way.
- I'd prefer to specify the list of source files, rather than the list of intermediate .o files
- is there a better way to specify additional include dirs (maybe using .INCLUDE_DIRS?) and library dirs?
- is there any automatic mechanism for handling .h dependencies
LVL 11
Who is Participating?
Duncan RoeConnect With a Mentor Software DeveloperCommented:
Ok this is how you do automatic dependency generation. Note that it WILL use the preprocessor in isolation so you'd better separate out CPPFLAGS and CXXFLAGS (IMHO it's never a "pointless complication" to do the right thing to start with:

# Following magic lifted from "info make"
%.d: %.cpp
        $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
        sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
        rm -f $@.$$$$
include $(SRCS:.cpp=.d)

The first time you run this, you get complaints from make because the .d files don't exist, but it goes ahead and generates them anyway.
The "clean" target should have the extra line "rm -f *.d"

The "magic" code should go right at the end (not sure if that's important, but I always do it)

Maximum debug information is obtained with options "-g3 -ggdb". With these options, gdb can see the values of #defined numeric constants, like EINVAL &c
evilrixSenior Software Engineer (Avast)Commented:
Various shortcuts and optimizations for makefiles are discussed here: -
Duncan RoeSoftware DeveloperCommented:
You should have -m64 -O -fPIC -fexceptions in CXXFLAGS (or maybe CFLAGS - you'll have to try it) since they are not preprocessor options.
You don't need CPPFLAGS on the link line and you shouldn't need CXXFLAGS either. I've never managed to avoid having a link line - post how it's done when you find out.
"info make" is a very good source of documentation. I always use the automatic dependency generation from it - have a look. (You can post again if you don't find it).
Is this homework?
Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

cupConnect With a Mentor Commented:
List of source files

SRCS=a.cxx b.cxx c.cxx

Include directories: there is no easy way to do it.  Just specifying a bunch of directories doesn't work.  You need the /I

MYINCDIR  = -I/usr/blabla/inc -I/usr/global/inc -I/usr/lablab
CPPFLAGS = -m64 -O -fPIC -fexceptions -DNDEBUG $(MYINCDIR)

Same with libraries.  It is better to specify path and library together

LIBXWIN=-L/usr/X11R6/lib -lXmu -lXm -lXt
LIBBOOST=-L/usr/boost/lib -lboostthread
LIBERATE=-L/home/erate -lerate
your gcc options miss a very important option.
-g option,without this option you couldn't debug your programme and if your programme cored, you will be embarrassed to process.
The GNU make manual is a good starting place for this. It's written in a very accessible way. See:
lbertaccoAuthor Commented:
Some answers:
evilrix/duncan_roe I will check your pointers and post back if I find interesting things, however  I already  know of "info make" and also the make manual in other formats, but the reason of my question was to avoid to read the whole make manual just for this.

duncan_roe: I mistakenly believed cppflags standed for cplusplus not cpreprocessor. Changed that to CXXFLAGS; I put CXXFLAGS and CPPFLAGS in the link rule because my make default link rule is: = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
so I tried to used the same rule with minimal changes
(you can see your make default rules running "make -p" in a directory without a makefile)
And no, this is no homework, I know how to use make quite well and used it for years but it might have evolved in ways I don't know so I'm just asking if there are better ways to use it for small projects. I mean, for example, having a default linking rule that doesn't work for c++ projects sounds suspicious to me, so maybe I'm missing something and there is a way to make it work (through a CXXFLAGS that make gcc behave like g++, or something else).

cup: good hint for the sources. Regarding inc/lib dirs, of course you can set and play with variables as you like as long as path dirs and lib dependencies end up in the final command, but I was asking if make has anything specific to handle this with its default rules.

yuy2002: we are not discussing compiler flags here, my flags were just an example

rstaveley: yes I know where to find the make manual in either pdf, html or info format, but see my first answer here.
lbertaccoAuthor Commented:
Ok I have something better, here is it:
SRCS=a.cpp b.cpp c.cpp

MYINCDIRS  = /usr/blabla/inc /usr/foe/inc
MYLIBDIRS  = /usr/blabla/lib
MYLIBS = mylib1 m pthread
CXXFLAGS =  -m64 -O -fPIC -fexceptions -DNDEBUG $(foreach dir,$(MYINCDIRS),-I$(dir))
LDLIBS = $(foreach dir,$(MYLIBDIRS),-L$(dir)) $(foreach lib,stdc++ $(MYLIBS),-l$(lib))

PROG=$(firstword $(SRCS:.cpp=))
$(PROG): $(SRCS:.cpp=.o)

        $(RM) $(PROG) $(SRCS:.cpp=.o)
This would build a final executable with the name of the first source file (it is quite common to have a source file with the same name of the final exec).
The differences are: a) I use LDLIBS instead of LDFLAGS so that the -l dependecies end up AFTER the .o dependencies in the link command. Note that LDLIBS is strangely missing in the "Variables Used by Implicit Rules" section of the make manual
b) I added -lstdc++ to the lib deps since default linking rule uses gcc instead of g++ and gcc doesn't add stdc++ automatically (g++ does). Alternatively you could set CC=g++.
c) it uses the default link rule

The only missing part is .h dependencies. Will see tomorrow if I find something simple.
Nifty, but...

> $(foreach dir,$(MYLIBDIRS),-L$(dir))

...doesn't specify path and lib together (as suggested by cup).

You might replace the directories in MYLIBDIRS with something that can be tokenised, using an inner patsubst invocation to split the directory from the list of libs and put an inner foreach to list libs within the directory.


MYLIBDIRLIBS  = /usr/blabla/lib,x:y /usr/foofoo/lib,z

(where the y and y libraries are in  /usr/blabla/lib and z is in /usr/foofoo/lib)

If I was a better person I'd attempt to write the function invocations, but I don't have the time to experiment right now and your Makefile is already a lot cleverer than any of mine.
Incidentally, using += makes it more legible:

 MYLIBDIRLIBS  = /usr/blabla/lib,x:y
 MYLIBDIRLIBS += /usr/foofoo/lib,z
Duncan RoeSoftware DeveloperCommented:
-DNDEBUG $(foreach dir,$(MYINCDIRS),-I$(dir))
should go in CPPFLAGS, because they are preprocessor directives
lbertaccoAuthor Commented:
Yes -D and -I are preproc options but in the implict rules the CPPCFLAGS is always used in pair with C/CXXFLAGS macro except when invoking the preprocessor alone. Since here I'm not using the preprocessor alone but only through the compiler, splitting options between CXX and CPP flags seemed a pointless complication
Here is a makefile I made this summer for the AIX  and Visual Age compiler xlc. I was a newbee same as you regarding UNIX makefiles. You may have to exchange the compiler and linker flags (and the names of course). But look at the 'rule' section, where it was defined how to *make* a  .o file from a .c file.

Regards, Alex

# Makefile

# macro(s)
CC = xlc
LFLAGS = -lc -lm
CSFLAGS = -qmkshrobj -bnoentry
EXPCOPT = -bE:wmvt.exp
OBJS = xxxxxx.o \
       yyyyyy.o \
       zzzzzz.o \
# rule(s)
# creates object from source.
      $(CC) $(CFLAGS) $<

# target(s), first target is default target
wmvt: $(OBJS)
      $(CC) $(CSFLAGS) -o $(EXPCOPT) $(LFLAGS) $(OBJS)

      rm -f *.o
      rm -f *.so
      rm -f wmvt

Note, the xlc wanted a <TAB> char preceeding any statement line following a target or rule.
lbertaccoAuthor Commented:
Interesting. Reading gcc docs and simplifying it considerably I'm now with:
sources = a.cpp b.cpp c.cpp

incdirs  = /usr/blabla/inc /usr/foe/inc
libdirs  = /usr/blabla/lib
libdeps = mylib1 m pthread
CPPFLAGS =  -DNDEBUG $(foreach dir,$(incdirs),-I$(dir))
CXXFLAGS =  -m64 -O -fPIC -fexceptions

LDLIBS = $(foreach d,$(libdirs),-L$(d)) $(foreach l,stdc++ $(libdeps),-l$(l))

prog = $(firstword $(sources:.cpp=))
$(prog): $(sources=:cpp=.o)

-include $(sources:.cpp=.d)
%.d: %.cpp
        $(CC) -MM -MF $@ -MT $(<:.cpp=.o) -MT $@ $(CPPFLAGS) $<

.PHONY : clean
        -$(RM) $(prog) $(sources=:cpp=.o) $(sources=:cpp=.d)
Differences: this generates and uses include-dependencies (with just 3 more lines). I replaced the ugly multi-step gcc/sed way which also uses intermediate files, with the more elegant gcc -MM option (of course you need GNU for this). The dep include is actually a "-include" so you don't get the warning if the dep is missing (it is just regenerated), "clean" is declared .PHONY and the "rm" command in clean has the leading "-" to ignore errors. Only predefined macros are uppercase, others are lowercase.
I agree that if you have MANY lib dependencies it is probably more elegant to declare each lib together with its libdir, also if you have just 1 or 2 lib deps, its' probably cleaner to just set LDLIBS directly without using the 'foreach' stuff; if you have a few libs I think this is a good compromise.

I'm quite happy now with this makefile and ready to give points unless someone has more comments...
Thanks for sharing, lbertacco. This has been educational.
lbertaccoAuthor Commented:
Well, to avoid building dependencies when doing a "make clean", which deletes them, the "include" statement can be surrounded by the following conditional:

ifneq ($(MAKECMDGOALS),clean)
-include $(sources:.cpp=.d)
The if..endif construct is specific to gnumake.  If that is your platform and you don't intend shifting to something else like AIX, Solaris, HPUX or Windows, then it isn't a problem.  If you do then you may get several variants of makefile.

One of the problems we used to have in dependency checking was that it dug deep into the includes from the C library.  These varied depening on the machine so the dependency table was being rebuilt whenever it was moved to a machine with different spec hardware.  To avoid this, we doctored the dependency files to stop once they got to files from the C library.
lbertaccoAuthor Commented:
Yes as you can see from the origianal question, this whole discussion is gnu make specific.
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.