├── .github └── workflows │ ├── build.yml │ └── release.yml ├── .gitignore ├── .gitmodules ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Directory.Build.props ├── Directory.Packages.props ├── LICENSE ├── README.md ├── RELEASE.md ├── SECURITY.md ├── nuget.config ├── samples └── calculator │ ├── Adder │ ├── Adder.csproj │ ├── OperationsImpl.cs │ └── calculator.wit │ ├── CalculatorComposed │ ├── .gitignore │ └── CalculatorComposed.csproj │ └── CalculatorHost │ ├── CalculatorHost.csproj │ └── Program.cs ├── src ├── WasmComponent.Sdk │ ├── .gitignore │ ├── ImportInDev.proj │ ├── WasmComponent.Sdk.csproj │ └── build │ │ ├── BytecodeAlliance.Componentize.DotNet.Wasm.SDK.props │ │ └── BytecodeAlliance.Componentize.DotNet.Wasm.SDK.targets └── WitBindgen │ ├── .gitignore │ ├── ImportInDev.proj │ ├── WitBindgen.csproj │ └── build │ ├── BytecodeAlliance.Componentize.DotNet.WitBindgen.props │ ├── BytecodeAlliance.Componentize.DotNet.WitBindgen.targets │ └── Wit.CSharp.xml ├── templates ├── BytecodeAlliance.Componentize.DotNet.Templates.csproj └── content │ └── wasi-cli │ ├── .template.config │ └── template.json │ ├── Program.cs │ ├── nuget.config │ └── wasi-cli.csproj ├── test ├── E2ETest │ ├── PackageTest │ │ ├── .gitignore │ │ ├── CompositionTest.cs │ │ └── PackageTest.csproj │ └── testapps │ │ ├── E2EConsumer │ │ ├── .gitignore │ │ ├── E2EConsumer.csproj │ │ └── Program.cs │ │ ├── E2EProducer │ │ ├── E2EProducer.csproj │ │ ├── OperationsImpl.cs │ │ └── producer-consumer.wit │ │ └── nuget.config ├── WasmComponentSdkTest │ ├── WasmComponentSdkTest │ │ ├── SimpleProducerConsumerTest.cs │ │ └── WasmComponentSdkTest.csproj │ └── testapps │ │ ├── AppWithWitFolder │ │ ├── AppWithWitFolder.csproj │ │ ├── program.cs │ │ └── wit │ │ │ ├── imports.wit │ │ │ └── world.wit │ │ ├── OciWit │ │ ├── Code.cs │ │ ├── OciWit.csproj │ │ └── wit │ │ │ └── api.wit │ │ ├── SimpleConsumer │ │ ├── .gitignore │ │ ├── Program.cs │ │ └── SimpleConsumer.csproj │ │ └── SimpleProducer │ │ ├── OperationsImpl.cs │ │ ├── SimpleProducer.csproj │ │ └── producer-consumer.wit ├── WasmtimeCliFetcher │ ├── .gitignore │ └── FetchWasmtime.targets └── WitBindgenTest │ ├── WitBindgenTest │ ├── CodeGenerationTest.cs │ └── WitBindgenTest.csproj │ └── testapps │ ├── LibraryUsingWit │ ├── Code.cs │ ├── LibraryUsingWit.csproj │ ├── MyFuncsWorldImpl.cs │ ├── SomeStuffImpl.cs │ ├── multiple-worlds.wit │ └── simple.wit │ ├── LibraryWithCustomGeneratedFilesLocation │ ├── Code.cs │ ├── LibraryWithCustomGeneratedFilesLocation.csproj │ ├── generated │ │ └── wit │ │ │ ├── MySimple.cs │ │ │ ├── MySimpleWorld_component_type.wit │ │ │ ├── MySimpleWorld_wasm_import_linkage_attribute.cs │ │ │ └── lastbuild.txt │ ├── simple.wit │ └── wit-bindgen-generatedlastbuild.txt │ ├── LibraryWithExceptions │ ├── LibraryWitExceptions.csproj │ ├── Result.cs │ └── result.wit │ └── LibraryWithWitResultType │ ├── LibraryWithWitResultType.csproj │ ├── Result.cs │ └── result.wit └── wasm-component-sdk.sln /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a .NET project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net 3 | 4 | name: Build 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | pull_request: 10 | branches: [ "main" ] 11 | workflow_call: 12 | 13 | jobs: 14 | build: 15 | runs-on: ${{ matrix.os }} 16 | name: Build on ${{ matrix.os }} with Dotnet ${{ matrix.dotnet }} 17 | strategy: 18 | matrix: 19 | dotnet: [ '10.x'] 20 | os: [ubuntu-latest, windows-latest] 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Setup .NET 24 | uses: actions/setup-dotnet@v4 25 | with: 26 | dotnet-version: ${{ matrix.dotnet }} 27 | - name: Restore dependencies 28 | run: dotnet restore 29 | - name: Prepare WASM SDKs 30 | run: dotnet msbuild src/WitBindgen/build/BytecodeAlliance.Componentize.DotNet.WitBindgen.targets /t:PrepareWasmSdks 31 | - name: Build 32 | run: dotnet build --no-restore /p:BuildNumber=${{ github.run_number }} 33 | - name: Test 34 | run: dotnet test --no-build --verbosity normal 35 | - name: Pack 36 | run: dotnet pack -c Release /p:BuildNumber=${{ github.run_number }} 37 | - name: Ensure package and template versions match 38 | shell: bash 39 | run: | 40 | ls ./artifacts/*.nupkg 41 | version=$(unzip -p ./artifacts/*SDK*.nupkg '*.nuspec' | grep -oE "[^<]+" | sed 's///' | grep -oE "^[0-9]+\.[0-9]+\.[0-9]+-preview") 42 | template_version=$(grep -oE "Version=\"[^\"]+" ./templates/content/wasi-cli/wasi-cli.csproj | sed 's/Version="//' | grep -oE "^[0-9]+\.[0-9]+\.[0-9]+-preview") 43 | echo "Package Version: $version | Template version: $template_version" 44 | if [ "$version" != "$template_version" ]; then 45 | echo "Version mismatch: Package version ($version) does not match template version ($template_version)"; 46 | exit 1; 47 | fi 48 | - name: Test Template 49 | shell: bash 50 | run: | 51 | artifact_dir=$GITHUB_WORKSPACE/artifacts 52 | dotnet new install ./artifacts/BytecodeAlliance.Componentize.DotNet.Templates.*.nupkg 53 | mkdir $RUNNER_TEMP/projects 54 | pushd $RUNNER_TEMP/projects 55 | dotnet new componentize.wasi.cli -o test 56 | cd test 57 | dotnet nuget add source $artifact_dir 58 | dotnet build 59 | dotnet list package 60 | popd 61 | # must use windows to generate package https://github.com/bytecodealliance/componentize-dotnet/issues/41 62 | # only need one package published https://github.com/actions/upload-artifact?tab=readme-ov-file#not-uploading-to-the-same-artifact 63 | - name: Upload artifacts 64 | uses: actions/upload-artifact@v4 65 | with: 66 | name: nuget-packages 67 | path: artifacts/*.nupkg 68 | if-no-files-found: error 69 | if: ${{ matrix.dotnet == '10.x' && matrix.os == 'windows-latest' }} 70 | 71 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | run-name: "Release (Test-Run: ${{ inputs.test-run }})" 3 | 4 | on: 5 | workflow_dispatch: 6 | # used for [release](https://github.com/bytecodealliance/componentize-dotnet/blob/main/RELEASE.md) 7 | branches: [ "main" ] 8 | inputs: 9 | test-run: 10 | description: 'DryRun: Run the workflow without publishing step' 11 | default: true 12 | required: false 13 | type: boolean 14 | 15 | jobs: 16 | build: 17 | uses: ./.github/workflows/build.yml 18 | 19 | release: 20 | runs-on: ubuntu-latest 21 | needs: build 22 | permissions: 23 | contents: write 24 | name: Release 25 | if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main' 26 | steps: 27 | - uses: actions/checkout@v4 # needed for the create release step 28 | - name: Setup .NET 29 | uses: actions/setup-dotnet@v4 30 | with: 31 | dotnet-version: 10.x 32 | - name: Download artifacts 33 | uses: actions/download-artifact@v4 34 | with: 35 | name: nuget-packages 36 | - name: Extract nuget version 37 | id: extract_version 38 | run: | 39 | ls *.nupkg 40 | version=$(unzip -p ./*SDK*.nupkg '*.nuspec' | grep -oPm1 "(?<=)[^<]+") 41 | echo "Version: $version" 42 | echo "version=$version" >> $GITHUB_OUTPUT 43 | # Publish to https://nuget.org and tag the version on repo if test-run=false 44 | - name: Publish 45 | run: dotnet nuget push ./*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }} 46 | if: ${{ !inputs.test-run }} 47 | - name: Push version tag 48 | if: ${{ !inputs.test-run }} 49 | env: 50 | TAG: v${{ steps.extract_version.outputs.version }} 51 | run: | 52 | git tag $TAG 53 | git push origin $TAG 54 | - name: Create release 55 | if: ${{ !inputs.test-run }} 56 | run: | 57 | gh release create $TAG --generate-notes --prerelease 58 | env: 59 | GH_TOKEN: ${{ github.token }} 60 | TAG: v${{ steps.extract_version.outputs.version }} 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | .vs/ 4 | artifacts/ 5 | test/WasmComponentSdkTest/testapps/OciWit/wit/*.wasm 6 | *.binlog 7 | .DS_Store 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "modules/wit-bindgen"] 2 | path = modules/wit-bindgen 3 | url = https://github.com/bytecodealliance/wit-bindgen.git 4 | [submodule "modules/wasm-tools"] 5 | path = modules/wasm-tools 6 | url = https://github.com/bytecodealliance/wasm-tools.git 7 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | This project adheres to the [Bytecode Alliance Code of 4 | Conduct](https://github.com/bytecodealliance/governance/blob/main/CODE_OF_CONDUCT.md). Any 5 | violations of the code of conduct should be reported to report@bytecodealliance.org -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Submitting bugs and fixes 2 | Open an issue detailing the issue you've encountered or feature you would like to see. 3 | 4 | Bug fixes and new features must be submitted using a pull request and pass CI to be included in the project. 5 | 6 | ## Building 7 | 8 | Requires [.NET 8+](https://dotnet.microsoft.com/en-us/download) 9 | 10 | ``` 11 | ## needed to avoid errors with multiple projects calling and downloading the sdks at same time (https://github.com/bytecodealliance/componentize-dotnet/issues/8) 12 | dotnet msbuild src/WitBindgen/build/BytecodeAlliance.Componentize.DotNet.WitBindgen.targets /t:PrepareWasmSdks 13 | dotnet build 14 | ``` 15 | 16 | ## Testing 17 | 18 | Run the tests: 19 | 20 | ``` 21 | dotnet test 22 | ``` 23 | 24 | > tip: If you've already built the project you can speed up the tests by running `dotnet test --no-build` 25 | 26 | ## Build Wasm tools locally 27 | 28 | > requires [rust](https://www.rust-lang.org/tools/install) 29 | 30 | The project is configured by default to pull tools such as [wit-bindgen](https://github.com/bytecodealliance/wit-bindgen) from their releases. It is possible to use custom builds of these tools via submodules: 31 | 32 | ``` 33 | ## get submodules 34 | git submodule update --int 35 | 36 | ## get latest code from configured branch 37 | git submodule update --recursive --remote 38 | 39 | ## optional, change the branch for the project 40 | cd modules/ 41 | git checkout 42 | ``` 43 | 44 | Modify the [WasmComponentSdk.csproj](./src/WasmComponent.Sdk/WasmComponent.Sdk.csproj) to enable building from source: 45 | 46 | ``` 47 | true 48 | ``` 49 | 50 | Modify the [WitBindgen.csproj](./src/WitBindgen/WitBindgen.csproj) to enable building from source: 51 | 52 | ``` 53 | true 54 | ``` 55 | 56 | And then follow the [project build steps](#building). 57 | 58 | ### Debugging 59 | 60 | Create a msbuild debug log: 61 | 62 | ``` 63 | dotnet build /bl 64 | ``` 65 | 66 | View the log with https://www.msbuildlog.com/. 67 | 68 | Learn more at [trouble shooting techniques](https://learn.microsoft.com/en-us/visualstudio/ide/msbuild-logs?view=vs-2022) for msbuild. 69 | 70 | ## Getting help 71 | 72 | > If you have any questions please drop a note in the [c# zulip chat](https://bytecodealliance.zulipchat.com/#narrow/stream/407028-C.23.2F.2Enet-collaboration). 73 | 74 | This project uses MSbuild and .NET Project SDKS. Learn more about this tooling in: 75 | 76 | - [MSbuild docs](https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild?view=vs-2022) 77 | - [.NET Project SDKS](https://learn.microsoft.com/en-us/dotnet/core/project-sdk/overview) 78 | - [Creating Reliable Builds](https://learn.microsoft.com/en-us/archive/msdn-magazine/2009/february/msbuild-best-practices-for-creating-reliable-builds-part-1#id0090093) 79 | 80 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0.7.0 4 | dev 5 | preview$([System.String]::Format('{0:00000}', $([MSBuild]::Add($(BuildNumber), 0)))) 6 | $(VersionPrefix)-$(VersionSuffix) 7 | $(MSBuildThisFileDirectory)artifacts\ 8 | false 9 | $(NoWarn);NU1507 10 | 11 | 12 | 1.227.1 13 | v0.6.1 14 | 0.41.0 15 | 0.10.0 16 | 17 | 18 | 30.0.2 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2024, Bytecode Alliance 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | 204 | --- LLVM Exceptions to the Apache 2.0 License ---- 205 | 206 | As an exception, if, as a result of your compiling your source code, portions 207 | of this Software are embedded into an Object form of such source code, you 208 | may redistribute such embedded portions in such Object form without complying 209 | with the conditions of Sections 4(a), 4(b) and 4(d) of the License. 210 | 211 | In addition, if you combine or link compiled forms of this Software with 212 | software that is licensed under the GPLv2 ("Combined Software") and if a 213 | court of competent jurisdiction determines that the patent provision (Section 214 | 3), the indemnity provision (Section 9) or other Section of the License 215 | conflicts with the conditions of the GPLv2, you may retroactively and 216 | prospectively choose to deem waived or otherwise exclude such Section(s) of 217 | the License, but only in their entirety and only with respect to the Combined 218 | Software. 219 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Latest Version 3 | 4 | 5 | # componentize-dotnet 6 | 7 | Simplifying C# wasm components 8 | 9 | **A [Bytecode Alliance](https://bytecodealliance.org/) hosted project** 10 | 11 | If you have any questions of problems feel free to reach out on the [c# zulip chat](https://bytecodealliance.zulipchat.com/#narrow/stream/407028-C.23.2F.2Enet-collaboration). 12 | 13 | ## Purpose 14 | 15 | This is to simplify using Wasm components in c#. 16 | 17 | Without this package, if you wanted to build a WASI 0.2 component with .NET, including using WIT imports/exports, there are several different tools you'd need to discover, download, configure, and manually chain together. Just figuring out which versions of each are compatible with the others is a big challenge. Working out how to get started would be very painful. 18 | 19 | With this package, you can add one NuGet reference. The build output is fully AOT compiled and is known to work in recent versions of wasmtime and WAMR. 20 | 21 | :construction: All the underlying technologies are under heavy development and are missing features. Please try to file it on the relevant underlying [tool](#credits) if relevant to that tool. 22 | 23 | ## Getting started 24 | 25 | ### 1. Set up SDKs 26 | 27 | If you don't already have it, install [.NET 10+ preview SDK](https://dotnet.microsoft.com/en-us/download/dotnet/10.0) 28 | 29 | ### 2. Install template and build 30 | 31 | ```bash 32 | dotnet new install BytecodeAlliance.Componentize.DotNet.Templates 33 | dotnet new componentize.wasi.cli -o MyApp 34 | dotnet build MyApp 35 | ``` 36 | 37 | ### 3. Run the WebAssembly binary 38 | 39 | If you have a recent version of [wasmtime](https://github.com/bytecodealliance/wasmtime/releases) on your path, you can now run 40 | 41 | ```bash 42 | wasmtime ./MyApp/bin/Debug/net10.0/wasi-wasm/publish/MyApp.wasm 43 | Hello world from compontize-dotnet! 44 | ``` 45 | 46 | (if needed, replace `MyApp` with the actual name of your project) 47 | 48 | ## Creating a WASI 0.2 component, including WIT support 49 | Lastest version of NativeAOT compiler package and the mono support in dotnet 9-preview 7 build native wasi 0.2 components with no additional tools. 50 | 51 | ### Referencing a WIT file 52 | 53 | The whole point of the WASI 0.2 component model is to be able to interoperate across components. This is achieved using [WebAssembly Interface Type (WIT)](https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md) files that specify data structures and functions to be imported or exported across components. 54 | 55 | There is a full sample of this walk through creating WIT components for you reference in [samples](./samples/). 56 | 57 | This package wraps `wit-bindgen` so that any `.wit` files in your project will automatically generate corresponding C# sources, allowing you to import or export functionality. 58 | 59 | For example, add a file called `calculator.wit` into your project, containing the following: 60 | 61 | ```js 62 | package example:calculator; 63 | 64 | interface operations { 65 | add: func(left: s32, right: s32) -> s32; 66 | } 67 | 68 | world computer { 69 | export operations; 70 | } 71 | 72 | world hostapp { 73 | import operations; 74 | } 75 | ``` 76 | 77 | Before you can build, you'll now need to specify which *world* you're generating code for, i.e., choose whether you're importing or exporting functions. 78 | 79 | #### Importing an implementation 80 | 81 | One way to pick a world is by editing your `.csproj`, adding the following: 82 | 83 | ```xml 84 | 85 | 86 | 87 | ``` 88 | 89 | Another option, if you use Visual Studio, is to select the WIT file in *Solution Explorer*, and then look at the *Properties* pane: 90 | 91 | ![image](https://github.com/dotnet/runtimelab/assets/1101362/86a204d1-985d-4d36-8bbd-5581375d989e) 92 | 93 | You can simply type the world name `hostapp` into the properties pane. 94 | 95 | Now you can call the imported `Add` function by putting the following in `Program.cs`: 96 | 97 | ```cs 98 | using HostappWorld.wit.imports.example.calculator; 99 | 100 | var left = 123; 101 | var right = 456; 102 | var result = OperationsInterop.Add(left, right); 103 | Console.WriteLine($"{left} + {right} = {result}"); 104 | ``` 105 | 106 | Since your component is no longer a self-contained application, you can no longer run it without also composing it with another WASI 0.2 component that implements the `add` function. To do that, either: 107 | 108 | * Create another .NET project and this time follow the steps for [exporting an implementation](#exporting-an-implementation) below 109 | * Or, read docs for other platforms such as Rust or TinyGo, to implement a WASI component containing the implementation. 110 | 111 | #### Exporting an implementation 112 | 113 | If you're **exporting** functionality, you'll be building a class library, not an executable. So be sure to go to your `.csproj` and change `` from `exe` to `library` and delete any `Program.cs`. 114 | 115 | Once you've done that, change your WIT file to use the `computer` world using one of the two techniques described above (i.e., either edit the `.csproj` or use the VS Properties pane). 116 | 117 | Now when you build, you'll get an error like `The name 'OperationsImpl' does not exist in the current context`. This is because you've said you'll provide an implementation, but haven't yet done so. To fix this, add the following class to your project: 118 | 119 | ```cs 120 | namespace ComputerWorld.wit.exports.example.calculator; 121 | 122 | public class OperationsImpl : IOperations 123 | { 124 | public static int Add(int left, int right) 125 | { 126 | return left + right; 127 | } 128 | 129 | public static string ToUpper(string input) 130 | { 131 | return input.ToUpperInvariant(); 132 | } 133 | } 134 | ``` 135 | 136 | Make sure to get the namespace exactly correct! Although this is quite difficult to figure out at the moment, hopefully a future version of the C# support in wit-bindgen will make it easier. 137 | 138 | Now when you build, you'll get a real WASI 0.2 component that exports an implementation for this WIT definition. You can confirm it using [wasm-tools](https://github.com/bytecodealliance/wasm-tools) by running: 139 | 140 | ```bash 141 | wasm-tools component wit bin\Debug\net8.0\wasi-wasm\native\MyApp.wasm 142 | ``` 143 | 144 | Outputs: 145 | 146 | ```js 147 | package root:component; 148 | 149 | world root { 150 | import ... various things ... 151 | 152 | export example:calculator/operations; 153 | } 154 | ``` 155 | 156 | ## Composing components 157 | 158 | Once you have a components containing the Adder and Calculator host, you can use [wac](https://github.com/bytecodealliance/wac) to compose a runnable application: 159 | 160 | ```bash 161 | wac plug MyApp.wasm --plug AddImplementation.wasm -o composed.wasm 162 | ``` 163 | 164 | then run it: 165 | 166 | ```bash 167 | wasmtime composed.wasm 168 | ``` 169 | 170 | While you can run wac manually, you can also generate this automatically. One way to do this is to [create a new project](./samples/calculator/CalculatorComposed/) and add the following: 171 | 172 | ```xml 173 | 174 | 175 | ../CalculatorHost/bin/$(Configuration)/$(TargetFramework)/wasi-wasm/native/calculatorhost.wasm 176 | ../Adder/bin/$(Configuration)/$(TargetFramework)/wasi-wasm/native/adder.wasm 177 | 178 | 179 | 180 | 181 | 182 | ``` 183 | 184 | Another option is to do it from the project where the final component will be composed as the output. See the example in the [e2e tests](test/E2ETest/testapps/E2EConsumer/E2EConsumer.csproj) 185 | 186 | You can also use this technique to use other [wasm-tools](https://github.com/bytecodealliance/wasm-tools) functionality such as `wasm-tools strip` to produce a final binary. 187 | 188 | This final component can be used anywhere that WASI 0.2 components can be used. For example, use `wasmtime` as illustrated above. 189 | 190 | ### Referencing Wit Packages 191 | 192 | By default the project will find all wit files and execute wit-bindgen against each one. This is makes it easy to get started with a single wit file. If you have more complicated wit files, then you can create wit packages. To use folder with all the wit in it you can add the following to your `.csproj`. 193 | 194 | ```xml 195 | 196 | 197 | 198 | 199 | ``` 200 | 201 | ### Configuring location of generated wit files 202 | 203 | By default the wit files are generated under the itermediate path `$(IntermediateOutputPath)wit_bindgen` which is by default at a location like `\obj\Debug\net10.0\wit_bindgen`. This means you can't really see the files and they will be ignored and not checked in to source by default (assuming you have a standard .net `.gitignore`) but intillisense will work. 204 | 205 | If you would like to have the files in a more discoverable place and potentially check the source files in you can configure the output location with a folder name and location of your choice, for example the following will create a folder `genererated/wit/` at the root of your project and put all the files in there. 206 | 207 | ```xml 208 | 209 | generated/wit 210 | 211 | ``` 212 | 213 | ### Passing additional wit-bindgen args 214 | 215 | [wit-bindgen](https://github.com/bytecodealliance/wit-bindgen/tree/main) for c# has some advanced settings that can be set by using `WitBindgenAddtionalArgs` property. A non-exhustive list of example args that might be useful are: 216 | 217 | - `--features ` - turn on [wit features](https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md#feature-gates) 218 | - `--with-wit-results` - use [wit Result types](https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md#wit-types) instead of generating exceptions 219 | - `--skip-support-files` - don't output files like `WasmImportLinkageAttribute` 220 | 221 | Example: 222 | 223 | ```xml 224 | 225 | --with-wit-results --features tls 226 | 227 | ``` 228 | 229 | To learn about addtional args run `wit-bindgen c-sharp -h` 230 | 231 | ### Referencing Wit Packages from OCI Registries 232 | 233 | Wit can be packaged into [OCI Artifacts](https://tag-runtime.cncf.io/wgs/wasm/deliverables/wasm-oci-artifact/) which can be pushed to OCI registries. To import a WIT definition from an OCI registry specify the Registry on the `Wit` Element. This will pull a WASM component binary that contains the WIT definition. wit-bindgen can use the binary format directly to generate the bindings. To view the WIT directly use [`wasm-tools component wit wit/wit.wasm`](https://github.com/bytecodealliance/wasm-tools). 234 | 235 | ```xml 236 | 237 | 238 | 239 | 240 | ``` 241 | 242 | ### WIT strings and memory 243 | 244 | The calculator example above works easily because it doesn't need to allocate memory dynamically. Once you start working with strings, you must add an extra line to the `` in your _host_ `.csproj` file (that is, the application that's _importing_ the interface): 245 | 246 | ```xml 247 | true 248 | ``` 249 | 250 | (You don't need to add this to your class library/exporting `.csproj`.) 251 | 252 | If you get a build error along the lines of _failed to encode a component from module ... module does not export a function named `cabi_realloc`_ then check you have remembered to add this line. 253 | 254 | ### Create a project manually 255 | 256 | * `dotnet new console -o MyApp` 257 | * `cd MyApp` 258 | 259 | Create a `nuget.config` file and add the `dotnet-experimental` package source for the `NativeAOT-LLVM` dependency: 260 | 261 | * `dotnet new nugetconfig` 262 | * Add these keys to `nuget.config` after ``: 263 | 264 | ```xml 265 | 266 | 267 | ``` 268 | 269 | Add the `componentize-dotnet` package: 270 | 271 | `dotnet add package BytecodeAlliance.Componentize.DotNet.Wasm.SDK --prerelease` 272 | 273 | Add the platform specific LLVM package: 274 | 275 | ``` 276 | ## On Linux 277 | dotnet add package runtime.linux-x64.microsoft.dotnet.ilcompiler.llvm --prerelease 278 | 279 | ## or 280 | 281 | ## On Windows 282 | dotnet add package runtime.win-x64.microsoft.dotnet.ilcompiler.llvm --prerelease 283 | ``` 284 | 285 | Edit the `.csproj` file, adding the following inside the ``: 286 | 287 | ``` 288 | wasi-wasm 289 | false 290 | true 291 | true 292 | true 293 | ``` 294 | 295 | Now you can `dotnet build` to produce a `.wasm` file using NativeAOT compilation. 296 | 297 | ### Troubleshooting 298 | 299 | #### Imports Wrong Type 300 | ```bash 301 | *import 'wasi:...' has the wrong type* 302 | ``` 303 | 304 | You need a different version of Wasmtime. Currently this package targets [Wasmtime](https://github.com/bytecodealliance/wasmtime/releases/tag/v23.0.2). WASI 0.2 is now stable and so you shouldn't run into this often. 305 | 306 | #### Component imports missing 307 | ```bash 308 | Error: component imports instance `wasi:cli/environment@0.2.0`, but a matching implementation was not found in the linker 309 | 310 | Caused by: 311 | 0: instance export `get-environment` has the wrong type 312 | 1: function implementation is missing 313 | ``` 314 | 315 | Some imports automatically imported since they are so common. In this case you should tell the runtime to implement those imports. For instance for the error above, in wasmtime you might add `-S cli` to the `wasmtime serve` command like `wasmtime serve -S cli` to include the `wasi:cli/environment@0.2.0` in wasmtime runtime host implementation. 316 | 317 | ## Credits 318 | 319 | This project was original developed and forked from https://github.com/SteveSandersonMS/wasm-component-sdk under the Apache 2.0 License with a LLVM exception. 320 | 321 | This is a wrapper around various other bits of tooling: 322 | 323 | * [NativeAOT-LLVM](https://github.com/dotnet/runtimelab/tree/feature/NativeAOT-LLVM) for compilation. 324 | * [wit-bindgen](https://github.com/bytecodealliance/wit-bindgen) for supporting WIT imports and exports 325 | * [wasm-tools](https://github.com/bytecodealliance/wasm-tools) for converting WebAssembly core modules into WASI 0.2 components. 326 | * [WASI SDK](https://github.com/WebAssembly/wasi-sdk) which is used by NativeAOT-LLVM. 327 | * Compatible versions of these will be downloaded and cached on your machine the first time you run a build, so the first build will take a few minutes. After that it will only take seconds. 328 | 329 | ## Contributing 330 | 331 | See our [contributing docs](./CONTRIBUTING.md) for details on how to build and contribute to this project. 332 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Releasing the package 2 | 3 | 1. Update all the tool versions in [Directory.Build.Props](./Directory.Build.props) 4 | 1. Open a PR to update: 5 | - the `` tag in [Directory.Build.Props](./Directory.Build.props) 6 | - the `BytecodeAlliance.Componentize.DotNet.Wasm.SDK` package `version` to match the `` in the [template](./templates/content/wasi-cli/wasi-cli.csproj). For example the template version might look like `Version="0.6.0-preview*"`. This ensures the templates use the latest package. 7 | 1. Maintainers approve and merge PR 8 | 1. After the PR merges a maintainer triggers the Release workflow on the main branch via the github Actions UI or runs: 9 | 10 | ``` 11 | gh workflow run build -f test-run=false 12 | ``` 13 | 14 | >The release flow will build and publish the packages to nuget, tag the repository with version of the release, and create a GH release 15 | 5. Maintainer updates release notes with package info: 16 | 17 | ``` 18 | # https://www.nuget.org/packages/BytecodeAlliance.Componentize.DotNet.Templates 19 | dotnet new install BytecodeAlliance.Componentize.DotNet.Templates 20 | 21 | # https://www.nuget.org/packages/BytecodeAlliance.Componentize.DotNet.Wasm.SDK 22 | dotnet add package BytecodeAlliance.Componentize.DotNet.Wasm.SDK 23 | 24 | # https://www.nuget.org/packages/BytecodeAlliance.Componentize.DotNet.WitBindgen 25 | dotnet add package BytecodeAlliance.Componentize.DotNet.WitBindgen 26 | ``` 27 | 28 | 6. Post message about release [c# collaboration Zulip channel](https://bytecodealliance.zulipchat.com/#narrow/channel/407028-C.23.2F.2Enet-collaboration) -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security 2 | 3 | ## Supply chain security 4 | 5 | This project uses GitHub's dependabot to file automatic issues for dependency security updates. 6 | Maintainers will review and apply these updates as soon as possible. 7 | 8 | ## Reporting a security vulnerability 9 | 10 | If you believe you have found a security vulnerability in this project, please report it using the 11 | "Security" tab at the top of the repo. This project uses the GitHub security features to allow for 12 | confidential vulnerability reporting and fixes. Any security bugs will receive a CVE number and be 13 | tracked through the GitHub security feature. -------------------------------------------------------------------------------- /nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /samples/calculator/Adder/Adder.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | Library 8 | net10.0 9 | enable 10 | enable 11 | 12 | wasi-wasm 13 | 14 | 15 | adder 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /samples/calculator/Adder/OperationsImpl.cs: -------------------------------------------------------------------------------- 1 | namespace ComputerWorld.wit.exports.example.calculator; 2 | 3 | public class OperationsImpl : IOperations 4 | { 5 | public static int Add(int left, int right) 6 | { 7 | return left + right; 8 | } 9 | 10 | public static string ToUpper(string input) 11 | { 12 | return input.ToUpperInvariant(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /samples/calculator/Adder/calculator.wit: -------------------------------------------------------------------------------- 1 | package example:calculator; 2 | 3 | interface operations { 4 | add: func(left: s32, right: s32) -> s32; 5 | to-upper: func(input: string) -> string; 6 | } 7 | 8 | world computer { 9 | export operations; 10 | } 11 | 12 | world hostapp { 13 | import operations; 14 | } 15 | -------------------------------------------------------------------------------- /samples/calculator/CalculatorComposed/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /samples/calculator/CalculatorComposed/CalculatorComposed.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | net10.0 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ../CalculatorHost/bin/$(Configuration)/$(TargetFramework)/wasi-wasm/native/CalculatorHost.wasm 22 | ../Adder/bin/$(Configuration)/$(TargetFramework)/wasi-wasm/native/adder.wasm 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /samples/calculator/CalculatorHost/CalculatorHost.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | Exe 8 | net10.0 9 | enable 10 | enable 11 | 12 | true 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /samples/calculator/CalculatorHost/Program.cs: -------------------------------------------------------------------------------- 1 | using HostappWorld.wit.imports.example.calculator; 2 | 3 | var left = 123; 4 | var right = 456; 5 | var result = OperationsInterop.Add(left, right); 6 | Console.WriteLine($"{left} + {right} = {result}"); 7 | 8 | Console.WriteLine(OperationsInterop.ToUpper("Hello, World!")); 9 | -------------------------------------------------------------------------------- /src/WasmComponent.Sdk/.gitignore: -------------------------------------------------------------------------------- 1 | tools/ 2 | -------------------------------------------------------------------------------- /src/WasmComponent.Sdk/ImportInDev.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/WasmComponent.Sdk/WasmComponent.Sdk.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | BytecodeAlliance.Componentize.DotNet.Wasm.SDK 6 | Bytecode Alliance Developers 7 | Tooling for creating WebAssembly components from C# 8 | https://github.com/bytecodealliance/componentize-dotnet 9 | Apache-2.0 WITH LLVM-exception 10 | Readme.md 11 | webassembly, .net, wasm 12 | https://github.com/bytecodealliance/componentize-dotnet/releases/tag/$(PackageVersion) 13 | 14 | net10.0 15 | enable 16 | enable 17 | true 18 | 19 | 20 | 21 | false 22 | $(MSBuildThisFileDirectory)..\..\modules\wasm-tools\ 23 | 24 | https://github.com/bytecodealliance/wasm-tools/releases/download/v$(WasmToolsVersion)/wasm-tools-$(WasmToolsVersion) 25 | https://github.com/bytecodealliance/wac/releases/download/$(WacVersion)/wac-cli 26 | 27 | 28 | true 29 | false 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | wasm-tools 52 | $(WasmToolsExeName).exe 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | <_PackageFiles Include="build\**" BuildAction="Content" PackagePath="build" /> 106 | <_PackageFiles Include="tools\**" BuildAction="Content" PackagePath="tools" /> 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /src/WasmComponent.Sdk/build/BytecodeAlliance.Componentize.DotNet.Wasm.SDK.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | 5 | 6 | wasi-wasm 7 | false 8 | true 9 | true 10 | true 11 | 12 | win 13 | linux 14 | osx 15 | $(ToolsTarget)-$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLower()) 16 | 17 | $(MSBuildThisFileDirectory)..\tools\$(ToolsTarget)\wasm-tools 18 | $(WasmToolsExe).exe 19 | 20 | $(MSBuildThisFileDirectory)..\tools\$(ToolsTarget)\wac 21 | $(WacExe).exe 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/WasmComponent.Sdk/build/BytecodeAlliance.Componentize.DotNet.Wasm.SDK.targets: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/WitBindgen/.gitignore: -------------------------------------------------------------------------------- 1 | tools/ 2 | -------------------------------------------------------------------------------- /src/WitBindgen/ImportInDev.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/WitBindgen/WitBindgen.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | BytecodeAlliance.Componentize.DotNet.WitBindgen 6 | Bytecode Alliance Developers 7 | Tooling for creating WebAssembly components from C# 8 | https://github.com/bytecodealliance/componentize-dotnet 9 | Apache-2.0 WITH LLVM-exception 10 | Readme.md 11 | webassembly, .net, wasm 12 | https://github.com/bytecodealliance/componentize-dotnet/releases/tag/$(PackageVersion) 13 | 14 | net10.0 15 | enable 16 | enable 17 | true 18 | 19 | 20 | 21 | false 22 | https://github.com/bytecodealliance/wit-bindgen/releases/download/v$(PrebuiltWitBindgenVersion)/wit-bindgen-$(PrebuiltWitBindgenVersion) 23 | $(MSBuildThisFileDirectory)..\..\modules\wit-bindgen\ 24 | 25 | 26 | $(MSBuildThisFileDirectory)tools\version-wit-bindgen-$(PrebuiltWitBindgenVersion) 27 | 28 | https://github.com/bytecodealliance/wasm-pkg-tools/releases/download/v$(PrebuildWkgVersion)/wkg 29 | $(MSBuildThisFileDirectory)tools\version-wkg-$(PrebuildWkgVersion) 30 | 31 | 32 | true 33 | false 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | wit-bindgen 48 | $(WitBindgenExeName).exe 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | <_PackageFiles Include="build\**" BuildAction="Content" PackagePath="build" /> 92 | <_PackageFiles Include="tools\**" BuildAction="Content" PackagePath="tools" /> 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /src/WitBindgen/build/BytecodeAlliance.Componentize.DotNet.WitBindgen.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | win 4 | linux 5 | osx 6 | $(WitBindgenToolTarget)-$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLower()) 7 | $(MSBuildThisFileDirectory)..\tools\$(WitBindgenToolTarget)\wit-bindgen 8 | $(WitBindgenExe).exe 9 | $(MSBuildThisFileDirectory)..\tools\$(WitBindgenToolTarget)\wkg 10 | $(WkgExe).exe 11 | 12 | 13 | 14 | true 15 | 16 | 17 | 18 | 19 | 20 | MSBuild:Compile 21 | 22 | 23 | 24 | 25 | 26 | File;BrowseObject 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/WitBindgen/build/BytecodeAlliance.Componentize.DotNet.WitBindgen.targets: -------------------------------------------------------------------------------- 1 |  2 | 3 | native-aot 4 | 5 | 6 | 24.0 7 | https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$(WasiSdkVersion.Split(".")[0])/wasi-sdk-$(WasiSdkVersion)-x86_64-windows.tar.gz 8 | https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$(WasiSdkVersion.Split(".")[0])/wasi-sdk-$(WasiSdkVersion)-x86_64-linux.tar.gz 9 | https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$(WasiSdkVersion.Split(".")[0])/wasi-sdk-$(WasiSdkVersion)-x86_64-macos.tar.gz 10 | $([System.IO.Path]::Combine("$([System.Environment]::GetFolderPath(SpecialFolder.UserProfile))", ".wasi-sdk", "wasi-sdk-$(WasiSdkVersion)")) 11 | 12 | 13 | 14 | 18 | 19 | 20 | $(WasiSdkRoot) 21 | 22 | 23 | 24 | 25 | 26 | $([System.IO.Path]::Combine($([System.IO.Path]::GetTempPath()), $([System.IO.Path]::GetRandomFileName()))) 27 | 28 | 29 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 46 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | @(Wit) 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | $(IntermediateOutputPath)wit_bindgen\ 77 | $(WitGeneratedFilesRoot)\ 78 | 79 | 80 | 81 | 82 | --world %(Wit.World) 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /src/WitBindgen/build/Wit.CSharp.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /templates/BytecodeAlliance.Componentize.DotNet.Templates.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | BytecodeAlliance.Componentize.DotNet.Templates 5 | Templates for Componentize-dotnet 6 | Bytecode Alliance Developers 7 | Provides templates for Templates for Componentize-dotnet 8 | Apache-2.0 WITH LLVM-exception 9 | webassembly, .net, wasm 10 | https://github.com/bytecodealliance/componentize-dotnet 11 | https://github.com/bytecodealliance/componentize-dotnet 12 | true 13 | https://github.com/bytecodealliance/componentize-dotnet/releases/tag/$(PackageVersion) 14 | 15 | 16 | 17 | 18 | Template 19 | net10.0 20 | true 21 | false 22 | content 23 | $(NoWarn);NU5128 24 | true 25 | README.md 26 | 27 | 28 | 29 | false 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /templates/content/wasi-cli/.template.config/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/template", 3 | "author": "Bytecode Alliance Developers", 4 | "classifications": [ 5 | "wasi", 6 | "wasm", 7 | "Console" 8 | ], 9 | "identity": "BytecodeAlliance.Componentize.DotNet.Templates.Console", 10 | "name": "Componentize-dotnet wasi console template", 11 | "shortName": "componentize.wasi.cli", 12 | "sourceName": "wasi-cli", 13 | "tags": { 14 | "language": "C#", 15 | "type": "project" 16 | }, 17 | "symbols": { 18 | "platform": { 19 | "type": "bind", 20 | "binding": "env:OS", 21 | "defaultValue": "linux" 22 | } 23 | }, 24 | "postActions": [ 25 | { 26 | "description": "Welcome to Componetize dotnet", 27 | "manualInstructions": [ 28 | { 29 | "text": "To get started run `dotnet build` inside your new project. Learn more at https://github.com/bytecodealliance/componentize-dotnet." 30 | } 31 | ], 32 | "actionId": "AC1156F7-BB77-4DB8-B28F-24EEBCCA1E5C", 33 | "continueOnError": true 34 | } 35 | ] 36 | } -------------------------------------------------------------------------------- /templates/content/wasi-cli/Program.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | Console.WriteLine("Hello world from compontize-dotnet!"); 3 | -------------------------------------------------------------------------------- /templates/content/wasi-cli/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /templates/content/wasi-cli/wasi-cli.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net10.0 6 | wasi_cli 7 | enable 8 | enable 9 | wasi-wasm 10 | false 11 | true 12 | true 13 | true 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/E2ETest/PackageTest/.gitignore: -------------------------------------------------------------------------------- 1 | packages/ 2 | -------------------------------------------------------------------------------- /test/E2ETest/PackageTest/CompositionTest.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Reflection; 3 | using Xunit; 4 | 5 | namespace PackageTest; 6 | 7 | public class CompositionTest 8 | { 9 | [Fact] 10 | public void CanComposeImportWithExportE2E() 11 | { 12 | var composed = FindModulePath("../testapps/E2EConsumer", "composed.wasm"); 13 | var stdout = ExecuteCommandComponent(composed); 14 | Assert.StartsWith("Hello, world on Wasm", stdout); 15 | Assert.Contains("123 + 456 = 579", stdout); 16 | } 17 | 18 | private static string WasmtimeExePath { get; } = GetAssemblyMetadataValue("WasmtimeExe")!; 19 | 20 | private static string? GetAssemblyMetadataValue(string key) => 21 | typeof(CompositionTest).Assembly 22 | .GetCustomAttributes() 23 | .SingleOrDefault(x => x.Key == key)?.Value; 24 | 25 | private static string ExecuteCommandComponent(string componentFilePath) 26 | { 27 | var startInfo = new ProcessStartInfo(WasmtimeExePath, $"-W component-model {componentFilePath}") { RedirectStandardOutput = true }; 28 | var stdout = Process.Start(startInfo)!.StandardOutput.ReadToEnd(); 29 | return stdout; 30 | } 31 | 32 | private static string FindModulePath(string searchDir, string filename) 33 | { 34 | var resolvedSearchDir = Path.Combine( 35 | Path.GetDirectoryName(typeof(CompositionTest).Assembly.Location)!, 36 | "../../..", 37 | searchDir); 38 | 39 | if (!Directory.Exists(resolvedSearchDir)) 40 | { 41 | throw new InvalidOperationException($"No such directory: {Path.GetFullPath(resolvedSearchDir)}"); 42 | } 43 | 44 | var matches = Directory.GetFiles(resolvedSearchDir, filename, SearchOption.AllDirectories); 45 | return Path.GetFullPath(matches.Single()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test/E2ETest/PackageTest/PackageTest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | net10.0 6 | enable 7 | enable 8 | 9 | false 10 | true 11 | $(MSBuildThisFileDirectory)packages 12 | 13 | $(UserProfile) 14 | $(Home) 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | runtime; build; native; contentfiles; analyzers; buildtransitive 26 | all 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /test/E2ETest/testapps/E2EConsumer/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /test/E2ETest/testapps/E2EConsumer/E2EConsumer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Exe 7 | net10.0 8 | enable 9 | enable 10 | false 11 | 12 | true 13 | wasi-wasm 14 | false 15 | true 16 | e2econsumer 17 | --features float-add 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ../E2EProducer/bin/$(Configuration)/$(TargetFramework)/wasi-wasm/native/e2eproducer.wasm 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /test/E2ETest/testapps/E2EConsumer/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using ConsumerWorld.wit.imports.test.producerConsumer; 3 | 4 | Console.WriteLine($"Hello, world on {RuntimeInformation.OSArchitecture}"); 5 | 6 | var result = OperationsInterop.Add(123, 456); 7 | Console.WriteLine($"123 + 456 = {result}"); 8 | 9 | // this is just here to make sure we can enable features and pass flags via WitBindgenAddtionalArgs 10 | // the fact that it compiles is enough to test this worked. 11 | var floatResult = OperationsInterop.AddFloat(1.1f, 1.2f); 12 | Console.WriteLine($"1.1 + 1.2 = {floatResult}"); 13 | -------------------------------------------------------------------------------- /test/E2ETest/testapps/E2EProducer/E2EProducer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | net10.0 7 | enable 8 | enable 9 | false 10 | 11 | true 12 | wasi-wasm 13 | true 14 | e2eproducer 15 | --features float-add 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /test/E2ETest/testapps/E2EProducer/OperationsImpl.cs: -------------------------------------------------------------------------------- 1 | namespace ProducerWorld.wit.exports.test.producerConsumer; 2 | 3 | public class OperationsImpl : IOperations 4 | { 5 | public static int Add(int left, int right) 6 | { 7 | return left + right; 8 | } 9 | 10 | public static float AddFloat(float left, float right) 11 | { 12 | return left + right; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/E2ETest/testapps/E2EProducer/producer-consumer.wit: -------------------------------------------------------------------------------- 1 | package test:producer-consumer; 2 | 3 | interface operations { 4 | add: func(left: s32, right: s32) -> s32; 5 | @unstable(feature = float-add) 6 | add-float: func(a: f32, b: f32) -> f32; 7 | } 8 | 9 | world producer { 10 | export operations; 11 | } 12 | 13 | world consumer { 14 | import operations; 15 | } 16 | -------------------------------------------------------------------------------- /test/E2ETest/testapps/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/WasmComponentSdkTest/WasmComponentSdkTest/SimpleProducerConsumerTest.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Reflection; 3 | using Xunit; 4 | 5 | namespace WasmComponentSdkTest; 6 | 7 | public class SimpleProducerConsumerTest 8 | { 9 | // Unfortunately it doesn't seem possible to use wasmtime-dotnet with the component model yet, 10 | // (there's literally no mention of the entire concept within the wasmtime-dotnet repo), so for 11 | // now the tests work by invoking the wasmtime CLI 12 | 13 | #if DEBUG 14 | const string Config = "Debug"; 15 | #else 16 | const string Config = "Release"; 17 | #endif 18 | 19 | [Fact] 20 | public void CanBuildComponentWithImport() 21 | { 22 | var witInfo = GetWitInfo(FindModulePath($"../testapps/SimpleConsumer/bin/{Config}", "simpleconsumer.wasm")); 23 | Assert.Contains("import test:producer-consumer/operations", witInfo); 24 | } 25 | 26 | [Fact] 27 | public void CanBuildComponentWithExport() 28 | { 29 | var witInfo = GetWitInfo(FindModulePath($"../testapps/SimpleProducer/bin/{Config}", "simpleproducer.wasm")); 30 | Assert.Contains("export test:producer-consumer/operations", witInfo); 31 | } 32 | 33 | [Fact] 34 | public void CanBuildComponentWithWitPackage() 35 | { 36 | var witInfo = GetWitInfo(FindModulePath($"../testapps/AppWithWitFolder/bin/{Config}", "appwithwitfolder.wasm")); 37 | Assert.Contains("import test:pkg/folder", witInfo); 38 | } 39 | 40 | [Fact] 41 | public void CanComposeImportWithExport() 42 | { 43 | var composed = FindModulePath("../testapps/SimpleConsumer", "composed.wasm"); 44 | var (stdout, stderr, code) = ExecuteCommandComponent(composed); 45 | if (code != 0) { 46 | Assert.Fail(stderr); 47 | } 48 | Assert.StartsWith("Hello, world on Wasm", stdout); 49 | Assert.Contains("123 + 456 = 579", stdout); 50 | } 51 | 52 | [Fact] 53 | public void CanBuildAppFromOci() 54 | { 55 | var composed = FindModulePath($"../testapps/OciWit/bin/{Config}", "ociwit.wasm"); 56 | var (stdout, stderr, code) = ExecuteCommandComponent(composed, "-S http"); 57 | if (code != 0) { 58 | Assert.Fail(stderr); 59 | } 60 | Assert.StartsWith("Oci is awesome!", stdout); 61 | } 62 | 63 | private static (string, string, int) ExecuteCommandComponent(string componentFilePath) 64 | { 65 | return ExecuteCommandComponent(componentFilePath, string.Empty); 66 | } 67 | 68 | private static (string, string, int) ExecuteCommandComponent(string componentFilePath, string wasmtime_args) 69 | { 70 | var startInfo = new ProcessStartInfo(WasmtimeExePath, $" {wasmtime_args} {componentFilePath}") { RedirectStandardOutput = true, RedirectStandardError = true }; 71 | var process = Process.Start(startInfo) ?? throw new InvalidOperationException("Failed to start process."); 72 | process.WaitForExit(); 73 | int code = process.ExitCode; 74 | var stdout = process.StandardOutput.ReadToEnd(); 75 | var stderr = process.StandardError.ReadToEnd(); 76 | 77 | return (stdout, stderr, code); 78 | } 79 | 80 | private static string GetWitInfo(string componentFilePath) 81 | { 82 | var startInfo = new ProcessStartInfo(WasmToolsExePath, $"component wit {componentFilePath}") { RedirectStandardOutput = true }; 83 | var witInfo = Process.Start(startInfo)!.StandardOutput.ReadToEnd(); 84 | return witInfo; 85 | } 86 | 87 | private static string WasmtimeExePath { get; } = GetAssemblyMetadataValue("WasmtimeExe")!; 88 | private static string WasmToolsExePath { get; } = GetAssemblyMetadataValue("WasmToolsExe")!; 89 | 90 | private static string? GetAssemblyMetadataValue(string key) => 91 | typeof(SimpleProducerConsumerTest).Assembly 92 | .GetCustomAttributes() 93 | .SingleOrDefault(x => x.Key == key)?.Value; 94 | 95 | private static string FindModulePath(string searchDir, string filename) 96 | { 97 | var resolvedSearchDir = Path.Combine( 98 | Path.GetDirectoryName(typeof(SimpleProducerConsumerTest).Assembly.Location)!, 99 | "../../..", 100 | searchDir); 101 | 102 | if (!Directory.Exists(resolvedSearchDir)) 103 | { 104 | throw new InvalidOperationException($"No such directory: {Path.GetFullPath(resolvedSearchDir)}"); 105 | } 106 | 107 | var matches = Directory.GetFiles(resolvedSearchDir, filename, SearchOption.AllDirectories); 108 | if (matches.Count() == 1) 109 | { 110 | return Path.GetFullPath(matches.Single()); 111 | } 112 | else if (matches.Count() == 2 && matches.Any(x => Path.GetFullPath(x).Contains($"wasi-wasm\\native"))) 113 | { 114 | return Path.GetFullPath(matches.First(x => Path.GetFullPath(x).Contains($"wasi-wasm\\native"))); 115 | } 116 | else if (matches.Count() == 2 && matches.Any(x => Path.GetFullPath(x).Contains($"wasi-wasm/native"))) 117 | { 118 | return Path.GetFullPath(matches.First(x => Path.GetFullPath(x).Contains($"wasi-wasm/native"))); 119 | } 120 | else 121 | { 122 | throw new Exception($"Failed to get modules path, matched {matches.Count()} entries for directory {resolvedSearchDir} and filename {filename}."); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /test/WasmComponentSdkTest/WasmComponentSdkTest/WasmComponentSdkTest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | net10.0 7 | enable 8 | enable 9 | 10 | false 11 | false 12 | 13 | 14 | false 15 | true 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | runtime; build; native; contentfiles; analyzers; buildtransitive 28 | all 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /test/WasmComponentSdkTest/testapps/AppWithWitFolder/AppWithWitFolder.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | Exe 8 | net10.0 9 | enable 10 | enable 11 | 12 | wasi-wasm 13 | appwithwitfolder 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/WasmComponentSdkTest/testapps/AppWithWitFolder/program.cs: -------------------------------------------------------------------------------- 1 | ImportstestWorld.wit.imports.test.pkg.v0_2_0.FolderInterop.Folder(); 2 | -------------------------------------------------------------------------------- /test/WasmComponentSdkTest/testapps/AppWithWitFolder/wit/imports.wit: -------------------------------------------------------------------------------- 1 | interface folder { folder: func();} 2 | 3 | world imports { 4 | import folder; 5 | } 6 | -------------------------------------------------------------------------------- /test/WasmComponentSdkTest/testapps/AppWithWitFolder/wit/world.wit: -------------------------------------------------------------------------------- 1 | package test:pkg@0.2.0; 2 | 3 | world importstest { 4 | include imports; 5 | } 6 | -------------------------------------------------------------------------------- /test/WasmComponentSdkTest/testapps/OciWit/Code.cs: -------------------------------------------------------------------------------- 1 | using CommandWorld.wit.exports.wasi.cli.v0_2_0; 2 | using MyFuncsWorld; 3 | using System.Text; 4 | 5 | namespace ProxyWorld.wit.exports.wasi.http.v0_2_0 6 | { 7 | using ProxyWorld.wit.imports.wasi.http.v0_2_0; 8 | public class IncomingHandlerImpl : IIncomingHandler 9 | { 10 | public static void Handle(ITypes.IncomingRequest request, ITypes.ResponseOutparam responseOut) 11 | { 12 | var content = Encoding.ASCII.GetBytes("Hello, from C#!"); 13 | var headers = new List<(string, byte[])> { 14 | ("content-type", Encoding.ASCII.GetBytes("text/plain")), 15 | ("content-length", Encoding.ASCII.GetBytes(content.Count().ToString())) 16 | }; 17 | var response = new ITypes.OutgoingResponse(ITypes.Fields.FromList(headers)); 18 | var body = response.Body(); 19 | ITypes.ResponseOutparam.Set(responseOut, Result.Ok(response)); 20 | using (var stream = body.Write()) 21 | { 22 | stream.BlockingWriteAndFlush(content); 23 | } 24 | ITypes.OutgoingBody.Finish(body, null); 25 | } 26 | } 27 | } 28 | namespace CommandWorld.wit.exports.wasi.cli.v0_2_0 29 | { 30 | public class RunImpl : IRun 31 | { 32 | public static void Run() 33 | { 34 | Console.WriteLine("Oci is awesome!"); 35 | } 36 | } 37 | } 38 | 39 | namespace MyFuncsWorld 40 | { 41 | public class MyFuncsWorldImpl : IMyFuncsWorld 42 | { 43 | public static int GetNumber() 44 | { 45 | return 123; 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /test/WasmComponentSdkTest/testapps/OciWit/OciWit.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | net10.0 7 | enable 8 | enable 9 | 10 | wasi-wasm 11 | ociwit 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /test/WasmComponentSdkTest/testapps/OciWit/wit/api.wit: -------------------------------------------------------------------------------- 1 | package test:simple; 2 | 3 | world my-funcs { 4 | export get-number: func() -> s32; 5 | } 6 | -------------------------------------------------------------------------------- /test/WasmComponentSdkTest/testapps/SimpleConsumer/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /test/WasmComponentSdkTest/testapps/SimpleConsumer/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using ConsumerWorld.wit.imports.test.producerConsumer; 3 | 4 | Console.WriteLine($"Hello, world on {RuntimeInformation.OSArchitecture}"); 5 | 6 | var result = OperationsInterop.Add(123, 456); 7 | Console.WriteLine($"123 + 456 = {result}"); 8 | -------------------------------------------------------------------------------- /test/WasmComponentSdkTest/testapps/SimpleConsumer/SimpleConsumer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | Exe 8 | net10.0 9 | enable 10 | enable 11 | 12 | true 13 | wasi-wasm 14 | simpleconsumer 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | ../SimpleProducer/bin/$(Configuration)/$(TargetFramework)/wasi-wasm/native/simpleproducer.wasm 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /test/WasmComponentSdkTest/testapps/SimpleProducer/OperationsImpl.cs: -------------------------------------------------------------------------------- 1 | namespace ProducerWorld.wit.exports.test.producerConsumer; 2 | 3 | public class OperationsImpl : IOperations 4 | { 5 | public static int Add(int left, int right) 6 | { 7 | return left + right; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/WasmComponentSdkTest/testapps/SimpleProducer/SimpleProducer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | net10.0 8 | enable 9 | enable 10 | 11 | true 12 | wasi-wasm 13 | 14 | simpleproducer 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /test/WasmComponentSdkTest/testapps/SimpleProducer/producer-consumer.wit: -------------------------------------------------------------------------------- 1 | package test:producer-consumer; 2 | 3 | interface operations { 4 | add: func(left: s32, right: s32) -> s32; 5 | } 6 | 7 | world producer { 8 | export operations; 9 | } 10 | 11 | world consumer { 12 | import operations; 13 | } 14 | -------------------------------------------------------------------------------- /test/WasmtimeCliFetcher/.gitignore: -------------------------------------------------------------------------------- 1 | tools/ 2 | -------------------------------------------------------------------------------- /test/WasmtimeCliFetcher/FetchWasmtime.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | mingw 4 | linux 5 | macos 6 | x86_64-$(WasmtimeTarget) 7 | aarch64-$(WasmtimeTarget) 8 | 9 | $(MSBuildThisFileDirectory)tools\wasmtime 10 | $(WasmtimeExe).exe 11 | 12 | 13 | $(MSBuildThisFileDirectory)tools\version-$(WasmtimeVersion) 14 | 15 | .tar.xz 16 | .zip 17 | https://github.com/bytecodealliance/wasmtime/releases/download/v$(WasmtimeVersion)/wasmtime-v$(WasmtimeVersion)-$(WasmtimeTarget)$(WasmtimeUrlExtension) 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /test/WitBindgenTest/WitBindgenTest/CodeGenerationTest.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace WitBindgenTest; 4 | 5 | public class CodeGenerationTest 6 | { 7 | [Fact] 8 | public void GeneratesSimpleImport() 9 | { 10 | // The fact that this compiles shows that the codegen worked 11 | var ex = Assert.Throws(() => 12 | LibraryUsingWit.Code.CallSimpleDoSomething()); 13 | 14 | // Currently, it generates [DllImport("*", ...)] so validate that 15 | var expectedErrorMessagePrefix = "Unable to load " + (OperatingSystem.IsWindows() ? "DLL" : "shared library"); 16 | Assert.StartsWith(expectedErrorMessagePrefix, ex.Message); 17 | } 18 | 19 | [Fact] 20 | public void GeneratesSimpleExport() 21 | { 22 | // The fact that this compiles is what matters. There would be no point calling 23 | // the function to validate its behavior, as that has nothing to do with WIT codegen 24 | // and wouldn't even be running as WebAssembly. 25 | Assert.NotNull((Func)MyFuncsWorldImpl.GetNumber); 26 | } 27 | 28 | [Fact] 29 | public void CanSpecifyWorld() 30 | { 31 | Assert.NotNull((Func)SomeStuffImpl.GetNumber); 32 | } 33 | 34 | [Fact] 35 | public void ShouldBeNormalResult() 36 | { 37 | Assert.NotNull((Func)MyResultsWorldImpl.StringError); 38 | } 39 | 40 | [Fact] 41 | public void ShouldBeNormalWitResult() 42 | { 43 | Assert.NotNull((Func>)MyWitResultsWorldImpl.StringError); 44 | } 45 | 46 | [Fact] 47 | public void CanChangeWitouputLocation() 48 | { 49 | Assert.NotNull((Func)MySimpleWorldImpl.GetNumber); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/WitBindgenTest/WitBindgenTest/WitBindgenTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net10.0 5 | enable 6 | enable 7 | 8 | false 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | all 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryUsingWit/Code.cs: -------------------------------------------------------------------------------- 1 | namespace LibraryUsingWit; 2 | 3 | public class Code 4 | { 5 | public static void CallSimpleDoSomething() 6 | { 7 | MyFuncsWorld.exports.MyFuncsWorld.DoSomething(); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryUsingWit/LibraryUsingWit.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | net10.0 7 | enable 8 | enable 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryUsingWit/MyFuncsWorldImpl.cs: -------------------------------------------------------------------------------- 1 | using MyFuncsWorld; 2 | 3 | public class MyFuncsWorldImpl : IMyFuncsWorld 4 | { 5 | public static int GetNumber() 6 | { 7 | return 123; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryUsingWit/SomeStuffImpl.cs: -------------------------------------------------------------------------------- 1 | // I don't think this namespace should be so different to the one in MyFuncsWorldImpl, 2 | // but currently that's what the codegen requires 3 | using ProducerWorld.wit.exports.test.multipleWorlds; 4 | 5 | public class SomeStuffImpl : ISomeStuff 6 | { 7 | public static int GetNumber() 8 | { 9 | return 456; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryUsingWit/multiple-worlds.wit: -------------------------------------------------------------------------------- 1 | package test:multiple-worlds; 2 | 3 | interface some-stuff { 4 | get-number: func() -> s32; 5 | } 6 | 7 | world producer { 8 | export some-stuff; 9 | } 10 | 11 | world consumer { 12 | import some-stuff; 13 | } 14 | -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryUsingWit/simple.wit: -------------------------------------------------------------------------------- 1 | package test:simple; 2 | 3 | world my-funcs { 4 | import do-something: func(); 5 | export get-number: func() -> s32; 6 | } 7 | -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryWithCustomGeneratedFilesLocation/Code.cs: -------------------------------------------------------------------------------- 1 | using MySimpleWorld; 2 | 3 | public class MySimpleWorldImpl : IMySimpleWorld 4 | { 5 | public static int GetNumber() 6 | { 7 | return 123; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryWithCustomGeneratedFilesLocation/LibraryWithCustomGeneratedFilesLocation.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | net10.0 7 | enable 8 | enable 9 | generated/wit 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryWithCustomGeneratedFilesLocation/generated/wit/MySimple.cs: -------------------------------------------------------------------------------- 1 | // Generated by `wit-bindgen` 0.40.0. DO NOT EDIT! 2 | // 3 | #nullable enable 4 | using System.Runtime.InteropServices; 5 | namespace MySimpleWorld { 6 | 7 | public interface IMySimpleWorld { 8 | static abstract int GetNumber(); 9 | 10 | } 11 | 12 | public readonly struct None {} 13 | 14 | [StructLayout(LayoutKind.Sequential)] 15 | public readonly struct Result 16 | { 17 | public readonly byte Tag; 18 | private readonly object value; 19 | 20 | private Result(byte tag, object value) 21 | { 22 | Tag = tag; 23 | this.value = value; 24 | } 25 | 26 | public static Result Ok(TOk ok) 27 | { 28 | return new Result(Tags.Ok, ok!); 29 | } 30 | 31 | public static Result Err(TErr err) 32 | { 33 | return new Result(Tags.Err, err!); 34 | } 35 | 36 | public bool IsOk => Tag == Tags.Ok; 37 | public bool IsErr => Tag == Tags.Err; 38 | 39 | public TOk AsOk 40 | { 41 | get 42 | { 43 | if (Tag == Tags.Ok) 44 | { 45 | return (TOk)value; 46 | } 47 | 48 | throw new ArgumentException("expected k, got " + Tag); 49 | } 50 | } 51 | 52 | public TErr AsErr 53 | { 54 | get 55 | { 56 | if (Tag == Tags.Err) 57 | { 58 | return (TErr)value; 59 | } 60 | 61 | throw new ArgumentException("expected Err, got " + Tag); 62 | } 63 | } 64 | 65 | public class Tags 66 | { 67 | public const byte Ok = 0; 68 | public const byte Err = 1; 69 | } 70 | } 71 | 72 | namespace exports { 73 | using System.Runtime.InteropServices; 74 | public static class MySimpleWorld 75 | { 76 | 77 | [UnmanagedCallersOnly(EntryPoint = "get-number")] 78 | public static unsafe int wasmExportGetNumber() { 79 | 80 | int ret; 81 | ret = MySimpleWorldImpl.GetNumber(); 82 | return ret; 83 | 84 | } 85 | 86 | } 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryWithCustomGeneratedFilesLocation/generated/wit/MySimpleWorld_component_type.wit: -------------------------------------------------------------------------------- 1 | package test:simple; 2 | 3 | world my-simple { 4 | export get-number: func() -> s32; 5 | } 6 | -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryWithCustomGeneratedFilesLocation/generated/wit/MySimpleWorld_wasm_import_linkage_attribute.cs: -------------------------------------------------------------------------------- 1 | // Generated by `wit-bindgen` 0.40.0. DO NOT EDIT! 2 | // 3 | #nullable enable 4 | 5 | #if !NET9_0_OR_GREATER 6 | // temporarily add this attribute until it is available in dotnet 9 7 | namespace System.Runtime.InteropServices 8 | { 9 | internal partial class WasmImportLinkageAttribute : Attribute {} 10 | } 11 | #endif 12 | -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryWithCustomGeneratedFilesLocation/generated/wit/lastbuild.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytecodealliance/componentize-dotnet/15a30cd85f968b717129c9caf148b1591c55f9fd/test/WitBindgenTest/testapps/LibraryWithCustomGeneratedFilesLocation/generated/wit/lastbuild.txt -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryWithCustomGeneratedFilesLocation/simple.wit: -------------------------------------------------------------------------------- 1 | package test:simple; 2 | 3 | world my-simple { 4 | export get-number: func() -> s32; 5 | } 6 | -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryWithCustomGeneratedFilesLocation/wit-bindgen-generatedlastbuild.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytecodealliance/componentize-dotnet/15a30cd85f968b717129c9caf148b1591c55f9fd/test/WitBindgenTest/testapps/LibraryWithCustomGeneratedFilesLocation/wit-bindgen-generatedlastbuild.txt -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryWithExceptions/LibraryWitExceptions.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | net10.0 7 | enable 8 | enable 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryWithExceptions/Result.cs: -------------------------------------------------------------------------------- 1 | using MyResultsWorld; 2 | 3 | public class MyResultsWorldImpl : IMyResultsWorld 4 | { 5 | public static float StringError(float a) 6 | { 7 | return a; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryWithExceptions/result.wit: -------------------------------------------------------------------------------- 1 | package test:results; 2 | 3 | world my-results { 4 | export string-error: func(a: f32) -> result; 5 | } 6 | -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryWithWitResultType/LibraryWithWitResultType.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | net10.0 7 | enable 8 | enable 9 | --with-wit-results 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryWithWitResultType/Result.cs: -------------------------------------------------------------------------------- 1 | // I don't think this namespace should be so different to the one in MyFuncsWorldImpl, 2 | // but currently that's what the codegen requires 3 | using MyWitResultsWorld; 4 | 5 | 6 | 7 | public class MyWitResultsWorldImpl : IMyWitResultsWorld 8 | { 9 | public static Result StringError(float a) 10 | { 11 | return Result.Ok(a); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/WitBindgenTest/testapps/LibraryWithWitResultType/result.wit: -------------------------------------------------------------------------------- 1 | package test:results; 2 | 3 | world my-wit-results { 4 | export string-error: func(a: f32) -> result; 5 | } 6 | -------------------------------------------------------------------------------- /wasm-component-sdk.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F40ED49E-72A3-410D-AFBC-94FE31614C1A}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WasmComponent.Sdk", "src\WasmComponent.Sdk\WasmComponent.Sdk.csproj", "{FB68D5A1-89AA-47AB-B397-F93FF529995C}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WitBindgen", "src\WitBindgen\WitBindgen.csproj", "{7D4CD1D4-4DD2-418F-9E46-FF4140293B63}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{AA757883-5539-467E-97EA-6FE67D09A697}" 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "calculator", "calculator", "{8A0A8F87-CEEB-447E-A694-36BEA1659CA5}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Adder", "samples\calculator\Adder\Adder.csproj", "{5A906283-BA3B-4335-A5FA-0DFDEB771D84}" 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CalculatorHost", "samples\calculator\CalculatorHost\CalculatorHost.csproj", "{09E495AF-959E-4B3C-90FC-7E6CD5869F27}" 19 | EndProject 20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CalculatorComposed", "samples\calculator\CalculatorComposed\CalculatorComposed.csproj", "{D6691373-08CB-466F-A230-A038BD82D6CD}" 21 | EndProject 22 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{A1E6722B-B184-4AB8-9629-E6A5E76EE9CA}" 23 | EndProject 24 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WitBindgenTest", "WitBindgenTest", "{1F70A217-41B7-4FCB-9C16-E0B9406E77AB}" 25 | EndProject 26 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testapps", "testapps", "{54191E3B-7EB0-4050-B781-415A87685BE3}" 27 | EndProject 28 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryUsingWit", "test\WitBindgenTest\testapps\LibraryUsingWit\LibraryUsingWit.csproj", "{20ED9DCE-3911-4382-BE1A-14BA3382A930}" 29 | EndProject 30 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WitBindgenTest", "test\WitBindgenTest\WitBindgenTest\WitBindgenTest.csproj", "{9B56CBAA-3E96-4ABD-A7E2-A986ADFD3408}" 31 | EndProject 32 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WasmComponentSdkTest", "WasmComponentSdkTest", "{FD37EDE5-DB46-4501-9153-7668C7CB9930}" 33 | EndProject 34 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testapps", "testapps", "{C9AB3852-164F-4DBA-B794-D9CC298174D6}" 35 | EndProject 36 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleProducer", "test\WasmComponentSdkTest\testapps\SimpleProducer\SimpleProducer.csproj", "{9176AC70-039F-43B5-BA3D-CDF9FE1D3BFB}" 37 | EndProject 38 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleConsumer", "test\WasmComponentSdkTest\testapps\SimpleConsumer\SimpleConsumer.csproj", "{BBF34708-0583-4708-AB93-CECADB446B8B}" 39 | EndProject 40 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WasmComponentSdkTest", "test\WasmComponentSdkTest\WasmComponentSdkTest\WasmComponentSdkTest.csproj", "{2BAB8E09-C4EC-40D3-9378-5BFB6620B26B}" 41 | EndProject 42 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WasmtimeCliFetcher", "WasmtimeCliFetcher", "{BAA8D48E-411B-4135-9E4F-5B01F5CF3C62}" 43 | ProjectSection(SolutionItems) = preProject 44 | test\WasmtimeCliFetcher\FetchWasmtime.targets = test\WasmtimeCliFetcher\FetchWasmtime.targets 45 | EndProjectSection 46 | EndProject 47 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "E2ETest", "E2ETest", "{B3F60B5E-F19A-4E69-91B5-51053E6BBF5A}" 48 | EndProject 49 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PackageTest", "test\E2ETest\PackageTest\PackageTest.csproj", "{777FE7FE-1B1A-4848-BE4A-7670A92DEBCC}" 50 | EndProject 51 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "templates", "templates", "{808186BE-9BD0-DD1D-D574-36EEAD1E7F8F}" 52 | EndProject 53 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BytecodeAlliance.Componentize.DotNet.Templates", "templates\BytecodeAlliance.Componentize.DotNet.Templates.csproj", "{16F33B39-83C5-4E6C-89D3-CF2B9385AC28}" 54 | EndProject 55 | Global 56 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 57 | Debug|Any CPU = Debug|Any CPU 58 | Debug|x64 = Debug|x64 59 | Debug|x86 = Debug|x86 60 | Release|Any CPU = Release|Any CPU 61 | Release|x64 = Release|x64 62 | Release|x86 = Release|x86 63 | EndGlobalSection 64 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 65 | {FB68D5A1-89AA-47AB-B397-F93FF529995C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 66 | {FB68D5A1-89AA-47AB-B397-F93FF529995C}.Debug|Any CPU.Build.0 = Debug|Any CPU 67 | {FB68D5A1-89AA-47AB-B397-F93FF529995C}.Debug|x64.ActiveCfg = Debug|Any CPU 68 | {FB68D5A1-89AA-47AB-B397-F93FF529995C}.Debug|x64.Build.0 = Debug|Any CPU 69 | {FB68D5A1-89AA-47AB-B397-F93FF529995C}.Debug|x86.ActiveCfg = Debug|Any CPU 70 | {FB68D5A1-89AA-47AB-B397-F93FF529995C}.Debug|x86.Build.0 = Debug|Any CPU 71 | {FB68D5A1-89AA-47AB-B397-F93FF529995C}.Release|Any CPU.ActiveCfg = Release|Any CPU 72 | {FB68D5A1-89AA-47AB-B397-F93FF529995C}.Release|Any CPU.Build.0 = Release|Any CPU 73 | {FB68D5A1-89AA-47AB-B397-F93FF529995C}.Release|x64.ActiveCfg = Release|Any CPU 74 | {FB68D5A1-89AA-47AB-B397-F93FF529995C}.Release|x64.Build.0 = Release|Any CPU 75 | {FB68D5A1-89AA-47AB-B397-F93FF529995C}.Release|x86.ActiveCfg = Release|Any CPU 76 | {FB68D5A1-89AA-47AB-B397-F93FF529995C}.Release|x86.Build.0 = Release|Any CPU 77 | {7D4CD1D4-4DD2-418F-9E46-FF4140293B63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 78 | {7D4CD1D4-4DD2-418F-9E46-FF4140293B63}.Debug|Any CPU.Build.0 = Debug|Any CPU 79 | {7D4CD1D4-4DD2-418F-9E46-FF4140293B63}.Debug|x64.ActiveCfg = Debug|Any CPU 80 | {7D4CD1D4-4DD2-418F-9E46-FF4140293B63}.Debug|x64.Build.0 = Debug|Any CPU 81 | {7D4CD1D4-4DD2-418F-9E46-FF4140293B63}.Debug|x86.ActiveCfg = Debug|Any CPU 82 | {7D4CD1D4-4DD2-418F-9E46-FF4140293B63}.Debug|x86.Build.0 = Debug|Any CPU 83 | {7D4CD1D4-4DD2-418F-9E46-FF4140293B63}.Release|Any CPU.ActiveCfg = Release|Any CPU 84 | {7D4CD1D4-4DD2-418F-9E46-FF4140293B63}.Release|Any CPU.Build.0 = Release|Any CPU 85 | {7D4CD1D4-4DD2-418F-9E46-FF4140293B63}.Release|x64.ActiveCfg = Release|Any CPU 86 | {7D4CD1D4-4DD2-418F-9E46-FF4140293B63}.Release|x64.Build.0 = Release|Any CPU 87 | {7D4CD1D4-4DD2-418F-9E46-FF4140293B63}.Release|x86.ActiveCfg = Release|Any CPU 88 | {7D4CD1D4-4DD2-418F-9E46-FF4140293B63}.Release|x86.Build.0 = Release|Any CPU 89 | {5A906283-BA3B-4335-A5FA-0DFDEB771D84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 90 | {5A906283-BA3B-4335-A5FA-0DFDEB771D84}.Debug|Any CPU.Build.0 = Debug|Any CPU 91 | {5A906283-BA3B-4335-A5FA-0DFDEB771D84}.Debug|x64.ActiveCfg = Debug|Any CPU 92 | {5A906283-BA3B-4335-A5FA-0DFDEB771D84}.Debug|x64.Build.0 = Debug|Any CPU 93 | {5A906283-BA3B-4335-A5FA-0DFDEB771D84}.Debug|x86.ActiveCfg = Debug|Any CPU 94 | {5A906283-BA3B-4335-A5FA-0DFDEB771D84}.Debug|x86.Build.0 = Debug|Any CPU 95 | {5A906283-BA3B-4335-A5FA-0DFDEB771D84}.Release|Any CPU.ActiveCfg = Release|Any CPU 96 | {5A906283-BA3B-4335-A5FA-0DFDEB771D84}.Release|Any CPU.Build.0 = Release|Any CPU 97 | {5A906283-BA3B-4335-A5FA-0DFDEB771D84}.Release|x64.ActiveCfg = Release|Any CPU 98 | {5A906283-BA3B-4335-A5FA-0DFDEB771D84}.Release|x64.Build.0 = Release|Any CPU 99 | {5A906283-BA3B-4335-A5FA-0DFDEB771D84}.Release|x86.ActiveCfg = Release|Any CPU 100 | {5A906283-BA3B-4335-A5FA-0DFDEB771D84}.Release|x86.Build.0 = Release|Any CPU 101 | {09E495AF-959E-4B3C-90FC-7E6CD5869F27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 102 | {09E495AF-959E-4B3C-90FC-7E6CD5869F27}.Debug|Any CPU.Build.0 = Debug|Any CPU 103 | {09E495AF-959E-4B3C-90FC-7E6CD5869F27}.Debug|x64.ActiveCfg = Debug|Any CPU 104 | {09E495AF-959E-4B3C-90FC-7E6CD5869F27}.Debug|x64.Build.0 = Debug|Any CPU 105 | {09E495AF-959E-4B3C-90FC-7E6CD5869F27}.Debug|x86.ActiveCfg = Debug|Any CPU 106 | {09E495AF-959E-4B3C-90FC-7E6CD5869F27}.Debug|x86.Build.0 = Debug|Any CPU 107 | {09E495AF-959E-4B3C-90FC-7E6CD5869F27}.Release|Any CPU.ActiveCfg = Release|Any CPU 108 | {09E495AF-959E-4B3C-90FC-7E6CD5869F27}.Release|Any CPU.Build.0 = Release|Any CPU 109 | {09E495AF-959E-4B3C-90FC-7E6CD5869F27}.Release|x64.ActiveCfg = Release|Any CPU 110 | {09E495AF-959E-4B3C-90FC-7E6CD5869F27}.Release|x64.Build.0 = Release|Any CPU 111 | {09E495AF-959E-4B3C-90FC-7E6CD5869F27}.Release|x86.ActiveCfg = Release|Any CPU 112 | {09E495AF-959E-4B3C-90FC-7E6CD5869F27}.Release|x86.Build.0 = Release|Any CPU 113 | {D6691373-08CB-466F-A230-A038BD82D6CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 114 | {D6691373-08CB-466F-A230-A038BD82D6CD}.Debug|Any CPU.Build.0 = Debug|Any CPU 115 | {D6691373-08CB-466F-A230-A038BD82D6CD}.Debug|x64.ActiveCfg = Debug|Any CPU 116 | {D6691373-08CB-466F-A230-A038BD82D6CD}.Debug|x64.Build.0 = Debug|Any CPU 117 | {D6691373-08CB-466F-A230-A038BD82D6CD}.Debug|x86.ActiveCfg = Debug|Any CPU 118 | {D6691373-08CB-466F-A230-A038BD82D6CD}.Debug|x86.Build.0 = Debug|Any CPU 119 | {D6691373-08CB-466F-A230-A038BD82D6CD}.Release|Any CPU.ActiveCfg = Release|Any CPU 120 | {D6691373-08CB-466F-A230-A038BD82D6CD}.Release|Any CPU.Build.0 = Release|Any CPU 121 | {D6691373-08CB-466F-A230-A038BD82D6CD}.Release|x64.ActiveCfg = Release|Any CPU 122 | {D6691373-08CB-466F-A230-A038BD82D6CD}.Release|x64.Build.0 = Release|Any CPU 123 | {D6691373-08CB-466F-A230-A038BD82D6CD}.Release|x86.ActiveCfg = Release|Any CPU 124 | {D6691373-08CB-466F-A230-A038BD82D6CD}.Release|x86.Build.0 = Release|Any CPU 125 | {20ED9DCE-3911-4382-BE1A-14BA3382A930}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 126 | {20ED9DCE-3911-4382-BE1A-14BA3382A930}.Debug|Any CPU.Build.0 = Debug|Any CPU 127 | {20ED9DCE-3911-4382-BE1A-14BA3382A930}.Debug|x64.ActiveCfg = Debug|Any CPU 128 | {20ED9DCE-3911-4382-BE1A-14BA3382A930}.Debug|x64.Build.0 = Debug|Any CPU 129 | {20ED9DCE-3911-4382-BE1A-14BA3382A930}.Debug|x86.ActiveCfg = Debug|Any CPU 130 | {20ED9DCE-3911-4382-BE1A-14BA3382A930}.Debug|x86.Build.0 = Debug|Any CPU 131 | {20ED9DCE-3911-4382-BE1A-14BA3382A930}.Release|Any CPU.ActiveCfg = Release|Any CPU 132 | {20ED9DCE-3911-4382-BE1A-14BA3382A930}.Release|Any CPU.Build.0 = Release|Any CPU 133 | {20ED9DCE-3911-4382-BE1A-14BA3382A930}.Release|x64.ActiveCfg = Release|Any CPU 134 | {20ED9DCE-3911-4382-BE1A-14BA3382A930}.Release|x64.Build.0 = Release|Any CPU 135 | {20ED9DCE-3911-4382-BE1A-14BA3382A930}.Release|x86.ActiveCfg = Release|Any CPU 136 | {20ED9DCE-3911-4382-BE1A-14BA3382A930}.Release|x86.Build.0 = Release|Any CPU 137 | {9B56CBAA-3E96-4ABD-A7E2-A986ADFD3408}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 138 | {9B56CBAA-3E96-4ABD-A7E2-A986ADFD3408}.Debug|Any CPU.Build.0 = Debug|Any CPU 139 | {9B56CBAA-3E96-4ABD-A7E2-A986ADFD3408}.Debug|x64.ActiveCfg = Debug|Any CPU 140 | {9B56CBAA-3E96-4ABD-A7E2-A986ADFD3408}.Debug|x64.Build.0 = Debug|Any CPU 141 | {9B56CBAA-3E96-4ABD-A7E2-A986ADFD3408}.Debug|x86.ActiveCfg = Debug|Any CPU 142 | {9B56CBAA-3E96-4ABD-A7E2-A986ADFD3408}.Debug|x86.Build.0 = Debug|Any CPU 143 | {9B56CBAA-3E96-4ABD-A7E2-A986ADFD3408}.Release|Any CPU.ActiveCfg = Release|Any CPU 144 | {9B56CBAA-3E96-4ABD-A7E2-A986ADFD3408}.Release|Any CPU.Build.0 = Release|Any CPU 145 | {9B56CBAA-3E96-4ABD-A7E2-A986ADFD3408}.Release|x64.ActiveCfg = Release|Any CPU 146 | {9B56CBAA-3E96-4ABD-A7E2-A986ADFD3408}.Release|x64.Build.0 = Release|Any CPU 147 | {9B56CBAA-3E96-4ABD-A7E2-A986ADFD3408}.Release|x86.ActiveCfg = Release|Any CPU 148 | {9B56CBAA-3E96-4ABD-A7E2-A986ADFD3408}.Release|x86.Build.0 = Release|Any CPU 149 | {9176AC70-039F-43B5-BA3D-CDF9FE1D3BFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 150 | {9176AC70-039F-43B5-BA3D-CDF9FE1D3BFB}.Debug|Any CPU.Build.0 = Debug|Any CPU 151 | {9176AC70-039F-43B5-BA3D-CDF9FE1D3BFB}.Debug|x64.ActiveCfg = Debug|Any CPU 152 | {9176AC70-039F-43B5-BA3D-CDF9FE1D3BFB}.Debug|x64.Build.0 = Debug|Any CPU 153 | {9176AC70-039F-43B5-BA3D-CDF9FE1D3BFB}.Debug|x86.ActiveCfg = Debug|Any CPU 154 | {9176AC70-039F-43B5-BA3D-CDF9FE1D3BFB}.Debug|x86.Build.0 = Debug|Any CPU 155 | {9176AC70-039F-43B5-BA3D-CDF9FE1D3BFB}.Release|Any CPU.ActiveCfg = Release|Any CPU 156 | {9176AC70-039F-43B5-BA3D-CDF9FE1D3BFB}.Release|Any CPU.Build.0 = Release|Any CPU 157 | {9176AC70-039F-43B5-BA3D-CDF9FE1D3BFB}.Release|x64.ActiveCfg = Release|Any CPU 158 | {9176AC70-039F-43B5-BA3D-CDF9FE1D3BFB}.Release|x64.Build.0 = Release|Any CPU 159 | {9176AC70-039F-43B5-BA3D-CDF9FE1D3BFB}.Release|x86.ActiveCfg = Release|Any CPU 160 | {9176AC70-039F-43B5-BA3D-CDF9FE1D3BFB}.Release|x86.Build.0 = Release|Any CPU 161 | {BBF34708-0583-4708-AB93-CECADB446B8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 162 | {BBF34708-0583-4708-AB93-CECADB446B8B}.Debug|Any CPU.Build.0 = Debug|Any CPU 163 | {BBF34708-0583-4708-AB93-CECADB446B8B}.Debug|x64.ActiveCfg = Debug|Any CPU 164 | {BBF34708-0583-4708-AB93-CECADB446B8B}.Debug|x64.Build.0 = Debug|Any CPU 165 | {BBF34708-0583-4708-AB93-CECADB446B8B}.Debug|x86.ActiveCfg = Debug|Any CPU 166 | {BBF34708-0583-4708-AB93-CECADB446B8B}.Debug|x86.Build.0 = Debug|Any CPU 167 | {BBF34708-0583-4708-AB93-CECADB446B8B}.Release|Any CPU.ActiveCfg = Release|Any CPU 168 | {BBF34708-0583-4708-AB93-CECADB446B8B}.Release|Any CPU.Build.0 = Release|Any CPU 169 | {BBF34708-0583-4708-AB93-CECADB446B8B}.Release|x64.ActiveCfg = Release|Any CPU 170 | {BBF34708-0583-4708-AB93-CECADB446B8B}.Release|x64.Build.0 = Release|Any CPU 171 | {BBF34708-0583-4708-AB93-CECADB446B8B}.Release|x86.ActiveCfg = Release|Any CPU 172 | {BBF34708-0583-4708-AB93-CECADB446B8B}.Release|x86.Build.0 = Release|Any CPU 173 | {2BAB8E09-C4EC-40D3-9378-5BFB6620B26B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 174 | {2BAB8E09-C4EC-40D3-9378-5BFB6620B26B}.Debug|Any CPU.Build.0 = Debug|Any CPU 175 | {2BAB8E09-C4EC-40D3-9378-5BFB6620B26B}.Debug|x64.ActiveCfg = Debug|Any CPU 176 | {2BAB8E09-C4EC-40D3-9378-5BFB6620B26B}.Debug|x64.Build.0 = Debug|Any CPU 177 | {2BAB8E09-C4EC-40D3-9378-5BFB6620B26B}.Debug|x86.ActiveCfg = Debug|Any CPU 178 | {2BAB8E09-C4EC-40D3-9378-5BFB6620B26B}.Debug|x86.Build.0 = Debug|Any CPU 179 | {2BAB8E09-C4EC-40D3-9378-5BFB6620B26B}.Release|Any CPU.ActiveCfg = Release|Any CPU 180 | {2BAB8E09-C4EC-40D3-9378-5BFB6620B26B}.Release|Any CPU.Build.0 = Release|Any CPU 181 | {2BAB8E09-C4EC-40D3-9378-5BFB6620B26B}.Release|x64.ActiveCfg = Release|Any CPU 182 | {2BAB8E09-C4EC-40D3-9378-5BFB6620B26B}.Release|x64.Build.0 = Release|Any CPU 183 | {2BAB8E09-C4EC-40D3-9378-5BFB6620B26B}.Release|x86.ActiveCfg = Release|Any CPU 184 | {2BAB8E09-C4EC-40D3-9378-5BFB6620B26B}.Release|x86.Build.0 = Release|Any CPU 185 | {777FE7FE-1B1A-4848-BE4A-7670A92DEBCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 186 | {777FE7FE-1B1A-4848-BE4A-7670A92DEBCC}.Debug|Any CPU.Build.0 = Debug|Any CPU 187 | {777FE7FE-1B1A-4848-BE4A-7670A92DEBCC}.Debug|x64.ActiveCfg = Debug|Any CPU 188 | {777FE7FE-1B1A-4848-BE4A-7670A92DEBCC}.Debug|x64.Build.0 = Debug|Any CPU 189 | {777FE7FE-1B1A-4848-BE4A-7670A92DEBCC}.Debug|x86.ActiveCfg = Debug|Any CPU 190 | {777FE7FE-1B1A-4848-BE4A-7670A92DEBCC}.Debug|x86.Build.0 = Debug|Any CPU 191 | {777FE7FE-1B1A-4848-BE4A-7670A92DEBCC}.Release|Any CPU.ActiveCfg = Release|Any CPU 192 | {777FE7FE-1B1A-4848-BE4A-7670A92DEBCC}.Release|Any CPU.Build.0 = Release|Any CPU 193 | {777FE7FE-1B1A-4848-BE4A-7670A92DEBCC}.Release|x64.ActiveCfg = Release|Any CPU 194 | {777FE7FE-1B1A-4848-BE4A-7670A92DEBCC}.Release|x64.Build.0 = Release|Any CPU 195 | {777FE7FE-1B1A-4848-BE4A-7670A92DEBCC}.Release|x86.ActiveCfg = Release|Any CPU 196 | {777FE7FE-1B1A-4848-BE4A-7670A92DEBCC}.Release|x86.Build.0 = Release|Any CPU 197 | {16F33B39-83C5-4E6C-89D3-CF2B9385AC28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 198 | {16F33B39-83C5-4E6C-89D3-CF2B9385AC28}.Debug|Any CPU.Build.0 = Debug|Any CPU 199 | {16F33B39-83C5-4E6C-89D3-CF2B9385AC28}.Debug|x64.ActiveCfg = Debug|Any CPU 200 | {16F33B39-83C5-4E6C-89D3-CF2B9385AC28}.Debug|x64.Build.0 = Debug|Any CPU 201 | {16F33B39-83C5-4E6C-89D3-CF2B9385AC28}.Debug|x86.ActiveCfg = Debug|Any CPU 202 | {16F33B39-83C5-4E6C-89D3-CF2B9385AC28}.Debug|x86.Build.0 = Debug|Any CPU 203 | {16F33B39-83C5-4E6C-89D3-CF2B9385AC28}.Release|Any CPU.ActiveCfg = Release|Any CPU 204 | {16F33B39-83C5-4E6C-89D3-CF2B9385AC28}.Release|Any CPU.Build.0 = Release|Any CPU 205 | {16F33B39-83C5-4E6C-89D3-CF2B9385AC28}.Release|x64.ActiveCfg = Release|Any CPU 206 | {16F33B39-83C5-4E6C-89D3-CF2B9385AC28}.Release|x64.Build.0 = Release|Any CPU 207 | {16F33B39-83C5-4E6C-89D3-CF2B9385AC28}.Release|x86.ActiveCfg = Release|Any CPU 208 | {16F33B39-83C5-4E6C-89D3-CF2B9385AC28}.Release|x86.Build.0 = Release|Any CPU 209 | EndGlobalSection 210 | GlobalSection(SolutionProperties) = preSolution 211 | HideSolutionNode = FALSE 212 | EndGlobalSection 213 | GlobalSection(NestedProjects) = preSolution 214 | {FB68D5A1-89AA-47AB-B397-F93FF529995C} = {F40ED49E-72A3-410D-AFBC-94FE31614C1A} 215 | {7D4CD1D4-4DD2-418F-9E46-FF4140293B63} = {F40ED49E-72A3-410D-AFBC-94FE31614C1A} 216 | {8A0A8F87-CEEB-447E-A694-36BEA1659CA5} = {AA757883-5539-467E-97EA-6FE67D09A697} 217 | {5A906283-BA3B-4335-A5FA-0DFDEB771D84} = {8A0A8F87-CEEB-447E-A694-36BEA1659CA5} 218 | {09E495AF-959E-4B3C-90FC-7E6CD5869F27} = {8A0A8F87-CEEB-447E-A694-36BEA1659CA5} 219 | {D6691373-08CB-466F-A230-A038BD82D6CD} = {8A0A8F87-CEEB-447E-A694-36BEA1659CA5} 220 | {1F70A217-41B7-4FCB-9C16-E0B9406E77AB} = {A1E6722B-B184-4AB8-9629-E6A5E76EE9CA} 221 | {54191E3B-7EB0-4050-B781-415A87685BE3} = {1F70A217-41B7-4FCB-9C16-E0B9406E77AB} 222 | {20ED9DCE-3911-4382-BE1A-14BA3382A930} = {54191E3B-7EB0-4050-B781-415A87685BE3} 223 | {9B56CBAA-3E96-4ABD-A7E2-A986ADFD3408} = {1F70A217-41B7-4FCB-9C16-E0B9406E77AB} 224 | {FD37EDE5-DB46-4501-9153-7668C7CB9930} = {A1E6722B-B184-4AB8-9629-E6A5E76EE9CA} 225 | {C9AB3852-164F-4DBA-B794-D9CC298174D6} = {FD37EDE5-DB46-4501-9153-7668C7CB9930} 226 | {9176AC70-039F-43B5-BA3D-CDF9FE1D3BFB} = {C9AB3852-164F-4DBA-B794-D9CC298174D6} 227 | {BBF34708-0583-4708-AB93-CECADB446B8B} = {C9AB3852-164F-4DBA-B794-D9CC298174D6} 228 | {2BAB8E09-C4EC-40D3-9378-5BFB6620B26B} = {FD37EDE5-DB46-4501-9153-7668C7CB9930} 229 | {BAA8D48E-411B-4135-9E4F-5B01F5CF3C62} = {A1E6722B-B184-4AB8-9629-E6A5E76EE9CA} 230 | {B3F60B5E-F19A-4E69-91B5-51053E6BBF5A} = {A1E6722B-B184-4AB8-9629-E6A5E76EE9CA} 231 | {777FE7FE-1B1A-4848-BE4A-7670A92DEBCC} = {B3F60B5E-F19A-4E69-91B5-51053E6BBF5A} 232 | {16F33B39-83C5-4E6C-89D3-CF2B9385AC28} = {808186BE-9BD0-DD1D-D574-36EEAD1E7F8F} 233 | EndGlobalSection 234 | GlobalSection(ExtensibilityGlobals) = postSolution 235 | SolutionGuid = {1F033B40-BF0A-4D81-B1D6-84080B73D385} 236 | EndGlobalSection 237 | EndGlobal 238 | --------------------------------------------------------------------------------