Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for MinGW #190

Closed
wants to merge 11 commits into from
Closed

Add support for MinGW #190

wants to merge 11 commits into from

Conversation

triplef
Copy link
Member

@triplef triplef commented Jan 4, 2021

These are some first steps to add support for MinGW, which was outlined by David as follows:

  1. Make libobjc2 build in a MinGW environment (and add MinGW to the test matrix eventually, though not until we’ve had a new LLVM release).
  2. Make it build the *NIX version of the exception handling code, not the Windows version, when targeting MinGW.
  3. Add a __gnustep_objc_personality_seh0 that calls _GCC_specific_handler, passing __gnustep_objc_personality_v0 as the last parameter (see: https://reviews.llvm.org/D49638).
  4. Modify clang using the patch to only use Windows native exceptions with an MSVC target triple and to use __gnustep_objc_personality_seh0 instead of the Windows C++ exception handler.

These patches do 1–3 above, including adding MinGW to CI using MSYS2 and the latest official Clang 11 from MSYS2 packages. This allows building the DLL in an MinGW environment, although building the tests currently expectantly fails on CI with the following errors (other tests involving exceptions fail with the same linker errors minus the vtable one):

FAILED: Test/ObjCXXEHInterop.exe 
cmd.exe /C "cd . && D:\a\msys64\mingw64\bin\clang.exe -Xclang -fexceptions -Xclang -fobjc-exceptions -O0 -Xclang -fno-inline -g -fuse-ld=lld Test/CMakeFiles/test_runtime.dir/Test.m.obj Test/CMakeFiles/ObjCXXEHInterop.dir/ObjCXXEHInterop.mm.obj Test/CMakeFiles/ObjCXXEHInterop.dir/ObjCXXEHInterop.m.obj -o Test\ObjCXXEHInterop.exe -Wl,--major-image-version,0,--minor-image-version,0  libobjc.dll.a  -lstdc++  -lgcc_s  -lgcc_s  -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 && cd ."
lld-link: error: undefined symbol: objc_exception_throw
>>> referenced by ../Test\ObjCXXEHInterop.mm:33
>>>               Test/CMakeFiles/ObjCXXEHInterop.dir/ObjCXXEHInterop.mm.obj:(poke_objcxx)
>>> referenced by ../Test\ObjCXXEHInterop.m:10
>>>               Test/CMakeFiles/ObjCXXEHInterop.dir/ObjCXXEHInterop.m.obj:(rethrow)

lld-link: error: undefined symbol: vtable for gnustep::libobjc::__objc_class_type_info
>>> referenced by Test/CMakeFiles/ObjCXXEHInterop.dir/ObjCXXEHInterop.mm.obj:(.weak.__objc_eh_typeinfo_Test.default.check_uncaught_count)

lld-link: error: undefined symbol: objc_begin_catch
>>> referenced by ../Test\ObjCXXEHInterop.m:19
>>>               Test/CMakeFiles/ObjCXXEHInterop.dir/ObjCXXEHInterop.m.obj:(main)

lld-link: error: undefined symbol: objc_end_catch
>>> referenced by ../Test\ObjCXXEHInterop.m:21
>>>               Test/CMakeFiles/ObjCXXEHInterop.dir/ObjCXXEHInterop.m.obj:(main)
>>> referenced by ../Test\ObjCXXEHInterop.m:21
>>>               Test/CMakeFiles/ObjCXXEHInterop.dir/ObjCXXEHInterop.m.obj:(main)

I’m unsure about the vtable issue, but I think fixing the other missing symbols requires patching Clang. I’m basically just running blind here as I have no knowledge of Clang internals, but I tried the following patch based on David’s patches sent on the mailing list, replacing EHPersonality::MSVC_CxxFrameHandler3 with EHPersonality::GNU_ObjC_SEH.

--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -2137,8 +2137,7 @@
     ProtocolVersion(protocolClassVersion), ClassABIVersion(classABI) {

   msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend");
-  usesSEHExceptions =
-      cgm.getContext().getTargetInfo().getTriple().isWindowsMSVCEnvironment();
+  usesSEHExceptions = cgm.getLangOpts().SEHExceptions;

   CodeGenTypes &Types = CGM.getTypes();
   IntTy = cast<llvm::IntegerType>(
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -142,6 +142,8 @@
   case ObjCRuntime::WatchOS:
     return EHPersonality::NeXT_ObjC;
   case ObjCRuntime::GNUstep:
+    if (L.SEHExceptions)
+      return EHPersonality::GNU_ObjC_SEH;
     if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
       return EHPersonality::GNUstep_ObjC;
     LLVM_FALLTHROUGH;
@@ -194,6 +196,8 @@
     return getObjCPersonality(Target, L);
 
   case ObjCRuntime::GNUstep:
+    if (L.SEHExceptions)
+      return EHPersonality::GNU_ObjC_SEH;
     return EHPersonality::GNU_ObjCXX;
 
   // The GCC runtime's personality function inherently doesn't support

This fixes the objc_begin_catch/objc_end_catch errors, but not objc_exception_throw and adds some new errors involving the standard library:

FAILED: Test/ObjCXXEHInterop.exe
cmd.exe /C "cd . && C:\msys64\mingw64\bin\clang.exe -Xclang -fexceptions -Xclang -fobjc-exceptions -fuse-ld=lld Test/CMakeFiles/test_runtime.dir/Test.m.obj Test/CMakeFiles/ObjCXXEHInterop.dir/ObjCXXEHInterop.mm.obj Test/CMakeFiles/ObjCXXEHInterop.dir/ObjCXXEHInterop.m.obj -o Test\ObjCXXEHInterop.exe -Wl,--major-image-version,0,--minor-image-version,0  libobjc.dll.a  C:/msys64/usr/lib/libm.a  -lstdc++  -lgcc_s  -lgcc_s  -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 && cd ."
lld-link: error: undefined symbol: objc_exception_throw
>>> referenced by Test/CMakeFiles/ObjCXXEHInterop.dir/ObjCXXEHInterop.mm.obj:(poke_objcxx)
>>> referenced by Test/CMakeFiles/ObjCXXEHInterop.dir/ObjCXXEHInterop.m.obj:(rethrow)
clang: error: linker command failed with exit code 1 (use -v to see invocation)
[138/214] Linking C executable Test\objc_msgSend.exe
FAILED: Test/objc_msgSend.exe
cmd.exe /C "cd . && C:\msys64\mingw64\bin\clang.exe -Xclang -fexceptions -Xclang -fobjc-exceptions -fuse-ld=lld Test/CMakeFiles/test_runtime.dir/Test.m.obj Test/CMakeFiles/objc_msgSend.dir/objc_msgSend.m.obj -o Test\objc_msgSend.exe -Wl,--major-image-version,0,--minor-image-version,0  libobjc.dll.a  C:/msys64/usr/lib/libm.a  -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 && cd ."
lld-link: error: undefined symbol: objc_exception_throw
>>> referenced by Test/CMakeFiles/objc_msgSend.dir/objc_msgSend.m.obj:(_c_MsgTest__initialize)

lld-link: error: undefined symbol: vtable for __cxxabiv1::__class_type_info
>>> referenced by Test/CMakeFiles/objc_msgSend.dir/objc_msgSend.m.obj:(typeinfo for objc_object)

lld-link: error: undefined symbol: vtable for __cxxabiv1::__pointer_type_info
>>> referenced by Test/CMakeFiles/objc_msgSend.dir/objc_msgSend.m.obj:(typeinfo for objc_object*)
clang: error: linker command failed with exit code 1 (use -v to see invocation)
[141/214] Linking C executable Test\NilException.exe

Note that the above is using libstdc++. I’m not sure if that’s what we want to use here – I also tried using libc++, which required some patching for the typeinfo test to work, but this resulted in the following errors linking the DLL:

FAILED: libobjc.dll libobjc.dll.a
cmd.exe /C "cd . && C:\msys64\mingw64\bin\clang.exe -Xclang -fexceptions -Xclang -fobjc-exceptions  -fuse-ld=lld -shared -o libobjc.dll -Wl,--out-implib,libobjc.dll.a -Wl,--major-image-version,0,--minor-image-version,0 CMakeFiles/objc.dir/alias_table.c.obj CMakeFiles/objc.dir/block_to_imp.c.obj CMakeFiles/objc.dir/caps.c.obj CMakeFiles/objc.dir/category_loader.c.obj CMakeFiles/objc.dir/class_table.c.obj CMakeFiles/objc.dir/dtable.c.obj CMakeFiles/objc.dir/encoding2.c.obj CMakeFiles/objc.dir/hooks.c.obj CMakeFiles/objc.dir/ivar.c.obj CMakeFiles/objc.dir/loader.c.obj CMakeFiles/objc.dir/mutation.m.obj CMakeFiles/objc.dir/protocol.c.obj CMakeFiles/objc.dir/runtime.c.obj CMakeFiles/objc.dir/sarray2.c.obj CMakeFiles/objc.dir/selector_table.c.obj CMakeFiles/objc.dir/sendmsg2.c.obj CMakeFiles/objc.dir/eh_personality.c.obj CMakeFiles/objc.dir/block_trampolines.S.obj CMakeFiles/objc.dir/objc_msgSend.S.obj CMakeFiles/objc.dir/eh_trampoline.s.obj CMakeFiles/objc.dir/NSBlocks.m.obj CMakeFiles/objc.dir/Protocol2.m.obj CMakeFiles/objc.dir/associate.m.obj CMakeFiles/objc.dir/blocks_runtime.m.obj CMakeFiles/objc.dir/properties.m.obj CMakeFiles/objc.dir/gc_none.c.obj CMakeFiles/objc.dir/arc.mm.obj CMakeFiles/objc.dir/objcxx_eh.cc.obj  -Wl,-Bstatic  -lc++abi  -Wl,-Bdynamic  C:/msys64/usr/lib/libm.a  -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 && cd ."
lld-link: error: undefined symbol: operator delete(void*)
>>> referenced by CMakeFiles/objc.dir/arc.mm.obj:(objc_storeWeak)
>>> referenced by CMakeFiles/objc.dir/arc.mm.obj:(incrementWeakRefCount(objc_object*))
>>> referenced by CMakeFiles/objc.dir/arc.mm.obj:(objc_loadWeakRetained)
>>> referenced 96 more times

lld-link: error: undefined symbol: operator new(unsigned long long)
>>> referenced by CMakeFiles/objc.dir/arc.mm.obj:(incrementWeakRefCount(objc_object*))

lld-link: error: undefined symbol: std::__1::__libcpp_execute_once(void**, void (*)())
>>> referenced by libc++abi.a(cxa_exception_storage.cpp.obj):(__cxa_get_globals)
>>> referenced by libc++abi.a(cxa_exception_storage.cpp.obj):(__cxa_get_globals_fast)

lld-link: error: undefined symbol: std::__1::__libcpp_tls_get(long)
>>> referenced by libc++abi.a(cxa_exception_storage.cpp.obj):(__cxa_get_globals)
>>> referenced by libc++abi.a(cxa_exception_storage.cpp.obj):(__cxa_get_globals_fast)

lld-link: error: undefined symbol: std::__1::__libcpp_tls_set(long, void*)
>>> referenced by libc++abi.a(cxa_exception_storage.cpp.obj):(__cxa_get_globals)
>>> referenced by libc++abi.a(cxa_exception_storage.cpp.obj):(__cxxabiv1::(anonymous namespace)::destruct_(void*))

lld-link: error: undefined symbol: std::__1::__libcpp_tls_create(long*, void (*)(void*))
>>> referenced by libc++abi.a(cxa_exception_storage.cpp.obj):(__cxxabiv1::(anonymous namespace)::construct_())

lld-link: error: undefined symbol: std::__1::__libcpp_mutex_lock(void**)
>>> referenced by libc++abi.a(cxa_guard.cpp.obj):(__cxa_guard_acquire)
>>> referenced by libc++abi.a(cxa_guard.cpp.obj):(__cxa_guard_release)
>>> referenced by libc++abi.a(cxa_guard.cpp.obj):(__cxa_guard_abort)
>>> referenced 4 more times

lld-link: error: undefined symbol: std::__1::__libcpp_condvar_wait(void**, void**)
>>> referenced by libc++abi.a(cxa_guard.cpp.obj):(__cxa_guard_acquire)

lld-link: error: undefined symbol: std::__1::__libcpp_mutex_unlock(void**)
>>> referenced by libc++abi.a(cxa_guard.cpp.obj):(__cxa_guard_acquire)
>>> referenced by libc++abi.a(cxa_guard.cpp.obj):(__cxa_guard_acquire)
>>> referenced by libc++abi.a(cxa_guard.cpp.obj):(__cxa_guard_release)
>>> referenced 5 more times

lld-link: error: undefined symbol: std::__1::__libcpp_condvar_broadcast(void**)
>>> referenced by libc++abi.a(cxa_guard.cpp.obj):(__cxa_guard_release)
>>> referenced by libc++abi.a(cxa_guard.cpp.obj):(__cxa_guard_abort)

I’d very much appreciate your further input @davidchisnall.

@triplef triplef force-pushed the mingw branch 8 times, most recently from c75e6df to a41b3f0 Compare January 6, 2021 13:02
@triplef triplef requested a review from davidchisnall January 7, 2021 13:06
@davidchisnall
Copy link
Member

Thanks, I hope to get to this at the weekend.

@davidchisnall
Copy link
Member

Please can you add some instructions for how to build with MinGW? I have installed msys2 from choco and started the msys2 shell. I have run:

$ pacman --needed -S mingw-w64-x86_64-cmake
$ pacman --needed -S mingw-w64-x86_64-ninja

These seem to have worked (running them again tells me that these things are already installed) but cmake is not in my path and neither is ninja. I can't test or work on this if I can't build it.

So far my experience with MinGW makes me absolutely loath it. It's painfully slow, it doesn't let me use a modern terminal, and it is incredibly badly documented.

@triplef
Copy link
Member Author

triplef commented Jan 9, 2021

Yeah the documentation is definitely lacking. The thing to know is that there are three subsystems with mostly separate binaries and installation paths: MSYS, mingw32, and mingw64. Since you installed the 64-bit packages they will only be available in the mingw64 environment. This page has a bit more info about this:
https://www.msys2.org/wiki/MSYS2-introduction/

You'll want to launch a mingw64 shell by running e.g.:
<msys-root>/msys2_shell.cmd -defterm -mingw64 -here
And then run cmake and ninja there.

If you use the MSYS2 installer you'll get Start menu launchers for the different shells. You can also add the different shells to Windows Terminal:
https://www.msys2.org/docs/terminals/

(In the CI script, to avoid further branching I'm running CMake directly in the native CMD shell, but it picks up the right clang binary because I added the mingw64 bin directory to the path. ninja needs the bash shell tho to run some of the scripts, so it's easiest to just run everything from the MinGW shell.)

Hope that helps! Thanks for giving it a try and please let me know if you need more info.

@davidchisnall
Copy link
Member

At the moment, I have a small time window each weekend when I can spare the time to work on this. I still can't build it. Please can you provide me with step-by-step instructions for building with a freshly built LLVM? I now have the MinGW shell working and CMake runs. I need to invoke it with:

cmake .. -G Ninja -DCMAKE_C_COMPILER=${LLVM_BUILD_PATH}/bin/clang.exe -DCMAKE_CXX_COMPILER=${LLVM_BUILD_PATH}/bin/clang++.exe -DCMAKE_RC_COMPILER=${LLVM_BUILD_PATH}/bin/llvm-rc.exe -DCMAKE_SHARED_LINKER_FLAGS='-fuse-ld=lld' -DCMAKE_EXE_LINKER_FLAGS='-fuse-ld=lld'

I now get a load of link failures for things like malloc and other libc symbols. It's also missing symbols for _DllMainCRTStartup and __acrt_iob_func, so it looks as if we're not linking the C runtime? I thought MinGW did that automatically. Do I need some MinGW-specific patches to LLVM to be able to build? If so, where do I find those (is there a git branch I can grab for my LLVM source tree)?

A bit more poking and it turns out that CMake isn't passing a MinGW triple. I (try to) fix that by adding this to my CMake invocation:

-DCMAKE_C_FLAGS='-target x86_64-pc-mingw64' -DCMAKE_CXX_FLAGS='-target x86_64-pc-mingw64'

Now it fails to compile because it can't find sys/types.h. Which, apparently, isn't in my MinGW install at all:

$ find / -name types.h
/mingw64/include/brotli/types.h

I am trying to minimise my stress levels this year, after a particularly stressful 2020. I have now reached my limit in frustration with this for today and am going to step away from my computer. I'll have another try next weekend. If you can provide me with instructions that I can use for building and testing it with an LLVM that I have built from source, using the normal LLVM build process for Windows, then I will be able to make the required clang changes.

@triplef
Copy link
Member Author

triplef commented Jan 18, 2021

Thank you very much for looking into this further, I am sorry this is not so straightforward.

I’ll try to get you step-by-step instructions for building Clang main with the MinGW Clang patches by next weekend. I had previously built the MinGW Clang package directly (using makepkg), which applies these patches automatically, but for the purposes of working on Clang sources I can see you’ll want to use the normal LLVM build process instead.

@gcasa
Copy link
Member

gcasa commented Feb 7, 2021

The libobjc2 library needs to be buildable under MSYS2. I would very much like to get clang working WITHOUT, I REPEAT WITHOUT using Visual Studio or any MS tools in any way, shape, or form.

@gcasa
Copy link
Member

gcasa commented Feb 7, 2021

The libobjc2 library needs to be buildable under MSYS2. I would very much like to get clang working WITHOUT, I REPEAT WITHOUT using Visual Studio or any MS tools in any way, shape, or form.

I really hate to keep emphasizing this!

@davidchisnall
Copy link
Member

The libobjc2 library needs to be buildable under MSYS2. I would very much like to get clang working WITHOUT, I REPEAT WITHOUT using Visual Studio or any MS tools in any way, shape, or form.

I really hate to keep emphasizing this!

Then please don't. You are contributing nothing to the discussion other than demands for unpaid volunteers to do work that you think is important.

@gcasa
Copy link
Member

gcasa commented Feb 7, 2021

The libobjc2 library needs to be buildable under MSYS2. I would very much like to get clang working WITHOUT, I REPEAT WITHOUT using Visual Studio or any MS tools in any way, shape, or form.

I really hate to keep emphasizing this!

Then please don't. You are contributing nothing to the discussion other than demands for unpaid volunteers to do work that you think is important.

David,

My sincere apologies if you thought I was asking for that. I had simply thought that it was something that would be easy for you to do.

I will create a branch and work on some changes which will make it possible to build on the MSYS2 command line. I may have questions for you along these lines. While working purely in Visual Studio is a nice idea I would still like for it to be possible to build from the MSYS2 command line. I will let you know when the changes are ready for review.

Yours... GC

@triplef
Copy link
Member Author

triplef commented Feb 8, 2021

Greg, thanks for your offer to help with this. I just want to make sure we’re all on the same page here: were you taking about a libobjc2 or LLVM branch you want to work on?

This libobjc2 branch mingw should already contain all necessary changes for building it under MSYS2/MinGW, including adding this configuration to CI using MSYS2.

The outstanding issue is the ObjC runtime support in Clang needing changes to work with MinGW. In order for David to be able to look into this, we need to figure out how to build LLVM with the MinGW patches in such a way that he can work on it. Last time I tried this I got an error "number of sections exceeded object file", but I’m planning to look into this further.

@triplef
Copy link
Member Author

triplef commented Mar 5, 2021

So instead of trying to compile LLVM with the MinGW patches, I’ve tried to get the standard Clang to use the MinGW ABI and made a bit of progress here.

First, one needs to make sure to use the "normal" Windows Ninja, not the one from MinGW as it will choke on Windows paths. If you installed LLVM and Ninja via Chocolatey just add their directories to your path in the MinGW shell:

export PATH="$PATH:/c/Program Files/LLVM/bin:/c/ProgramData/chocolatey/bin"

Then we tell CMake to use the x86_64-w64-mingw64 target triple, the MinGW sysroot, and tell it to use libc++:

cmake .. -G Ninja -DTESTS=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_ASM_COMPILER=clang \
  -DCMAKE_SHARED_LINKER_FLAGS='-fuse-ld=lld' -DCMAKE_EXE_LINKER_FLAGS='-fuse-ld=lld' \
  -DCMAKE_C_COMPILER_TARGET=x86_64-w64-mingw64 -DCMAKE_CXX_COMPILER_TARGET=x86_64-w64-mingw64 -DCMAKE_ASM_COMPILER_TARGET=x86_64-w64-mingw64 \
  -DCMAKE_SYSROOT=/mingw64 \
  -DCMAKE_CXX_FLAGS=-stdlib=libc++

The remaining problem I have is that the try_compile for typeinfo_test.cc is failing, so no C++ runtime is detected:

  [2/4] Building CXX object
  CMakeFiles/test_cxx_runtime.dir/typeinfo_test.cc.obj

  [3/4] Linking C executable test_cxx_runtime.exe

  FAILED: test_cxx_runtime.exe

  cmd.exe /C "cd .  && C:\PROGRA~1\LLVM\bin\clang.exe
  --target=x86_64-w64-mingw64 --sysroot=C:/msys64/mingw64
  -fuse-ld=lld CMakeFiles/test_cxx_runtime.dir/typeinfo_test.cc.obj -o
  test_cxx_runtime.exe -Wl,--major-image-version,0,--minor-image-version,0
  C:/msys64/usr/lib/libm.a -Wl,-Bstatic -lc++abi -Wl,-Bdynamic -lkernel32
  -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32
  -ladvapi32 && cd ."

  lld-link: error: undefined symbol: operator delete(void*)

  >>> referenced by
  CMakeFiles/test_cxx_runtime.dir/typeinfo_test.cc.obj:(type_info2::~type_info2())


  >>> referenced by
  libc++abi.a(stdlib_typeinfo.cpp.obj):(std::type_info::~type_info())

  >>> referenced by
  libc++abi.a(stdlib_typeinfo.cpp.obj):(std::bad_cast::~bad_cast())

  >>> referenced 90 more times



  lld-link: error: undefined symbol: std::__1::__libcpp_execute_once(void**,
  void (*)())

  >>> referenced by
  libc++abi.a(cxa_exception_storage.cpp.obj):(__cxa_get_globals)

  >>> referenced by
  libc++abi.a(cxa_exception_storage.cpp.obj):(__cxa_get_globals_fast)



  lld-link: error: undefined symbol: std::__1::__libcpp_tls_get(long)

  >>> referenced by
  libc++abi.a(cxa_exception_storage.cpp.obj):(__cxa_get_globals)

  >>> referenced by
  libc++abi.a(cxa_exception_storage.cpp.obj):(__cxa_get_globals_fast)

...

I’m guessing we need to pass some additional options to try_compile() in the test_cxx function. I’m already passing the target and sysroot for the above test, but that doesn’t seem to be enough. Any idea?

		try_compile(USERUNTIME 
			"${CMAKE_BINARY_DIR}/CMake"
			"${CMAKE_CURRENT_LIST_DIR}/CMake"
			test_cxx_runtime
			CMAKE_FLAGS "-DCXX_RUNTIME=${CXX_RUNTIME_LIB}"
				"-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}"
				"-DCMAKE_C_COMPILER_TARGET=${CMAKE_C_COMPILER_TARGET}"
				"-DCMAKE_CXX_COMPILER_TARGET=${CMAKE_CXX_COMPILER_TARGET}"
				"-DCMAKE_SYSROOT=${CMAKE_SYSROOT}"
				${CXX_RUNTIME_FLAGS}
			OUTPUT_VARIABLE TRY_COMPILE_OUTPUT)
		message(WARNING ${TRY_COMPILE_OUTPUT})

@triplef
Copy link
Member Author

triplef commented Mar 8, 2021

I got it working thanks to the help of the MinGW folks!

@davidchisnall the following steps should allow you to build libobjc2 for MinGW using the standard Windows (non-MinGW) Clang, and thereby also enable you to use the normal LLVM/Clang build process for Windows in order to debug this further. I tested this with a clean MSYS2 installation.

  1. Download this CMake toolchain file clang-mingw.cmake.txt (rename to clang-mingw.cmake).
  2. Open a MinGW 64-bit shell, e.g. using:
    C:\tools\msys64\msys2_shell.cmd -mingw64
  3. Uninstall MinGW Ninja if needed, as we’ll need to use Windows Ninja for Windows Clang to get Windows-style paths:
    pacman -R mingw-w64-x86_64-ninja
  4. Uninstall MinGW Clang if needed so it doesn’t get picked up by CMake:
    pacman -R mingw-w64-x86_64-clang
  5. Make sure you have CMake and GCC installed (GCC is needed for the system libraries):
    pacman --needed -S mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc
  6. Add the Ninja installation directory from Windows (installed via Chocolatey) to your PATH, as well as the LLVM bin dir (here I’m using LLVM installed via Chocolatey, so you will have to change this path when building your own):
    export PATH="$PATH:/c/ProgramData/chocolatey/bin:/c/Program Files/LLVM/bin"
  7. Make sure you’re on the libobjc2 branch mingw.
  8. Run CMake by specifying the toolchain file:
    cmake .. -G Ninja -DTESTS=ON -DCMAKE_TOOLCHAIN_FILE=path/to/clang-mingw.cmake
  9. Build:
    ninja

This should result in the exact same build errors as we’re seeing here on the CI, and which I presume will require changes in Clang, i.e.:

lld-link: error: undefined symbol: objc_exception_throw
>>> referenced by Test/CMakeFiles/ObjCXXEHInterop.dir/ObjCXXEHInterop.mm.obj:(poke_objcxx)
>>> referenced by Test/CMakeFiles/ObjCXXEHInterop.dir/ObjCXXEHInterop.m.obj:(rethrow)

lld-link: error: undefined symbol: vtable for gnustep::libobjc::__objc_class_type_info
>>> referenced by Test/CMakeFiles/ObjCXXEHInterop.dir/ObjCXXEHInterop.mm.obj:(.weak.__objc_eh_typeinfo_Test.default.check_uncaught_count)

lld-link: error: undefined symbol: objc_begin_catch
>>> referenced by Test/CMakeFiles/ObjCXXEHInterop.dir/ObjCXXEHInterop.m.obj:(main)

lld-link: error: undefined symbol: objc_end_catch
>>> referenced by Test/CMakeFiles/ObjCXXEHInterop.dir/ObjCXXEHInterop.m.obj:(main)
>>> referenced by Test/CMakeFiles/ObjCXXEHInterop.dir/ObjCXXEHInterop.m.obj:(main)

Copy link
Member

@davidchisnall davidchisnall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed some changes that allow me to compile and link everything (with a one-line patch to clang):

--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -144,7 +144,8 @@ static const EHPersonality &getObjCPersonality(const TargetInfo &Target,
   case ObjCRuntime::WatchOS:
     return EHPersonality::NeXT_ObjC;
   case ObjCRuntime::GNUstep:
-    if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
+    if (!L.hasSEHExceptions() &&
+        (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7)))
       return EHPersonality::GNUstep_ObjC;
     LLVM_FALLTHROUGH;
   case ObjCRuntime::GCC:

The exception tests are all failing; however. What do you use to debug things with MinGW? WinDBG doesn't seem to like MinGW .exes.

@@ -7,6 +7,14 @@
#include "class.h"
#include "objcxx_eh.h"

#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The second of these is never defined.

Suggested change
#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
#ifdef __SEH__

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I copied those lines from libcxxabi, but I’d be fine with removing that second check if we can’t come up with a reason for having it.

@@ -584,6 +596,16 @@ BEGIN_PERSONALITY_FUNCTION(__gnustep_objcxx_personality_v0)
return CALL_PERSONALITY_FUNCTION(__gxx_personality_v0);
}

#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
#ifdef __SEH__

@triplef
Copy link
Member Author

triplef commented Apr 2, 2021

I've pushed some changes that allow me to compile and link everything (with a one-line patch to clang):

Nice!

The exception tests are all failing; however. What do you use to debug things with MinGW? WinDBG doesn't seem to like MinGW .exes.

Good question. Maybe @mstorsjo would know?

@triplef
Copy link
Member Author

triplef commented Apr 2, 2021

I'm guessing GDB or lldb from MSYS2 should work.

pacman -S gdb

@davidchisnall
Copy link
Member

I've tried installing gdb in mingw, but it doesn't seem to be able to set breakpoints (even one on main).

@davidchisnall
Copy link
Member

There's something odd with MinGW's bridging of the SEH and DWARF EH models that is breaking the code that tries to figure out the layout of the C++ exception structure. I've pushed changes that let me pass all of the tests except those related to C++ exception interop.

It looks as if the __gxx_personality_v0 symbol isn't exported from the C++ runtime with MinGW, so we can't wrap it for Objective-C++ anyway. I don't see any way of getting C++ exception interop working with MinGW. If you know anyone on the MinGW project, perhaps they could help? My experience so far is that the MinGW environment is just sufficiently different from Windows and *NIX to be annoyingly incompatible with both and a massive pain to work with.

@davidchisnall
Copy link
Member

Thinking a bit more about it, the right strategy for MinGW may be to simply punt all exception handling to the C++ runtime, as Apple does.

@triplef
Copy link
Member Author

triplef commented Jul 22, 2021

I just saw that MSYS2 added a new "CLANG64" environment that is using an LLVM toolchain and libc++:
https://www.msys2.org/docs/environments/

Maybe that's more compatible with libobj2's EH integration. I'll give it a try.

triplef and others added 9 commits July 25, 2021 20:13
Enables building *NIX exception model with MinGW.
MinGW does not like the leading underscores.
All EH-related tests still fail.
The test personality function that attempts to understand the structure
of the C++ exception is now correctly set up, though it is not yet
called.
MinGW provides something that is almost the same as the Itanium ABI, but
with subtle differences.  Fix the structure layouts to account for this.

Disable the C++ exception structure layout check with MinGW - it is
currently broken and causes *all* exceptions to break.  Disabling it
just causes C++ exceptions to crash the program, rather than all
exceptions.
@triplef triplef force-pushed the mingw branch 4 times, most recently from e5023e0 to 63c81f5 Compare July 25, 2021 19:19
@triplef
Copy link
Member Author

triplef commented Jul 28, 2021

I tried using the MSYS2 CLANG64 environment, which uses clang and libc++ by default, but it’s failing with the following linker errors. Any ideas?

lld-link: error: undefined symbol: test_eh_personality_internal
>>> referenced by CMakeFiles/objc.dir/eh_personality.c.obj:(test_eh_personality)

lld-link: error: undefined symbol: cxx_throw()
>>> referenced by CMakeFiles/objc.dir/eh_trampoline.s.obj:(eh_trampoline())

@triplef
Copy link
Member Author

triplef commented Jan 2, 2024

Closing this as basic MinGW support was added in #254.

@triplef triplef closed this Jan 2, 2024
@triplef triplef deleted the mingw branch January 2, 2024 12:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants