wduquette / tcl-quill

Build tool for Tcl/Tk projects
BSD 2-Clause "Simplified" License
10 stars 2 forks source link

test pathfind-1.1 and 1.3 fail on Windows #14

Closed effelsberg closed 9 years ago

effelsberg commented 9 years ago

Some analysis for pathfind-1.1 follows, and it is not your fault but rather something in the Tcl interpreter itself. However, would be nice if the tests (or the quill lib itself) are aware of it.

With Tcl 8.6.1 from ActiveState and also a tclkit858/tclkit860 (from Pat Thoyts?):

% set env(PATH) ""
% info exists env(PATH)
1
% puts $env(PATH)
can't read "env(PATH)": no such variable
% parray env
<<can't find key PATH in output>>

A regular array works fine:

% set x(y) ""
% info exists x(y)
1
% puts $x(y)
<<empty string>>
% parray x
x(y) =
effelsberg commented 9 years ago

From the Tcl docs: this is not a bug, it's how Windows works.

Under Windows, the environment variables PATH and COMSPEC in any capitalization are converted automatically to upper case. For instance, the PATH variable could be exported by the operating system as “path”, “Path”, “PaTh”, etc., causing otherwise simple Tcl code to have to support many special cases. All other environment variables inherited by Tcl are left unmodified. Setting an env array variable to blank is the same as unsetting it as this is the behavior of the underlying Windows OS. It should be noted that relying on an existing and empty environment variable will not work on Windows and is discouraged for cross-platform usage.

effelsberg commented 9 years ago

Thinking about it again, there is still some slight annoyance:

% set env(PATH) ""
% info exists env(PATH)
1
% set env(PATH)
can't read "env(PATH)": no such variable
<< Gosh, Schrödinger's cat of a variable is dead and alive at the same time! >>
% unset env(PATH)
<< No error message, it must have existed then. But let's make a final check ... >>
% info exists env(PATH)
0
% unset env(PATH)
can't unset "env(PATH)": no such element in array
<< It's dead, Jim. >>
wduquette commented 9 years ago

Here's what I just did in [os pathfind]:

 set thePath ""
 catch {set thePath $env(PATH)}
 if {$thePath eq ""} { ... }

Does this fix findpath-1.1?

Also, how is findpath-1.3 failing? It doesn't involve an empty PATH.

effelsberg commented 9 years ago

Confirmation

pathfind-1.1 passes with your changes.

Now more on pathind-1.3

There is a strange thing: I ran the tests on a different machine (with Windows Vista) and pathfind-1.3 passed. Of course, I didn't investigate why everything was OK. But thinking about it revealed its nature.

About the reason of the failure:

On Windows [file dirname [info nameofexecutable]] returns:

C:/Tcl/bin

See? If you split this path by colons, you'll get:

{"C" "/Tcl/bin"}

Why does this work on the Vista machine but not on the Windows 7 machine? On the Vista machine I've got everything on drive C:, so globbing for "/Tcl/bin" uses drive C: as the root. On the Windows 7 machine there's Tcl installed on C: but all live action happens on D:, so "/Tcl/bin" gets translated by glob to "D:/Tcl/bin" and this doesn't exist.

wduquette commented 9 years ago

OK, I see. Now as it happens, pathfind-1.3 is specifically for the case where splitting the path with ":" is OK; I can reasonably constrain it so that it doesn't run on Windows.

Now, I use Tcl/Tk a lot on (at my day job) on Windows with MinGW's bash shell, in which case separating on ":" is the right thing to do; so on Windows [os pathfind] tries ";" first, and then ":". Perhaps I should change it: only fall back to ":" if there are no ";". Thoughts?

effelsberg commented 9 years ago

Using a MinGW shell doesn't mean that you also have Unix-like paths in your programs. The shell tries to translate between Unix paths and Windows paths, at least that's the way it works for me. The result for me is a combination that features a drive prefix and slashes.

E.g. this simple argument dumper:

#include <stdio.h>
int main(int argc, char **argv) {
    int i;
    for (i = 0; i < argc; i++) {
        printf("Arg %d: %s\n", i, argv[i]);
    }
    return 0;
}

See how the path gets half-transformed:

$ arg_dump /c/Tcl/bin
Arg 0: d:\arg_dump.exe
Arg 1: c:/Tcl/bin

And if I start ActiveTcl's tclsh from bash, I get genuine Windows paths in env(PATH) including backslashes.

Do you have Unix paths in your env(PATH)? What do [file volumes] and [file separator] give you?

wduquette commented 9 years ago

My bad. On Windows under MinGW, the PATH is colon-delimited; and I (working on a Mac) made the unwarranted assumption that tclsh received that environment variable unchanged. Of course, it doesn't; everything is translated back to Windows standard before tclsh sees it. I'll fix [os pathfind] this evening or tomorrow.

wduquette commented 9 years ago

Fixed. I now just use the official tcl_platform(pathSeparator) (D'oh!). Also, the FindWith command in that module had a completely gratuitous 'glob'; now cleaned up.