On Thu, Jul 18, 2024, at 5:09 AM, Tijl Coosemans wrote:
> Automake 1.17 produces a warning for the use of \# here:
>
> https://github.com/ddclient/ddclient/blob/d88e6438efbc53e977546693f6835f7517072a06/Makefile.am#L22

For reference, the construct in question is

subst = sed \
        -e 's|@PACKAGE_VERSION[@]|$(PACKAGE_VERSION)|g' \
        -e '1 s|^\#\!.*perl$$|\#\!$(PERL)|g' \
        -e 's|@localstatedir[@]|$(localstatedir)|g' \
        [etc]

and the warning triggers on the '1 s|^\#\!...' line.

> Is use within quotes also not portable?

I could be wrong about this, but I don't think any implementation of Make
pays _any_ attention to shell quotation in commands.  Therefore, no, this
is not portable.  If there was a portable way to define a Make variable
that expanded to a single # then you could write

subst = sed \
        -e 's|@PACKAGE_VERSION[@]|$(PACKAGE_VERSION)|g' \
        -e '1 s|^$(HASH)!.*perl$$|$(HASH)! $(PERL)|g' \
        -e 's|@localstatedir[@]|$(localstatedir)|g' \
        [etc]

but I think the only portable way to define that variable is from
outside the Makefile, e.g. by typing

make 'HASH=#'

every single time, ick.

My default recommendation for this sort of thing - for *any* circumstance
where you find yourself embedding more than a couple lines of shell script in
a Makefile, frankly - is that you split out the _entire_ troublesome construct
into a standalone script, like, put this in build-aux/subst

---
#! /bin/sh

set -e -u

if [ $# -ne 1 ]; then
    printf 'usage: %s out-file\n' "$0" >&2
    printf 'PACKAGE_VERSION, PERL, CURL, srcdir, localstatedir,\n' >&2
    printf 'runstatedir, and sysconfdir must be set in environment\n' >&2
    exit 1
fi

out="$1"
tmp="${out}.tmp.$$"
trap 'rm -f $tmp' 0

if [ -f "${out}.in" ]; then
    in="${out}.in"
elif [ -f "${srcdir}/${out}.in" ]; then
    in="${srcdir}/${out}.in"
else
    printf '%s: error: %s not found in . or %s\n' \
           "$0" "${out}.in" "$srcdir" >&2
    exit 1
fi

sed < "$in" > "$tmp" \
    -e 's|@PACKAGE_VERSION[@]|'"${PACKAGE_VERSION}"'|g' \
    -e '1 s|^#!.*perl$|#! '"${PERL}"'|g' \
    -e 's|@localstatedir[@]|'"${localstatedir}"'|g' \
    -e 's|@runstatedir[@]|'"${runstatedir}"'|g' \
    -e 's|@sysconfdir[@]|'"${sysconfdir}"'|g' \
    -e 's|@CURL[@]|'"${CURL}"'|g'

if [ -x "$in" ]; then
    chmod +x "$tmp"
fi
mv "$tmp" "$out"
trap '' 0
---

and then change your $(subst_files) rule to

---
$(subst_files): Makefile build-aux/subst
        PACKAGE_VERSION="$(PACKAGE_VERSION)" \
        PERL="$(PERL)" \
        CURL="$(CURL)" \
        srcdir="$(srcdir)" \
        localstatedir="$(localstatedir)" \
        runstatedir="$(runstatedir)" \
        sysconfdir="$(sysconfdir)" \
        $(SHELL) $(srcdir)/build-aux/subst $@
---

and then you don't have to worry about layering Makefile quotation
on top of shell quotation.

zw

Reply via email to