From c1bec3c1fd9d149059f4c3c4208ac7c603d14cf2 Mon Sep 17 00:00:00 2001 From: njlr Date: Sun, 7 Jun 2026 16:41:48 +0100 Subject: [PATCH 1/4] Fix runtime platforms --- dotnet/private/rules/common/binary.bzl | 5 +- dotnet/private/sdk/gen/ApphostPacks.fs | 4 +- dotnet/private/sdk/gen/BUILD.bazel | 1 + dotnet/private/sdk/gen/NugetRepo.fs | 83 ++++++++++++++----- dotnet/private/sdk/gen/RuntimePacks.fs | 4 +- dotnet/private/sdk/gen/TargetingPacks.fs | 4 +- dotnet/private/sdk/gen/paket.references | 1 + .../private/tests/target_runtime/BUILD.bazel | 64 ++++++++++++++ .../tests/target_runtime/host_model.dll | 1 + .../target_runtime/target_runtime_test.bzl | 72 ++++++++++++++++ dotnet/repositories.bzl | 32 +++++++ dotnet/toolchain.bzl | 28 +++++++ 12 files changed, 270 insertions(+), 29 deletions(-) create mode 100644 dotnet/private/tests/target_runtime/BUILD.bazel create mode 100644 dotnet/private/tests/target_runtime/host_model.dll create mode 100644 dotnet/private/tests/target_runtime/target_runtime_test.bzl diff --git a/dotnet/private/rules/common/binary.bzl b/dotnet/private/rules/common/binary.bzl index 52a78185f..0adf16acd 100644 --- a/dotnet/private/rules/common/binary.bzl +++ b/dotnet/private/rules/common/binary.bzl @@ -44,7 +44,8 @@ def _collect_native_dlls(assembly_runtime_info, deps): return result def _create_launcher(ctx, runfiles, executable): - runtime = get_toolchain(ctx).runtime + toolchain = get_toolchain(ctx) + runtime = toolchain.target_runtime windows_constraint = ctx.attr._windows_constraint[platform_common.ConstraintValueInfo] launcher = ctx.actions.declare_file("{}.{}".format(executable.basename, "bat" if ctx.target_platform_has_constraint(windows_constraint) else "sh"), sibling = executable) @@ -70,7 +71,7 @@ def _create_launcher(ctx, runfiles, executable): is_executable = True, ) - runfiles.extend(get_toolchain(ctx).dotnetinfo.runtime_files) + runfiles.extend(toolchain.dotnetinfo.target_runtime_files) return launcher diff --git a/dotnet/private/sdk/gen/ApphostPacks.fs b/dotnet/private/sdk/gen/ApphostPacks.fs index 2fac59a00..63b1cd2a5 100644 --- a/dotnet/private/sdk/gen/ApphostPacks.fs +++ b/dotnet/private/sdk/gen/ApphostPacks.fs @@ -132,10 +132,10 @@ let generateApphostPacksNugetRepo apphostPacksFile outputFolder = sha512 = packageInfo.sha512sri sources = [ NugetHelpers.nugetV3Feed ] netrc = None - dependencies = Dictionary() + dependencies = Map.empty targeting_pack_overrides = packageInfo.overrides framework_list = packageInfo.frameworkList - tools = Dictionary() }) + tools = Map.empty }) NugetRepo.generateBazelFiles "apphost_packs" repoPackages outputFolder "dotnet." () diff --git a/dotnet/private/sdk/gen/BUILD.bazel b/dotnet/private/sdk/gen/BUILD.bazel index 59310e695..76055b561 100644 --- a/dotnet/private/sdk/gen/BUILD.bazel +++ b/dotnet/private/sdk/gen/BUILD.bazel @@ -27,5 +27,6 @@ fsharp_binary( "@paket.paket2bazel_dependencies//nuget.versioning", "@paket.paket2bazel_dependencies//paket.core", "@paket.paket2bazel_dependencies//system.text.json", + "@paket.paket2bazel_dependencies//thoth.json.system.text.json", ], ) diff --git a/dotnet/private/sdk/gen/NugetRepo.fs b/dotnet/private/sdk/gen/NugetRepo.fs index e75c74b8f..ff129dac6 100644 --- a/dotnet/private/sdk/gen/NugetRepo.fs +++ b/dotnet/private/sdk/gen/NugetRepo.fs @@ -2,10 +2,7 @@ module NugetRepo open System.Text open System.IO -open System.Collections.Generic -open System.Text.Json -open System.Text.Json.Serialization -open System.Text.Encodings.Web +open Thoth.Json.Core type NugetRepoTool = { name: string @@ -19,16 +16,70 @@ type NugetRepoPackage = sha512: string sources: string seq netrc: string option - dependencies: Dictionary + dependencies: Map targeting_pack_overrides: string seq framework_list: string seq - tools: Dictionary } + tools: Map } + +let private encodeStringSeq values = + values + |> Seq.map Encode.string + |> Seq.toList + |> Encode.list + +let private encodeMap encodeValue values = + values + |> Map.toList + |> List.map (fun (key, value) -> key, encodeValue value) + |> Encode.object + +let private encodeTool (tool: NugetRepoTool) = + Encode.object [ + yield "name", Encode.string tool.name + yield "entrypoint", Encode.string tool.entrypoint + yield "runner", Encode.string tool.runner + ] + +let private encodePackage (package: NugetRepoPackage) = + Encode.object [ + yield "name", Encode.string package.name + yield "id", Encode.string package.id + yield "version", Encode.string package.version + yield "sha512", Encode.string package.sha512 + yield "sources", encodeStringSeq package.sources + + match package.netrc with + | Some netrc -> yield "netrc", Encode.string netrc + | None -> () + + yield "dependencies", encodeMap encodeStringSeq package.dependencies + yield "targeting_pack_overrides", encodeStringSeq package.targeting_pack_overrides + yield "framework_list", encodeStringSeq package.framework_list + + yield + "tools", + package.tools + |> encodeMap (fun tools -> + tools + |> Seq.map encodeTool + |> Seq.toList + |> Encode.list) + ] + +let private toGeneratedJson value = + value + |> Encode.toString 0 + // The replacements are so that the Bazel formatter does not have anything to format. + |> fun json -> + json + .Replace("\":\"", "\": \"") + .Replace("\",\"", "\", \"") + .Replace("\":[", "\": [") + .Replace("],", "], ") + .Replace("\":{", "\": {") + .Replace("},", "}, ") let generateTarget (packages: NugetRepoPackage seq) (repoName: string) (repoPrefix: string) = - let jsonOptions = JsonSerializerOptions() - jsonOptions.DefaultIgnoreCondition <- JsonIgnoreCondition.WhenWritingNull - jsonOptions.Encoder <- JavaScriptEncoder.UnsafeRelaxedJsonEscaping - let i = " " let sb = new StringBuilder() sb.Append($"{i}nuget_repo(\n") |> ignore @@ -40,17 +91,7 @@ let generateTarget (packages: NugetRepoPackage seq) (repoName: string) (repoPref for package in packages do sb.Append($"{i} ") |> ignore - sb.Append( - JsonSerializer - .Serialize(package, jsonOptions) - // The replacements are so that the Bazel formatter does not have anything to format - .Replace("\":\"", "\": \"") - .Replace("\",\"", "\", \"") - .Replace("\":[", "\": [") - .Replace("],", "], ") - .Replace("\":{", "\": {") - .Replace("},", "}, ") - ) + sb.Append(package |> encodePackage |> toGeneratedJson) |> ignore sb.Append(",\n") |> ignore diff --git a/dotnet/private/sdk/gen/RuntimePacks.fs b/dotnet/private/sdk/gen/RuntimePacks.fs index 6d9be70bc..a0cf65f9e 100644 --- a/dotnet/private/sdk/gen/RuntimePacks.fs +++ b/dotnet/private/sdk/gen/RuntimePacks.fs @@ -159,10 +159,10 @@ let generateRuntimePacksNugetRepo runtimePacksFile outputFolder = sha512 = packageInfo.sha512sri sources = [ NugetHelpers.nugetV3Feed ] netrc = None - dependencies = Dictionary() + dependencies = Map.empty targeting_pack_overrides = packageInfo.overrides framework_list = packageInfo.frameworkList - tools = Dictionary() }) + tools = Map.empty }) NugetRepo.generateBazelFiles "runtime_packs" repoPackages outputFolder "dotnet." () diff --git a/dotnet/private/sdk/gen/TargetingPacks.fs b/dotnet/private/sdk/gen/TargetingPacks.fs index 9c1688022..3d502e1f9 100644 --- a/dotnet/private/sdk/gen/TargetingPacks.fs +++ b/dotnet/private/sdk/gen/TargetingPacks.fs @@ -138,10 +138,10 @@ let generateTargetingPacksNugetRepo (targetingPacksFile: string) (outputFolder: sha512 = packageInfo.sha512sri sources = [ NugetHelpers.nugetV3Feed ] netrc = None - dependencies = Dictionary() + dependencies = Map.empty targeting_pack_overrides = packageInfo.overrides framework_list = packageInfo.frameworkList - tools = Dictionary() }) + tools = Map.empty }) NugetRepo.generateBazelFiles "targeting_packs" repoPackages outputFolder "dotnet." () diff --git a/dotnet/private/sdk/gen/paket.references b/dotnet/private/sdk/gen/paket.references index f6adfef1d..4f478286f 100644 --- a/dotnet/private/sdk/gen/paket.references +++ b/dotnet/private/sdk/gen/paket.references @@ -4,3 +4,4 @@ group paket2bazel_dependencies Paket.Core NuGet.PackageManagement System.Text.Json + Thoth.Json.System.Text.Json diff --git a/dotnet/private/tests/target_runtime/BUILD.bazel b/dotnet/private/tests/target_runtime/BUILD.bazel new file mode 100644 index 000000000..7cefa086d --- /dev/null +++ b/dotnet/private/tests/target_runtime/BUILD.bazel @@ -0,0 +1,64 @@ +load("//dotnet:toolchain.bzl", "dotnet_toolchain") +load(":target_runtime_test.bzl", "fake_executable", "resolved_target_runtime_test", "target_runtime_test") + +platform( + name = "windows_x64", + constraint_values = [ + "@platforms//os:windows", + "@platforms//cpu:x86_64", + ], +) + +config_setting( + name = "target_windows", + constraint_values = [ + "@platforms//os:windows", + "@platforms//cpu:x86_64", + ], +) + +fake_executable( + name = "runtime_host", +) + +fake_executable( + name = "runtime_windows", +) + +filegroup( + name = "host_model", + srcs = ["host_model.dll"], +) + +dotnet_toolchain( + name = "fake_dotnet_toolchain", + runtime = ":runtime_host", + target_runtime = select({ + ":target_windows": ":runtime_windows", + "//conditions:default": ":runtime_host", + }), + csharp_compiler = ":runtime_host", + fsharp_compiler = ":runtime_host", + host_model = ":host_model", + sdk_version = "0.0.0", + runtime_version = "0.0.0", + runtime_tfm = "net0.0", + csharp_default_version = "0.0", + fsharp_default_version = "0.0", +) + +toolchain( + name = "fake_registered_toolchain", + toolchain = ":fake_dotnet_toolchain", + toolchain_type = "//dotnet:toolchain_type", +) + +target_runtime_test( + name = "target_runtime_uses_target_platform", + toolchain_under_test = ":fake_dotnet_toolchain", +) + +resolved_target_runtime_test( + name = "resolved_target_runtime_uses_target_platform", + tags = ["manual"], +) diff --git a/dotnet/private/tests/target_runtime/host_model.dll b/dotnet/private/tests/target_runtime/host_model.dll new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/dotnet/private/tests/target_runtime/host_model.dll @@ -0,0 +1 @@ + diff --git a/dotnet/private/tests/target_runtime/target_runtime_test.bzl b/dotnet/private/tests/target_runtime/target_runtime_test.bzl new file mode 100644 index 000000000..5c8dd7aef --- /dev/null +++ b/dotnet/private/tests/target_runtime/target_runtime_test.bzl @@ -0,0 +1,72 @@ +def _fake_executable_impl(ctx): + out = ctx.actions.declare_file(ctx.label.name + ".sh") + ctx.actions.write( + output = out, + content = "#!/usr/bin/env bash\nexit 0\n", + is_executable = True, + ) + return [DefaultInfo(executable = out, files = depset([out]))] + +fake_executable = rule( + implementation = _fake_executable_impl, + executable = True, +) + +def _windows_platform_transition_impl(_settings, _attr): + return { + "//command_line_option:platforms": "//dotnet/private/tests/target_runtime:windows_x64", + } + +_windows_platform_transition = transition( + implementation = _windows_platform_transition_impl, + inputs = [], + outputs = ["//command_line_option:platforms"], +) + +def _target_runtime_test_impl(ctx): + toolchain_under_test = ctx.attr.toolchain_under_test + if type(toolchain_under_test) == "list": + toolchain_under_test = toolchain_under_test[0] + toolchain = toolchain_under_test[platform_common.ToolchainInfo] + return _assert_windows_runtime(ctx, toolchain) + +def _resolved_target_runtime_test_impl(ctx): + toolchain = ctx.toolchains["//dotnet:toolchain_type"] + return _assert_windows_runtime(ctx, toolchain) + +def _assert_windows_runtime(ctx, toolchain): + target_runtime_files = [ + file.basename + for file in toolchain.dotnetinfo.target_runtime_files + ] + + if "runtime_windows.sh" not in target_runtime_files: + fail("Expected target runtime files to contain runtime_windows.sh, got: {}".format(target_runtime_files)) + + out = ctx.actions.declare_file(ctx.label.name + ".sh") + ctx.actions.write( + output = out, + content = "#!/usr/bin/env bash\nexit 0\n", + is_executable = True, + ) + return [DefaultInfo(executable = out)] + +target_runtime_test = rule( + implementation = _target_runtime_test_impl, + attrs = { + "toolchain_under_test": attr.label( + cfg = _windows_platform_transition, + providers = [platform_common.ToolchainInfo], + ), + "_allowlist_function_transition": attr.label( + default = "@bazel_tools//tools/allowlists/function_transition_allowlist", + ), + }, + test = True, +) + +resolved_target_runtime_test = rule( + implementation = _resolved_target_runtime_test_impl, + test = True, + toolchains = ["//dotnet:toolchain_type"], +) diff --git a/dotnet/repositories.bzl b/dotnet/repositories.bzl index 572a76ff9..0bf2eb94c 100644 --- a/dotnet/repositories.bzl +++ b/dotnet/repositories.bzl @@ -12,10 +12,33 @@ _DOC = "Fetch external tools needed for dotnet toolchain" _ATTRS = { "dotnet_version": attr.string(mandatory = True, values = TOOL_VERSIONS.keys()), "platform": attr.string(mandatory = True, values = PLATFORMS.keys()), + "user_repository_name": attr.string(), } def _dotnet_repo_impl(repository_ctx): url = TOOL_VERSIONS[repository_ctx.attr.dotnet_version][repository_ctx.attr.platform]["url"] + user_repository_name = repository_ctx.attr.user_repository_name + if user_repository_name == "": + current_repo_suffix = "_" + repository_ctx.attr.platform + if not repository_ctx.name.endswith(current_repo_suffix): + fail("Expected repository name {} to end with {}".format(repository_ctx.name, current_repo_suffix)) + user_repository_name = repository_ctx.name[:-len(current_repo_suffix)] + + platform_config_settings = "" + target_runtime_select_entries = [] + for platform, meta in PLATFORMS.items(): + config_setting_name = "target_" + platform + platform_config_settings += """ +config_setting( + name = "{config_setting_name}", + constraint_values = {compatible_with}, +) +""".format( + config_setting_name = config_setting_name, + compatible_with = meta.compatible_with, + ) + target_runtime_select_entries.append("\":{}\": \"@{}_{}//:runtime\"".format(config_setting_name, user_repository_name, platform)) + repository_ctx.download_and_extract( url = url, integrity = TOOL_VERSIONS[repository_ctx.attr.dotnet_version][repository_ctx.attr.platform]["hash"], @@ -24,6 +47,8 @@ def _dotnet_repo_impl(repository_ctx): load("@rules_dotnet//dotnet:toolchain.bzl", "dotnet_toolchain") load("@rules_dotnet//dotnet:defs.bzl", "import_dll") +{platform_config_settings} + filegroup( name = "csc_binary", srcs = [ @@ -80,6 +105,10 @@ filegroup( dotnet_toolchain( name = "dotnet_toolchain", runtime = ":runtime", + target_runtime = select({{ + {target_runtime_select}, + "//conditions:default": ":runtime", + }}), csharp_compiler = ":csc_binary", fsharp_compiler = ":fsc_binary", host_model = ":host_model", @@ -91,6 +120,8 @@ dotnet_toolchain( visibility = ["//visibility:public"], ) """.format( + platform_config_settings = platform_config_settings, + target_runtime_select = ",\n ".join(target_runtime_select_entries), sdk_version = repository_ctx.attr.dotnet_version, runtime_version = TOOL_VERSIONS[repository_ctx.attr.dotnet_version]["runtimeVersion"], runtime_tfm = TOOL_VERSIONS[repository_ctx.attr.dotnet_version]["runtimeTfm"], @@ -129,6 +160,7 @@ def dotnet_register_toolchains(name, dotnet_version, register = True, **kwargs): name = name + "_" + platform, platform = platform, dotnet_version = dotnet_version, + user_repository_name = name, **kwargs ) if register: diff --git a/dotnet/toolchain.bzl b/dotnet/toolchain.bzl index 45b446e90..6e13be35b 100644 --- a/dotnet/toolchain.bzl +++ b/dotnet/toolchain.bzl @@ -9,6 +9,10 @@ DotnetInfo = provider( "runtime_files": """Files required in runfiles to make the dotnet executable available. May be empty if the runtime_path points to a locally installed tool binary.""", + "target_runtime_path": "Path to the dotnet executable for target binaries", + "target_runtime_files": """Files required in runfiles to make the target dotnet executable available. + +May be empty if target_runtime_path points to a locally installed tool binary.""", "csharp_compiler_path": "Path to the C# compiler executable", "csharp_compiler_files": """Files required in runfiles to make the C# compiler executable available. @@ -41,6 +45,8 @@ def _dotnet_toolchain_impl(ctx): fail("Can only set one of runtime or runtime_path but both were set.") if not ctx.attr.runtime and not ctx.attr.runtime_path: fail("Must set one of runtime or runtime_path.") + if ctx.attr.target_runtime and ctx.attr.target_runtime_path: + fail("Can only set one of target_runtime or target_runtime_path but both were set.") if ctx.attr.csharp_compiler and ctx.attr.csharp_compiler_path: fail("Can only set one of csharp_compiler or csharp_compiler_path but both were set.") @@ -54,6 +60,8 @@ def _dotnet_toolchain_impl(ctx): runtime_files = [] runtime_path = ctx.attr.runtime_path + target_runtime_files = [] + target_runtime_path = ctx.attr.target_runtime_path csharp_compiler_files = [] csharp_compiler_path = ctx.attr.csharp_compiler_path @@ -65,6 +73,13 @@ def _dotnet_toolchain_impl(ctx): runtime_files = ctx.attr.runtime.files.to_list() + ctx.attr.runtime.default_runfiles.files.to_list() runtime_path = _to_manifest_path(ctx, runtime_files[0]) + if ctx.attr.target_runtime: + target_runtime_files = ctx.attr.target_runtime.files.to_list() + ctx.attr.target_runtime.default_runfiles.files.to_list() + target_runtime_path = _to_manifest_path(ctx, target_runtime_files[0]) + else: + target_runtime_files = runtime_files + target_runtime_path = runtime_path + if ctx.attr.csharp_compiler: csharp_compiler_files = ctx.attr.csharp_compiler.files.to_list() + ctx.attr.csharp_compiler.default_runfiles.files.to_list() csharp_compiler_path = _to_manifest_path(ctx, csharp_compiler_files[0]) @@ -92,6 +107,8 @@ def _dotnet_toolchain_impl(ctx): dotnetinfo = DotnetInfo( runtime_path = runtime_path, runtime_files = runtime_files, + target_runtime_path = target_runtime_path, + target_runtime_files = target_runtime_files, csharp_compiler_path = csharp_compiler_path, csharp_compiler_files = csharp_compiler_files, fsharp_compiler_path = fsharp_compiler_path, @@ -110,6 +127,7 @@ def _dotnet_toolchain_impl(ctx): dotnetinfo = dotnetinfo, template_variables = template_variables, runtime = ctx.attr.runtime, + target_runtime = ctx.attr.target_runtime or ctx.attr.runtime, csharp_compiler = ctx.attr.csharp_compiler, fsharp_compiler = ctx.attr.fsharp_compiler, host_model = ctx.attr.host_model, @@ -134,6 +152,16 @@ dotnet_toolchain = rule( doc = "Path to the dotnet CLI. Do not set if `runtime` is set", mandatory = False, ), + "target_runtime": attr.label( + doc = "The dotnet CLI used by target binaries. Defaults to runtime.", + mandatory = False, + executable = True, + cfg = "target", + ), + "target_runtime_path": attr.string( + doc = "Path to the dotnet CLI used by target binaries. Defaults to runtime_path.", + mandatory = False, + ), "csharp_compiler": attr.label( doc = "The C# compiler binary", mandatory = False, From 7b32bc46b19121870c8432cd5b35be3f597d66f7 Mon Sep 17 00:00:00 2001 From: njlr Date: Sun, 7 Jun 2026 17:11:05 +0100 Subject: [PATCH 2/4] Revert --- dotnet/private/sdk/gen/paket.references | 1 - 1 file changed, 1 deletion(-) diff --git a/dotnet/private/sdk/gen/paket.references b/dotnet/private/sdk/gen/paket.references index 4f478286f..f6adfef1d 100644 --- a/dotnet/private/sdk/gen/paket.references +++ b/dotnet/private/sdk/gen/paket.references @@ -4,4 +4,3 @@ group paket2bazel_dependencies Paket.Core NuGet.PackageManagement System.Text.Json - Thoth.Json.System.Text.Json From 971d002eff443000748cea3842f7095c9ea1ba43 Mon Sep 17 00:00:00 2001 From: njlr Date: Sun, 7 Jun 2026 17:13:16 +0100 Subject: [PATCH 3/4] Revert --- dotnet/private/sdk/gen/ApphostPacks.fs | 4 +- dotnet/private/sdk/gen/BUILD.bazel | 1 - dotnet/private/sdk/gen/NugetRepo.fs | 83 ++++++------------------ dotnet/private/sdk/gen/RuntimePacks.fs | 4 +- dotnet/private/sdk/gen/TargetingPacks.fs | 4 +- 5 files changed, 27 insertions(+), 69 deletions(-) diff --git a/dotnet/private/sdk/gen/ApphostPacks.fs b/dotnet/private/sdk/gen/ApphostPacks.fs index 63b1cd2a5..2fac59a00 100644 --- a/dotnet/private/sdk/gen/ApphostPacks.fs +++ b/dotnet/private/sdk/gen/ApphostPacks.fs @@ -132,10 +132,10 @@ let generateApphostPacksNugetRepo apphostPacksFile outputFolder = sha512 = packageInfo.sha512sri sources = [ NugetHelpers.nugetV3Feed ] netrc = None - dependencies = Map.empty + dependencies = Dictionary() targeting_pack_overrides = packageInfo.overrides framework_list = packageInfo.frameworkList - tools = Map.empty }) + tools = Dictionary() }) NugetRepo.generateBazelFiles "apphost_packs" repoPackages outputFolder "dotnet." () diff --git a/dotnet/private/sdk/gen/BUILD.bazel b/dotnet/private/sdk/gen/BUILD.bazel index 76055b561..59310e695 100644 --- a/dotnet/private/sdk/gen/BUILD.bazel +++ b/dotnet/private/sdk/gen/BUILD.bazel @@ -27,6 +27,5 @@ fsharp_binary( "@paket.paket2bazel_dependencies//nuget.versioning", "@paket.paket2bazel_dependencies//paket.core", "@paket.paket2bazel_dependencies//system.text.json", - "@paket.paket2bazel_dependencies//thoth.json.system.text.json", ], ) diff --git a/dotnet/private/sdk/gen/NugetRepo.fs b/dotnet/private/sdk/gen/NugetRepo.fs index ff129dac6..e75c74b8f 100644 --- a/dotnet/private/sdk/gen/NugetRepo.fs +++ b/dotnet/private/sdk/gen/NugetRepo.fs @@ -2,7 +2,10 @@ module NugetRepo open System.Text open System.IO -open Thoth.Json.Core +open System.Collections.Generic +open System.Text.Json +open System.Text.Json.Serialization +open System.Text.Encodings.Web type NugetRepoTool = { name: string @@ -16,70 +19,16 @@ type NugetRepoPackage = sha512: string sources: string seq netrc: string option - dependencies: Map + dependencies: Dictionary targeting_pack_overrides: string seq framework_list: string seq - tools: Map } - -let private encodeStringSeq values = - values - |> Seq.map Encode.string - |> Seq.toList - |> Encode.list - -let private encodeMap encodeValue values = - values - |> Map.toList - |> List.map (fun (key, value) -> key, encodeValue value) - |> Encode.object - -let private encodeTool (tool: NugetRepoTool) = - Encode.object [ - yield "name", Encode.string tool.name - yield "entrypoint", Encode.string tool.entrypoint - yield "runner", Encode.string tool.runner - ] - -let private encodePackage (package: NugetRepoPackage) = - Encode.object [ - yield "name", Encode.string package.name - yield "id", Encode.string package.id - yield "version", Encode.string package.version - yield "sha512", Encode.string package.sha512 - yield "sources", encodeStringSeq package.sources - - match package.netrc with - | Some netrc -> yield "netrc", Encode.string netrc - | None -> () - - yield "dependencies", encodeMap encodeStringSeq package.dependencies - yield "targeting_pack_overrides", encodeStringSeq package.targeting_pack_overrides - yield "framework_list", encodeStringSeq package.framework_list - - yield - "tools", - package.tools - |> encodeMap (fun tools -> - tools - |> Seq.map encodeTool - |> Seq.toList - |> Encode.list) - ] - -let private toGeneratedJson value = - value - |> Encode.toString 0 - // The replacements are so that the Bazel formatter does not have anything to format. - |> fun json -> - json - .Replace("\":\"", "\": \"") - .Replace("\",\"", "\", \"") - .Replace("\":[", "\": [") - .Replace("],", "], ") - .Replace("\":{", "\": {") - .Replace("},", "}, ") + tools: Dictionary } let generateTarget (packages: NugetRepoPackage seq) (repoName: string) (repoPrefix: string) = + let jsonOptions = JsonSerializerOptions() + jsonOptions.DefaultIgnoreCondition <- JsonIgnoreCondition.WhenWritingNull + jsonOptions.Encoder <- JavaScriptEncoder.UnsafeRelaxedJsonEscaping + let i = " " let sb = new StringBuilder() sb.Append($"{i}nuget_repo(\n") |> ignore @@ -91,7 +40,17 @@ let generateTarget (packages: NugetRepoPackage seq) (repoName: string) (repoPref for package in packages do sb.Append($"{i} ") |> ignore - sb.Append(package |> encodePackage |> toGeneratedJson) + sb.Append( + JsonSerializer + .Serialize(package, jsonOptions) + // The replacements are so that the Bazel formatter does not have anything to format + .Replace("\":\"", "\": \"") + .Replace("\",\"", "\", \"") + .Replace("\":[", "\": [") + .Replace("],", "], ") + .Replace("\":{", "\": {") + .Replace("},", "}, ") + ) |> ignore sb.Append(",\n") |> ignore diff --git a/dotnet/private/sdk/gen/RuntimePacks.fs b/dotnet/private/sdk/gen/RuntimePacks.fs index a0cf65f9e..6d9be70bc 100644 --- a/dotnet/private/sdk/gen/RuntimePacks.fs +++ b/dotnet/private/sdk/gen/RuntimePacks.fs @@ -159,10 +159,10 @@ let generateRuntimePacksNugetRepo runtimePacksFile outputFolder = sha512 = packageInfo.sha512sri sources = [ NugetHelpers.nugetV3Feed ] netrc = None - dependencies = Map.empty + dependencies = Dictionary() targeting_pack_overrides = packageInfo.overrides framework_list = packageInfo.frameworkList - tools = Map.empty }) + tools = Dictionary() }) NugetRepo.generateBazelFiles "runtime_packs" repoPackages outputFolder "dotnet." () diff --git a/dotnet/private/sdk/gen/TargetingPacks.fs b/dotnet/private/sdk/gen/TargetingPacks.fs index 3d502e1f9..9c1688022 100644 --- a/dotnet/private/sdk/gen/TargetingPacks.fs +++ b/dotnet/private/sdk/gen/TargetingPacks.fs @@ -138,10 +138,10 @@ let generateTargetingPacksNugetRepo (targetingPacksFile: string) (outputFolder: sha512 = packageInfo.sha512sri sources = [ NugetHelpers.nugetV3Feed ] netrc = None - dependencies = Map.empty + dependencies = Dictionary() targeting_pack_overrides = packageInfo.overrides framework_list = packageInfo.frameworkList - tools = Map.empty }) + tools = Dictionary() }) NugetRepo.generateBazelFiles "targeting_packs" repoPackages outputFolder "dotnet." () From 64d4f12d69b2c8a713df51ca5fc12b31bab99e3a Mon Sep 17 00:00:00 2001 From: njlr Date: Sun, 7 Jun 2026 17:41:18 +0100 Subject: [PATCH 4/4] WiP --- dotnet/private/launcher.bat.tpl | 2 +- dotnet/private/launcher.sh.tpl | 2 +- .../private/tests/use_as_tool/fsharp/BUILD.bazel | 7 +++++++ .../fsharp/relocated_runfiles_test.sh | 16 ++++++++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) create mode 100755 dotnet/private/tests/use_as_tool/fsharp/relocated_runfiles_test.sh diff --git a/dotnet/private/launcher.bat.tpl b/dotnet/private/launcher.bat.tpl index 29f6b1981..77bd33655 100644 --- a/dotnet/private/launcher.bat.tpl +++ b/dotnet/private/launcher.bat.tpl @@ -62,4 +62,4 @@ if defined args ( set args=!args:\=\\\\! set args=!args:"=\"! ) -"!dotnet_executable!" exec "!run_script!" !args! +"!dotnet_executable!" exec --additionalprobingpath "%RUNFILES_DIR%" "!run_script!" !args! diff --git a/dotnet/private/launcher.sh.tpl b/dotnet/private/launcher.sh.tpl index 710318c5b..fc3cf4265 100644 --- a/dotnet/private/launcher.sh.tpl +++ b/dotnet/private/launcher.sh.tpl @@ -32,4 +32,4 @@ export DOTNET_NOLOGO="1" export DOTNET_CLI_TELEMETRY_OPTOUT="1" export DOTNET_ROOT="$(dirname $(rlocation TEMPLATED_dotnet))" -exec $(rlocation TEMPLATED_dotnet) exec $(rlocation TEMPLATED_executable) "$@" +exec $(rlocation TEMPLATED_dotnet) exec --additionalprobingpath "${RUNFILES_DIR}" $(rlocation TEMPLATED_executable) "$@" diff --git a/dotnet/private/tests/use_as_tool/fsharp/BUILD.bazel b/dotnet/private/tests/use_as_tool/fsharp/BUILD.bazel index 5eaa45abb..05ff39b37 100644 --- a/dotnet/private/tests/use_as_tool/fsharp/BUILD.bazel +++ b/dotnet/private/tests/use_as_tool/fsharp/BUILD.bazel @@ -54,6 +54,13 @@ assert_contains( expected = "Hello World!", ) +sh_test( + name = "relocated_runfiles_test", + srcs = ["relocated_runfiles_test.sh"], + args = ["$(rootpath :main)"], + data = [":main"], +) + # Also test that self contained binaries are also usable as tools in custom rules publish_binary( name = "publish_self_contained", diff --git a/dotnet/private/tests/use_as_tool/fsharp/relocated_runfiles_test.sh b/dotnet/private/tests/use_as_tool/fsharp/relocated_runfiles_test.sh new file mode 100755 index 000000000..31bca0128 --- /dev/null +++ b/dotnet/private/tests/use_as_tool/fsharp/relocated_runfiles_test.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail + +launcher="$(find "$TEST_SRCDIR" -path "*/$1" -print -quit)" +if [[ -z "$launcher" ]]; then + echo "Could not find launcher matching $1 under $TEST_SRCDIR" >&2 + exit 1 +fi +tmp="${TEST_TMPDIR}/relocated" +mkdir -p "$tmp" + +cp "$launcher" "$tmp/app" +cp -R "$TEST_SRCDIR" "$tmp/app.runfiles" + +"$tmp/app" "$tmp/output" +grep -F "Hello World!" "$tmp/output"