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

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.

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.

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/*

Related

Makefile with multiple separate *.cpp files to output separate *.exe files in different dir

I am stuck, writing my Makefile.
Directory structure:
.\
Makefile
.\src\*.cpp(s)
.\bin
Desire: What I want to achieve with one Makefile.
Run: make
Output (Terminal):
g++ -g -Wall -c -o src/program1.o src/program1.cpp
g++ -g -Wall -c -o src/program2.o src/program2.cpp
g++ -g -Wall -c -o src/program3.o src/program3.cpp
g++ -g -Wall -c -o src/program4.o src/program4.cpp
Output (in /bin/)
program1.exe
program2.exe
program3.exe
program4.exe
EDIT:
CXX = g++
CXXFLAGS = -Wall -g3 -O0
SRC := ${wildcard src/*.cpp}
OBJS := $(SRC:.cpp=.o)
BIN := $(SRC:src/%.cpp=bin/%)
.PHONY: all
all: $(BIN)
$(BIN): $(OBJS)
$(CXX) -c $(CXXFLAGS) -o $(OBJS)
bin/%: src/%.o
$(CXX) -o $# $^
Error:
g++: warning: linker input file unused because linking not done
The introductory parts of the GNU make manual describe that all: $(BIN) creates a target all that depends on a target bin. That means make will try to create bin. Then you have $(BIN): $(OBJS) which says bin depends on all the object files, so make will try to create all the object files. Then there's a recipe for that rule that says, after you've created the object files run this command, which links together all the object files into a single program (bin).
So make is doing exactly what you asked it to do.
The problem is that is apparently not what you want it to do.
In your question you write, then take the original filenames of each *.cpp and add that to the executable which I don't fully understand, but I assumed that you want to link all the objects into a single executable, which is what your makefile does.
But then later you write: How can I output to bin directory and generate the correct executables?, but you never define what "correct executables" means, and this makes it sound like you want to turn each individual object file into its own executable; that's clearly not what your makefile does.
So before you can tell make what you want, first you have understand clearly what you want so you can write it in your makefile. And if you need us to help you write it into your makefile, you need to explain it clearly in your question so we can understand it.
Cheers!
ETA
OK so you want every source file to compile into an object file, then every object file to compile to a separate binary.
First compute the names of all the binaries you want to build:
SRCS := $(wildcard src/*.cpp)
BINS := $(SRCS:src/%.cpp=bin/%)
Now make a rule that depends on all the binaries:
all: $(BINS)
Now make a pattern rule that tells make how to build each one of those binaries:
bin/% : src/%.o
$(CXX) $(CXXFLAGS) -o $# $^ $(LDLIBS)
Now you're actually done, because make already has a built-in rule that knows how to build a .o file into the same directory where the .c file lives, so it can figure out how to build the src/x.o files on its own.
Try something like:
SRC:=${wildcard src/*.cpp}
OBJ:=$(patsubst %.cpp,%.o,${patsubst src/%,bin/%,${SRC}}}
to get the list of the object files, and the rule:
obj/%.o : src/%.cpp
${CXX} -o $# -c $<
for compiling into the right location.
EDIT You have now clarified that each file is a separate main.
SRC:=${wildcard src/*.cpp}
BIN:=$(patsubst %.cpp,,${patsubst src/%,bin/%,${SRC}}}
to get the list of the object files, and the rule:
bin/% : src/%.cpp
${CXX} -o $# $<
will write each output as an executable in bin. To kick it off:
all : ${BIN}

variable not updating when executing bash code in makefile

I'm trying to write a makefile that contains some bash commands in order to collect the names of the cpp files from a folder.
SRC_FILES=""
CC = g++
CFLAGS = -g
gather-files:
for var in $$(cd ./src && (ls -all *.cpp | awk '{print $$9}')); \
do \
SRC_FILES+="./src/"+"$(var) "; \
done; \
game: gather-files
$(CC) -c $(CFLAGS) $(SRC_FILES)
The SRC_FILES and var variables seems not to update when I run the make game command.
What am I missing?
Ignore the relatively incomplete g++ command, I just want to know how to make the SRC_FILES variable contain all of the names of the cpp files in the src folder.
This is the output of make game:
g++ -c -g ""
clang: error: no input files
LATER EDIT:
Solution, as suggested:
SRC_FILES := $(wildcard src/*.cpp)
CC = g++
CFLAGS = -g
game: $(SRC_FILES)
$(CC) -c $(CFLAGS) $(SRC_FILES)
You are mixing shell commands with makefile commands. That's not valid. The entire recipe is sent to the shell to be run there. Once the recipe has been expanded (which happens once before the shell is invoked) the results cannot contain any make operations.
In short, it's not possible (technically it can be done but it's A Very Bad Idea (tm) so don't) to change make variables from within a shell recipe.
Why don't you use GNU make operations instead?
SRC_FILES := $(wildcard src/*.cpp)
game: $(SRC_FILES)
...
Of course, this is kind of a silly makefile because it will recompile ALL the source files if ANY source file changes. You could get equivalent behavior by just writing a script that ran the compiler.
Your 'Last Edit' is still not ideal, as it builds everthing every time. Try something like this:
SRC_FILES := $(wildcard src/*.cpp)
OBJ_FILES := $(SRC_FILES:.cpp=.o)
DEP_FILES := $(SRC_FILES:.cpp=.d)
#Important: this is =, not :=
DEP_FLAGS = -MT $# -MMD -MP -MF $(DEPDIR)/$*.d
game: $(OBJ_FILES)
$(CC) -o $# $(OBJ_FILES)
# Pattern rule to build .o files
$(OBJ_FILES): %.o : %.cpp %.d
$(CC) $(DEP_FLAGS) -c $(CFLAGS) $< -o $#
#dummy rule to prevent building .d files explicitly.
$(DEP_FILES):
include $(wildcard $(DEP_FILES))
As to what this does -- it first populates SRC_FILES with any cpp files it finds. It then generates a list of object and dependency files from that list. Then we do some magic dependency stuff, which is described here -- basically, when you compile a file, it generates a .d file with a list of all headers it depends on, so now, if anything changes, make knows to rebuild the .c file.
Then there's a static pattern rule to build all the .o files, and a rule to link them all together to the game. Last, but not least, it includes the DEP_FILES that happen to exist when you start make.

Using makefile arguments without foo=

I have a makefile I use to compile a single file. When I need to pass an argument, I use target=targetFile.
The script takes the argument, looks for the file (within the same directory) that has the same value as the argument and compiles it.
I use this for compiling problems from uhunt and uva, which use a single c++ file. So I dont' need multiple makefiles for multiple source files. Single makefile for multiple source files is the reason I made the makefile.
Here's the code I have so far
OBJS = $(target).o
CC = g++
CFLAGS = -Wall -g -std=c++11
INCLUDE = -I./$(target)
#default command to run
all : Main-$(target) clean run
#compile and build
Main-$(target) : $(OBJS)
$(CC) $(CFLAGS) $^ -o $#
%.o : %.cpp
$(CC) -c $(CFLAGS) $<
#remove object and any other garbage files.
clean:
rm -rf -d $(target).o *~ *% *# .#*
#remove the compiled file
clean-all:
$(clean) rm Main-$(target)
#run the compiled file
run:
./Main-$(target)
The command I use to compile is,
make target=sourceFile
Also I don't include the file extension, I have all my source file extensions to be cpp
What I want in the end is:
make sourceFile
Just a side note, for using the command clean and clean-all, I use
make target=sourceFile clean
make target=sourceFile clean-all
I'd prefer if I can use:
make sourceFile clean
make sourceFile clean-all
You may use common Makefile variable MAKECMDGOALS that contains all targets passed to make.
Please try this variant
CC = g++
CFLAGS = -Wall -g
MAKECMDGOALS := $(filter-out clean, $(MAKECMDGOALS))
.PHONY: $(MAKECMDGOALS)
$(MAKECMDGOALS):
$(CC) $(CFLAGS) $#.c -o Main-$#
clean:
rm -f *.o
Here the lines
$(MAKECMDGOALS):
$(CC) $(CFLAGS) $#.c -o Main-$#
will generate separate build targets for each word in MAKECMDGOALS.
Note, we need this Makefile to know that 'clean' is a target for removing stuff, but not to attempt build Main-clean. This why we remove clean from MAKECMDGOALS using filter-out function.
So if we run make a b clean, the build system will generate automatically targets for building Main-a and Main-b and then use already written clean target
Disclaimer -- this is a non-standard use of Make, and will therefore open up all kinds of corner cases, so I don't recommend it. This is better suited for a shell script calling make. That being said... it is an interesting question.
You can't do make xxx clean, and not have it try to build xxx (unless you do some really nasty cludge using recursive make, but I won't go there). You could do something like make clean-xxx though, as follows:
%:Main-%
Main-%:%.cpp
$(CC) $(CFLAGS) $< -o Main-$#
clean-%:
rm Main-$*
Notice that %-clean has a shorter stem, and therefor takes precedence over the % if the make target starts with clean-.

Makefile that compiles all cpp files in a directory into separate executable

I am now studying C++. I want a makefile which will compile all of the cpp files in the current directory to separate executables. For example:
In a directory there are 3 c++ files, such as examp1.cpp, examp2.cpp and examp3.cpp. I want a makefile which will compile and link them and give examp1.exe, examp2.exe and examp3.exe
I have created a bash script to compile all of them and create exes but I think; that's not the exact way to do this.
I have a a Makefile for ".c", but that does not seem to work here. It is only creating object files and not actually linking it. It is as follows:
SRCS=$(wildcard *.c)
OBJS=(SRCS:.c=.o)
all: $(OBJS)
The above code compiles all the new and modified ".c" files to ".o" files with same name in the current directory.
The bash script I am using to create executables is as follows:
for i in ./*.cpp
do
g++ -Wno-deprecated $i -o `basename $i .cpp`".exe"
done
This means I want whatever ".cpp" files I put in that directory, by using a simple "make all" or anything like that it should compile.
A minimal Makefile that does what you want would be:
#Tell make to make one .out file for each .cpp file found in the current directory
all: $(patsubst %.cpp, %.out, $(wildcard *.cpp))
#Rule how to create arbitary .out files.
#First state what is needed for them e.g. additional headers, .cpp files in an include folder...
#Then the command to create the .out file, probably you want to add further options to the g++ call.
%.out: %.cpp Makefile
g++ $< -o $# -std=c++0x
You'll have to replace g++ by the compiler you're using and possibly adjust some platform specific setting, but the Makefile itself should work.
This is the Makefile that I use
CC = gcc
CFLAGS = -g -O2 -std=gnu99 -static -Wall -Wextra -Isrc -rdynamic -fomit-frame-pointer
all: $(patsubst %.c, %.out, $(wildcard *.c))
%.out: %.c Makefile
$(CC) $(CFLAGS) $< -o $# -lm
clean:
rm *.out
You should paste it somewhere in your home and whenever you change the dirctory just copy it there. I use an alias in my ~/.basrc to copy it
alias get_makefile_here='cp ~/Makefile ./'
Simply press make and bam, you're done. Also notice the fact that once you're done with the old files it will not rebuild their executable.
My answer builds on top of the answer by #Haatschii
I don't prefer to have the .out prefix to my binaries. Also I used his existing Make syntax to perform clean as well.
CXX=clang++
CXXFLAGS=-Wall -Werror -std=c++11
all: $(patsubst %.cpp, %.out, $(wildcard *.cpp))
%.out: %.cpp Makefile
$(CXX) $(CXXFLAGS) $< -o $(#:.out=)
clean: $(patsubst %.cpp, %.clean, $(wildcard *.cpp))
%.clean:
rm -f $(#:.clean=)
The simplest makefile you can create that might work for you is this:
all: examp1.exe examp2.exe examp3.exe
That will use make's default rules to create your three programs.

minimum c++ make file for linux

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++