Single top-level makefile with source subdirectories - c++

Firstly, apologies for my ignorance. I'm sure the answer to my question exists in one of the many existing makefile threads here. However, I have been unable to find one that concisely and clearly answers my specific question without obfuscating the answer with details that aren't relevant to my particular situation.
My code directory has a single top-level source file containing main. The rest of the source files are organised in subdirectories according to logical divisions in the system. The code contains no relative paths in the includes. This means that everything works perfectly if all the code is in a single directory using the following, simple makefile:
CC=g++
CFLAGS=-c
LDFLAGS=
SOURCES=Main.cpp Source1.cpp Source2.cpp Source3.cpp Etc.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=executable
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
$(CC) $(CFLAGS) $< -o $#
Until now I have been building my code using the NetBeans IDE. This has helped preserve my make ignorance by generating some vast and overly complicated makefiles on my behalf. Now the time has come to distribute my code for public use so I'm looking to produce a makefile will enable me to distribute the code with the directory structure I have.
Can you help?
Regards,
Enthusastic Amateur.

Take a look at this:
# Source directories separated by space
# Example ./ src1/ src2/
SRCDIR = ./ src/
# Directory where object files will be placed
OBJDIR = obj/
# Include directories separated by space
# Example: include1/ include2/
INCDIR = include/
# Directory where binary file will be placed
BINDIR = bin/
# Name of the result file
TARGET = app
# Compiler
CXX = g++
# Retrive list of the source files
SRC = $(wildcard $(addsuffix *.cpp,$(SRCDIR)))
# Generate list of the object files
OBJ = $(addprefix $(OBJDIR), $(patsubst %.cpp, %.o, $(notdir $(SRC))))
VPATH = $(SRCDIR)
# Compilation flags
CXXFLAGS = -std=c++11 -pthread
$(TARGET) : $(OBJ)
#echo Linking...
#mkdir -p $(BINDIR)
#$(CXX) $(CXXFLAGS) -o $(BINDIR)$# $(OBJ)
$(OBJDIR)%.o : %.cpp
#echo Compiling $< in $#...
#mkdir -p $(OBJDIR)
#$(CXX) $(CXXFLAGS) $(addprefix -I,$(INCDIR)) -c -o $# $<
clean :
#$(RM) -r $(OBJDIR)
#$(RM) -r $(BINDIR)
Here you can provide multiple source directories.

And "everything works perfectly" as well if the code is in multiple directories, using the same makefile you already have. No changes needed.

Related

Makefile target with wildcard is not working

I have a simple project, whose folder structure is something like:
ls -R
.:
build include makefile src
./build:
./include:
myfunc.h
./src:
main.cpp myfunc.cpp
I want to compile the .cpp sources into .o object files, which should end into ./build folder. Using the GNUmake documentation and other sources (e.g. Proper method for wildcard targets in GNU Make), I wrote this makefile:
CXX := g++
CXXFLAGS += -I./include
CXXFLAGS += -Wall
OBJDIR := ./build
SRCDIR := ./src
PROGRAM = release
DEPS = myfunc.h
SRC = $(wildcard $(SRCDIR)/*.cpp)
OBJ = $(patsubst $(SRCDIR)/%.cpp, $(OBJDIR)/%.o, $(SRC))
all: $(PROGRAM)
$(PROGRAM): $(OBJ)
$(CXX) $(CXXFLAGS) -o $(PROGRAM) $(OBJ)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(DEPS)
$(CXX) $(CXXFLAGS) -c $< -o $#
.PHONY: clean
clean:
rm $(PROGRAM) $(OBJ)
But I get the error message: make: *** No rule to make target 'build/main.o', needed by 'release'. Stop.. I tried a lot of different ways but I cannot manage to have my .o files end up in the ./build directory. Instead, everything works if I put them in the root directory of the project. I can also make it work by specifying a rule for each object file, but I'd like to avoid that. What am I missing?
(I am using GNUmake version 4.3)
The problem is here:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(DEPS)
$(CXX) $(CXXFLAGS) -c $< -o $#
See the $(DEPS)? That expands to myfunc.h. The compiler knows where to find that file (or would if this recipe were executed), because you've given it -I./include, but Make doesn't know where to find it (so it passes over this rule).
Add this line:
vpath %.h include
P.S. If you want to be really clean, you can add a variable:
INCDIR := ./include
CXXFLAGS += -I$(INCDIR)
vpath %.h $(INCDIR)

Makefile: dynamic source file names and object directory

Im currently trying to improve the makefile im using to build my c++ project using the sfml-framework. The folder structure of my project currently looks like this:
Src/Header for Header Files
Src/Source for .cpp Files
Bin/ for the .exe
Lib/ for the sfml library
My current makefile:
CC = g++ -g
SRC = Src/Source/
BIN = Bin/
INC = -I Lib/SFML/include/ -I Src/Header/
LIB = -L Lib/SFML/lib/ -lsfml-graphics-d -lsfml-window-d -lsfml-system-d
EXE = Test
SOURCEFILES = $(SRC)Main.cpp $(SRC)Menu.cpp $(SRC)Button.cpp
OBJ = $(SOURCEFILES:.cpp=.o)
all: $(SOURCEFILES) $(EXE)
$(EXE) : $(OBJ)
$(CC) -o $(BIN)$(EXE).exe $(OBJ) $(LIB)
.cpp.o:
$(CC) -c $< $(INC) -o $#
This makefile works fine, however there are a few things i would like to improve but could not get to work.
It's currently nessecary to add all cpp files manually to the list of source files. Since the project is most likely going to grow fast in terms of file count and i kind of want to split the source files into different subdirectories this is going to be a mess very soon. I tried to get all cpp files in a directory with $(wildcard Src/Source/*.cpp) instead of listing them individually but it failed to even execute the makefile. What am i missing there?
With my current makefile all .o files are placed at the same location as the .cpp file which is also something i dont really want. Is there a way to output all .o files in a extra \obj\ directory and link it into the .exe from there?
Also since this is the first time im writing a makefile if there are some general improvements to my approach any advice is appreciated aswell.
wildcard should work:
SOURCEFILES = $(wildcard $(SRC)/*.cpp)
But if you plan to have your source files in various subdirectories of Src/Source/, it will not work that well. Use the find utility instead, thanks to the shell make function. And yes, you can store all your object files in a separate directory:
CC = g++ -g
SRC = Src/Source/
OBJ = Obj/
BIN = Bin/
INC = -I Lib/SFML/include/ -I Src/Header/
LIB = -L Lib/SFML/lib/ -lsfml-graphics-d -lsfml-window-d -lsfml-system-d
EXE = $(BIN)Test.exe
SOURCEFILES = $(shell find $(SRC) -type f -name *.cpp)
OBJECTFILES = $(patsubst $(SRC)%.cpp,$(OBJ)%.o,$(SOURCEFILES))
all: $(SOURCEFILES) $(EXE)
$(EXE): $(OBJECTFILE)
$(CC) -o $# $^ $(LIB)
$(OBJ)%.o: $(SRC)%.cpp
mkdir -p $(dir $#)
$(CC) -c $< $(INC) -o $#
Note that I also modified your EXE definition such that the corresponding rule is a real files-to-file make rule and uses the $# and $^ automatic variables.
I'm kinda suprised that wildcard doesn't work for you, any error codes you could share?
Usually I write my SRCS and OBJS variables like this:
SRCS = $(wildcard src/*.cpp) \
$(wildcard test/*.cpp)
OBJS = $(patsubst %.cpp,$(BINDIR)/%.o,$(SRCS))
And to build your object files into another directory you could write something like this:
$(BINDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $#

Set Makefile to build in another directory

Lets say my Makefile is located in the same directory as the sources and I want to store object files in obj/ subdirectory and the target executable in bin/ subdirectory.
src/
main.cpp
test.cpp
test.h
/many other *.cpp files and headers/
Makefile
obj/
bin/
The problem with my Makefile is that I cannot get the OBJECTS variable to
contain a list of *.o files with the samy names as *.cpp files, but in OBJDIR subdirectory.
Currently it only works if I name all object files one by one.
CXX=g++
CXXFLAGS=-c -Wall
LDFLAGS=
SOURCES=$(wildcard *.cpp) # very convenient wildcard
BINDIR=bin
OBJDIR=obj
OBJECTS=$(OBJDIR)/main.o $(OBJDIR)/test.o # how do I make a wildcard here?
TARGET=$(BINDIR)/my_executable
all: $(SOURCES) $(TARGET)
$(TARGET): $(OBJECTS)
$(CXX) $(LDFLAGS) $(OBJECTS) -o $#
$(OBJECTS): $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $< -o $#
clean:
rm -rf $(OBJDIR)/$(OBJECTS) $(BINDIR)/$(TARGET)
Please help
Thank you!
Similar question to yours already exists on this site here:
Can I compile all .cpp files in src/ to .o's in obj/, then link to binary in ./?
either way something like this should solve your problem:
OBJ_FILES := $(addprefix obj/,$(notdir $(CPP_FILES:.cpp=.o)))

Makefile, find sources in src directory tree and compile to .o in build file

I'm currently trying to re-write a makefile for a project that I've inherited to make the source tree neater and easier to work with. At the moment the source tree is something like this:
Project/
----bin/
----build/
----include/
----main.h
----part1.h
----part2.h
----part3.h
----src/
----main.cpp
----part1.cpp
----Subdir/
----part2.c
----Subdir2/
----part3.cpp
What I want is a rule in my makefile that will find all of the .cpp and .c files in my src directory and compile them to a flat directory of objects in the build directory. At the moment I have the following in my makefile but this seems to miss a number of the cpp files:
BUILDDIR = build
$(BUILDDIR)/%.o : src/**/%.cpp | $(BUILDDIR)
$(BUILDDIR)/%.o : src/%.cpp | $(BUILDDIR)
$(CXX) $(CFLAGS) -c $< -o $# $(INCS)
$(BUILDDIR)/%.o : src/**/%.c | $(BUILDDIR)
$(BUILDDIR)/%.o : src/%.c | $(BUILDDIR)
$(CC) $(CFLAGS) -c $< -o $# $(INCS)
At the moment when I run make -n it seems that it has detected main.cpp and part1.cpp but none of the ones in subdirectories. Make then goes on to try and load the files according to later rules in the Makefile.
Due to the number of files in the project I'd rather not write a list of them manually but if it comes to that I might have to.
You can explicitly define directories with source files. For example:
DIRS = src src/subdir1 src/subdir2
SEARCHC = $(addsuffix /*.c ,$(DIRS))
SEARCHCPP = $(addsuffix /*.cpp ,$(DIRS))
SRCS = $(wildcard $(SEARCHC))
SRCS += $(wildcard $(SEARCHCPP))
And to let make find your sources files add to your Makefile:
vpath %.c $(DIRS)
vpath %.cpp $(DIRS)
I am also using special target to check my Makefile:
help:
#echo 'Sources:'
#echo $(SRCS)
Make's wildcard function could be of use to you here.
See also
Sources from subdirectories in Makefile

Makefile: Failed to get basename to work with patsubst

My Makefile:
compiler=g++
cflags=-g -Wall -I.
src=$(shell find . -name *.cc) #find all .cc files, with path name
srcBaseName=$(shell basename -a $(src)) # extract base names by stripping off the path
header=$(shell find . -name *.h) # all header files
obj=$(patsubst %.cc, %.o, $(srcBaseName)) # Problematic line
bin=bin/myProgram
all: $(bin)
$(bin): $(obj)
$(compiler) $^ -o $#
%.o: %.cc
$(compiler) $(cflags) -c $^ -o $#
clean:
rm $(obj) $(bin)
results in the following error:
make: *** No rule to make target 'SomeObjectFile.o', needed by
'bin/myProgram'. Stop.
The problematic line:
obj=$(patsubst %.cc, %.o, $(srcBaseName))
If I change $(srcBaseName) to $(src), then everything builds fine. But in that case the .o files are going to be scattered in the corresponding folders with .cc files, which I don't want.
I'd like to have a dedicated (obj/) folder to store all the .o files.
How can I do it?
First try:
obj=$(patsubst %.cc, %.o, obj/$(srcBaseName))
Second try:
obj=$(patsubst %.cc, %.o, obj\/$(srcBaseName))
Why did they NOT work?
/**********************Edited on 16th Feb 2015**********************/
Based on the suggestions in the answers, I updated my Makefile to be this:
compiler=g++
# source compilation flags
cflag=-g -Wall -std=gnu++0x -I./header/
# source link flags
lflag=
# lib used by proj
lib=
tflag=-g -Wall -std=gnu++0x
# test link flags
tlflag=
# test libs
testLib=lib/libgtest.a
# source code
src=$(shell find "./src" -name "*.cc")
srcBaseName=$(shell basename -a $(src))
obj=$(addprefix obj/, $(patsubst %.cc, %.o, $(srcBaseName)))
vpath %.cc $(dir $(src))
# header files
header=$(shell find "./header" -name "*.h")
# test files
testSrc=$(shell find "./test" -name "*.cc")
testSrcBase=$(shell basename -a $(testSrc))
testObj=$(addprefix obj/, $(patsubst %.cc, %.o, $(testSrcBase)))
vpath %.cc $(dir $(testSrc))
# binary files
bin=bin/Driver
testBin=bin/Test
all: prog test
prog: $(bin)
$(bin): $(obj)
$(compiler) $(lflag) $^ $(lib) -o $#
#$(obj): $(src) $(header)
obj/%.o: %.cc $(header)
$(compiler) $(cflag) -c $< -o $#
test: $(testBin)
$(testBin): $(testObj)
$(compiler) $(tlflag) $^ $(testLib) -o $#
obj/%.o: %.cc
$(compiler) $(tflag) -c $< -o $#
clean:
rm $(obj) $(bin) $(testObj) $(testBin)
Here's the intention behind the make:
make prog:
make should find all the source files(.cc) under ./src directory, and produce an .o file with the same file name in the ./obj directory, insensitive to the levels of subdirectories so that I can freely add new cc files without the need to update the Makefile. Each .o file depends on the corresponding(just the one with the same name, not all) .cc file and ALL headers(make does not automatically know what header files a cc file includes without parsing the file; if you have a clever method to achieve this, do let me know!). For example, ./src/subdirectory1/sample1.cc should produce ./obj/sample1.o and ./obj/sample1.o depends on ./src/subdirectory1/sample1.cc + ./header/sample1.h + ./header/sample2.h + ...
make test:
it should do similar things to the test source files in the ./test folder, with the exception that there's no header involved. In case this detail helps, I'm using Google Test.
However, my Makefile is not quite working in the intended way because it has the following problems:
1, if I run make test, the recipe $(compiler) $(tflag) -c $< -o $# is not executed(tflag means 'test compilation flag', which doesn't have the -I./header/ part; cflag means 'source code compilation flag', it has the -I./header/ part). Instead, the recipe in phony prog $(compiler) $(cflag) -c $< -o $# is executed. This observation comes from the output in which '-I./header/' shows up. I guess this is because the cflag pattern rule in phony prog overrides the tflag one in phony test? I vaguely remember make picks the best matching pattern rule - the two are essentially the same(I have the intention that the pattern rule under a specific phony should get executed when that phony is executed, which doesn't seem to be feasible?), so make will always pick the first one. This conclusion is verified by swapping the order of two pattern rules in the Makefile, and this time the tflag rule always gets picked. So a natural question to ask is, how do I execute the pattern rule under a specific phony when that phone is executed?
2, Assuming it's not feasible to do what I wanted to do in point 1, I start to think about alternatives. Can I do something like: #$(obj): $(src) $(header) so that I can get rid of the pattern rule to work around the way make picks the pattern rule. However, this is obviously not correct as it's saying, each .o file in $(obj) depends on ALL src files and ALL header files. Is it at all a right direction?
Thanks a lot, looking forward to hearing from you.
3 key questions have been highlighted in bold and italicized.
Your problem is this line:
%.o: %.cc
That line tells make that to create some/path/file.o you will use some/path/file.cc.
If you want all .o files in one single directory, but still want to have the source files in different directories you will need one such rule for each source directory. Or, you could add all directories to the VPATH variable, something like:
VPATH=$(dir $(src))
Or maybe better:
VPATH=$(dir $(SRC))
Usuing capital letters for your variables in a Makefile is a good way to avoid confusing them with function names.
I will do my best to also answer your new questions:
1) As you are using the gnu compilers it is possible to automatic find the dependencies of .h files in .c files. You could add rules like this to your Makefile:
# Where .d-files will be created for dependencies
DEP=dep
# Dependency files
DEPS = $(srcBaseName:%.cc=$(DEP)/%.d)
# Before compiling object file, also make sure dependency file is
# created to test the need for future recompilation
obj/%.o: %.cc $(DEP)/%.d
$(compiler) $(cflags) -c $< -o $#
# Use gnu compiler to create dependency files
$(DEPS): $(DEP)/%.d: %.cc $(filter-out $(wildcard $(DEP)), $(DEP))
$(compiler) -MM $(cflags) -MT $# $< > $#
# Create directories which might be needed
$(DEP) $(OBJ) $(BIN) $(MO):
mkdir -p $#
# Let Makefile use any generated dependency files
ifneq ($(wildcard $(DEPS)),)
include $(wildcard $(DEPS))
endif
Please note that in the compilation rule I replaced $^ with $< as we don't want to compile the dependency file.
2) I would avoid two pattern rules looking the same. Instead I would change cflag depending on the target, something like this:
ifeq ($(MAKECMDGOALS),debug)
CFLAGS += -g
else
CFLAGS += -O2
endif
I hope these answers will guide you in the right direction
The main problem is that make cannot use the pattern rule
%.o: %.cc
$(compiler) $(cflags) -c $^ -o $#
to build obj since it cannot find common stems between your .o files and your .cc files to match %. An easy way to fix this is to tell make where those files are through the vpath directive, e.g. by adding
vpath %.cc $(dir $(src))
vpath %.o obj/ #not a good idea for .o files though, see below
and changing the pattern rule (needed by the use of vpath %.o) into
%.o: %.cc
$(compiler) $(cflags) -c $^ -o obj/$#
EDIT: MadScientist has made a very good point that I completely missed, based on which, a better solution that does not involve vpath %.o is
vpath %.cc $(dir $(src))
obj=$(addprefix obj/,$(patsubst %.cc, %.o, $(srcBaseName)))
obj/%.o: %.cc
$(compiler) $(cflags) -c $^ -o $#