Skip to content

Commit

Permalink
Support libffi on Windows (#12200)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
HertzDevil authored Jul 15, 2022
1 parent 98a15ee commit bf4009d
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 29 deletions.
33 changes: 33 additions & 0 deletions .github/workflows/win.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -110,6 +111,37 @@ jobs:
</Project>' > '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 '<Project>
<PropertyGroup>
<ForceImportAfterCppTargets>$(MsbuildThisFileDirectory)\Override.props</ForceImportAfterCppTargets>
</PropertyGroup>
</Project>' > 'Directory.Build.props'
echo '<Project>
<ItemDefinitionGroup Label="Configuration">
<ClCompile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DebugInformationFormat>None</DebugInformationFormat>
<WholeProgramOptimization>false</WholeProgramOptimization>
</ClCompile>
<Link>
<GenerateDebugInformation>false</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
</Project>' > '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: |
Expand Down Expand Up @@ -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/
Expand Down
62 changes: 33 additions & 29 deletions spec/compiler/ffi/ffi_spec.cr
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit bf4009d

Please sign in to comment.