Force make not to re-order pre-requisites in automatic variable expansion - makefile

Here a is my makefile (GNU make) to compile a small OCaml program:
SUFFIXES:=
OCAML=ocamlopt
LD=ocamlopt
OFLAGS=
.PHONY: all clean
all: playground
playground.cmx: playground.ml lstream.cmi
playground: lstream.cmx playground.cmx
%.cmi: %.ml
$(OCAML) $(OFLAGS) -c $<
%.cmx: %.ml
$(OCAML) $(OFLAGS) -c $<
%: %.cmx
$(LD) -o $# $^
playground uses functions from the Lstream module. In this case, the ocaml linker requires the files to link to be specified in order of dependency (eg: ocamlopt -o playground lstream.cmx playground.cmx).
Despite the fact that I defined the playground rule's dependencies in the right order,
make consistently re-orders them and executes ocamlopt -o playground playground.cmx lstream.cmx which causes a linker error.
Is there a way to enforce the correct behaviour ? I would like to avoid specifying the link command explicitely and let make infer it from the dependencies.

Implicit rules always force the pattern matching prerequisite to be first, regardless of the order in which they're defined elsewhere. This is almost always what you want, because in most rules the pattern matching prerequisite is special.
For example when compiling an object file the prerequisites consist of one source file and a bunch of header files; the source file is special and needs to be listed on the command line. Make ensures that for a pattern rule %.o : %.c (for example) the prerequisite matching %.c is first in the list, and so is assigned to the $< automatic variable, and it can be treated differently.
In any event the short answer is no, you cannot modify this behavior. An implicit rule % : %.cmx matching a target playground will always force the prerequisite playground.cmx to be listed first in the prerequisite list. The other prerequisites will maintain their order.
If you really need the prerequisites to maintain their order then I recommend using a static pattern rule:
TARGETS = playground
$(TARGETS) : % :
$(LD) -o $# $^
(you can also use a "match anything" pattern rule but this can be a real performance degrader). Here since you have no pattern in the prerequisite list, nothing will be reordered.

Related

Can I add object files as dependency?

I have a makefile for multiple mains
info ::
#echo "make main1/2/3"
PROGS = main1 main2 main3
.SECONDEXPANSION:
${PROGS} :: $$#.o
${CC} -o $# $^
but one (and only one) main needs another object linked in. I tried solving that with
main3 :: lib.o
but somehow lib.o is not added to the list of prerequisites.
The ordering of the link lines makes a difference.
I add that main3 line after the PROGS link line, then that one bombs because of the missing object file.
If I add it before the PROGS line, then the custom line is executed first with a default rule, which I don't want, and then the PROGS rule is executed anyway, and it bombs.
Is there a way to use macros such as $^ for objects linking? I can of course split out main3 from the PROGS macro, but that macro is used for a bunch of other purposes too.
You are using double-colon rules in a case which doesn't seem to call for them. From the manual:
Double-colon rules with the same target are in fact completely separate from one another. Each double-colon rule is processed individually, just as rules with different targets are processed.
If you want different rules for the same target to combine (as you seem to want for main3), just switch to ordinary (single-colon) rules:
.SECONDEXPANSION:
${PROGS} : $$#.o
${CC} -o $# $^
main3 : lib.o
And you can make your ${PROGS} rule less complicated by turning it into a static pattern rule:
${PROGS} : % : %.o
${CC} -o $# $^

Make removes files as intermediate

When trying to organize the compilation output into a build directory, make keeps removing object files. The Makefile is:
MPI_INSTALLATION=/home/gkaf/Software/MPI
IDIR=$(MPI_INSTALLATION)/include
LDIR=$(MPI_INSTALLATION)/lib
CC=gcc
CFLAGS=-I$(IDIR)
LDFLAGS=-L$(LDIR) -Wl,-rpath=$(LDIR)
BUILD_DIR=build
OBJ_DIR=$(BUILD_DIR)/obj
BIN_DIR=$(BUILD_DIR)/bin
SRC_DIR=src
LIBS=-lmpi
.PHONY: all
all: test-mpi
.PHONY: test-mpi
test-mpi: prepare $(BIN_DIR)/test-mpi
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) -c -o $# $< $(CFLAGS)
$(BIN_DIR)/%: $(OBJ_DIR)/%.o
$(CC) -o $# $^ $(LDFLAGS) $(LIBS)
prepare: $(BUILD_DIR) $(OBJ_DIR) $(BIN_DIR)
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
$(OBJ_DIR):
mkdir -p $(OBJ_DIR)
$(BIN_DIR):
mkdir -p $(BIN_DIR)
.PHONY: clean
clean:
rm -rf $(BUILD_DIR)
The object file build/obj/test-mpi.o generated during the compilation is deleted after the executable build/bin/test-mpi is created.
I believe that make treats build/obj/test-mpi.o as an intermediate file. However, I was expecting that build/obj/test-mpi.o would not be treated as an intermediate file since it appears explicitly in the target $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c and gnu make documentation states that "ordinarily, a file cannot be intermediate if it is mentioned in the makefile as a target or prerequisite".
This behavior has been reported in a similar issue, but I believe that in both cases the files should not be treated as intermediate since they appear in a target. Am I missing something?
I believe that make treats build/obj/test-mpi.o as an intermediate file.
Yes, that looks right.
However, I was expecting that build/obj/test-mpi.o would not be treated as an intermediate file since it appears explicitly in the target $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c [...]
Given that $(OBJ_DIR) expands to build/obj, the pattern $(OBJ_DIR)/%.o matches build/obj/test-mpi.o. That's the opposite of build/obj/test-mpi.o appearing explicitly.
Even so, you have read the GNU make documentation correctly: make would not consider build/obj/test-mpi.o to be an intermediate file if it was mentioned as a target or prerequisite of some other rule. But it isn't. If make builds that file at all, it is entirely make's idea, notwithstanding the fact that you set the stage for it to come to that decision. This is exactly what it means to be an intermediate file.
Am I missing something?
Apparently you are missing what it means for a file to be "mentioned in" a makefile, as the GNU docs put it. It means that the file's name appears literally in the makefile text, after macro expansion, as a target or prerequisite of a rule. Example:
$(BIN_DIR)/test-mpi: $(OBJ_DIR)/test-mpi.o
or
$(OBJ_DIR)/test-mpi.o: $(SRC_DIR)/test-mpi.c
Matching a target or prerequisite pattern of an implicit ("pattern") rule does not suffice. In fact, it is exactly files that are generated as intermediates in chains of implicit rules that make aims to remove. Implicit rules defined in the makefile are not distinguished from make's built-in implicit rules in this regard.
However, although files such as the one you asked about are definitely intermediate files as GNU make defines that term, make has an additional capability here that might serve your purposes. If you want to use a pattern to specify intermediate targets that you want to preserve, then you can do so by designating the pattern as a prerequisite of the special target .PRECIOUS, like so:
.PRECIOUS: $(OBJ_DIR)/%.o
Intermediate files matching such a pattern will be spared from the automatic deletion to which they otherwise they would be subject.

GNU Make: Force use of my own version of a rule

I have this rule in my Makefile:
%: ${OBJ}/%.o ${OBJ}/AgentProgram.o ${LIB}
$(CXX) $^ ${LDFLAGS} ${LIB_DIRS} ${LIBS} $(OUTPUT_OPTION)
If obj/Foo.o exists, make will use this rule. However, if the object doesn't already exist, it will use the built-in rule and attempt to directly compile from my .cpp.
Is there some way to define this rule as the default, or turn off the built-in rule?
My workaround is to modify my make bins target to produce all .o files first. It wasn't that hard in this case, I altered:
bins: ${BINS}
and turned it into this: (I already had ${OBJECTS} available)
bins: ${OBJECTS} ${BINS}
You can cancel pattern rules, including built-in pattern rules, by defining them without a recipe:
%: %.c
%: %.cpp
will remove the pattern rule for creating binaries from a .c and a .cpp.
Or, with a sufficiently new version of GNU make, you can disable ALL builtin rules by adding this to your makefile:
MAKEFLAGS += -r
(see the manual for the meaning of the -r option).

GNU make generate assembly first, them compile them to .o and link

SOURCE=a.c b.c c.c
ASM=$(patsubst %.c,%.s, $(SOURCE))
all:%.o
gcc -o test $^
$(ASM):%.c
gcc -S -o $# $<
%.o:%.s
gcc -c -o$# $<
I want to generate assembly code (.s) first, then compile the assembly code to object (.o), then link them.
But it seems above makefile code does not work. What is the correct code?
When asking questions, does not work is never very useful... if it worked you probably wouldn't be asking a question! :-) Instead you should always show the command you ran and the output you received (or at least the failing part of the output if it's long). Please cut and paste the actual text rather than paraphrasing messages. Also, including the version of the make program you're using (make --version) and the platform you're running on is often helpful.
Luckily this time we can figure out the problem without this information:
This:
$(ASM):%.c
gcc -S -o $# $<
where ASM is a.s b.s c.s, is not a pattern rule because the targets don't contain a pattern character %. That means the prerequisite %.c is not treated as a pattern, but as an actual file name, literally %.c which obviously doesn't exist.
Similarly, this:
all: %.o
has the same problem: all is a target, so this depends on the literal file named %.o which doesn't exist, and can't be created.
Also as a general rule every recipe that creates a target must create the actual target you told make it would, so this all rule is wrong because the target name is all but the recipe creates the target test.
Finally, it's a very bad idea to name your program test because test is a common UNIX program and a shell built-in, so if you run test it won't do the right thing (if you run ./test it will work).
You want to have all depend on the program you want to build, say mytest, and mytest should depend on the actual .o files:
all: mytest
mytest: $(SOURCE:.c=.o)
gcc -o $# $^
Next, you need to define a pattern rule that knows how to create an assembly file from a source file:
%.s : %.c
gcc -S -o $# $<
That, along with your other pattern rules, is all you need: make will figure it all out from that.
Finally, make has a built-in rule that tells it how to build object files directly from source files. It's best to get rid of this to force make to use your rules; add this to your makefile to delete it:
%.o : %.c

GNU Makefile - Pattern rule with multiple targets with one dependency ignores all targets but the first

I want to make a language depend target. In Particular: I have one source-file and I want to create different Objects which where add to the corresponding language folder. That single source file will differ in the C-Flags, the compiler will get. As long as I used it in a static way, it works quite fine.
de/info.o en/info.o es/info.o : info.c
$(ECHO) (DEP) $< for $#
Now I thought, it would be great if it is a bit more dynamic, in case i'll add a new language depending file. So I used a wildcard as followed:
de/%.o en/%.o es/%.o : %.c
$(ECHO) (DEP) $< for $#
But now it just make the first target and ignores the rest. The Make-Debug prints the following thing:
Successfully remade target file `de/info.o'.
Considering target file `en/info.o'.
File `en/info.o' was considered already.
Just in case: No, the objects do not exist. So there is no target, but an existing dependencie, so make should execute the rules.
EDIT: Found a solution for that Problem.
define FOO
$(1)/%.o : %.c
$(ECHO) $$< for $(1)
endef
$(foreach lang,$(LANGUAGE_LIST), $(eval $(call FOO,$(lang))))
Inspired by: http://www.gnu.org/software/make/manual/make.html#Eval-Function
Pattern rules work differently than implicit rules. While an implicit rule such as
a b c: d
command
is equivalent to the longer notation
a: d
command
b: d
command
c: d
command
this does NOT hold for pattern rules. Pattern rules with multiple targets are explicitly required to build all of their targets in a single invocation of command. Thus you would have to write
$ cat GNUmakefile
all: de/x.o en/x.o es/x.o
de/%.o: %.c
#echo $# from $<
en/%.o: %.c
#echo $# from $<
es/%.o: %.c
#echo $# from $<
$ gmake
de/x.o from x.c
en/x.o from x.c
es/x.o from x.c
The relevant documentation is found in 10.5.1 Introduction to Pattern Rules of the GNU make manual:
Pattern rules may have more than one target. Unlike normal rules, this does not act as many different rules with the same prerequisites and recipe. If a pattern rule has multiple targets, make knows that the rule’s recipe is responsible for making all of the targets. The recipe is executed only once to make all the targets. When searching for a pattern rule to match a target, the target patterns of a rule other than the one that matches the target in need of a rule are incidental: make worries only about giving a recipe and prerequisites to the file presently in question. However, when this file’s recipe is run, the other targets are marked as having been updated themselves.

Resources