|No such thing as a small change|
Using MinGW to build perl on windows forcing it to expand * into glob in cmd.exeby Discipulus (Abbot)
|on Feb 14, 2021 at 16:01 UTC||Need Help??|
A recent post evidentiated a bug in some raku builds for windows: if compiled using MinGW (instead of compiled with MS tools as rakubrew uses) an unexpected expansion of * into a glob happens in cmd.exe prompt. The thread born because Athanasius found impossible to escape this * in cmd.exe (more on this later on).
Contributions to the above threads highlighted a fact unkonwn to me: there is a tiny layer, the C runtime library, responsible to find argc and build argv to pass to main (see jcb's answer). The actual C runtime library depends on the tool used to build perl (or raku). At least this is what I understood.
While the above is interesting per se triggered another question in my mind: if a raku built using MinGW unintentionally expands * there must be a way to build a perl that expands too * into a glob. You will see later on why this is a futile question, but: futile, complex and hackish is exactly the kind of task I love.
-Prepare the ground-
To build this new frankestein perl we need: a recent strawberry portable edition: strawberry-perl-184.108.40.206-64bit-portable is what I used. Extract this wherever you want: in the following examples I will use C:\ulisse\perl5.32-64bit
Then we need to download perl-5.32.1.tar.gz.
Finally make an empty dir to use as playground. Open the folder where you extracted the strawberry portable edition and launch the portableshell.bat then in the prompt window execute (adjust to your needs):
Then just to be sure nothing in PATH will interfere with our experiments clean up the PATH as much as possible, leaving only strawberry directories and windows system ones (adjust to your needs):
Finally extract the source of perl downloaded from CPAN, perl-5.32.1.tar.gz to X:\globperl\perl-5.32.1
-Modify the source code-
Browse the folder X:\globperl\perl-5.32.1\win32 and edit the win32.c file, in my case around line 73 and change:
the relevant line into int _CRT_glob = 1; save and close the file.
In the same folder edit the runperl.c file around line 19 in my case putting again int _CRT_glob = 1; and so resulting in:
Save and close.
In the above portableshell.bat window move to the cd X:\globperl\perl-5.32.1\win32 directory where win32 perl source is. Now we have to instruct gmake ( which will use GNUmakefile inside win32 folder while Makefile and makefile.mk are used by other flavours of make) to install our new perl inside a custom dir. We can modify the GNUmakefile (around lines 49 and 50) to use different INST_DRV and INST_TOP or we can feed this parameter from command line.
So we are ready to build and install our new perl:
-First test and dll hell-
This shouldnt happen but as happened to me can also happens to you. Open a new command prompt ( not a portableshell.bat but a regular plain cmd.exe prompt). I erase completely PATH to be sure nothing will interefere, then I tried to invoke our brand new perl
A nasty error window pops up complaining libgcc_s_seh-1.dll is missing. It is present in the C:\ulisse\perl5.32-64bit\perl\bin strawberry folder and should be available during building, but we can copy in our brand new perl\bin directory to overcome the error, but then another error pops up about missing libwinpthread-1.dll and then again about libstdc++-6.dll so we copy these missing dlls and finally we got a sane perl.exe
Sometimes the dll hell can be even worst and the sybilline The application was unable to start ... 0x000007b error appears: in this case you can profit of the wonderful program Dependencies to dipanate the dll hell.
Now let's look if our new perl is able to expand * into glob on cmd.exe as we wanted to prove:
Now we have a perl expanding * into a glob, but... what if we need to pass a regex? Oh well we can escape an eventual * you'd say. No: this * is impossible to escape!
-Acknowledgements and useful reads-
I got an invaluable and patient help from a wise one in the #perl freenode irc channel who pointed me to the relevant source code modifications needed and helped me to escape from dll hell.
They also explained me that glob expansion is disabled by default because MinGW used to enable it by default, but now while mingw-w64 crt defaults to disabled globbing, mingw-builds scripts, which is what most people use to build mingw, instead of doing that manually, do enable glob expansion by default.
There are other discrepancies: while in mingw-w64 _CRT_glob is a boolean in mingw.org it's a bitfield.. so good luck.
Also an interesting page about escaping in cmd.exe and a SO answer and dont miss everyone-quotes-command-line-arguments-the-wrong-way ( the last one added 2021-02-15, found here)
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.