Skip to content

Commit 65fbab6

Browse files
committed
refactor(c#): Consolidate cs project generation code
Signed-off-by: James Sturtevant <[email protected]>
1 parent d40ab04 commit 65fbab6

File tree

4 files changed

+177
-209
lines changed

4 files changed

+177
-209
lines changed

crates/csharp/src/csproj.rs

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
use anyhow::Result;
2+
use std::{fs, path::PathBuf};
3+
4+
use heck::ToUpperCamelCase;
5+
6+
pub struct CSProject {
7+
name: String,
8+
dir: PathBuf,
9+
aot: bool,
10+
clean_targets: bool,
11+
world_name: String,
12+
wasm_imports: Vec<(String, String)>,
13+
}
14+
15+
impl CSProject {
16+
pub fn generate(&self) -> Result<()> {
17+
let name = &self.name;
18+
let world = &self.world_name.replace("-", "_");
19+
let snake_world = world.to_upper_camel_case();
20+
21+
fs::write(
22+
self.dir.join("rd.xml"),
23+
format!(
24+
r#"<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
25+
<Application>
26+
<Assembly Name="{name}">
27+
</Assembly>
28+
</Application>
29+
</Directives>"#
30+
),
31+
)?;
32+
33+
let mut csproj = format!(
34+
"<Project Sdk=\"Microsoft.NET.Sdk\">
35+
36+
<PropertyGroup>
37+
<TargetFramework>net8.0</TargetFramework>
38+
<LangVersion>preview</LangVersion>
39+
<RootNamespace>{name}</RootNamespace>
40+
<ImplicitUsings>enable</ImplicitUsings>
41+
<Nullable>enable</Nullable>
42+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
43+
</PropertyGroup>
44+
45+
<PropertyGroup>
46+
<PublishTrimmed>true</PublishTrimmed>
47+
<AssemblyName>{name}</AssemblyName>
48+
</PropertyGroup>
49+
<ItemGroup>
50+
<NativeLibrary Include=\"{world}_component_type.o\" />
51+
52+
</ItemGroup>
53+
54+
<ItemGroup>
55+
<RdXmlFile Include=\"rd.xml\" />
56+
</ItemGroup>
57+
"
58+
);
59+
60+
if self.aot {
61+
//TODO: Is this handled by the source generator? (Temporary just to test with numbers and strings)
62+
csproj.push_str(
63+
r#"
64+
<ItemGroup>
65+
<CustomLinkerArg Include="-Wl,--export,_initialize" />
66+
<CustomLinkerArg Include="-Wl,--no-entry" />
67+
<CustomLinkerArg Include="-mexec-model=reactor" />
68+
</ItemGroup>
69+
70+
<ItemGroup>
71+
<PackageReference Include="Microsoft.DotNet.ILCompiler.LLVM" Version="8.0.0-*" />
72+
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler.LLVM" Version="8.0.0-*" />
73+
</ItemGroup>
74+
"#,
75+
);
76+
77+
fs::write(
78+
self.dir.join("nuget.config"),
79+
r#"<?xml version="1.0" encoding="utf-8"?>
80+
<configuration>
81+
<config>
82+
<add key="globalPackagesFolder" value=".packages" />
83+
</config>
84+
<packageSources>
85+
<!--To inherit the global NuGet package sources remove the <clear/> line below -->
86+
<clear />
87+
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
88+
<add key="dotnet-experimental" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json" />
89+
<!--<add key="dotnet-experimental" value="C:\github\runtimelab\artifacts\packages\Debug\Shipping" />-->
90+
</packageSources>
91+
</configuration>"#,
92+
)?;
93+
}
94+
95+
if !&self.wasm_imports.is_empty() {
96+
csproj.push_str("\t<ItemGroup>\n");
97+
for (module_name, func_name) in &self.wasm_imports {
98+
csproj.push_str(&format!(
99+
r#"
100+
<WasmImport Include="{}!{}" />
101+
"#,
102+
module_name, func_name,
103+
));
104+
}
105+
csproj.push_str("\t</ItemGroup>\n\n");
106+
}
107+
108+
if self.clean_targets {
109+
let mut wasm_filename = self.dir.join(name);
110+
wasm_filename.set_extension("wasm");
111+
// In CI we run out of disk space if we don't clean up the files, we don't need to keep any of it around.
112+
csproj.push_str(&format!(
113+
"<Target Name=\"CleanAndDelete\" AfterTargets=\"Clean\">
114+
<!-- Remove obj folder -->
115+
<RemoveDir Directories=\"$(BaseIntermediateOutputPath)\" />
116+
<!-- Remove bin folder -->
117+
<RemoveDir Directories=\"$(BaseOutputPath)\" />
118+
<RemoveDir Directories=\"{}\" />
119+
<RemoveDir Directories=\".packages\" />
120+
</Target>",
121+
wasm_filename.display()
122+
));
123+
}
124+
125+
csproj.push_str(
126+
r#"</Project>
127+
"#,
128+
);
129+
130+
let camel = snake_world.to_upper_camel_case();
131+
fs::write(self.dir.join(format!("{camel}.csproj")), csproj)?;
132+
133+
Ok(())
134+
}
135+
136+
pub fn aot(&mut self) {
137+
self.aot = true;
138+
}
139+
140+
pub fn clean(&mut self) {
141+
self.clean_targets = true;
142+
}
143+
144+
pub fn add_import(&mut self, module_name: &str, func_name: &str) {
145+
self.wasm_imports
146+
.push((module_name.to_string(), func_name.to_string()));
147+
}
148+
}
149+
150+
pub fn project_builder(dir: PathBuf, name: &str, world_name: &str) -> CSProject {
151+
CSProject {
152+
name: name.to_string(),
153+
dir,
154+
aot: false,
155+
clean_targets: false,
156+
world_name: world_name.to_string(),
157+
wasm_imports: Vec::new(),
158+
}
159+
}

crates/csharp/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ use wit_bindgen_core::{
2222
Files, InterfaceGenerator as _, Ns, WorldGenerator,
2323
};
2424
use wit_component::StringEncoding;
25+
mod csproj;
26+
pub use csproj::project_builder;
2527

2628
//cargo run c-sharp --out-dir testing-csharp tests/codegen/floats.wit
2729

crates/csharp/tests/codegen.rs

Lines changed: 8 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// TODO: Implement tests similar to the other generators.
22
// This requires that we have any dependencies either included here or published to NuGet or similar.
33
use std::{
4-
env, fs,
4+
env,
55
path::{Path, PathBuf},
66
process::{Command, Stdio},
77
};
@@ -57,7 +57,6 @@ macro_rules! codegen_test {
5757
"simple-http",
5858
"simple-lists",
5959
"small-anonymous",
60-
"strings",
6160
"unused-import",
6261
"use-across-interfaces",
6362
"variants",
@@ -89,109 +88,10 @@ fn verify(dir: &Path, name: &str) {
8988
}
9089

9190
fn aot_verify(dir: &Path, name: &str) {
92-
let mut wasm_filename = dir.join(name);
93-
wasm_filename.set_extension("wasm");
94-
95-
fs::write(
96-
dir.join("nuget.config"),
97-
r#"<?xml version="1.0" encoding="utf-8"?>
98-
<configuration>
99-
<config>
100-
<add key="globalPackagesFolder" value=".packages" />
101-
</config>
102-
<packageSources>
103-
<!--To inherit the global NuGet package sources remove the <clear/> line below -->
104-
<clear />
105-
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
106-
<add key="dotnet-experimental" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json" />
107-
<!--<add key="dotnet-experimental" value="C:\github\runtimelab\artifacts\packages\Debug\Shipping" />-->
108-
</packageSources>
109-
</configuration>"#,
110-
).unwrap();
111-
112-
fs::write(
113-
dir.join("rd.xml"),
114-
format!(
115-
r#"<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
116-
<Application>
117-
<Assembly Name="{name}">
118-
</Assembly>
119-
</Application>
120-
</Directives>"#
121-
),
122-
)
123-
.unwrap();
124-
125-
let mut csproj = format!(
126-
"<Project Sdk=\"Microsoft.NET.Sdk\">
127-
128-
<PropertyGroup>
129-
<TargetFramework>net8.0</TargetFramework>
130-
<LangVersion>preview</LangVersion>
131-
<RootNamespace>{name}</RootNamespace>
132-
<ImplicitUsings>enable</ImplicitUsings>
133-
<Nullable>enable</Nullable>
134-
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
135-
</PropertyGroup>
136-
137-
<PropertyGroup>
138-
<PublishTrimmed>true</PublishTrimmed>
139-
<AssemblyName>{name}</AssemblyName>
140-
</PropertyGroup>
141-
"
142-
);
143-
144-
csproj.push_str(
145-
r#"
146-
<ItemGroup>
147-
<RdXmlFile Include="rd.xml" />
148-
</ItemGroup>
149-
150-
"#,
151-
);
152-
153-
csproj.push_str("\t<ItemGroup>\n");
154-
csproj.push_str(&format!(
155-
"\t\t<NativeLibrary Include=\"the_world_component_type.o\" />\n"
156-
));
157-
csproj.push_str("\t</ItemGroup>\n\n");
158-
159-
csproj.push_str(
160-
r#"
161-
<ItemGroup>
162-
<CustomLinkerArg Include="-Wl,--export,_initialize" />
163-
<CustomLinkerArg Include="-Wl,--no-entry" />
164-
<CustomLinkerArg Include="-mexec-model=reactor" />
165-
</ItemGroup>
166-
"#,
167-
);
168-
169-
// In CI we run out of disk space if we don't clean up the files, we don't need to keep any of it around.
170-
csproj.push_str(&format!(
171-
"<Target Name=\"CleanAndDelete\" AfterTargets=\"Clean\">
172-
<!-- Remove obj folder -->
173-
<RemoveDir Directories=\"$(BaseIntermediateOutputPath)\" />
174-
<!-- Remove bin folder -->
175-
<RemoveDir Directories=\"$(BaseOutputPath)\" />
176-
<RemoveDir Directories=\"{}\" />
177-
<RemoveDir Directories=\".packages\" />
178-
</Target>
179-
180-
",
181-
wasm_filename.display()
182-
));
183-
184-
csproj.push_str(
185-
r#"
186-
<ItemGroup>
187-
<PackageReference Include="Microsoft.DotNet.ILCompiler.LLVM" Version="8.0.0-*" />
188-
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler.LLVM" Version="8.0.0-*" />
189-
</ItemGroup>
190-
</Project>
191-
"#,
192-
);
193-
194-
fs::write(dir.join(format!("{name}.csproj")), csproj).unwrap();
91+
let mut project = wit_bindgen_csharp::project_builder(dir.to_path_buf(), &name, "the_world");
92+
project.aot();
93+
project.clean();
94+
project.generate().unwrap();
19595

19696
let dotnet_root_env = "DOTNET_ROOT";
19797
let dotnet_cmd: PathBuf;
@@ -204,9 +104,11 @@ fn aot_verify(dir: &Path, name: &str) {
204104

205105
cmd.current_dir(&dir);
206106

107+
let mut wasm_filename = dir.join(name);
108+
wasm_filename.set_extension("wasm");
207109
// add .arg("/bl") to diagnose dotnet build problems
208110
cmd.arg("build")
209-
.arg(dir.join(format!("{name}.csproj")))
111+
.arg(dir.join(format!("TheWorld.csproj")))
210112
.arg("-r")
211113
.arg("wasi-wasm")
212114
.arg("-c")

0 commit comments

Comments
 (0)