unable to `publish_binary` with cross-compiled, runtime-specific, and self-contained
I'm unable to create a cross-compiled, runtime-specific, and self-contained application with publish_binary: while publish_binary produces the right runtime packs for the cross platform/architecture, the executable that it produces is wrong: it's always the one for the host platform/architecture.
I'll illustrate the problem with macos/arm64 as the host platform/architecture and Windows/x64 as the cross one — I also tried other variations but they lead to a similar issue.
Consider the rules below for a trivial .NET application.
csharp_binary(
name = "sample",
srcs = ["Program.cs"],
private_deps = ["@paket.main//microsoft.netcore.app.ref"],
target_frameworks = ["net7.0"],
deps = [],
)
publish_binary(
name = "publish-sample",
binary = ":sample",
runtime_identifier = select({
"@rules_dotnet//dotnet/private:macos-arm64": "osx-arm64",
"@rules_dotnet//dotnet/private:windows-x64": "win-x64",
"@rules_dotnet//dotnet/private:linux-x64": "linux-x64",
}),
runtime_packs = select({
"@rules_dotnet//dotnet:rid_osx-arm64": ["@paket.main//microsoft.netcore.app.runtime.osx-arm64"],
"@rules_dotnet//dotnet:rid_win-x64": ["@paket.main//microsoft.netcore.app.runtime.win-x64"],
"@rules_dotnet//dotnet:rid_linux-x64": ["@paket.main//microsoft.netcore.app.runtime.linux-x64"],
}),
self_contained = True,
target_framework = "net7.0",
)
To cross-compile sample for Windows/x64 from macos/arm64, I switched the bazel toolchain, like this.
bazel build //sample:sample -platforms=@io_bazel_rules_go//go/toolchain:windows_amd64
But that didn't work as rules_dotnet attempted to run the compiler wrapper .bat script. Then, I added specific bazel configuration to switch only the runtime identifier of the compilation/build.
string_flag(
name = "cross_build",
build_setting_default = "",
)
config_setting(
name = "cross_build_linux-x64",
flag_values = {":cross_build": "linux_amd64"},
)
config_setting(
name = "cross_build_osx-arm64",
flag_values = {":cross_build": "macos_arm64"},
)
config_setting(
name = "cross_build_win-x64",
flag_values = {":cross_build": "windows_amd64"},
)
publish_binary(
name = "publish-sample",
binary = ":sample",
runtime_identifier = select({
"cross_build_osx-arm64": "osx-arm64",
"cross_build_win-x64": "win-x64",
"cross_build_linux-x64": "linux-x64",
"@rules_dotnet//dotnet/private:macos-arm64": "osx-arm64",
"@rules_dotnet//dotnet/private:windows-x64": "win-x64",
"@rules_dotnet//dotnet/private:linux-x64": "linux-x64",
}),
runtime_packs = select({
"@rules_dotnet//dotnet:rid_osx-arm64": ["@paket.main//microsoft.netcore.app.runtime.osx-arm64"],
"@rules_dotnet//dotnet:rid_win-x64": ["@paket.main//microsoft.netcore.app.runtime.win-x64"],
"@rules_dotnet//dotnet:rid_linux-x64": ["@paket.main//microsoft.netcore.app.runtime.linux-x64"],
}),
self_contained = True,
target_framework = "net7.0",
)
Now, to cross-compile sample for Windows/x64 from macos/arm64, I used the cross build flag.
bazel build //sample:sample --//src/dotnet:cross_build=windows_amd64
This time, the build "worked", as rules_dotnet ran the compiler wrapper .sh script. The runtime packs look right too... for instance, I see Windows-specific artifacts/libraries in the output — just as I see .so and .dylib files in the output for linux and macos too. Yet, I noticed that the application's executable was named sample (as it's the case for a macos and linux build) instead of sample.exe. I thought that this was just a naming issue, but indeed the executable didn't work; and when I check it with objdump -f sample, this is what I see.
sample: file format mach-o arm64
What I expected instead is this (regardless whether the file name is sample or sample.exe).
sample.exe: file format coff-x86-64
architecture: x86_64
Which is what I would get by an equivalent cross-compilation of a runtime-specific self-contained application with .NET's native toolchain with dotnet publish --self-contained -r win-x64.
Is this a bug with rules_dotnet or am I doing something wrong?
I think this is the same issue as https://github.com/bazelbuild/rules_dotnet/issues/320
Yes, this is the same issue as #320. I want to fix this soonish but I have been too busy to look into it. The issue is that we are using the apphost that comes from the host SDK instead of downloading the different NuGet packages depending on what our target is.
This should now be working in the latest release.
Thank you @purkhusid !