Upgrade from msvcrt.lib to ucrt.lib
With the minimum requirements for OCaml at Windows 10 (I think), we should consider moving off the legacy msvcrt.lib.
Here is the branch I have used for testing: https://github.com/jonahbeckford/flexdll/commits/0.43%2Bucrt
There are two blockers:
- https://github.com/ocaml/flexdll/issues/29 is probably related (I'm seeing this error only after upgrading to
ucrt.lib. - Some extra libraries are needed (not sure whether this belongs in ocaml/flexdll or ocaml/ocaml itself). I'll place each library in a separate comment below.
+ vcruntime.lib
Fixes:
** Cannot resolve symbols for C:\GitLab-Runner\builds\diskuv\distributions\1.0\dksdk-ffi-ocaml\build\DkSDKFiles\cfg-Release\o\bin\flexdll_msvc64.obj:
memcpy
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(ints.n.obj):
_fltused
memcpy
memmove
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(weak.n.obj):
memcpy
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(obj.n.obj):
memcpy
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(readlink.obj):
__chkstk
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(mmap_ba.obj):
memcpy
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(misc.n.obj):
memmove
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(extern.n.obj):
memcpy
memmove
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(_dn\lwt\src\unix\windows_pread_job.obj):
memcpy
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(startup_nat.n.obj):
_setjmp
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(time.obj):
_fltused
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(_dn\lwt\src\unix\windows_read_job.obj):
memcpy
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(domain.n.obj):
_fltused
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(compact.n.obj):
_fltused
memmove
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(roots_nat.n.obj):
memset
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(major_gc.n.obj):
_fltused
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(compare.n.obj):
_fltused
memcmp
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(io.n.obj):
memmove
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(bigarray.n.obj):
_fltused
memcpy
memmove
memset
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(backtrace.n.obj):
memcpy
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(getaddrinfo.obj):
memcpy
memset
strchr
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(sendrecv.obj):
__chkstk
memcpy
memmove
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(sys.n.obj):
__chkstk
_fltused
memmove
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(addrofstr.obj):
memset
strchr
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(strofaddr.obj):
memset
strchr
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(freelist.n.obj):
__chkstk
memcpy
memmove
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(minor_gc.n.obj):
_fltused
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(select.obj):
_fltused
memset
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(_dn\_opam\.opam-switch\build\cstruct.6.2.0\lib\cstruct_stubs.obj):
memcmp
memcpy
memmove
memset
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(memory.n.obj):
_fltused
memcpy
memset
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(callback.n.obj):
memcpy
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(win32.n.obj):
__chkstk
wcsstr
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(hash.n.obj):
_fltused
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(stat.obj):
__chkstk
_fltused
wcsrchr
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(times.obj):
_fltused
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(_dn\lwt\src\unix\lwt_unix_stubs.obj):
memcpy
memmove
memset
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(utimes.obj):
_fltused
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(gettimeofday.obj):
_fltused
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(array.n.obj):
_fltused
memcpy
memmove
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(st_stubs.n.obj):
_setjmp
longjmp
memmove
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(alloc.n.obj):
_fltused
memcpy
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(floats.n.obj):
_fltused
memcpy
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(getnameinfo.obj):
__chkstk
memset
strchr
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(md5.n.obj):
__chkstk
memcpy
memset
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(parsing.n.obj):
_fltused
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(_dn\lwt\src\unix\windows_write_job.obj):
memcpy
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(printexc.n.obj):
memmove
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(write.obj):
__chkstk
memmove
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(intern.n.obj):
_fltused
memcpy
** Cannot resolve symbols for tests\Units\test_arithmetic_c.lib(tests\Units\CMakeFiles\test_arithmetic_c.dir\arithmetic\arithmetic.c.obj):
_fltused
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(gmtime.obj):
_fltused
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(sleep.obj):
_fltused
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(sockopt.obj):
_fltused
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(gc_ctrl.n.obj):
_fltused
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(custom.n.obj):
_fltused
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(memprof.n.obj):
_fltused
memcpy
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(_dn\lwt\src\unix\windows_pwrite_job.obj):
memcpy
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(read.obj):
__chkstk
memmove
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(str.n.obj):
memcmp
memmove
memset
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(socketaddr.obj):
memmove
+ kernel32.lib
Fixes
** Cannot resolve symbols for descriptor object:
AddVectoredExceptionHandler
CloseHandle
CreateEventW
CreateFileMappingW
CreateFileW
CreateMutexW
CreatePipe
CreateProcessW
CreateThread
DeleteCriticalSection
DeleteFileW
DeviceIoControl
DuplicateHandle
EnterCriticalSection
ExitThread
FindClose
FindFirstFileW
FindNextFileW
FlushFileBuffers
FormatMessageA
FormatMessageW
FreeEnvironmentStringsW
FreeLibrary
GetConsoleMode
GetConsoleOutputCP
GetCurrentProcess
GetCurrentProcessId
GetCurrentThreadId
GetEnvironmentStringsW
GetEnvironmentVariableW
GetExitCodeProcess
GetFileAttributesW
GetFileInformationByHandle
GetFileType
GetFinalPathNameByHandleW
GetHandleInformation
GetLastError
GetModuleFileNameW
GetModuleHandleW
GetProcAddress
GetProcessTimes
GetSystemDirectoryA
GetSystemInfo
GetSystemTime
GetSystemTimeAsFileTime
GetTempFileNameW
GetTempPathW
GetVersionExW
InitializeCriticalSection
LeaveCriticalSection
LoadLibraryA
LoadLibraryExW
LoadLibraryW
LockFileEx
MapViewOfFile
MoveFileExW
MultiByteToWideChar
PeekConsoleInputW
PeekNamedPipe
QueryPerformanceCounter
ReadConsoleInputW
ReadFile
ReleaseMutex
RemoveVectoredExceptionHandler
ResetEvent
SearchPathW
SetConsoleCtrlHandler
SetConsoleOutputCP
SetEndOfFile
SetEvent
SetFilePointer
SetFilePointerEx
SetFileTime
SetHandleInformation
SetLastError
SignalObjectAndWait
Sleep
SystemTimeToFileTime
Sorry for the naïve question, but to make sure I understand: are we speaking here of linking the executables produced by flexlink/MSVC against ucrt? Somehow I remember that ever since switching to VS 2015, the executables produced by the OCaml comiler (via flexlink/MSVC) already depended on ucrt? I must be missing something...
The issue is that msvcrt and ucrt don't always play nicely when linked into an executable. From what I understand, we are supposed to be able to mix/match the old C runtime and the Universal C runtime, but we still can get conflicts:
msvcrtd.lib(gs_report.obj) : error LNK2005: __report_gsfailure already defined in vcruntimed.lib(VCRUNTIME140D.dll)
Seems safer just not to link to the old msvcrt runtime when it is not needed. Caveat: I am still testing.
A small summary is at https://www.msys2.org/docs/environments/#msvcrt-vs-ucrt:
Binaries linked with MSVCRT should not be mixed with UCRT ones because the internal structures and data types are different. (More strictly, object files or static libraries built for different targets shouldn't be mixed. DLLs built for different CRTs can be mixed as long as they don't share CRT objects, e.g. FILE*, across DLL boundaries.) Same rule is applied for MSVC compiled binaries because MSVC uses UCRT by default (if not changed).
@nojb "the executables produced by the OCaml comiler (via flexlink/MSVC) already depended on ucrt? I must be missing something...".
I suspect the new thing in VS 2015 was that the binaries started to depend on vcruntime140.dll. If so, that is independent of MSVCRT versus UCRT.
+ Compiler Routines
I believe these are the last missing symbols to be resolved:
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(ints.n.obj):
_fltused
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(readlink.obj):
__chkstk
** Cannot resolve symbols for tests\Units\test_arithmetic_ml.lib(startup_nat.n.obj):
_setjmp
From what I can tell these aren't defined in libraries but are instead emitted by the compiler and/or linker. For example, __chkstk should be emitted by MSVC to implement /Gs<n>: https://learn.microsoft.com/en-us/cpp/build/reference/gs-control-stack-checking-calls?view=msvc-170.
I am currently puzzled by why these symbols are not present! My guesses so far:
- Perhaps
link.exeis inserting these routines, andflexlink.exeis not doing the same? - Perhaps these symbols are in
.objfiles, butflexlink.exeis dropping these symbols for some weird reason.
Edit 1:
-
_fltusedis answered by https://stackoverflow.com/a/1583220.flexlink.exewill need to define this symbol but only if there is an external link to that symbol. The stackoverflow is incorrect though ... the real code isC:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\crt\src\vcruntime\fltused.cppand is defined to be0x9875.
Edit 2:
-
__chkstkis defined inC:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\crt\src\i386\chkstk.asm,C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.26.28801\crt\src\i386\chkstk.asm(etc.). - Better yet,
__chkstkcomes pre-compiled atC:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30133(etc.):./lib/arm/chkstk.obj ./lib/arm64/chkstk.obj ./lib/x64/chkstk.obj ./lib/x86/chkstk.obj
Edit 3:
-
_setjmp. I made a version https://github.com/diskuv/dkml-compiler/blob/main/src/f/setjmp.asm that can be included in github.com/ocaml/ocaml.
All the above still needs testing
+ msvcrt.lib (only for .exe link)
Fixes:
LINK : error LNK2001: unresolved external symbol wmainCRTStartup
src\MainCLI\main-cli.exe : fatal error LNK1120: 1 unresolved externals
Now it is weird that I am putting msvcrt.lib back in. But this is back not when linking DLLs; it is only back when linking .exe (the only place where CRT initialization should occur). And if necessary we could write our own CRT initialization routine just like https://github.com/ocaml/flexdll/blob/cc0525e99e7109c8d3206085759185bd733ac49f/flexdll_initer.c#L35-L55 is the DLL initialization routine. Confer: https://learn.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-170