Deal with MAKEFILE_LIST spaces on windows - windows

I would like to get the makefiles list in a cross-platform way.
However on Windows, MAKEFILE_LIST doesn't support well spaces (not protected):
$(warning MAKEFILE_LIST=$(MAKEFILE_LIST))
Give the following result (because the Makefile is included in another):
MAKEFILE_LIST= Makefile C:/Program Files/MyApp/Makefile.include
The make string operations are not powerful enough to deal with that, and the regular way to get the top Makefile don't work:
THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST))
returns obviously this corrupted result (because lastword is based on spaces):
THIS_MAKEFILE=Files/MyApp/Makefile.include
Any solution to fix that cleanly (meaning using make functions or system commands calls)?

The basic answer is that make does not support filenames with whitespace in them. Some very limited use can be successful in some very limited situations, if you're willing to do a lot of extra work. MAKEFILE_LIST is not one of those limited situations.
It's simplest to just treat pathnames containing whitespace as not supported. Just don't do it.

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 rule with no target

I'm debugging a makefile, and in a macro expansion it creates a rule with no target (as so:)
: | directoryA
#echo running $#
...
I've looked it up online, and the makefile documentation seems to hint (but not explicitly state) that there should be at least one target.
With my current version of make (gnu Make 4.2.1), it's not killing me, but I'm just wondering whether this is considered undefined behavior or whether this is supported, and if so, what it should do.
I've looked it up online, and the makefile documentation seems to hint (but not explicitly state) that there should be at least one target.
Different makes may behave differently. They may even exhibit variant handling of specific makefile syntax matters depending on the content of the makefile -- for example, a makefile may be interpreted differently if it starts with a rule for the .POSIX: special target than an otherwise identical makefile without that rule is interpreted.
Overall, however, if you want some sort of general idea of what should be considered correct then the POSIX standard's defintion of make is a reasonably good baseline. It says:
Target rules are formatted as follows:
target [target...]: [prerequisite...][;command]
[<tab>command<tab>command...]
line that does not begin with <tab>
Target entries are specified by a <blank>-separated, non-null list of
targets, then a <colon>, [...]
(emphasis added). It furthermore goes on to say that
Applications shall select target names from the set of characters
consisting solely of periods, underscores, digits, and alphabetics
from the portable character set
, from which we can infer that the syntax description is talking about the rule text after macro expansion, since macro references can appear in the target lists of rules (or literally anywhere in a makefile, per the spec), but the characters $, (, ), {, and } appearing in macro references are not among those that can appear in targets.
That specification of makefiles' expected contents does explicitly state that target lists are non-empty, and it is reasonable to treat it as authoritative where your specific make's documentation does not override it.
I'm just wondering whether [an empty target list] is considered undefined behavior or
whether this is supported
Your combination of makefile and runtime macro values does not conform to the requirements of POSIX make. The spec does not define what should happen in this case, so in that sense the behavior is undefined, but "undefined behavior" isn't as strong a concept in this area as it is in, say, the C and C++ language specifications.
In view of that, I would account it a makefile flaw for any rule's target list to be empty (after macro expansion). Although the make you are presently using may accept it without complaint, other makes, including future versions of your present make, may reject it or worse.
Rule does expect one or more targets, there really are no two ways about it in the docs. For instance GNU make docs notation:
targets : prerequisites
recipe
Or 1p section manpage:
target [target...]: [prerequisite...][;command]
Illumos:
target [:|::] [dependency] ... [; command] ...
[command]
...
After all how would you refer to a target that had no name? I would assume no target rule should be an error...
However, I've tried different flavors of make (BSD, Illumos, GNU) and with varying degree of leniency (GNU make for instance seemed to also not care about syntax of prerequisites any more) or lack thereof they all seemed to have processed the line and possibly following tab indented block as a rule (with a recipe)... which then was ignored (also for the purpose of determining the default target).
I guess a rationale for this actually being consider valid Makefile... you could end up in this situation also with:
$(VAR):
#echo foobar
other:
#echo barbaz
In case VAR is undefined or empty, you'd end up with a such empty target as well.

make file, what is the idea behind coining of special variables as described below

In make file, for one example, $# is the name of the file being generated,
Find it difficult to remember these special variables
Is there a systematic way that this been coined?
or How this can be remembered?
No, there is no mnemonic that I can think of. The list of automatic variables is documented here. There are really only three that are typically used, so they're not that hard to remember once you get used to them: $# for the target, $< for the first prerequisite, and $^ for all the prerequisites. The others are more for special situations.
What you really need is a cheat-sheet. There are plenty available (search for makefile cheat sheet , and maybe specify the variant, eg gnu).
As an example: http://www.cheatography.com/bavo-van-achte/cheat-sheets/gnumake/

Can MinGW Make be sped up without disabling implicit rules?

GNU Make under MinGW is known to be very slow under certain conditions due to how it executes implicit rules and how Windows exposes file information (per "MinGW “make” starts very slowly").
That previous question and all other resources on the issue that I've found on the internet suggest working around the problem by disabling implicit rules entirely with the -r flag. But is there another way?
I have a "portable" Makefile that relies on them, and I'd like to make it so that it does not take around a minute to start it up each time, rather than having to get the Makefile owner to alter it just for me.
You should use make -d to see all the things make is doing and try to see where the time is going. One common reason for lengthy make times are match-anything rules which are used to determine whether or not a makefile needs to be rebuilt. Most of the match-anything rules CAN be removed; they're rarely needed anymore.
You can add this to your makefile and see if it helps:
%:: %,v
%:: RCS/%,v
%:: RCS/%
%:: s.%
%:: SCCS/s.%
And, if you don't need to auto-create your makefile you can add:
Makefile: ;
(also put any included makefiles there that you don't need to auto-create).
ETA
It seems your real question can be summed up as, "why does make take so much longer to start on Windows than on Linux, and what can I do to fix that without changing makefiles?"
The answer is, nothing. Make does exactly the same amount of work on both Windows and Linux: there are no extra rules or procedures happening on Windows that could be removed. The problem is that Windows NTFS is slower than typical Linux filesystems for these lookups. I know of no system setting, etc. that will fix this problem. Your only choice is to get make to do less work so that it's faster, and the only way to do that is by removing built-in rules you don't need.
If the problem is you really don't want to edit the actual makefiles, that's simple enough to solve: just write the rules above into a small separate makefile, maybe something like speedup.mk, then set the environment variable MAKEFILES=speedup.mk before invoking make. Make will parse that makefile as well without you having to change any makefiles.

Nontrivial pattern replacement in Makefile

I want to make a rule that transforms files in the format 1/2/112.jpg into 1/2/th/112_s.jpg.
However, patsubst is too weak:
$(patsubst /%.jpg,/th/%_s.jpg,$(var))
does not work, since patsubst wants to match the whole pattern on the string.
Is this doable somehow?
(I only use GNU make, so I never bother to learn what features are specific to it. This solution may require GNU make.)
Take it apart, alter, and reassemble.
$(dir $(var))$(patsubst %,th/%_s,$(basename $(var))).jpg

Resources