I am learning Gnu Make and don't understand the construction. Actually wondering what parameters are in quotes? This entry is the first in the Makefile.
LIBLORAGW_VERSION := `cat ../VERSION`
Backticks ` ` are shell syntax to return enclosed command output as a string.
So that, this line executes cat ../VERSION, grabs its output and assigns it to LIBLORAGW_VERSION
Upd: Yes, the explanation above is a simplified "it looks like" but is not correct in details. See MadScientist's comment and try this
DATE=`date`
all:
$(info DATE is $(DATE))
#echo DATE is $(DATE)
Related
I'm looking to record the exact commands used to build artifacts within a makefile. I'd like this to be stored in a file for later consumption. I am running into issues due to quotes. Basically, what I want is:
define record_and_run_recipe
#echo '$(2)' > $1
$2
endef
all:
$(call record_and_run_recipe,out.cmd,\
#echo 'hello world "$$1"' )
cat out.cmd
I would like this to output (exactly)
#echo 'hello world "$1"'
Of course, the quotes end up matching with the quotes in the expansion of the variable, and this messes everything up. (I get #echo hello world instead). Bash doesn't like '\'' either, so I can't simply do $(2:'=\'). I also seem to have issues with , characters...
I'm not looking to debug the entire makefile, just dump a couple of recipes. I'm wondering if anyone has a robust way of accomplishing this.
As I said in my comment above, you can use GNU make's $(info ...) function. It's not exactly clear from your example above what you want to do; why are you trying to put the output into a file, then cat it? Is that important?
If you can't use info, the canonical way to handle quoting in shell is to surround the string with single quotes, then replace every single quote with '\''. You say "bash doesn't like" that, but I don't know what that means. Normally you'd do something like:
define record_and_run_recipe
#echo '$(subst ','\'',$2)' > $1
$2
endef
As far as commas you will absolutely have a problem with commas if you want to use the $(call ...) function. The only way to avoid that is to put the string into a variable, like:
output = foo, bar
... $(call blah,$(output))
to "hide" the comma from call.
Makefile:
.PHONY: all
SHELL:=/usr/bin/env bash
all:
$(eval x=$(shell cat file))
#echo "$x"
File:
foo
bar
Output:
foo bar
How do I get the contents of the file into the make variable without losing the newlines?
You can't do this with shell, as described in its documentation.
If you have a sufficiently new version of GNU make, you can use the file function however.
Make converts newlines from shell outputs to spaces (see here):
The shell function performs the same function that backquotes (‘`’)
perform in most shells: it does command expansion. This means that it
takes as an argument a shell command and evaluates to the output of
the command. The only processing make does on the result is to convert
each newline (or carriage-return / newline pair) to a single space. If
there is a trailing (carriage-return and) newline it will simply be
removed.
So, you cannot preserve spaces from the $(shell) command directly. That being said, make does allow multiline variables using define -- but beware, attempting to use such variables is problematic. Consider:
define x
foo
bar
endef
all:
#echo "$x"
Make expands the $x in place, and you end up with:
all:
#echo " foo
bar"
(where the newline is considered the end of the recipe line..).
Depending on what you want this for, you may be able to get around this is using a bash variable:
all:
#x=$$(cat file); \
echo $$x
Or potentially storing your output in a file, and referencing that when necessary.
all:
eval (cat file >> output.txt)
cat output.txt
(and yes, the last one is convoluted as written, but I'm not sure what you're trying to do, and this allows the output of your command to be persistent across recipe lines).
If the file contents are ensured not to contain any binary data, and if you're willing to to extra processing each time you access the variable, then you could:
foo:=$(shell cat file | tr '\n' '\1')
all:
#echo "$(shell echo "$(foo)" | tr '\1' '\n')"
Note that you cannot use nulls \0, and I suspect that probably means there's a buffer overflow bug in my copy of Make.
I am writing a Bash script that creates a CMakeLists.txt file for a project.
The problem arises at this portion:
echo "file(GLOB projSRC src/*.cpp)" >> CMakeLists.txt
After that, I need the program to output ${SOURCES} into CMakeLists.txt
I don't mean a variable in the script named SOURCES, I mean it should actually write the plaintext ${SOURCES}.
What I mean is, the final file should look this like:
arbitrary_command(target PROJECT sources ${SOURCES})
and not like:
arbitrary_command(target PROJECT sources [insert however bash messes it up here])
How can I do this in my Bash script?
Use single quotes, not double quotes, for a literal string:
echo 'file(GLOB ${projSRC} src/*.cpp)' >> CMakeLists.txt
That said, you might consider using a heredoc (or even a quoted heredoc) in this case, to write the entire file as one command:
cat >CMakeLists.txt <<'EOF'
everything here will be emitted to the file exactly as written
${projSRC}, etc
even over multiple lines
EOF
...or, if you want some substitutions, an unquoted heredoc (that is, one where the sigil -- EOF in these examples -- isn't quoted at the start):
foo="this"
cat >CMakeLists.txt <<EOF
here, parameter expansions will be honored, like ${foo}
but can still be quoted: \${foo}
EOF
You can also have multiple commands writing output to a single redirection, to avoid paying the cost of opening your output file more than once:
foo=this
{
echo "Here's a line, which is expanded due to double quotes: ${foo}"
echo 'Here is another line, with no expansion due to single quotes: ${foo}'
} >CMakeLists.txt
May be I don't understand your question...
But
echo \${SOURCES}
will print
${SOURCES}
for you.
I found this as a suggestion of how to store the output of "eval" into a variable called line. So, what's the use of \$$?
command = "some command"
line = $(eval \$$command)
The \$ prevents the shell from trying to treat the $ as the beginning of a parameter expansion. However, the code as a whole doesn't do anything useful. After fixing the whitespace issues and adding a real command to the example, your code looks like
command="ls -l"
line=$(eval \$$command)
command is simply a string ls -l. To evaluate the next line, the shell first evaluates the command substitution. The first step is to expand the parameter command, yielding line=$(eval \$ls -l). Quote removal gets rid of the backslash, so eval receives the arguments $ls and -l. Since ls presumably is not a variable, $ls is expanded to the empty string, and eval is left simply with -l to execute. There being no such command, you get an error.
You might think, then, that the correct form is simply
line=$(eval $command)
or slightly better
line=$(eval "$command")
That will work for simple cases, but not in general. This has been hashed over many times in many questions; see Bash FAQ 50, "I'm trying to put a command in a variable, but the complex cases always fail!" for the details.
To answer the literal question, though, \$$ is useful for outputing the string $$, instead of expanding it to the current process ID:
# The exact output will vary
$ echo $$
86542
# Literal quotes
$ echo \$\$
$$
# Escaping either quote is sufficient
$ echo \$$ $\$
$$ $$
I am writing a shell program to output another shell program to be evalled later. Is there some common shell program to print shell escaped for a string?
I'm not sure I understand you question. But the %q option of printf might be what you are looking for.
%q Output the corresponding argument in a format that can be reused as shell input
printf %q 'C:\ProgramFiles is a Windows path;'
outputs C:\\ProgramFiles\ is\ a\ Windows\ path\;
(In this example, simple quotes are needed – comment of Gordon Davisson – but this doesn't matter if you print from a variable or the output of a command.)
You could use single quoted string as this is evaluated without any substitution.
For example the following commands are equivalent
cat abc\ hi.txt
cat 'abc hi.txt'