8

My latest project is in C++ and I am using GNU Make. The project directory layout is as follows:

project
|-src
  |-subdir1
  |-subdir2 (containing tests)
|-doc
|-bin

I would like to be able to call make in the top level directory (i.e. need a makefile in the project directory) to compile all sources in both "src" subdirectories and place the resulting binaries in the "bin" directory.

What would be the best approach to do this? It would also be great if I didn't have to add a make rule for every source file, but just had one for all .cc and .h files in the directories.

Kara
  • 6,115
  • 16
  • 50
  • 57
Jakob
  • 83
  • 1
  • 1
  • 3

3 Answers3

14

Make allows you to generalise your rules, so you won't need to create one for every file.

project
|-src
  |-subdir1
  |-subdir2 (containing tests)
|-doc
|-bin

You can try something like this:

#This finds all your cc files and places then into SRC. It's equivalent would be
# SRC = src/main.cc src/folder1/func1.cc src/folder1/func2.cc src/folder2/func3.cc

SRC = $(shell find . -name *.cc)

#This tells Make that somewhere below, you are going to convert all your source into 
#objects, so this is like:
# OBJ =  src/main.o src/folder1/func1.o src/folder1/func2.o src/folder2/func3.o

OBJ = $(SRC:%.cc=%.o)

#Tells make your binary is called artifact_name_here and it should be in bin/
BIN = bin/artifact_name_here

# all is the target (you would run make all from the command line). 'all' is dependent
# on $(BIN)
all: $(BIN)

#$(BIN) is dependent on objects
$(BIN): $(OBJ)
    g++ <link options etc>

#each object file is dependent on its source file, and whenever make needs to create
# an object file, to follow this rule:
%.o: %.cc
    g++ -c $< -o $@
Sagar
  • 9,456
  • 6
  • 54
  • 96
3

Use one make run to do the build (I'm not a fan of recursive make). Don't use $(shell) as it kills performance. Put build products into a temporary dir.

Sketch:

subdir1-srcs := $(addprefix subdir1/,1.cc 2.cc 3.cc)
subdir1-objs := ${subdir1-srcs:subdir1/%.cc=subdir1/obj/%.o)
bin/prog1: ${subdir1-objs} ; gcc $^ -o $@
${subdir1-objs}: subdir1/obj/%.o: subdir1/%.cc # Static pattern rules rule
    gcc -c $< -o $@
${subdir1-objs}: subdir1/obj/.mkdir # Need to create folder before compiling
subdir1/obj/.mkdir:
    mkdir -p ${@D}
    touch $@

Can you see the boiler plate here? A few functions together with $(eval) should allow you to write:

$(call build,bin/prog1,subdir1,1.cc 2.cc 3.cc)
$(call build,bin/prog2,subdir2,a.cc b.cc c.cc d.cc)

with these targets automatically added as dependencies of the phony all, and nicely -j compatible (just type make -j5 all to build).

bobbogo
  • 14,989
  • 3
  • 48
  • 57
-1

You will have to make sub-makefile within the directories, and use the commands to output g++ compiled files into the directories you want. (Use makefile variables etc...)

You will find a nice introduction on recursive Makefiles here

Makefile let you use some generic rules like :

%.o:%.cpp
    gcc blahblahblah

and also you can include a global makefile from another using include.

If you also google makefile, you'll find plenty of how-to on the subject.

M'vy
  • 5,696
  • 2
  • 30
  • 43