Implicit Makefile Targets - makefile

http://www.cprogramming.com/tutorial/makefiles_continued.html explains implicit targets:
There are some actions that are nearly ubiquitous: for instance, you might have a collection of .c files that you may wish to execute the same command for. Ideally, the name of the file would be the target; using the implicit target ".c" you can specify a command to execute for any target that corresponds to the name of a .c file (minus the .c extension).
However, when I try it, the implicit target is simply ignored. My test makefile is as follows:
Default: Foo.bar
echo "In default."
.bar:
echo "In .bar."
make: *** No rule to make target `Foo.bar', needed by `Default'. Stop.
What am I missing?

Try:
default: foo.bar
echo "In default."
%.bar:
echo "In .bar."
You may be asking about old-style suffix rules - for example this rule:
.c.o:
cc -c $<
tells make how to build a .o file from a .c source. The form with the '%' is known as a pattern rules and is more "modern". I suggest you read the GNU Make manual, which is very informative about such stuff, and easy to read.

Related

GNU make - transform every prerequisite into target (implicitly)

I have another make-like tool that produces an XML as an artifact after parsing my makefile which I'll then further process with Python.
It'd simplify things for me - a lot - if I could have make consider every single prerequisite to be an actual target because then this other tool
will classify each and every file as a "job".
This is a fragment of my makefile:
.obj/eventlookupmodel.o: C:/Users/User1/Desktop/A/PROJ/src/AL2HMIBridge/LookupModels/eventlookupmodel.cpp C:\Users\User1\Desktop\A\PROJ\src\AL2HMIBridge\LookupModels\eventlookupmodel.h \
C:/Users/User1/Desktop/A/PROJ/qt5binaries/include/QtCore/qabstractitemmodel.h \
C:/Users/User1/Desktop/A/PROJ/qt5binaries/include/QtCore/qvariant.h \
...
I'd want for make to think I have a dummy rule for each prerequisite such as below:
C:/Users/User1/Desktop/A/PROJ/qt5binaries/include/QtCore/qvariant.h:
#echo target pre= $#
C:/Users/User1/Desktop/A/PROJ/qt5binaries/include/QtCore/qabstractitemmodel.h:
#echo target pre=$#
C:/Users/User1/Desktop/A/PROJ/src/AL2HMIBridge/LookupModels/eventlookupmodel.cpp :
#echo target pre=$#
C:\Users\User1\Desktop\A\PROJ\src\AL2HMIBridge\LookupModels\eventlookupmodel.h:
#echo target pre=$#
I don't care about the exact form of the rule just that each file is considered an actual target.
My method of passing in this rule would be by setting the MAKEFILES variable like so
make all MAKEFILES=Dummy.mk
with Dummy.mk containing this rule so that I do not modify the makefiles.
I've tried the following so far.
Dummy.mk:
%.h:
#echo header xyz = $#
%:
#echo other xyz= $#
This partially works.
I run make all --trace --print-data-base MAKEFILES=Dummy.mk and I can see that
make does "bind" the %.h: rule to the header files. In the --print-data-base section, I see that rule being assigned to the header files.
C:/Users/User1/Desktop/A/QNX_SDK/target/qnx6/usr/include/stddef.h:
# Implicit rule search has been done.
# Implicit/static pattern stem: 'C:/Users/User1/Desktop/A/QNX_SDK/target/qnx6/usr/include/stddef'
# Last modified 2016-05-27 12:39:16
# File has been updated.
# Successfully updated.
# recipe to execute (from '#$(QMAKE) top_builddir=C:/Users/User1/Desktop/A/HMI_FORGF/src/../lib/armle-v7/release/ top_srcdir=C:/Users/User1/Desktop/A/HMI_FORGF/ -Wall CONFIG+=release CONFIG+=qnx_build_release_with_symbols CONFIG+=rtc_build -o Makefile C:/Users/User1/Desktop/A/HMI_FORGF/src/HmiLogging/HmiLogging.pro
', line 2):
#echo header xyz = $#
However, I do NOT see the "echo header xyz $#"-rule being executed.
Regarding the %: rule, it is neither executed for the .cpp files nor "bound" to them in the --print-data-base section.
However, it is bound and executed for existing targets which have no suffix i.e.
all: library binary
binary: | library
ifs: | library
For the %: rule, the reason for this behavior is because of 10.5.5 Match-Anything Pattern Rules: If you do not mark the match-anything rule as terminal, then it is non-terminal. A non-terminal match-anything rule cannot apply to a file name that indicates a specific type of data. A file name indicates a specific type of data if some non-match-anything implicit rule target matches it.
If I make it non-terminal - no double colon - then the rule doesn't apply to built-in types like .cppunless I un-define the built-in rules that negate my intended %: rule.
If I make it terminal, "it does not apply unless its prerequisites actually exist". But a .h or .cpp doesn't technically have prerequisites; can I just create a dummy file and have that as its prerequisite?
NOTE: This has NOTHING to do with gcc -M generation. Yes the -M option would help in the specific case of header and source files but this question is for more generic targets and prerequisites that already exist in the makefile when make is launched.
This may take a few iterations. Try:
%.h: null
#echo header xyz = $#
%: null
#echo other xyz= $#
null:
#:
Try generating static pattern rules for the header files. See one of the answers to Make ignoring Prerequisite that doesn't exist.
Static pattern rules only apply to an explicit list of target files like this:
$(OBJECTS): %.o: %.c
*recipe here*
where the variable OBJECTS is defined earlier in the makefile to be a list of target files (separated by spaces), for example:
OBJECTS := src/fileA.c src/fileB.c src/fileC.c
Note that you can use the various make utility functions to build that list of target files. For example, $(wildcard pattern), $(addsuffix), etc.
You should also ensure that the recipe "touches" the header file to change the timestamp.
I've found that using static pattern rules instead of pattern rules fixes problems where make doesn’t build prerequisites that don’t exist, or deletes files that you want.
Here is an example of using wildcard to copy files from one directory to another.
# Copy images to build/images
img_files := $(wildcard src/images/*.png src/images/*.gif src/images/*.jpg \
src/images/*.mp3)
build_images := $(subst src/,$(BUILD_DIR)/,$(img_files))
$(build_images): $(BUILD_DIR)/images/% : src/images/%
mkdir -p $(dir $#)
cp -v -a $< $#
There are other make functions like addprefix that could be used to generate a more complex file specification.

Using Make with force snippet to override other file

I've been trying to get a makefile, a, to include another makefile, b, if the target specified is not found in file a. I'm using this snippet to try and achieve this, but from echos I've put into the file I can see that makefile b is being accessed even when the target is found in a and run.
The snippet I'm using from the link above is:
foo:
frobnicate > foo
%: force
#echo "No target found locally, running default makefile"
#$(MAKE) -f Makefile $#
force: ;
Specifically I'm getting "Nothing to be done" outputs when makefile b is being used, and makefile a is behaving as expected. This is shown below:
$ make all # all target appears in both make files
No target found locally, running default makefile
make[1]: Entering directory `/home/user/currdir' # (b)
make[1]: Nothing to be done for `Makefile'.
make[1]: Leaving directory `/home/user/currdir'
Local all # (a)
Is there a better way to be doing this?
addition: After adding another echo to the % rule, I've found that $# is "Makefile", when it should be the target trying to be built.
I don't really understand your question based on the example you gave; there is no "a" or "b" in that example, just one Makefile.
However, the behavior you're seeing is due to GNU make's re-making makefiles capability. When you create match-anything pattern rules as you've done, you have to consider that every single target or prerequisite that make wants to build will match that rule. That's a large burden.
You can avoid having remade makefiles match by creating explicit rules for them, such as:
Makefile: ;

Percentage used in the Makefile rule that aims at renaming all .c files

I think percentage in Makefile means wildcard. As a try, I test a contrive Makefile that aims at changing any .c file to 'hi'. This is my Makefile rule:
%.c:
mv $# hi
I save the file above to 'Makefile', and then type in the terminal
touch hello.c
make
The terminal says
make: `hello.c' is up to date.
which is certainly not what I wanted. Two naive questions:
a) Why does makefile determine that 'hello.c' is actually "up to date"?
b) How can we enforce the rule to be applied anyway?
You have not defined any dependencies in your rule. The hello.c already exists and none of the dependencies have newer timestamp than hello.c.
There are rules with no dependencies like clean. In this case the file clean does not exist and make tries to create it by executing the rule's set of commands. However, as mentioned in GNU make documentation this will not work in the case where clean file is created. The solution on this is to define clean as "Phony Target".
Additionally the output of the command is file hi and not %.c
The Makefile should look like:
%.hi : %.c
mv $< $#

error using makefile, targets and %

I'm trying to debug the following code:
TESTS=$(shell cat yoursourcefile)
all: $(TESTS)
%: compile_design
compile $#_tb.vhd >> log_file.log
simulate $#
I got this error:
makefile_tb.vhd >> log_file.log
as if makefile is a target
this error disappears when I add a character or more before %:
T%: compile_design
compile $#_tb.vhd >> log_file.log
simulate $#
This works but implies that all my targets starts with "T" which is not always the case.
My questions are:
what's exactly the function of % here ?
How to get rid of this error?
As suggested, I added
makefile: ; $#:
at the end, so I have now:
TESTS=$(shell cat yoursourcefile)
all: $(TESTS)
%: compile_design
compile $#_tb.vhd >> log_file.log
simulate $#
makefile: ; $#:
then when I do:
make all
I get [all] error2 all_tb.vhd >> log_file.log
but all_tb.vhd does not exist !
The %: compile_design rule is a "match-anything" pattern rule. It says "hey make, if you ever want to build any file, with any name, then you can do it by running these commands. Oh and by the way, if you have a file you want to build and it's older than the compile_design file, then you need to rebuild it". Generally you want to avoid match-anything rules, but if your target names truly have no specific pattern, you can't.
When you add the T before it then it tells make that instead of any file, that rule can only build files that begin with T.
The reason make is trying to rebuild the makefile is that GNU make has a special feature that allows it to remake its own makefiles. So after it reads its makefile it will try to re-make it. Normally this has no effect because there's no rule to build a makefile, but here you've added a rule that you've told make can build anything. Adding the T keeps the pattern from matching Makefile because Makefile doesn't begin with T.
The simplest thing for you to do is define an explicit rule for the makefile: make always chooses an explicit rule, if it exists, over an implicit rule like a pattern rule:
Makefile: ; #:
This creates an explicit rule that does nothing (: is the shell built-in command that does nothing).

Ensuring a prerequisite exists for a pattern rule

I understand that an "explicit" pattern rule will take precedence on its implicit counterpart when its prerequisites can be made.
all: src/foo.o
src/%.o: makefile my_haeder.h src/%.c
echo Do something with those source files
If there is a typo for "my_header.h", the implicit rule for %.o will take precedence. Not only my recipe will not be executed, but touching the prerequisites will not trigger the rule. Actually it is the second point which is of interest for me.
The make documentation offers a verification using static pattern rules:
SET_OF_FILES=src/foo.o
all: src/foo.o
$(SET_OF_FILES): src/%.o: makefile my_haeder.h src/%.c
echo Do something with those source files
This results in:
gmake: *** No rule to make target `src/my_haeder.h', needed by `src/foo.o'. Stop.
Though a larger rule, that solution is nice, as long as I don't have to add a rule for which the stem could overlap:
SET_OF_FILES=src/foo.o src/subsrc/bar.o
all: src/foo.o
$(SET_OF_FILES): src/%.o: makefile my_header.h src/%.c
echo Do something with those source files
$(SET_OF_FILES): src/subsrc/%.o: makefile my_header.h src/subsrc/%.c
echo Do something with those other source files
Which results in:
makefile:8: target `src/foo.o' doesn't match the target pattern
makefile:9: warning: overriding commands for target `src/foo.o'
makefile:6: warning: ignoring old commands for target `src/foo.o'
makefile:9: warning: overriding commands for target `src/subsrc/bar.o'
makefile:6: warning: ignoring old commands for target `src/subsrc/bar.o'
The first message is here because I didn't bother $(filter)ing SET_OF_FILES. I don't know how to solve the next warnings, which for any reviewer would mean "something's wrong".
Is there another (more elegant) way to verify that the prerequisites are actually feasible, in order to avoid dropping the explicit pattern rule?
(using GNU Make 3.79.1 win32)
Add a separate rule to check for your prerequisites
all: prereqs src/foo.o
prereqs: Makefile my_header.h
src/%.o: src/%.c Makefile my_header.h
echo Do something with those source files
src/subsrc/%.o: src/subsrc/%.c Makefile my_header.h
echo Do something with those other source files
which will give you:
make
make: *** No rule to make target 'my_header.h', needed by 'prereqs'. Stop

Resources