[Top][All Lists]

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

Re: make: # in quotes is still treated as comment character

From: Paul D. Smith
Subject: Re: make: # in quotes is still treated as comment character
Date: Sat, 13 Apr 2002 13:35:52 -0400

%% Manoj Srivastava <address@hidden> writes:

  ms> I would claim that the makefile lexer should be string-aware, and
  ms> not process # characters as comments inside quoted strings.  I'm
  ms> not positive this is a bug, but it seems like one to me.

It's not a bug.  Over 20 years of make history, plus various versions of
the POSIX and SingleUNIX standards, not to mention hundreds of thousands
of makefiles already existing, reaffirm that make is not string-aware.

Changing this would not only break huge numbers of makefiles, but it is
not even possible.  What is a "string"?  What is the proper way to
escape things inside a string?  Remember that make doesn't _HAVE_ to
invoke /bin/sh to run commands; you can change the SHELL variable to
anything you like and make will invoke that instead.  So, assuming
Bourne shell semantics, or any other semantics, when dealing with
command scripts is completely outside of make's purview.

  ms> ######################################################################

  ms> If a filename contains a space or a dollar, make/its default rules
  ms> fail to escape or quote the name correctly when invoking the
  ms> compiler.

See above.  There is no way make _can_ quote things correctly for you,
because there is no way that make can know what the right way to quote
things is.  Even if it could know what the right quoting is, as I
mention below, by the time make gets to this point it doesn't know
_itself_ what the right way is to quote the string (except in simple
cases like $< and $@ which are single filenames).

Make is doing exactly the right thing in each of these cases: it
performs its quoting and escaping properly and sends the resulting text
string to whatever interpreter is contained in SHELL.  Since it cannot
know what that interpreter is or how it works, it simply passes exactly
what you gave it.

_All_ of the failures below are due to the way the _shell_ handles the
command line, after make is done with it.

  ms> cc    -c -o pound#file.o pound#file.c
  ms> Pounds work

Hm.  This might not work with other shells; the rules about when the
shell treats a # as a comment and when it doesn't are sometimes subtlely
different between shells.

  ms> cc    -c -o dollar$file.o dollar$file.c
  ms> cc: dollar.c: No such file or directory

Right, because there is no shell variable $file, so "dollar$file.c" is
expanded by the shell to just dollar.c.

  ms> cc    -c -o space file.o space file.c
  ms> cc: cannot specify -o with -c or -S and multiple compilations

Right, because there is no quoting here so these are treated as separate

  ms> Things to note:
  ms>  * 'cc dollar$file.o', $file is not set so cc tries to read 'dollar.c'
  ms> and fails. The $ should have been escaped but there is no way to escape
  ms> it in the Makefile that will work.

Of course there is!  If you are going to be dealing with odd filenames
like this you have to rewrite the default rule, like this:

  OUTPUT_OPTION = -o '$@'

  %.o : %.c
        $(COMPILE.c) $(OUTPUT_OPTION) '$<'

  ms>  * 'cc space file.c', same thing, the space is not escaped so cc tries
  ms> to read 'space.c' and fails. Adding an additional \ in the Makefile
  ms> results in make complaining it cannot find 'space\ file.c'. 

Again, you rewrite the rule as above.

  ms>  * Putting single or double quotes around the troublesome filenames does
  ms> not work: make takes them to be part of the file name.

Again, instead of changing the filename you rewrite the rule.

  ms>  * Escaping the pound sign works. I'm not sure how make invokes cc (via
  ms> fork()/exec(), system(), sh?), but it seems no shell is
  ms> involved since '#' would make the start of the comments.

Not necessarily, as above.

Make always invokes _all_ commands "as if" they were sent to the
interpreter in SHELL.  That is, from looking at the results there should
be no way to tell if it doesn't.

For efficiency make _will_ use a direct fork/exec if SHELL is /bin/sh,
and the command is simple enough to not need the shell.  To know if the
command is simple enough, make has a list of shell-special characters
and if any of those characters appears anywhere in the command script,
make will use the shell.  Otherwise it uses fork/exec.

Note that "#" _is_ one of those special characters, so in your example
the shell was invoked.

  ms>  * '$' behaves strangely. It is interpreted by make before
  ms> anything else, including '\'. So '\$' does not work and one must use
  ms> '$$' (which is documented). This is a bit confusing. Would it break many
  ms> makefiles if '\' were interpreted first so that '\$' is equivalent to
  ms> '$$'?

It would break thousands and thousands.  There are innumerable makefiles
with scripts like:

    echo foo | sed s,foo\$$,bar, > $@

or whatever.

As I mentioned above, make's syntax has been essentially set in stone
for over 20 years.  It's simply not possible to even consider any change
which would not be 100% backward-compatible.

  ms>  * Workaround: adding rules like the one below solve this problem:
  ms> .c.o:
  ms>   cc -c -o '$*.o' '$<'

This is the solution, not the workaround.

  ms>  * Optional question: how would one write a generic command to link a
  ms> bunch of object files containing spaces together? It seems "'$^'"
  ms> would not work.

The short answer is, you cannot productively deal with filenames
containing whitespace in make.  There are hacks and tricks that can get
you part of the way, but they're all gross to use and hard to work with,
and they don't solve the entire problem.  Fundamentally, make is a
string-based utility.  It concatenates strings.  It doesn't know
anything about filenames.  The contents of $^ internally to make is just
a long string that it inserts into another string (the command script)
and then gives to the shell to interpret.  The internal value of
something like $^ is _NOT_ a discrete list of filenames like ARGV or
whatever, such that make can delineate individual filenames.

Make was never designed with these kinds of files in mind, and it is far
to established (and the syntax is far too forgiving) to allow for
fundamental changes at this point.

If you need to deal with filenames containing these kinds of special
characters on a regular basis, I respectfully submit that perhaps make
is not the tool for you.  There are a number of other build control
utilities out there and some of them do handle these issues much better
than make.

 Paul D. Smith <address@hidden>          Find some GNU make tips at:
 http://www.gnu.org                      http://www.paulandlesley.org/gmake/
 "Please remain calm...I may be mad, but I am a professional." --Mad Scientist

reply via email to

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