Skip to content

Commit

Permalink
c#: Update to use latest packages incorporating WasmImportLinkage (#791)
Browse files Browse the repository at this point in the history
* Update to use latest packages incorporating WasmImportLinkage

Remove WasmImport from csproj
Move cabi-realloc to c

* update to 9.0.0

redo import name

* move the cabi_realloc compilation to csproj

* update emscripten to 3.1.47 (LLVM 17)

* Use BeforeTargets instead  of BeforeBuild, append cabi_realloc to file names.
  • Loading branch information
yowl authored Dec 19, 2023
1 parent 1c5d94f commit 04b715a
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 82 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ jobs:
curl.exe -OL https://github.com/emscripten-core/emsdk/archive/refs/heads/main.zip
unzip main.zip
cd emsdk-main
./emsdk.bat install 3.1.23
./emsdk.bat activate 3.1.23
./emsdk.bat install 3.1.47
./emsdk.bat activate 3.1.47
if : matrix.os == 'windows-latest'
- run: ci/download-teavm.sh
Expand Down
44 changes: 20 additions & 24 deletions crates/csharp/src/csproj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ pub struct CSProject {
aot: bool,
clean_targets: bool,
world_name: String,
wasm_imports: Vec<(String, String)>,
}

impl CSProject {
Expand All @@ -20,14 +19,14 @@ impl CSProject {
aot: false,
clean_targets: false,
world_name: world_name.to_string(),
wasm_imports: Vec::new(),
}
}

pub fn generate(&self) -> Result<()> {
let name = &self.name;
let world = &self.world_name.replace("-", "_");
let snake_world = world.to_upper_camel_case();
let camel = snake_world.to_upper_camel_case();

fs::write(
self.dir.join("rd.xml"),
Expand Down Expand Up @@ -57,8 +56,9 @@ impl CSProject {
<PublishTrimmed>true</PublishTrimmed>
<AssemblyName>{name}</AssemblyName>
</PropertyGroup>
<ItemGroup>
<ItemGroup>
<NativeLibrary Include=\"{world}_component_type.o\" />
<NativeLibrary Include=\"$(MSBuildProjectDirectory)/{camel}_cabi_realloc.o\" />
</ItemGroup>
Expand All @@ -79,12 +79,27 @@ impl CSProject {
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.DotNet.ILCompiler.LLVM" Version="8.0.0-*" />
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler.LLVM" Version="8.0.0-*" />
<PackageReference Include="Microsoft.DotNet.ILCompiler.LLVM" Version="9.0.0-*" />
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler.LLVM" Version="9.0.0-*" />
</ItemGroup>
<Target Name="CheckWasmSdks">
<Error Text="Emscripten not found, not compiling to WebAssembly. To enable WebAssembly compilation, install Emscripten and ensure the EMSDK environment variable points to the directory containing upstream/emscripten/emcc.bat"
Condition="'$(EMSDK)' == ''" />
</Target>
"#,
);

csproj.push_str(&format!("
<Target Name=\"CompileCabiRealloc\" BeforeTargets=\"IlcCompile\" DependsOnTargets=\"CheckWasmSdks\"
Inputs=\"$(MSBuildProjectDirectory)/{camel}_cabi_realloc.c\"
Outputs=\"$(MSBuildProjectDirectory)/{camel}_cabi_realloc.o\"
>
<Exec Command=\"emcc.bat &quot;$(MSBuildProjectDirectory)/{camel}_cabi_realloc.c&quot; -c -o &quot;$(MSBuildProjectDirectory)/{camel}_cabi_realloc.o&quot;\"/>
</Target>
"
));

fs::write(
self.dir.join("nuget.config"),
r#"<?xml version="1.0" encoding="utf-8"?>
Expand All @@ -103,19 +118,6 @@ impl CSProject {
)?;
}

if !&self.wasm_imports.is_empty() {
csproj.push_str("\t<ItemGroup>\n");
for (module_name, func_name) in &self.wasm_imports {
csproj.push_str(&format!(
r#"
<WasmImport Include="{}!{}" />
"#,
module_name, func_name,
));
}
csproj.push_str("\t</ItemGroup>\n\n");
}

if self.clean_targets {
let mut wasm_filename = self.dir.join(name);
wasm_filename.set_extension("wasm");
Expand All @@ -138,7 +140,6 @@ impl CSProject {
"#,
);

let camel = snake_world.to_upper_camel_case();
fs::write(self.dir.join(format!("{camel}.csproj")), csproj)?;

Ok(())
Expand All @@ -151,9 +152,4 @@ impl CSProject {
pub fn clean(&mut self) {
self.clean_targets = true;
}

pub fn add_import(&mut self, module_name: &str, func_name: &str) {
self.wasm_imports
.push((module_name.to_string(), func_name.to_string()));
}
}
92 changes: 54 additions & 38 deletions crates/csharp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ impl WorldGenerator for CSharp {
let name = &format!("{}-world", resolve.worlds[world].name);
let mut gen = self.interface(resolve, name, true);

for (_, func) in funcs {
gen.import(name, func);
for (import_module_name, func) in funcs {
gen.import(import_module_name, func);
}

gen.add_world_fragment();
Expand Down Expand Up @@ -409,41 +409,39 @@ impl WorldGenerator for CSharp {
}

src.push_str("\n");
src.push_str(
r#"
internal static class Intrinsics
{
[UnmanagedCallersOnly(EntryPoint = "cabi_realloc")]
internal static IntPtr cabi_realloc(IntPtr ptr, uint old_size, uint align, uint new_size)
{
if (new_size == 0)
{
if(old_size != 0)
{
Marshal.Release(ptr);
}
return new IntPtr((int)align);
}
if (new_size > int.MaxValue)
{
throw new ArgumentException("Cannot allocate more that int.MaxValue", nameof(new_size));
}
if(old_size != 0)
{
return Marshal.ReAllocHGlobal(ptr, (int)new_size);
}

return Marshal.AllocHGlobal((int)new_size);
}
}
"#,
);
src.push_str("}\n");

files.push(&format!("{name}.cs"), indent(&src).as_bytes());

let mut cabi_relloc_src = String::new();

cabi_relloc_src.push_str(
r#"
#include <stdlib.h>
/* Done in C so we can avoid initializing the dotnet runtime and hence WASI libc */
/* It would be preferable to do this in C# but the constrainst of cabi_realloc and the demands */
/* of WASI libc prevent us doing so. */
/* See https://github.com/bytecodealliance/wit-bindgen/issues/777 */
/* and https://github.com/WebAssembly/wasi-libc/issues/452 */
/* The component model `start` function might be an alternative to this depending on whether it
/* has the same constraints as `cabi_realloc` */
__attribute__((__weak__, __export_name__("cabi_realloc")))
void *cabi_realloc(void *ptr, size_t old_size, size_t align, size_t new_size) {
(void) old_size;
if (new_size == 0) return (void*) align;
void *ret = realloc(ptr, new_size);
if (!ret) abort();
return ret;
}
"#,
);
files.push(
&format!("{name}_cabi_realloc.c"),
indent(&cabi_relloc_src).as_bytes(),
);

let generate_stub = |name: String, files: &mut Files, stubs: Stubs| {
let stub_file_name = format!("{name}Impl");
let interface_name = CSharp::get_class_name_from_qualified_name(name.clone());
Expand Down Expand Up @@ -496,6 +494,23 @@ impl WorldGenerator for CSharp {
.as_slice(),
);

// TODO: remove when we switch to dotnet 9
let mut wasm_import_linakge_src = String::new();

wasm_import_linakge_src.push_str(
r#"
// temporarily add this attribute until it is available in dotnet 9
namespace System.Runtime.InteropServices
{
public class WasmImportLinkageAttribute : Attribute {}
}
"#,
);
files.push(
&format!("{snake}_wasm_import_linkage_attribute.cs"),
indent(&wasm_import_linakge_src).as_bytes(),
);

for (name, interface_type_and_fragments) in &self.interface_fragments {
let fragments = &interface_type_and_fragments.interface_fragments;

Expand Down Expand Up @@ -535,10 +550,11 @@ impl WorldGenerator for CSharp {
"// Generated by `wit-bindgen` {version}. DO NOT EDIT!
{CSHARP_IMPORTS}
namespace {namespace}.{name};
public static class {interface_name}Interop {{
{body}
namespace {namespace}.{name}
{{
public static class {interface_name}Interop {{
{body}
}}
}}
"
);
Expand Down Expand Up @@ -694,7 +710,7 @@ impl InterfaceGenerator<'_> {
});
}

fn import(&mut self, _module: &String, func: &Function) {
fn import(&mut self, import_module_name: &str, func: &Function) {
if func.kind != FunctionKind::Freestanding {
todo!("resources");
}
Expand Down Expand Up @@ -766,7 +782,7 @@ impl InterfaceGenerator<'_> {
r#"
internal static class {camel_name}WasmInterop
{{
[DllImport("*", EntryPoint = "{import_name}")]
[DllImport("{import_module_name}", EntryPoint = "{import_name}"), WasmImportLinkage]
internal static extern {wasm_result_type} wasmImport{camel_name}({wasm_params});
}}
"#
Expand Down
18 changes: 0 additions & 18 deletions tests/runtime/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,24 +541,6 @@ fn tests(name: &str, dir_name: &str) -> Result<Vec<PathBuf>> {
wit_bindgen_csharp::CSProject::new(out_dir.clone(), &assembly_name, world_name);
csproj.aot();

// Write the WasmImports for NativeAOT-LLVM.
// See https://github.com/dotnet/runtimelab/issues/2383

for world in &resolve.worlds {
for import in &world.1.imports {
let module_name = resolve.name_world_key(import.0);
match import.1 {
WorldItem::Function(f) => csproj.add_import(&module_name, &f.name),
WorldItem::Interface(id) => {
for (_, f) in resolve.interfaces[*id].functions.iter() {
csproj.add_import(&module_name, &f.name)
}
}
WorldItem::Type(_) => {}
}
}
}

// Copy test file to target location to be included in compilation
let file_name = path.file_name().unwrap();
fs::copy(path, out_dir.join(file_name.to_str().unwrap()))?;
Expand Down

0 comments on commit 04b715a

Please sign in to comment.