This directory contains the source code and build logic to build the platform assemblies.
The generator takes API definition files (most *.cs files in src/) as input, and generates the required binding code.
There is one generator executable, that's used to generate the binding code for all platforms.
The generator relies heavily on binding attributes; all the binding attributes (that are not in the platform assembly) are compiled into a separate attribute assembly (Xamarin.Apple.BindingAttributes.dll).
Since the platform assemblies (and thus all the binding attributes assemblies as well) reference each platform's BCL, those assemblies can't be loaded directly into the generator at runtime. In order to not make the generator code too complicated, all the attributes are also compiled into the generator executable, and then instantiated as mock-objects of the real attributes.
The solution generator.sln can be used to debug the generator. There are multiple run configurations, each configured to execute the generator with the options for the corresponding profile.
Two special make targets can be used to compare the generated code (.g.cs files) changes between two branches.
This is required when making changes to the generator.
- Checkout the clean base branch (e.g main's HEAD) the feature (target) branch is based on.
- Do
make generator-referenceinxamarin-macios/src. - Checkout the feature branch that requires the diff.
- Do
make generator-diff.
Tip: do git diff | pbcopy in macios/src/generator-reference and paste that anywhere (gist for instance).
These are the symbols defined for each platform assembly:
| Assembly | Symbols |
|---|---|
| Microsoft.iOS.dll | __IOS__ IOS |
| Microsoft.macOS.dll | __MACOS__ MONOMAC |
| Microsoft.tvOS.dll | __TVOS__ TVOS |
| Microsoft.MacCatalyst.dll | __MACCATALYST__ __IOS__ |
To build core for only one platform, use the platform unique variables
__IOS__, __MACOS__, __MACCATALYST__ or __TVOS__. The other variables
can still be used, but will eventually be phased out.
The binding process is a multi-step process:
- We build an assembly with all the attributes used by the generated code
(
Xamarin.Apple.BindingAttributes.dll) - We build the generator (
bgen) - We compile a
core.dllwith a few important core types (this is any<FRAMEWORK>_CORE_SOURCESmentions inframeworks.sources). - We compile all the api definitions into an apidefinition.dll (this is the
<framework.cs>.csfile in this directory + any<FRAMEWORK>_API_SOURCESmentions inframeworks.sources). This referencescore.dll, so that must happen first. - We pass the
apidefinition.dllassembly tobgen, asking it to generate the binding code (but not compile it). - We compile the generated binding code + any
<FRAMEWORK>_SOURCESmentions inframeworks.sources. - We inject a reference to Apple's documentation into the xml documentation
produced by the C# compiler, using the
adrcommand-line tool.
Enums are handled specially. Most native enums are backed by NSInteger or
NSUInteger. Unfortunately in C#, the backing type of an enum may only be
one of the primitive integral C# types. Thus, an enum cannot be backed by
nint or nuint.
The convention is to make all enums that are backed natively by NSInteger
or NSUInteger backed by a 64-bit primitive integral C# type (long or
ulong) and then annotated with the [Native] attribute. This ensures that
API is identical between the 32/64-bit assemblies but also hints to the code
generator that Objective-C runtime calls should first cast the enum to a
nint or nuint.
Native Enum Definition
typedef NS_ENUM(NSUInteger, NSTableViewDropOperation) {
NSTableViewDropOn,
NSTableViewDropAbove
};Managed Enum Definition
[Native]
public enum NSTableViewDropOperation : nuint {
DropOn,
DropAbove
}When dealing with enums in P/Invokes, one must never pass such an enum
directly. The P/Invoke signature should take a nint or nuint and a wrapper
API must cast the enum manually (as mentioned above, this is handled
automatically for Objective-C APIs by the generator).
Objective-C Binding
interface Fooable {
[Export ("foo:")]
void Foo (NSTableViewDropOperation dropOp);
}C Binding
public partial class Fooable {
[DllImport ("foo")]
static extern void Foo (nuint dropOp);
public static void Foo (NSTableViewDropOperation dropOp)
{
Foo ((nuint)(ulong)dropOp);
}
}Coming soon!
See Localization Wiki for more details on our localization process
or the OneLocBuild Wiki for information on OneLocBuild.