I'm new to Makefile. While trying to write a generic Makefile which could be used in most of my projects with least modification, I encountered a problem (simplified as the following):
My "project" looks like:
proj/
src1.cpp
subdir1/
src2.cpp
Makefile
Part of the Makefile:
OBJ := bin/src1.o bin/subdir1/src2.o
OBJ_DIR := bin/ bin/subdir1/
PROGRAMS := prog1
define compile_template =
$(1)/%.o: %.cpp
mkdir -p $$(#D)
$$(CXX) $$(CXXFLAGS) -c $$< -o $$#
endef
define PROGRAM_template =
$(1): $$(OBJ)
$$(CXX) $$(LDFLAGS) $$^ -o $$# $$(LDLIBS)
endef
$(foreach odir,$(OBJ_DIR),$(eval $(call compile_template,$(odir))))
$(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog))))
And the error is:
gmake: *** No rule to make target `bin/src1.o', needed by `proj1'. Stop.
Another question is should I wrote my own Makefile or use automake etc if I only compile in particular machines (So I have control to the compiler, OS, ...)?
The best way to debug issues like this (problems with eval) is to replace the $(eval ...) function with a call to $(info ...). This will print out the text that make is parsing and it's usually pretty obvious what your problem is. If you rewrite your eval lines to this:
$(foreach odir,$(OBJ_DIR),$(info $(call compile_template,$(odir))))
$(foreach prog,$(PROGRAMS),$(info $(call PROGRAM_template,$(prog))))
(and fixing your obvious syntax error, the space between : and = in the first line) you see:
bin//%.o: %.cpp
mkdir -p $(#D)
$(CXX) $(CXXFLAGS) -c $< -o $#
bin/subdir1//%.o: %.cpp
mkdir -p $(#D)
$(CXX) $(CXXFLAGS) -c $< -o $#
prog1: $(OBJ)
$(CXX) $(LDFLAGS) $^ -o $# $(LDLIBS)
From this you can see the prog1 depends on bin/src1.o and bin/subdir1/src2.o so make wants to build bin/src1.o. It looks through your rules, but in make's internal matching syntax bin//%.o does not match bin/src1.o because of the extra slash.
Change your assignment to remove the trailing slash and it should work better:
OBJ_DIR := bin bin/subdir1
Related
I have found a lot of related questions, but I was still not able to make my own Makefile.
This makefile is using Mingw64 on Windows, and I want it to run on *nix, currently Debian, but I would like to be able to make it run on Alpine too, as it's used in a Docker container.
The project tree structure is something like :
./
src/
main.cpp
Server.cpp <- use asio and Utils/Split.h
Server.h <- use asio
Utils/
Split.h
lib/
asio/include/ <- asio library (without boost, header only)
Makefile <- That is what I am trying to do right now
Dockerfile
I tried multiple things, here is my latest Makefile (that obviously, does not work) :
NAME := GameServer
CXX := g++
CXXFLAGS := -std=c++2a -DASIO_STANDALONE
SRC_DIR := ./src
LIBS := -I lib/asio-1.18.1/include \
-I lib/rapidjson-1.1.0/include \
-I src
rwildcard = $(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))
SRCS := $(call rwildcard,$(SRC_DIR),*.cpp)
OBJS := $(SRCS:%.cpp=%.o)
.PHONY: all
all: $(NAME)
$(NAME): $(OBJS)
$(CXX) -o $# $^
$(OBJS): $(SRCS)
$(CXX) $(CXXFLAGS) -c -o $# $< $(LIBS)
Note: the code (.cpp, .h) is valid, it's coming from an already-running project, but built on Visual Studio (compiled with MSVC).
Here are the two functions done my mingw32-make :
g++ -c -o src/Server.o src/main.cpp -I lib/asio/include -I src
g++ -o Server src/main.o src/Server.o
First line : It should builds the .o from the .cpp and adds the include to asio. I added -I src to add src/Utils, but I guess that's not the way of doing it ?
Second line : It should (link ?) the two .o in a single file : the executable.
The errors I am getting with this makefile are :
src/Server.o:main.cpp:(.text+0x36): multiple definition of 'main', src/main.o:main.cpp:(.text+0x36): first defined here (and this, for every .o)
src/main.o:main.cpp:(.text+0x4b): undefined reference to 'Server::Server()' (and this, for every Server methods main calls, even some from asio)
They appears when the second g++ line starts (g++ -o Server src/main.o src/Server.o)
So here are my questions :
What am I doing wrong ?
Is there a better way of trying to make a development environment on Windows and still be able to copy the project in a Docker container (and then compile it with the gcc image) to build it with the same Makefile ?
Sorry if I forgot to mention some details, I am new with Mingw and its environment.
Thank you
Edit : Corrected version :
NAME := GameServer
CXX := g++
CXXFLAGS := -std=c++1z
SRC_DIR := ./src
LIBS := -lwsock32 -lws2_32 \
-I lib/asio-1.18.1/include \
-I lib/rapidjson-1.1.0/include \
-I src
rwildcard = $(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))
SRCS := $(call rwildcard,$(SRC_DIR),*.cpp)
OBJS := $(SRCS:%.cpp=%.o)
.PHONY: all
all: $(NAME)
$(NAME): $(OBJS)
$(CXX) -o $# $^ $(LIBS)
$(OBJS): $(SRC_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(CXXFLAGS) -c -o $# $< $(LIBS)
Consider the rule...
$(OBJS): $(SRCS)
$(CXX) $(CXXFLAGS) -c -o $# $< $(LIBS)
This tells make that all items in $(OBJS) depend on all items in $(SRCS). But the command...
$(CXX) $(CXXFLAGS) -c -o $# $< $(LIBS)
...always compiles the first dependency as identified by $<. It just so happens that in your case $< is src/main.cpp.
Instead you should probably use a pattern rule such as...
$(SRC_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(CXXFLAGS) -c -o $# $< $(LIBS)
You can also limit the scope of that rule to only those targets specified by $(OBJS) with a full static pattern rule...
$(OBJS): $(SRC_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(CXXFLAGS) -c -o $# $< $(LIBS)
I am having an issue with this makefile. I cannot figure out how to build the object files from their coresponding sources. Every obj gets built with the main source, instead of its one.
TARGET = af_optional
SOURCES := $(wildcard src/*.cpp)
OBJECTS := $(patsubst src/%.cpp,obj/%.o,$(SOURCES))
DEPENDS := $(patsubst src/%.cpp,obj/%.d,$(SOURCES))
CXXFLAGS = -g -I.
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: bin/$(TARGET)
clean:
$(RM) $(OBJECTS) $(DEPENDS) $(TARGET)
# Linking the executable from the object files
bin/$(TARGET): $(OBJECTS)
#echo "target : $(TARGET)"
#echo "sources: $(SOURCES)"
#echo "objects: $(OBJECTS)"
#echo "depends: $(DEPENDS)"
#mkdir -p bin
$(CXX) $(WARNING) $(CXXFLAGS) $^ -o $#
-include $(DEPENDS)
$(OBJECTS): $(SOURCES) makefile
#mkdir -p obj
$(CXX) $(WARNING) $(CXXFLAGS) -MMD -MP -c $< -o $#
I have written this makefile while researching a while ago, but I broke something after I had got it working and I haven't noticed until now, since all the project's I've had to work with since were single source.
This rule is wrong:
$(OBJECTS): $(SOURCES) makefile
What does this expand to? If you have sources src/foo.cpp, src/bar.cpp, and src/baz.cpp then it will be this:
obj/foo.o obj/bar.o obj/baz.o : src/foo.cpp src/bar.cpp src/baz.cpp makefile
This is an extremely common problem: people seem to have this idea that make will somehow massage all these targets and prerequisites to match them up somehow so that each object file depends only on the corresponding source file.
But, make does NOT do that. The above rule is exactly identical to writing all these rules:
obj/foo.o : src/foo.cpp src/bar.cpp src/baz.cpp makefile
obj/bar.o : src/foo.cpp src/bar.cpp src/baz.cpp makefile
obj/baz.o : src/foo.cpp src/bar.cpp src/baz.cpp makefile
Now maybe you can see why you see the behavior you do: the first prerequisite for every target is exactly the same file src/foo.cpp so when you use the $< automatic variable, that's the one you always get.
You have to write ONE rule that builds ONE object, then let make figure out how to apply that rule for all the appropriate objects.
So, to build one object file from one source file you can use a pattern rule like this:
obj/%.o : src/%.cpp makefile
#mkdir -p obj
$(CXX) $(WARNING) $(CXXFLAGS) -MMD -MP -c $< -o $#
That's all you need.
My question is about compiling error on linux. Every time I try to compile the program it gives me this error. I tried different things without luck.
*** No rule to make target '/pthread.d', needed by '/thread.exe'. Stop.
The makefile for the program ( pthread is as follow:
SOURCES=pthread.cpp
OBJECTS=$(addprefix $(BUILD_DIR)/, $(SOURCES:.cpp=.o))
DEPS=$(addprefix $(BUILD_DIR)/, $(SOURCES:.cpp=.d))
EXE=thread.exe
CXXFLAGS=-I.
LIBS=-pthread
//Making for host > make ARCH=host
ifeq ($(ARCH),host)
CXX=g++
BUILD_DIR=build/host
BIN_DIR=bin/host
endif
//Making for target > make ARCH= target
ifeq ($(ARCH),target)
CXX=arm-rpizw-g++
BUILD_DIR=build/target
BIN_DIR=bin/target
endif
all: $(BIN_DIR)/$(EXE)
$(BIN_DIR)/$(EXE): $(DEPS) $(OBJECTS)
mkdir -p $(BIN_DIR)
$(CXX) $(CXXFLAGS) -o $# $(OBJECTS)
$(BUILD_DIR)/%.d: %.cpp
mkdir -p $(BUILD_DIR)
$(CXX) -MT$(#:.d=.o) -MM $(CXXFLAGS) $^ > $#
$(BUILD_DIR)/%.o: %.cpp
mkdir -p $(BUILD_DIR)
$(CXX) -c $< -o $# $(CXXFLAGS)
ifneq ($(MAKECMDGOALS), $(filter $(MAKECMDGOALS),clean help))
-include $(DEPS)
endif
clean:
-rm -rf bin/
-rm -rf build/
You likely have spaces after BUILD_DIR=build/target. Thus, $(DEPS) resolves to:
build/target /pthread.d
..., and thus make will try to make /pthread.d (and build/target...). When assigning a value, make discards any preceding spaces, but not trailing spaces. It will drop a trailing comment, but it will not drop whitespace between the end of the line and the comment.
For debugging this type of problem, it's often useful to add $(info) lines into your makefile as so:
$(info DEPS=_$(DEPS)_)
and then run to see if there are any unexpected values.
Edit
After writing this I noticed some things and went back over the file. I changed the line:
$(CXX) -MT $(BUILD_DIR)/$(#:.d=.o) -MM $(CXXFLAGS) $^ > $#
To the following:
$(CXX) -MM $(CXXFLAGS) $^ > $#
Since it seemed kind of redundant to first take the generated dependency files, name them into .o files and then turn them back into .d files.
Now the target actually makes, but it will still not remake when the header files are changed.
Original
I have this makefile I created as part of a course, and everything works fine when running make, building for both the host and target. The problem arises when a change occurs in a header file(example: part1.h), this implementation was made specifically to take this into account, and it seemed to work.
A few weeks on now, and I finally realised it doesn't work as intended, as it will not recompile after a change to any of the header files. (part1.h or part2.h).
I took a look into the dependency files generated by the target:
$(BUILD_DIR)/%.d: %.cpp
An example of part1.d has the following contents:
build/host/build/host/part1.o: part1.cpp part1.h
To me, the double directory listing is an error, but so I tried changing the line:
$(CXX) -MT $(BUILD_DIR)/$(#:.d=.o) -MM $(CXXFLAGS) $^ > $#
To the following, removing the BUILD_DIR variable:
$(CXX) -MT $(#:.d=.o) -MM $(CXXFLAGS) $^ > $#
Doing this solves the double directory listing problem, but gives me a linker error:
build/host/main.o: file not recognized: File format not recognized
I'm trying to find some solution to this, which will make sure that the program is recompiled when changes are made to the header files.
I'm trying to figure out what I'm missing, I've looked at the related literature and everything seems to match up.
SOURCES=main.cpp part1.cpp part2.cpp
OBJECTS=$(addprefix $(BUILD_DIR)/,$(SOURCES:.cpp=.o))
DEPS=$(addprefix $(BUILD_DIR)/,$(SOURCES:.cpp=.d))
EXE=prog
CXXFLAGS=-I.
#Make sure that default choice for make is the host
ifndef (${ARCH})
ARCH=host
endif
#Making for host
ifeq (${ARCH},host)
CXX=g++
BUILD_DIR=build/host
BIN_DIR=bin/host
endif
# Making for target
ifeq (${ARCH},target)
CXX=arm-devkit-g++
BUILD_DIR=build/target
BIN_DIR=bin/target
endif
$(BIN_DIR)/$(EXE): $(DEPS) $(OBJECTS)
$(CXX) $(CXXFLAGS) -o $# $(OBJECTS)
#Generate dependency files. Place them in build/host or build/target depending on choice
$(BUILD_DIR)/%.d: %.cpp
$(CXX) -MT $(BUILD_DIR)/$(#:.d=.o) -MM $(CXXFLAGS) $^ > $#
#Generate object files. Place them in build/host or build/target, depending on choice.
$(BUILD_DIR)/%.o: %.cpp
$(CXX) -o $# -c $^
#Create the build dir,
${BUILD_DIR}:
mkdir -p ${BUILD_DIR}
#Create the bin dir
${BIN_DIR}:
mkdir -p ${BIN_DIR}
.PHONY:clean
clean:
rm -f $(BUILD_DIR)/*.o $(BIN_DIR)/$(EXE) $(BUILD_DIR)/*.d
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPS)
endif
If you generate the dependencies as part of the compilation not only do you avoid having to take the extra step, you also rely on the compiler to generate the correct paths. This entails a few other changes to your makefile but I found it simpler to just rewrite it, make has a number of features to simplify some of the other operations.
arch ?= host
build_dir := build/$(arch)
bin_dir := bin/$(arch)
ifeq ($(arch),target)
prefix := arm-devkit-
endif
sources := main.cpp part1.cpp part2.cpp
objects := $(sources:%.cpp=$(build_dir)/%.o)
deps := $(objects:.o=.d)
target := $(bin_dir)/prog
CXX := $(prefix)$(CXX)
CPPFLAGS := -MMD -MP
$(target): CC := $(CXX)
$(target): $(objects) | $(bin_dir)
$(LINK.o) $^ $(LDLIBS) -o $#
$(build_dir)/%.o: %.cpp | $(build_dir)
$(COMPILE.cpp) $(OUTPUT_OPTION) $<
$(build_dir) $(bin_dir): ; mkdir -p $#
.PHONY: clean
clean: ; $(RM) $(target) $(objects) $(deps)
-include $(deps)
I was looking for a solution on this site and also tried google for some time now, but somehow I can't get it to work.
My source should be in the src directory and the object files would be in the obj directory. Now I try to create a simple makefie but I either get an error that there is no rule, or I can't make it work to use the directories.
CC = /usr/bin/gcc
CXXFLAGS = -O2 -g -Wall -fmessage-length=0
SRC:= nohupshd.cpp \
task.cpp
OBJ:= nohupshd.o \
task.o
OBJDIR:= obj
SRCDIR:= src
DEP:= src/task.h
LIBS:=
TARGET:= nohupshd
all: $(TARGET)
$(TARGET): $(OBJ)
$(CC) -o $(TARGET) $(OBJ) $(LIBS)
clean:
rm -f $(OBJ) $(TARGET)
Variant 1:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
$(CC) -S $(SRCDIR)/$< -o $(OBJDIR)/$#
$(CC) -c $(SRCDIR)/$< -o $(OBJDIR)/$#
Variant 1a:
%.o: %.cpp
$(CC) -S $(SRCDIR)/$< -o $(OBJDIR)/$#
$(CC) -c $(SRCDIR)/$< -o $(OBJDIR)/$#
When I use this pattern I always get an error that there is no rule for nohupshd.o to build.
Variant 2:
$(OBJ) : $(OBJDIR)/%.o: $(SRCDIR)/%.cpp
$(CC) -S $(SRCDIR)/$< -o $(OBJDIR)/$#
$(CC) -c $(SRCDIR)/$< -o $(OBJDIR)/$#
When I use this variant, I can see that it tries to build, but I get errors saying that "file".o doesn't fit the target pattern.
Another issue is that "$<" doesn't give me the source name. According to several sites it should, but I can see in the output that there is nothing, so how can I fix this?
Update:
In the meantime my newest version looks like this:
$(OBJDIR)/$(OBJ) : $(OBJDIR)/%.o : $(SRCDIR)/%.cpp
$(CC) -S $< -o $(OBJDIR)/`basename $# .o`.asm
$(CC) -c $< -o $#
This now manages to compile the first objectfile (nohupshd.o) but when make tries to do the second file it fails again saying: target 'task.o' doesn't match a pattern.
You actually have a couple if incorrect things above.
First you write My error was, that I was assuming that the pattern %.o matches ANY pattern ending with .o which it doesn't; that's not true. The pattern does match any string ending in .o. However, the pattern character % that is matched on the target side is replaced on the prerequisite side with the identical string. So if you have a target obj/task.o and it matches the pattern %.o then the stem (what the manual calls it) will be obj/task, and when the prerequisite is %.c that means that make will look for a prerequisite obj/task.c. Since there isn't one, and make doesn't know how to build one, that rule is discarded as not applying. When writing pattern rules you must write them so ONLY the identical parts of the names match the pattern character (%). ALL non-identical parts, including directories, must be specified explicitly.
Second, the rule $(OBJ) : $(SRC) is really not right. That line says that each object file depends on all the source files, so whenever any single source file changes all the object files will be recompiled. That's really not what you want (if that IS what you want you don't need make: you can just write a simple shell script). I don't know what you mean by since the rules is empty it invokes the pattern rule; you don't need this to invoke the pattern rule. The target depends on $(OBJ), and each object file depends on its source file (due to the pattern). You don't need this line at all.
Third, I don't know why you are trying to construct .asm files rather than just compiling directly from source to object, but if you really want them it would be cleaner and more "make-like" to create a separate pattern rule to build them: create a pattern rule $(OBJDIR)/%.o : $(OBJDIR)/%.asm and a rule $(OBJDIR)/%.asm : $(SRCDIR)/%.c. If you want the ASM files to be products of the build you should declare them as a prerequisite of all or similar, otherwise they'll be deleted as intermediate files.
Fourth, using things like basename is unnecessary. There are lots of automatic make variables that can be used instead. For example, $* expands to the stem, so you could write $(OBJDIR)/$*.asm. Of course if you make a separate pattern rule for ASM files you can just use $# or $< directly. There are various make functions that can also be used; see the manual.
Fifth, you define a variable containing a header file, DEP, but then never use it. Because it's not used, if you change that file nothing would be rebuilt. If you know that all the source files include every header you can use $(OBJ) : $(DEP) to define that; but it does mean (as in the second point above) that any change to any header causes all objects to recompile. You would be better off auto-generating the prerequisites; since you're using GCC this is quite simple.
Sixth, you're using C++ files (xxx.cpp) but you're using the C compiler. This will not work (the link line will fail: although the compiler can see you're compiling a C++ file and do the right thing, even if you call gcc, when you link a bunch of objects together it has no idea if those were C objects or C++ objects (or FORTRAN or whatever) so you MUST use the C++ front-end to link or it won't pull in the right C++ libraries). You should be using the make variable CXX to build C++ code, not CC, and setting it to g++ not gcc.
Seventh, you don't need .SUFFIXES: .c .o to use pattern rules. They are only needed for suffix rules, which you don't have here. You can keep the plain .SUFFIXES: though to disable built-in pattern matching which is a slight performance improvement.
Finally, you'll note you don't actually need the $(SRC) variable because make can infer it from the pattern rules. However, if you wanted to have your makefile less onerous to change, you could construct the contents of the OBJ variable from the SRC variable, like SRC = nohupshd.cpp task.cpp then OBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(SRC)).
So, all-in, this is how I would recommend you write your makefile (I don't include the auto-generated dependencies here though):
.SUFFIXES:
CXX := g++
CXXFLAGS := -O2 -g -Wall -fmessage-length=0
OBJDIR := obj
SRCDIR := src
TARGET := nohupshd
SRC := nohupshd.cpp task.cpp
DEP := src/task.h
LIBS :=
# ----
OBJ := $(patsubst %.cpp,$(OBJDIR)/%.o,$(SRC))
ASM := $(patsubst %.cpp,$(OBJDIR)/%.asm,$(SRC))
.PHONY: all clean
all: $(TARGET) $(ASM)
$(TARGET): $(OBJ)
$(CXX) -o $# $^ $(LIBS)
clean:
rm -f $(OBJDIR)/* $(TARGET)
$(OBJDIR)/%.o : $(SRCDIR)/%.asm
$(CXX) $(CXXFLAGS) -c -x assembler-with-cpp $< -o $#
$(OBJDIR)/%.asm : $(SRCDIR)/%.cpp
$(CXX) $(CPPFLAGS) -S $< -o $#
Don't repeat the directory names in the compiler line. $< and $# already have the directory names.
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
$(CC) -S $< -o $#
$(CC) -c $< -o $#
So finally I found the answer on how to write this makefile, for an exaplanation of my mistakes look at the posting I marked as correct answer:
The resulting makefile looks like this, and for completeness I post it here including dependencies for header files (remove the ASM parts if you don't need 'em):
.SUFFIXES:
.SUFFIXES: .o .cpp
.SUFFIXES: .o .d
CC := g++
LNK:= ar
CXXFLAGS = -O2 -g -Wall -fmessage-length=0
OBJDIR:= obj
SRCDIR:= src
HDIR:= include
INCLUDE_PATHS:= -Iinclude -Iinclude/interfaces -Iinclude/support
CPP_FILES := propertyfile/propertyfile.cpp \
propertyfile/propertyitem.cpp \
propertyfile/propertyfactory.cpp
OBJ := $(patsubst %.cpp,$(OBJDIR)/%.o, $(CPP_FILES))
SRC := $(patsubst %.cpp,$(SRCDIR)/%.o, $(CPP_FILES))
ASM := $(patsubst %.cpp, $(OBJDIR)/$*.asm, $(CPP_FILES))
LIBS:=
TARGET:= libsupport.a
all: $(TARGET)
$(TARGET): $(OBJ)
#echo "Linking..."
#$(LNK) rvs $(TARGET) $(OBJ)
#cp $(TARGET) ../lib
#cp -r include ..
clean:
rm -f $(OBJ) $(ASM) $(TARGET)
-include $(patsubst %.cpp,$(OBJDIR)/%.d, $(CPP_FILES))
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(OBJDIR)/%.d
#mkdir -p `dirname $#`
$(CC) $(CXXFLAGS) -S $< -o $(OBJDIR)/$*.asm $(INCLUDE_PATHS)
$(CC) $(CXXFLAGS) -c $< -o $# $(INCLUDE_PATHS)
$(OBJDIR)/%.d: $(SRCDIR)/%.cpp
$(CC) $(CXXFLAGS) -MM -MT $# -MF $(OBJDIR)/$*.d -c $< $(INCLUDE_PATHS)
I hope this helps other user. All examples that I found were either extremly simple and listed multiple files individually and not part of a rule, but didn't really explain how it works, or were so complicated that I couldn't find out how it can help me.