makefile with computed variables inside a search pattern - makefile

I am working on a makefile that I think should use computed variables inside of a pattern. As part of a larger project I have three different parsers that have a lot of overlap and are written in modular form so as to be able to maintain the common components more easily. The relevant part of the makefile is this:
parser1object = firstobject
parser2object = secondobject
parser3object = thirdobject
$(srcdir)/HIG%.y: \
$(srcdir)/HIG%.y.1 \
$(srcdir)/common.tokens \
$(srcdir)/HIG%.y.2 \
$(srcdir)/common.syntax \
$(srcdir)/HIG%.y.3
sed 's/parserObjects/S((S*)object))/g' \
$(srcdir)/HIG$*.y.2 >$*temp.tmp
sed 's/parserObjects/S((S*)object))/g' \
$(srcdir)/common.syntax >common.syntax.tmp
cat $(srcdir)/HIG$*.y.1 \
$(srcdir)/common.tokens \
$*temp.tmp common.syntax.tmp \
$(srcdir)/HIG$*.y.3 >$(srcdir)/HIG$*.y
rm -f $*temp.tmp
rm -f common.syntax.tmp
That is, I want to concatenate a number of files into one of several grammar files for bison. In the common syntax file I have some references to a generic object that need to be replaced with the name of the object in the respective parser. However, because it is inside of a pattern, the variable replacement mechanism doesn't seem to work as I had hoped. (For parser1, I want to change $($*)object to $(parser1object) and finally to firstobject.
How can I achieve what I want to do?
Incidentally, because of the pattern replacement this seems to be different from {Makefile and computed variable names}

Related

How to list a number of files with the same ending?

I have a list 15 files all with the ending ******_filteredSNPs.txt.
The starred bit is individual names for each of the 15 file. How do I list all these files?
I need the output files to have the individual names at the start but with the ending clumped.
E.g.
cd /data/PRS/
i=$PBS_ARRAYID
file="${i}_filteredSNPs.txt"
out="${i}_clumped"
./plink \
--bfile filesforPRS \
--clump-p1 1 \
--clump-r2 0.1 \
--clump-kb 250 \
--clump ${file} \
--clump-snp-field ID \
--clump-field P \
--out ${out}
I am trying the above but get an error as it fails to open my input files.
Your question remains unclear and probably a duplicate, but I'm guessing it's either of the following. Please follow up in a comment, or edit your question to clarify it still.
Perhaps you are looking for a way to run plink on each matching file separately?
for file in *_filteredSNPs.txt; do
./plink \
--bfile filesforPRS \
--clump-p1 1 \
--clump-r2 0.1 \
--clump-kb 250 \
--clump "$file" \
--clump-snp-field ID \
--clump-field P \
--out "${file%_filteredSNPs.txt}_clumped"
done
Notice also how double quotes (but not braces {...}) are necessary to avoid problems when handling files with unusual characters in their names; see When to wrap quotes around a shell variable?
The parameter expansion ${file%_filteredSNPs.txt} returns the value of the variable with the suffix after % removed.
This uses no Bash features, and so will work with any sh variant.
Or, if your plink command allows more than one --clump option, and you want to add them all into the same command line, you can just interpolate them into it.
# Put beginning of command into array
cmd=(./plink \
--bfile filesforPRS \
--clump-p1 1 \
--clump-r2 0.1 \
--clump-kb 250)
# Add matches to array
for file in *_filteredSNPs.txt; do
cmd+=(--clump "$file")
done
# Then add tail of command
cmd+=(--clump-snp-field ID \
--clump-field P \
--out "$out")
# Finally, execute it
"${cmd[#]}"
If you have 15 matching files, this will add the --clump option 15 times, each followed by another one of the 15 file names, then run plink once.
Arrays are a Bash feature, so this will not work portably with sh.

How can I access to the relative path of the target in Makefile?

I have a Makefile that contains rules that are very similar to the following
data/processed/21.12.2021/experiment6/averaged_flow_profile.csv: data/processed/21.12.2021/experiment6/PIVlab_output.mat \
data/processed/21.12.2021/experiment6/parameters.csv \
data/processed/21.12.2021/experiment6/PIVlab_set_10.01.2022.mat \
data/processed/21.12.2021/experiment6/piv21122021.005.exp6.roimask.tif \
data/processed/21.12.2021/experiment6/written_piv21122021.005.exp6.mp4 \
data/processed/21.12.2021/experiment6/PIVlab_output.mat \
code/piv/get_flowProfileFromPIV.R
code/piv/get_flowProfileFromPIV.R data/processed/21.12.2021/experiment6/PIVlab_output.mat \
data/processed/21.12.2021/experiment6/parameters.csv \
data/processed/21.12.2021/experiment6/PIVlab_set_10.01.2022.mat \
data/processed/21.12.2021/experiment6/piv21122021.005.exp6.roimask.tif \
data/processed/21.12.2021/experiment6/averaged_flow_profile.csv
where each target file, namely *.csv, depends on the data file and metadata files that are in the same directory as the target file.
How can I access to the relative path of the target, namely "data/processed/21.12.2021/experiment6", so that I can pattern match these similar rules?
How can I access to the relative path of the target, namely "data/processed/21.12.2021/experiment6", so that I can pattern match these similar rules?
You can simply use the pattern to match the path. This presents no hardship for you at all, because that's the only part of any of your prerequisite names that corresponds to the target name in the first place. (I discount the appearance of the target name itself in the prerequisite list, as this is useless.) Thus, your pattern rule might have this form:
%/averaged_flow_profile.csv: \
%/PIVlab_output.mat \
%/parameters.csv \
%/PIVlab_set_10.01.2022.mat \
%/piv21122021.005.exp6.roimask.tif \
%/written_piv21122021.005.exp6.mp4 \
code/piv/get_flowProfileFromPIV.R
# Recipe ...
Furthermore, if you then want easy access to the path inside the rule's recipe, you can access it via the $* automatic variable. For a target named data/processed/21.12.2021/experiment6/averaged_flow_profile.csv that is matched by such a pattern rule, $* would expand to data/processed/21.12.2021/experiment6.

Better way to resolve a list of path strings to a different path in make?

I am using an autogenerated make file from Atmel. When linking, it uses a variable, $(OBJS_AS_ARGS). where:
OBJS_AS_ARGS += \
"hal/src/hal_io.o" \
"hpl/systick/hpl_systick.o" \
"samd21a/gcc/gcc/startup_samd21.o" \
"hal/utils/src/utils_syscalls.o" \
"hal/src/hal_delay.o" \
"hpl/pm/hpl_pm.o" \
"hpl/core/hpl_init.o" \
"samd21a/gcc/system_samd21.o" \
"hpl/core/hpl_core_m0plus_base.o" \
my goal is to alter each string's path to be relative to the parent, i.e.:
OBJS_AS_ARGS += \
"../hal/src/hal_io.o" \
"../hpl/systick/hpl_systick.o" \
I prepend ../ I was thinking of some vpath way of doing this. Or perhaps string concatenation. However, the variable is a list of strings. I ended up adding ../ to each string. Is there a way to set up a variable/vpath that would work instead of me modifying each string? THank you.
It's not clear to me what you're trying to do exactly, but by going with your examples does this do what you want? More information on the patsubst function.
NEW_ARGS := $(patsubst "%","../%",$(OBJS_AS_ARGS))

GNU make loop variable strange behavior

In my Makefile I am trying to copy a list of files from location1 to location2, then to location2 to location3. I got the following strange behavior:
FILES_LIST=dir1/file1 dir2/file2 dir3/file3 ........
mytarget:
for file in $(FILES_LIST) ; do \
#this works
cp -vf location1/$$file location2/$(shell $$file##*/) ; \
#this does not work
cp -vf location2/$(shell $$(file)##*/) location3/ ; \
done
I am using "$(shell $$(file)##/)" to strip out "dir1/" part of each item in FILES_LIST.
The first cp works (from location1 to 2), however, the send does not, build log shows "$(shell $$(file)##/)" is evaluated to empty.
I am using GNU Make 3.81
The problem is $$(file). That's not a variable evaluation. That's a Command Substitution. You meant $${file} (well not quite but we'll get to that).
There is also absolutely no reason to be using $(shell) here at all as you are already in a shell context when those lines run.
Not to mention that those $(shell) calls aren't doing anything even remotely like what you want (they aren't operating at the right time to do that).
You want this:
FILES_LIST=dir1/file1 dir2/file2 dir3/file3 ........
mytarget:
for file in $(FILES_LIST) ; do \
#this works
cp -vf location1/$$file location2/$${file##*/} ; \
#this does not work
cp -vf location2/$${file)##*/} location3/ ; \
done
Your $file variable is a shell variable not a make one. The call to $(shell) does not see it. You are effectively running $(shell $file##*/) which runs the $file##*/ command through the shell. That shell has no $file variable so that becomes ##*/ which is a comment and the whole thing returns nothing. (Actually I think the comment may be stripped first but that doesn't change anything.)
Use $(notdir $file) command.
notdir will strip out the directories and return the filename. For example, $(notdir dir1/file.h) will return file.h
Reference link for more detailed info:
https://www.gnu.org/software/make/manual/html_node/File-Name-Functions.html

functions in makefiles?

I have a slew of makefile targets that do the same thing:
${SOME_FILE}:
${FILES} | ${DIST_DIR}
##cat ${FILES} | \
sed 's/#DATE/'"${DATE}"'/' | \
sed 's/#VERSION/'"${CR_VER}"'/' \
> ${OUT_FILE};
where ${FILES} and ${OUT_FILE} are the only things changing. I'm trying to figure out if it's possible to simplify these targets to something like:
${SOME_FILE}:
compile(${FILES},${OUT_FILE})
Thanks for any insight.
GNU make has this:
http://www.gnu.org/software/make/manual/make.html#Call-Function
To define a multi-line function, you would use this syntax:
http://www.gnu.org/software/make/manual/make.html#Canned-Recipes
Links to docs (like in the accepted answer) are good but good example is better :)
define my_func
$(eval $#_PROTOCOL = "https:")
$(eval $#_HOSTNAME = $(1))
$(eval $#_PORT = $(2))
echo "${$#_PROTOCOL}//${$#_HOSTNAME}:${$#_PORT}/"
endef
my-target:
#$(call my_func,"example.com",8000)
Take into consideration the following:
There are no custom "functions" in Makefile language. So "my_func" is actually a variable that simply contains a text.
That "function" doesn't have its own scope. All the content of that "function" is copied into the recipe as is. All variables in the body will be used after that as a part of the recipe.
Don't use spaces near the commas to prettify param list of "call" function.
Args are passed like $(1), $(2), ... that is not very handy, so re-declare them with meaningful names. This is optional but recommended for bigger "function" bodies.
Variables are declared with $#_ prefix that makes them "local" to the rule (actually not local but prefixed by the target name).
So we have imitation of functions with imitation of local variables but generally this works good.
If you don't want to restrict yourself to GNUmake, your best bet is probably to generate makefile fragments yourself and then include them.

Resources