Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Is it ever legitimate to override $^O ?

by syphilis (Archbishop)
on Aug 02, 2022 at 01:53 UTC ( #11145885=perlquestion: print w/replies, xml ) Need Help??

syphilis has asked for the wisdom of the Perl Monks concerning the following question:

Ken Williams' Path-Class module has a test file (t/01-basic.t) that begins with:
BEGIN { $^O = 'Unix'; # Test in Unix mode }
Without that override, many tests fail on Windows because paths that are expected to contain '/' are detected as instead containing '\\'.
And there are also cases of an expected empty string being detected as '0'.
Try building Path::Class on Windows and watch it pass - then comment out the BEGIN{} block in t/01-basic.t and examine the failures then elicited by that script.
(BTW, I don't know how that override hack even works.)

The trouble is that, beginning with perl-5.34.0, this hack fails to deliver because running 'perl -Mblib t/01-basic.t' fails in the way already outlined above, irrespective of whether that override is included or commented out.
In addition (with perl-5.34.0 onwards and the BEGIN{} block included), t/01-basic.t fails in an entirely different way when run inside the Test::Harness (as part of 'make test'):
t/01-basic.t .......... 1/78 Can't call method "relative" on an undefi +ned value at C:\sisyphusion\Path-Class-0.37\blib\lib/Path/Class/Entity.pm line 7 +6. t/01-basic.t .......... Dubious, test returned 22 (wstat 5632, 0x1600)
What bug(s) should be investigated ?
Is overriding $^O a legitimate thing to do ?
Is it a bug that, on perl-5.34 and later, the "Can't call method "relative"..." error arises ? If so, is it a Path::Class bug ? or a Test::Harness bug ? or a perl bug ?.
Is it a bug that, on perl-5.34 and later, the override loses its effectiveness when run outside Test::Harness ? If so, is it a Path::Class bug ? or a perl bug ?

Cheers,
Rob

Replies are listed 'Best First'.
Re: Is it ever legitimate to override $^O ?
by kcott (Archbishop) on Aug 02, 2022 at 07:43 UTC

    G'day Rob,

    I was curious about this, so I did a little digging. I don't have a v5.34.0 on MSWin available so I can't do any direct testing.

    "Try building Path::Class on Windows and watch it pass ..."

    In the "mswin32" column of the "CPAN Testers Matrix: Path-Class 0.37", there are only passes from v5.12.2 to v5.29.3 then, a lone test for v5.34.0 which failed (see "Report for Path-Class-0.37"). The problem here is very similar to what you report for 'make test':

    Output from 'C:\perl-5.34.0\bin\perl.exe ./Build test': Can't call method "relative" on an undefined value at C:\Users\jndt\Ap +pData\Local\.cpan\build\Path-Class-0.37-0\blib\lib/Path/Class/Entity. +pm line 71. t/01-basic.t .......... Dubious, test returned 22 (wstat 5632, 0x1600) Failed 28/78 subtests

    The line numbers are different: 71 (here) vs. 76 (yours) — I don't know if that's significant.

    The distribution provides both a Makefile.PL and a Build.PL. The INSTALL file only references perl Build.PL followed by various ./Build commands (no make anywhere). I had a look at a few reports, all had ./Build test — again, I don't know if that's significant.

    The last update to Path-Class was six years ago (2016). So, it would seem more likely the "bug" is due to a Perl change (v5.34.0 was released in 2021, a little over a year ago) or something in Strawberry/ActivePerl/etc.

    I don't know if any of that helps. Maybe some avenues for further investigation.

    I've no idea if overriding $^O is legitimate. I had a think about it but drew a blank.

    — Ken

      The problem here is very similar to what you report for 'make test'

      Yes - that's the issue.
      On MS Windows, be it Windows 7 & mingw-built perl-5.34.0 (as in my case), or Windows 10 & MSVC-built (as in the testers matrix), the overriding of $^O generates that error.

      The line numbers are different: 71 (here) vs. 76 (yours) I don't know if that's significant.

      In earlier attempts to work out what was going on, I had inserted some debug statements into Entity.pm.
      I then commented out those statements - thereby leaving the code in its original state, but altering the line numbers.
      So it's not significant, and I'm sorry for the confusion.
      I believe it's only Windows that's being affected by this.

      The distribution provides both a Makefile.PL and a Build.PL. The INSTALL file only references perl Build.PL followed by various ./Build commands (no make anywhere). I had a look at a few reports, all had ./Build test again, I don't know if that's significant.

      I don't think there's anything significant in that.
      It makes no difference whether the module is built using Module::Build or ExtUtils::MakeMaker. The behaviour is still the same.
      If cpan/cpanm/cpanp is invoked to do the building, then I think M::B will be used.
      When I build manually from source, I use EU::MM as that's my preference.

      Because Strawberry Perl have not yet released a perl later than 5.32.1, there aren't many Windows perls in the wild that are at version 5.34 or later.
      I build my own perls and test them regularly, but I haven't been testing their capabilities to build Path::Class because that module has never interested me.
      Having recently become aware of this problem, I'm unsure as to where it should be reported.
      Maybe I should just open a perl Issue and ask there - but I wanted to first draw on any wisdom that exists here.

      Cheers,
      Rob
      > The line numbers are different: 71 (here) vs. 76 (yours) I don't know if that's significant.

      yes it is: Entity.pm#L71

      L*

      There are no rules, there are no thumbs..
      Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Is it ever legitimate to override $^O ?
by Discipulus (Abbot) on Aug 02, 2022 at 07:47 UTC
    Hello syphilis,

    no clues by me, only other doubts..

    In the very first place I dont understand why a module aimed to help with path and filenames plays so dirty on testing, faking a Unix mode

    Second, as I dont have any strawberry available newer than 5.32 I played a bit with the t/01-basic.t and I discovered it fails in the same way even with this modified part:

    use Config; BEGIN { #$^O = 'Unix'; # Test in Unix mode $Config{'osname'} = 'Unix'; warn "DEBUG: config: ",$Config{'osname'}," -- \$^O: $^O\n"; }

    So $Config{'osname'} and $^O are indipendent and the above code is only influenced by $^O.

    In perlvar I read: $^O .. The value is identical to $Config{'osname'}. They are identical but not bound.

    Infact the module you are talking about rely on the core module File::Spec (..yes, boring to use but works very well) and it simply inspect $^O as you can see. And yes you can also try $^O = ''; to fake the Unix mode.

    With my poor understanding I can find nothing in perldelta about osname nor about $^O

    As last doubt I have noting at Entity.pm line 76. ..merely a blank line after the sub resolve ending.

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
      So $Config{'osname'} and $^O are independent and the above code is only influenced by $^O.

      Yes - initially $Config{osname} and $^O are identical. But $^O can be altered (is writeable) whereas $Config{osname} is permanently set in stone and attempting to assign a value to it should be a fatal compile-time error.

      And yes you can also try $^O = ''; to fake the Unix mode.

      I didn't know that. So I tried specifying $^O = ''; in t/01-basic.t but it didn't help wrt perl-5.34.0 and later :-(

      As last doubt I have noting at Entity.pm line 76. ..merely a blank line after the sub resolve ending

      Yeah - it should be line 71 (I think).
      As I've (now) noted elsewhere in this thread, I made changes (comments) in Entity.pm that did not alter the code but did bugger up the line numbering. Sorry 'bout that.

      Cheers,
      Rob
        Hello syphilis,

        > whereas $Config{osname} is permanently set in stone and attempting to assign a value to it should be a fatal compile-time error.

        perl -MConfig -wE "say $Config{'osname'}; $Config{'osname'} = 'Unix'; +say $Config{'osname'}" MSWin32 Unix

        L*

        There are no rules, there are no thumbs..
        Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Is it ever legitimate to override $^O ?
by kcott (Archbishop) on Aug 02, 2022 at 22:44 UTC
Re: Is it ever legitimate to override $^O ? -- Cwd and File::Spec
by Discipulus (Abbot) on Aug 03, 2022 at 07:59 UTC
    Hello again syphilis,

    some steps backward? Can this $^O be only some smoke in our eyes? t/01-basic.t .......... 1/78 Can't call method "relative" on an undefined value ...lets start again from this point:

    # https://metacpan.org/release/KWILLIAMS/Path-Class-0.37/source/lib/Pa +th/Class/Entity.pm#L65 sub resolve { my $self = shift; Carp::croak($! . " $self") unless -e $self; # No such file or direc +tory my $cleaned = $self->new( scalar Cwd::realpath($self->stringify) ); # realpath() always returns absolute path, kind of annoying $cleaned = $cleaned->relative if $self->is_relative; + # line 71 (76 in your modified version) %$self = %$cleaned; return $self; }

    So $cleaned is undefined at line 71 and it should be initialized in the line my $cleaned = $self->new( scalar Cwd::realpath($self->stringify) ); so going backward I'd verify:

    • $self->stringify
    • Cwd::realpath($self->stringify) ) # first charged in my opinion
    • $self->new( scalar Cwd::realpath($self->stringify) );

    So, maybe, the problem is not at all with Path::Class nor with (or maybe yes..) with assignement to $0 but within Cwd or File::Spec as they are heavily used in the background.

    I mean: I tried to track back Cwd::realpath and this module also use $^O to decide what to do.

    I'd also investigate which version of Cwd and File::Spec come with your testing distros of Perl.

    As last point (maybe due to a dumb moment): the failing test is the first one: there are 78 tests and I checked them... the first one is.... ok(1) O_O is this one failing?!?

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
      Yes - I had started off by checking most of those things. (That was how line 71 became line 76 ;-)
      Everything looked fine, except that $cleaned was not defined.
      It was actually quite some time before I looked at the test script itself and noticed the $^O override.

      File/Spec.pm contains very little code - and it certainly seems to be inviting this override that t/01-basic.t uses.
      So I decided to investigate some basic behaviour of File::Spec, without any reference to Path::Class. I used this script:
      # fake_os.pl BEGIN { $^O = 'Unix'; } use strict; use warnings; use File::Spec; my $x = File::Spec->catfile('a', 'b', 'c'); print $x;
      I find that on both perl-5.32 and 5.34, this script outputs 'a/b/c' as expected.
      If I comment out the BEGIN block, then the script outputs 'a\b\c' as expected - on both perl-5.32 and perl-5.34. What is odd is that if I simply load Test::Harness, then on both perl-5.32 and 5.34 I always get 'a\b\c' even when the BEGIN block is included:
      C:\_32\pscrpt\file-spec>perl fake_os.pl a/b/c C:\_32\pscrpt\file-spec>perl -MTest::Harness fake_os.pl a\b\c
      I think that demonstrates that there might be some fragility around overriding $^O, though it doesn't really explain much about the behaviour of t/01-basic.t.

      I think it's a pity that File::Spec invites users to mess with the path formatting by fiddling with $^O.
      Surely it would be better if there was a function to call or an environment variable to set ... or something else that doesn't involve fiddling with $^O.

      I think I might just file bug reports against both perl (based on the demo of the Test::Harness interference) and Path::Class ... and see where it all ends up.

      I've just tried my fake_os.pl on Ubuntu with $^O = 'Win32'; and it just ignores that and gives the Unix style 'a/b/c' (on both perl-5.32 and 5.36).(I think that's intended behaviour.)
      I totally buggered that up. I can get Win32 path formatting with fake_os.pl on Ubuntu if I specify $^O = 'MSWin32' .
      Again, it doesn't work if the Test::Harness is loaded.
      I think I'm just fiddling about with a heap of rubbish ...

      Update: Forgot to mention that I did hack File::Spec on Windows perl-5.34 such that 'Unix' was hard coded in, and $^O didn't need to be altered. In that case the t/01-basic.t script ran fine and passed all tests.
      To me, that shows that the problem with t/01-basic.t is not that 'Unix' formatting is being selected - it's because $^O is being messed with.
      I'll post again with links to relevant bug reports once they have been filed.
      Thanks for the interest that has been shown.

      Cheers,
      Rob
        Ah!

        ..and Cwd that my spider sense supposed the first to be charged?

        while your fakOS.pl behaves the same way for me.. the following Cwd version acts in the opposite way

        C:>cat fakeOS.pl BEGIN { $^O = 'Unix'; } use strict; use warnings; use Cwd 'abs_path'; my $abs_path = abs_path('.'); print $abs_path; C:>perl fakeOS.pl C:\EX_D\ulisseDUE C:>perl -MTest::Harness fakeOS.pl C:/EX_D/ulisseDUE

        L*

        There are no rules, there are no thumbs..
        Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Is it ever legitimate to override $^O ?
by Anonymous Monk on Aug 02, 2022 at 07:44 UTC
      It's a terrible hack.

      I think that was my reaction, too.
      The question is "Having worked in perl-5.32.x and earlier, should this hack be expected to continue working in 5.34.x and onwards ?"
      I don't know the answer ... but maybe we should just work on rewriting t/01-basic.t such that the hack is not needed.

      BTW, thanks for pointing out the part that File::Spec plays in this.

      Cheers,
      Rob
Re: Is it ever legitimate to override $^O ?
by davies (Prior) on Aug 08, 2022 at 22:18 UTC

    If it's not legitimate, how should I have written the test & code below?

    use strict; use warnings; use Test::More; use FindBin qw( $RealBin ); use lib $RealBin; use MyModule; if (connected()) { pass("\"connected\" works with defaults ($^O)"); } else { plan skip_all => 'Internet inaccessible'; } my $careto = $^O; if ($careto =~ /win/gmsi) { $^O = 'linux'; } else { $^O = 'win'; } ok !connected(), "\"connected\" fails with defaults overwritten ($^O)" or diag("\"connected\" returns true regardless (OS = $^O)"); $^O = $careto; done_testing;

    SSCCE (I hope!) from the module:

    Package MyModule; use strict; use warnings; sub connected { my $pingcmd = 'ping -c 1 8.8.8.8'; my $pingworks = ' 0% packet loss'; if ($^O =~ /win/gmsi) { $pingcmd =~ s/-c/\/n/; $pingworks = 'bytes=32'; } my $pingrtn = qx($pingcmd); return $pingrtn =~ /$pingworks/msi; } 1;

    I accept this may be an ugly hack, but it tests what I want in a way that seems obvious to me. But I will gladly accept improvements, advice and explanations.

    Regards,

    John Davies

    Almost immediate update: deleted a couple of relic lines

      Heh
      sub connected_win32 { ... } sub connected_linux { ... }
      Poking at global vars is no api

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11145885]
Approved by kcott
Front-paged by kcott
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (2)
As of 2022-11-27 02:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Notices?