Appearance
| 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 |