1
Go to file
laurynasl 4d65b80903 Add libc constraint and libc aware toolchains
- Also get rid of @bazel_skylib dependency
2022-04-14 14:29:06 +00:00
bin Restructure tests to all run in bazel 2022-04-14 10:47:02 +00:00
ci Add libc constraint and libc aware toolchains 2022-04-14 14:29:06 +00:00
contrib [docs] how to test your own zig version 2022-02-05 17:27:38 +02:00
rules Add libc constraint and libc aware toolchains 2022-04-14 14:29:06 +00:00
test Add libc constraint and libc aware toolchains 2022-04-14 14:29:06 +00:00
toolchain Add libc constraint and libc aware toolchains 2022-04-14 14:29:06 +00:00
.bazelrc Add libc constraint and libc aware toolchains 2022-04-14 14:29:06 +00:00
.bazelversion Upgrade to Bazel 5.1.0 2022-03-26 15:56:11 +02:00
.build.yml Add libc constraint and libc aware toolchains 2022-04-14 14:29:06 +00:00
.envrc Restructure tests to all run in bazel 2022-04-14 10:47:02 +00:00
.gitignore Restructure tests to all run in bazel 2022-04-14 10:47:02 +00:00
BUILD Restructure tests to all run in bazel 2022-04-14 10:47:02 +00:00
go.mod Restructure tests to all run in bazel 2022-04-14 10:47:02 +00:00
go.sum remove sqlite from dependencies 2022-01-28 15:50:33 +02:00
LICENSE add license 2021-06-11 06:16:23 +03:00
README.md Add libc constraint and libc aware toolchains 2022-04-14 14:29:06 +00:00
release avoid including a phony commit to relnotes 2022-04-09 00:20:55 +03:00
relnotes.awk add release note updater 2021-10-18 15:46:05 +03:00
repositories.bzl rename/fix the package 2022-01-28 15:57:22 +02:00
WORKSPACE Add libc constraint and libc aware toolchains 2022-04-14 14:29:06 +00:00

builds.sr.ht status

Bazel zig cc toolchain

This is a C/C++ toolchain that can (cross-)compile C/C++ programs. It contains clang-13, musl, glibc (versions 2-2.34, selectable), all in a ~40MB package. Read here about zig-cc; the rest of the README will present how to use this toolchain from Bazel.

Usage

Add this to your WORKSPACE:

BAZEL_ZIG_CC_VERSION = "v0.6.1"

http_archive(
    name = "bazel-zig-cc",
    sha256 = "6969858b7f142a0629c61aea4338fca1c81f4e137892464a96bfe9a42ed74821",
    strip_prefix = "bazel-zig-cc-{}".format(BAZEL_ZIG_CC_VERSION),
    urls = ["https://git.sr.ht/~motiejus/bazel-zig-cc/archive/{}.tar.gz".format(BAZEL_ZIG_CC_VERSION)],
)

load("@bazel-zig-cc//toolchain:defs.bzl", zig_toolchains = "toolchains")

zig_toolchains()

zig sdk download control

If you are using this in production, you probably want more control over where the zig sdk is downloaded from:

zig_register_toolchains(
    version = "<...>",
    url_formats = [
        "https://example.internal/zig/zig-{host_platform}-{version}.tar.xz",
    ],
    host_platform_sha256 = { ... },
)

And this to .bazelrc:

build --incompatible_enable_cc_toolchain_resolution

The snippets above will download the zig toolchain and make the bazel toolchains available for registration and usage.

The next steps depend on your use case.

I want to manually build a single target with a specific zig cc toolchain

You may explicitly request Bazel to use a specific toolchain (compatible with the specified platform). For example, if you wish to compile a specific binary (or run tests) on linux/amd64/musl, you may specify:

bazel build \
    --platforms @zig_sdk//platform:linux_arm64 \
    --extra_toolchains @zig_sdk//toolchain:linux_arm64_musl \
    //test/go:go

This registers the toolchain @zig_sdk//toolchain:linux_arm64_musl for linux arm64 targets. This toolchains links code statically with musl. We also specify that we want to build //test/go:go for linux arm64.

I want to use zig cc as the default compiler

Replace the call to zig_register_toolchains with

register_toolchains(
    "@zig_sdk//toolchain:linux_amd64_gnu.2.19",
    "@zig_sdk//toolchain:linux_arm64_gnu.2.28",
    "@zig_sdk//toolchain:darwin_amd64",
    "@zig_sdk//toolchain:darwin_arm64",
)

The snippets above will download the zig toolchain and register it for the following configurations:

  • toolchain:linux_amd64_gnu.2.19 for ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:unconstrained"].
  • toolchain:linux_arm64_gnu.2.28 for ["@platforms//os:linux", "@platforms//cpu:aarch64", "@zig_sdk//libc:unconstrained"].
  • toolchain:darwin_arm64 for ["@platforms//os:macos", "@platforms//cpu:x86_64"].
  • toolchain:darwin_arm64 for ["@platforms//os:macos", "@platforms//cpu:aarch64"].

Naming

Both Go and Bazel naming schemes are accepted. For convenience with Go, the following Go-style toolchain aliases are created:

Bazel (zig) name Go name
x86_64 amd64
aarch64 arm64
macos darwin

For example, the toolchain linux_amd64_gnu.2.28 is aliased to x86_64-linux-gnu.2.28. To find out which toolchains can be registered or used, run:

$ bazel query @zig_sdk//toolchain/...

Disabling the default bazel cc toolchain

It may be useful to disable the default toolchain that bazel configures for you, so that configuration issues can be caught early on:

.bazelrc

build:zig_cc --action_env BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1

This is not documented in bazel, so use at your own peril.

I want to start using the zig cc toolchain gradually

You can register your zig cc toolchains under a config in your .bazelrc

build:zig_cc --extra_toolchains @zig_sdk//toolchain:linux_amd64_gnu.2.19
build:zig_cc --extra_toolchains @zig_sdk//toolchain:linux_arm64_gnu.2.28
build:zig_cc --extra_toolchains @zig_sdk//toolchain:darwin_amd64
build:zig_cc --extra_toolchains @zig_sdk//toolchain:darwin_arm64

Then for your builds/tests you need to specify that the zig_cc config should be used:

bazel build --config zig_cc //test/go:go

You can build a target for a different platform like so:

bazel build --config zig_cc \
    --platforms @zig_sdk//platform:linux_arm64 \
    //test/go:go

I want to use zig to build targets for multiple libc variants

If you have targets that need to be build with different glibc versions or with musl, you can register a linux toolchain declared under libc_aware/toolchains. It will only be selected when building for a specific libc version. For example

  • libc_aware/toolchain:linux_amd64_gnu.2.19 for ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:gnu.2.19"].
  • libc_aware/toolchain:linux_amd64_gnu.2.28 for ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:gnu.2.28"].
  • libc_aware/toolchain:x86_64-linux-musl for ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:musl"].

With these toolchains registered, you can build a project for a specific libc aware platform:

$ bazel build --platforms @zig_sdk//libc_aware/platform:linux_amd64_gnu.2.19 //test/go:go
$ bazel build --platforms @zig_sdk//libc_aware/platform:linux_amd64_gnu.2.28 //test/go:go
$ bazel build --platforms @zig_sdk//libc_aware/platform:linux_amd64_musl //test/go:go

You can see the list of libc aware toolchains and platforms by running:

$ bazel query @zig_sdk//libc_aware/toolchain/...
$ bazel query @zig_sdk//libc_aware/platform/...

This is especially useful if you are relying on transitions, as transitioning extra_platforms will cause your host tools to be rebuilt with the specific libc version, which takes time, and your host may not be able to run them.

The @zig_sdk//libc:variant constraint is used to select a matching toolchain. If you are using your own platform definitions, add a @zig_sdk//libc:variant constraint to them. See the list of available values:

$ bazel query "attr(constraint_setting, @zig_sdk//libc:variant, @zig_sdk//...)"

@zig_sdk//libc:unconstrained is a special value that indicates that no value for the constraint is specified. The non libc aware linux toolchains are only compatible with this value to prevent accidental silent fallthrough to them.

UBSAN and "SIGILL: Illegal Instruction"

zig cc differs from "mainstream" compilers by enabling UBSAN by default. Which means your program may compile successfully and crash with:

SIGILL: illegal instruction

This is by design: it encourages program authors to fix the undefined behavior. There are many ways to find the undefined behavior.

Known Issues In bazel-zig-cc

These are the things you may stumble into when using bazel-zig-cc. I am unlikely to implement them any time soon, but patches implementing those will be accepted. See Questions & Contributions on how to contribute.

Zig cache

Currently zig cache is in $HOME, so bazel clean --expunge does not clear the zig cache. Zig's cache should be stored somewhere in the project's path.

OSX: sysroot

For non-trivial programs (and for all darwin/arm64 cgo programs) MacOS SDK may be necessary. Read Jakub's comment about it. Support for OSX sysroot is currently not implemented.

OSX: different OS targets (Catalina -- Monterey)

Zig 0.9.0 may target macos.10 (Catalina), macos.11 (Big Sur) or macos.12 (Monterey). It currently targets the lowest version, without ability to change it.

Known Issues In Upstream

This section lists issues that I've stumbled into when using zig cc, and is outside of bazel-zig-cc's control.

using glibc 2.27 or older

Severity: Low

Task: ziglang/zig #9485 glibc 2.27 or older: fcntl64 not found, but zig's glibc headers refer it

Background: when glibc 2.27 or older is selected, it may miss fcntl64. A workaround is applied for x86_64, but not for aarch64. The same workaround may apply to aarch64, but the author didn't find a need to test it (yet).

Closed Upstream Issues

Testing

Transient docker environment

First of all, make sure that your kernel is configured to run arm64 binaries. You can either apt install qemu-user-static binfmt-support; this should setup binfmt_misc to handle arm64 binaries. Or you can use this handy dockerized script docker run --rm --privileged multiarch/qemu-user-static --reset -p yes.

$ docker run -e CC=/usr/bin/false -ti --rm -v $(git rev-parse --show-toplevel):/x -w /x debian:bullseye-slim
# dpkg --add-architecture arm64 && apt update && apt install -y direnv git shellcheck libc6:arm64
# . .envrc
# ./ci/test
# ./ci/lint

See ci/test for how tests are run.

Questions & Contributions

Project's mailing list is ~motiejus/bazel-zig-cc. The mailing list is used for:

  • announcements (I am aiming to send an email with every release).
  • user discussions.
  • raising issues.
  • contributions.

I will generally respond to emails about issues. I may even be able to fix them. However, no promises: you are much more likely (and welcome!) to get it fixed by submitting a patch.

To contribute, send your patches to the mailing list, as described in git-send-email.io or via Sourcehut web UI.

Copyright is retained by the contributors.

Thanks

Many thanks to Adam Bouhenguel and his bazel-zig-cc, the parent of this repository. Also, the Zig team for making this all possible and handling the issues promptly.