I'm new to makefiles, but I finally managed to get one working for a project I'm working on. The original goal was to search the folder "Source" for any CPP files, then create an Object file in the folder Products/Objs. Instead, it finds the CPP files, but OBJECT_FILES is the same as SOURCE_FILES, and I'm not sure how it's working. It doesn't generate any .o files (that I could see), but still compiles successfully. Super confused but would love some help. Thanks!
##########################################
# Editable options #
##########################################
# Program Name
EXECUTABLE=net
# Compiler options
CC=g++
CFLAGS=
LDFLAGS=
# Folders
SRC=Source
OBJ=Products/Objs
#########################################################
# Do Not Touch This #
#########################################################
SOURCE_FILES := $(shell find $(SRC)/ -type f -name '*.cpp')
## This should not work
OBJECT_FILES := $(SOURCE_FILES: $(SRC)/%.cpp=%.o)
## Like at all --> It's the same as SOURCE_FILES
## But I guess???
build: $(EXECUTABLE)
## Deletes the executable (assumes small compile time)
clean:
#rm -r -f $(shell find $(SRC)/ -type f -name '*.o')
#rm $(EXECUTABLE)
.PHONY: build clean
$(EXECUTABLE): $(OBJECT_FILES)
#$(CC) $(LDFLAGS) -o $# $^
#echo "Build successful!"
$(OBJECTS_FILES): %.o : $(SRC)/%.cpp
#$(CC) $(CFLAGS) -o -c $# $^
Well first you have a typo; you create a variable OBJECT_FILES:
OBJECT_FILES := $(SOURCE_FILES: $(SRC)/%.cpp=%.o)
Also you shouldn't use spaces here (after the :). Then you use a variable named OBJECTS_FILES instead:
$(OBJECTS_FILES): %.o : $(SRC)/%.cpp
That variable is empty so this is essentially a no-op.
Your compiler invocation is wrong. The word after the -o option is the file the output should go to; yours is:
#$(CC) $(CFLAGS) -o -c $# $^
which means that the output of this command is going to the file -c. Then the input is an object file that doesn't exist... most likely you'll get an error. Also you only want to pass the source file to the compiler, not all the other prerequisites (headers etc.) This should be:
#$(CC) $(CFLAGS) -c -o $# $<
Related
I'm working on a Makefile that i can use on most of my school projects.
I only did basics makefile before and never had a problem, but for this one i wanted to put some colors etc...
And it relink everytime i make it.
I think the relink come from my echos ? But i'm not sure.
Here is my makefile :
#GENERAL
CC = clang++
FLAGS = -Wall -Wextra -Werror -std=c++98
RM = rm -rf
#PROJET
EXEC = ClapTrap
#FILES
SRCS = ClapTrap.cpp main.cpp
OBJS = $(SRCS:.cpp=.o)
OBJSDIR = objects/
#REGLES
.cpp.o: $(SRCS)
mkdir -p $(OBJSDIR)
echo "$(BLUE)Compiling $^ ..$(CLEAR)"
$(CC) $(FLAGS) -c $< -o $(addprefix $(OBJSDIR), $#)
echo " $(YELLOW)$(addprefix $(OBJSDIR), $#)$(CLEAR) [$(GREEN)OK$(CLEAR)]"
all: $(EXEC)
$(EXEC): $(OBJS)
echo "$(BLUE)========================================$(CLEAR)"
echo "$(BLUE) Compiling binary file ..$(CLEAR)"
echo "$(BLUE)========================================$(CLEAR)"
$(CC) -o $(EXEC) $(addprefix $(OBJSDIR), $^) $(FLAGS)
echo "$(YELLOW)$(EXEC)$(GREEN) is now ready to use !$(CLEAR)"
clean:
#$(RM) $(OBJSDIR)
#echo "$(RED)Cleaning up..$(CLEAR)"
fclean: clean
#$(RM) $(EXEC)
#echo -n "$(RED)$(EXEC)$(CLEAR)"
re: fclean all
.PHONY: all
Thank's for reading !
EDIT :
So i removed SRCS from my .cpp.o rules dependencies, but still relinking.
Here the updated Makefile :
#FILES
SRCS = ClapTrap.cpp main.cpp
OBJS = $(SRCS:.cpp=.o)
OBJSDIR = objects
#REGLES
.cpp.o:
echo "$(BLUE)Compiling $(YELLOW)$^$(BLUE) ..$(CLEAR)"
mkdir -p $(OBJSDIR)
$(CC) $(FLAGS) -c $< -o $#
mv $# $(OBJSDIR)
echo "$(BLUE) - $(YELLOW)$#$(CLEAR) [$(GREEN)OK$(CLEAR)]"
all: $(EXEC)
$(EXEC): $(OBJS)
echo "$(BLUE)========================================$(CLEAR)"
echo "$(BLUE) Compiling binary file ..$(CLEAR)"
echo "$(BLUE)========================================$(CLEAR)"
$(CC) $(FLAGS) $(STD) $(addprefix $(OBJSDIR)/, $(OBJS)) -o $(EXEC)
echo "$(YELLOW)$(EXEC)$(GREEN) is now ready to use !$(CLEAR)"
This is wrong:
$(CC) $(FLAGS) -c $< -o $#
mv $# $(OBJSDIR)
When make runs your recipe it will put the file it expects you to build into the $# automatic variable. If your makefile builds some OTHER file, not the one it asked you to build, then the next time you run make it will see that the file it wants doesn't exist (because you didn't build it, you build some other file) and so it's always out of date.
Your rules must always build exactly the file $#, not some other file.
It's not actually possible to write a makefile that puts targets in a different directory, using suffix rules. They can only create files in the same directory. That's (one reason) why GNU make supports pattern rules which are much more flexible.
If you have to write a POSIX conforming makefile that doesn't support pattern rules, and you want to put the object files in some other directory, all you can do is write out all the targets and their rules explicitly.
My Makefile:
CXX = clang++
CXXFLAGS = -g -Wall -std=c++14
LDFLAGS = -lboost_system -lcrypto -lssl -lcpprest -lpthread
OBJDIR = obj
SRCDIR = .
SRC := $(shell find $(SRCDIR) -name "*.cpp")
OBJ := $(SRC:%.cpp=%.o)
APP = run
all: $(APP)
$(APP): $(OBJ)
#echo "== LINKING EXECUTABLE $(APP)"
#$(CXX) $^ $(LDFLAGS) -o $(APP)
%.o: %.cpp
#echo "COMPILING SOURCE $< INTO OBJECT $#"
#$(CXX) -c $(CXXFLAGS) $< -o $#
clean:
find . -name *.o -delete
rm -f $(APP)
Directory structure:
Makefile
sources/
directory1
...cpp
directory2
...cpp
...
main.cpp
obj/
I try to make make create *.o files in a directory obj/ and then compile the final executable from there. I tried various approaches and they fail because of the project structure that stores *.cpp files in sub-directories. Particularly, I've tried the following: https://stackoverflow.com/a/26032630/2042546
I've also tried to manipulate the command itself clang++ $< -o obj/$# but it breaks whole idea of make and it's dependency management.
If I modify OBJ via patsubstr and notdir, make becomes unable to deduce dependency of a *.o on a corresponding *.cpp by it's path, cause *.o's path loses it's directory part and becomes unable to find it's *.cpp file when executing %.o:%.cpp rule (I hope I managed to write down my thoughts correctly).
If you want objects to live in the same source directory structure but under obj, then simply change your pattern rule (and how you generate the object files). And you should create the directory first:
OBJ := $(SRC:%.cpp=$(OBJDIR)/%.o)
...
$(OBJDIR)/%.o: %.cpp
#echo "COMPILING SOURCE $< INTO OBJECT $#"
#mkdir -p '$(#D)'
#$(CXX) -c $(CXXFLAGS) $< -o $#
I'm preparing a c++ app on linux (Ubuntu 16.04) with the use of a few poco libraries which I have dynamically linked. I have project folder that consists of : include, bin, lib , src and build folders and the relevant Makefile. So far I used the following Makefile which got the libraries from /usr/local/lib
CC := g++
# Folders
SRCDIR := src
BUILDDIR := build
TARGETDIR := bin
# Targets
EXECUTABLE := C++_APP
TARGET := $(TARGETDIR)/$(EXECUTABLE)
SRCEXT := cpp
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o))
CFLAGS := -c -Wall
INC := -I include -I /usr/local/include
LIB := -L /usr/local/lib -lPocoFoundation -lPocoNet -lPocoUtil
$(TARGET): $(OBJECTS)
#echo " Linking..."
#echo " $(CC) $^ -o $(TARGET) $(LIB)"; $(CC) $^ -o $(TARGET) $(LIB)
$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT)
#mkdir -p $(BUILDDIR)
#echo " $(CC) $(CFLAGS) $(INC) -c -o $# $<"; $(CC) $(CFLAGS) $(INC) -c -o $# $<
clean:
#echo " Cleaning...";
#echo " $(RM) -r $(BUILDDIR) $(TARGET)"; $(RM) -r $(BUILDDIR) $(TARGET)
.PHONY: clean
Now I'd like during running the linker to search for libraries only in project lib folder without changing LD_LIBRARY_PATH or editing ld.so.conf. So I searched and I found that this can be achieved by the linker argument -Wl,rpath,$ORIGIN. So I assume that I need to add the following statement
LDFLAGS := -Wl,-rpath,$ORIGIN/../lib
and change the the LIB statement as following:
LIB := -L $ORIGIN/../lib -lPocoFoundation -lPocoNet -lPocoUtil
However it still get the libraries from the default directory (usr/local/lib) , since I tested it with no library on the project lib folder. What have I done wrong?
No, you're misunderstanding. You need to pass the literal string $ORIGIN/../lib as an argument to your linker. The $ORIGIN token is kept inside your program after it's created and when the runtime linker starts to run your program it will replace $ORIGIN with the current path that your program was invoked from. This is true even if you've copied your program somewhere else. So if you run your program as /usr/local/bin/myprogram then the runtime linker will replace $ORIGIN with /usr/local/bin. If you copy it to /opt/mystuff/libexec/myprogram then the runtime linker will replace $ORIGIN with /opt/mystuff/libexec.
In order to pass a literal $ to the command invoked by a make recipe, you have to escape the $ by doubling it: $$. Otherwise, make will see the $ as introducing a make variable or function. Remember, it's perfectly legal for a make variable to avoid the parentheses etc., if it's a single character (note, $#, $<, etc.)
So when you write -Wl,-rpath,$ORIGIN/../lib make will interpret the $O in $ORIGIN as expanding a variable named O, which is empty, giving you -Wl,-rpath,RIGIN/../lib.
Also you have to escape the $ from the shell, otherwise it will try to expand $ORIGIN as a shell variable which you don't want.
You want to do something like this:
LDFLAGS = '-Wl,-rpath,$$ORIGIN/../lib' -L/usr/local/lib
LDLIBS = -lPocoFoundation -lPocoNet -lPocoUtil
$(TARGET): $(OBJECTS)
#echo " Linking..."
$(CC) $^ -o $# $(LDFLAGS) $(LDLIBS)
(I don't know why you use # to hide the command, then echo the command... why not just take out the # and the echo and let make show you the command?)
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 $#
I'm still quite new to make. I am trying to compile a project in which maketest.cpp and maketest.hpp rests on Users/wen/Projects/maketest with the Makefile itself. Problem is, I want to also compile and link the source files (.cc and .hh) in Users/wen/Projects/include/bigint.
# Macros
INCLUDE = -I/Users/wen/Projects/include/bigint
LIBS =
CC = g++
override FLAGS += -O2
HEADERS= $(wildcard *.hpp) $(wildcard Users/wen/Projects/include/bigint/*.hh)
# EXE Name
INSTALL = maketest
CC_FILES = %.cpp Users/wen/Projects/include/bigint/%.cc
OBJ_FILES = maketest.o $(wildcard Users/wen/Projects/include/bigint/*.o)
# Rules
$(INSTALL): $(OBJ_FILES)
$(CC) $(FLAGS) $^ -o $# $(LIBS)
%.o: $(CC_FILES) $(HEADERS)
$(CC) $(FLAGS) $(INCLUDE) -c $< -o $#
# Installation types
install: $(INSTALL)
release:
#echo "Re-run with parameter:"
#echo "FLAGS=-D_RELEASE"
debug:
#echo "Re-run with parameter:"
#echo "FLAGS=-D_DEBUG"
# Cleaning up
clean:
rm -f $(OBJ_FILES) $(INSTALL)
The code compiles maketest.cpp and links it, but not bigint.
What will be the right way to build and link the files from Users/wen/Projects/include/bigint? Many thanks!
I figured it out at the end, thank you Jay. The problem was I forgot a slash at the front of Users/wen/Projects/include/bigint, so it was not searching from root but instead the project folder. Now it works!
Try explicitly specifying one of the files from bigint in OBJ_FILES (perhaps "bigint.o" ?). I don't think your wildcard is getting what you want.