Escape program names in automake - automake

How can I escape program names in GNU automake? For example, the following works:
lib_LTLIBRARIES = libc.la
libc_la_SOURCES = source.cc
However, if I try to use the symbol 'plus' (+) on the program name, like this:
lib_LTLIBRARIES = libc++.la
libc++_la_SOURCES = source.cc
Make will respond with:
make[1]: *** No rule to make target 'libc++.c', needed by 'libc++.lo'. Stop.
It seems like it is not finding the SOURCES variable. I tried prepending the plus sign with the dollar ($), backslash (\) and double backslash (\\), without success.

automake will simply replace all uncanny characters with underscores _, to generate variable names.
So to reference your libc++.la library in variable names, use the libc___la prefix (two (2) underscores for the + characters, another one (1) underscore for the . character).
Your Makefile.am snippet will thus look like:
lib_LTLIBRARIES = libc++.la
libc___la_SOURCES = source.cc

Related

gnu make hash symbol in the middle of string

I'm trying to print out the perforce file version of the make file when it's executed. I'm using the $Id$ tag, which expands to $Id: //repository/path/check.make#6 $ or the like and I want to print //repository/path/check.make#6 to a file (currently using echo). I can't figure out how to get make to take the # as part of the string and not the beginning of a comment. I tried:
str1 = $(subst \#,\\\#,'$Id: //repository/path/check.make#6 $')
and other variations but I keep getting:
unterminated call to function `subst': missing `)'. Stop.
It would help if you provided a full example of what you want. I don't really understand why you're trying to subst a hash with a backslash hash. If you showed us a full example, including how you get the string and also what you want to do with the variable ar1, we could actually give you advice.
But, the way to use hashes in GNU make is to put them into a variable:
HASH := \#
$(info HASH = $(HASH))
That's all I can say without more info.
ETA
Yes, I'm very familiar with keyword expansion... it originated with SCCS/RCS back in the day :).
I see, you mean, you want to put the $Id$ into your makefile, then when your makefile is checked out the value will be replaced. That wasn't clear to me.
I'm sorry to say that what you want to do is close to impossible. The problem is that you can't escape the value in the makefile because you're not writing the value into the makefile, Perforce is. And Perforce is not escaping it.
You have only two options that I can see:
First, don't try to put this into a make variable. There are many ways to do this, depending on what you really want. One way is to create a header file that contains const char* foo = "$Id$"; and let that be replaced. If you really want the ID of the makefile, but you only need it within a certain recipe, you can put it directly into that recipe:
myrecipe: ; echo '$$Id$$'
(I'm not actually sure the $$ trick here will work, it depends on how Perforce replaces things... if it doesn't you can use echo '$Id$x' you'll lose the dollar signs but keep the rest).
The only other option is to upgrade your version of GNU make to the latest (4.3). In that release, some broken handling of hash characters in the $(shell ...) function was fixed, which means you can use:
var1 := $(shell echo '$$Id$$')
and it will work (same caveats, and solutions, for $$ here as above).
Maybe I didn't get you correctly but the following works for an outside actor replacing $Id$ without escaping:
define PERFORCE_ID
$Id$
endef
PERFORCE_ID := $(word 2,$(value PERFORCE_ID))
$(info $(PERFORCE_ID))
As a test, I simply put in the text substitution from Perforce myself:
define PERFORCE_ID
$Id: //repository/path/check.make#6 $
endef
PERFORCE_ID := $(word 2,$(value PERFORCE_ID))
$(info Perforce id is: $(PERFORCE_ID))
Output:
Perforce id is: //repository/path/check.make#6
You can't have an unescaped literal # in a make assignment and not have it be interpreted as a comment character. But as a hack, you can have the shell extract this token from the current Makefile.
# $Id: //repository/path/check.make#6 $
str1 := $(shell sed '/[$$]Id[$$:]/!d;s/^\# [$$]Id: \(.*\) [$$].*/\1/' Makefile)
The sed script looks for the $Id$ or $Id: token in the Makefile itself by way of a regex which doesn't match itself; the doubled dollar sign is how you put a literal dollar sign in a Makefile. It extracts the contents of the field, and make assigns the output to str1. Because there is no literal # in the code which assigns the variable, no further escaping is necessary.
Demo: https://ideone.com/hWjnCp
This requires GNU Make, but that's apparently what you are using already. (Please tag such questions explicitly as gnu-make.)

Can a makefile pattern match contain both prefix and suffix as vairables?

I am trying to match a pattern in the rule to compile and generate binary files from c files like below
$(BIN_TARGETS) : $(BIN_DIR)/%.$(BIN_EXT) : $(BIN_DIR)/%.$(EXE_EXT)
I see the following error
../../rules/mkrules.mk:13: target 'bin/hello.bin' doesn't match the target pattern
I have tried the below and it seems to work
$(BIN_TARGETS) : $(BIN_DIR)/%.bin : $(BIN_DIR)/%.elf
I would like to make the file name extensions not fixed.
I have assigned the variables as shown below at the start of makefile
EXE_EXT = .elf
BIN_EXT = .bin
I see here it is mentioned
"Note that expansion using ‘%’ in pattern rules occurs after any variable or function expansions, which take place when the makefile is read."
So, aren't variables supposed to be expanded before % is substituted?
The answer is simple:
EXE_EXT = .elf
BIN_EXT = .bin
$(BIN_TARGETS) : $(BIN_DIR)/%.$(BIN_EXT) : $(BIN_DIR)/%.$(EXE_EXT)
So $(BIN_DIR)/%.$(BIN_EXT) expands to $(BIN_DIR)/%..bin (note double periods).
You'll have to decide whether you want the period either in the variable or in the pattern, but it can't be in both places.

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.

Special character removal under GNU make

For my make file I use a variable named VERSION_NUMBER which is passed from a build environment in the following form:
VERSION_NUMBER='#258'
Now, I wish to extract the number 258 from this string under make, but I'm unable to do so due to the special character '#'.
I've tried the following and it works (for now assume that the variable is locally defined in the makefile and not passed from the build environment):
VERSION_NUMBER:='\#258'
empty:=
quote:='
space:= $(empty) $(empty)
pound:=\#
extract:= $(subst $(quote),$(empty),$(VERSION_NUMBER))
$(info $$extract is [${extract}]) # Debug print
extract:= $(subst $(pound),$(empty),$(extract))
$(info $$extract is [${extract}]) # Debug print
This prints out the following:
$extract is [#258]
$extract is [258]
The problem however is that here I'm using the VERSION_NUMBER as '\#258' instead of '#258' and unfortunately I can't get it to work in any other way.
The backslash is here to escape the # symbol, so as it's not interpreted by make. I don't see where's your problem, because in your case it will not appear in your string.
Anyway you already hold the solution, which works for a var declared in your Makefile as well as for a var coming from the call to make. The only difference is that inside your Makefile you have to escape the # character.
Take this simple Makefile :
VERSION_NUMBER:='\#258'
pattern:=\#
# Remove the quotes and the hash symbol
PARSED_VERSION_NUMBER = $(subst ',,$(subst $(pattern),,$(VERSION_NUMBER)))
all:
#echo Version number is $(VERSION_NUMBER)
#echo Parsed version number is $(PARSED_VERSION_NUMBER)
If you call it with make all you will have this output :
Version number is '#258'
Parsed version number is 258
See how the backslash disappeared.
Now if you call it with make all VERSION_NUMBER='#286' you will have this output :
Version number is '#286'
Parsed version number is 286
As you can see it's exactly the same behavior.

How to specify a pathname with space in middle to prefix in a makefile

In a Makefile for a gnu software distribution, I want to change the value of prefix to be a pathname with some whitespaces in the middle. When I do that, make reports error at the assignment to prefix. When I double quote the pathname, make still doesn't work. How shall I assign the pathname with whitespaces to prefix?

Resources