On Sat, 28 Sep 2024, Pali Rohár wrote:
MinGW-w64 still does not provide full ISO C95 or C99 compatibility for
applications. I was looking what is missing to get runtime library
compatibility for ISO C95. And I identified that missing parts for C95
are wcstok() and (v)swprintf() functions, which signatures in header
files and msvcrt.dll symbols are incompatible.
This patch series implements wcstok() and (v)swprintf() functions
compatible with C95 and C99 (and should be compatible also with later
ISO C versions). And brings C95 compatibility for all CRT import
libraries.
In __USE_MINGW_ANSI_STDIO=0 mode (v)swprintf() has one deviation from
ISO C95, its %s takes wchar_t* instead of char*. This is because of
msvcrt behavior. For C99 there are more deviations: missing C99 formats
which are unsupported by msvcr* DLL. In __USE_MINGW_ANSI_STDIO=1 mode
(v)swprintf() should be fully compatible with ISO C95 and C99.
This patch series also aligns API/ABI of (v)sw(n)printf() functions
between different __USE_MINGW_ANSI_STDIO modes, to make it sane and
consistent.
There are also new automated tests for some printf functions, so I would
be happy if somebody check that they are passing also on other machine
than mine.
I do not know of any other missing C95 functionality in MinGW-w64 but it
does not mean that there cannot be something still hidden.
Note that MinGW-w64 currently has swprintf() and wcstok() incompatible
with ISO C95+ and these changes will break compilation of applications
which depends on the current behavior. But this behavior is incompatible
with MSVC and also with Linux glibc headers, so I'm not sure how big
problem it is. I think that having swprintf() and wcstok() function
signatures different from what is in ISO C is bigger problem.
Previous API could be achieved by -D_CRT_NON_CONFORMING_SWPRINTFS and
-D_CRT_NON_CONFORMING_WCSTOK options (same as with msvc).
Also note that fix for wcstok() for clang builds would require Martin's
changes to llvm dlltool and linker.
Pali Rohár (15):
crt: Add support for C95 wcstok() function for non-UCRT import
libraries
headers: Fix _tcstok and _wcstok_l macros in _UNICODE mode
crt: Add support for C95 (v)swprintf() functions when
__USE_MINGW_ANSI_STDIO=0
crt: Add support for C95 (v)swprintf() functions when
__USE_MINGW_ANSI_STDIO=1
crt: Fix non-ISO (v)snwprintf() functions when
__USE_MINGW_ANSI_STDIO=0
crt: Add _(v)scwprintf emulation for msvcrt.dll
headers: Fix _stprintf and _vstprintf macros in _UNICODE mode
headers: Fix _*tscanf and _*tprintf macros which expands to ISO C
functions
crt: Add snprintf test
crt: Add swprintf test
crt: Add snwprintf test
crt: Add _stprintf test
crt: crtdll and msvcrt10: Add support for C95 getwc(), getwchar(),
putwc(), putwchar() functions
crt: crtdll and msvcrt10: Add support for C95 fputws() function
crt: crtdll and msvcrt10: Add support for C95 fgetws() function
I've started reading your patchset, but this will take some time to get
through.
I don't have a setup ready for running the tests from mingw-w64-crt, so I
can't see readily if those work as is - but I'd like to add some tests for
these functions in
https://github.com/mstorsjo/llvm-mingw/blob/master/test/crt-test.c where I
can test that they behave as expected.
I did try to run some general testing with these patches, but it does seem
break building in C++ mode, at least when building libc++ and libstdc++.
To ease validation of more complex patches for mingw-w64, like this, I've
tried to set up some sort of rough CI environment for it, on github. See
the topmost commit at https://github.com/mstorsjo/mingw-w64/commits/ci.
(The second topmost commit is a patch to temporarily work around a recent
breakage.)
It's quite easy to use this CI setup for your own patchsets, even if
mingw-w64 itself isn't hosted officially on github. Just make a personal
fork of https://github.com/mingw-w64/mingw-w64, and make a branch where
you add your own commits, and the commit from my branch. When you push
that to github, it will run the CI validation steps.
See https://github.com/mstorsjo/mingw-w64/actions/runs/11290055847 for an
example of such a run.
This CI environment does this:
- It takes an existing release of llvm-mingw, and rebuilds mingw-w64 on
top of it, and then rebuilds the runtimes (libunwind, libc++ etc) on top
of it. This is done for all of ucrt, ucrtbase and msvcrt, for all 4 target
architectures of llvm-mingw (i686, x86_64, armv7 and aarch64).
- It repackages the native Windows packages of llvm-mingw, with the newly
rebuilt runtimes included
- It builds GCC from scratch, as a cross compiler, with the current
mingw-w64 version to be tested, targeting x86_64. This is set up both with
ucrt and msvcrt.
- With the GCC from the previous step, it cross-builds a Windows-hosted
GCC compiler, both with ucrt and msvcrt.
To validate functionality of these rebuilt/updated toolchains, it does the
following tests:
- Tests running the llvm-mingw suite of smoke tests (including my
crt-test.c) for (i686, x86_64) x (msvcrt, ucrt, ucrtbase)
- It builds a couple of tests from my llvm-mingw testsuite, with GCC, and
tests running them
- With llvm-mingw, it tests cross compiling ffmpeg for all 4 target
architectures
- With llvm-mingw, it builds ffmpeg natively on i686 and x86_64 and runs
the runtime tests
- It runs the full libc++ testsuite, with i686 and ucrt. (This doesn't
pass with msvcrt.)
It should be fairly easy for you to look at the test setup and extend it
with more tests if you like that:
https://github.com/mstorsjo/mingw-w64/commit/679c506b76fad10867655e085cacac4741a9c434
With this setup, you should be able to iterate on your patchset and make
sure that it doesn't break any of these cases, before returning it to
review. With your patches applied, it fails like this:
https://github.com/mstorsjo/mingw-w64/actions/runs/11289029592/job/31398015190
// Martin
_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public