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

Re: use of $$ versus $ in makefile and bash



On 8/29/07, Russell L. Harris <rlharris@oplink.net> wrote:
> I am puzzled concerning the use of the symbols "$" and "$$" in a
> makefile.  I do not understand why "$$" is required in some instances,
> and "$" in other instances.

"$" is a special character to make, so in cases where you need make to
pass an actual "$" to something else, you have to use the special
variable "$$".

> I have spent several hours searching through the documentation for
> BASH and for GNU Make, but I have found no answer.
>
> Here are three examples, all taken from the same makefile:
>
> EXAMPLE 1 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
>
>         -ln -s ../journal.cls ../journal.hlx .
>         -(for d in ${SYMLINKDIR};                          \
>          do                                                \
>              pushd $$d &&                                  \
>                ln -sf $(addprefix ../,${SYMLINKTARGET}) .; \
>              popd;                                         \
>          done;)

In this case, "d" is a shell variable defined within a rule.  The
shell refers to it as "$d", but using "$d" in your makefile would
cause make to look for one of its own variables named "d".  "$$d"
becomes a literal "$d" to make, which is then passed to sh.
"$(addprefix ...)" is a make command, and "${SYMLINKDIR}" and
"${SYMLINKTARGET}" are makefile variables, which will be expanded by
make and passed to the shell as literals.

> EXAMPLE 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
>
>         (for d in $$(find .                           \
>                 \( -type d                            \
>                         -name '.svn'     -prune    -o \
>                         -name 'hevea'    -prune    -o \
>                         -name 'metatags' -prune \) -o \
>                    -type d -print);                   \
>         do mkdir --parents ../stageweb/$$d;           \
>         done;)

The difference in this example is that find is being run, and its
stdout returned as a string.  The shell pattern is "$(command)", which
is equivalent to "`command`".  Again, since the "$" is relevant to the
shell, not make, we have to use the special "$$".

> EXAMPLE 3 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
>
>         (for bn in ${CLEANDIR};                      \
>          do                                          \
>              rm -f $(addprefix $$bn/*.,${CLEANEXT}); \
>          done;)
>         rm -f ${CLEANOTHER}
>
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Hopefully this example is clearer now.

> Also, in the third example, does the variable name "bn" have
> significance?  Could the name "b" or "c" or "x" be used instead?  The
> name "f" commonly is used in a for-loop when working with files, and
> the name "d", when working with directories.  The name "bn" appears
> nowhere else in the makefile.

It's defined locally to the for loop (well, not *really* locally, but
effectively).  Any name that isn't already being used should be fine
here.  Not knowing what the context around that snippet is, I couldn't
say if "bn" was chosen for some mnemonic reason.

-- 
Michael A. Marsh
http://www.umiacs.umd.edu/~mmarsh
http://mamarsh.blogspot.com
http://36pints.blogspot.com



Reply to: