136

My project directory looks like this:

/project
    Makefile
    main
    /src
        main.cpp
        foo.cpp
        foo.h
        bar.cpp
        bar.h
    /obj
        main.o
        foo.o
        bar.o

What I would like my makefile to do would be to compile all .cpp files in the /src folder to .o files in the /obj folder, then link all the .o files in /obj into the output binary in the top-level folder /project.

I have next to no experience with Makefiles, and am not really sure what to search for to accomplish this.

Also, is this a "good" way to do this, or is there a more standard approach to what I'm trying to do?

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Austin Hyde
  • 26,347
  • 28
  • 96
  • 129
  • http://www.gnu.org/software/make/manual/make.html, example: http://www.gnu.org/software/make/manual/make.html#Simple-Makefile – Anycorn May 25 '10 at 20:03
  • 9
    @aaa: I'm guessing the OP wants a solution that doesn't require explicitly listing each source file. – Cascabel May 25 '10 at 20:08
  • 12
    I don't want to specify each source file I have, and I've tried to read that manual before, but I find it disorganized and hard to understand. I learn much better from an actual example that does what I expect it does and is well explained, rather than dry technical manuals. – Austin Hyde May 25 '10 at 20:08
  • okay. But make documentation is excellent with good examples (it is not try technical manual). you are looking for pattern rules: http://www.gnu.org/software/make/manual/make.html#Pattern-Rules – Anycorn May 25 '10 at 20:13
  • 13
    That looks a little more like what I want. Though, IMHO, the make manual is a little dry, as it seems more targeted to developers who are at an intermediate level with make, and beyond that is very large and in-depth. Perhaps too much so. – Austin Hyde May 25 '10 at 20:39

2 Answers2

209

Makefile part of the question

This is pretty easy, unless you don't need to generalize try something like the code below (but replace space indentation with tabs near g++)

SRC_DIR := .../src
OBJ_DIR := .../obj
SRC_FILES := $(wildcard $(SRC_DIR)/*.cpp)
OBJ_FILES := $(patsubst $(SRC_DIR)/%.cpp,$(OBJ_DIR)/%.o,$(SRC_FILES))
LDFLAGS := ...
CPPFLAGS := ...
CXXFLAGS := ...

main.exe: $(OBJ_FILES)
   g++ $(LDFLAGS) -o $@ $^

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
   g++ $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<

Automatic dependency graph generation

A "must" feature for most make systems. With GCC in can be done in a single pass as a side effect of the compilation by adding -MMD flag to CXXFLAGS and -include $(OBJ_FILES:.o=.d) to the end of the makefile body:

CXXFLAGS += -MMD
-include $(OBJ_FILES:.o=.d)

And as guys mentioned already, always have GNU Make Manual around, it is very helpful.

bobah
  • 18,364
  • 2
  • 37
  • 70
  • 14
    Ah, you beat me by seconds. But I suggest `OBJ_FILES = $(patsubst src/%.cpp,obj/%.o,$(CPP_FILES))`. – Beta May 25 '10 at 20:48
  • 2
    I had to change this for it to work: `$<` should be `$^` for main.exe's rule and I think there's a typo with `obj/%.o: src/%cpp`. –  Jun 27 '12 at 11:56
  • 1
    @bobah You are missing a '.' in your objects rule for the cpp – regomodo Sep 25 '12 at 12:32
  • 1
    the special variables are probably worth explaining, since they're makefile specific and difficult to search for: https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html – Blake Nov 04 '14 at 16:07
  • Is there a place that describe how the automatic graph generation works? – Karim Tarabishy Mar 09 '15 at 01:49
  • 1
    @KarimTarabishy - if you mean the dependency graph with `-MMD` `gcc` flag then `gcc` documentation covers that. – bobah Jul 03 '15 at 13:23
  • Adding the -MP flag to the gcc command line will avoid make errors when/if some depended-on file disappears. – hmijail Aug 27 '15 at 21:25
  • Looks like this solution doesn't work if the src/ directory contains any subdirectories. – Lucas Penney Sep 28 '15 at 04:37
  • @LucasPenney - doing nested folders or just multiple folders (which can depend on one other) is a a more complex topic then just compiling files in a simple project and was not what the author of the question was asked about. – bobah Sep 28 '15 at 06:32
  • How would you write the same makefile, but have the cpp be dependant on the .h as well? So if I change the .h the cpp recompiles. The seems like a necessity, but I never see this in makefiles. I must be missing something... – Scorb Oct 17 '15 at 06:04
  • 1
    ScottF - see the very bottom of my answer – bobah Oct 17 '15 at 07:01
  • This answer appears to be specific to GNU Make (I'm thinking of the text functions). It's probably worth specifically mentioning that, so as not to mislead those looking for a portable solution (or just a solution for a different Make). – Toby Speight Oct 03 '16 at 18:20
  • @TobySpeight - considering how much easier GNU Make makes it, I'd recommend upgrading to it even on a non-GNU platforms, but fair point, the examples won't work on the bare [POSIX Make](http://pubs.opengroup.org/onlinepubs/009695399/utilities/make.html) – bobah Oct 03 '16 at 18:40
  • Agreed - it's the only Make I'll agree to use. – Toby Speight Oct 03 '16 at 20:51
  • 2
    I know this is an old question, but I modified a little according to my project, but it's not working. Here is my makefile: http://pastebin.com/4CksG9Wc I get in console: `make: *** No rule to make target '/main.o', needed by 'bin/main'. Pare.` – Mateus Felipe Jan 03 '17 at 00:35
  • 1
    I also like to include the Makefile itself as a dependency (because it is.) To do so, change `obj/%.o: src/%.cpp` to include your Makefile: `obj/%.o: src/%.cpp Makefile`. – pauln May 07 '17 at 14:53
  • @MateusFelipe I cloned a pastebin from yours and I hope to have it fixed: https://pastebin.com/sLFh65VF Please ignore mine -std=c++11, error was in OBJECT_FILES and then you have to link all object files in the main. I'm a beginner though. – Stanislav Dvoychenko Jun 17 '17 at 17:56
  • 1
    @Beta - incorporated your change ( proposed years ago :) ), thanks – bobah Oct 13 '17 at 07:08
8

Wildcard works for me also, but I'd like to give a side note for those using directory variables. Always use slash for folder tree (not backslash), otherwise it will fail:

BASEDIR = ../..
SRCDIR = $(BASEDIR)/src
INSTALLDIR = $(BASEDIR)/lib

MODULES = $(wildcard $(SRCDIR)/*.cpp)
OBJS = $(wildcard *.o)
xesf
  • 101
  • 1
  • 3
  • did you mean forward slash? Your example shows what traditionally is considered the forward slash. Specifically, the ones "leaning right" are considered to be "forward" and the ones left are considered to be "back" – Evan Teran Mar 04 '14 at 20:14
  • Yes, you right, I mean "slash" only. I updated the post. – xesf Jun 18 '14 at 10:11