From bf4009dacbf67a63a1cbaffddbdc99549bb70a03 Mon Sep 17 00:00:00 2001 From: Quinton Miller Date: Fri, 15 Jul 2022 16:54:52 +0800 Subject: [PATCH] Support libffi on Windows (#12200) Builds the libffi static library on Windows CI and bundles it with the build artifacts. It uses https://github.com/winlibs/libffi, which is at version 3.3. It is not the most recent version, but that repository seems easiest to integrate into our CI. (Weirdly, the upstream provides an MSVC solution for AArch64 static builds only.) It is assumed #12192 will take care of any potential issues when upgrading to 3.4.x. --- .github/workflows/win.yml | 33 +++++++++++++++++++ spec/compiler/ffi/ffi_spec.cr | 62 +++++++++++++++++++---------------- 2 files changed, 66 insertions(+), 29 deletions(-) diff --git a/.github/workflows/win.yml b/.github/workflows/win.yml index c2016ce612fa..133a469034ef 100644 --- a/.github/workflows/win.yml +++ b/.github/workflows/win.yml @@ -44,6 +44,7 @@ jobs: libs/pcre.lib libs/iconv.lib libs/gc.lib + libs/ffi.lib libs/z.lib libs/mpir.lib libs/yaml.lib @@ -110,6 +111,37 @@ jobs: ' > 'Override.props' MSBuild.exe /p:Platform=x64 /p:Configuration=ReleaseStatic libiconv.vcxproj + - name: Download libffi + if: steps.cache-libs.outputs.cache-hit != 'true' + uses: actions/checkout@v2 + with: + repository: winlibs/libffi + ref: libffi-3.3 + path: libffi + - name: Build libffi + if: steps.cache-libs.outputs.cache-hit != 'true' + working-directory: ./libffi + run: | + echo ' + + $(MsbuildThisFileDirectory)\Override.props + + ' > 'Directory.Build.props' + + echo ' + + + MultiThreaded + None + false + + + false + + + ' > 'Override.props' + + MSBuild.exe /p:PlatformToolset=v143 /p:Platform=x64 /p:Configuration=Release win32\vs16_x64\libffi-msvc.sln -target:libffi:Rebuild - name: Download zlib if: steps.cache-libs.outputs.cache-hit != 'true' run: | @@ -200,6 +232,7 @@ jobs: mv pcre/Release/pcre.lib libs/ mv libiconv/lib64/libiconvStatic.lib libs/iconv.lib mv bdwgc/Release/gc.lib libs/ + mv libffi/win32/vs16_x64/x64/Release/libffi.lib libs/ffi.lib mv zlib/Release/zlibstatic.lib libs/z.lib mv mpir/lib/x64/Release/mpir.lib libs/ mv libyaml/Release/yaml.lib libs/ diff --git a/spec/compiler/ffi/ffi_spec.cr b/spec/compiler/ffi/ffi_spec.cr index 4b70658e6bb8..5bf1b3cc97f2 100644 --- a/spec/compiler/ffi/ffi_spec.cr +++ b/spec/compiler/ffi/ffi_spec.cr @@ -1,4 +1,5 @@ -{% skip_file if !flag?(:unix) || flag?(:without_ffi) || flag?(:wasm32) %} +{% skip_file if flag?(:without_ffi) || flag?(:wasm32) %} +{% skip_file unless flag?(:unix) || flag?(:win32) %} require "../spec_helper" require "compiler/crystal/ffi" @@ -167,34 +168,37 @@ describe Crystal::FFI::CallInterface do loader.try &.close_all end - it "array" do - call_interface = Crystal::FFI::CallInterface.new Crystal::FFI::Type.sint32, [ - Crystal::FFI::Type.struct([ - Crystal::FFI::Type.sint32, - Crystal::FFI::Type.sint32, - Crystal::FFI::Type.sint32, - Crystal::FFI::Type.sint32, - ]), - ] of Crystal::FFI::Type - - loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH]) - loader.load_library "sum" - function_pointer = loader.find_symbol("sum_array") - - return_value = 0_i32 - - ary = [1, 2, 3, 4] - - arg_pointers = StaticArray[ - Pointer.malloc(1, ary.to_unsafe).as(Void*), - Pointer(Void).null, - ] - - call_interface.call(function_pointer, arg_pointers.to_unsafe, pointerof(return_value).as(Void*)) - return_value.should eq 10 - ensure - loader.try &.close_all - end + # passing C array by value is not supported everywhere + {% unless flag?(:win32) %} + it "array" do + call_interface = Crystal::FFI::CallInterface.new Crystal::FFI::Type.sint32, [ + Crystal::FFI::Type.struct([ + Crystal::FFI::Type.sint32, + Crystal::FFI::Type.sint32, + Crystal::FFI::Type.sint32, + Crystal::FFI::Type.sint32, + ]), + ] of Crystal::FFI::Type + + loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH]) + loader.load_library "sum" + function_pointer = loader.find_symbol("sum_array") + + return_value = 0_i32 + + ary = [1, 2, 3, 4] + + arg_pointers = StaticArray[ + Pointer.malloc(1, ary.to_unsafe).as(Void*), + Pointer(Void).null, + ] + + call_interface.call(function_pointer, arg_pointers.to_unsafe, pointerof(return_value).as(Void*)) + return_value.should eq 10 + ensure + loader.try &.close_all + end + {% end %} end describe ".variadic" do