Can GNU make handle spaces? - makefile

I have a makefile that has C INCLUDES with spaces in them. There is no way for me to get around having to have the spaces in the file names. Is there any way to have spaces in file names with gnu make?

Make has some basic support for this by escaping spaces in filenames, in that the following Makefile will correctly compile and recompile the C file foo bar.c:
foo\ bar: foo\ bar.c
gcc -o "${#}" "${<}"
However, you have to be super-careful in quoting every command you run, and variables that are space-separated lists of files—e.g., SRCS, LIBS—won’t work, although it’ß possible that with enough hacking using Make text functions you can parse out the quotes and get everything working…
So while there is rudimentary support for spaces in filenames in rules and patterns, anything complicated is going to be an awful lot of very hard and frustrating work.

Related

Make error: *** multiple target patterns. Stop

this is my first time posting here, so sorry if this ends up in the wrong place. I am trying to compile some code I've downloaded from a GitHUb repository and am running make from the MSYS Shell. There is a problem with the makefile that has the common make rules. When I run make, I get the following error:
C:\Mios32/include/makefile/common.mk:143: *** multiple target patterns. Stop.
Since I'm a complete beginner with regard to make and makefile, I can't find the problem. Here's the code from common.mk file from line 152 to 154:
# rule to create .elf file
$(PROJECT_OUT)/$(PROJECT).elf: $(ALL_OBJS)
#$(CC) $(CFLAGS) $(ALL_OBJS) $(LIBS) $(LDFLAGS) -o$#
Lmk if I need to upload the whole common makefile. Thanks
You can find documentation on error messages in the GNU make manual.
This error means that you have a static pattern rule, with multiple patterns (% characters) in the target. Your line is here:
$(PROJECT_OUT)/$(PROJECT).elf: $(ALL_OBJS)
The only way to know what the problem is, is to find the values of the PROJECT_OUT, PROJECT, and ALL_OBJS variables. No doubt they contain colon characters and/or percent characters.
The make program is a tool developed on UNIX, well before "driver letters", backslash as directory separators, etc. were popularized by Microsoft. As such, its syntax is geared towards UNIX systems where : is not expected in pathnames, backslash is an escape character, etc.
If you want to build software on Windows that was developed for POSIX systems such as GNU/Linux and MacOS, you'll have to do some work translating pathnames between them. You should not use drive-letter-qualified paths when working with makefiles, and you should not use any paths containing whitespace, and you should always use forward-slashes (/) as directory separators, never backslashes.

How to make "%" wildcard match targets containing the equal sign?

The makefile wildcard system doesn't seem to match targets if they contain the equal sign. Is there a way to work around this deficiency? Some flag or setting or rule to escape the equal sign? I know I can just not use the equal sign but I'd prefer to fix this idiosyncrasy of make if possible.
Here's an example of what I mean
$ cat Makefile
all:
echo Dummy target
b_%:
echo $#
$ make b_c=1
echo Dummy Target
$ make b_c1
echo b_c1
The first make command does not match b_% even though it should. I also wasn't able to find documentation for exactly what is supposed to be matched by the % wildcard. Any pointers? My make version is
$ make --version
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This program built for i386-apple-darwin10.0
The problem here is not with the % syntax, but with the fact that any command-line argument with an equals sign in it is interpreted as a variable assignment.
You should find that if you add the dependency all: b_c=1, then make all will generate the file just fine.
There are restrictions on what file names you can use with make -- they can't contain spaces or newlines, and e.g. backslashes are problematic, too (though not completely impossible to accommodate for simple use cases).
If you absolutely have to have a file named like this, my suggested workaround would be to use a different name internally, and then symlink it to the external name as the last step of the make recipe.

What does $(#:.h=.h.d) mean in GNU make?

I'm maintaining a (horrendously complicated) Makefile, and in some recipes I saw the following:
$(#:.h=.h.d)
I have absolutely no clue as to how to interpret this, or whether there's any documentation on those characters. Obviously, Google won't work because it thinks I'm typing gibberish.
I saw a related question about #:H, but this is GNU make instead of BSD make.
This is a variable reference with a substitution: $(VAR:FROM=TO). It means the value of the variable VAR, but for each whitespace-separated word in the value, if the word ends with the suffix FROM, it is replaced by the suffix TO.
In this case, the variable is #, the filename of the target of the rule (with special handling for archive members). If the target of the rule ends with .h, then .d is added at the end.
A common file naming convention is to use .d for a list of dependencies. The file foo.h.d presumably contains dependencies for rules to compile source files that include foo.h (so, in practice, foo.d.h would contains foo.h and the headers that it includes).
By the way, this is portable syntax. There is another slightly more wordy syntax which is common (supported by both GNU and BSD make) but not POSIX: $(#:%.h=%.h.d) where the % acts as a wildcard; this syntax allows a prefix to be substituted in addition to a suffix. There is yet another syntax to do the same thing in GNU make: call the function patsubst, written $(patsubst %.h,%.h.d,$#) — it's arguably less cryptic, but because the portable syntax has existed for decades, it's commonly used even in makefiles that otherwise require GNU make.

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.

can't use variable in Makefile

My main Makefile call config.mk
include $(TOPDIR)/config.mk
then config.mk include some sentences like this:
ifdef CPU
sinclude $(TOPDIR)/cpu/$(CPU)/config.mk
endif
ifdef SOC
sinclude $(TOPDIR)/cpu/$(CPU)/$(SOC)/config.mk
endif
I have prepared these two tree and necessary config.mks. But for "SOC", whose value is "versatile", there is a problem. If I put "versatile" directly here, it could find the file and everything is fine; but when I use $(SOC), il will meet an error, and say
/../../../cpu/arm926ejs/versatile: is a folder, stop
Anyone know what the problem is ??
Are you sure you gave the exact error message? What version of make are you using? That error doesn't look like anything GNU make would print.
Anyway, I'll bet the problem is that your assignment of the SOC variable has trailing whitespace. According to the POSIX definition of make, leading whitespace before a variable value is removed, but trailing whitespace is preserved. That means, for example, if you write your makefile like this:
SOC = versatile # this is the versatile SOC
then make will remove the comment, but keep the space, so the value will be 'versatile' (space at the end). This means when the value is expanded in the sinclude line you get:
sinclude $(TOPDIR)/cpu/$(CPU)/versatile /config.mk
which make interprets as trying to include two different values, the first of which is a directory.
Even if you don't have a comment there, any trailing whitespace will be preserved. When editing makefiles you should try to put your editor into a mode where it flags trailing whitespace, or even better removes it automatically. GNU Emacs, for example, can do this.

Resources