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
13 changes: 8 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ set(libBlocksRuntime_COMPATIBILITY_HDRS
Block.h
Block_private.h
)
# Windows does not use DWARF EH
if (WIN32)
# Windows MSVC does not use DWARF EH
if (MSVC)
list(APPEND libobjc_CXX_SRCS eh_win32_msvc.cc)
else ()
list(APPEND libobjc_C_SRCS eh_personality.c)
endif (WIN32)
endif (MSVC)

if (NOT EXISTS "${CMAKE_SOURCE_DIR}/third_party/robin-map/include/tsl/robin_map.h")
message(FATAL_ERROR "Git submodules not present, please run:\n\n"
Expand Down Expand Up @@ -279,7 +279,7 @@ endif()


if (ENABLE_OBJCXX)
if (WIN32)
if (MSVC)
message(STATUS "Using MSVC-compatible exception model")
else ()
message(STATUS "Testing C++ interop")
Expand Down Expand Up @@ -322,8 +322,11 @@ if (ENABLE_OBJCXX)
if (CMAKE_CXX_COMPILER_TARGET)
list(APPEND EH_PERSONALITY_FLAGS "${CMAKE_CXX_COMPILE_OPTIONS_TARGET}${CMAKE_CXX_COMPILER_TARGET}")
endif ()
if (NOT WIN32)
list(APPEND EH_PERSONALITY_FLAGS "-fPIC")
endif ()
add_custom_command(OUTPUT eh_trampoline.s
COMMAND ${CMAKE_CXX_COMPILER} ARGS ${EH_PERSONALITY_FLAGS} -fPIC -S "${CMAKE_SOURCE_DIR}/eh_trampoline.cc" -o - -fexceptions -fno-inline | sed "s/__gxx_personality_v0/test_eh_personality/g" > "${CMAKE_BINARY_DIR}/eh_trampoline.s"
COMMAND ${CMAKE_CXX_COMPILER} ARGS ${EH_PERSONALITY_FLAGS} -S "${CMAKE_SOURCE_DIR}/eh_trampoline.cc" -o - -fexceptions -fno-inline | sed "s/__gxx_personality_v0/test_eh_personality/g" | sed "s/__gxx_personality_seh0/test_eh_personality/g" > "${CMAKE_BINARY_DIR}/eh_trampoline.s"
MAIN_DEPENDENCY eh_trampoline.cc)
list(APPEND libobjc_ASM_SRCS eh_trampoline.s)
list(APPEND libobjc_CXX_SRCS objcxx_eh.cc)
Expand Down
84 changes: 66 additions & 18 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,61 +121,109 @@ jobs:
inputs:
testResultsFormat: cTest
testResultsFiles: build/Testing/*/Test.xml

- job: Windows
displayName: Windows-2016
pool:
vmImage: vs2017-win2016
strategy:
matrix:
Debug-32:
MSVC-Debug-32:
BuildType: Debug
Arch: x64_x86
Flags: -m32
Release-32:
MSVC-Release-32:
BuildType: Release
Arch: x64_x86
Flags: -m32
Debug-64:
MSVC-Debug-64:
BuildType: Debug
Arch: x64
Flags: -m64
Release-64:
MSVC-Release-64:
BuildType: Release
Arch: x64
Flags: -m64
MSYS2-CLANG64-Debug-32:
BuildType: Debug
Arch: x86_64
Flags: -m32
MSYSTEM: clang64
MSYS2-CLANG64-Release-32:
BuildType: Release
Arch: x86_64
Flags: -m32
MSYSTEM: clang64
MSYS2-CLANG64-Debug-64:
BuildType: Debug
Arch: x86_64
Flags: -m64
MSYSTEM: clang64
MSYS2-CLANG64-Release-64:
BuildType: Release
Arch: x86_64
Flags: -m64
MSYSTEM: clang64
variables:
Flags:
MSYS2_ROOT: $(System.Workfolder)\msys2
MinGW_Shell: '%MSYS2_ROOT%\msys2_shell.cmd -defterm -no-start -%MSYSTEM% -full-path -here -c'
steps:
- checkout: self
submodules: true
- script: |
choco.exe install ninja
choco.exe install llvm


IF DEFINED MSYSTEM (
echo Installing MSYS2...
choco.exe install --no-progress --params="/InstallDir:$(MSYS2_ROOT)" msys2
echo Installing packages...
$(MSYS2_ROOT)\usr\bin\pacman --noconfirm --needed -S ^
mingw-w64-clang-$(Arch)-cmake ^
mingw-w64-clang-$(Arch)-ninja ^
mingw-w64-clang-$(Arch)-toolchain
echo Setting PATH for subsequent tasks...
echo "##vso[task.setvariable variable=PATH]$(MSYS2_ROOT)\$(MSYSTEM)\bin;%PATH%"
) else (
choco.exe install --no-progress ninja
choco.exe install --no-progress llvm
)
displayName: 'Install Dependencies'

- script: |
echo Creating build directory...
mkdir build
cd build
echo Importing visual studio environment variables...
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat" $(Arch)
echo Checking that we're calling the correct link.exe
where link.exe
IF DEFINED MSYSTEM (
set CC=clang
set CXX=clang++
) else (
echo Importing visual studio environment variables...
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat" $(Arch)
echo Checking that we're calling the correct link.exe
where link.exe
set "CC=C:/Program Files/LLVM/bin/clang-cl.exe"
set "CXX=C:/Program Files/LLVM/bin/clang-cl.exe"
)
set CFLAGS=$(Flags)
set CXXFLAGS=$(Flags)
echo Running cmake...
cmake .. -G Ninja -DTESTS=ON -DCMAKE_C_COMPILER="c:/Program Files/LLVM/bin/clang-cl.exe" -DCMAKE_CXX_COMPILER="c:/Program Files/LLVM/bin/clang-cl.exe" -DCMAKE_BUILD_TYPE=$(BuildType)
cmake .. -G Ninja -DTESTS=ON -DCMAKE_C_COMPILER="%CC%" -DCMAKE_CXX_COMPILER="%CXX%" -DCMAKE_BUILD_TYPE=$(BuildType)
echo CMake completed.

failOnStderr: false
displayName: 'CMake'

- script: |
cd build
echo Importing visual studio environment variables...
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat" $(Arch)
set CCC_OVERRIDE_OPTIONS=x-TC x-TP x/TC x/TP
echo Running ninja...
ninja
IF DEFINED MSYSTEM (
echo Running ninja...
$(MinGW_Shell) "ninja"
) else (
echo Importing visual studio environment variables...
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat" $(Arch)
set CCC_OVERRIDE_OPTIONS=x-TC x-TP x/TC x/TP
echo Running ninja...
ninja
)
echo Ninja completed.

failOnStderr: false
Expand Down
51 changes: 42 additions & 9 deletions eh_personality.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@
#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.

#include <windows.h>
#include <winnt.h>

EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
PDISPATCHER_CONTEXT, void *);
DECLARE_PERSONALITY_FUNCTION(test_eh_personality_internal);
#endif

#ifndef DEBUG_EXCEPTIONS
#define DEBUG_LOG(...)
#else
Expand Down Expand Up @@ -184,14 +193,14 @@ static void cleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception *e)
*/
}

void objc_exception_rethrow(struct _Unwind_Exception *e);
OBJC_PUBLIC void objc_exception_rethrow(struct _Unwind_Exception *e);

/**
* Throws an Objective-C exception. This function is, unfortunately, used for
* rethrowing caught exceptions too, even in @finally() blocks. Unfortunately,
* this means that we have some problems if the exception is boxed.
*/
void objc_exception_throw(id object)
OBJC_PUBLIC void objc_exception_throw(id object)
{
struct thread_data *td = get_thread_data();
DEBUG_LOG("Throwing %p, in flight exception: %p\n", object, td->lastThrownObject);
Expand Down Expand Up @@ -391,7 +400,10 @@ static inline _Unwind_Reason_Code internal_objc_personality(int version,
#ifndef NO_OBJCXX
if (cxx_exception_class == 0)
{
#ifndef __SEH__
// FIXME: This is currently broken with MinGW
test_cxx_eh_implementation();
#endif
}

if (exceptionClass == cxx_exception_class)
Expand Down Expand Up @@ -535,25 +547,29 @@ static inline _Unwind_Reason_Code internal_objc_personality(int version,
}
}

_Unwind_SetIP(context, (unsigned long)action.landing_pad);
_Unwind_SetIP(context, (uintptr_t)action.landing_pad);
_Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
(unsigned long)(isNew ? exceptionObject : object));
(uintptr_t)(isNew ? exceptionObject : object));
_Unwind_SetGR(context, __builtin_eh_return_data_regno(1), selector);

DEBUG_LOG("Installing context, selector %d\n", (int)selector);
get_thread_data()->cxxCaughtException = NO;
return _URC_INSTALL_CONTEXT;
}

OBJC_PUBLIC
BEGIN_PERSONALITY_FUNCTION(__gnu_objc_personality_v0)
return internal_objc_personality(version, actions, exceptionClass,
exceptionObject, context, NO);
}

OBJC_PUBLIC
BEGIN_PERSONALITY_FUNCTION(__gnustep_objc_personality_v0)
return internal_objc_personality(version, actions, exceptionClass,
exceptionObject, context, YES);
}

OBJC_PUBLIC
BEGIN_PERSONALITY_FUNCTION(__gnustep_objcxx_personality_v0)
#ifndef NO_OBJCXX
if (cxx_exception_class == 0)
Expand All @@ -569,11 +585,11 @@ BEGIN_PERSONALITY_FUNCTION(__gnustep_objcxx_personality_v0)
}
// We now have two copies of the _Unwind_Exception object (which stores
// state for the unwinder) in flight. Make sure that they're in sync.
COPY_EXCEPTION(ex->cxx_exception, exceptionObject)
COPY_EXCEPTION(ex->cxx_exception, exceptionObject);
exceptionObject = ex->cxx_exception;
exceptionClass = cxx_exception_class;
int ret = CALL_PERSONALITY_FUNCTION(__gxx_personality_v0);
COPY_EXCEPTION(exceptionObject, ex->cxx_exception)
COPY_EXCEPTION(exceptionObject, ex->cxx_exception);
if (ret == _URC_INSTALL_CONTEXT)
{
get_thread_data()->cxxCaughtException = YES;
Expand All @@ -584,7 +600,24 @@ BEGIN_PERSONALITY_FUNCTION(__gnustep_objcxx_personality_v0)
return CALL_PERSONALITY_FUNCTION(__gxx_personality_v0);
}

id objc_begin_catch(struct _Unwind_Exception *exceptionObject)
#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__

OBJC_PUBLIC EXCEPTION_DISPOSITION
__gnu_objc_personality_seh0(PEXCEPTION_RECORD ms_exc, void *this_frame,
PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp)
{
return _GCC_specific_handler(ms_exc, this_frame, ms_orig_context, ms_disp,
__gnustep_objc_personality_v0);
}
PRIVATE EXCEPTION_DISPOSITION
test_eh_personality(PEXCEPTION_RECORD ms_exc, void *this_frame,
PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp)
{
return _GCC_specific_handler(ms_exc, this_frame, ms_orig_context, ms_disp,
test_eh_personality_internal);
}
#endif

OBJC_PUBLIC id objc_begin_catch(struct _Unwind_Exception *exceptionObject)
{
struct thread_data *td = get_thread_data();
DEBUG_LOG("Beginning catch %p\n", exceptionObject);
Expand Down Expand Up @@ -656,7 +689,7 @@ id objc_begin_catch(struct _Unwind_Exception *exceptionObject)
return (id)((char*)exceptionObject + sizeof(struct _Unwind_Exception));
}

void objc_end_catch(void)
OBJC_PUBLIC void objc_end_catch(void)
{
struct thread_data *td = get_thread_data_fast();
// If this is a boxed foreign exception then the boxing class is
Expand Down Expand Up @@ -702,7 +735,7 @@ void objc_end_catch(void)
}
}

void objc_exception_rethrow(struct _Unwind_Exception *e)
OBJC_PUBLIC void objc_exception_rethrow(struct _Unwind_Exception *e)
{
struct thread_data *td = get_thread_data_fast();
// If this is an Objective-C exception, then
Expand Down
10 changes: 8 additions & 2 deletions objc_msgSend.x86-32.S
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
test %eax, %eax
jz 5f # Nil slot - invoke some kind of forwarding mechanism
mov SLOT_OFFSET(%eax), %ecx
#ifdef _WIN32
#ifdef _MSC_VER
call *CDECL(__guard_check_icall_fptr)
#endif
jmp *%ecx
Expand All @@ -62,7 +62,7 @@
add $12, %esp # restore the stack


#ifdef _WIN32
#ifdef _MSC_VER
mov %eax, %ecx
call *CDECL(__guard_check_icall_fptr)
jmp *%ecx
Expand Down Expand Up @@ -126,7 +126,13 @@ CDECL(objc_msgSend_stret):

#ifdef _WIN32
.section .drectve,"yn"
#ifdef _MSC_VER
.ascii " /EXPORT:_objc_msgSend"
.ascii " /EXPORT:_objc_msgSend_stret"
.ascii " /EXPORT:_objc_msgSend_fpret"
#else
.ascii " /EXPORT:objc_msgSend"
.ascii " /EXPORT:objc_msgSend_stret"
.ascii " /EXPORT:objc_msgSend_fpret"
#endif
#endif
2 changes: 1 addition & 1 deletion objc_msgSend.x86-64.S
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@

12:
#endif // WITH_TRACING
#ifdef _WIN64
#ifdef _MSC_VER
mov %r10, %rax
jmp *__guard_dispatch_icall_fptr(%rip)
#else
Expand Down
10 changes: 7 additions & 3 deletions objcxx_eh.cc
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ namespace gnustep
/**
* Superclass for the type info for Objective-C exceptions.
*/
struct __objc_type_info : std::type_info
struct OBJC_PUBLIC __objc_type_info : std::type_info
{
/**
* Constructor that sets the name.
Expand Down Expand Up @@ -266,7 +266,7 @@ namespace gnustep
/**
* Singleton type info for the `id` type.
*/
struct __objc_id_type_info : __objc_type_info
struct OBJC_PUBLIC __objc_id_type_info : __objc_type_info
{
/**
* The `id` type is mangled to `@id`, which is not a valid mangling
Expand All @@ -278,7 +278,7 @@ namespace gnustep
void **obj,
unsigned outer) const;
};
struct __objc_class_type_info : __objc_type_info
struct OBJC_PUBLIC __objc_class_type_info : __objc_type_info
{
virtual ~__objc_class_type_info();
virtual bool __do_catch(const type_info *thrownType,
Expand Down Expand Up @@ -448,7 +448,11 @@ PRIVATE void cxx_throw()
*/
extern "C"
PRIVATE
#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
BEGIN_PERSONALITY_FUNCTION(test_eh_personality_internal)
#else
BEGIN_PERSONALITY_FUNCTION(test_eh_personality)
#endif
// Don't bother with a mutex here. It doesn't matter if two threads set
// these values at the same time.
if (!done_setup)
Expand Down
Loading