janet-lang / janet

A dynamic language and bytecode vm
https://janet-lang.org
MIT License
3.53k stars 227 forks source link

`file/temp` fails for `:mingw` (according to `os/which`) #1500

Closed sogaiu closed 2 months ago

sogaiu commented 2 months ago

I'm trying to get something working via the bash shell that comes with git for windows on Windows 10.

When I build janet via the Makefile in that sort of environment (mingw in janet's banner and :ming via os/which), the resulting janet binary doesn't seem to succeed with file/temp:

$ ./build/janet
Janet 1.35.2-fda0a08 mingw/x64/gcc - '(doc)' for help
repl:1:> (os/which)
:mingw
repl:2:> (file/temp)
error: unable to create temporary file - Permission denied
  in file/temp [src/core/io.c] on line 124
  in thunk [repl] (tail call) on line 2, column 1

May be that is tmpfile not succeeding?

I tried a simple .c program that calls tmpfile and got similar results.

Came across an answer to this SO question:

I think the MinGW guys rolled a special version that keeps the temporary file entirely in memory.

I don't know how complete their solution is without combing through MinGW's source and/or asking on the mailing lists. In either case, it is probably a better idea to use some function other than tmpfile() anyway, given its problems.

not sure if that is relevant or if it was valid at one point whether it still is, but FWIW.

Will keep investigating, but if someone knows something about this already, would appreciate being informed (^^;


For reference, below is the output of janet's make test (which also fails):

$ make test
for f in test/suite*.janet; do  ./build/janet.exe "$f" || exit; done
Starting suite test/suite-array.janet...
Finished suite test/suite-array.janet in 0.003 seconds - 20 of 20 tests passed.
Starting suite test/suite-asm.janet...
Finished suite test/suite-asm.janet in 0.004 seconds - 6 of 6 tests passed.
Starting suite test/suite-boot.janet...
Finished suite test/suite-boot.janet in 0.019 seconds - 527 of 527 tests passed.
Starting suite test/suite-buffer.janet...
Finished suite test/suite-buffer.janet in 0.005 seconds - 57 of 57 tests passed.
Starting suite test/suite-bundle.janet...
Finished suite test/suite-bundle.janet in 0.150 seconds - 35 of 35 tests passed.
Starting suite test/suite-capi.janet...
Finished suite test/suite-capi.janet in 0.003 seconds - 9 of 9 tests passed.
Starting suite test/suite-cfuns.janet...
Finished suite test/suite-cfuns.janet in 0.001 seconds - 2 of 2 tests passed.
Starting suite test/suite-compile.janet...
Finished suite test/suite-compile.janet in 0.001 seconds - 10 of 10 tests passed.
Starting suite test/suite-corelib.janet...
Finished suite test/suite-corelib.janet in 0.005 seconds - 90 of 90 tests passed.
Starting suite test/suite-debug.janet...
Finished suite test/suite-debug.janet in 0.002 seconds - 1 of 1 tests passed.
Starting suite test/suite-ev.janet...
✘ test/helper.janet:17: "file writing 1": false
Finished suite test/suite-ev.janet in 2.919 seconds - 502 of 503 tests passed.
make: *** [Makefile:256: test] Error 1
sogaiu commented 2 months ago

There is a sample .c program that MS provides here:

// crt_tmpfile.c
// compile with: /W3
// This program uses tmpfile to create a
// temporary file, then deletes this file with _rmtmp.
#include <stdio.h>

int main( void )
{
   FILE *stream;
   int  i;

   // Create temporary files.
   for( i = 1; i <= 3; i++ )
   {
      if( (stream = tmpfile()) == NULL ) // C4996
      // Note: tmpfile is deprecated; consider using tmpfile_s instead
         perror( "Could not open new temporary file\n" );
      else
         printf( "Temporary file %d was created\n", i );
   }

   // Remove temporary files.
   printf( "%d temporary files deleted\n", _rmtmp() );
}

This also gives permission denied:

Could not open new temporary file
: Permission denied
Could not open new temporary file
: Permission denied
Could not open new temporary file
: Permission denied
0 temporary files deleted

I've reproduced this with both "official" git for windows and a scoop-based installation.

I don't think there's anything odd about my setup -- it's a relatively recent installation of Windows (and I'm pretty sure I encountered it on another Windows setup because I have this comment from a bit back.).

Perhaps it's a "git for windows" peculiarity...

sogaiu commented 2 months ago

On a side note, there is something about tmpfile being deprecated on Windows (in the sample code above too):

// Note: tmpfile is deprecated; consider using tmpfile_s instead

There was a sample for tmpfile_s:

// crt_tmpfile_s.c
// This program uses tmpfile_s to create a
// temporary file, then deletes this file with _rmtmp.
//

#include <stdio.h>

int main( void )
{
   FILE *stream;
   char tempstring[] = "String to be written";
   int  i;
   errno_t err;

   // Create temporary files.
   for( i = 1; i <= 3; i++ )
   {
      err = tmpfile_s(&stream);
      if( err )
         perror( "Could not open new temporary file\n" );
      else
         printf( "Temporary file %d was created\n", i );
   }

   // Remove temporary files.
   printf( "%d temporary files deleted\n", _rmtmp() );
}

...so I gave that a try and got:

Temporary file 1 was created
Temporary file 2 was created
Temporary file 3 was created
0 temporary files deleted

which seems somewhat better except the deletions don't look successful.

I guess tmpfile_s isn't so great because it was added in C11?

sogaiu commented 2 months ago

I think this may be my bad (^^;

I built janet using gcc and make installed via scoop, but after I read the bits below about what "git for windows" is based on, it occurred to me that there might be a mismatch.

I recompiled janet using gcc and make that came with what one gets by installing mingw via scoop and this seemed to do the trick.

Sorry for the noise!


For reference, below is a bit of what I found about the basis for "git for windows":

Git is not a monolithic executable, but consists of a couple of executables written in C, a couple of Bash scripts, a couple of Perl scripts, and a couple of Tcl/Tk scripts. Some parts (not supported by Git for Windows yet) are written in other script languages, still.

To support those scripts, Git for Windows uses MSYS2, a project providing a minimal POSIX emulation layer (based on Cygwin), a package management system (named "Pacman", borrowed from Arch Linux) and a number of packages that are kept up-to-date by an active team of maintainers, including Bash, Perl, Subversion, etc.

The difference between MSYS2 and MinGW

MSYS2 refers to the libraries and programs that use the POSIX emulation layer ("msys2 runtime", derived from Cygwin's cygwin1.dll). It is very easy to port libraries and programs from Unix/Linux because most of the POSIX semantics is emulated reasonably well, for example the fork() function. Bash and Perl are examples of MSYS2 programs.

MinGW refers to libraries and programs that are compiled using GNU tools but do not require any POSIX semantics, instead relying on the standard Win32 API and the C runtime library. MinGW stands for "Minimal GNU for Windows". Examples: cURL (a library to talk to remote servers via HTTP(S), (S)FTP, etc), emacs, Inkscape, etc

The POSIX emulation layer of MSYS2 binaries is convenient, but comes at a cost: Typically, MSYS2 programs are noticably slower than their MinGW counterparts (if there are such counterparts). As a consequence, the Git for Windows project tries to provide as many components as possible as MinGW binaries.

sogaiu commented 2 months ago

I'll assume that this was pilot error and close this for now.