Microsoft UCRT + BCX

Started by MrBcx, October 03, 2023, 12:40:21 PM

Previous topic - Next topic

MrBcx

I just took my first successful baby step into compiling for the UCRT.

PRINT "Hello, World!", compiled in BED with MSVC as the selected compiler,
created a 64-bit statically linked executable whose file size is 137kb.

Using the same, unedited .c file created by BCX and a new batch file,
I created a 64-bit executable with file size 12kb that uses the UCRT.

I have more to learn and more experimenting to do but I'm hoping, if all goes well,
that I'll be able to include an option on BED's BUILD dialog for building for the UCRT
using MSVC.  It also looks like adding that option for the MINGW compiler is a strong
possibility but I haven't tried that yet.

Having said all that, who among you that have compiled for the UCRT, can share any
experience, tips, or tricks which might quicken what I need to learn?

Reference:  https://learn.microsoft.com/en-us/cpp/windows/universal-crt-deployment?view=msvc-170

Vortex

Hi Kevin,

Thanks. Kindly, could you please upload your example built with BCX and UCRT?

MrBcx

Quote from: Vortex on October 03, 2023, 03:03:28 PM
Hi Kevin,

Thanks. Kindly, could you please upload your example built with BCX and UCRT?

I will share after I've tested more code with it.  I don't like uploading preliminary
and untested code or batch files.  That always leads to problems and otherwise
avoidable discussions when things go sideways.


MrBcx

#3
[UPDATE 1]

Below is the batch file I've been testing this afternoon. 
It only works with the Microsoft Visual Studio compiler tools  (cl.exe and link.exe). 
This batch file builds 64-bit apps from *.c and *.cpp files produced by BCX.

The paths are setup for my system - you will need to edit for yours.

Testing results.

There are 156 console mode demos in the \Con_Demo\ collection. 
153 successfully compiled, targeting the UCRT
Some compiled but had warnings ( deprecated functions, non-portability, etc ) but still ran.

I also tested this batch file to see what would happen with some of the more complex \GUI_DEMO\
files
.  I was amazed that they also compiled and ran correctly.  And has been mentioned before,
executable sizes were generally smaller. 

For example, the GUI_DEMO\Amort.bas, which creates a loan amortization table, normally has a file size of 52kb when statically linked to the Win32 libraries.  Linking to the UCRT resulted in Amort.exe being 24kb (less than half its normal file size)

There's still much to learn but I feel this is useful enough to release to our forum, so that we can gain more
experience with it.


SETLOCAL

SET  VCFOLDER=C:\VS2022\VC\Tools\MSVC\14.32.31326\bin\Hostx64\x64

call C:\VS2022\VC\Auxiliary\Build\vcvarsall.bat  x64

IF EXIST %1.cpp GOTO CPPFILE
IF EXIST %1.c   GOTO CFILE
GOTO USAGE

:CFILE
@ECHO Compiling %1 with MSVC for 64-bit
%VCFOLDER%\cl.exe /std:c++20 /permissive /O2 /c /Gd /W4 -D NTDDI_VERSION=0x0A000000 -D_WIN32_WINNT=0x0A000000 /MD /EHsc /Tp %1.c
GOTO LINK

:CPPFILE
@ECHO Compiling %1 with MSVC for 64-bit
%VCFOLDER%\cl.exe /std:c++20 /permissive /O2 /c /Gd /W4 -D NTDDI_VERSION=0x0A000000 -D_WIN32_WINNT=0x0A000000 /MD /EHsc /Tp %1.cpp
GOTO LINK

:LINK
@ECHO Linking %1
%VCFOLDER%\link %1.obj /OUT:%1.exe UCRT.LIB  %2  %3  %4  %5  %6  %7  %8  %9
ECHO Completed

goto done

:USAGE
ECHO **************************************************************
ECHO  VC64UCRT: VC64UCRT.bat MainFile ExtraFile1 ExtraFile2 ExtraFile3 ...
ECHO  Note: ExtraFiles can be .libs, .res , .obj
ECHO  Use this batch file to create console mode program
ECHO **************************************************************
:done

ENDLOCAL




jbk

#4
any chance for a mingw64 bat file?
I just tried it with a mingw-ucrt toolchain and it compiles and runs without complaint
when I look at the dll dependencies it looks like it's using the ucrt version of the dlls

MrBcx

#5
[UPDATE 2]

Just now, I used the batch file that I posted earlier to build BED.

That is confidence building!

This will be in the next release of BED.  It has been fully tested.
Console / Gui / Dll generation in 32-bit and 64-bit targeting the UCRT.

I've had a productive day!  8)



Robert

Quote from: MrBcx on October 03, 2023, 07:14:07 PM
[UPDATE 2]

Just now, I used the batch file that I posted earlier to build BED.

That is confidence building!

This will be in the next release of BED.  It has been fully tested.
Console / Gui / Dll generation in 32-bit and 64-bit targeting the UCRT.

I've had a productive day!  8)

You wild and crazy guy daredevil !

Didn't your mother tell you .... ?

For those BCXers who are wondering what's the deal or those who are thinking ... meh ... check these references

https://learn.microsoft.com/en-us/cpp/porting/upgrade-your-code-to-the-universal-crt?view=msvc-170

where it is stated

Quote

The Microsoft C Runtime Library (CRT) was refactored in Visual Studio 2015.
The Standard C Library, POSIX extensions and Microsoft-specific functions,
macros, and global variables were moved into a new library,
the Universal C Runtime Library (Universal CRT or UCRT).
The compiler-specific components of the CRT were moved into a new vcruntime library.


and here

https://learn.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-170

where we are informed

Quote
If you link your program from the command line
without a compiler option that specifies a C runtime library,
the linker will use the statically linked CRT libraries:
libcmt.lib, libvcruntime.lib, and libucrt.lib.

and if you really want to have yourself shaking in your boots checkout

Overview of potential upgrade issues

https://learn.microsoft.com/en-us/cpp/porting/overview-of-potential-upgrade-issues-visual-cpp?view=msvc-170&viewFallbackFrom=vs-2019

where they tell us that, under some circumstances, we gotta

Quote

... add the new library names in the second column
to the libraries in the first column.
Some of these libraries are import libraries, but that shouldn't matter.

If you were using:   You need to use these libraries:

libcmt.lib           libcmt.lib, libucrt.lib, libvcruntime.lib
libcmtd.lib          libcmtd.lib, libucrtd.lib, libvcruntimed.lib
msvcrt.lib           msvcrt.lib, ucrt.lib, vcruntime.lib
msvcrtd.lib          msvcrtd.lib, ucrtd.lib, vcruntimed.lib



Thanks MrBCX. Very  8) indeed.

MrBcx

Regarding making Mingw g++ work with UCRT, this is what worked for me.

Unlike MSVC, Mingw requires explicit static linking of lots of static libraries that are not part of UCRT,
in addition to adding -lucrt ( the UCRT library reference ) to the compiler instructions. 

But that's not all.
We also have to add the following which somehow tells the compiler to link and use the UCRT.

-static-libgcc   -static-libstdc++

So, if you have a favorite batch file for compiling console, gui, and dll using Mingw, simply add the following
to your compiler switches:   -lucrt  -static-libgcc  -static-libstdc++ and you should be good to go. 

Amort.bas compiles (64-bit)  to 72,704 without UCRT.

Amort.bas compiles (64-bit)  to 74,752 with      UCRT.

The compiler added references to these UCRT libraries inside Amort.exe

api-ms-win-crt-convert-l1-1-0.dll
api-ms-win-crt-environment-l1-1-0.dll 
api-ms-win-crt-heap-l1-1-0.dll
api-ms-win-crt-math-l1-1-0.dll
api-ms-win-crt-private-l1-1-0.dll
api-ms-win-crt-runtime-l1-1-0.dll
api-ms-win-crt-stdio-l1-1-0.dll
api-ms-win-crt-string-l1-1-0.dll

MrBcx

Quote from: Robert on October 03, 2023, 10:36:22 PM
Quote from: MrBcx on October 03, 2023, 07:14:07 PM
[UPDATE 2]

Just now, I used the batch file that I posted earlier to build BED.

That is confidence building!

This will be in the next release of BED.  It has been fully tested.
Console / Gui / Dll generation in 32-bit and 64-bit targeting the UCRT.

I've had a productive day!  8)

You wild and crazy guy daredevil !

Didn't your mother tell you .... ?



What can I say?  I enjoy running with scissors!  ;)

Robert

Quote from: MrBcx on October 04, 2023, 01:01:15 AM
Regarding making Mingw g++ work with UCRT, this is what worked for me.

Unlike MSVC, Mingw requires explicit static linking of lots of static libraries that are not part of UCRT,
in addition to adding -lucrt ( the UCRT library reference ) to the compiler instructions. 

But that's not all.
We also have to add the following which somehow tells the compiler to link and use the UCRT.

-static-libgcc   -static-libstdc++

So, if you have a favorite batch file for compiling console, gui, and dll using Mingw, simply add the following
to your compiler switches:   -lucrt  -static-libgcc  -static-libstdc++ and you should be good to go. 

Amort.bas compiles (64-bit)  to 72,704 without UCRT.

Amort.bas compiles (64-bit)  to 74,752 with      UCRT.

The compiler added references to these UCRT libraries inside Amort.exe

api-ms-win-crt-convert-l1-1-0.dll
api-ms-win-crt-environment-l1-1-0.dll 
api-ms-win-crt-heap-l1-1-0.dll
api-ms-win-crt-math-l1-1-0.dll
api-ms-win-crt-private-l1-1-0.dll
api-ms-win-crt-runtime-l1-1-0.dll
api-ms-win-crt-stdio-l1-1-0.dll
api-ms-win-crt-string-l1-1-0.dll

Hi MrBCX:

What flavor of MinGW are you using with these UCRT compiler switches ?

LLVM-MinGW and Winlibs both provide UCRT compiled toolchains with two different choices of CRT (C runtime), MSVCRT and UCRT. The compilers switches above are not needed for the UCRT toolchains.

MrBcx

#10
Quote from: Robert on October 04, 2023, 11:59:47 AM

Hi MrBCX:

What flavor of MinGW are you using with these UCRT compiler switches ?

LLVM-MinGW and Winlibs both provide UCRT compiled toolchains with two different choices of CRT (C runtime), MSVCRT and UCRT. The compilers switches above are not needed for the UCRT toolchains.

Hi Robert,

I'm using the Equation Solution package. 

I know a lot of people use the others, and I've tested them in the past on hundreds of demos.

The Equation Solution package is my hands down favorite for getting the job done.

[Added later]


If "flavors" of those other compiler systems limit their use of CRT to either MSVCRT or UCRT then
there would be no need for the switches.  The compiler builders could eliminate the need for the
switches in just a handful of lines of code.

One hopes those "flavors" would be smart enough to tolerate the switches, even if they are redundant.

MrBcx

I'm open to adding a MINGW (UCRT) option to the BED BUILD dialog.  And although I
have a batch file that seems to unlock that door, I'm not yet convinced that I have the best
solution. If in a few days time, no one has shared any alternatives, then I will likely add my
solution.  Like most things, it can always be revised/enhanced/removed, if needed.

Although much has been written about UCRT, my focus is on cutting through the noise and
getting UCRT to work with BCX.  If I can help BCX users leverage UCRT in an easy way
then I'll feel good about that. 

In the meantime, the MSVC (UCRT) option in BED goes a long way towards helping
us reap the benefits of UCRT.

Vortex

Hi Kevin,

Here is my test with Msys2 :

Starting the shell C:\msys64\ucrt64.exe :

User@Notebook UCRT64 ~
# cat hello.c
#include <stdio.h>

int main()
{
printf("Hello world!");
return 0;
}

User@Notebook UCRT64 ~
# gcc hello.c -o hello-ucrt64.exe -s

User@Notebook UCRT64 ~
# ldd hello-ucrt64.exe
        ntdll.dll => /c/Windows/SYSTEM32/ntdll.dll (0x77720000)
        kernel32.dll => /c/Windows/system32/kernel32.dll (0x77500000)
        KERNELBASE.dll => /c/Windows/system32/KERNELBASE.dll (0x7fefd2a0000)
        api-ms-win-crt-environment-l1-1-0.dll => /c/Windows/system32/api-ms-win-crt-environment-l1-1-0.dll (0x7fef5610000)
        ucrtbase.DLL => /c/Windows/system32/ucrtbase.DLL (0x7fef56e0000)
        api-ms-win-core-timezone-l1-1-0.dll => /c/Windows/system32/api-ms-win-core-timezone-l1-1-0.dll (0x7fef56d0000)
        api-ms-win-core-file-l2-1-0.dll => /c/Windows/system32/api-ms-win-core-file-l2-1-0.dll (0x7fef56c0000)
        api-ms-win-core-localization-l1-2-0.dll => /c/Windows/system32/api-ms-win-core-localization-l1-2-0.dll (0x7fef56b0000)
        api-ms-win-core-synch-l1-2-0.dll => /c/Windows/system32/api-ms-win-core-synch-l1-2-0.dll (0x7fefae70000)
        api-ms-win-core-processthreads-l1-1-1.dll => /c/Windows/system32/api-ms-win-core-processthreads-l1-1-1.dll (0x7fef56a0000)
        api-ms-win-core-file-l1-2-0.dll => /c/Windows/system32/api-ms-win-core-file-l1-2-0.dll (0x7fef5690000)
        api-ms-win-crt-heap-l1-1-0.dll => /c/Windows/system32/api-ms-win-crt-heap-l1-1-0.dll (0x7fef5680000)
        api-ms-win-crt-math-l1-1-0.dll => /c/Windows/system32/api-ms-win-crt-math-l1-1-0.dll (0x7fef55f0000)
        api-ms-win-crt-private-l1-1-0.dll => /c/Windows/system32/api-ms-win-crt-private-l1-1-0.dll (0x7fefaed0000)
        api-ms-win-crt-runtime-l1-1-0.dll => /c/Windows/system32/api-ms-win-crt-runtime-l1-1-0.dll (0x7fef6330000)
        api-ms-win-crt-stdio-l1-1-0.dll => /c/Windows/system32/api-ms-win-crt-stdio-l1-1-0.dll (0x7fef5660000)
        api-ms-win-crt-string-l1-1-0.dll => /c/Windows/system32/api-ms-win-crt-string-l1-1-0.dll (0x7fef5670000)
        api-ms-win-crt-time-l1-1-0.dll => /c/Windows/system32/api-ms-win-crt-time-l1-1-0.dll (0x7fef5600000)

User@Notebook UCRT64 ~
# ls -l hello-ucrt64.exe
-rwxr-xr-x 1 User None 18432 Oct  4 23:02 hello-ucrt64.exe

User@Notebook UCRT64 ~
# ./hello-ucrt64.exe
Hello world!

MrBcx

#13
Quote from: Vortex on October 04, 2023, 03:06:05 PM
Hi Kevin,

Here is my test with Msys2 :


Thanks Erol ... but generally speaking, in order to be useful with BCX, g++ is needed, not gcc.

Lcc-Win32 and Pelles have C++ extensions that BCX has relied upon from the beginning, most
importantly, the ability to use default arguments in FUNCTION and SUBs. The gcc compiler does
not have a default arguments extension. That's too bad because BCX uses hundreds of them.


BED has used the g++ (GNU's c++ compiler) from the beginning.  It obviously works great when
using BCX commands and functions that require a c++ compiler, such as CLASSES, NAMESPACES,
etc.  But g++ also works well as a C compiler, commonly stated as "Using C++ as a better C"

Robert

Test file:

#include <stdio.h>

int main()
{
printf("Hello world!");
return 0;
}

Using Visual Studio Community 2022 with MrBcx's compiler command

cl.exe /std:c++20 /permissive /O2 /c /Gd /W4 -D NTDDI_VERSION=0x0A000000 -D_WIN32_WINNT=0x0A000000 /MD /EHsc /Tp hello_ucrt.cpp

and MrBcx's linker command

link hello_ucrt.obj /OUT:WithUCRTLIB.exe UCRT.LIB

Running git bash ldd on the .exe outputs

$ ldd WithUCRTLIB.exe
        ntdll.dll => /c/Windows/SYSTEM32/ntdll.dll (0x7ffc0d010000)
        KERNEL32.DLL => /c/Windows/System32/KERNEL32.DLL (0x7ffc0c790000)
        KERNELBASE.dll => /c/Windows/System32/KERNELBASE.dll (0x7ffc0a850000)
        apphelp.dll => /c/Windows/SYSTEM32/apphelp.dll (0x7ffc07720000)
        ucrtbase.dll => /c/Windows/System32/ucrtbase.dll (0x7ffc0a390000)
        VCRUNTIME140.dll => /c/Windows/SYSTEM32/VCRUNTIME140.dll (0x7ffbf8090000
   
linking without UCRT.LIB on the linker command line, that is,

link hello_ucrt.obj /OUT:WithoutUCRTLIB.exe,

running git bash ldd on the .exe produces

ldd WithoutUCRTLIB.exe
        ntdll.dll => /c/Windows/SYSTEM32/ntdll.dll (0x7ffc0d010000)
        KERNEL32.DLL => /c/Windows/System32/KERNEL32.DLL (0x7ffc0c790000)
        KERNELBASE.dll => /c/Windows/System32/KERNELBASE.dll (0x7ffc0a850000)
        apphelp.dll => /c/Windows/SYSTEM32/apphelp.dll (0x7ffc07720000)
        ucrtbase.dll => /c/Windows/System32/ucrtbase.dll (0x7ffc0a390000)
        VCRUNTIME140.dll => /c/Windows/SYSTEM32/VCRUNTIME140.dll (0x7ffbf8090000
      
the same git bash ldd output as is produced with UCRT.LIB on the linker command line.