Makefile 'for' variable as dynamic variable name - makefile

I have some dynamically named variables in Makefile. That all works and is fine.
Now I need to reference some of those variables in a for loop, but I can't seem to find the right syntax:
#for module in $(MODULES); do \
(echo $(SRC_$$module)); \
done
each $(MODULE) is a name that needs to be appended to $(SRC_.. for example $(SRC_foo) $(SRC_bar)... but I can't seem to do that with this syntax.

You have expansion-time issues. You can't expand make-level variables dynamically once the shell has started to run. Which is what you are trying to do here.
You either expand the variables at make time or at shell time but not both.
To expand everything at make time you can use something like this.
#$(foreach module,$(MODULES),$(foreach cfile,$(SRC_$(module)),echo '[$(cfile)]';))
Expanding at shell time is possible but a bit messier/trickier.

Related

How to pass make flags stored in text files in command line?

I have a text file called OPTIONS.txt storing all flags of Makefile:
arg1=foo arg2="-foo -bar"
I want to pass all flags in this file to make. However,
make `cat OPTIONS.txt`
fails with make: invalid option -- 'a'. It seems that shell interprets it as:
make arg1=foo arg2="-foo -bar"
^argv[1] ^argv[2] ^argv[3]
Is there any way to make it interpreted as:
make arg1=foo arg2="-foo -bar"
^argv[1] ^--------argv[2]
Since you control the options file, store the options one per line:
arg1=foo
arg2="-foo -bar"
Then in the shell, you'll read the file into an array, one element per line:
readarray -t opts < OPTIONS.txt
Now you can invoke make and keep the options whole:
make "${opts[#]}"
If you want the shell to interpret quotes after backtick expansion you need to use eval, like this:
eval make `cat OPTIONS.txt`
however just be aware that this evaluates everything, so if you have quoted content outside of the backticks you'll get the same issue:
eval make `cat OPTIONS.txt` arg4="one two"
will give an error. You'd have to double-quote the arg4, something like this:
eval make `cat OPTIONS.txt` arg4='"one two"'
In general it's tricky to do stuff like this from the command line, outside of scripts.
ETA
The real problem here is that we don't have a set of requirements. Why do you want to put these into a file, and what kind of things are you adding; are they only makefile variable assignments, or are there other make options here as well such as -k or similar?
IF the OP controls (can change) the format of the file AND the file contains content only used by make AND the OP doesn't care about the variables being command line assignments vs. regular assignments AND there are only variable assignments and not other options, then they can just (a) put each variable assignment on its own line, (b) remove all quotes, and (c) use include OPTIONS.txt from inside the makefile to "import" them.

Use 'subst' in a multiline makefile bash script?

I read this question: Makefile: $subst in dependency list, but I still can't make my shell script work correctly.
I have a makefile with a line with the contents:
##public_detailed#|test_create|Syntax: commoncmdsyntax test_create test_name=<test-name>
A target runs a multiline bash script, where the commoncmdsyntax must be replaced by a string containing words and spaces.
In the script, I use cut to assign to a variable desc the following string:
Syntax: commoncmdsyntax test_create test_name=<test-name>
The problem is that commoncmdsyntax is not replaced by new text here:
$(subst commoncmdsyntax,new text,$$desc)
I also tried to replace it by a single word, like XX, but it also does not work.
The subst function (as in $(subst commoncmdsyntax,new text,$$desc)) is a Make function, so Make will perform the substitution before running any rule and therefore before your script assigns a value to desc. So even if secondary expansion worked the way you seem to think it will, this approach would still fail.
If you want to perform a substitution within something made by a shell script (in a recipe), the sensible way is to do so within the recipe:
echo $dest | sed 's/commoncmdsyntax/new text/'
We can give you a more detailed solution if you give us a minimal complete example of the problem.

Makefile environment variable changes between recipes

I'm attempting to create a single log file that tracks and reports the results of each recipe as the make process moves through the makefile.
To do this, I'm creating an environment variable to hold my logfile reference like so:
LOGDIR = logs
LOGFILE = $(LOGDIR)/$(shell date --iso=seconds).log
The intention is then to add relevant messaging to the log file by using
echo "message" >> $(LOGFILE)
Trouble is, when processing moves from one recipe to the next, the environment variable is re-evaluated, resulting in a new log file from every recipe in my makefile.
Why does the environment variable get re-evaluated, and how can I prevent this to use a single global reference to a logfile?
I thought that using the $(shell operator) syntax prevents re-evaluation of the variable, based on Aaron's answer here.
If you are using GNU make then writing
LOGFILE := $(LOGDIR)/$(shell date --iso=seconds).log
is supposed to evaluate the expression only once. Does that solves your problem?

Defining recursively expanded variable with same name as environment variable

I'm trying to lazily evaluate configuration option. I want to issue a Make error only if the variable is actually used (substituted).
Consider the following Makefile:
VAR = $(error "E")
NFS_DIR = NFS_DIR is $(VAR)
T = $(NFS_DIR) is 1
all:
echo Test
If I run it with my environment (which has /srv/nfs value), the output is following:
➜ ~ make
echo Test
Makefile:3: *** "E". Stop.
So the recursive definition acts like simple definition.
If I clear the environment, it works as expected:
➜ ~ env -i make
echo Test
Test
I couldn't find any mention that recursively-expanded variable, when defined with same name as environment variable, will act like simply-expanded variable.
So the questions are:
Why the observed behavior?
How to implement the desired behavior?
Update: to clarify — I don't want to use ?= since the options are configuration options I want them to come strictly from Makefile and not from environment.
Any variable which is in the environment when make starts, will be exported to the environment of any command make runs (as part of a recipe, etc.) In order for make to send the value of the variable to the command, make first has to expand it. It's not acting like a simply-expanded variable. It's just that running a command forces the expansion.
This is kind of a nasty side-effect but I'm not sure there's anything that can be done directly: this behavior is traditional and mandated by POSIX and lots of makefiles would break if it were changed.
You have two choices I can think of. The first is to use the unexport make command to tell make to not send that variable in the command's environment.
The second is to change the name of the variable in make to something that is not a valid environment variable: make will only export variables whose names are legal shell variables (contain only alphanumeric plus _). So using a name like VAR-local instead of VAR would do it.
The question appear to be extremely clear in the title but the actual request get lost in details so the only other reply left it mostly unanswered. Directly answering to the question in the title, which is very interesting, to define a variable in a Makefile with same name as environment variable you can get its value with printenv:
PATH=${shell printenv PATH}:/opt/bin
echo:
echo $(PATH)
Other techniques to achieve the same result without relying on evaluation with external commands are welcome.

Shell Scripting: Using a variable to define a path

My problem lies with my confusion with shell variables.
To my understanding, variables allow me to store a value (String in this case) and to call it later in my code. So if I wanted to have a variable that holds the path to some set of scripts, I could ideally just store it like this:
SPTH = '/home/Foo/Documents/Programs/ShellScripts/Butler'
//Later on in the script//
cd $SPTH
./script1
What I'm trying to do, with probably the wrong syntax, is to set the path to variable SPTH.
Then I use cd with argument $SPTH.
Ideally this would allow me to run the file there without typing in the path. However it doesn't work. The $SPTH is ignored and the result is as if cd was used alone.
So what am I doing wrong? And what would be a way to do this?
Don't use spaces...
(Incorrect)
SPTH = '/home/Foo/Documents/Programs/ShellScripts/Butler'
(Correct)
SPTH='/home/Foo/Documents/Programs/ShellScripts/Butler'
To add to the above correct answer :-
For my case in shell, this code worked (working on sqoop)
ROOT_PATH="path/to/the/folder"
--options-file $ROOT_PATH/query.txt

Resources