Force make to look at files before conclude to a circular dependency - makefile

I have a circular dependency using make:
CC = gcc
IFLAGS = -Iinclude
CFLAGS = -Wall -g -c -fPIC -pedantic
AFLAGS = -shared
LFLAGS =
VERSION = $(shell cat desc/major).$(shell cat desc/minor).$(shell cat desc/patch)
DFLAGS = -D_XOPEN_SOURCE=700 -DLTKVER=\"$(VERSION)\"
OBJECTS = $(patsubst src/%.c,tmp/%.o, $(shell ls -1 src/*.c))
#OUTPUT = tmp/$(lastword $(subst /, ,$(shell pwd)))
OUT_BIN = install/usr/lib/libLTK.so
OUT_MAN = $(patsubst man/%,install/usr/share/man/%.gz, $(shell find man -type f))
PATH_INCLUDE = install/usr/include/LTK-$(VERSION)
OUT_INCLUDE = $(patsubst %,$(PATH_INCLUDE)/%, $(shell find include -type f -printf "%f\n"))
PC = %
all: $(OUT_BIN) $(OUT_MAN) $(OUT_INCLUDE)
# chmod 755 install/usr/lib/libLTK.so.$(VERSION)
ln -sf install/usr/lib/libLTK.so.$(VERSION) install/usr/lib/libLTK.so
# chmod 755 install/usr/include/LTK-$(VERSION)
# chmod 644 install/usr/include/LTK-$(VERSION)/*
ln -sf install/usr/include/LTK-$(VERSION) install/usr/include/LTK
$(OUT_BIN): $(OBJECTS)
mkdir -p $(shell dirname $#)
$(CC) $(AFLAGS) -o $#.$(VERSION) $^ $(LFLAGS)
tmp/%.o : src/%.c
mkdir -p $(shell dirname $#)
$(CC) $(CFLAGS) -o $# $< $(DFLAGS) $(IFLAGS)
install/usr/share/%.gz : %
mkdir -p $(shell dirname $#)
gzip -c $< > $#
.SECONDEXPANSION:
%.h : $$(patsubst $(PATH_INCLUDE)/$$(PC),include/$$(PC),$$#)
mkdir -p $(shell dirname $$#)
cp $< $$#
clean:
rm -rf tmp install
At second expansion header files, prerequisites are generated from second expansions.
But it's a header that generates another and this new one can be found on the disk.
But make rather prefers to consider a circular dependency and ignore it.
How can I force make to see that the file exists before it searches a target to generate it?

Circular dependences are completely independent of what exists on the disk or doesn't exist on the disk. When make runs it parses the makefile and constructs a graph representing the dependency relationship between targets. This graph must be acyclic, because make will walk the graph looking for whether targets are out of date. If there's a cycle in the graph, then make would recurse forever trying to walk the graph.
For example:
a: b ; touch $#
b: a ; touch $#
It doesn't matter whether these files exist or not: make still needs to be sure that "a" is newer than "b" to satisfy the first dependency, and that "b" is newer than "a" to satisfy the second dependency.
This cannot ever be true, obviously.

Finally resolved by substituing $(OUT_INCLUDE) to %.h.
The goal to auto copy include files is preserved.
Substitued this:
.SECONDEXPANSION:
$(OUT_INCLUDE) : $$(patsubst $(PATH_INCLUDE)/$$(PERCENT),include/$$(PERCENT),$$#)
mkdir -p $(shell dirname $#)
cp $< $#
For this:
.SECONDEXPANSION:
%.h : $$(patsubst $(PATH_INCLUDE)/$$(PC),include/$$(PC),$$#)
mkdir -p $(shell dirname $$#)
cp $< $$#
But I'm still asking myself on "is there anything to force file before dependency".
After looking at the code it looks like no, unless I omit something.

Related

Makefile does not find rules despire of available files

Currently I am trying to get a rather big project of mine to work with a Makefile. I used Make before but in a rather crude way and not really "dynamic", this means I am pretty new to good Makefiles.
My Makefile looks like this:
INCLUDE_DIR = /inc
SOURCE_DIR = /src
BUILD_DIR = /build
BUILD_NAME = build
CC = arm-none-eabi-gcc
CFLAGS = -I$(INCLUDE_DIR)
_INCLUDES = main.h pfc.h
INCLUDES = $(patsubst %, $(INCLUDE_DIR)/%, $(_INCLUDES))
_OBJ = main.o pfc.o
OBJ = $(patsubst %, $(BUILD_DIR)/%, $(_OBJ))
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c $(INCLUDES)
$(CC) -c -o $# $< $(CFLAGS)
$(BUILD_NAME): $(OBJ)
$(CC) -o $# $^ $(CFLAGS)
all: $(BUILD_NAME)
.PHONY: clean
clean:
rm -rf $(BUILD_DIR)/*
When I make the file I get this:
make: *** No rule to make target '/build/main.o', needed by 'build'. Stop.
I guess it is an error in this recipe:
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c $(INCLUDES)
$(CC) -c -o $# $< $(CFLAGS)
Sadly I am not able to get this done on my own.
All files a available in the correct folders.
I really appreciate all the help!
Tristan
You have a few issues here that I can see. But first off - just check (just incase) that all your rules are only indented with tabs and not spaces..... this can be a real "silent" killer of makefiles as they give crap error messages.
Ok so - lets assume you have:
INCLUDE_DIR = inc
SOURCE_DIR = src
BUILD_DIR = build
instead of /src etc.. as mentioned in the comments.
Do you really have inc/main.h and inc/pfc.h?
I copied and pasted your makefile added your src and inc folders (but I used gcc instead of arm-none-eabi-gcc. It did the compile lines correctly, but failed at the linker stage because you are trying to build an output file called build when there is already a folder called build (not allowed in linux - maybe ok for windows but I don't recommend).
I made an answer for another question - but it might be a better start point then you have here in the case where you have nested src/inc directories and you want to be able to clean your output folders - ill put it here for convenience:
# Get your source list (use wildcard or what ever, but just for clarity you should end up with a list of files with full paths to start with):
# Output folders/targets
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
OUTPUT_FILE = output
# Generate list of source files - this is a linux command - but you can do this in pure make using wildcard and such).
SOURCES := $(shell find $(SOURCEDIR) -name '*.c')
# Create your objects list in the obj directory
OBJECTS = $(addprefix $(OBJ_DIR)/,$(addsuffix .o,$(basename $(SOURCES))))
# Create list of unique folders to create
DIRS = $(sort $(dir $(OBJECTS))) $(BIN_DIR)
# Create list of include paths
INCS = $(addprefix -I,$(sort $(dir $(SOURCES))))
# Main target rule
$(BIN_DIR)/$(OUTPUT_FILE): $(OBJECTS) | $(DIRS)
#echo linker: gcc $(OBJECTS) -o $#
#touch $#
# Rule to build your object file - ensure that the folders are created first (also create a dummy obj file) - note this works for parallel builds too (make -j
$(OBJ_DIR)/%.o: %.c | $(DIRS)
#echo compile: gcc $(INCS) -c $? -o $#
#touch $#
# Create your directories here
$(DIRS):
#echo Creating dir: $#
#mkdir -p $#
# Clean if needed
.PHONY: clean
clean:
rm -rf $(OBJ_DIR) $(BIN_DIR)
Note this is just a template, you still need to fill in the gcc/makefile flags - but its a decent start point...
Debugging
$(info ...) is your friend - for example you could do:
$(info OBJ = $(OBJ))
$(info objrule = $(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c $(INCLUDES))
To print our what make has expanded these variables / lines to be - this can yield useful debug.
Here is another version of your makefile with automatic dependency generation:
INCLUDE_DIR := inc
SOURCE_DIR := src
BUILD_DIR := build
CC := arm-none-eabi-gcc
CPPFLAGS := -I$(INCLUDE_DIR)
exes := build
build.obj := main.o pfc.o
all : ${exes:%=${BUILD_DIR}/%}
.SECONDEXPANSION:
${BUILD_DIR}:
mkdir -p $#
# Rule to link all exes.
${exes:%=${BUILD_DIR}/%} : ${BUILD_DIR}/% : $$(addprefix ${BUILD_DIR}/,$${$$*.obj}) | $${#D}
${CC} -o $# ${LDFLAGS} $^ ${LDLIBS}
# Rule to compile C sources. And generate header dependencies.
${BUILD_DIR}/%.o : ${SOURCE_DIR}/%.c | $${#D}
${CC} -o $# -c ${CPPFLAGS} ${CFLAGS} -MD -MP $<
# Include automatically generated header dependencies.
ifneq ($(MAKECMDGOALS),clean)
-include $(foreach exe,${exes},$(patsubst %.o,${BUILD_DIR}/%.d,${${exe}.obj}))
endif
clean:
rm -rf $(BUILD_DIR)
.PHONY: all clean
To add another executable target do:
exes += another
another.obj := another_main.o another_pfc.o

Makefile to auto compile, assemble and link many files in a directory

Sorry for repetition, but I could not find the solution.
Following is the sequence of the commands I want Makefile to accomplish.
gcc-elf-gcc -S -combine loadStoreByte.c string.c lib_uart.c bubble_uart.c -o bubble_uart.s
gcc-elf-as -o startup.o startup.s;
gcc-elf-as -o handler.o handler.s;
gcc-elf-as -o bubble_uart.o bubble_uart.s;
gcc-elf-ld -o bubble_uart -T browtb.x bubble_uart.o startup.o handler.o;
That is, I want to compile all C files into a single S file and then assemeble all s files into corresponding object files and the link all object files into one executable.
I tried the following makefile. The individual targets work fine, but could not run all the target at the same time using "make all".
Please guide how to fix it.
CC = brownie32-elf-gcc
AS = brownie32-elf-as
LK = brownie32-elf-ld
SFILE = $(wildcard *.s)
OFILE = $(patsubst %.s,%,$(SFILE))
CFILE = $(wildcard *.c)
OBJ = $(wildcard *.o)
APP = bubble_uart
all: compile assemble link
link: $(OBJ)
$(LK) -o $(APP) -T browtb.x $^
assemble: $(OFILE)
%: %.s compile
$(AS) -o $#.o $<
compile: $(CFILE)
$(CC) -S -combine $^ -o $(APP).s
clean:
rm -f $(OBJ) $(APP) $(APP).s *.o
Thanks
Your makefile is not written with "best practices" and because of that it was easy for you to make mistakes. I will re-write your makefile here, with best practices, which solves all your problems. Please study it with the aid of the GNU Make manual.
The biggest single problem is that you have "procedures/actions", such as "assemble" as make targets. This makes the makefile into a kind of "procedural" program. GNU Make is not designed to be a procedural language, instead, it is a declarative language. The "targets" should not be actions, but actual files, or "phony" files, which should be collections of actual files.
The use of wildcard in makefiles is a bad idea - it is best to list your files explicitly, as I have shown.
Please consult my answer
makefile enforce library dependency ordering
for a discussion of good practices, including phony and real targets.
MAKEFILE := $(lastword $(MAKEFILE_LIST))
CFILES := \
loadStoreByte.c \
string.c \
lib_uart.c \
bubble_uart.c
SFILE_OUTPUT := bubble_uart.s
SFILES := $(SFILE_OUTPUT) \
startup.s \
handler.s
OFILES := $(SFILES:s=o)
APP := bubble_uart
.PHONY: all
all: $(APP)
$(APP): browtb.x $(OFILES) $(MAKEFILE)
gcc-elf-ld -o $# -T $< $(OFILES)
$(OFILES): %o : %s $(MAKEFILE)
gcc-elf-as -o $# $<
$(SFILE_OUTPUT): $(CFILES) $(MAKEFILE)
gcc-elf-gcc -S -combine $(CFILES) -o $#
It is usually best if the target of a rule is the name of the file the rule produces.
So the compile rule:
compile: $(CFILE)
$(CC) -S -combine $^ -o $(APP).s
should be this:
$(APP).s: $(CFILE)
$(CC) -S -combine $^ -o $#
Likewise the object rule:
%: %.s compile
$(AS) -o $#.o $<
should be this:
%.o: %.s
$(AS) -o $# $<
(There's no reason for it to depend on compile or $(APP).s, since bubble_uart.s is irrelevant to most object files.)
Then the list of object files should include bubble_uart.o:
SFILES = $(sort $(wildcard *.s) $(APP).s)
OFILES = $(patsubst %.s,%.o,$(SFILES))
(The sort is to remove duplicates.) Note that this is the list of object files needed for construction of the executable, not the list of object files that happen to exist at the beginning of the build process.
Finally, the executable:
$(APP): $(OFILES)
$(LK) -o $# -T browtb.x $^

Depend on subdirectory creation in makefile rule

I have a project with sources in the src/ directory and its subdirectories (e.g. src/foo/ and src/bar/), and the objects in the obj directory and the matching subdirectories (e.g. obj/foo/ and obj/bar/).
I use the following (smimplified) Makefile:
SOURCES=$(shell find src/ -type f -name '*.c')
OBJECTS=$(patsubst src/%.c,obj/%.o,$(SOURCES))
all: $(OBJECTS)
obj/%.o: src/%.c
gcc -c $< -o $#
The problem
The problem is that if obj/ or one of its subdirectories doesn't exist, I get the following error:
Fatal error: can't create obj/foo/f1.o: No such file or directory
How can I tell make that %.o files depend on the creation of their containing directory?
What I tried
One solution when there are no subdirectories is to use "order only prerequisites":
$(OBJECTS): | obj
obj:
mkdir $#
But that fixes the problem only with obj/, but not obj/foo and obj/bar/. I thought about using $(#D), but I don't know how to get all this together.
I have also used hidden marker files in each directory, but that's just a hack, and I have also put a mkdir -p just before the GCC command but that also feels hacky. I'd rather avoid using recursive makefiles, if that were a potential solution.
Minimal example
To create a minimal project similar to mine you can run:
mkdir /tmp/makefile-test
cd /tmp/makefile-test
mkdir src/ src/foo/ src/bar/
echo "int main() { return 0; }" > src/main.c
touch src/foo/f1.c src/bar/b1.c src/bar/b2.c
I don't know why you consider adding mkdir -p before each compiler operation to be "hacky"; that's probably what I'd do. However, you can also do it like this if you don't mind all the directories created all the time:
First, you should use := for assigning shell variables, not =. The former is far more efficient. Second, once you have a list of filenames it's easy to compute the list of directories. Try this:
SOURCES := $(shell find src/ -type f -name '*.c')
OBJECTS := $(patsubst src/%.c,obj/%.o,$(SOURCES))
# Compute the obj directories
OBJDIRS := $(sort $(dir $(OBJECTS))
# Create all the obj directories
__dummy := $(shell mkdir -p $(OBJDIRS))
If you really want to have the directory created only when the object is about to be, then you'll have to use second expansion (not tested):
SOURCES := $(shell find src/ -type f -name '*.c')
OBJECTS := $(patsubst src/%.c,obj/%.o,$(SOURCES))
# Compute the obj directories
OBJDIRS := $(sort $(dir $(OBJECTS))
.SECONDEXPANSION:
obj/%.o : src/%.c | $$(#D)
$(CC) -c $< -o $#
$(OBJDIRS):
mkdir -p $#
I'd do it this way:
SOURCES=$(shell find src -type f -name '*.c') # corrected small error
...
obj/%.o: src/%.c
if [ ! -d $(dir $#) ]; then mkdir -p $(dir $#); fi
gcc -c $< -o $#

Make says "missing separator" for source .c file from CuTest

I'm trying to get started with CuTest to do unit testing in C.
When make-ing, I get the following error:
dev:~/bistro# make
cutest/CuTest.c:10: *** missing separator. Stop.
The file cutest/CuTest.c comes directly from the library. I have done no mods to it. Here are the concerned lines:
08 - #include "CuTest.h"
09 -
10 - /*-------------------------------------------------------------------------*
11 - * CuStr
12 - *-------------------------------------------------------------------------*/
13 -
14 - char* CuStrAlloc(int size)
Here's the Makefile I'm using, for complete reference:
NAME = bistro
SOURCES_DIR = src
OBJECTS_DIR = obj
SOURCES = $(shell find $(SOURCES_DIR) -type f -name *.c) cutest/CuTest.c
OBJECTS = $(patsubst $(SOURCES_DIR)/%.c, $(OBJECTS_DIR)/%.o, $(SOURCES))
DEPS = $(OBJECTS:.o=.d)
CFLAGS = -Wall -Werror -Wextra
COMPILER = gcc -I cutest -I $(SOURCES_DIR) $(CFLAGS)
BISTRO_MAIN = $(OBJECTS_DIR)/bistro/bistro_main.o
.PHONY: test all clean fclean re
all: $(NAME)
# header dependencies
-include $(DEPS)
$(NAME): $(OBJECTS)
$(COMPILER) -o $(NAME) $(OBJECTS)
test: $(filter-out $(BISTRO_MAIN), $(OBJECTS))
$(COMPILER) -c all_tests.c -o all_tests.o
$(COMPILER) -o test $(filter-out $(BISTRO_MAIN), $(OBJECTS)) all_tests.o
rm -f all_tests.o
$(OBJECTS_DIR)/%.o: $(SOURCES_DIR)/%.c
#if [ ! -d "$(#D)" ]; then mkdir -p $(#D); fi
$(COMPILER) -MMD -c $< -o $#
clean:
rm -Rf $(OBJECTS_DIR)/*
fclean: clean
rm -f $(NAME)
re: fclean all
What could be the cause of this error message?
EDIT 1: The makefile is indented with 4-space tabs only. Could the call to the "find" command be the cause of that? Also, how come the error says the missing separator is in the .c file?
EDIT 2: The accepted answer shows the error. In addition, the call did not work because it was searching for *.c, which should be "*.c".
It means you are using (four) spaces instead of tab symbol.
Make target's command must be indented with a tab.
See http://www.gnu.org/software/make/manual/make.html#Rule-Introduction:
Please note: you need to put a tab character at the beginning of every recipe line! This is an obscurity that catches the unwary. If you prefer to prefix your recipes with a character other than tab, you can set the .RECIPEPREFIX variable to an alternate character
Your error comes because you include a C source file into Makefile.
SOURCES = $(shell find $(SOURCES_DIR) -type f -name *.c) cutest/CuTest.c
OBJECTS = $(patsubst $(SOURCES_DIR)/%.c, $(OBJECTS_DIR)/%.o, $(SOURCES)) # cutest/CuTest.c stays cutest/CuTest.c
DEPS = $(OBJECTS:.o=.d)
-include $(DEPS) # oops, includes cutest/CuTest.c

Makefile adds itself as target

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)

Resources