makefile - escape parentheses - windows

I have a folder on my HD which contains parentheses in its name. Like: C:/stuff (really cool)/. The make $(wildcard ..) function does not work properly with this directory.
$(wildcard C:/stuff (really cool)/*.jpg)`
evaluates to no results at all. I guess this is due to the fact that the closing parentheses in the directory-name is treated as the closing parentheses for the $(wildcard ..) function. Escaping the ( and ) with a backslash does not work. What also does not work, is putting the directory-name into a variable and then using the wildcard function.
DIR = C:/stuff (really cool)
all:
#echo "$(wildcard $(DIR)/*.jpg)"
No results at all, again.
How should I properly escape the parentheses?

The following does not work, kept to warn others:
Special characters are typically "protected", or escaped, with enclosing quotes. To create a variable with parenthesis, you use double quotes.
DIR = "C:/stuff (really cool)"
In your case, the biggest problem is the spaces that will result in your path being broken down into several parts instead of one.
This works:
GNU Make lets you escape spaces with \\ so your call to $wildcard would turn into
$(wildcard C:/stuff\\ (really\\ cool)/*.jpg)

You did not mention in what kind of environment you are running, but both of the following print mechanism work for me from a regular DOS prompt as well as from msys/mingw:
DIR = C:/stuff\ (really\ cool)
$(info Files in subdir are: $(wildcard $(DIR)/*.jpg))
all:
#echo "Files in subdir are: $(wildcard $(DIR)/*.jpg)"
The double quotes around the echo-ed expression are only necessary for msys/mingw.

Related

Makefile string with spaces

var := 'C:/some/path here' labas
all:
#echo $(words $(var))
This returns 3.
How to make it return 2? Or make does not work the way I think??
Make definitely doesn't work the way you think, if you think that make has any interest in quotes of any type :). Make ignores (i.e., treats as normal characters like any other) both single- and double-quote characters in virtually every situation, and all make functions work in simple whitespace delimiters without regard to quote characters.
In general, it's not practical to use make with any system that requires spaces in target names. It just doesn't work: too much of make is based on whitespace as a separator character and there's no general, common way to escape the whitespace that works everywhere.
In your very particular case you can play a trick like this:
E :=
S := $E $E
path := C:/some/path here
xpath := $(subst $S,^,$(path))
var := $(xpath) labas
all:
#echo $(words $(var))
#echo $(subst ^,$S,$(var))
Basically, this creates a variable $S which contains a space, then it substitutes all spaces in the variable path with some other, non-space character (here I chose ^ but you can pick what you like, just note it has to be a character which is guaranteed to not appear in the path).
Now this path doesn't contain whitespace so you can use it with make functions.
This has major downsides: not only the complexity visible here, but note these paths cannot be used in target names since they won't actually exist on disk.
In general, you should simply not use paths containing whitespace with make. If you must use paths containing whitespace, then very likely make is not the right tool for you to be using.

Using notdir within substitution reference as opposed to patsubst

In my makefile, I am stripping the file paths from a list of objects, and replacing that path with a build directory.
Using patsubst, this seems to work fine, however using substitution replacements it doesnt seem to work, e.g:
OBJS=/path/to/obj1.o /another/path/obj2.o
BUILD_DIR=build
$(info patsubst = $(patsubst %, $(BUILD_DIR)/%, $(notdir $(OBJS))))
$(info substref = $( $(notdir $(OBJS)):%=$(BUILD_DIR)/%) )
The output of this is :
patsubst = build/obj1.o build/obj2.o
substref =
Is this a shortcoming of substitution references or am I doing something wrong?
Im using GNU Make 4.1, but would like my makefile to be valid with other/older versions.
That syntax is not right. A substitution reference requires a variable name in the first part, and make will expand that variable and the substitution will be performed on the expansion. You are giving $(notdir $(OBJS)) as the thing to substitute on, and that expands to a set of strings, not a variable name.
patsubst works fine here so why do you need to use a substitution reference?

Does any make variant support dependency filename with colon?

I saw this question: Escaping colons in filenames in a Makefile, which is explicitly in reference to GNU make. The accepted answer references a discussion on the bug-make#gnu.org mailing list which states pretty definitively that it's impossible; GNU make does not support files with colons or spaces in the name.
Fair enough. But is there any make variant that does? I'm guessing the answer is still no but I wanted to see if there's an answer more definitive than my guess.
You can kind of use colons but it requires extra work. You can use a colon in a target or a prerequisite if you escape it with a backslash... but then it's escaped with a backslash if you use that variable in your recipe, too:
FOO = biz\:baz
all: foo\:bar $(FOO) ; #echo '$#: $^'
foo\:bar: ; #echo '$#'
$(FOO): ; #echo '$#' '$(FOO)'
This gives:
foo:bar
biz:baz biz\:baz
all: foo:bar biz:baz
Note how the expansion of $(FOO) (and only that!) contains the backslash. So, while it's do-able, it's problematic. As you start to work with it you'll run into all kinds of issues.
As for whitespace, you can also escape that in targets and prerequisites with backslashes. However, again the problem is that the backslashes are included sometimes in the recipe and not other times. Whitespace has an even bigger problem, because the functions make uses to manipulate words are not backslash-aware so things like addsuffix, etc. will not work right.
I'm not aware of any general-purpose make variant that handles this better, at the moment.

How to prevent GNU Make from executing when a variable definition has trailing spaces

I had a simple variable definition in my makefile:
THIS := ~/edan
and it had trailing spaces in the line.
Later, when I defined another variable in terms of this one:
WARES := $(THIS)/wares
the actual variable defined was /home/directory/edan wares
and then the make clean rule removed /home/directory/edan instead of what I wanted it to.
How can I prevent a makefile from executing if a line has trailing spaces?
Although you could write the Makefile so that it checks the variable for trailing whitespace and exits if it finds some, there are better ways of dealing with this situation.
In this instance, I would recommend using the addsuffix function to catenate $(THIS) and /wares instead of doing it manually. The addsuffix function will strip the trailing whitespace for you. In other words:
WARES := $(addsuffix /wares,$(THIS))
If you really want it to exit if it discovers trailing whitespace, you could do this:
THIS := ~/edan
ifneq "$(THIS)" "$(strip $(THIS))"
$(error Found trailing whitespace)
endif

GNU Make: How to call $(wildcard) within $(eval)

I'm trying to create a generic build template for my Makefiles, kind of like they discuss in the eval documentation.
I can't seem to get the wildcard function to work within an eval. The basic code I'm having issues with looks like this.
SRC_DIR = ./src/
PROG_NAME = test
define PROGRAM_template
$(1)_SRC_DIR = $(join $(SRC_DIR), $(1)/)
$(1)_SRC_FILES = $(wildcard $$($(1)_SRC_DIR)*.c)
endef
$(eval $(call PROGRAM_template, $(PROG_NAME)))
all:
#echo $(test_SRC_DIR)
#echo $(test_SRC_FILES)
#echo $(wildcard $(wildcard $(test_SRC_DIR)*.c)
When I run make with this, the output is
./src/test
[correct list of all .c files in ./src/test/]
Basically, the wildcard call within PROGRAM_template is not being eval'd as I expect it. The call results in an empty list.
The join call is being eval'd correctly though.
So, what am I doing wrong? My guess is that
$$($(1)_SRC_DIR)
is not correct, but I can't figure out the right way to do it.
EDIT
Once this was solved, it didn't take long for me to hit another issue with eval.
I posted it as a new question at
Workaround for GNU Make 3.80 eval bug
You need to double escape virtually all of the functions and variables when you use eval. In most cases, the only things that don't need to be double-escaped are function arguments (because the call function will fully expand them). In this case, you technically don't need to double-escape join or SRC_DIR either, but it will simplify your life if you just always double-escape all variables and functions when using eval.
The reason you need the double escapes is that expansion happens twice when using eval. The eval function itself performs expansion, and then expansion is done again when the block is finally parsed as makefile syntax (i.e. when it is actually evaluated).
The way you've got it written, wildcard is invoked on the string literal $( test_SRC_DIR)*.c. If you want, you can see this for yourself by replacing wildcard with info in your version and see what happens.
You need to hold off on actually invoking wildcard until the second expansion, so that it's argument is the result of the expansion of $(test_SRC_DIR).
Try this:
SRC_DIR = ./src/
PROG_NAME = test
define PROGRAM_template
$(1)_SRC_DIR = $$(join $$(SRC_DIR),$(1)/)
$(1)_SRC_FILES = $$(wildcard $$($(1)_SRC_DIR)*.c)
endef
$(eval $(call PROGRAM_template,$(PROG_NAME)))
all:
#echo $(test_SRC_DIR)
#echo $(test_SRC_FILES)
#echo $(wildcard $(test_SRC_DIR)*.c)
EDIT: After posting this, I thought I'd better test it out to make sure it actually works. In doing so, I discovered another problem. You should avoid putting spaces between the comma and argument when calling functions. It causes a literal space character to be prepended to the argument that is passed to the function and leads to unintended results. I've removed the spaces after the commas in the function calls in my version (while this isn't a problem for the call to join, I removed the space there as well just because it's a good habit to get into).

Resources