How to limit Makefile pattern matching to a list of options - makefile

I would like to use an implicit rule (of the %.final: %.intermediate type) in a makefile, but only for certain files (only a.final and b.final, but not x.final)
I've tried to use
targets=a b c
${targets} %.intermediate: %.original
process1 $< > $#
${targets}: %.final: %.intermediate
process2 $< > $#
all: ${targets}
but I'm just not making make happy. I'm not sure exactly what these implicit rules are doing, and if targets needs to include '.final', or how to really make it come together.
If I do
a.intermediate: a.original
process1 a.original > a.intermediate
a.final: a.intermediate
process2 a.intermediate > a.final
#and continue for b, c, etc.
Then things are just fine and dandy.
Here's the general idea. It's not in good form because I'm not used to writing makefiles with pattern substitution and so forth.
#Reference data
CHIP_WCE_ACCESSION=SRR713343
CHIP_BLANK_ACCESSION=SRR713344
#Experiment data
CHIP_NANOG_ACCESSION=SRR713342
CHIP_SOX2_ACCESSION=SRR713341
CHIP_OCT4_ACCESSION=SRR713340
CHIP_TARGETS=${CHIP_NANOG_ACCESSION} ${CHIP_SOX2_ACCESSION} ${CHIP_OCT4_ACCESSION}
#Note that CHIP_WCE_ACCESSION is *not* processed with these.
CHIP_REFERENCE=${CHIP_BLANK_ACCESSION} ${CHIP_WCE_ACCESSION}
BAM_COVERAGE=bamCoverage --numberOfProcessors 16 --binSize 10
#This is a specific bioinformatics program.
${CHIP_REFERENCE}: %.sort.bam
echo hello > $# #Not the same way the CHIP_TARGETS are created.
${CHIP_TARGETS}: %.sort.bam
touch $# #There's actually a long chain of processing, but touch works for the minimal example.
${CHIP_TARGETS}: %.bw: %.sort.bam ${CHIP_BLANK_ACCESSION}.sort.bam
${BAM_COVERAGE} --use-reference ${CHIP_BLANK_ACCESSION}.sort.bam --bam $< -o $#
chip: ${CHIP_NANOG_ACCESSION}.bw ${CHIP_SOX2_ACCESSION}.bw ${CHIP_OCT4_ACCESSION}.bw
Expected result: ${BAM_COVERAGE} is executed on all of the CHIP_TARGETS, with appropriate execution of CHIP_REFERENCE rules for the $CHIP_BLANK_ACCESSION.
Current results: I don't know how to write this rule.

This:
${targets} %.intermediate: %.original
is not valid because all targets in a pattern rule must contain the pattern.
This:
${targets}: %.final: %.intermediate
is a static pattern rule, which is what you want, BUT every target in the static pattern rule must match the target. So you want this:
$(targets:%=%.final) : %.final : %.intermediate

Related

GNUMake - Using text functions with match pattern as prerequisite

I want to use the match pattern of a Makefile rule in a text function in the perquisites list.
Let's say I want to build a file, and that files perquisites are any other files with the same name in a list.
list_of_files=a/x b/x a/y b/y c/z
%:
echo 0 $#
touch $#
build/%: $(filter %/$*,$(list_of_files))
echo 1 target $#
echo 1 prereq $?
touch $#
.PHONY:
all: build/x
echo
In the above case, I want for a/x and b/x rules to also be triggered as they are filtered out of the list, however they are not.
The docs are pretty clear that what you're trying won't work as-is:
It’s very important that you recognize the limited scope in which automatic variable values are available: they only have values within the recipe. In particular, you cannot use them anywhere within the target list of a rule; they have no value there and will expand to the empty string. Also, they cannot be accessed directly within the prerequisite list of a rule.
One way to deal with this (as mentioned in the above documentation) is to use the secondary expansion capability:
.SECONDEXPANSION:
getprereqs = $(filter %/$*,$(list_of_files))
build/%: $$(getprereqs)

Apply a single Makefile target rule to multiple input files

Say I have the following set of inputs:
list = foo \
bar \
baz
And say I have a rule such as follows:
$(somedir)/%:
# Do something here
I know I am able to invoke the rule by statically defining the target and its dependency:
$(somedir)/foo : foo
$(somedir)/bar : bar
$(somedir)/baz : baz
However, would there be a way to apply this rule to an evergrowing $(list) of inputs rather than having to statically define them all?
To be more specific, I am looking for a way to run a rule for each input and get an output (which is $(somedir)/input). Is this possible in Make?
Well, not sure I understand all the details but it seems to me that pattern rules are exactly what you need:
$(somedir)/%: %
# your recipe
This tells make that any $(somedir)/foo depends on foo and is built by the given recipe. Of course, you will also need to tell make which target you want to build:
make somedir=there there/foo there/bar
Bonus: if you know the list you can add a phony target to build them all at once:
list = foo bar baz
.PHONY: all
all: $(addprefix $(somedir)/,$(list))
$(somedir)/%: %
# your recipe
Second bonus: to help writing your recipe you can use automatic variables: $# expands as the target, $< as the first prerequisite, $^ as all prerequisites, etc. So your recipe could resemble this:
$(somedir)/%: %
build $# from $<

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.

Understanding pattern rules

I am trying to wrap my head around pattern rules and how they function. I am using this article for reference which states
A pattern rule is a concise way of specifying a rule for many files at
once. The rule will depend on the file names, but usually it depends
on them in a simple way. You specify a pattern by using the %
wildcard. When present in the dependency list, % matches any string of
any length; when present in the list of targets, % stands for the
string that % in the dependency list matched.
The following pattern rule will take any .c file and compile it into a
.o file:
%.o: %.c $(CC) $(CFLAGS) $(INCLUDES) -c $(input) -o $(output)
(This assumes that you have the variables CC, CFLAGS, and INCLUDES
defined to be something suitable. Makepp will guess a value for CC and
CFLAGS.)
The first line of the rule says that it applies to every possible
input file that matches the pattern %.c. These .c files can be
transformed into the corresponding .o file using the specified
actions.
The action of rule is quite similar to the other actions we've seen
previously, except that it uses automatic variables. An automatic
variable is a variable whose value is automatically set by makepp
depending on the rule that it appears in. Some useful automatic
variables are:
$(input)
The name of the first input file. In this rule, this would be the file that matches the %.c pattern. $(dependency) is a synonymn for $(input). In older makefiles, you will also see the cryptic symbol $< used as well.
$(output)
The name of the first output file. In this rule, this would be the file that matches the %.o pattern. $(target) and $# are synonymns.
$(inputs)
The name of all explicitly listed input files. In this case, since there is only one, $(inputs) is equivalent to $(input). $(dependencies) and $^ are synonymns.
$(outputs)
The name of all explicitly listed targets. In this case, since there is only one, $(outputs) is equivalent to $(output). $(targets) is a synonymn for $(outputs).
Here are the questions that I have:
1 ) Suppose I have 2 files FileA.c and FileB.c. When I apply the above mentioned pattern rule how would that apply to the above two files. The example given only deals with one file.
2) Whats the difference between the automatic variable input and inputs
A pattern rule will be applied to each target file that matches the rule that make needs to build.
So if you need to build both FileA.o and FileB.o (because they are both listed as prerequisites of some other target (e.g. FileBin: FileA.o FileB.o) that rule will be run twice, once for each.
Take the rule
FileBin: FileA.o FileB.o
#echo '$$input = $(input)'
#echo '$$inputs = $(inputs)'
When run that would output
$input = FileA.o
$inputs = FileA.o FileB.o
It should also be pointed out that input and output are makepp variable names and not valid for GNU make itself.

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).

Resources