variable not updating when executing bash code in makefile - c++

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.

Related

Why don't I need to use the -MT option for dependency generation when I save my object files to a separate directory?

I have a (GNU)Makefile that gives the .o files a name that puts them in a separate directory. If I'm reading the GCC documentation on preprocessor options correctly, then all directory components and the file extension of the source file are stripped, .o is appended, and that's the name of the target. However, it seems to also prepend the path to where I store my object files automatically, without me manually specifying what to name the target with the -MT option. What am I misunderstanding?
I tried to attach a minimal working example (MWE) project for your convenience, but I cannot figure out how to do this on stackoverflow.
I have tried with and without -MT $# in the CPPFLAGS. It doesn't seem to change a thing.
Makefile:
# Name directories
SRC_DIR := src
BUILD_DIR := build
OBJ_DIR := ${BUILD_DIR}/obj
DEP_DIR := ${BUILD_DIR}/dep
BUILD_DIRS := ${BUILD_DIR} ${OBJ_DIR} ${DEP_DIR}
# Name executable
BIN := ${BUILD_DIR}/howdy
# List directories where header files are found
_INCLUDE := include
INCLUDE := ${_INCLUDE:%=-I%}
# Make obj and dep files per source file
SRC := $(wildcard ${SRC_DIR}/*.cc) # Sneaky trick to get all .cc in a directory
OBJ := ${SRC:${SRC_DIR}/%.cc=${OBJ_DIR}/%.o}
DEP := ${OBJ:${OBJ_DIR}/%.o=${DEP_DIR}/%.d}
# Compiler and preprocessor setup
CXX := g++
CPPFLAGS = -MP -MMD -MF ${DEP_DIR}/$*.d
.PHONY: all # Output info and build if "make" or "make all" is invoked
all: ${BIN}
${BIN}: ${OBJ} # Link the object files to build the executable
${CXX} ${LDFLAGS} $^ -o $#
# Compile the source files into object files
${OBJ}: ${OBJ_DIR}/%.o: ${SRC_DIR}/%.cc | ${BUILD_DIRS}
${CXX} ${CXXFLAGS} ${CPPFLAGS} ${INCLUDE} -c $< -o $#
${BUILD_DIRS}: # Create directories as needed
mkdir -p $#
.PHONY: clean # Delete all object files, all dep files, and the executable
clean:
rm -rf ${BUILD_DIR}/*
-include ${DEP} # The dash makes make not fail if .d file not found
main.d:
build/obj/main.o: src/main.cc include/howdy.hh
include/howdy.hh:
This question doesn't have anything to do with make or makefiles. It's purely about how the GCC compiler's dependency generation works.
I agree with you that the behavior generated doesn't seem to match the documentation, unless we're misinterpreting what it says. Here's a test case, that doesn't need all the complexity of the makefile you provided:
$ touch /tmp/foo.c
$ gcc -MP -MMD -MF /tmp/foo.d -c -o /tmp/blahlbah.o /tmp/foo.c
$ cat /tmp/foo.d
/tmp/blahblah.o: /tmp/foo.c
It appears that, regardless of what the docs appear to say, the output target name by default (with no -MT) is the name provided with -o.
Perhaps what the docs mean is that if you don't provide -o and you don't provide -MT, then the result will be as documented. But, I think this is not a very successful way to document this.
In any event, I don't think StackOverflow is the right place to pursue this; you should contact the GCC folks for example at gcc-help#gnu.org

How to create a Makefile for a C++ project with multiple directories?

I want to create a Makefile for a project with the following layout:
Source files (.cpp, potentially .c) in /src, with potential subdirectories
Header files (.h, .hpp...) in /inc, with potential subdirectories
Object files (.o) in /obj, with potential subdirectories
External libraries in /lib
Compiled program in /bin
So far, I've managed to write together this Makefile, but with some issues:
SRC_DIR := src
BIN_DIR := bin
LIB_DIR := lib
INC_DIR := inc
OBJ_DIR := obj
SRCEXTS := .c .C .cc .cpp .CPP .c++ .cxx .cp
HDREXTS := .h .H .hh .hpp .HPP .h++ .hxx .hp
TARGETS := $(BIN_DIR)/program
SOURCES := $(wildcard $(addprefix $(SRC_DIR)/*,$(SRCEXTS)))
HEADERS := $(wildcard $(addprefix $(LIB_DIR)/*,$(HDREXTS)))
OBJECTS := $(addsuffix .o, $(basename $(SOURCES)))
CXX = g++
CXXFLAGS = -std=c++17 -c -g -Wall
.PHONY: all clean
all: $(TARGETS)
$(TARGETS): $(OBJECTS)
$(CXX) $^ -o $#
$(OBJ_DIR)%$(OBJECTS): $(SRC_DIR)%$(SOURCES)
$(CXX) $(CXXFLAGS) $< -o $#
clean:
rm -f $(OBJECTS) $(TARGETS)
I've tried to make it as "generic" as possible, so future projects could be started with this layout and makefile as a template. Currently, it creates the .o-files inside the src-directory alongisde the source code. It also fails when trying to compile the program with
g++ src/main.o -o bin/program
/usr/bin/ld: src/main.o: _ZSt4cout: invalid version 3 (max 0)
/usr/bin/ld: src/main.o: error adding symbols: bad value
collect2: error: ld returned 1 exit status
make: *** [Makefile:23: bin/program] Error 1
Very new to C++ development. Been on a wild goose-chase for a while, trying to get a clear image of how it all works. My code is basically a weird Frankenstein monster of several code snippets I've stumbled upon. Hopefully my intentions are clear enough, this is my last ditch effort! Thanks in advance :)
As #JohnBollinger points out, you are attempting too much at once. I will suggest a few changes to get your makefile off the ground.
I can't explain the error you get when you try to build the executable (you haven't given us enough information to reproduce the error), but it doesn't look like a Make problem. I suggest you try to build it without Make, using the command line, and see what happens.
I will assume that the names of your sources end in ".cpp" (such as src/sailboat/foo.cpp), the names of your headers end in ".hpp", and the directory tree under obj/ is already present and correct. These restrictions are temporary training wheels; you can remove them when you have more skill.
First, finding the source files. This:
SOURCES := $(wildcard $(addprefix $(SRC_DIR)/*,$(SRCEXTS)))
will not work if src/ has subdirectories. To recurse into subdirectories, we will use find. (There is a shortcut available to GNUMake, but for now we'll do things the slow and careful way).
SOURCES := $(shell find src -name "*.cpp")
Now to construct the names of the desired object files, such as obj/sailboat/foo.o. This:
OBJECTS := $(addsuffix .o, $(basename $(SOURCES)))
will give you src/sailboat/foo.o. We need a different command to change the leading directory as well as the suffix:
OBJECTS := $(patsubst src/%.cpp,obj/%.o,$(SOURCES))
Some of the source files refer to header files, so before we can start building objects, we must be able to supply them. The compiler can find the needed headers, but we must tell it where to search. So we need the directories, not the full paths:
HEADERS := $(shell find inc -name "*.hpp")
HEADERDIRS := $(sort $(dir $(HEADERS)))
(The sort is just to remove duplicates. Not necessary, but tidy.)
Now the rule to build the objects. This is incorrect:
$(OBJ_DIR)%$(OBJECTS): $(SRC_DIR)%$(SOURCES)
$(CXX) $(CXXFLAGS) $< -o $#
Remember that OBJECTS can contain several space-separated words. So if it contains foo bar, the target will be obj/%foo bar, which is clearly not what you intended. Likewise the prerequisite list is wrong, and the recipe too. Junk it and start over.
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $< -c -o $#
Then remember the header files, and add flags to tell the compiler where to look for them:
INCLUDEFLAGS := $(addprefix -I,$(HEADERDIRS))
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $< -c $(INCLUDEFLAGS) -o $#
That should be enough to get your makefile working; further refinements can wait.
I'm not mastering makefiles but one thing for sure : target "all" is definitively not a PHONY target because it often depends on other targets (in fact, it always depends on other targets, by definition !).
Also, as said John Bollinger, it is obviously possible to have only one makefile at the root.
"all" target is not mandatory : make will look for the first target fisrt.
The folder structure is like this :
----root
----src
----inc
----obj
----lib
Here's a simple one of mine (rules to build static libraries have been commented out) :
CC=g++
SRCDIR=./src/
INCDIR=./inc/
INCFLAG=-I$(INCDIR)
OBJDIR=./obj/
LIB=./lib/
LIBFLAG=-lstdc++
#-lmystaticlibrary -lmyclasses
#$(LIBFLAG) -L$(LIB)
#STATICLIBRARIES= mystaticlibrary myclasses
OBJECTS = $(OBJDIR)apprendre.o $(OBJDIR)myfunctions.o $(OBJDIR)myclasses.o
apprendre: $(OBJECTS)
# echo
# echo --------------------- Edition des liens
$(CC) $(OBJECTS) -o $# $(INCFLAG)
# mystaticlibrary: mystaticlibrary.o
# # echo
# # echo --------------------- Compilation librairie statique $#
# ar cr $(LIB)lib$#.a $(OBJ)$#.o
# ranlib $(LIB)lib$#.a
# myclasses: myclasses.o
# # echo
# # echo --------------------- Compilation librairie statique $#
# ar cr $(LIB)lib$#.a $(OBJ)$#.o
# ranlib $(LIB)lib$#.a
$(OBJDIR)%.o: $(SRCDIR)%.cpp $(INCDIR)myfunctions.h $(INCDIR)myclasses.h
# echo
# echo --------------------- Compilation $<
$(CC) -c $< $(INCFLAG) -o $#
run:
# echo
# echo "-----------------------> GO !!! : apprendre"
# ./apprendre

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

How do I write a smart makefile?

I'm new to linux and new to makefiles so I'm a little stumped at this point. I've been staring the make manual for an hour now and figured I would just ask:
I want to create a makefile for a relatively small project, whose source files are in proj/src/, and within subdirectories of that location. I have written a makefile at proj/makefile and want to use it to gather up all the source files, find their dependencies, and compile the result into proj/build/. Here is what I've written:
# here are my files and directories (there are also header files that are not
# listed here, but these are referred to from within the .cpp files with
# respect to the proj/src directory)
# proj/makefile
# proj/src/
# proj/src/main.cpp
# proj/src/dir1/
# proj/src/dir1/source1.cpp
# proj/src/dir2/
# proj/src/dir2/source2.cpp
# proj/build/
srcDir = src/
buildDir = build/
# This is a list of all the object files (can I get this programatically?)
objects = main.o source1.o source2.o
all: prog
# Here I want to compile all source (.cpp) files from src/ and all of its subdirectories, and to find the dependencies I want to call g++ -MM to automatically generate the list:
%.o: %.cpp
$(CXX) $(CXXFLAGS) -MM -I $(srcDir)
clean:
rm -rf *o $(buildDir)/prog
This is far from functional but I wanted to give it ago before asking. Running this gives
make: * No rule to make target main.o', needed byprog'. Stop.
So presumably my attempt at automatically writing the object files failed. If someone could give me some direction that would be great, I'm hoping that between the comments and code you can make out the intention.
EDIT: I have now tried the following:
SHELL := /bin/bash
srcDir = src
buildDir = bin
sources := $(shell find $(srcDir) -name *.cpp)
objects := $(sources:%.cpp=%.o)
-include $(sources:%.cpp=%.d)
# This is a list of all the object files (can I get this programatically?)
all: prog
prog: $(objects)
g++ $(objects) -o $(buildDir)/prog
# Here I want to compile all source (.cpp) files from src/ and all of its subdirectories, and to find the dependencies I want to call g++ -MM to automatically generate the list:
%.o: %.cpp
$(CXX) $(CXXFLAGS) -MMD -MP -c -I $(srcDir)
clean:
rm -rf *o $(buildDir)/hello
But when I run this I get the following error:
g++ -MMD -MP -I src
g++: fatal error: no input files
compilation terminated.
make: *** [src/core/Cell.o] Error 1
It wants to build main.o from main.cpp, but there is no main.cpp at the top level. You could specify the full paths of the object files, if they are to be built alongside the source files:
objects = $(srcDir)/main.o $(srcDir)/dir1/source1.o $(srcDir)/dir2/source2.o
can I get this programatically?
I do it using gnumake's shell function:
SHELL := /bin/bash
sources := $(shell find $(srcDir) -name *.cpp)
objects := $(sources:%.cpp=%.o)
to find the dependencies I want to call g++ -MM to automatically generate the list
Use -MMD to generate dependency files as well as compiling. It's also a good idea to specify -MP here - that makes sure the dependencies are correctly updated when you remove a header. Given the variables defined above, you can include the dependency files with
-include $(sources:%.cpp=%.d)

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.