Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document setting up a cross-compiling toolchain with cgo #1642

Open
jayconrod opened this issue Aug 9, 2018 · 6 comments
Open

Document setting up a cross-compiling toolchain with cgo #1642

jayconrod opened this issue Aug 9, 2018 · 6 comments

Comments

@jayconrod
Copy link
Contributor

Setting up C/C++ cross-compiling toolchains in Bazel is non-trivial. We should document how to do this in a way that works with cgo.

@prestonvanloon
Copy link
Contributor

prestonvanloon commented Oct 2, 2018

+1

Specifically looking for Linux to Mac|Windows cross-compilation for projects with cgo.

@prestonvanloon
Copy link
Contributor

@jayconrod is there any support for this documentation in the near future?
I've reached a dead end trying to get cgo to produce non-empty archives for cgo libraries when cross compiling for windows.

@jayconrod
Copy link
Contributor Author

@prestonvanloon Does #1956 solve your problem with non-empty archives? It should be released soon.

About setting up cross-compilation, I wrote Configuring a custom C toolchain some time ago. It doesn't get into cross-compilation specifically, but maybe it will be helpful.

@prestonvanloon
Copy link
Contributor

Not quite. We have this target here https://github.com/prysmaticlabs/bazel-go-ethereum/blob/master/crypto/secp256k1/BUILD.bazel#L4-L50 which happily produces an empty .a file when cross-compiling to windows. (That is, when you set --platforms=@io_bazel_rules_go//go/toolchain:windows_amd64 from a linux system)

Generated file looks something like this:

!<arch>
__.PKGDEF       0           0     0     644     80        `
go object windows amd64 go1.11.5 X:framepointer
----


$$B
i^@^G^@^@^Eempty^A^@^A^@^@^@
$$
_go_.o          0           0     0     644     82        `
go object windows amd64 go1.11.5 X:framepointer
----


!
^@^@go19ld^A^@ÿ^@^@^@^@^@^@ÿÿgo19ld

@excavador
Copy link

Any updates?

@rcorre
Copy link

rcorre commented Dec 17, 2020

I've managed to to cross compile from 64-bit linux to 32-bit Windows. I may have overcomplicated, but it seems to work.

I borrowed a lot from https://docs.bazel.build/versions/3.3.0/tutorial/cc-toolchain-config.html.

The following is tested with;

  1. First, define your cross-compiling toolchain in toolchain/cc_toolchain_config.bzl:
load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
load(
   "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
   "feature",
   "flag_group",
   "flag_set",
   "tool_path",
)

def _impl_32(ctx):
    # TODO: make hermetic
    tool_paths = [
        tool_path(
            name = "gcc",
            path = "/usr/bin/i686-w64-mingw32-gcc",
        ),
        tool_path(
            name = "ld",
            path = "/usr/bin/i686-w64-mingw32-ld",
        ),
        tool_path(
            name = "ar",
            path = "/usr/bin/i686-w64-mingw32-ar",
        ),
        tool_path(
            name = "cpp",
            path = "/usr/bin/i686-w64-mingw32-g++",
        ),
        tool_path(
            name = "gcov",
            path = "/bin/false",
        ),
        tool_path(
            name = "nm",
            path = "/bin/false",
        ),
        tool_path(
            name = "objdump",
            path = "/bin/false",
        ),
        tool_path(
            name = "strip",
            path = "/bin/false",
        ),
    ]
    features = [
        feature(
            name = "default_linker_flags",
            enabled = True,
            flag_sets = [
                flag_set(
                    actions = [
                        ACTION_NAMES.cpp_link_executable,
                        ACTION_NAMES.cpp_link_dynamic_library,
                        ACTION_NAMES.cpp_link_nodeps_dynamic_library,
                    ],
                    flag_groups = ([
                        flag_group(
                            flags = [
                                "-lstdc++",
                            ],
                        ),
                    ]),
                ),
            ],
        ),
    ]
    return cc_common.create_cc_toolchain_config_info(
        ctx = ctx,
        cxx_builtin_include_directories = [
            "/usr/i686-w64-mingw32/include",
            "/usr/lib/gcc/i686-w64-mingw32"
        ],
        features = features,
        toolchain_identifier = "local",
        host_system_name = "local",
        target_system_name = "windows",
        target_cpu = "@platforms//cpu:x86_32",
        target_libc = "unknown",
        compiler = "mingw",
        abi_version = "unknown",
        abi_libc_version = "unknown",
        tool_paths = tool_paths,
    )

cc_toolchain_config_32 = rule(
    implementation = _impl_32,
    attrs = {},
    provides = [CcToolchainConfigInfo],
)
  1. Add a BUILD file for your toolchain at toolchain/BUILD.bazel
package(default_visibility = ["//visibility:public"])

cc_toolchain_suite(
    name = "mingw_suite",
    toolchains = {
        "x86_32": ":mingw_toolchain_32",
        "x86_32|mingw": ":mingw_toolchain_32",
    },
)

filegroup(name = "empty")

cc_toolchain(
    name = "mingw_toolchain_32",
    all_files = ":empty",
    compiler_files = ":empty",
    dwp_files = ":empty",
    linker_files = ":empty",
    objcopy_files = ":empty",
    strip_files = ":empty",
    supports_param_files = 0,
    toolchain_config = ":mingw_toolchain_config_32",
    toolchain_identifier = "mingw-toolchain-32",
)

load(
    ":cc_toolchain_config.bzl",
    "cc_toolchain_config_32",
)

cc_toolchain_config_32(name = "mingw_toolchain_config_32")

toolchain(
    name = "cc-toolchain-mingw",
    exec_compatible_with = [
        "@platforms//cpu:x86_64",
        "@platforms//os:linux",
    ],
    target_compatible_with = [
        "@platforms//cpu:x86_32",
        "@platforms//os:windows",
    ],
    toolchain = ":mingw_toolchain_32",
    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
)
  1. Define a platform in your main BUILD.bazel that will select this toolchain:
platform(
    name = "windows_386_cgo",
    constraint_values = [
        ":mingw",
    ],
    parents = ["@io_bazel_rules_go//go/toolchain:windows_386_cgo"],
)
  1. Register your toolchain in WORKSPACE:
register_toolchains(
    "//toolchain:cc-toolchain-mingw",
)
  1. Create a build config in .bazelrc
build:go_win32 --host_crosstool_top=@bazel_tools//tools/cpp:toolchain
build:go_win32 --host_platform=@local_config_platform//:host
build:go_win32 --crosstool_top=//toolchain:mingw_suite
build:go_win32 --cpu=x86_32
build:go_win32 --compiler=mingw
build:go_win32 --platforms=:windows_386_cgo
  1. Build
bazel build ${target} --config=go_win32

That's it! You should be able to run this on a 64-bit linux machine (with the 32-bit mingw toolchain installed) and produce a Go binary for 32-bit Windows.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants