Fix 4 more bad delegates missing the attribute that cause iOS AOT errors at runtime (#18390)

### Description
<!-- Describe your changes. -->
Fix bad delegates.
Add script to detect mismatch, and run in CI and when creating nuget
package.

Ignore whitespace when looking at the diff to the .cs file as
clang-format ran.

### Motivation and Context
<!-- - Why is this change required? What problem does it solve?
- If it fixes an open issue, please link to the issue here. -->
#18363
This commit is contained in:
Scott McKay 2023-11-14 14:00:21 +10:00 committed by GitHub
parent 37d8bed53d
commit 8ff41aea09
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 351 additions and 283 deletions

View file

@ -92,6 +92,13 @@ CMake creates a target to this project
</Target>
<Target Name="CreatePackage">
<!-- Validate no missing UnmanagedFunctionPointer attributes on delegates. -->
<Exec Condition="'$(IsWindowsBuild)' == 'true' AND $(OrtPackageId) == 'Microsoft.ML.OnnxRuntime'"
Command="$(PythonExe) tools/ValidateNativeDelegateAttributes.py"
ContinueOnError="False">
<Output TaskParameter="ConsoleOutput" PropertyName="GenerateNuspecOutput" />
</Exec>
<!-- Create Microsoft.ML.OnnxRuntime.Managed with the C# bindings using the C# project -->
<Message Importance="High" Text="Creating Microsoft.ML.OnnxRuntime.Managed nuget package..." />
<MSBuild Projects="src\Microsoft.ML.OnnxRuntime\Microsoft.ML.OnnxRuntime.csproj"
@ -100,8 +107,8 @@ CMake creates a target to this project
<!-- Manually create the nuspec for the native Microsoft.ML.OnnxRuntime package -->
<Message Importance="High" Text="Generating nuspec for the native Microsoft.ML.OnnxRuntime nuget package..." />
<Exec Command="$(PythonExe) $(GenerateNuspecScript) --package_version $(PackageVersion) --package_name $(OrtPackageId) --target_architecture $(TargetArchitecture) --build_config $(Configuration) --native_build_path $(NativeBuildOutputDirAbs) --packages_path $(OnnxRuntimePackagesDirectoryAbs) --ort_build_path $(OnnxRuntimeBuildDirectoryAbs) --sources_path $(OnnxRuntimeSourceDirectoryAbs) --commit_id $(GitCommitHash) --is_release_build $(IsReleaseBuild) --execution_provider $(ExecutionProvider)"
ContinueOnError="False"
<Exec Command="$(PythonExe) $(GenerateNuspecScript) --package_version $(PackageVersion) --package_name $(OrtPackageId) --target_architecture $(TargetArchitecture) --build_config $(Configuration) --native_build_path $(NativeBuildOutputDirAbs) --packages_path $(OnnxRuntimePackagesDirectoryAbs) --ort_build_path $(OnnxRuntimeBuildDirectoryAbs) --sources_path $(OnnxRuntimeSourceDirectoryAbs) --commit_id $(GitCommitHash) --is_release_build $(IsReleaseBuild) --execution_provider $(ExecutionProvider)"
ContinueOnError="False"
ConsoleToMSBuild="true">
<Output TaskParameter="ConsoleOutput" PropertyName="GenerateNuspecOutput" />
</Exec>
@ -109,9 +116,9 @@ CMake creates a target to this project
<!-- run `nuget pack` on Windows or `dotnet pack` on Linux to create the native nupkg -->
<Message Importance="High" Text="Bundling native shared library artifacts into Microsoft.ML.OnnxRuntime nuget package..." />
<Exec Condition=" '$(IsWindowsBuild)' == 'true'"
Command="$(NugetExe) pack NativeNuget.nuspec"
Command="$(NugetExe) pack NativeNuget.nuspec"
WorkingDirectory="$(NativeBuildOutputDirAbs)"
ContinueOnError="False"
ContinueOnError="False"
ConsoleToMSBuild="true">
<Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" />
</Exec>
@ -119,11 +126,11 @@ CMake creates a target to this project
<!-- build.py uses dotnet to build on linux so we know it's available.
nuget needs to be run using mono to work correctly, but installing mono on WSL breaks interop
(see https://github.com/microsoft/WSL/issues/8531). in order to play nicely with both we use `dotnet pack`
to pack the native nuget package using a stub csproj to provide the nuspec file path.
to pack the native nuget package using a stub csproj to provide the nuspec file path.
-->
<Exec Condition="'$(IsLinuxBuild)' == 'true'"
Command="dotnet pack tools/linux_pack/LinuxPackNativeNuget.csproj /p:Configuration=$(Configuration) /p:OnnxRuntimeBuildDirectory=$(NativeBuildOutputDirAbs)"
ContinueOnError="False"
Command="dotnet pack tools/linux_pack/LinuxPackNativeNuget.csproj /p:Configuration=$(Configuration) /p:OnnxRuntimeBuildDirectory=$(NativeBuildOutputDirAbs)"
ContinueOnError="False"
ConsoleToMSBuild="true" >
<Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" />
</Exec>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,62 @@
#!/usr/bin/env python3
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
import argparse
import pathlib
def check_all_delegates_have_unmanaged_function_pointer_attribute(file: pathlib.Path):
"""
Check that all 'public delegate' declarations have a matching UnmanagedFunctionPointer attribute.
:param file: C# source file to check.
:return: Number of errors
"""
print(f"Checking {file!s}")
errors = 0
line_num = 0
with open(str(file.resolve(strict=True))) as f:
prev_line = ""
for line in f.readlines():
line_num += 1
# strip so it's easier to deal with commented out lines.
line = line.strip() # noqa
if line.startswith("public delegate ") and not prev_line.startswith("[UnmanagedFunctionPointer"):
errors += 1
print(f"Line {line_num} is missing UnmanagedFunctionPointer attribute:\n\t{prev_line}\n\t{line}")
prev_line = line
return errors
def main():
arg_parser = argparse.ArgumentParser(
"Script to validate that the native delegates for the ONNX Runtime C# managed projects have the required "
"attributes for iOS AOT. Paths are inferred from the script location."
"Errors of this nature can only be detected at runtime, in a release build, of a Xamarin/MAUI app, "
"on an actual iOS device. Due to that we take extra steps to identify problems early."
)
# no real args. just using this to provide description as help message
_ = arg_parser.parse_args()
# CI needs resolve() as __file__ is a relative path when the script is run there
script_dir = pathlib.Path(__file__).resolve().parent
csharp_root = script_dir.parent
managed_dir = csharp_root / "src" / "Microsoft.ML.OnnxRuntime"
native_methods = managed_dir / "NativeMethods.shared.cs"
training_native_methods = managed_dir / "Training" / "NativeTrainingMethods.shared.cs"
errors = check_all_delegates_have_unmanaged_function_pointer_attribute(native_methods)
errors += check_all_delegates_have_unmanaged_function_pointer_attribute(training_native_methods)
if errors:
raise ValueError(f"{errors} errors were found. Please check output for specifics.")
if __name__ == "__main__":
main()

View file

@ -175,6 +175,11 @@ jobs:
msbuildArguments: '-t:restore -p:OrtPackageId=$(OrtPackageId)'
workingDirectory: '$(Build.SourcesDirectory)\csharp'
- script: |
python3 tools\ValidateNativeDelegateAttributes.py
displayName: 'Validate C# native delegates'
workingDirectory: '$(Build.SourcesDirectory)\csharp'
- task: MSBuild@1
displayName: 'Build C#'
inputs: