Makefile : No rule to make target (automatic variables) - makefile

I am having trouble with my makefile, i have been reading somme tutoriels on how to make a more re-usable makefile but i am facing this error, and i have been searching for a while now, especially on the GNU make manual and here.
Here is my makefile :
SRC_DIR=./src
BUILD_DIR=./build
OBJS= $(BUILD_DIR)/main.o $(BUILD_DIR)/hamming.o
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c $(SRC_DIR)/%.h
$(CC) -c $< $(CFLAGS) -o $#
$(BUILD_DIR)/main: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
I am having the error :
make: No rule to make target build/main.o', needed bybuild/main'. Stop.
It seems to me that the objects in the variable OBJS are not associated with the %.o pattern rule, but i don't know why.
In my working directory there is : my makefile and the two directories 'src' and 'build'.
Thank you.

I'll go out on a limb and guess that there is no src/main.h. If that's the case, you could fix things this way:
$(BUILD_DIR)/hamming.o: $(BUILD_DIR)/%.o : $(SRC_DIR)/%.h
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) -c $< $(CFLAGS) -o $#
EDIT:
Now I'm puzzled. Please try this (it is crude, but if it works we can refine it):
SRC_DIR=./src
BUILD_DIR=./build
OBJS= $(BUILD_DIR)/main.o $(BUILD_DIR)/hamming.o
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c $(SRC_DIR)/%.h
$(CC) -c $< $(CFLAGS) -o $#
$(BUILD_DIR)/main.o: $(SRC_DIR)/main.c
$(CC) -c $< $(CFLAGS) -o $#
$(BUILD_DIR)/main: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)

Here is a little documentation I put together for NMake a while back I hope it helps. Are you sure there are only tabs before the commands. You can't have spaces that is the number one error I have seen in the past.

Related

GNU make pattern rule when .c files in different directory

I can write pattern rules like that to compile .cfiles to .ofiles.
%.o:%.c
$(CC) -c $< $(CFLAGS) -o $#
But it seems that this method will only work when all the c file are in the same directory.
If my project's struct is like this
|-folder1
|----a.c
|----b.c
|-folder2
|----c.c
|----d.c
|Makefile
I have to change my Makefile to this
%.o:folder1/%.c
$(CC) -c $< $(CFLAGS) -o $#
%.o:folder2/%.c
$(CC) -c $< $(CFLAGS) -o $#
If i have a lot of folders, I think repeating code like this is not the correct way to solve the problem.
Anyone has better solutions?

Understanding deeply using a specific case how makefiles are interpreted

I'm trying to understand deeply how makefiles work.
For example, I've the following one:
CC = gcc
CFLAGS = -I.
DEPS = int_array.h
OBJS = int_array.o test_int_array.o
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
clean:
rm -rf *.o test_int_array *.dSYM
The part that I really don't understand fully is :
...
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
...
I know that the option -c basically indicates just to run the preprocessor, compiling and assembling steps (i.e. without producing executables, I guess).
-o means to write the output to the specified file. Which file in this case?
I understood that $# (and $^ for right) is apparently referring to a "left" side, but which one? Is it referring, in the first case, to the left side of :, that is %.o?
What does $< mean?
Could you please explain step by step how the make tool would interpret those two statements?
I think I understood this part more or less:
...
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
...
which should mean produce an executable called "test_int_array" (which basically is indicated by these options -o $# from the $(OBJS) files on the right (stated using the option $^).
Is $(CFLAGS) needed in both cases? Does the order matter?
In the example:
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
$# is the filename of the target for this rule: test_int_array.
$^ is the names of all prerequisites.
This would be whatever is contained in OBJS, so: int_array.o test_int_array.o
In the example:
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
$< is the name of the first prerequisite: %.c
$# is the filename of the target for this rule: %.o
$(CFLAGS) is not needed for linking, since it only includes the flag -I. Also the CFLAGS indicates that the flags are used for compiling only, hence C FLAGS.
In a Makefile, each rule follows this format:
resulting_file : source_files
steps to get resulting_file from source_files
What is called respectively lefthand and righthand in a rule is the resulting_file and the source_files.
%.ext : %.ext2
is a pattern rule. It allows your Makefile to automatically create any .ext file it needs if it can find a file at the same path with .ext2.
%.c : %.o
is a pattern rule to obtain your .o files (int_array.o test_int_array.o) from their equivalent .c files (int_array.c test_int_array.c)
This is invoked when you specify that $(OBJS) is needed to build the test_int_array file.
Pattern rules automatically use certain variables, such as $(CFLAGS) so you do not need to manually add it in that rule. You can find a full list of implicitly used variables in pattern rules here: https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_10.html#SEC96
You can find out about $#, $< and $^ and similar here: https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_10.html#SEC101
$#: the entire lefthand
$<: the first file in the righthand
$^: the entire righthand list of files, space separated.

multiple targets build in makefile

Any idea why something like this wouldnt work in makefile ?
all : $(GOAL_DB) $(GOAL)
%.d: %.cpp
$(CC) $(CPPFLAGS_DB) $< > $#
%.o : %.cpp
$(CC) $(FLAGS_DB) $< -o $#
$(GOAL_DB) : $(OFILES)
$(CC) $(LFLAGS_DB) -o $# $^ $(LIBS_DB)
strip $(GOAL_DB)
rm -f *.o *.d
%.d: %.cpp
$(CC) $(CPPFLAGS) $< > $#
%.o : %.cpp
$(CC) $(FLAGS) $< -o $#
$(GOAL) : $(OFILES)
$(CC) $(LFLAGS) -o $# $^ $(LIBS)
strip $(GOAL)
rm -f *.o *.d
I'm just trying to build two different targets using make all , GNU make.
The first target builds fine , but it not creating new objects files for another target.
A makefile is not like a standard program that is executed sequentially. It seems you've made the assumption that new rules appearing before a new target will apply to that target. This is not the case. The makefile is fully evaluated for variables, targets, dependencies, and more, before it starts applying rules.
Make is going to match those $(OFILES) against only one of those %.d: targets, probably the first target pattern it finds.
The reason you are not getting new objects for the other target is that to make it looks like you are building the same set of files twice, thus skipping the second build because it's already complete.
A solution is to use 'target specific variables':
all : $(GOAL_DB) $(GOAL)
$(GOAL): BUILD_FLAGS=$(FLAGS)
$(GOAL): BUILD_CPPFLAGS=$(CPPFLAGS)
$(GOAL): BUILD_OUTDIR=./outdir
$(GOAL): $(OFILES)
$(GOAL_DB): BUILD_FLAGS=$(FLAGS_DB)
$(GOAL_DB): BUILD_CPPFLAGS=$(CPPFLAGS_DB)
$(GOAL_DB): BUILD_OUTDIR=./outdir_db
$(GOAL_DB): $(OFILES)
%.d: %.cpp
mkdir -p $(BUILD_OUTDIR)
$(CC) $(BUILD_CPPFLAGS) $< > $(BUILD_OUTDIR)/$#
%.o : %.cpp
mkdir -p $(BUILD_OUTDIR)
$(CC) $(BUILD_FLAGS) $< -o $(BUILD_OUTDIR)/$#

How to make this Makefile more concise?

I know there are ways to remove duplicates $(CC) $(CFLAGS) $# $^ in Makefile. Can you tell me how to make the Makefile below more concise?
CC=gcc
CFLAGS=-pthread -g -o
all: p1 p2
p1: p1.c
$(CC) $(CFLAGS) $# $^
p2: p2.c
$(CC) $(CFLAGS) $# $^
To make your Makefile more concise, you can write it as follows.
CC=gcc
CFLAGS=-pthread -g -o
all: p1 p2
%: %.c
$(CC) $(CFLAGS) $# $^
Then you can add as many p's as you want on the all: line. As long as you provide pN.c, make will compile them into the corresponding pN.
Yes, you can combine commands "by prerequisite". For example:
CC=gcc
CFLAGS=-O3
INCLS=-I$(BASEDIR)/include
LIBS=$(BASEDIR)/lib/thread.a
OBJS = dotprod_mutex.o dotprod_serial.o
EXEC = dotprod
$(EXEC): $(OBJS)
$(CC) -o $(EXEC) $(OBJS) $(LIBS)
$(OBJS): dotprod.h
$(CC) $(CFLAGS) $(INCLS) -c $*.c
or somesuch -- you'll need to go through the details and make sure those libraries and so on actually make sense.
Note that the phrase $(OBJS): dotprod.h means that $(OBJS): depends on the presence of dotprod.h.
You will want to read the manual to get all the gory details, in particular:
Letting Make deduce commands
Combine by prerequisite
As for tools to automate this stuff, you want automake and autoconf: http://sourceware.org/autobook/

What do $< and $# represent in a Makefile?

Can anybody please explain the meaning of $< and $# in a Makefile?
$< evaluates to the first "prerequisite" in the make rule, and $# evaluates to the "target" in the make rule.
Here's an example:
file.o : file.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $#
In this case, $< will be replaced with file.c and $# will be file.o.
These are more useful in generic rules like this:
%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $#
See this manual for more info.
$# is the target of the current rule.
$< is the name of the first prerequisite ("source") of the current rule.
So for example:
.c.o:
$(CC) -c $(CFLAGS) -o $# $<
This will expand to a command something like:
gcc -c -Wall -o foo.o foo.c
See also the GNU make manual ยง 10.5.3, "Automatic Variables".

Resources