I'm on my path to study the wonderful world of Makefiles and this was my first attempt on my own makefile. However I have hit my small brains at a wall with errors and I can not figure the cause, I only know the issue is in the Makefile, I am doing something wrong, because when I compile my "project" manually, it compiles.
cxx := g++
dirs := obj bld_win32 bld_linux
cpp := $(wildcard src/*.cpp)
obj := $(addprefix obj/,$(notdir $(cpp:.cpp=.o)))
ifeq ($(OS), Windows_NT)
target := bld_win32/engine.exe
flags := -mwindows -lopengl32 -openal32 -lgdi32
else
target := bld_linux/engine
flags := -lX11 -lGL -lopenal -lalut
endif
all: precheck $(target)
precheck:
mkdir -p $(dirs)
$(target): $(obj)
$(cxx) -std=c++11 -Wall -o $# $^ $(flags)
obj/%.o: $(cpp)
$(cxx) -c -o $# $<
Your pattern rule is wrong, as you would have noticed if you'd tried to build object files one by one using this makefile. This rule:
obj/%.o: $(cpp)
$(cxx) -c -o $# $<
lists all source files as prerequisites of every object file, and when you try to build any object file, it compiles only the first source file in the list (src/aardvark.cpp, or whatever), so that all of your object files are the same, even though they have different names.
Change it to this:
obj/%.o: src/%.cpp
$(cxx) -c -o $# $<
Related
Summarize the problem
I would like to change the compilation for a single source file, like so:
%.exe: %.c
ifeq($#, cannon.exe)
$(CC) $(CFLAGS) -o $(patsubst %.exe,%,$#) $^ $(inc_flags) $(LDLIBS)
else
$(CC) $(CFLAGS) -o $(patsubst %.exe,%,$#) $^
endif
but it doesn't work!
Describe what you’ve tried
I have tried getting bash conditionals involved, but I couldn't figure it out and I shouldn't have to mix bash and make.
Here's the full Makefile:
CC := gcc
CFLAGS := -g -Wall -Wextra
LDLIBS := -lm
inc_dirs := math.h stdio.h
inc_flags := $(addprefix -I,$(inc_dirs))
executable:=cannon.exe
source:=$(executable:%.exe=%.cpp)
.DELETE_ON_ERROR:
all: $(executable)
%.exe: %.c
ifeq($#, cannon.exe)
$(CC) $(CFLAGS) -o $(patsubst %.exe,%,$#) $^ $(inc_flags) $(LDLIBS)
else
$(CC) $(CFLAGS) -o $(patsubst %.exe,%,$#) $^
endif
clean:
rm -f $(executable:%.exe=%)
It turns out that if you want to do a special case for a certain source file, you can just define its recipe explicitly! Make will take explicit over implicit rules. Full working code below.
CC := gcc
CFLAGS := -g -Wall -Wextra
LDLIBS := -lm
inc_dirs := math.h stdio.h
inc_flags := $(addprefix -I,$(inc_dirs))
executable:=cannon.exe
source:=$(executable:%.exe=%.cpp)
# no deps so no objs
.DELETE_ON_ERROR:
all: $(executable)
%.exe: %.c
$(CC) $(CFLAGS) -o $(patsubst %.exe,%,$#) $^
cannon.exe: cannon.c
$(CC) $(CFLAGS) -o $(patsubst %.exe,%,$#) $^ $(inc_flags) $(LDLIBS)
clean:
rm -f $(executable:%.exe=%)
A better / more make-ish solution is to use constructed variable names, like this:
CC := gcc
CFLAGS := -g -Wall -Wextra
LDLIBS := -lm
inc_dirs := math.h stdio.h
cannon_CFLAGS := $(addprefix -I,$(inc_dirs))
executable := cannon.exe
source := $(executable:%.exe=%.cpp)
# no deps so no objs
.DELETE_ON_ERROR:
all: $(executable)
%.exe: %.c
$(CC) $(CFLAGS) $($*_CFLAGS) -o $# $^
clean:
rm -f $(executable:%.exe=%)
Notes:
Your rules should always create the same name as the target in the makefile. It's not right for the target to be named foo.exe but the build command creates a file named foo. If you want to create a file named foo, then the makefile target should be named foo. Basically you should always create the file contained in the make variable $#.
Is it really the case that the directories you have are named math.h and stdio.h? That's.... bizarre. And very likely to cause serious problems. If math.h and stdio.h are files, then you should not add them with -I because -I takes directory names, in which to search file files. It doesn't take filenames.
If you really did create local files named math.h and stdio.h, that's also a very bad idea: those are standard header file names and you shouldn't redeclare them yourself unless you really know what you're doing.
If you didn't create these files and you're just trying to include the standard headers math.h and stdio.h in your file, then you definitely don't need to add any flags to your compile line. Just include them.
Good day. I am in a directory, where is Makefile and folders src and bin. How can I compile object files into bin folder and then build an executable file?
I read some instructions and added $(BIN) before %.o, but it didn't helped, object files appear in folder with makefile. Where is the problem?
CC = arm-linux-gnueabihf-gcc
CXX = arm-linux-gnueabihf-g++
CPPFLAGS = -I .
CFLAGS =-g -std=gnu99 -O1 -Wall
CXXFLAGS = -g -std=gnu++11 -O1 -Wall
LDFLAGS = -lrt -lpthread
SRCDIR = src
BIN = bin
SOURCES = $(wildcard $(SRCDIR)/*.cpp) $(wildcard $(SRCDIR)/*.c)*
...
OBJECTS += $(filter %.o,$(SOURCES:%.c=%.o))
OBJECTS += $(filter %.o,$(SOURCES:%.cpp=%.o))
#$(warning OBJECTS=$(OBJECTS))
ifeq ($(filter %.cpp,$(SOURCES)),)
LINKER = $(CC)
LDFLAGS += $(CFLAGS) $(CPPFLAGS)
else
LINKER = $(CXX)
LDFLAGS += $(CXXFLAGS) $(CPPFLAGS)
endif
$(BIN)/%.o:%.c
$(CC) $(CFLAGS) -c $<
$(BIN)/%.o:%.cpp
$(CXX) $(CXXFLAGS) -c $<
all: $(TARGET_EXE)
$(TARGET_EXE): $(OBJECTS)
$(LINKER) $(LDFLAGS) -L. $^ -o $#
.PHONY : dep all run copy-executable debug
dep: depend
depend: $(SOURCES) *.h
echo '# autogenerat`enter code here`ed dependencies' > depend
ifneq ($(filter %.c,$(SOURCES)),)
$(CC) $(CFLAGS) $(CPPFLAGS) -w -E -M $(filter %.c,$(SOURCES)) \
>> depend
endif
ifneq ($(filter %.cpp,$(SOURCES)),)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -w -E -M $(filter %.cpp,$(SOURCES)) \
>> depend
endif
clean:
rm -f *.o *.a $(OBJECTS) $(TARGET_EXE) connect.gdb depend
...
It's not clear to me how this makefile can works as well as it does, given that you haven't told it where to find the source files (unless you do so in one of the elided sections).
In these rules:
$(BIN)/%.o:%.c
$(CC) $(CFLAGS) -c $<
$(BIN)/%.o:%.cpp
$(CXX) $(CXXFLAGS) -c $<
you tell the compiler to build object files, but you don't specify where to build them, and the default is to build them in the working directory. You can override that with the -o option:
$(BIN)/%.o:%.c
$(CC) $(CFLAGS) -c $< -o $#
$(BIN)/%.o:%.cpp
$(CXX) $(CXXFLAGS) -c $< -o $#
Once you have the object files where you want them (bin/), you must ensure that the linking rule:
$(TARGET_EXE):$(OBJECTS)
$(LINKER) $(LDFLAGS) -L. $^ -o $#
can find them. The best way to do that is to ensure that OBJECTS contains the correct paths to the object files. I'm not sure how to advise you to do that, since from the look of your makefile that variable might not contain what you think it does.
EDIT:
Let's take this in stages.
Suppose we have on source file, src/foo.c. What we want is:
src/foo.c -> bin/foo.o
bin/foo.o -> foo
This requires two rules, which we can write like this:
$(BIN)/%.o: src/%.c
$(CC) $(CFLAGS) -c $< -o $#
$(TARGET_EXE): bin/foo.o
$(LINKER) $(LDFLAGS) -L. $^ -o $#
We actually have many source files, some of which are C++ files. So we must have a rule for them:
$(BIN)/%.o: src/%.cpp
$(CXX) $(CXXFLAGS) -c $< -o $#
and construct a longer list of objects:
OBJECTS := bin/foo.o bin/bar.o bin/baz.o bin/quartz.o...
$(TARGET_EXE): $(OBJECTS)
$(LINKER) $(LDFLAGS) -L. $^ -o $#
(Mixing C and C++ seems unhealthy to me, but never mind.)
And how do we construct that list of objects? We must start with the list of sources which wildcard can produce:
SRC := src
C_SOURCES := $(wildcard $(SRC/*.c)
# this is src/foo.c src/bar.c
SRC := src
CPP_SOURCES := $(wildcard $(SRC/*.cpp)
# this is src/baz.cpp src/quartz.cpp
and then convert them to the object file names we actually want:
BIN := bin
OBJECTS := $(patsubst $(SRC)/%.cpp,$(BIN)/%.o, $(CPP_SOURCES))
OBJECTS += $(patsubst $(SRC)/%.c,$(BIN)/%.o, $(C_SOURCES))
# this is bin/foo.o bin/bar.o bin/baz.o bin/quartz.o
That should give you the effect you want, and if you understand it you will understan why your old makefile did not.
Following this question and my answer and its comments I have a doubt.
What is the proper way to reference dependencies in a Makefile?
Let me give an example considering this file:
CXX = g++
CXXFLAGS = -stdlib=libc++ -std=c++17
WARNING := -Wall -Wextra
PROJDIR := .
SOURCEDIR := $(PROJDIR)/
SOURCES := $(wildcard $(SOURCEDIR)/*.cpp)
OBJDIR := $(PROJDIR)/
OBJECTS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.o,$(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.d,$(SOURCES))
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
all: main
clean:
$(RM) $(OBJECTS) $(DEPENDS) main
clean:
$(RM) $(OBJECTS) $(DEPENDS) parking
# Linking the executable from the object files
main: $(OBJECTS)
$(CXX) $(WARNING) $(CXXFLAGS) $^ -o $#
#include your dependencies
-include $(DEPENDS)
#create OBJDIR if not existin (you should not need this)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.cpp Makefile | $(OBJDIR)
$(CXX) $(WARNING) $(CXXFLAGS) -MMD -MP -c $< -o $#
I can do DEPENDS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.d,$(SOURCES)) but also DEPENDS := $(wildcard $(OBJDIR)/*.d): can't I?
If I delete a source file before running make clean the correspondent dependency file remains. In the second case it will be removed with the next make clean while in the first it will not. However if I do not run make clean dependencies not related to the sources might be included.
What is the best way to reference dependencies in a Makefile? Should I use two variables, one to run clean and the other for include?
This question already has answers here:
'make' does not recompile when source file has been edited
(3 answers)
Closed 4 years ago.
I have two .c files and one .h file which is included in both .c files.
I have make file :
CC=gcc
CFLAGS=-I.
OBJ = hellofunc.o hellomake.o
DEPS := $(OBJ:.o=.d)
-include $(DEPS)
%.o: %.c
$(CC) $(CFLAGS) -MM -MT $# -MF $(patsubst %.o,%.d,$#) $<
$(CC) -c -o $# $< $(CFLAGS)
hellomake: hellomake.o hellofunc.o
$(CC) -o $# $^
I modified hellomake.h header file and then ran above make file. It is compiling only the first file which is assigned to DEPS variable, Which is hellofunc.c
FYI, When i change the order of DEPS variable it is compiling hellomake.o , Seems like make is only picking first file assigned to DEPS variable.
Is there anything wrong in my makefile.. Please help.
As #tripleee noted in the comments, make will by default build the first target it encounters. Since the include files are included directly, as if they were cut-and-pasted in place, the first target in the first .d file (which I'm guessing you'll find to be hellofunc.c) is the first target that make encounters, so that's what make aims to build.
If you move the include line to the end of the file, then the first target in the file will be hellomake, and so that's the target make will attempt to build by default.
Meta remark: if you can, I'd say it's better to avoid this pattern of depending on .d files, and instead aim to express sufficiently many of the dependencies ‘by hand’ directly in the makefile. Doing it this .d way does work (ie, I'm not saying what you're doing is wrong) and appears to be labour-saving, but in my experience it tends to be a little brittle, partly because if you don't have the .d files to hand then you suddenly have zero dependencies. In order to have the .d files to hand, you'll have to check them in to your code repository (you are using a repository, aren't you?), but that will mean they'll frequently be trivially out of date, and... it can turn into a bit of a mess.
EDIT: considered MadScientist's comment and blog post about separate recipe for .d files.
You could tell make how to generate the .d files with a separate rule instead of putting this in another recipe (but see the above mentioned blog post for several reasons for not doing so).
And you should probably tell make that your default goal is hellomake:
.DEFAULT_GOAL := hellomake
CC=gcc
CFLAGS=-I.
OBJ = hellofunc.o hellomake.o
DEPS := $(OBJ:.o=.d)
-include $(DEPS)
%.d: %.c
$(CC) $(CFLAGS) -MM -MT $# -MF $# $<
%.o: %.c
$(CC) -c -o $# $< $(CFLAGS)
hellomake: hellomake.o hellofunc.o
$(CC) -o $# $^
And it would probably be even better if you were letting make find the source files and deduce the rest:
.DEFAULT_GOAL := hellomake
CC := gcc
CFLAGS := -I.
SRCS := $(wildcard *.c)
OBJS := $(patsubst %.c,%.o,$(SRC))
DEPS := $(patsubst %.c,%.d,$(SRC))
-include $(DEPS)
%.d: %.c
$(CC) $(CFLAGS) -MM -MT $# -MF $# $<
%.o: %.c
$(CC) -c -o $# $< $(CFLAGS)
hellomake: $(OBJS)
$(CC) -o $# $^
Finally, following MadScientist's advices, a better, more efficient, less prone to failures solution could be:
.DEFAULT_GOAL := hellomake
CC := gcc
CFLAGS := -I.
SRCS := $(wildcard *.c)
OBJS := $(patsubst %.c,%.o,$(SRC))
DEPS := $(wildcard $(patsubst %.c,%.d,$(SRC)))
include $(DEPS)
%.o: %.c %.d
$(CC) -MT $# -MMD -MP -MF $*.Td $(CFLAGS) -c -o $# $<
mv -f $*.Td $*.d && touch $#
hellomake: $(OBJS)
$(CC) -o $# $^
%.d: ;
.PRECIOUS: %.d
so I learned what a Makefile was some time ago, created a template Makefile and all I do is copy and alter the same file for every program I'm doing. I changed it a few times, but it's still a very crude Makefile. How should I improve it? This is an example of my current version:
CC = g++
CFLAGS = -std=gnu++0x -m64 -O3 -Wall
IFLAGS = -I/usr/include/igraph
LFLAGS = -ligraph -lgsl -lgslcblas -lm
DFLAGS = -g -pg
# make all
all: run test
# make a fresh compilation from scratch
fresh: clean test
#makes the final executable binary
run: main.o foo1.o foo2.o
$(CC) $(CFLAGS) $(LFLAGS) $^ -o $#
#makes the test executable with debugging and profiling tags
test: test.o foo1.o foo2.o
$(CC) $(DFLAGS) $(CFLAGS) $(LFLAGS) $^ -o $#
#makes teste.o
teste.o: teste.cpp
$(CC) $(CFLAGS) $(IFLAGS) -c $^ -o $#
#makes main.o
main.o: main.cpp
$(CC) $(CFLAGS) $(IFLAGS) -c $^ -o $#
#file foo1
foo1.o: foo1.cpp
$(CC) $(CFLAGS) $(IFLAGS) -c $^ -o $#
#file foo2
foo2.o: foo2.cpp
$(CC) $(CFLAGS) $(IFLAGS) -c $^ -o $#
clean: clean-test clean-o clean-annoying
clean-test:
rm test-rfv
clean-o:
rm *.o -rfv
clean-annoying:
rm *~ -rfv
Just by visually comparing with other makefiles I saw around in the web, this seems to be not a very bright Makefile. I don't know how they work, but I can see there's significantly less boilerplate and more generic code in them.
Can this can be made better, safer, and easier to particularize for each project?
You don't want to name specific files in a makefile if you can get away with it, and 99% of the time you can. This page shows how to develop a very general makefile. The following is my own makefile, based on that page's info:
SHELL := bash
PROG := pathed.exe
OUTDIRS := bin/debug bin/rel obj/debug obj/rel
PROG_REL := bin/rel/$(PROG)
PROG_DEBUG := bin/debug/$(PROG)
SRCFILES := $(wildcard src/*.cpp)
OBJFILES_REL := $(patsubst src/%.cpp,obj/rel/%.o,$(SRCFILES))
OBJFILES_DEBUG := $(patsubst src/%.cpp,obj/debug/%.o,$(SRCFILES))
DEPFILES := $(patsubst src/%.cpp,obj/%.d,$(SRCFILES))
CFLAGS := -Iinc -Wall -Wextra -MMD -MP
DBFLAGS := -g
RELFLAGS :=
CC := g++
.PHONY: default all testmake debug release clean dirs
default: debug
all: dirs clean debug release
dirs:
#mkdir -p $(OUTDIRS)
debug: $(PROG_DEBUG)
release: $(PROG_REL)
testmake:
#echo OBJFILES_REL = $(OBJFILES_REL)
#echo OBJFILES_DEBUG = $(OBJFILES_DEBUG)
#echo SRCFILES = $(SRCFILES)
#echo DEPFILES = $(DEPFILES)
clean:
rm -f $(OBJFILES_REL) $(OBJFILES_DEBUG) $(DEPFILES) $(PROG)
$(PROG_REL): $(OBJFILES_REL)
$(CC) $(OBJFILES_REL) -o $(PROG_REL)
strip $(PROG_REL)
#echo "---- created release binary ----"
$(PROG_DEBUG): $(OBJFILES_DEBUG)
$(CC) $(OBJFILES_DEBUG) -o $(PROG_DEBUG)
#echo "---- created debug binary ----"
-include $(DEPFILES)
obj/rel/%.o: src/%.cpp
$(CC) $(RELFLAGS) $(CFLAGS) -MF $(patsubst obj/rel/%.o, obj/%.d,$#) -c $< -o $#
obj/debug/%.o: src/%.cpp
$(CC) $(DBFLAGS) $(CFLAGS) -MF $(patsubst obj/debug/%.o, obj/%.d,$#) -c $< -o $#
Do NOT use CC for the C++ compiler. The standard convention is that CC is the C compiler, CXX is the C++ compiler. CFLAGS are flags for the C compiler, CXXFLAGS are flags for the C++ compiler, and CPPFLAGS are flags for the pre-processor (eg, -I or -D flags). Use LDFLAGS for -L flags to the linker, and LDLIBS (or LOADLIBES) for -l flags.
Using the standard conventions is good not just because it makes things easier for others to understand, but also because it allows you to take advantage of implicit rules. If make needs to make a .o file from a .c file and you have not provided a rule, it will use a standard rule and honor the settings of CC, CFLAGS, and CPPFLAGS. If CC is a C++ compiler, things will probably not work.