Use make to clean outdated outputs - makefile

Suppose I have a make file with an automatic rule like:
%.o: %.c
gcc -c $(CFLAGS) $< -o $#
And a source file a.c:
int main() {}
Running make will produce a.o. Now if I rename a.c to b.c, and run make again, it produces b.o. Is there some way for me to remove a.o when I delete a.c, without removing all other .o files?
For instance, is there some way I can provide a pattern (*.o, which matches a.o and b.o) and remove from it all generated/skipped files (b.o) to get a.o?

Something like this should work (untested!)
ALL_OBJS := $(wildcard *.o)
WANTED_OBJS := $(addsuffix .o,$(basename $(wildcard *.c)))
.PHONY: clean-orphaned
clean-orphaned:
#rm $(filter-out $(WANTED_OBJS),$(ALL_OBJS))
I would test it by running make -n clean-orphaned or changing rm to echo and carefully checking which objects would be removed.
Personally I wouldn't bother with this, just remove *.o and rebuild. It seems highly unlikely that you rename files so often that rebuilding everything is a serious problem.

Related

no rule make object file

I need help, simply because I need help:
SRC=src/main.c
OBJ_PATH=bin
OBJS := $(addprefix $(OBJ_PATH)/, $(addsuffix .o, $(notdir $(basename $(SRC)))))
all:$(OBJ_PATH)/target.exe
$(OBJ_PATH)/target.exe: $(OBJ_PATH) $(OBJS)
$(CC) $(OBJS) -o $(OBJ_PATH)/target.exe
$(OBJ_PATH):
mkdir -p bin
$(OBJ_PATH)/%.o:%.c
mkdir -p bin
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $#
.PHONY: clean
clean:
rm -f $(OBJ_PATH)/*
when running it gives this:
make: *** No rule to make target 'bin/main.o', needed by 'bin/target.exe'. Stop.
If I leave the objects in the same folder as the c files, it works.
I just need some help, maybe it is something simple that I am not seeing.
Thanks guys.
This is wrong:
$(OBJ_PATH)/%.o: %.c
When make wants to build a file bin/main.o. It matches the target pattern bin/%.o, with a stem of main (the part that matches the %). After replacing the prerequisite pattern %.c with main, make will try to find the prerequisite main.c.
But, that file doesn't exist and make has no idea how to create it. So, that pattern doesn't match and make tries to find a different pattern that will build bin/main.o, but there isn't one, so make says there's no way to build that target.
You need to make your pattern rule:
$(OBJ_PATH)/%.o: src/%.c
so that when make replaces % in the prerequisite pattern it yields src/main.c, which exists, and this will work.
There are other problems with your makefile; for example this is a bad idea:
$(OBJ_PATH)/target.exe: $(OBJ_PATH) $(OBJS)
You never(*) want to use a directory like $(OBJ_PATH) as a simple prerequisite.
Also, this:
OBJS := $(addprefix $(OBJ_PATH)/, $(addsuffix .o, $(notdir $(basename $(SRC)))))
can be more easily written:
OBJS := $(patsubst src/%.c,$(OBJ_PATH)/%.o,$(SRC))
(*) There can indeed be very specific situations where having a directory as a prerequisite can be useful but they are rare and you shouldn't do it unless you fully understand why it's usually not what you want.

Make: wildcard to use all object files

I have a Makefile that looks like this:
CC=cc
CFLAGS=-g -std=c99 -Wfatal-errors
OBJS=$(wildcard *.o)
all: main.o cmdargs.o io.o
$(CC) -o app $(OBJS)
main.o: main.c
$(CC) -c main.c $(CFLAGS)
cmdargs.o: cmdargs.c
$(CC) -c cmdargs.c $(CFLAGS)
io.o: io.c
$(CC) -c io.c $(CFLAGS)
clean:
#rm -rf app $(OBJS)
Whenever I run make all after a clean, there's an error saying
cc -o
undefined reference to `main'
But when I run it a second time everything works as expected. What is wrong with the script, and how can we fix it?
The previous respondents gave good answers but not complete. So let me post one too.
First of all, it is a bad idea to use wildcard in makefiles. It is much better to not be lazy and list your files explicitly.
If you must be lazy, the way to use wildcard is, as shawncorey writes, to use it for sources.
Also, do not have a recipe for phony targets such as all. In your example, the recipe for all will always run, which is inefficient.
CC := gcc
SRCS := $(wildcard *.c)
OBJS := $(SRCS:c=o)
.PHONY: all clean
all: app
app: $(OBJS) Makefile
$(CC) -o $# $(OBJS)
$(OBJS): %.o: %.c Makefile
$(CC) -c $< $(CFLAGS)
clean:
#rm -rf app $(OBJS)
You can automatically create the names of the objects files if you're careful about including all the source files.
# --------------------------------------
# list all source files
CPP_SOURCES := $(wildcard *.cpp)
C_SOURCES := $(wildcard *.c)
# other source files here
# consolidate all sources
SOURCES := $(CPP_SOURCES) $(C_SOURCES)
# --------------------------------------
# list all object files
CPP_OBJECTS := $(CPP_SOURCES:.cpp=.o)
C_OBJECTS := $(C_SOURCES:.c=.o)
# other object files here
# consolidate all objects
OBJECTS := $(CPP_OBJECTS) $(C_OBJECTS)
all:
echo $(SOURCES)
echo $(OBJECTS)
PS: A more compact makefile:
# list all source files
SOURCES := $(wildcard *.cpp) $(wildcard *.c)
# determine all object files
OBJECTS := $(addsuffix .o, $(basename $(notdir $(SOURCES))))
all:
echo $(SOURCES)
echo $(OBJECTS)
The statement
OBJS=$(wildcard *.o)
collects all the *.o files currently in the file system, but it doesn't know about any object files that might be created in the future.
When you run make for the first time, there are no .o files around, so the variable OBJS will be an empty string and the final linking command does not get passed into the command that would tell it which object files to use. But all the other compilation steps are run nevertheless. Upon the second invocation make will skip the compilation phases, because the object files are already there, but because linking failed and the final binary is missing, it will run that step, which will now produce something, because there have been files to collect by the wildcard.
Lesson learned: Don't use file system wildcards in Makefile, it's just causing trouble. Instead learn about implicit rules if you want to save yourself from work.

Why is makefile exhibiting non-deterministic behaviour?

I have a makefile that is trying to do the following: identify all files under the current directory (all sub-directories included) with .c and .s extensions, for each one compile a non-linked object file and put it into a directory. All C files end up in objects/c, all assembly files end up in objects/ass.
The makefile always works as expected on the first execution (all commands are called in the right order) and no errors are produced.
However if I call make again, half of the time i get "nothing to be done for 'all'.". Which is what you would expect, since no files have been modified. But the other half of the time, make is selecting a random assembly file and compiling that file. That is to say,if I keep doing "make" I sometimes compile file1.s sometimes file2.s. and it keeps randomly swapping between the assembly files add infinitum (it never reaches a "nothing to be done") state.
How is make exhibitting non deterministic behaviour?
This is the smallest makefile I could make that reproduces the error:
SRC_C = $(wildcard *.c) $(wildcard **/*.c)
SRC_ASS = $(wildcard *.s) $(wildcard **/*.s)
OBJECTS_C = $(addprefix $(OBJECT_DIR)c/, $(notdir $(SRC_C:.c=.o)))
OBJECTS_ASS = $(addprefix $(OBJECT_DIR)ass/, $(notdir $(SRC_ASS:.s=.o)))
OBJECTS = $(OBJECTS_C) $(OBJECTS_ASS)
OBJECT_DIR = objects/
all: $(OBJECTS)
%/:
mkdir $#
$(OBJECTS_C): $(OBJECT_DIR) $(OBJECT_DIR)c/
arm-none-eabi-gcc -O0 -march=armv8-a $(wildcard */$(#F:.o=.c)) -nostartfiles -c -o $#
$(OBJECTS_ASS): $(OBJECT_DIR) $(OBJECT_DIR)ass/
arm-none-eabi-as -march=armv8-a $(wildcard */$(#F:.o=.s)) -c -o $#
.PHONY: clean
clean:
rm -rf $(OBJECT_DIR)
You have many errors here.
The biggest is a conceptual one: By flattening all your object files into one directory, there's no way to express proper dependencies using pattern rules, so your object files do not really depend on their respective source files. I'd say: just don't do that! Having object directories is fine, but they should mirror the directory structure of the source tree.
Further errors:
directly depending on directories. This will not work as expected, directories should always be order-only dependencies, as already stated in the comments
Make doesn't support recursive wildcards -- if you really need that, you could write your own function or, assuming you're always building on *nix, just call find instead
Pattern rules for creating directories are not the best idea either -- I'd suggest to collect all needed directories in a variable and loop over that.
Stylistic improvements:
Assign variables that don't need deferred evaluation with :=
Assign variables influencing the build process with ?=, so the user can override them at the command line
Use "standard" variables like CC, AS, CROSS_COMPILE
declare all phony targets in .PHONY.
Your Makefile with these changes applied would look like this:
OBJECT_DIR ?= objects
C_OBJECT_DIR ?= $(OBJECT_DIR)/c
AS_OBJECT_DIR ?= $(OBJECT_DIR)/ass
SRC_C:= $(shell find -name \*.c)
SRC_ASS:= $(shell find -name \*.s)
OBJECTS_C:= $(addprefix $(C_OBJECT_DIR)/, $(SRC_C:.c=.o))
OBJECTS_ASS:= $(addprefix $(AS_OBJECT_DIR)/, $(SRC_ASS:.s=.o))
OBJECTS:= $(OBJECTS_C) $(OBJECTS_ASS)
OUTDIRS:= $(sort $(dir $(OBJECTS)))
CROSS_COMPILE ?= arm-none-eabi-
CC ?= gcc
AS ?= as
CFLAGS ?= -O0 -march=armv8-a -nostartfiles
ASFLAGS ?= -march=armv8-a
all: $(OBJECTS)
$(OUTDIRS):
$(foreach _dir,$#,mkdir -p $(_dir);)
$(C_OBJECT_DIR)/%.o: %.c | $(OUTDIRS)
$(CROSS_COMPILE)$(CC) -c -o $# $(CFLAGS) $<
$(AS_OBJECT_DIR)/%.o: %.s | $(OUTDIRS)
$(CROSS_COMPILE)$(AS) -c -o $# $(ASFLAGS) $<
clean:
rm -rf $(OBJECT_DIR)
.PHONY: all clean
Note there is one important thing missing: automatic dependencies. With this Makefile, each object file depends on its respective source file, but completely misses any headers included. For anything other than a simple toy, you should add that, google for "gnu make gcc automatic dependencies" or something similar (not the scope of this question).

Makefile - compile multiple C file at once

This question is different from the one at makefiles - compile all c files at once in the sense that I have one extra requirement: I want to redirect all the object files in a separate directory.
Here is the setup:
I have multiple sources in a directory say src/mylib.
I want the objects files to end up in build/mylib.
Please note also that under mylib there are subdirectories.
The first attempt was as follows:
sources = $(shell find src/ -name ".c")
objects_dirs = $(subst src/, build/, $(dir $(sources)) # This variable is used by the build rule to create directories for objects files prior to compilation
objects = $(subst src/, build/, $(patsubst %.c, %.o, $(sources))) # This variable has the paths to the objects files that will be generated in the build directory
# This is where things aren't working as expected
$(objects): build $(sources)
$(cc) $(cflags) -o $# $(word 2, $^))
build:
$(foreach dir, $(objects_dirs), $(shell mkdir -p $(dir)))
For the makefile above, only one object file was being generated. I guessed this might have something to do with GCC only being able to generate one object file at a time. Regardless of that, checking the values of $# and $(word 2, $^) in the $(objects) target shows that only one file is being considered even though I have multiple files.
So I changed my makefile to the following:
sources = $(shell find src/ -name ".c")
objects = $(subst src/, build/, $(patsubst %.c, %.o, $(sources))) # This variable has the paths to the objects files that will be generated in the build directory
# This works as expected but it appears to me like make is generating all the objects files even though source files did not change. This can be seen by checking the timestamps on new object files after running make again.
$(objects): build $(sources)
$(foreach source, $(sources), $(shell $(cc) $(cflags) -o $(subst src/,build/, $(patsubst %.o,%.c,$(source))) $(source)))
build:
$(foreach dir, $(objects_dirs), $(shell mkdir -p $(dir)))
The second makefile works as expected but objects files are being rebuilt again which defeats another purpose of using make: only recompile those source files that changed from the last compilation.
Hence my question: how does one generate all object files in a separate directory at once (by this I mean perform the compilation of all sources files in one rule) while making sure that if a source file didn't change the associated object file should not be regenerated.
I am not after speeding up compilation. What I seek is one rule that will generate all objects files such that only updated source files should be recompiled.
The last makefile does the job but there is a recompiling of all source files which defeats another purpose of using make: only changed source files should be recompiled.
EDIT
After reading comments, it appears I have not phrased my question properly. As the details of what I have are already present, I leave the question as it is with additional details below.
The second makefile in the source code above does work. But it does only half the job. The build directory effectively mirrors the src directory.
So if I have say a file as src/mylib/point/point.c, I get build/mylib/point/point.o generated. This is the first part.
The second part is that if point.c does not changes, point.o in the build/mylib/point/ directory must not be regenerated. But after checking timestamps on the object file, I can tell that a new object file replaced the old one after running make again. This is not good because for large projects, compilation time remains O(n) with n being the number of source files to compile.
So this question is about how to preserve the second makefile without make regenerating object files.
From what I can gather from comments, I am asking too much from make. But if anyone knows how to make this happen, I leave the question open.
Makefile:
all:
clean:
src_root := src
src_subdirs := foo foo/bar foo/bar/buz
build_root := build
o_suffix := .o
# Build list of sources. Iterate every subfolder from $(src_subdirs) list
# and fetch all existing files with suffixes matching the list.
source_suffixes := .c .cpp .cxx
sources := $(foreach d,$(addprefix $(src_root)/,$(src_subdirs)),$(wildcard $(addprefix $d/*,$(source_suffixes))))
# If src_subdirs make variable is unset, use 'find' command to build list of sources.
# Note that we use the same list of suffixes but tweak them for use with 'find'
ifeq ($(src_subdirs),)
sources := $(shell find $(src_root) -type f $(foreach s,$(source_suffixes),$(if $(findstring $s,$(firstword $(source_suffixes))),,-o) -name '*$s'))
endif
$(info sources=$(sources))
# Build source -> object file mapping.
# We want map $(src_root) -> $(build_root) and copy directory structure
# of source tree but populated with object files.
objects := $(addsuffix $(o_suffix),$(basename $(patsubst $(src_root)%,$(build_root)%,$(sources))))
$(info objects=$(objects))
# Generate rules for every .o file to depend exactly on corresponding source file.
$(foreach s,$(sources),$(foreach o,$(filter %$(basename $(notdir $s)).o,$(objects)),$(info New rule: $o: $s)$(eval $o: $s)))
# This is how we compile sources:
# First check if directory for the target file exists.
# If it doesn't run 'mkdir' command.
$(objects): ; $(if $(wildcard $(#D)),,mkdir -p $(#D) &&) g++ -c $< -o $#
# Compile all sources.
all: $(objects)
clean: ; rm -rf $(build_root)
.PHONY: clean all
Environment:
$ find
.
./src
./src/foo
./src/foo/bar
./src/foo/bar/bar.cxx
./src/foo/bar/buz
./src/foo/bar/buz/buz.c
./src/foo/bar/foo.c
./src/foo/foo.cpp
Run makefile:
$ make -f /cygdrive/c/stackoverflow/Makefile.sample -j
sources=src/foo/bar/bar.cxx src/foo/bar/buz/buz.c src/foo/bar/foo.c src/foo/foo.cpp
objects=build/foo/bar/bar.o build/foo/bar/buz/buz.o build/foo/bar/foo.o build/foo/foo.o
New rule: build/foo/bar/bar.o: src/foo/bar/bar.cxx
New rule: build/foo/bar/buz/buz.o: src/foo/bar/buz/buz.c
New rule: build/foo/bar/foo.o: src/foo/bar/foo.c
New rule: build/foo/foo.o: src/foo/bar/foo.c
New rule: build/foo/bar/foo.o: src/foo/foo.cpp
New rule: build/foo/foo.o: src/foo/foo.cpp
mkdir -p build/foo/bar && g++ -c src/foo/bar/bar.cxx -o build/foo/bar/bar.o
mkdir -p build/foo/bar/buz && g++ -c src/foo/bar/buz/buz.c -o build/foo/bar/buz/buz.o
mkdir -p build/foo/bar && g++ -c src/foo/bar/foo.c -o build/foo/bar/foo.o
mkdir -p build/foo && g++ -c src/foo/bar/foo.c -o build/foo/foo.o
Environment again:
$ find
.
./build
./build/foo
./build/foo/bar
./build/foo/bar/bar.o
./build/foo/bar/buz
./build/foo/bar/buz/buz.o
./build/foo/bar/foo.o
./build/foo/foo.o
./src
./src/foo
./src/foo/bar
./src/foo/bar/bar.cxx
./src/foo/bar/buz
./src/foo/bar/buz/buz.c
./src/foo/bar/foo.c
./src/foo/foo.cpp
Try running this Makefile with 'src_subdirs=' to exercise another approach to locate sources. Output should be the same.
I finally had some time to experiment with this, so here is what I came up with:
BUILD_DIR = build
SRC_DIR = src
SOURCES = $(shell find $(SRC_DIR)/ -name "*.c")
TARGET = program
OBJECTS = $(SOURCES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
default: $(TARGET)
.SECONDEXPANSION:
$(OBJECTS) : $$(patsubst $(BUILD_DIR)/%.o,$(SRC_DIR)/%.c,$$#)
mkdir -p $(#D)
$(CC) -c -o $# $(CFLAGS) $<
$(TARGET): $(OBJECTS)
$(CC) -o $# $(CFLAGS) $^
.PHONY: default
Points of interest:
I had to change the sources find pattern from ".c" to "*.c", I'm not sure if it depends on the exact shell used, but if you want to stay portable, be sure to use a widely accepted pattern.
The .SECONDEXPANSION: is needed to enable the $$ rules for GNU Make. It is needed to allow target based substitution rules in the prerequisites for the $(OBJECTS).
The prerequisite $$(patsubst $(BUILD_DIR)/%.o,$(SRC_DIR)/%.c,$$#) is saying, that the current target depends on a specific source file with the same folder structure and name.
The command mkdir -p $(#D) is ensuring, that the path of the current target is created if it's missing.
If all you want is a single rule to handle all object files, without necessarily needing to "compile all at once" then you could have something like this:
BUILD_DIR = build
SOURCES = ...
TARGET = ...
OBJECTS = $(SOURCES:%.c=$(BUILD_DIR)/%.o)
default: target
target: $(TARGET)
$(TARGET): $(OBJECTS)
$(LD) -o $# $(LDFLAGS) $^ $(LIBS)
$(BUILD_DIR)/%.o: %.c
$(CC) -c -o $# $< $(CFLAGS)
$(BUILD_DIR):
-mkdir $#
[Note: This is written from memory and without testing.]
After reading the GNU make manual again, here is a solution that solves the second problem.
The first attempt was the correct path. And the second attempt has the $(sources) in the prerequisites but does not use it in the commands and this is silly.
So the working makefile follows. It puts object files in a separate directory and it only compiles files that have changed.
sources = $(shell find src/ -name ".c")
$objects_dirs = $(subst src/, build/, $(dir $(sources)) # This variable is used by the build rule to create directories for objects files prior to compilation
objects = $(subst src/, build/, $(patsubst %.c, %.o, $(sources))) # This variable has the paths to the objects files that will be generated in the build directory
# This should now work as expected: object files go into their designated directories under "build/" and only updated files will be recompiled.
$(objects): build $(sources)
# After running say "make clean", make will figure out the need to run the first prerequisite.
# If we are doing a clean build, the number of prerequisites will equal the number of new prerequisites.
ifeq ($(words $?), $(words $^))
# Note the use of "$?" instead of "$^". $? is used since it holds prerequisites that are newer than the target while $^ will holds all prerequisites whether they are new or not.
$(foreach source, $(wordlist 2, $(words $?), $?), $(shell $(cc) $(cflags) -o $(subst src/,build, $(patsubst %.c,%.o, $(source))) $(source)))
else
# If we have a few new targets, no need to exclude "build" from prerequisites because the first prerequisite will be a file that changed.
$(foreach source, $?, $(shell $(cc) $(cflags) -o $(subst src/,build, $(patsubst %.c,%.o, $(source))) $(source)))
endif
.PHONY: build
build:
$(foreach dir, $(objects_dirs), $(shell mkdir -p $(dir)))
.PHONY: clean
clean:
#rm -rf build/
The makefile is heavily commented with changes that made it work. The most important changes were:
Use of $(foreach) to compile each file individually as required by GCC
Use of $? to work only with prerequisites that are newer than the target
Use of conditional to detected whether the first prerequisite has changed depending on circumstances. If we have a clean build (running make for the first time or after running make clean), the number of updated prerequisites will be the same as the number of newer prerequisites compared to the target. In other words $(words $?) == $(words $^) will be true. So we use this fact to exclude the firs prerequisite listed (build in our case) from the list of files to pass to GCC.
Also, when building the executable from the objects files, make sure to use $^ and not $? when selecting prerequisites else you will end up with only newer files in the executable and it will not run.
target = bin/mylib.a
.PHONY: all
all: $(target)
$(target): $(objects)
ar -cvq $# $^ # Notice that we're not using $? else only updated object files will end up in the archive.

Makefile Dynamic Rules w/ No GNU-make Pattern

I have a set of .cpp files that I want to compile. These .cpp files are in a hierarchical directory structure. I want the corresponding .o files to all end up in one build folder.
Here's how I get GNU make to enumerate the files:
SRCS = \
$(wildcard $(CODE)/**/*.cpp) \
$(wildcard $(CODE)/AlgebraLibraries/**/*.cpp) \
$(wildcard $(CODE)/Calculator/Environments/**/*.cpp)
BARE_SRCS = $(notdir $(SRCS))
BARE_OBJS = $(BARE_SRCS:.cpp=.o)
OBJS = $(addprefix $(BUILD)/, $(BARE_OBJS))
Having done this, I have no idea how to create the rules that will create the .o files from the .cpp files. Intuitively, what I want to do is the following pseudocode:
for i=0, N do # <-- a for-loop!
$(OBJS)[i]: $(SRCS)[i] # <-- the rule!
$(CPP) -c $(SRCS)[i] -o $(OBJS)[i] # <-- the recipe
end
Of course, this is not valid GNU make code, but I trust you understand what it is here that I'm trying to do. The following will not work.
%.o: %.cpp
$(CPP) -c $< -o $#
This doesn't work, because GNU make is matching up the % signs, assuming that the .o files live along-side the .cpp files.
The alternative to all of this, which I know will work, but will be extremely tedious, is to enumerate all of the rules by-hand as explicit rules. There has to be a better way!
I've been researching GNU make's ability to generate rules, but there appears to be no way to do it without the built-in logic. It would be really nice if I could utilize some flow-control statements to generate the rules that I want to make. Is this asking too much of GNU-make?
In any case, is there a way to do what it is I'm trying to do with GNU make? If so, how?
This looks like a job for... several advanced Make tricks:
all: $(OBJS)
define ruletemp
$(patsubst %.cpp, $(BUILD)/%.o, $(notdir $(1))): $(1)
$$(CPP) -c $$< -o $$#
endef
$(foreach src,$(SRCS),$(eval $(call ruletemp, $(src))))
If $(BUILD) is constant, you can always just do:
$(BUILD)/%.o: %.cpp
$(CPP) -c $< -o $#

Resources