The function of the "ifneq ($(MAKECMDGOALS),clean)" part in the Makefile - makefile

I really don't know the function of the following part:
ifneq ($(MAKECMDGOALS),clean)
-include $(DFILES)
endif
Here is the possible explanation I get from the GNU make manual:
to avoid including ‘.d’ files during clean rules, so make won’t create
them only to immediately remove them again:
But I don't fully understand "won’t create them only to immediately remove them again".
Here is the Makefile from derivative.tar.bz2 from http://www.dirac.org/linux/gdb/03-Initialization,_Listing,_And_Running.php#wherearewegoingtogo:
TARGET = driver
# CC = colorgcc
CC = gcc
CFILES = $(wildcard *.c)
OFILES = $(patsubst %.c, %.o, $(CFILES))
DFILES = $(patsubst %.c, .deps/%.d, $(CFILES))
WARN = -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Waggregate-return \
-Wpointer-arith -Wcast-qual -Wcast-align -Wmissing-declarations -pedantic \
-Wnested-externs -Wredundant-decls -Wwrite-strings -Winline -Werror
CFLAGS = -std=c99 $(WARN) -g3
LDLIBS = -lm
all: $(TARGET)
ctags *.c *.h
$(TARGET): $(OFILES)
$(CC) -o $(TARGET) $(OFILES) $(LDLIBS)
.deps/%.d: %.c
#mkdir -p .deps
#$(CC) -MM $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; $(RM) -rf $#.$$$$
ifneq ($(MAKECMDGOALS),clean)
-include $(DFILES)
endif
.PHONY: clean nuke
clean:
$(RM) -rf $(TARGET) *.o core .deps tags

Let's suppose you've just untarred the archive, and for whatever reason you want to run make clean before anything else. Presumably, it is already clean. Now, without the ifneq, make would:
Execute the include $(DFILES) line. Before doing the include proper, it would...
Run the recipe for .deps/%.d: %.c because the $(DFILES) variable contains files with names that match .deps/%.d. This means running $(CC) (which is gcc by default), which is a rather expensive operation. Once the recipe is run as many times as there are .d files to generate, then...
Run the recipe for clean.
All the work done in 2 is pointless since at step 3 it will be deleted. The reason 2 exists is that when you include a file, make first checks whether it has a recipe to generate the file to be included an runs the recipe if the file does not exist or is out of date.
The ifneq bit allows the Makefile to avoid doing the work in step 2 if the goal is clean.

Related

How to let avr-gcc output *.o to separate folder in Makefile with `%.o: %.c`?

As showed in first screenshot, my ideal AVR project structure is that:
*.o, *.elf and *.hex files are in build folder.
PomoScheler.c and pinDefines.h as main files are in root folder, while other *.c and *.h are in src folder.
But *.o are always generated at the same folder as *.c like showed in second screenshot, no matter how.
(I attached my endeavors and whole Makefile below the screenshots)
Firstly, I tried build/ before $#, in vain. The terminal still the same.
# My first Makefile endeavor
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o build/$#
# Terminal command generated by Makefile (Look at the end: *.o path still same as *.c)
avr-gcc -Os -g -std=gnu99 -Wall -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -ffunction-sections -fdata-sections -DF_CPU=1000000UL -DBAUD=9600UL -I. -I~/Developer/bin/avr8-gnu-toolchain-darwin_x86_64/avr/include -mmcu=atmega328p -c -o src/RotaryEncoder.o src/RotaryEncoder.c
Secondly, I tried to add mv $# build to explicitly move it to build folder. But nothing happened. Even echo are not displayed in Terminal.
# My second Makefile endeavor
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $#
mv $# build
echo ---------Hello---------
Thirdly, I delete $(HEADERS) and replace $< with $^ just to have a try. The mv is executed. But it cannot find *.o file this time even though I have VPATH = src:build in Makefile.
# My third Makefile endeavor
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $^ -o $#
mv $# build
# Terminal error
Assembler messages:
Fatal error: can't create build/src/RotaryEncoder.o: No such file or directory
And my whole Makefile is here. Please help me out.
# My whole Makefile
MCU = atmega328p
F_CPU = 1000000UL
BAUD = 9600UL
LIBDIR = ~/Developer/bin/avr8-gnu-toolchain-darwin_x86_64/avr/include
PROGRAMMER_TYPE = usbtiny
PROGRAMMER_ARGS =
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRSIZE = avr-size
AVRDUDE = avrdude
##########------------------------------------------------------##########
VPATH = ./src:./build
TARGET = $(lastword $(subst /, ,$(CURDIR)))
SOURCES=$(wildcard *.c src/*.c $(LIBDIR)/*.c)
OBJECTS=$(SOURCES:.c=.o)
HEADERS=$(SOURCES:.c=.h)
CPPFLAGS = -DF_CPU=$(F_CPU) -DBAUD=$(BAUD) -I. -I$(LIBDIR)
CFLAGS = -Os -g -std=gnu99 -Wall
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CFLAGS += -ffunction-sections -fdata-sections
LDFLAGS = -Wl,-Map,build/$(TARGET).map
LDFLAGS += -Wl,--gc-sections
TARGET_ARCH = -mmcu=$(MCU)
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o build/$#
$(TARGET).elf: $(OBJECTS)
$(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LDLIBS) -o build/$#
%.hex: %.elf
$(OBJCOPY) -j .text -j .data -O ihex build/$< build/$#
all: $(TARGET).hex
size: $(TARGET).elf
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
clean:
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
$(TARGET).eeprom
flash: $(TARGET).hex
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
This is clearly not right:
OBJECTS = $(SOURCES:.c=.o)
because the object files you want to create are not foo.o etc. which is what this will expand to; the object files are build/foo.o etc. So this has to be:
OBJECTS = $(patsubst %.c,build/%.o)
All of your attempts to trick make by telling it your recipe will build one target (foo.o) but actually building a totally different target (build/foo.o) are doomed to fail, regardless of whether you have the compiler do it directly, you use mv, or any other method.
If you just tell make what your recipe actually does, you will have a much simpler time of it:
build/%.o: %.c
mkdir -p $(#D)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $^ -o $#
Probably you have similar issues with the other rules that you want to put into other directories.
You can't do this by trying to hide it from make. Make has to know where the files actually are.
BTW, VPATH cannot help here. VPATH is for finding source files, it cannot be used for finding generated files. So you could use VPATH to find your .c files but not your .o files.

Makefile won't compile anything other than "kernel.c"

I've been trying to compile an OS however whenever I attempt to compile it using the make file it only compiles "kernel.c" and I can't seem to figure out why. I need help to figure what's wrong. I've tried everything I could possibly do to fix it at least from my knowledge.
Here's the code:
PROJECT_DIR= ..
CXXFLAGS= -ggdb3 -O0 -Wall -O2 -ffreestanding -nostdinc -nostdlib
CFLAGS=-std=c17
CSRCFLAGS= -O2 -Wall -Wextra
LFLAGS= -ffreestanding -O2 -nostdlib
IMG_PATH= ../
BUILD_BACK_TWO= ../../../build
CFILES= $(wildcard *.c)
OFILES= $(CFILES:.c=.o)
GCCPATH=C:/CrossCompilers/gcc-arm-10.3-2021.07-mingw-w64-i686-aarch64-none-elf
CFLAGSSTART= -ffreestanding -c
CFLAGSEND= -O2 -Wall -Wextra
GCCFLAGS= -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles
GCCPATHAARCH= $(GCCPATH)/aarch64-none-elf/bin
GCCPATHBIN= $(GCCPATH)/bin
ASMCFLAGS= -f elf32 -F dwarf -g -w+all
ASM= -s
# Location of the files
THIS_DIR := $(dir $(abspath $(firstword $(MAKEFILE_LIST))))
SRC = $(PROJECT_DIR)/src
UI_IMAGES = $(PROJECT_DIR)/images/ui
OBJ_DIR = $(PROJECT_DIR)/build/objects
ASMSOURCES = $(wildcard $(SRC)/*.s)
SOURCES = $(wildcard $(SRC)/*.c)
SOURCES = $(wildcard $(SRC)/$(ARCHDIR)/*.c)
UISOURCES = $(wildcard $(UI_IMAGES)/*.png)
OBJECTS = $(patsubst $(SRC)/%.s, $(OBJ_DIR)/%.o, $(ASMSOURCES))
OBJECTS += $(patsubst $(SRC)/%.c, $(OBJ_DIR)/%.o, $(SOURCES))
OBJECTS += $(patsubst $(SRC)/$(ARCHDIR)/*.c, $(OBJ_DIR)/$(ARCHDIR)%.o, $(SOURCES))
OBJ_KEEP = objects_keep
#Headers
HEADERS = $(PROJECT_DIR)/inc
INCLUDE = -I$(HEADERS)
#File settings
KERNEL_NEEDED=kernel8.img
BASE_KERNEL=base_kernel.img
IMG_NAME=edited_reality
$(OBJ_DIR)/%.o: $(SRC)/%.s
mkdir -p $(#D)
#echo COMPILING $^
$(GCCPATHBIN)/aarch64-none-elf-as -c $^ -o $#
$(OBJ_DIR)/%.o: $(SRC)/%.c
mkdir -p $(#D)
#echo COMPILING $^
$(GCCPATHBIN)/aarch64-none-elf-gcc -ffreestanding $(INCLUDE) $(CFLAGS) -c $^ -o $# -O2 -Wall -Wextra
$(OBJ_DIR)/$(ARCHDIR)/%.o: $(SRC)/$(ARCHDIR)/%.c
mkdir -p $(#D)
#echo COMPILING $^
$(GCCPATHBIN)/aarch64-none-elf-gcc -ffreestanding $(INCLUDE) $(CFLAGS) -c $^ -o $# -O2 -Wall -Wextra
BUILD: $(OBJECTS)
mkdir -p $(#D)
#echo COMPILING $^
$(GCCPATHBIN)/aarch64-none-elf-gcc -nostdlib -T linker.ld -o $(IMG_NAME).elf -ffreestanding -O2 -nostdlib $(OBJECTS) $(INCLUDE) -lgcc
$(GCCPATHBIN)/aarch64-none-elf-objcopy $(IMG_NAME).elf -O binary $(KERNEL_NEEDED)
clean:
rm -rf $(OBJ_DIR)
rm -rf $(IMG_NAME).elf
rm -rf $(IMG_NAME).img
start:
#echo Starting
mkdir $(OBJ_DIR)
#echo .
#echo .
#echo .
.PHONY: clean start BUILD
EDIT: I couldn't figure it out so what I'm doing is just writing a one file C++ program that will compile everything else because that is so much easier (for some reason).
Anyways thanks everyone.
It's not clear whether you mean it runs the compiler one time then stops, or whether it runs the compiler many times but always on the same file. When asking for help please cut and paste the command you typed and the output you got (or the useful parts if there's a lot of it), and describe what is wrong and what you wanted to happen.
But, I think this is just a typo:
OBJECTS += $(patsubst $(SRC)/$(ARCHDIR)/*.c, $(OBJ_DIR)/$(ARCHDIR)%.o, $(SOURCES))
Note here you use $(SRC)/$(ARCHDIR)/*.c when you mean $(SRC)/$(ARCHDIR)/%.c.
You can add things like $(info $(OBJECTS)) to see the value of various variables (or run make -p).

`Makefile` rule to regenerate object files directory without recompiling from scratch?

I have the following Makefile which works great but everytime it is recompiling from start evenif nothing has changed.
CXX = g++
CXXFLAGS = -std=c++11
INC_PATH = `pkg-config --cflags ../openCV/build/lib/pkgconfig/opencv.pc` \
`pkg-config --cflags ../SDL2-2.0.8/instDir/lib/pkgconfig/sdl2.pc` \
`pkg-config --cflags ../jsoncpp/build/pkg-config/jsoncpp.pc` \
-I ../poco/instDir/include/
#LIB_PATH = -L../cmake_bin_dir/lib/ ./gainput/build/lib -L../SDL2-2.0.8/build/ -L../SDL2-2.0.8/build/lib
LIBS = `pkg-config --libs ../openCV/build//lib/pkgconfig/opencv.pc` \
`pkg-config --libs ../SDL2-2.0.8/instDir/lib/pkgconfig/sdl2.pc` \
`pkg-config --libs ../jsoncpp/build/pkg-config/jsoncpp.pc` \
-L../poco/instDir/lib/ -lPocoNetd -lPocoUtild -lPocoFoundationd \
SOURCEDIR := ./
SOURCES := $(wildcard $(SOURCEDIR)/*.cpp)
OBJDIR=$(SOURCEDIR)/obj
OBJECTS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.d,$(SOURCES))
# 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: parking
clean:
$(RM) $(OBJECTS) $(DEPENDS) parking
# Linking the executable from the object files
parking: $(OBJECTS)
$(CXX) $(WARNING) $(CXXFLAGS) $(INC_PATH) $^ -o $# $(LIBS)
-include $(DEPENDS)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.cpp Makefile $(OBJDIR)
$(CXX) $(WARNING) $(CXXFLAGS) $(INC_PATH) -MMD -MP -c $< -o $#
The problem seems to be these lines
$(OBJDIR)/%.o: $(SOURCEDIR)/%.cpp Makefile $(OBJDIR)
$(CXX) $(WARNING) $(CXXFLAGS) $(INC_PATH) -MMD -MP -c $< -o $#
and particularly the dependency from $(OBJDIR) (where *.o and *.d files are saved) in fact when I remove it seems not to recompile. The problem is that if I remove the $(OBJDIR), the directory is not regenerated again.
What is the Makefile rule to regenerate the directory where object files are stored without starting all the compilation from scratch?
$(OBJDIR) is a prerequisite of your object files. As with any directory, its last modification time changes every time its content changes... Declare it as an order-only prerequisite instead:
$(OBJDIR)/%.o: $(SOURCEDIR)/%.cpp Makefile | $(OBJDIR)
This way, if it exists already, its last modification time will not be considered by make to decide which targets need to be re-built.

Simplifying a makefile

I have written a scary-looking Makefile by copy/pasting suggestions from Stack Overflow. However, I have read that it might not be necessary to provide explicit compiler invocations so many times (for example, the -O3 flag is everywhere). How can I simplify this Makefile?
CFLAGS = -Weverything -Wno-padded -Wno-unused-parameter -Wno-unused-variable -Wno-sign-conversion
all: fianchetto.o util.o ttable.o movegen.o
clang -O3 $(CFLAGS) -D NDEBUG $^ -o fianchetto
debugf: fianchetto.o ttable.o movegen.o
clang -O3 $(CFLAGS) -g3 $^ -o fianchetto
clean:
rm *.o && rm *.gch & rm fianchetto && rm -rf fianchetto.dSYM
%.o: %.c
clang -O3 -c $(CFLAGS) $< -o $#
fianchetto.o: fianchetto.c
ttable.o: ttable.h ttable.c
movegen.o: movegen.h movegen.c
util.o: util.h util.c
I am mystified by a lot of the syntax, and would appreciate links or explanations of why simplifications work!
CFLAGS and defines (which should be in CPPFLAGS anyway) are useless when linking
You're reinventing make's built-in rules, make will automatically link a target if one of its dependencies is "target.o" (in this case fianchetto: fianchetto.o). Make also knows how to compile C source files (as long as the source and object path match), so your pattern rule is superfluous too.
The object prerequisites aren't necessary as both clang and GCC can generate dependencies for you with the -M set of flags.
Compiling release and debug builds in the same dir makes for a more simple makefile, although you will need to remember to clean the object files when switching.
By default make assigns cc to CC, and cc should be a link to your system's default compiler, so you might not even need the first line below
CC := clang
CPPFLAGS := -MMD -MP
CFLAGS := -Weverything -Wno-padded -Wno-unused-parameter -Wno-unused-variable -Wno-sign-conversion -O3
objs := fianchetto.o util.o ttable.o movegen.o
deps := $(objs:.o=.d)
.PHONY: all debugf clean
all: CPPFLAGS += -DNDEBUG
debugf: CFLAGS += -g3
all debugf: fianchetto
fianchetto: $(objs)
clean: ; $(RM) $(objs) $(deps) fianchetto fianchetto.dSYM
-include $(deps)

gmake compile and link source files in different directories

I'm trying to compile and link several files in different folders using gfortran, and GNU Make 3.81 on a windows machine. I learned how to use wildcards from this reference:
gmake compile all files in a directory
And I want to do something similar to this reference:
Makefiles with source files in different directories
But the difference is that I want to build only one executable in my root directory from the source files in several other directories. I tried reading the make manual:
http://www.gnu.org/software/make/manual/make.html
But it seems primarily directed towards c/c++ programming and non-windows syntax.
My current makefile looks like this:
FC = gfortran
MOD_DIR = "bin"
FCFLAGS = -O0 -Og -Wall -pedantic -fbacktrace -fcheck=all
FCFLAGS += -J$(MOD_DIR) -fopenmp -fimplicit-none -Wuninitialized
TARGET = test
SRCS_C = $(wildcard *.f90) $(TARGET).f90
OBJS_C = $(patsubst %.f90,%.o,$(SRCS_C))
all: $(TARGET)
$(TARGET): $(OBJS_C)
$(FC) -o $# $(FCFLAGS) $(OBJS_C)
$(OBJS_C): $(SRCS_C)
$(FC) $(FCFLAGS) -c $(SRCS_C)
clean:
del *.o $(MOD_DIR)\*.mod
Which works fine when all of my source files are in the root directory. And so I thought this would work:
FC = gfortran
MOD_DIR = "bin"
FCFLAGS = -O0 -Og -Wall -pedantic -fbacktrace -fcheck=all
# FCFLAGS += -J$(MOD_DIR) -I$(INCLUDE_DIR) -fopenmp -fimplicit-none -Wuninitialized
FCFLAGS += -J$(MOD_DIR) -fopenmp -fimplicit-none -Wuninitialized
TARGET = test
SRCS_C =\
"solvers/"$(wildcard *.f90) \
"user/"$(wildcard *.f90) \
$(wildcard *.f90) $(TARGET).f90
OBJS_C = $(patsubst %.f90,%.o,$(SRCS_C))
all: $(TARGET)
$(TARGET): $(OBJS_C)
$(FC) -o $# $(FCFLAGS) $(OBJS_C)
$(OBJS_C): $(SRCS_C)
$(FC) $(FCFLAGS) -c $(SRCS_C)
clean:
del *.o $(MOD_DIR)\*.mod
Where I don't mind just entering the names of the folders where a list of source files can be taken from. I've also tried using -I$(INCLUDE_DIR), but this didn't work either. The error from what I have above is:
gmake: *** No rule to make target `"user/"gridFun.f90', needed by `"user/"gridFu
n.o'. Stop.
Any help is greatly appreciated!
To accomplish what you want with SRCS_C, consider using:
SRCS_C =\
$(wildcard solvers/*.f90) \
$(wildcard user/*.f90) \
$(wildcard *.f90) $(TARGET).f90
Also note that (TARGET).f90 will also be matched by $(wildcard *.f90), in your cases causing test.f90 to be included twice in SRCS_C. You can safely omit $(TARGET).f90 in this example.

Resources