Makefile - set value to variable from another rule - makefile

In the following makefile, the wat rule is for producing a .wat file from a .c file.
CC=emcc
CFLAGS= -O2 -s WASM=1 -s SIDE_MODULE=1
# flags are for not generating any emscripten glue code
# makes a .wat version of a .c file of specified name
# TARGET must be specified from command line
wat: $(TARGET).c
$(CC) $(CFLAGS) -o $(TARGET).wasm $(TARGET).c && wasm2wat $(TARGET).wasm > $(TARGET).wat && rm $(TARGET).wasm
struct: TARGET = struct
struct: wat
clear:
rm -f *.wasm *.wat
Called like this, it works fine:
[user#pc]$ make wat TARGET=struct
emcc -O2 -s WASM=1 -s SIDE_MODULE=1 -o struct.wasm struct.c && wasm2wat struct.wasm >
struct.wat && rm struct.wasm
Now I want a more specific rule, struct, written as you see. In essence, I want to reuse the wat rule, and just make sure that TARGET is set to 'struct' before running. However, running make struct gives me a no input file error from emcc, as if the value of TARGET does not exist:
[user#pc]$ make struct
emcc -O2 -s WASM=1 -s SIDE_MODULE=1 -o .c
shared:ERROR: no input files
What is the correct way to do what I aim?

The problem is, that when make evaluates how to make targets and what the prerequisites are, your TARGET is undefined and hence the rule says: wat needs .c. You could try recursion and say something like this:
struct:
$(MAKE) TARGET=struct wat
It really isn't that great to start with, because nothing actually generates file wat so the target is always out of date and the Makefile really is just a somewhat glorified shell script.
You should probably consider writing a pattern rule how to build .wat from .c, something like (based on your example):
%.wat: %.c
$(CC) $(CFLAGS) -o $(*F).wasm $< \
&& wasm2wat $(*F).wasm > $#.wat \
&& rm $(*F).wasm
You then can call make struct.wat and if you still wanted (for convenience) have just struct target, you could add:
.PHONY: struct
struct: struct.wat

You appear to be attempting to use target-specific variables and in particular, their inheritance feature, to achieve your goal.
However, this cannot work because of this statement in the documentation:
As with automatic variables, these values are only available within the context of a target’s recipe (and in other target-specific assignments).
This means that the $(TARGET) in the prerequisite:
wat: $(TARGET).c
is evaluated when the makefile is parsed, not when the struct rule is invoked, and expands to:
wat: .c
I see that Ondrej provided an answer so I'll stop here :)

Related

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

Makefile stops running at the middle [duplicate]

Hopefully this is a very simple question. I have a makefile pattern rule that looks like this:
%.so : %.f %.pyf
f2py -c -L${LAPACK_DIR} ${GRASPLIBS} -m $* $^ ${SOURCES} --opt='-02' --f77flags='-fcray-pointer' >> silent.txt
I want the makefile to build a number of .so files, so I tried to get it to build two files (radgrd_py.so and lodiso_py.so) by doing this:
radgrd_py.so lodiso_py.so:
%.so : %.f %.pyf
f2py -c -L${LAPACK_DIR} ${GRASPLIBS} -m $* $^ ${SOURCES} --opt='-02' --f77flags='-fcray-pointer' >> silent.txt
and then tried this:
radgrd_py.so:
lodiso_py.so:
%.so : %.f %.pyf
f2py -c -L${LAPACK_DIR} ${GRASPLIBS} -m $* $^ ${SOURCES} --opt='-02' --f77flags='-fcray-pointer' >> silent.txt
But in each case, it only builds the first target that I specify. If I run 'make radgrd_py.so' it works fine, I'm just not sure how to specify a list of files that need to be built so I can just run 'make'.
The usual trick is to add a 'dummy' target as the first that depends on all targets you want to build when running a plain make:
all: radgrd_py.so lodiso_py.so
It is a convention to call this target 'all' or 'default'. For extra correctness, let make know that this is not a real file by adding this line to your Makefile:
.PHONY: all
Best way is to add:
.PHONY: all
.DEFAULT: all
all: radgrd_py.so lodiso_py.so
Explanations:
make uses the first target appearing when no .DEFAULT is specified.
.PHONY informs make that the targets (a coma-separated list, in fact) don't create any file or folder.
all: as proposed by schot

Makefile for using make as gcc

Is it possible to write universal Makefile which would get any target and act like a wrapper to gcc, but with parameters? For example, this means that
make 01.c
will have the same result as
g++ -o 01.out 01.c
make already has several "implicit rules" to do what you're trying.
For example, even with no makefile,
make 01.o
Will run:
c++ -c -o 01.o 01.cpp
If it finds a file called 01.cpp in your current directory. You can set the CXXFLAGS environment variable if you want to pass more flags. If you're really set on using g++ rather than the system compiler, you can set CXX=g++, too.
Yes - You using implicit rules.
Summat like (if memory serves me right)
.cpp.o:
$(CCC) $(CFLAGS) $< -o $#
Maybe in the set of default implicit rules
You can use a wildcard - %.
However, the thing specified on the commandline is the target, not the source - what you want, not what you have.
It looks like what you want is approximately:
%.out: %.c
g++ -o $# $<
This means: to make (something).out, first make sure you have (something).c, then run g++ -o (something).out (something).c
$# is always the target file, and $< is the first prerequisite.
You will need to run make 01.out, not make 01.c

Pass arguments following make to variables in makefile

I have a piece of makefile to generate .pdf, .ps, .dvi from .tex:
...
$(FILE).pdf: $(FILE).tex $(SRC) $(DEPS)
latex $(FILE).tex && \
bibtex --min-crossrefs=500 $(FILE) && \
latex $(FILE).tex && \
latex $(FILE).tex && \
dvips $(FILE).dvi -o $(FILE).ps && \
ps2pdf $(FILE).ps $(FILE).pdf
...
I would like to get $(FILE) directly from the command line, as the first argument following make. For instance, make paper compiles paper.tex and generates paper.pdf. Also, I don't want to permit make or make all as a command, where no file name is specified.
Could anyone tell me how to pass the first argument following make to $(FILE)?
You have a couple of options here, depending on exactly what behavior you want. (And I'm not sure I entirely understand your command-- I don't think there's any reason to have it as one wrapped line-- but never mind.)
If you want to allow only targets from a list known beforehand:
FILES = scissors paper rock
$(FILES): % : %.tex $(SRC) $(DEPS)
latex $*.tex && \
...
If you want to allow only targets for which .tex files exist:
% : %.tex $(SRC) $(DEPS)
latex $*.tex && \
...
Now for what to do about unwanted targets. If a warning is enough:
all:
#echo $# is not a valid target
(real rule)
%:
#echo $# is not a valid target
If you want Make to abort entirely, I think it's possible but I'll have to think it over some more...
This is not how make works. Perhaps you want to use a shell script which accepts a parameter, validates it, and invokes make with your Makefile, passing the file in as a make variable; that is, something like
make -f tex.mk FILE="$validated_filename"

How to force make to always rebuild a file

I have a version.c file in my project that contains current revision of the project and some other stuff that is passed as a definition (-D compiler option) from makefile.
I know that to force make to compile version.c always regardless of modification date I can touch version.c.
Is there a makefile only way to achieve this? If I write .PHONY : version.o the object file doesn't get build at all.
EDIT:
Here is my makefile:
export CC = gcc
export MODULES = $(sort \
sys \
cim \
version \
)
export FILES = $(sort \
main.c \
cim.c \
version.c \
)
VPATH = $(MODULES)
OBJS = $(FILES:.c=.o)
INCLUDES = $(addprefix -I,$(MODULES))
all:$(OBJS)
$(CC) $(INCLUDES) $(OBJS) -o main.exe
clean:
rm -rf *.o *.exe
cim.o: cim.c
main.o: main.c cim.o
version.o: version.c
.PHONY: version.o
.c.o :
$(CC) $(CFLAGS) $(INCLUDES) -c $<
The classic way to do it is:
version.o: .FORCE
.FORCE:
(and you might add .PHONY: .FORCE). The file '.FORCE' is presumed not to exist, so it is always 'created', so version.o is always out of date w.r.t it, so version.o is always compiled.
I'm not sure that making version.o into a phony file is correct; it is actually a real file, not a phony one.
Not a makefile way, but easier than touch:
make -B
‘-B’ ‘--always-make’
Consider all targets out-of-date. GNU make proceeds to consider targets and their prerequisites using the normal algorithms; however,
all targets so considered are always remade regardless of the status
of their prerequisites. To avoid infinite recursion, if MAKE_RESTARTS
(see Other Special Variables) is set to a number greater than 0 this
option is disabled when considering whether to remake makefiles (see
How Makefiles Are Remade).
If you want to do this using the FORCE mechanism the correct solution looks like this:
version.o: FORCE
.PHONY: FORCE
FORCE:
By explicitly declaring FORCE to be phony we make sure things will work right even if .SECONDARY: is used (.SECONDARY: will cause FORCE to be considered an intermediate file, and make doesn't rebuilt intermediate files unless they have prerequisites newer than the ultimate target, and FORCE doesn't have any prerequisites, so .PHONY: FORCE is needed).
The other solution (using $(shell touch version.c)) also has a problem: it may cause your editor to think version.c has been updated, and prompt for a reload of the file, which might end up being destructive if you've been editing the file's buffer but haven't yet saved it. If you don't mind this, it can be made even simpler by observing that the touch command is silent, so the assignment to the hack dummy variable isn't needed:
$(shell touch version.c) # This is enough, but will likely confuse your editor
The .PHONY "trick" referred to in the comments on the question generally DOES NOT work. It may look like it does because it will force a relink iff version.o already exists, but the actual object file won't get rebuilt if the .o file rule is an implicit rule (which it usually is). The problem is that make doesn't do the implicit rule search for explicitly phony targets. This make file shows the failure:
fooprog: test.o
cp $< $#
%.o: %.c
cp $< $#
.PHONY: test.o # WRONG
clean:
rm test.o fooprog
If a static pattern rule is used instead of an implicit rule the .PHONY: version.o trick will work. In general using static pattern rules instead of implicit rules cuts out most of the more confusing Make behaviors. But most make files use implicit rules.
The quick hack version when you just need it to work and you don't want to play Make games:
# Hack to get main.c rebuilt
hack := $(shell touch main.c)
Basically just make Make run touch for you.

Resources