help-make
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: getting the value of a make variable into a file


From: John Dill
Subject: Re: getting the value of a make variable into a file
Date: Fri, 8 Apr 2011 13:33:45 -0400

>Is there by any chance a clever way of getting the value of a variable
>into a file without exposing it to a shell? Eg some variant of
>
>foo:
>        @echo $(var) > file
>
>I have some text which is potentially quite convoluted with single and
>double quotes and backslashes and literal $ and so on. It needs to get
>into a file and I'm fighting with shell and make escaping rules to
>make it work. But if there's some cute trick which can avoid all that
>and, from within make, open the file and write $(var) to it, I'd be
>grateful to know it.
>
>Thanks in advance,
>AK

The nice thing is that any characters stored in a 'make' variable are literal, 
which is why variables are used to provide literal characters that conflict 
with 'make' syntax, like $(space), $(left_parenthesis), ...

There are two components to writing text to a file; using the shell with the 
appropriate command sequence, and applying an escape filter that adds escape 
characters that would otherwise interfere with shell syntax.

Here are some excerpts from my 'make' library that should do the job.

# This variable contains the 'echo' command or equivalent.
__mxl_echo:=echo

# This function appends a single line of text to a file.
#
# In contrast with $(info), there is no native 'make' function to
# write text to a file, so the shell must be relied on to define
# $(fwrite).  There is no 'make' function equivalent to compare
# semantics.  After going back and forth, I decided to leave the
# $(_mxl_sh_text_escape) call out and keep it as close to the shell
# as possible (at least for now).
#
# $1 - The file.
# $2 - The text.
ifeq (sh,$(__mxl_shell))
fwrite=$(_mxl_tr2)$(shell ($(__mxl_echo) "$2") >> $1)
else

ifeq (cmd,$(__mxl_shell))
fwrite=$(_mxl_tr2)$(shell ($(__mxl_echo)/$2) >> $1)
else
fwrite=$(_mxl_tr2)$(call _mxl_shell_not_supported)
endif

endif

Depending on whether the shell is 'sh' based or 'cmd' based, you can see the 
slight syntax differences required to properly write text to a file.  
Unfortunately, this does not help you with shell special characters.

# This function escapes all of the shell special characters in a
# string.  The motivation is to be able to write any literal
# character to the standard output using the shell's echo command.
# The standard output may be redirected to a file or other program
# as well.  The $(info) and $(fwrite) functions require that any
# shell special characters be escaped or the function will fail to
# write out the string properly.
#
# The UNIX shell implementation to write text to the standard output
# is '($(__mxl_echo) "$1")'.  In this implementation, the quotes
# around the argument suppress the behavior of many special
# characters.  The special characters not interpreted as literal
# characters by the shell when in quotes are the backslash '\',
# backtick, '`' and quote '"' characters.
#
# The Windows shell implementation to write text to the standard
# output is a little different.  Its implementation is
# '($(__mxl_echo)/$1)'.  In this implementation, there are no quotes
# around the argument, so all of the special characters will require
# escape characters.  The special characters not interpreted as
# literal characters by the shell are listed below.
#
# caret             '^'
# percent           '%'
# quote             '"'
# left parenthesis  '('
# right parenthesis ')'
# less-than sign    '<'
# greater-than sign '>'
# ampersand         '&'
# pipe              '|'
#
# NOTE: The '$' character for make version 3.79.1 has issues when
# trying to write the literal '$' character to the standard output in
# a shell.  No workaround to the problem has been found at this time,
# so avoid using '$' in text when using this version of make.

# This function escapes the shell characters in a text string.
# $1 - The text.
ifeq (sh,$(__mxl_shell))
_mxl_sh_text_escape=$(subst `,\`,$(subst ",\",$(subst \,\\,$1)))
else

ifeq (cmd,$(__mxl_shell))
__mxl_lp:=(
__mxl_rp:=)

_mxl_sh_text_escape=$(subst |,^|,$(subst &,^&,$(subst >,^>,$(subst <,^<,$(subst 
$(__mxl_rp),^$(__mxl_rp),$(subst $(__mxl_lp),^$(__mxl_lp),$(subst ",^",$(subst 
%,%%,$(subst ^,^^,$1)))))))))

else
_mxl_sh_text_escape=$(call _mxl_shell_not_supported)
endif

endif

Using the following pieces, I was able to combine to two to create an $(info) 
that works without native make support (at the time I was working with 3.79.1 
from MinGW).

ifndef __mxl_have_info

ifeq (sh,$(__mxl_shell))
info=$(shell ($(__mxl_echo) "$(call _mxl_sh_text_escape,$1)") 
$(__mxl_stdout_to_stderr))
else

ifeq (cmd,$(__mxl_shell))
info=$(shell ($(__mxl_echo)/$(call _mxl_sh_text_escape,$1)) 
$(__mxl_stdout_to_stderr))
else
info=$(call _mxl_shell_not_supported)
endif

endif

endif # !__mxl_have_info

You can duplicate similar functionality by incorporating $(_mxl_sh_text_escape) 
into the definition of $(fwrite) if desired, or wrap your argument explicitly.

$(call fwrite,my_file.txt,$(call _mxl_sh_text_escape,<your text here>))

Hope it helps,
John Dill

<<winmail.dat>>


reply via email to

[Prev in Thread] Current Thread [Next in Thread]