ocaml / flexdll

a dlopen-like API for Windows
Other
100 stars 30 forks source link

Upgrade from msvcrt.lib to ucrt.lib #122

Open jonahbeckford opened 1 year ago

jonahbeckford commented 1 year ago

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:

  1. https://github.com/ocaml/flexdll/issues/29 is probably related (I'm seeing this error only after upgrading to ucrt.lib.
  2. 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.
jonahbeckford commented 1 year ago

+ 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
jonahbeckford commented 1 year ago

+ 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
nojb commented 1 year ago

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...

jonahbeckford commented 1 year ago

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.

jonahbeckford commented 1 year ago

+ 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:


Edit 1:

Edit 2:

Edit 3:

All the above still needs testing

jonahbeckford commented 1 year ago

+ 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