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

A user of one of my modules (File::Touch) sent me a bug report, complaining that his ActiveState Perl barfed on the following line:

sysopen my $fh,$file,O_WRONLY|O_CREAT|O_NONBLOCK|O_NOCTTY or croak("Can't create $file : $!");

The error message was "Your vendor has not defined Fcntl macro O_NONBLOCK, used at..."

So, I tweaked the code to check whether the Fcntl constant exists in the module's symbol table:

my $SYSOPEN_MODE = O_WRONLY|O_CREAT; if(exists $Fcntl::{'O_NONBLOCK'}){ $SYSOPEN_MODE |= &{ $Fcntl::{'O_NONBLOCK'} }; } if(exists $Fcntl::{'O_NOCTTY'}){ $SYSOPEN_MODE |= &{ $Fcntl::{'O_NOCTTY'} }; }

Strangely, the code causes an error at 'exists $Fcntl::{'O_NONBLOCK'}'. The error message is "Your vendor has not defined Fcntl macro O_NONBLOCK, used at File/Touch.pm line 16." The same error occurs with ActiveState 5.8 and 5.10.

Any ideas?

Replies are listed 'Best First'.
Re: Fcntl constants missing
by puudeli (Pilgrim) on Mar 24, 2009 at 11:32 UTC

    Maybe fcntl.h is not included in your compilation of Perl?. Fcntl is a simple translation of the fcntl.h C header file. Try 'perl -V' to see the compile time flags.

    --
    seek $her, $from, $everywhere if exists $true{love};

      Being the user the OP was talking about, let me drop into this discussion.

      The error appears on the standard ActiveState distribution of Perl, both 5.8.8 and 5.10. The compiler flags, as shown by perl -V, are:

      cc='cl', ccflags ='-nologo -GF -W3 -MD -Zi -DNDEBUG -O1 -DWIN32 -D +_CONSOLE -DNO_STRICT -DHAVE_DES_FCRYPT -DNO_HASH_SEED -DUSE_SITECUSTO +MIZE -DPRIVLIB_LAST_IN_INC -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SY +S -DUSE_PERLIO -DPERL_MSVCRT_READFIX', optimize='-MD -Zi -DNDEBUG -O1', cppflags='-DWIN32' ccversion='12.00.8804', gccversion='', gccosandvers='' intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234 d_longlong=undef, longlongsize=8, d_longdbl=define, longdblsize=8 ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='__int64 +', lseeksize=8 alignbytes=8, prototype=define
      Update: Maybe this part of perl -V is also important:
      Compile-time options: MULTIPLICITY PERL_IMPLICIT_CONTEXT PERL_IMPLICIT_SYS PERL_MALLOC_WRAP PL_OP_SLAB_ALLOC USE_ITHREADS USE_LARGE_FILES USE_PERLIO USE_SITECUSTOMIZE
      But can we see from this whether it was compiled with fcntl.h?

      Some other Fcntl macros work well - for instance, O_CREAT.

      Even if O_NONBLOCK is not defined, I wonder why the error message is issued on a line, where only the existence is tested, i.e.

      if(exists $Fcntl::{'O_NONBLOCK')) { ... }
      -- 
      Ronald Fischer <ynnor@mm.st>

        Have you tried FNONBLOCK instead? You can export the old constants by using the tag :Fcompat,

        --
        seek $her, $from, $everywhere if exists $true{love};
Re: Fcntl constants missing
by rovf (Priest) on Mar 24, 2009 at 13:05 UTC

    I think this is how you can do it:

    eval { $SYSOPEN_MODE |= &{ $Fcntl::{'O_NONBLOCK'} }; }; if($@) { if($@ =~ /Your vendor has not defined/) { # OK, we don't have O_NONBLOCK } else { die "$@"; # Rethrow exception, must be something different } }

    -- 
    Ronald Fischer <ynnor@mm.st>

      it looks like the problem is $AUTOLOAD in Fcntl, which throws the error when the symbol table is queried.

      looping through the symbol table doesn't throw the same error:

      foreach my $sym (keys $Fnctl::){ if($sym eq 'O_NONBLOCK'){ $SYSOPEN_MODE |= &{ $Fcntl::{'O_NONBLOCK'} }; } }

      however, this doesn't work with another constant, O_NOCTTY

Re: Fcntl constants missing
by rovf (Priest) on Mar 24, 2009 at 13:01 UTC

    I modified your code a bit:

    use warnings; use strict; use Fcntl; my $SYSOPEN_MODE = O_WRONLY|O_CREAT; if(exists $Fcntl::{'O_NONBLOCK'}) { print "Exists\n"; $SYSOPEN_MODE |= &{ $Fcntl::{'O_NONBLOCK'} }; }
    The output of this is really surprising to me:
    Exists Your vendor has not defined Fcntl macro O_NONBLOCK, used at fctest.pl +line 8.
    So 'exists' is not a good way to check for the existence of the macro; and it is not the exists expression which printed the error (we were mislead because the line number pointed to the 'if'; or did we just miscount the lines?).

    -- 
    Ronald Fischer <ynnor@mm.st>