Skip to content
← Back

src/driver/path_config.ghul

1
namespace Driver is
2
use System.Runtime.InteropServices.RuntimeInformation;
3
use System.Runtime.InteropServices.OSPlatform;
4
use System.Runtime.InteropServices.Architecture;
5
6
use IO.Std;
7
8
use Collections.Iterable;
9
use Collections.LIST;
10
11
use Ghul.Pipes;
12
13
class PATH_CONFIG is
14
_default_library_prefix: string;
15
_library_prefix: string?;
16
17
_ilasm_package_paths: LIST[string];
18
install_folder: string;
19
20
// The .NET reference-assembly directory, supplied by the build via
21
// `--sdk-ref-path`. Only consulted when no assemblies are passed with
22
// `-a` (the bare-invocation / test path); MSBuild builds pass the full
23
// resolved reference set and never set this.
24
sdk_reference_path: string? public;
25
26
// Explicit override from the `--target-framework` flag, used when
27
// deriving the .runtimeconfig.json moniker beside the compiled binary.
28
// Wins over inference from `sdk_reference_path` and the host TFM.
29
target_framework: string? public;
30
31
_host_target_framework: string?;
32
_host_target_framework_resolved: bool;
33
34
// The TFM the compiler was itself built for, read from its own
35
// .runtimeconfig.json (sibling of the executing assembly). Cached.
36
// Returns null when the file is missing or doesn't contain a "tfm"
37
// field — the resolver chain falls back to a hardcoded default.
38
host_target_framework: string? public is
39
if _host_target_framework_resolved then
40
return _host_target_framework;
41
fi
42
43
_host_target_framework_resolved = true;
44
45
let executing_assembly = System.Reflection.Assembly.get_executing_assembly();
46
let assembly_path = IO.Path.get_full_path(executing_assembly.location);
47
let directory = IO.Path.get_directory_name(assembly_path);
48
let name = IO.Path.get_file_name_without_extension(assembly_path);
49
let config_path = IO.Path.join(directory, "{name}.runtimeconfig.json");
50
51
if !IO.File.exists(config_path) then
52
return null;
53
fi
54
55
try
56
_host_target_framework = TARGET_FRAMEWORK_RESOLVER().extract_tfm(IO.File.read_all_text(config_path));
57
catch ex: System.Exception
58
_host_target_framework = null;
59
yrt
60
61
return _host_target_framework;
62
si
63
64
library_prefix: string public =>
65
if _library_prefix? then
66
_library_prefix
67
else
68
_default_library_prefix
69
fi,
70
= value is
71
_library_prefix = value;
72
73
if !library_prefix.ends_with('/') then
74
library_prefix = "{library_prefix}/";
75
fi
76
si
77
78
_ilasm_path: string?;
79
80
ilasm_path: string is
81
if _ilasm_path? then
82
return _ilasm_path;
83
fi
84
85
let os: string mut;
86
let file_extension: string mut = "";
87
if RuntimeInformation.is_o_s_platform(OSPlatform.linux) then
88
os = "linux";
89
elif RuntimeInformation.is_o_s_platform(OSPlatform.osx) then
90
os = "osx";
91
elif RuntimeInformation.is_o_s_platform(OSPlatform.windows) then
92
os = "win";
93
file_extension = ".exe";
94
else
95
throw System.Exception("Unsupported host {RuntimeInformation.osdescription}");
96
fi
97
98
let architecture =
99
if RuntimeInformation.osarchitecture == Architecture.ARM then
100
"arm";
101
elif RuntimeInformation.osarchitecture == Architecture.ARM64 then
102
"arm64";
103
elif RuntimeInformation.osarchitecture == Architecture.X86 then
104
"x86";
105
elif RuntimeInformation.osarchitecture == Architecture.X64 then
106
"x64";
107
else
108
throw System.Exception("Unsupported host {RuntimeInformation.osdescription}");
109
fi;
110
111
// FIXME: we have a method for this, why are we not calling it?
112
_ilasm_path = "{install_folder}runtimes/{os}-{architecture}/native/ilasm{file_extension}";
113
114
if !IO.File.exists(_ilasm_path) then
115
_ilasm_path = _try_find_ilasm_package(os, architecture, file_extension);
116
fi
117
118
if !_ilasm_path? \/ !IO.File.exists(_ilasm_path) then
119
Std.error.write_line("error: ILAsm not found. Try adding the ILAsm package for your host to your .ghulproj: <PackageReference Include=\"runtime.{os}-{architecture}.Microsoft.NETCore.ILAsm\" Version=\"10.0.0\" GeneratePathProperty=\"true\" />");
120
121
System.Environment.exit(1);
122
fi
123
124
return _ilasm_path!;
125
si
126
127
init() is
128
super.init();
129
130
let executing_assembly = System.Reflection.Assembly.get_executing_assembly();
131
132
let assembly_path = IO.Path.get_full_path(executing_assembly.location);
133
134
install_folder = IO.Path.get_directory_name(assembly_path) ?? ".";
135
136
if !install_folder.ends_with('/') then
137
install_folder = "{install_folder}/";
138
fi
139
140
_default_library_prefix = "{install_folder}lib/";
141
142
_ilasm_package_paths = LIST();
143
si
144
145
add_ilasm_packages(package_paths: Iterable[string]) is
146
_ilasm_path = null;
147
148
for path in package_paths do
149
_ilasm_package_paths.add(path);
150
od
151
si
152
153
get_library_location(directory: string mut) -> string is
154
if !directory.starts_with('/') then
155
directory = "{library_prefix}{directory}";
156
fi
157
158
if !directory.ends_with('/') then
159
directory = "{directory}/";
160
fi
161
162
return directory;
163
si
164
165
_try_find_ilasm_package(os: string, architecture: string, file_extension: string) -> string? is
166
let match = _ilasm_package_paths |> find(p => p.contains("{os}-{architecture}"));
167
168
if match? then
169
// FIXME this works on Windows despite wrong path separator but should use path join
170
return "{match}/runtimes/{os}-{architecture}/native/ilasm{file_extension}";
171
fi
172
173
return null;
174
si
175
si
176
si