how could I change variable value into a target? - makefile

here I am again with another make issue Im trying to handle (hardly), I have set several values I want make to read, but when I try to change inside a loop it does not work; $(FOUND) stills being the same as it was first, what could I being doing bad? is other way to set variables or to change them into?
here's a part of my code related to this question:
$(shell for d in $(INPUT); \
do \
$(if $(FOUND) -eq 1, REL=$(REL)../); \
$(if $(findstring $(WORD),$(INPUT)), \
echo '$(WORD)../'; FOUND=1)\
done)
$(FOUND) variable is defined outside but want it to change when it gets $(WORD)
any suggestion for that???
thank you so much

There are several things wrong with the code above, so much so that it is difficult to understand your intention. Here is a partial list (sorry if I sound like Microsoft clippy)
The code $(if $(FOUND) -eq 1, REL=$(REL)../), looks like a mix between gnu-make syntax and shell syntax.
Your loop seems to be superfluous. You are not using the loop variable d, and you are using a construct that process the entire sequence. E.g.: $(findstring $(WORD),$(INPUT)
It seems that you are trying to generate code like echo '$(WORD)../', but the context of this code is unclear. If it is outside a rule, the code has no meaning. If it is inside a rule, it will evaluate too late to set a makefile variable. There is a way to work around this problem, but first you need to clarify your intention better.
I can only suspect you intended to have REL=$(REL)/.. or REL=../$(REL) but I can be mistaken.
Lastly it is important to understand that what you really should do in a Makefile is to describe a dependency graph, and let make figure out the order of operation needed to be performed. So a procedural approach such as may inferred from your code above should be minimized.
Edit:
If I read you correctly, you are trying to achieve a tricky goal in Makefile. Let me assure you that your inexperience is not the only stumbling block you have. Writing good Makefiles is hard. If you have any control over this, I strongly suggest to have a look at some other build solutions. For example, cmake can write good Makefiles for you.
If you are trying to calculate a base-dir or a relative-dir, please note that the concept of current-working-directory as saved in $(CURDIR) might or might not be what you expect.
For your question, you can indeed use a GNU make $(foreach ...) construct, but there are several functions that are designed to handle sequences without iterations, that might serve you better.

Related

Why don't makefiles behave more like shell scripts within recipes?

I find makefiles very useful, and the header of each recipe
<target> : [dependencies]
is helpful. Within a recipe, the prefixes # and - are useful, as well as the automatically-defined variables like $# and $?. However, besides that, I find the way of coding the actual recipe to be strange and unhelpful. There are so many questions on StackOverflow along the lines of "how to do this in a makefile" for something that's simple (or at least more familiar) to do in bash.
Is there a reason why the recipe contents are not just interpreted as a regular shell script? Reading the manual pages, there seems to be many tools with equivalent functionality to a shell script but with different syntax. I end up specifying .ONESHELL and escaping $ with $$, or sometimes just call a script from the recipe when I can't figure out how to make it work in a makefile. My question is whether this is just unfortunate design, or are there are important features of makefiles that force them to be designed this way?
I don't really know how to answer your question. Probably that means it's not really appropriate for StackOverflow.
The requirement for using $$ instead of $ is obvious. The reasoning for using a separate shell for each logical line of a makefile instead of passing the entire recipe to a single shell, is less clear. It could have worked either way, and this is the way it was chosen.
There is one advantage to the way it works now, although maybe most people don't care about it: you only have to indent the first recipe line with TAB, if you use backslash newline to continue each line. If you don't use backslash newline, then every line has to be indented with TAB else you don't know where the recipe ends.
If your question is, could Stuart Feldman have made very different syntax decisions that would have made it easier to write long/complex recipes in makefiles, then sure. Choosing a more obscure character than $ as a variable introducer would reduce the amount of escaping (although, shell scripting uses pretty much every special character somewhere so "reduce" is the best you can do). Choosing an explicit "start/stop" character sequence for recipes would make it simpler to write long recipes, possibly at the expense of some readability.
But that's not how it was done.

Makefile dynamic variables as prerequisites

Perhaps it's something that I'm getting wrong. Basically my task is to use make to automate a build, deploy, starting, stopping of different services.
One of the things that I'm trying to do is to have a variable as a target prerequisite, however that variable has to be changed in another target.
Here's a basic sample of what I'm trying to do:
IMAGE_COUNT=-1
count_images:
$(eval IMAGE_COUNT=5)
_should_build: $(if $(findstring $(IMAGE_COUNT),0), build,)
build:
...some procedure to build...
start: _should_build
...some procedure to start a service...
Obviously the $(IMAGE_COUNT) in _should_build check will stay as -1, but what I want is to have the $(IMAGE_COUNT) become a 5 during the prerequisite check. A thing to note is that I cannot place the counting of images outside the count_images target.
Does anyone know if this is possible at all?
Perhaps it's something that I'm getting wrong.
That "something" is called an evaluation order.
One of the things that I'm trying to do is to have a variable as a target prerequisite, however that variable has to be changed in another target.
Not a target, but a recipe. The recipes are preprocessed before execution. While the prerequisites are preprocessed on the first pass. In fact, changing the value of a make's variable inside a recipe in 90% of cases is a mistake. (Also remember that all preprocessing is done before feeding the recipe to the shell).
Does anyone know if this is possible at all?
Everything is possible, of course, but not this way.
A thing to note is that I cannot place the counting of images outside the count_images target.
Most probably, you can.
Anyway, the point is that some shell script (a recipe, or a part of a recipe) should return a number. However, such return values cannot be stored in a make's variable. Re-think your design and find another way for communication between your targets.

Preprocess conditional arch/make file to get non-conditional file

I have a conditional makefile (well, actually I am dealing with the arch file that will be called when invoking make) that is quite involved and I would like to preprocess it to get rid of all the 'ifeq', 'ifneq' parts that only worsen the readability, in order to see better what is being actually done. I tried doing
make -n -d
where I get the whole calls to the compiler, but that is also a pain since then I need to separate manually all the flags. I just want to get my nice makefile with my separate FLAGS, DFLAGS, LIBS sentences etc etc.
(My apologies if this has been said anywhere, but I am unable to find it).
Thanks!

Why is eval evil in makefiles

I have had several people tell me at this point that eval is evil in makefiles. I originally took their word for it, but now I'm starting to question it. Take the following makefile:
%.o:
$(eval targ=$*)
echo making $targ
%.p:
echo making $*
I understand that if you then did make "a;blah;".o, then it would run blah (Which could be an rm -rf \, or worse). However, if you ran make "a;blah;".p you would get the same result without the eval. Furthermore, if you have permissions to run make, you would also have permissions to run blah directly as well, and wouldn't need to run make at all. So now I'm wondering, is eval really an added security risk in makefiles, and if so, what should be avoided?
Why is eval evil?
Because it grants a whole power of language to things you actually don't want to give that power.
Often it is used as "poor man's metaprogramming" to construct some piece of code and then run it. Often it looks like eval("do stuff with " + thing) - and thing is only known during runtime, because it gets supplied from outside.
However, if you don't make sure that thing belongs to some tiny subset of language you need in that particular case (like, is a string representation of one valid name), your code would grant permissions to stuff you didn't intend to. For example, if thing is "apples; steal all oranges" then oranges would be stolen.
If you do make sure that thing belongs to some subset of language you actually need then 2 problems arise:
You are reimplementing language features (parsing source) which is not DRY and is often a sign of misusing a language.
If you resort to this that means simpler means are not suitable and your use case is somewhat complicated which makes validating your input harder.
Thus, it's really easy to break security with eval and taking enough precautions to make it safe is hard, that's why if you see an eval you should suspect possible security flaw. That's just a heuristic, not a law.
eval is a very powerful tool - as powerful as the whole language - and it's too easy to shoot your leg off with it.
Why this particular use of eval is not good?
Imagine a task that requires making some steps that depend on a file. Task can be done with various files. (like, user gives Virtualbox image of a machine that is to be brought up and integrated into existing network infrastructure)
Imagine, say, lazy administrator that automated this task - all commands are written in a makefile because it fits better than sh script (some steps depend on other and sometimes don't need to be re-done).
Administrator made sure that all commands are ok and correct and had given sudoers permission to run make with that specific makefile. Now, if makefile contains string like yours then using properly crafted name for your Virtualbox image you could pwn the system, or something like that.
Of course, I had to stretch far to make this particular case a problem, but it's a potential problem anyway.
Makefiles usually offer simple contracts: you name the target and some very specific stuff - written in makefile - gets done. Using eval the way you've used it offers a different contract: the same stuff as above but you also can supply commands in some complicated way and they would get executed too.
You could try patching the contract by making sure that $* would not cause any trouble. Describing what that means exactly could be an interesting exercise in language if you want to keep as much flexibility in target names as possible.
Otherwise, you should be aware of extended contract and don't use solutions like this in cases where that extension would cause problems. If you intend your solution to be reusable by as many people as possible, you should make its contract cause as little problems as possible, too.

Makefile analyzer/simulator?

I'm no Makefile expert, and I was wondering if someone knew of some kind of analyzer or simulator that would start from the top-most Makefile all the way down to the inner-most Makefile, each time showing me the value of each variable and the order in which it goes through rules.
Thank you.
Most implementations of make offer the -d flag which will cause the program to print out everything it is doing, in great detail. The -n flag will cause make to do a dry-run, ie report what it would do but not actually do it.
Be warned, make produces a lot of output so you probably want to redirect it to a file for your later perusal.

Resources