bug-make
[Top][All Lists]
Advanced

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

Globbing broken


From: Fabio Alemagna
Subject: Globbing broken
Date: Sat, 5 Feb 2005 02:43:00 +0100

This is not so much of a Make problem, but rather of the globbling
library it uses. However, since Make is affected, I thought I'd post
here about my findings to see whether someone else noticed this issue
and whether someone is willing to take a look at the library :-)

Say we are in a directory which contains the following items
(directories have a trailing slash):

    foo/ baz/ bar 

Now, let's look at the following makefile:

DIRS1 := $(wildcard */)
DIRS2 := $(wildcard ./*/)

foo:
        @echo dir1: $(DIRS1)
        @echo dir2: $(DIRS2)

The output will be

dir1: baz/ foo/
dir2: ./bar ./baz/ ./foo/

dir2 should list only the directories, instead it also lists the files. Typing 

    echo */; echo ./*/

in the shell confirms that the correct result is the one of dir1, and
that dir2 should merely have a traling ./ in front of each item.

Generally speaking, make gives a correct result only when there's no
slashes before the last part in the path, that is when the last part
is also the first, as in the dir1 example. So, for example, also
$(wildcard foo/*/) will give the same problem.

Another problem arises when one tries to make a rule to automatically
make a directory, like this:

file.h : include/
        @cp $@ $<

%/:
        mkdir $@

What should happen is that when make goes to build include/, it will
find the pattern rule %/ and will execute it. This is really a fancy
and useful way to automatically make directories, isn't it? Well, if
it worked, that is.

The problem is, it works with directory names not longer than *one*
char, it doesn't work otherwise.

You may try it by yourself:

file.h : i/
        cp $@ $<

%/:
        mkdir $@

That will first make i/, and then copy file.h to i/. 

It won't work if instead of i/ we have include/: make will say that
there's no rule to make include/. If however we have an _explicit_
rule for include/, like this:

include/:
        mkdir $@

Then make fill wind it!

But we can rewrite the above rule like this:

include:
        mkdir $@

Notice the lack of the trailing slash. Make will still execute the above rule.

Morover, if I make the directory include/ by myself, then surprisingly
make does recognize the directory is already there and thus doesn't
make it and doesn't spit any error!

This tells us something, which I got confirmation for by looking at make's code.

When make goes to build the various prerequisites, it _always_ uses
globbing to match the corresponding files, even if the names don't
contain any globbing characters. It basically leaves to the globbing
library the respobsibility to determine whether the filename really
needs globbing processing or not.

It works somewhat like this:

    filenames_list = glob(filename)

Now, if /filename/ doesn't contain globbing characters, it should be
returned "as is". At least this is the intent, but we'll see it
doesn't really work like that.

In fact, if /filename/ points to a string like "a/", then indeed
glob() returns "a/", whether a/ already exists or not.

If /filename/ is "include/", two things may happen:

    1) include/ already exists, then glob() returns "include/"
    2) include/ doesn't exist, then glob() returns "include", without
the trailing slash!

And (2) is what causes the problem, because when make goes to build
"include/" but ends up building "include", without the trailing slash,
it won't find a matching pattern rule. However, if we have a rule
whose target is "include/", then make will find it, even if the rule's
 target has a trailing slash. I'm not sure why this last thing happens
exactly, and I don't know whether it's related to the same problem or
not.

This is a bug I found some time ago but just now got to report, as it
happened to me again to need make's globbing facilities. When I first
discovered the bug I did make some investigation, and I found the
cause of the problem, but right now I can't remember exactly. I didn't
have much time, though, and didn't come up with a clean patch (I had
an hackish one ready, but lost it).

So, that's all I think. Let me know what you think.




reply via email to

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