GingerPlusPlus
GingerPlusPlus

Reputation: 5606

How to write simple generic build script for C++ project?

I'm writing C++ project made of few files on Linux. The project have no subdirectories.

I wanted like to have some as simple as possible, generic build script.

By generic, I mean that I don't want to hardcode file names, so that when I put new .cpp file into project, I don't have to modify build script. It should find and compile all modyfied source files in current directory, and link object files into executable. Nothing more.

I don't care about tool you'll use, since I don't know any yet.

I don't want to learn a tool from basics to write something as simple as that. For now, I just need a code, I'll learn when I'll need something more fancy.

What I tryed

make:

a.out: %.o
    $(CXX) %.o

%.o: %.cpp
    $(CXX) -Wall -c %.cpp

with no success:

make: *** Brak reguł do zrobienia obiektu `%.o', wymaganego przez `a.out'. Stop.

my translation of this message:

make: *** No rules to make object `%.o', required by `a.out'. Stop.

Before someone will ask, I'll answer: yes, my makefile is indented with 1 tab, not with spaces.

make -d prints out 664 lines, so I won't paste it here.

scons:

Program("main.cpp")

It's copyed from some StackOverflow answer, but it is definietly intended to build a executable from one source file, because I get linker errors when I want use it.

I ended us using bash:

g++ -Wall *.cpp

Simple. Does the job well... for now. I don't think it's elegant and I know it's probably inefficent, because it recompiles everything, even unmodyfied files.

Upvotes: 0

Views: 3716

Answers (2)

GingerPlusPlus
GingerPlusPlus

Reputation: 5606

SRC := $(wildcard src/*.c)
DEP := $(SRC:src/%.c=lib/%.d)
OBJ := $(SRC:src/%.c=lib/%.o)
CFLAGS := -Wall -Wextra -O2 -MMD

# Executable
lib/mines: lib/assets.o $(OBJ)
    ${CC} $^ -o $@

# Object files
lib/%.o:: src/%.c
    ${CC} -c $< -o $@ ${CFLAGS}

# Dependencies
# http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/
-include $(DEP)

.PHONY: clean
clean:
    rm lib/*

Upvotes: 0

I guess that you have a directory full of single-source C++ programs (e.g. each program has one single C++ source file) named .cpp (e.g. foo.cpp & bar.cpp), each independently compiled to an executable (e.g. foo & bar). You might try the following (untested) Makefile for GNU make.

CXX= g++
CXXFLAGS= -Wall -Wextra -g -O
RM= rm -vf

SOURCES= $(wildcard *.cpp)
BINARIES= $(patsubst %.cpp, %, $(SOURCES))

.PHONY: all clean

all: $(BINARIES)

clean:
     $(RM) *~ *.o $(BINARIES)

Read the documentation of GNU make and try make -p to find the builtin rules. See also these two examples of Makefile-s: this & that

If on the contrary you want one single executable myprogram from all the *.cpp files (like foo.cpp & bar.cpp etc....), you still can use $(wildcard *.cpp) in your Makefile (and you'll better not name a.out your executable, but something more meaningful), something like (in addition of common stuff like CXXFLAGS= above):

SOURCES= $(wildcard *.cpp)
OBJECTS= $(patsubst %.cpp, %.o, $(SOURCES))
all: myprogram
myprogram: $(OBJECTS)
    $(LINK.cc) $^ -o $@ $(LIBES)

In all cases, using $(wildcard *.cpp) is enough to have a Makefile generic enough on the list of sources. You may want to generate autodependencies (using gcc -M things, to some of your header files), see this.

Notice that you might have some C++ source or header files generated by some other means (e.g. your own awk or python script, or a _timestamp.c file generated with date, or some C++ files produced by a code generator like GNU bison or gperf, etc, etc...). Then you need to add specific rules into your Makefile.

So in practice, I don't believe in fully generic build files, but I am trying to show you that a Makefile can be almost generic and short. At some time you'll adapt it to your particular needs.

Upvotes: 2

Related Questions