make-w32
[Top][All Lists]
Advanced

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

Re: behavior on Win depends on whether \ or / is used??


From: Eli Zaretskii
Subject: Re: behavior on Win depends on whether \ or / is used??
Date: Fri, 11 Dec 2009 13:58:41 +0200

> From: "Mark Galeck (CW)" <address@hidden>
> Date: Thu, 10 Dec 2009 13:06:14 -0800
> 
> I have 2 subdirectories foobar0 and foobar1, and only in foobar1 there is a=
>  file foobar.s  . There is no file foobar.o .
> 
> The makefile is:
> 
> SHELL=Dcmd.exe
> 
> vpath %.s .\foobar0 .\foobar1
> 
> %.o : %.s
>             echo $<
> 
> foobar0\foobar.s:;
> 
> 
> This behaves as expected:
> 
> C:\tmp>make foobar.o
> echo .\foobar1/foobar.s
> 
> However, if I change all the backslashes to forward-slashes, then I get:
> 
> C:\tmp>make foobar.o
> make: *** No rule to make target `foobar.s', needed by `foobar.o'.  Stop.

The behavior with the forward slashes is the "correct" one (see below
for the reasons I put ``correct'' in quotes).  Backslashes are not
treated by Make on Windows in a 100% consistent manner, because in
some cases they have special semantics.

One such special case is in file-name wildcards, where a backslash
quotes special wildcard characters.

Another is in searching for files along vpath: Make looks up its
database of known files by literally comparing hash values of the file
names as strings, so foobar1/foobar.s and foobar1\foobar.s are not
considered equal, and the search fails.  This is your case.  If you
replace the backslash with forward slashes only in the last line of
your Makefile, it will work (after applying the patch below).  That is
because, when Make searches vpath, it looks for .\foobar0/foobar.s and
.\foobar1/foobar.s, but your Makefile specifies foobar0\foobar.s, so
Make thinks the file foobar0\foobar.s is not mentioned in the
Makefile.  If you use forward slashes everywhere, then Make realizes
that file foobar0/foobar.s _is_ mentioned in the Makefile.

I found and fixed a small bug in how the leading ".\" was treated on
Windows: it should be treated the same as "./", but it wasn't.  The
patch below fixes that.  However, this does not (and cannot) make the
backslash version of your Makefile behave 100% like the version with
forward slashes, due to the fact that targets of the Makefile are
looked up by comparing hash values of their strings, and the different
flavor of slashes defeats the comparison.

Paul, do you see any potential problems in providing on Windows a
special version of the hash macros that would treat forward and
back-slashes the same?

The above explains why the behavior with backslashes was different.
As to why the behavior with forward slashes is correct: this seems to
be because you have the foobar0/foobar.s target in the Makefile, but
not foobar1/foobar.s, while in reality the file that exists is
foobar1/foobar.s.  This seems to dupe Make into thinking that it found
the right prerequisite as foobar0/foobar.s, and it does not proceed
looking for foobar1/foobar.s.  If you change the order of directories
in the vpath line, the commands will work as you expect.

There is a long comment in the function vpath.c:selective_vpath_search
which seems to describe why files mentioned as targets in the Makefile
are treated specially, but I don't understand what it says.  Perhaps
Paul or someone else could help in explaining the current behavior.

(I added help-make to the list of addressees, because this question
was first asked there.)

Here's the patch mentioned above that I will install in the
development sources:

2009-12-11  Eli Zaretskii  <address@hidden>

        * file.c (lookup_file) [HAVE_DOS_PATHS]: Treat '\\' like we do
        with '/'.

--- file.c~     2006-03-17 18:24:20.000000000 +0200
+++ file.c      2009-12-11 13:12:13.760750000 +0200
@@ -102,10 +102,20 @@
   while (name[0] == '[' && name[1] == ']' && name[2] != '\0')
       name += 2;
 #endif
-  while (name[0] == '.' && name[1] == '/' && name[2] != '\0')
+  while (name[0] == '.'
+#ifdef HAVE_DOS_PATHS
+        && (name[1] == '/' || name[1] == '\\')
+#else
+        && name[1] == '/'
+#endif
+        && name[2] != '\0')
     {
       name += 2;
-      while (*name == '/')
+      while (*name == '/'
+#ifdef HAVE_DOS_PATHS
+            || *name == '\\'
+#endif
+            )
        /* Skip following slashes: ".//foo" is "foo", not "/foo".  */
        ++name;
     }




reply via email to

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