Makefile rule matching - makefile

In my gnu-make-3.81 Makefile, I wish to generate .o files from .s files if there is no .c source files. So I defined the following rules which I have simplified:
all::$(OBJS)
%.s: %.c
$(CC) $(CFLAGS) -o $# -S $<
%.o: %.s
$(CC) $(CFLAGS) -o $# -c $<
With gnu-make-3.81, when there is no .c source files, it will generate .o files using the second rule. But with gnu-make-3.82, there is a error:
make: *** No rule to make target `xxx.c', needed by `xxx.s'. Stop.
How can I make it work like gnu-make-3.81 ?

Related

How to write build target for sources from different paths?

At first, I'm a noobie in makefiles...
I have next targets in my Makefile:
$(BUILD_PATH)/%.o: %.c $(GEN_PATH)/%.c
$(CC) $(FLAGS) $(CFLAGS) $(HEADERS) -c $< -o $#
server: $(BUILD_PATH)/main.o $(BUILD_PATH)/socket.o $(BUILD_PATH)/settings.o $(BUILD_PATH)/options.o
$(CC) -L$(LIB_PATH) -Wl,-rpath=$(LIB_PATH) $(FLAGS) $(CFLAGS) -o $(DIST_PATH)/server $^ $(LDFLAGS)
I specified that object files must be compiled from the current folder and $(GEN_PATH) but it doesn't work and I am getting error:
make: *** No rule to make target '../build/server/options.o', needed by 'server'. Stop.
How can I write this rule right?
P.S. It's not primary question but how can I write my input targets shorter? I tried this variant:
server: $(BUILD_PATH)/%.o
$(CC) -L$(LIB_PATH) -Wl,-rpath=$(LIB_PATH) $(FLAGS) $(CFLAGS) -o $(DIST_PATH)/server $^ $(LDFLAGS)
But it didn't work.

GNU Make reports no rule when dealing with a target under subdirectory with source from another directory

My project's directory is mounted via NFS. From the directory under which it is mounted, I call make -f msh/Makefile cd=msh. (msh is my mount.) cd is a variable in the Makefile that is prepended to source files. This works fine with source files directly under cd. However, if the source files are under a subdirectory within cd, Make fails, saying that there is no rule to make that target. It does not fail if I call Make from within my mount.
This is my Makefile.
CC?=gcc
CFLAGS:=-Wall -Werror -D_POSIX_C_SOURCE=200112L $(CFLAGS)
cd?=.
objects_nix=if/tty.o
objects:=sub.o if.o $(objects_nix)
ifdef SO
CFLAGS+=-fPIC
bin=libmsh.so
else
bin=libmsh.a
endif
.PHONY : clean
$(bin) :
libmsh.a : $(objects)
$(AR) -r -c -s $# $(objects)
libmsh.so : $(objects)
#echo
#echo If you have resumed compilation after not having used the SO flag,
#echo you should run make clean.
#echo
$(LD) $(LDFLAGS) -shared -o $# $(objects)
test : $(cd)/test.c $(bin)
ifdef SO
$(CC) $(CFLAGS) -I$(cd) $(LDFLAGS) -L. -lmsh -Wl,-rpath,. -o $# $(cd)/test.c
else
$(CC) $(CFLAGS) -I$(cd) $(LDFLAGS) -o $# $(cd)/test.c $(bin)
endif
%.o : $(cd)/%.c
$(CC) $(CFLAGS) -c -o $# $<
clean :
rm -f libmsh.so libmsh.a
rm -f $(objects)
rm -f test.o test
I have tried creating another rule for the subdirectory, and this works. But I'd like it to work with only the one rule.
You have told Make how to make a .o file from .c file in $(cd). It does not know how to make a .o file if the .c file in some other directory. You can solve this in various ways, such as:
Add an explicit rule for all directories. You have already done that.
Use VPATH.
Create a Makefile for each directory.

make 'vpath' directive, why isn't it sufficient for this prerequisite?

The following example makefile works as expected, using vpath to find object files and source files. But in the last line, where i tell make about the dependency of one object file on the other, I need to specify the directory $(objd)/ of the prerequisite file, otherwise i get an error (see error message below the code). How come the vpath directive isn't sufficient in the last line?
# Program Name
prog = avpar
#dirs
objd=obj
modd=mod
# extra places to search for prerequisites
vpath %.f90 ../modules
vpath %.o obj/
# etc
FC = gfortran
flags = -I$(modd) -J$(modd) #-fopenmp
obj_files = $(prog).o rw_mod.o
# compile
p$(prog): $(obj_files)
$(FC) $(flags) $^ -o $#
$(objd)/%.o: %.f90
$(FC) $(flags) -c $< -o $#
$(objd)/$(prog).o: $(objd)/rw_mod.o
That is, changing the last line to:
$(objd)/$(prog).o: rw_mod.o
gives the error:
make: *** No rule to make target 'rw_mod.o', needed by 'obj/avpar.o'. Stop.
EDIT
with this form of the last lines it does also work, without the directory specification:
#compile
p$(prog): $(obj_files)
$(FC) $(flags) $^ -o $#
$(objd)/rw_mod.o: rw_mod.f90
$(FC) $(flags) -c $< -o $#
$(objd)/$(prog).o: $(prog).f90 rw_mod.o
$(FC) $(flags) -c $< -o $#
vpath can only be used to find prerequisites that exist.
Makefiles rule 3
Use VPATH to locate the sources from the objects directory, not to locate the objects from the sources directory.
There's no rule that matches rw_mod.o so the rule for obj/avpar.o fails, vpath won't prepend stuff during prerequisite rule lookup, the only way it would work here would be if obj/rw_mod.o already existed.
It's unlikely that rule is correct anyway, why would one object file depend on another?

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.

Passing target name to a dependency in makefile

If I have the following rule in a makefile:
$(OBJ)/%.o: $(SRC)/%.c
$(CC) -c -o $# $< $(CFLAGS)
Every file matching the prefix ./obj/ and sufix .o will have its stem passed to %, so I can provide some dependencies based on its name.
But, suppose I have this kind of rule, which I specify one by one the targets I want:
OBJECTS=abc.o bca.o cba.o
$(OBJECTS): $(SRC)/%.c
$(CC) -c -o $# $< $(CFLAGS)
How do I make the % stem actually work for the current target name make is executing? Just using % doesn't work, neither $#.
Note that I'm trying to write the actual target name to its own dependency. For example, when make is executing the rule for abc.o, it would include $(SRC)/abc.c and just it (something like $(patsubst %.o, $(SRC)/%.c, MAGIC_TARGET_NAME_VARIABLE)).
You can just replace this rule:
$(OBJECTS): $(SRC)/%.c
with:
$(OBJECTS) : %.o : $(SRC)/%.c
You will need to add the $(OBJ) to the -o part of the recipe if you still want them built there:
$(OBJECTS) : %.o : $(SRC)/%.c
$(CC) -c -o $(OBJ)/$# $< $(CFLAGS)
I’m not completely clear on what you’re asking, but I think this accomplishes what you’re trying to do:
OBJECTS=abc.o bca.o cba.o
.PHONY: all
all: $(OBJECTS:%=obj/%)
$(OBJ)/%.o: $(SRC)/%.c
echo $(CC) -c -o $# $< $(CFLAGS)
All .o files are built; each .o file is built using only the .c file corresponding to it; and if you want to refer to the list of all object files or source files in the command for compiling a .o file, then you can reference ${OBJECTS} directly.
If this isn’t what you’re trying to do, you’ll be able to get a better answer by listing the input files you have, the output files you want to make, the input dependencies of each output file, and what compilation command you want to execute for each output file.

Resources