I'm very new to makefiles. I'm reading the GNU-make manual, but I'm still unclear about how to set the parameters for the compiler and the linker when they are executed by an implicit rule.
This is part of the makefile, note there is no explicit declaration of how to compile and link everything:
.PHONY: $(TARGET) build_libs
all: build_libs $(TARGET)
$(TARGET):
#echo "============> building target: $(TARGET)"
#$(MAKE) -C $(SDK_PATH)/VP_SDK/Build $(TMP_SDK_FLAGS) $(SDK_FLAGS) $(MAKECMDGOALS) USE_LINUX=yes
mv $(ARDRONE_TARGET_DIR)/ardrone_testing_tool $(TARGET)
mv $(TARGET) $(ARDRONE_TARGET_DIR)/
#echo "============> end building target: $(TARGET)"
$(MAKECMDGOALS): build_libs
#echo "============> making cmd goals"
#$(MAKE) -C $(SDK_PATH)/VP_SDK/Build $(TMP_SDK_FLAGS) $(SDK_FLAGS) $(MAKECMDGOALS) USE_LINUX=yes
#echo "============> end making cmd goals"
build_libs:
#echo "============> building libs"
#$(MAKE) -C $(SDK_PATH)/Soft/Build $(TMP_SDK_FLAGS) $(SDK_FLAGS) $(MAKECMDGOALS) USE_LINUX=yes
#echo "============> end building libs"
That makefile builds an executable from the source files and library. But I want to compile them into a shared library. Because of that I (think I) have to add the -fPIC parameter to cc and the -shared and -soname parameters to ld. I've tried with CFLAGS=-fPIC and LDFLAGS=-shared -soname foo, which didn't work. Has anybody suggestions on how to get a shared libarary? If you need more information please just ask. Thanks in advance!
UPDATE: The makefile in $(SDK_PATH)/Soft/Build:
GEN_CUSTOM_HEADER:=../Common/generated_custom.h
include custom.makefile
include config.makefile
GNUTOOLS_PATH=/usr/local/$(GNUTOOLS_VERSION)/bin
define ADD_RULE_TEMPLATE
TO_BUILD+=build_$(1)
endef
# Add rule for each target
$(foreach target,$(TARGETS),$(eval $(call ADD_RULE_TEMPLATE,$(target))))
.PHONY: linux_sample svn_update $(TO_BUILD) build_libs $(MAKECMDGOALS)
all: $(GEN_CUSTOM_HEADER) build_libs $(TO_BUILD)
$(GEN_CUSTOM_HEADER): custom.makefile
#echo "#ifndef _GENERATED_CUSTOM_CONFIGURATION_H_" > $#
#echo "#define _GENERATED_CUSTOM_CONFIGURATION_H_" >> $#
#echo >> $#
#echo "#if defined(BR2_PACKAGE_BCM4318_AP)" >> $#
#echo "# define AP" >> $#
#echo "#else" >> $#
#echo "# define STA" >> $#
#echo "#endif" >> $#
#echo "#define CURRENT_NUM_VERSION_SOFT \"$(MAJOR_VERSION).$(MINOR_VERSION).$(MODIF_VERSION)\"" >> $#
#echo "#define CURRENT_BUILD_DATE \"$(shell date +%F\ %H:%M)\"" >> $#
#echo >> $#
ifeq ("$(VIDEO_YUV)","yes")
#echo "#define USE_VIDEO_YUV" >> $#
endif
ifeq ("$(RECORD_VISION_DATA)","yes")
#echo "#define RECORD_VISION_DATA" >> $#
endif
#echo >> $#
#echo "#define WIFI_NETWORK_NAME \"$(WIFI_NETWORK_NAME)\"" >> $#
#echo "#define WIFI_BROADCAST \"$(WIFI_BROADCAST)\"" >> $#
#echo "#define WIFI_ARDRONE_IP \"$(WIFI_ARDRONE_IP)\"" >> $#
#echo >> $#
#echo "#if defined(__linux__) || defined(USE_MINGW32)" >> $#
#echo "# define WIFI_MOBILE_IP \"$(WIFI_MOBILE_IP)\"" >> $#
#echo "# define WIRED_ITFNAME \"$(WIRED_ITFNAME)\"" >> $#
#echo "#endif // ! __linux__" >> $#
#echo >> $#
#echo >> $#
#echo "#endif // ! _GENERATED_CUSTOM_CONFIGURATION_H_" >> $#
ifneq "$(MAKECMDGOALS)" ""
ifneq "$(MAKECMDGOALS)" "clean"
ifneq "$(MAKECMDGOALS)" "update"
$(MAKECMDGOALS):
#echo -e "\nCannot make what you ask me to do :-("
else
$(MAKECMDGOALS): svn_update
endif
endif
endif
$(MAKECMDGOALS): build_libs $(TO_BUILD)
checkpackages:
ifeq ($(IPHONE_MODE),yes)
sh $(shell pwd)/check_dependencies.sh iphone RELEASE_BUILD=$(RELEASE_BUILD) $(MAKECMDGOALS)
else
ifeq ($(USE_LINUX),yes)
sh $(shell pwd)/check_dependencies.sh static RELEASE_BUILD=$(RELEASE_BUILD) $(MAKECMDGOALS)
else
ifeq ($(USE_ANDROID),yes)
sh $(shell pwd)/check_dependencies.sh android_no_neon RELEASE_BUILD=$(RELEASE_BUILD) $(MAKECMDGOALS)
endif
endif
endif
define GENERIC_RULES_TEMPLATE
build_$(1):
#$(MAKE) -C $(1) $(MAKECMDGOALS)
endef
$(foreach target,$(TARGETS),$(eval $(call GENERIC_RULES_TEMPLATE,$(target))))
build_libs: checkpackages
#$(MAKE) PC_TARGET=yes USE_ARDRONE_TOOL=yes TARGET=pc_ USE_MINGW32=no -C ../Lib/Build $(MAKECMDGOALS)
#$(MAKE) PC_TARGET=yes USE_ARDRONE_TOOL=no TARGET=pc_ USE_MINGW32=no -C ../Lib/Build $(MAKECMDGOALS)
ifeq ("$(MINGW32_MODE)","yes")
ifeq ($(shell which i586-mingw32msvc-gcc 2> /dev/null),)
$(warning You need MinGW32 to compile My Ardrone lib for Windows if you want. (under Debian: apt-get install mingw32))
else
# #$(MAKE) PC_TARGET=yes TARGET=mingw32_ USE_MINGW32=yes TMP_SDK_FLAGS="USE_MINGW32=yes NO_COM=yes USE_BLUEZ=no" -C ../Lib/Build $(MAKECMDGOALS)
# #$(MAKE) PC_TARGET=yes TARGET=emb_mingw32_ USE_MINGW32=yes CONTROL_DLL=yes TMP_SDK_FLAGS="USE_MINGW32=yes NO_COM=yes USE_BLUEZ=no" -C ../Lib/Build $(MAKECMDGOALS)
endif
endif
ifeq ($(WIIMOTE_SUPPORT),yes)
# #$(MAKE) PC_TARGET=yes TARGET=pc_ TMP_SDK_FLAGS="USE_BLUEZ=yes" -C ../Lib/libcwiid $(MAKECMDGOALS)
endif
define svn_update_template
cd ../.. ; \
echo "Checking out tag $(1) of $(2) ..." ; \
if [ $(1) != head ] ; then \
svn co -r $(1) https://svn.ardrone.org/repo/ARDrone_API/$(2) ; \
else \
svn co https://svn.ardrone.org/repo/ARDrone_API/$(2) ; \
fi ; \
cd Soft/Build ;
endef
svn_update:
#-$(call svn_update_template,$(SDK_VERSION),ARDroneLib)
If custom.makefile and config.makefile are needed you can find them here: http://pastebin.com/H8PNKKhu
UPDATE 2: I just discovered this, located in $(SDK_PATH)/VP_SDK/Build: http://pastebin.com/3knnSkmy
Since you haven't showed us the makefile in $(SDK_PATH)/Soft/Build, I'm going to take a guess.
In the GNU Make manual, there is the list of variables used by implicit rules:
CFLAGS: Extra flags to give the C compiler.
LDFLAGS: Extra flags to give to compiler when they are supposed to invoke the linker 'ld'.
In addition, the catalogue of implicit rules mentions the LDLIBS variable that names libraries used in the implicit link rule. (The implicit link rule is fine when you have a single source file being linked or where one of the object files is the name of the final executable, otherwise you need to write an explicit linking rule.)
This isn't coming into focus. These appear to be generated makefiles, so they're hard to trace, there's clearly more going on than we're seeing (and I don't blame you for not posting everything), and I don't see where the build_libs rule leads, or any use of the linker, or anything that could build a static library. We could show you how to write an explicit rule to build a shared library, but without a list of sources or objects we wouldn't know what to put into that library.
This is getting desperate, but could you try the following:
1) make -C $(SDK_PATH)/Soft/Build (putting in the appropriate value for $(SDK_PATH)) and verify that this produces the static library.
2) make -n, capture the torrent of output and put it in pastebin. We'll try to see what rules it's using, which might lead to what we need.
I did it. Finally!!!
The solution: in $(SDK_PATH)/VP_SDK/Build there was a file named generic.makefile containing all the compiler and linker invocations. I had to add the -shared and -fPIC arguments to some of them. Sounds really simple, but nothing of that was documented so I first had to look for that hidden compiler/linker invocations...
Related
Below code is part of Makefile,i confuse what the purpose of use $$$$(dir $$$$#) as order-only-prerequisites in cc_template function
.SECONDEXPANSION:
# get .o obj files: (#files[, packet])
toobj = $(addprefix $(OBJDIR)$(SLASH)$(if $(2),$(2)$(SLASH)),\
$(addsuffix .o,$(basename $(1))))
# get .d dependency files: (#files[, packet])
todep = $(patsubst %.o,%.d,$(call toobj,$(1),$(2)))
# cc compile template, generate rule for dep, obj: (file, cc[, flags, dir])
define cc_template
$$(call todep,$(1),$(4)): $(1) | $$$$(dir $$$$#)
#$(2) -I$$(dir $(1)) $(3) -MM $$< -MT "$$(patsubst %.d,%.o,$$#) $$#"> $$#
$$(call toobj,$(1),$(4)): $(1) | $$$$(dir $$$$#)
#echo + cc $$<
$(V)$(2) -I$$(dir $(1)) $(3) -c $$< -o $$#
ALLOBJS += $$(call toobj,$(1),$(4))
endef
The whole Makefile is from https://github.com/chyyuu/ucore_os_lab/blob/master/labcodes/lab1/tools/function.mk
Since you didn't directly ask about the quoting I won't go through it, except to say that after all is said and done what this will do is make the target's directory into an order-only prerequisite.
So, if your target is my/foo/bar.o then my/foo will be an order-only prerequisite of that target.
This is done to ensure that the target directory exists before invoking the rule that creates an object file in it (the compiler won't create output directories for you: if they don't exist it will just fail).
Elsewhere in your makefile you should find a rule that creates directories:
<sometargets>:
mkdir -p $#
.PHONY: <sometargets>
Here is my project structure.
| - src
| - boot
| - table.s
| - boot.s
| - machine
| - revb
| - memmap
| - vars.s
| - os
| - utils
| - ...lots here
I am grouping features by folder, and have a special folder for machine specific code, link scripts, anything.
The problem I am having with make is that I can't seem to get the Pattern match to work.
The below runs and builds the .o files.
#This gets repetative as every file needs to have a recipe by itself.
$(TARGET_DIR)/hash.o : $(SRC_DIR)/utils/hash.s machine
#echo "compiling $<"
$(CC) $(CFLAGS) $< -o $#
#echo "assembly dump $#"
$(DUMP) -D $# > $#.list
The below does NOT work. It doesn't run any of the commands.
#if this works that would be perfect every folder/file will be a recipe!
$(TARGET_DIR)/%.o : $(SRC_DIR)/%.s machine
#echo "compiling $<"
$(CC) $(CFLAGS) $< -o $#
#echo "assembly dump $#"
$(DUMP) -D $# > $#.list
Nothing runs at all, For some reason no files seem to match that pattern.
I have also tried this.
# if this works, it would be a bit annoying as this is per feature recipe/target.
$(TARGET_DIR)/%.o : $(SRC_DIR)/boot/%.s machine
#echo "compiling $<"
$(CC) $(CFLAGS) $< -o $#
#echo "assembly dump $#"
$(DUMP) -D $# > $#.list
Edit
full makefile for reference
CFLAGS = -march=rv32i -mabi=ilp32
CC = riscv32-unknown-linux-gnu-as
LINKER = riscv32-unknown-linux-gnu-ld
DUMP = riscv32-unknown-linux-gnu-objdump
COPY = riscv32-unknown-linux-gnu-objcopy
SRC_DIR = src
TARGET_DIR = target
MACHINE_FILES_DIR = machine
TARGET_MACHINE = revb
# vizoros : $(TARGET_DIR)/%.o
# $(LINKER) $(TARGET_DIR)/boot.o $(TARGET_DIR)/table.o $(TARGET_DIR)/os.o $(TARGET_DIR)/hash.o -T $(TARGET_DIR)/memmap -o $(TARGET_DIR)/$#.elf
# $(DUMP) -D $(TARGET_DIR)/$#.elf > $(TARGET_DIR)/$#.list
$(TARGET_DIR)/%.o : $(SRC_DIR)/boot/%.s machine
#echo "compiling $<"
$(CC) $(CFLAGS) $< -o $#
#echo "assembly dump $#"
$(DUMP) -D $# > $#.list
machine: folders
cp -r $(SRC_DIR)/$(MACHINE_FILES_DIR)/$(TARGET_MACHINE)/. $(TARGET_DIR)
folders:
mkdir -p $(TARGET_DIR)
.phony: clean
clean:
rm -rf $(TARGET_DIR)
As with your other question, you are expecting too much fancy capability from make. Make is a very simple tool. It will not go looking around your directories for files that could be built. It will build only exactly what you ask it to build. It will not infer matching files based on heuristics: it will match only exact strings.
Make always works backwards: it starts with the final target you ask it to build and finds a rule that can build that. Then it looks at each of the prerequisites of that final target and finds a rule that can build each one of those. Then it looks at any prerequisites of each of the prerequisites of those, etc. Once it has built (or found source files for) all the prerequisites of a target, it builds that target, then walks back up until finally it builds the final target you asked for.
In your makefile above you've commented out the "final target" you want built (vizoros), so of course make will not build it.
I'm just going to give you a makefile that solves your problem... if you want to understand what it does please consult the GNU make manual. Note I haven't actually tried this, I just wrote it here. Also note I omitted the whole machine thing because I don't understand what it's supposed to do and you didn't really define it.
CFLAGS = -march=rv32i -mabi=ilp32
CC = riscv32-unknown-linux-gnu-as
LINKER = riscv32-unknown-linux-gnu-ld
DUMP = riscv32-unknown-linux-gnu-objdump
COPY = riscv32-unknown-linux-gnu-objcopy
SRC_DIR = src
TARGET_DIR = target
MACHINE_FILES_DIR = machine
TARGET_MACHINE = revb
# Find all .s files under SRC_DIR
SRCS := $(shell find $(SRC_DIR) -name \*.s)
# Use VPATH with a list of directories to be searched for
VPATH := $(sort $(dir $(SRCS)))
# Convert all .s files into .o files directly under TARGET_DIR
# First strip off the directory, then convert
OBJS := $(patsubst %.s,$(TARGET_DIR)/%.o,$(notdir $(SRCS)))
# Define the final target and provide all the object files as prerequisites
$(TARGET_DIR)/vizoros.elf : $(OBJS)
mkdir -p $(#D)
$(LINKER) $^ -T $(TARGET_DIR)/memmap -o $#
$(DUMP) -D $# > $(#:.elf=.list)
# Define a pattern rule to build an object file in TARGET_DIR
# The source file will be searched for via VPATH
$(TARGET_DIR)/%.o : %.s
mkdir -p $(#D)
#echo "compiling $<"
$(CC) $(CFLAGS) -c $< -o $#
#echo "assembly dump $#"
$(DUMP) -D $# > $#.list
# It must be .PHONY, not .phony: make, like all POSIX tools, is
# case-sensitive
.PHONY: clean
clean:
rm -rf $(TARGET_DIR)
References:
GNU make manual
= vs := variables
shell function
dir and notdir functions
sort and patsubst functions
VPATH
Substitution references
Automatic variables
Phony targets
Also note you had an error in your compile command; you were missing the -c option which tells the compiler to generate an object file rather than a final executable file.
I want to compile the project and run it in the debugger. There is the following line in the Makefile:
all: build_libs $(TARGET)
Can i specify -g option of gcc in this line? Or it should be somewhere else?
All contents of the Makefile are bellow.
SDK_PATH:=$(shell pwd)/../../ARDroneLib
PC_TARGET=yes
USE_LINUX=yes
ifdef MYKONOS
include $(ARDRONE_CUSTOM_CONFIG)
include $(ARDRONE_BUILD_CONFIG)
else
include $(SDK_PATH)/Soft/Build/custom.makefile
include $(SDK_PATH)/Soft/Build/config.makefile
endif
ifeq "$(RELEASE_BUILD)" "yes"
ARDRONE_TARGET_DIR=$(shell pwd)/../../Build/Release
else
ARDRONE_TARGET_DIR=$(shell pwd)/../../Build/Debug
endif
TARGET=video_opencv
SRC_DIR:=$(shell pwd)/../Sources
# Define application source files
GENERIC_BINARIES_SOURCE_DIR:=$(SRC_DIR)
GENERIC_BINARIES_COMMON_SOURCE_FILES+=\
Video/pre_stage.c\
Video/post_stage.c\
Video/display_stage.c\
image_processing.c\
controls.c
GENERIC_INCLUDES+= \
$(SRC_DIR) \
$(LIB_DIR) \
$(SDK_PATH)/Soft/Common \
$(SDK_PATH)/Soft/Lib
GENERIC_TARGET_BINARIES_PREFIX=
GENERIC_TARGET_BINARIES_DIR=$(ARDRONE_TARGET_DIR)
GENERIC_BINARIES_SOURCE_ENTRYPOINTS+= \
ardrone_testing_tool.c
GENERIC_INCLUDES:=$(addprefix -I,$(GENERIC_INCLUDES))
GENERIC_INCLUDES+=`pkg-config --cflags opencv`
GENERIC_LIB_PATHS=-L$(GENERIC_TARGET_BINARIES_DIR)
GENERIC_LIBS=-lpc_ardrone -lrt -lgtk-x11-2.0 -lcairo -lgobject-2.0 -lgdk-x11-2.0 -lm `pkg-config --libs opencv`
SDK_FLAGS+="USE_APP=yes"
SDK_FLAGS+="APP_ID=linux_video_demo"
export GENERIC_CFLAGS
export GENERIC_LIBS
export GENERIC_LIB_PATHS
export GENERIC_INCLUDES
export GENERIC_BINARIES_SOURCE_DIR
export GENERIC_BINARIES_COMMON_SOURCE_FILES
export GENERIC_TARGET_BINARIES_PREFIX
export GENERIC_TARGET_BINARIES_DIR
export GENERIC_BINARIES_SOURCE_ENTRYPOINTS
# Bug fix ...
export GENERIC_LIBRARY_SOURCE_DIR=$(GENERIC_BINARIES_SOURCE_DIR)
.PHONY: $(TARGET) build_libs
all: build_libs $(TARGET)
$(TARGET):
#$(MAKE) -C $(SDK_PATH)/VP_SDK/Build $(TMP_SDK_FLAGS) $(SDK_FLAGS) $(MAKECMDGOALS) USE_LINUX=yes
mv $(ARDRONE_TARGET_DIR)/ardrone_testing_tool $(TARGET)
mv $(TARGET) $(ARDRONE_TARGET_DIR)/
$(MAKECMDGOALS): build_libs
#$(MAKE) -C $(SDK_PATH)/VP_SDK/Build $(TMP_SDK_FLAGS) $(SDK_FLAGS) $(MAKECMDGOALS) USE_LINUX=yes
build_libs:
#$(MAKE) -C $(SDK_PATH)/Soft/Build $(TMP_SDK_FLAGS) $(SDK_FLAGS) $(MAKECMDGOALS) USE_LINUX=yes
It seems like if you add GENERIC_CFLAGS = -g to this makefile, it should work. However, the real work of compilation is not being done by this makefile, it's being done by a makefile in the subdirectory $(SDK_PATH)/VP_SDK/Build (note how the $(TARGET) rule re-invokes make in that subdirectory with the -C flag). So we can't know exactly what needs to be done by looking at this makefile.
I am trying to build a code on Ubuntu 12.04 using Eclipse with Arduino Due.
Every time I am getting the error in the console as -
make all
make: *** No rule to make target ArduinoLib5.a, needed by all. Stop.
My makefile is below : Please have a look and let me know how can I fix the error.
ifneq ($(strip $(C_DEPS)),)
-include $(C_DEPS)
endif
ifneq ($(strip $(ASM_DEPS)),)
-include $(ASM_DEPS)
endif
ifneq ($(strip $(CC_DEPS)),)
-include $(CC_DEPS)
endif
ifneq ($(strip $(CPP_DEPS)),)
-include $(CPP_DEPS)
endif
ifneq ($(strip $(CXX_DEPS)),)
-include $(CXX_DEPS)
endif
ifneq ($(strip $(C_UPPER_DEPS)),)
-include $(C_UPPER_DEPS)
endif
ifneq ($(strip $(S_UPPER_DEPS)),)
-include $(S_UPPER_DEPS)
endif
endif
-include ../makefile.defs
# Add inputs and outputs from these tool invocations to the build variables
EXECUTABLES += \
USER_OBJS \
SECONDARY_FLASH += \
ArduinoLib5.hex \
SECONDARY_LIST += \
ArduinoLib5.lst \
SECONDARY_SIZE += \
ArduinoLib5.siz \
# All Target
all: ArduinoLib5.a
# Tool invocations
#echo 'No tool found that can build the extension specified with the build artifact name $#'
USER_OBJS: $(OBJS) $(USER_OBJS)
#echo 'Invoking: ARM Sourcery Linux GCC C++ Linker'
arm-none-eabi-g++ -Wl,-Map,ArduinoLib5.map -mcpu=cortex-m3 -mthumb -g -ggdb -o "USER_OBJS" $(OBJS) $(USER_OBJS) $(LIBS)
#echo 'Finished building: $#'
#echo ' '
ArduinoLib5.hex: ArduinoLib5.a
#echo 'Invoking: ARM Sourcery Linux GNU Create Flash Image'
arm-none-eabi-objcopy -O ihex ArduinoLib5.a "ArduinoLib5.hex"
#echo 'Finished building: $#'
#echo ' '
ArduinoLib5.lst: ArduinoLib5.a
#echo 'Invoking: ARM Sourcery Linux GNU Create Listing'
arm-none-eabi-objdump -h -S ArduinoLib5.a > "ArduinoLib5.lst"
#echo 'Finished building: $#'
#echo ' '
ArduinoLib5.siz: ArduinoLib5.a
#echo 'Invoking: ARM Sourcery Linux GNU Print Size'
arm-none-eabi-size --format=berkeley ArduinoLib5.a
#echo 'Finished building: $#'
#echo ' '
# Other Targets
clean:
-$(RM) $(OBJS)$(C_DEPS)$(SECONDARY_FLASH)$(CXX_DEPS)$(S_UPPER_DEPS)$(SECONDARY_LIST)$(C++_DEPS)$(SECONDARY_SIZE)$(ASM_DEPS)$(CC_DEPS)$(CPP_DEPS)$(EXECUTABLES)$(C_UPPER_DEPS) ArduinoLib5.a
-#echo ' '
.PHONY: all clean dependents
.SECONDARY:
-include ../makefile.targets
you're indeed missing a rule which name is ArduinoLib5.a: or a ArduinoLib5.a file in current directory.
And I don't get your all rule. If it relies on the already existing ArduinoLib5.a file, it would do nothing. If it relies on a missing rule that generates ArduinoLib5.a, then it would not do "all" (i.e. not going through the .hex/.lst/.siz rules) but only that file.
Furthermore, looking at what the all rule does, I don't understand what $(OBJS)/$(USER_OBJS) are... but maybe they're given in env by eclipse!
Overall, your Makefile looks totally wrong to me.
I have a Makefile for a C++ program that uses automatic dependency generation. The %.d recipe is taken from the GNU Make manual.
The problem is that somehow "Makefile" is being added as a target and then an implicit rule is causing it to assume it's an executable and using my src/%.cpp rule to try to compile src/Makefile.cpp. When looking at the debug info, this always happens right after the include is executed.
No need to remake target `build/Sprite.d'.
Considering target file `Makefile'.
Looking for an implicit rule for `Makefile'.
...
Trying pattern rule with stem `Makefile'.
Trying implicit prerequisite `Makefile.o'.
Looking for a rule with intermediate file `Makefile.o'.
I know include causes the given Makefiles to be rebuilt if necessary. Does it also try to rebuild the current Makefile? If so how do I stop it, and if not, then why is "Makefile" being added as a target?
Also, the include is executed, causing the .d files to be remade even if I specify a target on the command line, such as make clean. Is there any way to stop that from happening?
# $(call setsuffix,newsuffix,files)
# Replaces all the suffixes of the given list of files.
setsuffix = $(foreach file,$2,$(subst $(suffix $(file)),$1,$(file)))
# $(call twinfile,newdir,newsuffix,oldfile)
# Turns a path to one file into a path to a corresponding file in a different
# directory with a different suffix.
twinfile = $(addprefix $1,$(call setsuffix,$2,$(notdir $3)))
MAIN = main
SOURCE_DIR = src/
INCLUDE_DIR = include/
BUILD_DIR = build/
SOURCES = $(wildcard $(SOURCE_DIR)*.cpp)
OBJECTS = $(call twinfile,$(BUILD_DIR),.o,$(SOURCES))
DEPENDENCIES = $(call twinfile,$(BUILD_DIR),.d,$(SOURCES))
CXX = g++
LIBS = -lpng
CXXFLAGS = -I $(INCLUDE_DIR)
.PHONY: all
all: $(MAIN)
$(MAIN): $(OBJECTS)
$(CXX) $(LIBS) $^ -o $(MAIN)
include $(DEPENDENCIES)
%.o: $(BUILD_DIR)stamp
$(CXX) $(CXXFLAGS) -c $(call twinfile,$(SOURCE_DIR),.cpp,$#) -o $#
$(BUILD_DIR)%.d: $(SOURCE_DIR)%.cpp $(BUILD_DIR)stamp
# echo Generate dependencies for $ $#.$$$$; \
sed 's,\($*\)\.o[ :]*,$(BUILD_DIR)\1.o $# : ,g' $#; \
rm -f $#.$$$$
$(BUILD_DIR)stamp:
mkdir -p $(BUILD_DIR)
touch $#
.PHONY: clean
clean:
rm -rf $(BUILD_DIR)
.PHONY: printvars
printvars:
# echo $(SOURCES)
# echo $(OBJECTS)
# echo $(DEPENDENCIES)
Make will always try to remake the Makefile before executing the Makefile. To do so, make will look for rules which can be used to recreate the Makefile. Make will look for quite a few implicit rules and other obscure methods to (re)create the Makefile.
In your case, make somehow decided that the pattern rule %.o: $(BUILD_DIR)/stamp should be used to recreate the Makefile, which failed.
To prevent make from remaking the Makefile you can write a rule with an empty recipe:
Makefile: ;
Read the chapter Remaking Makefiles in the make manual for more explanation.
About the included Makefiles: Included Makefiles will always be included, regardless of the target. If the included makefiles are missing (or older than their prerequisites) then they will first be (re)created. That means a make clean will first generate the .d Makefiles, only to delete them again.
You can prevent the including for specific goals by wraping the include directive in a conditional:
ifneq ($(MAKECMDGOALS),clean)
include $(DEPENDENCIES)
endif
Here is your entire Makefile with some fixes. I marked the places where I changed something.
# Makefile
# $(call setsuffix,newsuffix,files)
# Replaces all the suffixes of the given list of files.
setsuffix = $(foreach file,$2,$(subst $(suffix $(file)),$1,$(file)))
# $(call twinfile,newdir,newsuffix,oldfile)
# Turns a path to one file into a path to a corresponding file in a different
# directory with a different suffix.
twinfile = $(addprefix $1/,$(call setsuffix,$2,$(notdir $3)))
MAIN = main
SOURCE_DIR = src
INCLUDE_DIR = include
BUILD_DIR = build
SOURCES = $(wildcard $(SOURCE_DIR)/*.cpp)
OBJECTS = $(call twinfile,$(BUILD_DIR),.o,$(SOURCES))
DEPENDENCIES = $(call twinfile,$(BUILD_DIR),.d,$(SOURCES))
CXX = g++
LIBS = -lpng
CXXFLAGS = -I $(INCLUDE_DIR)
.PHONY: all
all: $(MAIN)
$(MAIN): $(OBJECTS)
$(CXX) $(LIBS) $^ -o $(MAIN)
# -------> only include if goal is not clean <---------
ifneq ($(MAKECMDGOALS),clean)
include $(DEPENDENCIES)
endif
# ---------> fixed this target <--------------
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.cpp $(BUILD_DIR)/stamp
$(CXX) $(CXXFLAGS) -c $(call twinfile,$(SOURCE_DIR),.cpp,$#) -o $#
# ---------> and this target <---------------
$(BUILD_DIR)/%.d: $(SOURCE_DIR)/%.cpp $(BUILD_DIR)/stamp
# echo Generate dependencies for $#;
#set -e; rm -f $#; \
$(CC) -M $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,$(BUILD_DIR)\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
$(BUILD_DIR)/stamp:
mkdir -p $(BUILD_DIR)
touch $#
.PHONY: clean
clean:
rm -rf $(BUILD_DIR)
.PHONY: printvars
printvars:
# echo $(SOURCES)
# echo $(OBJECTS)
# echo $(DEPENDENCIES)