dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.11k stars 1.57k forks source link

[ffi] Add support for abi-specific structs #42816

Open dcharkes opened 4 years ago

dcharkes commented 4 years ago

Sometimes structs are defined differently on different platforms. (Some fields might be commented out on some platforms.)

A workaround is to have a different struct for the different platforms, but that cascades into everything that is using that struct (function signatures, struct fields, and pointers).

We could introduce an AbiSpecificStruct that exposes all the different fields on all platforms in one api.

@AbiSpecificStructMapping({
  Abi.linuxX64: MyStructLinux(),
  Abi.windowsX64: MyStructWindows(),
  // ...
})
class MyStruct extends AbiSpecificStruct {
  external int a;
  external int b;
}

This would be the struct/union counterpart of https://github.com/dart-lang/sdk/issues/42563.

edit: We would probably make an API similar to https://api.dart.dev/stable/2.17.0/dart-ffi/AbiSpecificInteger-class.html with annotations instead of types.

artob commented 4 years ago

@dcharkes That's pretty neat. What happens if accessing field external int b on Windows, in this example? A compiler error, I trust?

LeoSandbox commented 2 months ago

Hey guys, I'm looking to use this package https://pub.dev/packages/steamworks on both Windows and MacOS. This issue is blocking the package to work properly.

I've been making a breakthrough RPG with Flutter for the past 2 years and about to start the last stretch of production to ship a demo and then release. This package will be used to send Steam Achievement to Steam API.

Is there any way I can help on this issue? Can you point me to the right resource so I can try to work on it?

dcharkes commented 2 months ago

Hi @LeoSandbox nice to meet you!

We welcome contributions! ❤️

The first step is to build a Dart SDK locally:

The best starting point would be to look at the commits that introduced ABI-specific integers:

The analyzer is a different implementation than the common compiler frontend (CFE).

To run the analyzer and CFE from source to be able to run the debugger in vscode:

            {
                "name": "dart analyzer.dart",
                "type": "dart",
                "request": "launch",
                "program": "pkg/analyzer_cli/bin/analyzer.dart",
                "args": [
                    "tests/ffi/static_checks/vmspecific_static_checks_array_test.dart",
                ],
                "toolArgs": [],
                "enableAsserts": true,
                "cwd": "${workspaceFolder}",
            },
            {
                "name": "dart gen_kernel.dart",
                "type": "dart",
                "request": "launch",
                "program": "pkg/vm/bin/gen_kernel.dart",
                "args": [
                    "--enable-experiment=records",
                    "--platform=${workspaceFolder}/xcodebuild/ReleaseARM64/vm_platform_strong.dill",
                    "pkg/vm/testcases/transformations/ffi/address_of_struct_element.dart",
                ],
                "toolArgs": [],
                "enableAsserts": true,
                "cwd": "${workspaceFolder}",
            },

You might need to adjust the build folder to out/ instead of xcodebuild/ if you're not on MacOS.

The use of the API could look something like the following:

@AbiSpecificStructMapping({
  Abi.linuxX64: MyStructLinux(),
  Abi.windowsX64: MyStructWindows(),
  // ...
})
final class MyStruct extends AbiSpecificStruct {
  // No annotation, the native types are per ABI
  external int a;

  // The ABI-specific struct should have the superset of all fields of the struct per ABI.
  external int b;

  // The ABI-specific struct should have the superset of all fields of the struct per ABI.
  external int c;
}

final class MyStructLinux extends Struct {
  @Int8()
  external int a;

  @Int8()
  external int b;
}

final class MyStructWindows extends Struct {
  @Int64()
  external int a;

  @Int64()
  external int c;
}

I expect a PR to implement this feature to roughly have the following changes:

You'll have to touch many parts of the Dart compiler for this feature (similar to https://dart-review.googlesource.com/c/sdk/+/221501). However, the feature should be somewhat straightforward to implement due to its similarity to the AbiSpecificIntegers. Please feel free to ping me or this issue with any questions!