-
Notifications
You must be signed in to change notification settings - Fork 189
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
Implement projection tooling for simple P/Invoke cases #2517
Conversation
The SwiftRuntimeLibrary includes C# implementation of Swift types used for marshalling. This commit adds initial layout of the project.
The SyntaxDynamo is a code generator for C# source code generation. Also, it contains Swift syntax and is used as a parser for API aggregation.
Introduces type mapping and API reflection of the tooling. Key components: - Inventory: Collects mangled names and generates entry points mapping. - Reflector and SwiftXmlReflection: Aggregates Swift public API. - TopLevelFunctionCompiler: Provides tools to generate C# methods, properties, and P/Invoke definitions. - TypeMapping: Facilitates Swift to C# type conversion, maintaining a type database. - BindingsCompiler: Handles generating the C# bindings onto the types from the Swift module.
A command-line interface that orchestrates the tooling workflow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some basic comments around the sample/infra to start.
I'm a little concerned by the fact that we have a totally independent C# syntax writer here that also seems to understand Swift syntax, not just SwiftInterface syntax (likely from when BTfS would write separately). Maybe we can delete the Swift-writing support or move it into a separate assembly now that that's not on the roadmap?
@@ -0,0 +1,25 @@ | |||
cmake_minimum_required(VERSION 3.24) | |||
|
|||
project(SmokeTests) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use the Swift language support in CMake and require using a generator that supports it (ie. Ninja). As this code isn't going in the runtime repo, we can be more reasonable about requiring specific features/options.
project(SmokeTests) | |
project(SmokeTests Swift) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that the ninja
generator is not installed on build machines: https://github.com/actions/runner-images/blob/macOS-12/20240202.1/images/macos/macos-12-Readme.md
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/actions/runner-images/blob/macOS-12/20240202.1/images/macos/macos-12-Readme.md
Nit: We use our build images. This link is for GitHub Actions images - I do not think it is relevant to our builds.
src/SwiftReflector/SwiftInterfaceReflector/GeneratedParser/SwiftInterfaceBaseListener.cs
Outdated
Show resolved
Hide resolved
README.md
Outdated
|
||
Options: | ||
``` | ||
-d, --dylibs Required. Paths to the dynamic libraries (dylibs), separated by commas. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original design was to operate on multiple libraries, but frankly, this made things worse overall. I feel like we should simplify and make it take only a single dylib/swiftinterface pair.
const string kSwiftID = "__T"; | ||
public const string kSwift4ID = "__T0"; | ||
public const string kSwift4xID = "_$s"; | ||
public const string kSwift5ID = "_$S"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we discussed in the meeting, I think it's reasonable to shed everything before swift 5 and throw if we get anything else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, removed. Is it safe to remove the kSwift4xID
? It is used in
f (swiftIdentifier.StartsWith (kSwift4xID, StringComparison.Ordinal)|| swiftIdentifier.StartsWith (kSwift5ID, StringComparison.Ordinal)) {
src/SwiftReflector/Extensions.cs
Outdated
|
||
public static bool IsSwiftEntryPoint (this NListEntry entry) | ||
{ | ||
return !String.IsNullOrEmpty (entry.str) && (entry.str.StartsWith ("__T", StringComparison.Ordinal) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
__T
and _$s
are legacy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the ABI document, the _$s
is used for globals: https://github.com/apple/swift/blob/main/docs/ABI/Mangling.rst#L11
Did you mean _$S
perhaps?
Co-authored-by: Jeremy Koritzinsky <jkoritzinsky@gmail.com>
…tatic functions within the same class
https://github.com/dotnet/arcade/blob/main/Documentation/MirroringPackages.md is the way to do it correctly. |
I agree, let's try to narrow the scope at this point.
I've implemented (and will upstream) a prototype ABI parser that consumes |
This change removes SwiftInterfaceReflector and its dependencies to simplify code review. Temporarily, the tooling will consume the ABI interface instead of swiftinterface. The code has been reorganized into components: SwiftBindings, which generates C# bindings, and SwiftReflector, which contains type system ABI aggregation logic. The ISwiftParser interface has been introduced to facilitate modularization within the project, and ABI aggregators are expected to implement this interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a unsupported type is encountered, the tooling will ignore it and generate C# source code for known syntax.
So one test scenario would be to throw all the .swiftinterface files Xcode ships at it and verify that the binding process doesn't fail.
for sw in $(find /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks -name '*.swiftinterface'); do
dotnet SwiftBindings.dll --swiftinterface $sw ...
done
The scope of the tooling has been narrowed to only support projecting public functions into static C# methods with P/Invoke declarations. The tooling has been split into two phases: public ABI aggregation and code generation. The integration point is ISwiftParser and ModuleDeclaration as implemented in https://github.com/dotnet/runtimelab/blob/swift-bindings/basic-tooling/src/SwiftBindings/src/Program.cs#L69-L86. For simplicity, the Swift interface parser has been temporarily removed and will be introduced in subsequent PRs. Stress tests have been added to https://github.com/dotnet/runtimelab/tree/swift-bindings/basic-tooling/src/SwiftBindings/tests (kudos to @jakobbotsch). Please reflect on important points that you think should be addressed in this PR, with focus on the |
Good idea. I suggest to bundle it with |
To facilitate easier code review, this PR will be divided into smaller PRs:
|
Most of the code has been moved from https://github.com/xamarin/binding-tools-for-swift.
This PR is quite large, and there are multiple options for reviewing it. It includes all necessary components to demonstrate the end-to-end flow and allow for CI testing.
I have attempted to prune the tooling as much as possible, though there are some limitations. When reviewing this PR, I recommend initially focusing on the tooling UX and the quality of the generated bindings rather than the internal workings of the tooling.
Here are my suggestions for the review process: Begin with the
SwiftRuntimeLibrary
, it is a small project that outlines the implementation of Swift types in C#. TheSwiftBindings
project includes the tool interface and compilers for bindings. TheSwiftReflector
project includes ABI aggregation logic, module declarations, and type system. TheSyntaxDynamo
project includes API for C# source code generation and can potentially be improved at a later stage as it shouldn't impact the quality of the generated bindings.Description
This PR represents a minimal set of features required for a simple direct P/Invoke scenario. It includes the following components, along with unit tests and samples.
Usage
Options:
Example usage:
If a unsupported type is encountered, the tooling will ignore it and generate C# source code for known syntax.
Simple binding
The supported scenario involves simple P/Invoke calls without primitive params and no exceptions.
Swift library example:
User's code in C#:
Generated bindings in C#:
The design discussion for the simple P/Invoke scenarios is available at #2518. The documentation is available at #2512.