rules_dotnet icon indicating copy to clipboard operation
rules_dotnet copied to clipboard

unable to `publish_binary` with cross-compiled, runtime-specific, and self-contained

Open ltcmelo opened this issue 2 years ago • 2 comments

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?

ltcmelo avatar Jul 11 '23 21:07 ltcmelo

I think this is the same issue as https://github.com/bazelbuild/rules_dotnet/issues/320

njlr avatar Jul 11 '23 21:07 njlr

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.

purkhusid avatar Jul 12 '23 12:07 purkhusid

This should now be working in the latest release.

purkhusid avatar Apr 04 '24 10:04 purkhusid

Thank you @purkhusid !

ltcmelo avatar Apr 04 '24 13:04 ltcmelo