forked from google/skia
-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[infra] Add hermetic toolchain for C/C++ using Clang+Musl
This can successfully build a C library: bazel build --config=clang //third_party:libpng This can build and run a statically-linked executable: bazel test --config=clang //:bazel_test For more verbose compile and linking output, add the `--features diagnostic` flag to a Bazel command (see _make_diagnostic_flags() in toolchain/clang_toolchain_config.bzl. Similarly, a `--features print_search_dirs` can be used to show where clang is looking for libraries etc to link against. These features are made available for easier debugging. Suggested review order: - Read https://docs.bazel.build/versions/4.2.1/tutorial/cc-toolchain-config.html if unfamiliar with setting up C++ toolchains in Bazel - .bazelrc and WORKSPACE.bazel that configure use and download of the toolchain (Clang 13, musl 1.2.2) - toolchain/build_toolchain.bzl which downloads and assembles the toolchain (w/o installing anything on the host machine) - toolchain/BUILD.bazel and toolchain/*trampoline.sh to see the setup of the toolchain rules. - toolchain/clang_toolchain_config.bzl to see the configuration of the toolchain. Pay special attention to the various command line flags that are set. - See that tools/bazel_test.cc has made a new home in experimental/bazel_test/bazel_test.cpp, with a companion BUILD.bazel. Note the addition of some function calls that test use of the C++ standard library. The number being used to test the PNG library is the latest and greatest that verifies we are compiling the one brought in via DEPS (and not a local one). - third_party/* to see how png (and its dependent zlib) have been built. Pay special attention to the musl_compat hack to fix static linking (any idea what the real cause is?) - //BUILD.bazel to see definition of the bazel_test executable. Change-Id: I7b0922d0d45cb9be8df2fd5fa5a1f48492654d5f Bug: skia:12541 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/461178 Reviewed-by: Ben Wagner <[email protected]> Reviewed-by: Leandro Lovisolo <[email protected]>
- Loading branch information
Showing
15 changed files
with
640 additions
and
20 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
build:clang --crosstool_top=//toolchain:clang_suite | ||
build:clang --compiler=clang | ||
|
||
# Use the default Bazel C++ toolchain to build the tools used during the | ||
# build. | ||
build:clang --host_crosstool_top=@bazel_tools//tools/cpp:toolchain |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,11 @@ | ||
cc_test( | ||
name = "bazel_test", | ||
size = "small", | ||
srcs = [ | ||
"tools/bazel_test.cc", | ||
"//experimental/bazel_test:srcs", | ||
], | ||
deps = [ | ||
"//third_party:libpng", | ||
"//third_party:musl_compat", | ||
], | ||
deps = ["@libpng//:libpng"], | ||
size = "small", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,15 @@ | ||
load("@bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository") | ||
workspace(name = "skia") | ||
|
||
new_git_repository( | ||
name = "libpng", | ||
remote = "https://skia.googlesource.com/third_party/libpng", | ||
#tag = "v1.6.37", | ||
commit = "a40189cf881e9f0db80511c382292a5604c3c3d1", | ||
shallow_since = "1555265432 -0400", | ||
build_file = "//bazel:libpng.bazel", | ||
load("//toolchain:build_toolchain.bzl", "build_cpp_toolchain") | ||
|
||
build_cpp_toolchain( | ||
# Meant to run on amd64 linux and compile for amd64 linux using musl as the c library. | ||
name = "clang_linux_amd64_musl", | ||
# From https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.0/clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-20.04.tar.xz.sha256 | ||
clang_prefix = "clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-20.04/", | ||
clang_sha256 = "2c2fb857af97f41a5032e9ecadf7f78d3eff389a5cd3c9ec620d24f134ceb3c8", | ||
clang_url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.0/clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-20.04.tar.xz", | ||
# From https://packages.debian.org/bullseye/amd64/musl-dev/download | ||
musl_dev_sha256 = "b017792ad6ba3650b4889238c73cd19c1d6b0e39ca8319cdd3ad9e16374e614e", | ||
musl_dev_url = "http://ftp.debian.org/debian/pool/main/m/musl/musl-dev_1.2.2-1_amd64.deb", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package(default_visibility = ["//:__subpackages__"]) | ||
|
||
filegroup( | ||
name = "srcs", | ||
srcs = [ | ||
"bazel_test.cpp", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// Copyright 2020 Google LLC. | ||
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. | ||
#include <png.h> | ||
#include <ctime> | ||
#include <iostream> | ||
|
||
void print_localtime() { | ||
std::time_t result = std::time(nullptr); | ||
std::cout << std::asctime(std::localtime(&result)); | ||
} | ||
|
||
int main(int argc, char** argv) { | ||
printf("Hello world\n"); | ||
print_localtime(); | ||
// https://docs.bazel.build/versions/main/test-encyclopedia.html#role-of-the-test-runner | ||
if (png_access_version_number() == 10638) { | ||
printf("PASS\n"); // This tells the human the test passed. | ||
return 0; // This tells Bazel the test passed. | ||
} | ||
printf("FAIL\n"); // This tells the human the test failed. | ||
return 1; // This tells Bazel the test failed. | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
load("@rules_cc//cc:defs.bzl", "cc_library") | ||
|
||
package(default_visibility = ["//:__subpackages__"]) | ||
|
||
cc_library( | ||
name = "libpng", | ||
srcs = [ | ||
"externals/libpng/png.c", | ||
"externals/libpng/pngerror.c", | ||
"externals/libpng/pngget.c", | ||
"externals/libpng/pngmem.c", | ||
"externals/libpng/pngpread.c", | ||
"externals/libpng/pngread.c", | ||
"externals/libpng/pngrio.c", | ||
"externals/libpng/pngrtran.c", | ||
"externals/libpng/pngrutil.c", | ||
"externals/libpng/pngset.c", | ||
"externals/libpng/pngtrans.c", | ||
"externals/libpng/pngwio.c", | ||
"externals/libpng/pngwrite.c", | ||
"externals/libpng/pngwtran.c", | ||
"externals/libpng/pngwutil.c", | ||
# TODO(kjlubick) arm/x86 support | ||
], | ||
hdrs = ["libpng/pnglibconf.h"] + glob([ | ||
"externals/libpng/*.h", | ||
]), | ||
copts = [ | ||
"-Ithird_party/libpng/", | ||
"-Wno-unused-but-set-variable", | ||
], | ||
includes = [ | ||
# This adds -isystem "third_party/externals/libpng" to any dependent | ||
# compilation steps. This allows #include <png.h> to work | ||
"externals/libpng", | ||
# png.h attempts to #include "pnglibconf.h" , which we store in //third_party/libpng/ | ||
# This rule adds -isystem "third_party/externals/libpng" to any dependent | ||
# rule on this, which avoids having to add "-Ithird_party/libpng/" to copts for | ||
# those dependent rules. | ||
"libpng", | ||
], | ||
textual_hdrs = ["externals/libpng/scripts/pnglibconf.h.prebuilt"], | ||
deps = [":zlib"], | ||
) | ||
|
||
cc_library( | ||
name = "zlib", | ||
srcs = [ | ||
"externals/zlib/adler32.c", | ||
"externals/zlib/compress.c", | ||
"externals/zlib/cpu_features.c", | ||
"externals/zlib/crc32.c", | ||
"externals/zlib/deflate.c", | ||
"externals/zlib/gzclose.c", | ||
"externals/zlib/gzlib.c", | ||
"externals/zlib/gzread.c", | ||
"externals/zlib/gzwrite.c", | ||
"externals/zlib/infback.c", | ||
"externals/zlib/inffast.c", | ||
"externals/zlib/inflate.c", | ||
"externals/zlib/inftrees.c", | ||
"externals/zlib/trees.c", | ||
"externals/zlib/uncompr.c", | ||
"externals/zlib/zutil.c", | ||
] + glob([ | ||
"externals/zlib/**/*.h", | ||
]), | ||
hdrs = glob([ | ||
"externals/zlib/*.h", | ||
]), | ||
copts = [ | ||
"-Wno-unused-function", | ||
], | ||
strip_include_prefix = "externals/zlib/", | ||
) | ||
|
||
# This library is used to fix linking errors when trying to statically link in some symbols | ||
# The symbols defined here: | ||
# https://github.com/llvm/llvm-project/blob/main/libcxx/include/__support/musl/xlocale.h | ||
# are defined to be inlined, however they are missing during the final linking of a static | ||
# executable. By re-defining them in our own .a file, this makes the linker happy. | ||
cc_library( | ||
name = "musl_compat", | ||
srcs = [ | ||
"musl_compat/locale.c", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/* | ||
* Copyright 2021 Google LLC | ||
* | ||
* Use of this source code is governed by a BSD-style license that can be | ||
* found in the LICENSE file. | ||
* | ||
* Fixes linking issues with musl due to missing locale-specific string functions. | ||
*/ | ||
|
||
#include <stdlib.h> | ||
|
||
long long strtoll_l(const char *nptr, char **endptr, int base, | ||
int locale_t) { | ||
return strtoll(nptr, endptr, base); | ||
} | ||
|
||
long long strtoull_l(const char *nptr, char **endptr, int base, | ||
int locale_t) { | ||
return strtoull(nptr, endptr, base); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
load("@rules_cc//cc:defs.bzl", "cc_toolchain", "cc_toolchain_suite") | ||
load(":clang_toolchain_config.bzl", "provide_clang_toolchain_config") | ||
|
||
package(default_visibility = ["//visibility:public"]) | ||
|
||
cc_toolchain_suite( | ||
name = "clang_suite", | ||
toolchains = { | ||
"k8|clang": ":clang_toolchain", | ||
}, | ||
) | ||
|
||
filegroup(name = "not_implemented") | ||
|
||
filegroup( | ||
name = "all-toolchain-files", | ||
srcs = [ | ||
"ar_trampoline.sh", | ||
"clang_trampoline.sh", | ||
"lld_trampoline.sh", | ||
"@clang_linux_amd64_musl//:all_files", | ||
], | ||
) | ||
|
||
provide_clang_toolchain_config( | ||
name = "clang_toolchain_config", | ||
) | ||
|
||
cc_toolchain( | ||
name = "clang_toolchain", | ||
all_files = ":all-toolchain-files", | ||
ar_files = ":all-toolchain-files", | ||
compiler_files = ":all-toolchain-files", | ||
dwp_files = ":not_implemented", | ||
linker_files = ":all-toolchain-files", | ||
objcopy_files = ":not_implemented", | ||
strip_files = ":not_implemented", | ||
supports_param_files = 0, | ||
toolchain_config = ":clang_toolchain_config", | ||
toolchain_identifier = "clang-toolchain", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#!/bin/bash | ||
# Copyright 2021 Google LLC | ||
# | ||
# Use of this source code is governed by a BSD-style license that can be | ||
# found in the LICENSE file. | ||
|
||
external/clang_linux_amd64_musl/bin/llvm-ar $@ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
""" | ||
This file assembles a toolchain for Linux using the Clang Compiler and musl. | ||
It currently makes use of musl and not glibc because the pre-compiled libraries from the latter | ||
have absolute paths baked in and this makes linking difficult. The pre-compiled musl library | ||
does not have this restriction and is much easier to statically link in as a result. | ||
As inputs, it takes external URLs from which to download the clang binaries/libraries/includes | ||
as well as the musl headers and pre-compiled binaries. Those files are downloaded and put | ||
into one folder, with a little bit of re-arrangement so clang can find files (like the C runtime). | ||
""" | ||
|
||
def _download_and_extract_deb(ctx, deb, sha256, prefix, output = ""): | ||
"""Downloads a debian file and extracts the data into the provided output directory""" | ||
|
||
# https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#download | ||
download_info = ctx.download( | ||
url = deb, | ||
output = "deb.ar", | ||
sha256 = sha256, | ||
) | ||
|
||
# https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#execute | ||
# This uses the extracted llvm-ar that comes with clang. | ||
ctx.execute(["bin/llvm-ar", "x", "deb.ar"]) | ||
|
||
# https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#extract | ||
extract_info = ctx.extract( | ||
archive = "data.tar.xz", | ||
output = output, | ||
stripPrefix = prefix, | ||
) | ||
|
||
# Clean up | ||
ctx.delete("deb.ar") | ||
ctx.delete("data.tar.xz") | ||
ctx.delete("control.tar.xz") | ||
|
||
def _build_cpp_toolchain_impl(ctx): | ||
# Download the clang toolchain (the extraction can take a while) | ||
# https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#download | ||
download_info = ctx.download_and_extract( | ||
url = ctx.attr.clang_url, | ||
output = "", | ||
stripPrefix = ctx.attr.clang_prefix, | ||
sha256 = ctx.attr.clang_sha256, | ||
) | ||
|
||
# This puts the musl include files in ${PWD}/usr/include/x86_64-linux-musl | ||
# and the runtime files and lib.a files in ${PWD}/usr/lib/x86_64-linux-musl | ||
_download_and_extract_deb( | ||
ctx, | ||
ctx.attr.musl_dev_url, | ||
ctx.attr.musl_dev_sha256, | ||
".", | ||
) | ||
|
||
# kjlubick@ cannot figure out how to get clang to look in ${PWD}/usr/lib/x86_64-linux-musl | ||
# for the crt1.o files, so we'll move them to ${PWD}/usr/lib/ where clang *is* looking. | ||
for file in ["crt1.o", "crtn.o", "Scrt1.o", "crti.o", "rcrt1.o"]: | ||
ctx.execute(["cp", "usr/lib/x86_64-linux-musl/" + file, "usr/lib/"]) | ||
|
||
# Create a BUILD.bazel file that makes all the files in this subfolder | ||
# available for use in rules, i.e. in the toolchain declaration. | ||
# https://docs.bazel.build/versions/main/skylark/lib/repository_ctx.html#file | ||
ctx.file( | ||
"BUILD.bazel", | ||
content = """ | ||
filegroup( | ||
name = "all_files", | ||
srcs = glob([ | ||
"**", | ||
]), | ||
visibility = ["//visibility:public"] | ||
) | ||
""", | ||
executable = False, | ||
) | ||
|
||
build_cpp_toolchain = repository_rule( | ||
implementation = _build_cpp_toolchain_impl, | ||
attrs = { | ||
"clang_url": attr.string(mandatory = True), | ||
"clang_sha256": attr.string(mandatory = True), | ||
"clang_prefix": attr.string(mandatory = True), | ||
"musl_dev_url": attr.string(mandatory = True), | ||
"musl_dev_sha256": attr.string(mandatory = True), | ||
}, | ||
doc = "", | ||
) |
Oops, something went wrong.