diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f152113 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +**/.DS_Store +**/*.pyc +bazel-* \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..59e5a2d --- /dev/null +++ b/.travis.yml @@ -0,0 +1,34 @@ +matrix: + include: + - os: linux + dist: trusty + sudo: required + language: java + - os: osx + osx_image: xcode8.3 + language: java + +env: + global: + - BAZEL_VERSION=0.5.2 + +before_install: + - echo $TRAVIS_OS_NAME; + - unset CC + - unset CXX + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get autoremove openjdk-9-jre-headless openjdk-9-jdk oracle-java9-installer; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get purge openjdk-9-jre-headless openjdk-9-jdk oracle-java9-installer; fi + - mkdir -p ${HOME}/bazel/install + - pushd ${HOME}/bazel/install + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wget --no-clobber https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/bazel_${BAZEL_VERSION}-linux-x86_64.deb; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo dpkg -i bazel_${BAZEL_VERSION}-linux-x86_64.deb; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install bazel; fi + - popd + +script: + - bazel test --crosstool_top=//tools/cpp:default-toolchain //src/... + +notifications: + email: false + slack: false diff --git a/README.md b/README.md index 1ed5e34..b253022 100644 --- a/README.md +++ b/README.md @@ -1 +1,15 @@ -# bazel-toolchains \ No newline at end of file +# Bazel Toolchains + +A collection of [Bazel](https://bazel.build) C++ build infrastructure based on [Chromium](https://chromium.org)'s [LLVM](https://llvm.org) toolchain. There are tags corresponding to stable Chromium releases. The build targets currently supported are Linux x64 and macOS. As in Chromium, the Linux toolchain has a sysroot, bundled copies of binutils, and a copy of libc++. The macOS build is less hermetic, and relies on system binutils and libraries. + +## Prerequisites + +On macOS, run `xcode-select --install` in Terminal. + +## Running the Python scripts + +The files in the `scripts/` directory are written in Python. Follow these [instructions](http://docs.python-guide.org/en/latest/starting/installation/) to install a version of Python that comes with the necessary tools for installation of third party libraries. On macOS, this means `brew install python`, and then following the instructions printed by `brew info python`. + +Once that's working, type `pip install requests` to install the necessary dependencies. + +From the root of this repository, type `python scripts/generate_workspace.py --rev="61.0.3153.4"` where --rev is the Chromium tag you wish to pull from. The script will print status messages to `stderr` and write a file similar to toolchains/repositories.bzl to `stdout`. \ No newline at end of file diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 0000000..6ee086d --- /dev/null +++ b/WORKSPACE @@ -0,0 +1,13 @@ +# Chromium toolchain corresponding to Chromium 61.0.3153.4 + +load("//toolchains:repositories.bzl", "bazel_toolchains_repositories") +bazel_toolchains_repositories() + +# GTest +new_http_archive( + name = "gtest", + url = "https://github.com/google/googletest/archive/release-1.8.0.zip", + sha256 = "f3ed3b58511efd272eb074a3a6d6fb79d7c2e6a0e374323d1e6bcbcc1ef141bf", + build_file = "build_files/gtest.BUILD", + strip_prefix = "googletest-release-1.8.0/googletest", +) diff --git a/build_files/BUILD b/build_files/BUILD new file mode 100644 index 0000000..1f3f527 --- /dev/null +++ b/build_files/BUILD @@ -0,0 +1,5 @@ +filegroup( + name = "build_files", + srcs = glob(["*.BUILD"]), + visibility = ["//visibility:public"], +) diff --git a/build_files/gtest.BUILD b/build_files/gtest.BUILD new file mode 100644 index 0000000..ae1e24c --- /dev/null +++ b/build_files/gtest.BUILD @@ -0,0 +1,17 @@ +cc_library( + name = "main", + srcs = glob( + ["src/*.cc"], + exclude = ["src/gtest-all.cc"] + ), + hdrs = glob([ + "include/**/*.h", + "src/*.h" + ]), + copts = [ + '-Iexternal/gtest/include', + '-Wno-unused-const-variable', + ], + linkopts = ["-v"], + visibility = ["//visibility:public"], +) diff --git a/build_files/org_chromium_binutils_linux_x64.BUILD b/build_files/org_chromium_binutils_linux_x64.BUILD new file mode 100644 index 0000000..0b539e8 --- /dev/null +++ b/build_files/org_chromium_binutils_linux_x64.BUILD @@ -0,0 +1,95 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "ar", + srcs = [ + "bin/ar", + ], +) + +filegroup( + name = "as", + srcs = [ + "bin/as", + ], +) + +filegroup( + name = "ld", + srcs = [ + "bin/ld", + ], +) + +filegroup( + name = "ld.bfd", + srcs = [ + "bin/ld.bfd", + ], +) + +filegroup( + name = "ld.gold", + srcs = [ + "bin/ld.gold", + ], +) + +filegroup( + name = "nm", + srcs = [ + "bin/nm", + ], +) + +filegroup( + name = "objcopy", + srcs = [ + "bin/objcopy", + ], +) + +filegroup( + name = "objdump", + srcs = [ + "bin/objdump", + ], +) + +filegroup( + name = "ranlib", + srcs = [ + "bin/ranlib", + ], +) + +filegroup( + name = "readelf", + srcs = [ + "bin/readelf", + ], +) + +filegroup( + name = "strip", + srcs = [ + "bin/strip", + ], +) + +filegroup( + name = "binutils_components", + srcs = [ + ":ar", + ":as", + ":ld", + ":ld.bfd", + ":ld.gold", + ":nm", + ":objcopy", + ":objdump", + ":ranlib", + ":readelf", + ":strip", + ], +) diff --git a/build_files/org_chromium_clang_linux_x64.BUILD b/build_files/org_chromium_clang_linux_x64.BUILD new file mode 100644 index 0000000..3811c53 --- /dev/null +++ b/build_files/org_chromium_clang_linux_x64.BUILD @@ -0,0 +1,21 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "clang", + srcs = [ + "bin/clang", + ], +) + +filegroup( + name = "lib", + srcs = glob(["lib/**"]), +) + +filegroup( + name = "compiler_components", + srcs = [ + ":clang", + ":lib", + ], +) diff --git a/build_files/org_chromium_clang_mac.BUILD b/build_files/org_chromium_clang_mac.BUILD new file mode 100644 index 0000000..81cc14e --- /dev/null +++ b/build_files/org_chromium_clang_mac.BUILD @@ -0,0 +1,27 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "clang", + srcs = [ + "bin/clang", + ], +) + +filegroup( + name = "include", + srcs = glob(["include/**"]), +) + +filegroup( + name = "lib", + srcs = glob(["lib/**"]), +) + +filegroup( + name = "compiler_components", + srcs = [ + ":clang", + ":include", + ":lib", + ], +) diff --git a/build_files/org_chromium_libcxx.BUILD b/build_files/org_chromium_libcxx.BUILD new file mode 100644 index 0000000..dba8664 --- /dev/null +++ b/build_files/org_chromium_libcxx.BUILD @@ -0,0 +1,88 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "libcxx_includes", + srcs = glob(["include/**/*"]) +) + +cc_library( + name = "cxxlib", + copts = [ + "-fPIC", + "-fstrict-aliasing", + "-nostdinc++", + "-std=c++11", + ], + hdrs = glob(["src/support/runtime/*.ipp"]), + includes = ["include"], + defines = [ + "_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS", + "_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", + "_LIBCPP_BUILDING_LIBRARY", + "LIBCXX_BUILDING_LIBCXXABI" + + # This resets the visibility to default only for the various + # flavors of operator new and operator delete. These symbols + # are weak and get overriden by Chromium-provided ones, but if + # these symbols had hidden visibility, this would make the + # Chromium symbols hidden too because elf visibility rules + # require that linkers use the least visible form when merging, + # and if this is hidden, then when we merge it with tcmalloc's + # operator new, hidden visibility would win. However, tcmalloc + # needs a visible operator new to also override operator new + # references from system libraries. + # TODO(lld): Ask lld for a --force-public-visibility flag or + # similar to that overrides the default elf merging rules, and + # make tcmalloc's gn config pass that to all its dependencies, + # then remove this override here. + #"_LIBCPP_OVERRIDABLE_FUNC_VIS=__attribute__((__visibility__(\"\"default\"\"")))", + ], + srcs = [ + "src/algorithm.cpp", + "src/any.cpp", + "src/bind.cpp", + "src/chrono.cpp", + "src/condition_variable.cpp", + "src/debug.cpp", + "src/exception.cpp", + "src/functional.cpp", + "src/future.cpp", + "src/hash.cpp", + "src/ios.cpp", + "src/iostream.cpp", + "src/locale.cpp", + "src/memory.cpp", + "src/mutex.cpp", + "src/new.cpp", + "src/optional.cpp", + "src/random.cpp", + "src/regex.cpp", + "src/shared_mutex.cpp", + "src/stdexcept.cpp", + "src/string.cpp", + "src/strstream.cpp", + "src/system_error.cpp", + "src/thread.cpp", + "src/typeinfo.cpp", + "src/utility.cpp", + "src/valarray.cpp", + "src/variant.cpp", + "src/include/atomic_support.h", + "src/include/config_elast.h", + ], + deps = [ + "@org_chromium_libcxxabi//:include", + ] +) + +cc_library( + name = "cxx", + hdrs = [ + "libcxx_includes", + "@org_chromium_libcxxabi//:include", + ], + deps = [ + "@org_chromium_libcxxabi//:cxxabi", + ":cxxlib" + ], +) \ No newline at end of file diff --git a/build_files/org_chromium_libcxxabi.BUILD b/build_files/org_chromium_libcxxabi.BUILD new file mode 100644 index 0000000..26bfa22 --- /dev/null +++ b/build_files/org_chromium_libcxxabi.BUILD @@ -0,0 +1,71 @@ +package(default_visibility = ["//visibility:public"]) + +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# +# Based on the BUILD.gn version in the Chromium tree. + +config_setting( + name = "is_mac", + values = {"cpu": "darwin"}, +) + +config_setting ( + name = "is_arm", + values = {"cpu": "armeabi-v7a"} +) + +filegroup( + name = "libcxxabi_includes", + srcs = glob(["include/**/*"]) +) + +cc_inc_library( + name = "include", + hdrs = [":libcxxabi_includes"] +) + +cc_library( + name = "cxxabi", + includes = ["include"], + defines = [ + "LIBCXX_BUILDING_LIBCXXABI", + ], + srcs = [ + "src/abort_message.h", + "src/abort_message.cpp", + "src/cxa_aux_runtime.cpp", + "src/cxa_default_handlers.cpp", + "src/cxa_demangle.cpp", + "src/cxa_exception.hpp", + "src/cxa_exception.cpp", + "src/cxa_exception_storage.cpp", + "src/cxa_guard.cpp", + "src/cxa_handlers.hpp", + "src/cxa_handlers.cpp", + + # This file is supposed to be used in fno-exception builds of + # libc++abi. We build lib++/libc++abi with exceptions enabled. + #"src/cxa_noexception.cpp", + + "src/cxa_personality.cpp", + "src/cxa_unexpected.cpp", + "src/cxa_vector.cpp", + "src/cxa_virtual.cpp", + "src/fallback_malloc.h", + "src/fallback_malloc.cpp", + "src/private_typeinfo.h", + "src/private_typeinfo.cpp", + "src/stdlib_exception.cpp", + "src/stdlib_stdexcept.cpp", + "src/stdlib_typeinfo.cpp", + ] + select({ + ":is_mac": [], + "//conditions:default": [ "src/cxa_thread_atexit.cpp" ], + }), + deps = select({ + ":is_arm": [ "@org_chromium_libunwind//:libunwind" ], + "//conditions:default": [], + }) +) diff --git a/build_files/org_chromium_libunwind.BUILD b/build_files/org_chromium_libunwind.BUILD new file mode 100644 index 0000000..085e4a2 --- /dev/null +++ b/build_files/org_chromium_libunwind.BUILD @@ -0,0 +1,27 @@ +package(default_visibility = ['//visibility:public']) + +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# +# Based on the BUILD.gn version in the Chromium tree. + +cc_library( + name = "unwind", + defines = [ + "_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", + ], + copts = [ + # ValueAsBitPattern in Unwind-EHABI.cpp is only used on Debug builds. + "-Wno-unused-function", + ], + srcs = [ + "trunk/src/Unwind-EHABI.cpp", + "trunk/src/libunwind.cpp", + "trunk/src/Unwind-sjlj.c", + "trunk/src/UnwindLevel1-gcc-ext.c", + "trunk/src/UnwindLevel1.c", + "trunk/src/UnwindRegistersRestore.S", + "trunk/src/UnwindRegistersSave.S", + ], +) diff --git a/build_files/org_chromium_sysroot_linux_x64.BUILD b/build_files/org_chromium_sysroot_linux_x64.BUILD new file mode 100644 index 0000000..c3ab670 --- /dev/null +++ b/build_files/org_chromium_sysroot_linux_x64.BUILD @@ -0,0 +1,6 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "sysroot", + srcs = glob(["*/**"]), +) diff --git a/scripts/chromium_repo.py b/scripts/chromium_repo.py new file mode 100644 index 0000000..d8b364f --- /dev/null +++ b/scripts/chromium_repo.py @@ -0,0 +1,123 @@ +import base64 +import hashlib +import functools +import json +import requests +import sys +import tempfile + +# Given a revision of Chromium like "61.0.3153.4", these files are needed: +# +# Clang version download: +# https://chromium.googlesource.com/chromium/src/+/61.0.3153.4/tools/clang/scripts/update.py +# Then, use the Clang version to produce a download url used to calculate a sha256. +# +# Sysroot version download: +# https://chromium.googlesource.com/chromium/src/+/61.0.3153.4/build/linux/sysroot_scripts/sysroots.json +# Then, use the sysroot version found in the JSON to produce a download url used to calculate a sha256. +# +# libcxx download. +# Buildtools revision: +# https://chromium.googlesource.com/chromium/src/+/61.0.3153.4/DEPS +# Then, use the buildtools revision to download something like this: +# https://chromium.googlesource.com/chromium/buildtools/+/5ad14542a6a74dd914f067b948c5d3e8d170396b/DEPS +# Then, return the revisions for libcxx etc. found in that file. +# +# Binutils version download: +# https://chromium.googlesource.com/chromium/src/+/61.0.3153.4/third_party/binutils/Linux_x64/binutils.tar.bz2.sha1 + +SRC_REPO = "https://chromium.googlesource.com/chromium/src/+" +TOOLS_REPO = "https://chromium.googlesource.com/chromium/buildtools/+" +DATA_STORE = "https://commondatastorage.googleapis.com" + +def download(url, stream=False): + print >> sys.stderr, "Downloading %s" % url + response = requests.get(url, stream=stream) + if response.status_code != 200: + raise Exception("Unexpected status code %d" % response.status_code) + return response + +def base64_dl(url): + # Appending '?format=TEXT' downloads a base64 version of the raw file, instead of the HTML view. + return base64.b64decode(download(url + "?format=TEXT").text) + +def progressbar_download(url, f): + with open(f, "wb") as f: + response = download(url, stream=True) + total_length = response.headers.get('content-length') + if total_length is None: # no content length header + f.write(response.content) + else: + dl = 0 + total_length = int(total_length) + for data in response.iter_content(chunk_size=4096): + dl += len(data) + f.write(data) + done = int(50 * dl / total_length) + sys.stderr.write("\r[%s%s]" % ('=' * done, ' ' * (50-done)) ) + sys.stderr.flush() + sys.stderr.write("\n") + +def download_clang_rev(revision): + clang_script = base64_dl("%s/%s/tools/clang/scripts/update.py" % (SRC_REPO, revision)) + exec(clang_script) + return "%s-%s" % (CLANG_REVISION, CLANG_SUB_REVISION) + +def calc_sha256(url): + with tempfile.NamedTemporaryFile() as f: + progressbar_download(url, f.name) + digest = hashlib.sha256() + [digest.update(chunk) for chunk in iter(functools.partial(f.read, 65336), '')] + return digest.hexdigest() + +def clang_url(platform, clang_rev): + return ("%(data_store)s/chromium-browser-clang/%(platform)s/clang-%(rev)s.tgz" % + {"platform": platform, "data_store": DATA_STORE, "rev": clang_rev}) + +def download_clang_info(revision): + clang_rev = download_clang_rev(revision) + return [{ + "platform": p, + "url": clang_url(p, clang_rev), + "sha256": calc_sha256(clang_url(p, clang_rev)) + } for p in ["Mac", "Linux_x64"]] + +def sysroot_url(sysroot): + return ("%s/chrome-linux-sysroot/toolchain/%s/%s" % (DATA_STORE, sysroot["Revision"], sysroot["Tarball"])).encode('ascii', 'ignore') + +# Only need a sysroot for amd64 at the moment +def download_sysroot_info(revision): + sysroot_json = base64_dl("%s/%s/build/linux/sysroot_scripts/sysroots.json" % (SRC_REPO, revision)) + sysroots = json.loads(sysroot_json) + amd64 = sysroots["jessie_amd64"] + amd64["platform"] = "Linux_x64" + return [{ + "platform": p["platform"], + "url": sysroot_url(p), + "sha256": calc_sha256(sysroot_url(p)) + } for p in [amd64]] + +def binutils_url(sha): + return "%s/chromium-binutils/%s" % (DATA_STORE, sha) + +def download_binutils_info(revision): + binutils_platforms = [ + (p, base64_dl("%s/%s/third_party/binutils/%s/binutils.tar.bz2.sha1" % (SRC_REPO, revision, p))) + for p in ["Linux_x64"]] + return [{ + "type": "tar.bz2", + "platform": bp[0], + "url": binutils_url(bp[1]), + "sha256": calc_sha256(binutils_url(bp[1])), + } for bp in binutils_platforms] + +def download_toolchain_info(revision): + # DEPS files call a function named "Var" that doesn't have to be correct + # for this purpose, but must return a string. This shim works. + def Var(s): + return s + deps = base64_dl("%s/%s/DEPS" % (SRC_REPO, revision)) + exec(deps) + tool_deps = base64_dl("%s/%s/DEPS" % (TOOLS_REPO, vars['buildtools_revision'])) + exec(tool_deps) + return [{'name': name, 'rev': vars[name + "_revision"]} for name in ["libcxx", "libcxxabi", "libunwind"]] diff --git a/scripts/generate_workspace.py b/scripts/generate_workspace.py new file mode 100755 index 0000000..1300414 --- /dev/null +++ b/scripts/generate_workspace.py @@ -0,0 +1,76 @@ +# Prints a Bazel WORKSPACE file to stdout. +# Download status updates are printed to stderr. + +import argparse +import chromium_repo +import os + +class Repository: + def __init__(self, name, repo_type, **kwargs): + self.name = name + self.repo_type = repo_type + self.args = dict((k,v) for k, v in kwargs.iteritems() if v is not None) + + def print_invocation(self): + print " " + self.name + "()" + + def print_def(self): + print """ +def %(name)s(): + native.%(repo_type)s( + name = '%(name)s', + build_file = str(Label('//build_files:%(name)s.BUILD')),""" % {'name': self.name, 'repo_type': self.repo_type} + + for key, value in self.args.iteritems(): + print \ +" %(key)s = %(value)s," % {'key': key, 'value': value} + print \ +" )" + +def get_archive_type(repo): + archive_type = repo.get('type', None) + if archive_type is None: + return None + + return "'" + archive_type + "'" + +def get_http_archives(revision, prefix, fetch_func): + return [Repository( + name = prefix + repo['platform'].lower(), + repo_type = 'new_http_archive', + urls = [repo['url']], + sha256 = "'" + repo['sha256'] + "'", + type = get_archive_type(repo), + ) for repo in fetch_func(revision)] + +def get_git_repositories(revision, fetch_func): + return [Repository( + name = 'org_chromium_' + repo['name'], + repo_type = 'new_git_repository', + remote = "'" + 'https://chromium.googlesource.com/chromium/llvm-project/' + repo['name'] + "'", + commit = "'" + repo['rev'] + "'" + ) for repo in fetch_func(revision)] + +def print_workspace(revision): + repos = (get_http_archives(revision, 'org_chromium_clang_', chromium_repo.download_clang_info) + + get_http_archives(revision, 'org_chromium_sysroot_', chromium_repo.download_sysroot_info) + + get_http_archives(revision, 'org_chromium_binutils_', chromium_repo.download_binutils_info) + + get_git_repositories(revision, chromium_repo.download_toolchain_info)) + + base_dir = os.path.dirname(os.path.abspath(__file__)) + with open(os.path.join(base_dir, 'license_block.txt')) as f: + print f.read() + print '# Defines external repositories needed by bazel-toolchains.' + print '# Chromium toolchain corresponds to Chromium %s.\n' % revision + print 'def bazel_toolchains_repositories():' + for repo in repos: + repo.print_invocation() + for repo in repos: + repo.print_def() + print '' + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("-r", "--rev", action="store", required=True) + args = parser.parse_args() + print_workspace(args.rev) \ No newline at end of file diff --git a/scripts/license_block.txt b/scripts/license_block.txt new file mode 100644 index 0000000..7175f97 --- /dev/null +++ b/scripts/license_block.txt @@ -0,0 +1,14 @@ +# Copyright 2016 Google Inc. +# Copyright 2017 VSCO. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/src/BUILD b/src/BUILD new file mode 100644 index 0000000..fa866bc --- /dev/null +++ b/src/BUILD @@ -0,0 +1,18 @@ +config_setting( + name = 'darwin_mode', + values = {'cpu': 'darwin'}, +) + +cc_test( + name = 'test', + srcs = glob(['*_test.cpp']), + copts = ['-Iexternal/gtest/include'], + deps = [ + '@gtest//:main', + ] + select({ + ':darwin_mode': [], + '//conditions:default': [ + '@org_chromium_libcxx//:cxx', + ], + }), +) \ No newline at end of file diff --git a/src/allocation_test.cpp b/src/allocation_test.cpp new file mode 100644 index 0000000..91d59b7 --- /dev/null +++ b/src/allocation_test.cpp @@ -0,0 +1,13 @@ +#include "gtest/gtest.h" +#include <string> + +namespace vsco { + +TEST(Allocation, NewDelete) { + std::string *foo = new std::string("abcd"); + foo->pop_back(); + EXPECT_STREQ("abc", foo->c_str()); + delete foo; +} + +} diff --git a/src/string_test.cpp b/src/string_test.cpp new file mode 100644 index 0000000..d7d4b27 --- /dev/null +++ b/src/string_test.cpp @@ -0,0 +1,12 @@ +#include "gtest/gtest.h" +#include <string> + +namespace vsco { + +TEST(String, PopBack) { + std::string foo = "abcd"; + foo.pop_back(); + EXPECT_EQ("abc", foo); +} + +} diff --git a/src/version_test.cpp b/src/version_test.cpp new file mode 100644 index 0000000..26a38dd --- /dev/null +++ b/src/version_test.cpp @@ -0,0 +1,14 @@ +#include "gtest/gtest.h" + +namespace vsco { + +TEST(CompilerMeta, AppleBuild) { +#if defined(__apple_build_version__) + // __apple_build_version__ shouldn't be defined in the Chromium toolchain + ASSERT_TRUE(false); +#else + ASSERT_GE(__clang_major__, 5); +#endif +} + +} diff --git a/toolchains/BUILD b/toolchains/BUILD new file mode 100644 index 0000000..eb847c9 --- /dev/null +++ b/toolchains/BUILD @@ -0,0 +1,5 @@ +filegroup( + name = "repositories", + srcs = ["repositories.bzl"], + visibility = ["//visibility:public"], +) \ No newline at end of file diff --git a/toolchains/repositories.bzl b/toolchains/repositories.bzl new file mode 100644 index 0000000..1383c67 --- /dev/null +++ b/toolchains/repositories.bzl @@ -0,0 +1,84 @@ +# Copyright 2016 Google Inc. +# Copyright 2017 VSCO. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Defines external repositories needed by bazel-toolchains. +# Chromium toolchain corresponds to Chromium 61.0.3153.4. + +def bazel_toolchains_repositories(): + org_chromium_clang_mac() + org_chromium_clang_linux_x64() + org_chromium_sysroot_linux_x64() + org_chromium_binutils_linux_x64() + org_chromium_libcxx() + org_chromium_libcxxabi() + org_chromium_libunwind() + +def org_chromium_clang_mac(): + native.new_http_archive( + name = 'org_chromium_clang_mac', + build_file = str(Label('//build_files:org_chromium_clang_mac.BUILD')), + sha256 = '9195a37d06c52a208415d14efd31fc807e100258478c69465239df1e30e59761', + urls = ['https://commondatastorage.googleapis.com/chromium-browser-clang/Mac/clang-305735-3.tgz'], + ) + +def org_chromium_clang_linux_x64(): + native.new_http_archive( + name = 'org_chromium_clang_linux_x64', + build_file = str(Label('//build_files:org_chromium_clang_linux_x64.BUILD')), + sha256 = '9088f855c587d236e924b3c0e1942f45d8eb30630c355970d6ca3f32611ed96f', + urls = ['https://commondatastorage.googleapis.com/chromium-browser-clang/Linux_x64/clang-305735-3.tgz'], + ) + +def org_chromium_sysroot_linux_x64(): + native.new_http_archive( + name = 'org_chromium_sysroot_linux_x64', + build_file = str(Label('//build_files:org_chromium_sysroot_linux_x64.BUILD')), + sha256 = 'ad9bf71fad4e37e1cae53709bcd95c96c4bb9114f1e1551d60947df3846551aa', + urls = ['https://commondatastorage.googleapis.com/chrome-linux-sysroot/toolchain/ebb50a1c59e577567470b00582f81ed14222353e/debian_jessie_amd64_sysroot.tgz'], + ) + +def org_chromium_binutils_linux_x64(): + native.new_http_archive( + name = 'org_chromium_binutils_linux_x64', + build_file = str(Label('//build_files:org_chromium_binutils_linux_x64.BUILD')), + sha256 = '24c3df44af5bd377c701ee31b9b704f2ea23456f20e63652c8235a10d7cf1be7', + type = 'tar.bz2', + urls = ['https://commondatastorage.googleapis.com/chromium-binutils/0cb5726d9701f8be6a81b199899de1de552922f2'], + ) + +def org_chromium_libcxx(): + native.new_git_repository( + name = 'org_chromium_libcxx', + build_file = str(Label('//build_files:org_chromium_libcxx.BUILD')), + commit = '3a07dd740be63878167a0ea19fe81869954badd7', + remote = 'https://chromium.googlesource.com/chromium/llvm-project/libcxx', + ) + +def org_chromium_libcxxabi(): + native.new_git_repository( + name = 'org_chromium_libcxxabi', + build_file = str(Label('//build_files:org_chromium_libcxxabi.BUILD')), + commit = '4072e8fd76febee37f60aeda76d6d9f5e3791daa', + remote = 'https://chromium.googlesource.com/chromium/llvm-project/libcxxabi', + ) + +def org_chromium_libunwind(): + native.new_git_repository( + name = 'org_chromium_libunwind', + build_file = str(Label('//build_files:org_chromium_libunwind.BUILD')), + commit = '41f982e5887185b904a456e20dfcd58e6be6cc19', + remote = 'https://chromium.googlesource.com/chromium/llvm-project/libunwind', + ) + diff --git a/tools/cpp/BUILD b/tools/cpp/BUILD new file mode 100644 index 0000000..6e73236 --- /dev/null +++ b/tools/cpp/BUILD @@ -0,0 +1,97 @@ +cc_toolchain_suite( + name = "default-toolchain", + toolchains = { + "darwin|compiler": "cc_toolchain_apple", + "k8|clang": "cc_toolchain_linux", + }, + visibility = ["//visibility:public"], +) + +cc_toolchain( + name = "cc_toolchain_linux", + all_files = ":linux_toolchain_deps", + compiler_files = ":linux_toolchain_deps", + cpu = "k8", + dwp_files = ":linux_toolchain_deps", + dynamic_runtime_libs = [":empty"], + linker_files = ":linux_toolchain_deps", + objcopy_files = ":linux_toolchain_deps", + static_runtime_libs = [":empty"], + strip_files = ":linux_toolchain_deps", + supports_param_files = 0, + visibility = ["//visibility:public"], +) + +cc_toolchain( + name = "cc_toolchain_apple", + all_files = ":apple_toolchain_deps", + compiler_files = ":apple_toolchain_deps", + cpu = "darwin", + dwp_files = ":apple_toolchain_deps", + dynamic_runtime_libs = [":empty"], + linker_files = ":apple_toolchain_deps", + objcopy_files = ":apple_toolchain_deps", + static_runtime_libs = [":empty"], + strip_files = ":apple_toolchain_deps", + supports_param_files = 0, + visibility = ["//visibility:public"], +) + +filegroup( + name = "empty", + srcs = [], + visibility = ["//visibility:private"], +) + +filegroup( + name = "apple_toolchain_deps", + srcs = [ + "//tools/cpp/tool_wrappers/mac:clang", + "@org_chromium_clang_mac//:compiler_components", + ], + visibility = ["//visibility:private"], +) + +filegroup( + name = "linux_toolchain_deps", + srcs = [ + "//tools/cpp/tool_wrappers/linux_x64:tool-wrappers", + "@org_chromium_binutils_linux_x64//:binutils_components", + "@org_chromium_clang_linux_x64//:compiler_components", + "@org_chromium_sysroot_linux_x64//:sysroot", + "@org_chromium_libcxx//:libcxx_includes", + "@org_chromium_libcxxabi//:libcxxabi_includes", + ], + visibility = ["//visibility:private"], +) + +config_setting( + name = "debug", + values = {"compilation_mode": "dbg"}, +) + +config_setting( + name = "linux", + values = {"cpu": "k8"}, +) + +config_setting( + name = "apple", + values = {"cpu": "darwin"}, +) + +config_setting( + name = "clang-linux", + values = { + "compiler": "clang", + "cpu": "k8", + }, +) + +config_setting( + name = "apple_debug", + values = { + "compilation_mode": "dbg", + "cpu": "darwin", + }, +) diff --git a/tools/cpp/CROSSTOOL b/tools/cpp/CROSSTOOL new file mode 100644 index 0000000..78a496b --- /dev/null +++ b/tools/cpp/CROSSTOOL @@ -0,0 +1,253 @@ +major_version: "local" +minor_version: "" +default_target_cpu: "same_as_host" + +default_toolchain { + cpu: "darwin" + toolchain_identifier: "osx" +} + +# We use Clang on Ubuntu. +default_toolchain { + cpu: "k8" + toolchain_identifier: "clang-chromium-linux" +} + +# Chromium's Clang on Linux +toolchain { + toolchain_identifier: "clang-chromium-linux" + abi_libc_version: "local" + abi_version: "local" + builtin_sysroot: "" + compiler: "clang" + + # Include paths + compiler_flag: "--sysroot=external/org_chromium_sysroot_linux_x64" + compiler_flag: "-nostdinc++" + compiler_flag: "-isystem" + compiler_flag: "external/org_chromium_libcxxabi/include" + compiler_flag: "-isystem" + compiler_flag: "external/org_chromium_libcxx/include" + compiler_flag: "-isystem" + compiler_flag: "external/org_chromium_clang_linux_x64/lib/clang/5.0.0/include" + compiler_flag: "-isystem" + compiler_flag: "external/org_chromium_sysroot_linux_x64/usr/include/x86_64-linux-gnu" + compiler_flag: "-isystem" + compiler_flag: "external/org_chromium_sysroot_linux_x64/usr/include" + + cxx_builtin_include_directory: "%package(@org_chromium_clang_linux_x64//lib/clang/5.0.0/include)%" + cxx_builtin_include_directory: "%package(@org_chromium_sysroot_linux_x64//usr/include/x86_64-linux-gnu)%" + cxx_builtin_include_directory: "%package(@org_chromium_sysroot_linux_x64//usr/include)%" + + cxx_flag: "-std=c++1y" + host_system_name: "local" + linker_flag: "-latomic" + linker_flag: "-lm" + linker_flag: "-lpthread" + linker_flag: "--sysroot=external/org_chromium_sysroot_linux_x64" + + needsPic: true + objcopy_embed_flag: "-I" + objcopy_embed_flag: "binary" + supports_fission: false + supports_gold_linker: false + supports_incremental_linker: false + supports_interface_shared_objects: false + supports_normalizing_ar: false + supports_start_end_lib: false + target_cpu: "k8" + target_libc: "local" + target_system_name: "local" + + # Chromium toolchain, no gcov + tool_path {name: "gcc" path: "tool_wrappers/linux_x64/chromium_clang" } + tool_path {name: "ld" path: "tool_wrappers/linux_x64/chromium_ld" } + tool_path {name: "ar" path: "tool_wrappers/linux_x64/chromium_ar" } + tool_path {name: "cpp" path: "tool_wrappers/linux_x64/chromium_clang" } + tool_path {name: "nm" path: "tool_wrappers/linux_x64/chromium_nm" } + tool_path {name: "objcopy" path: "tool_wrappers/linux_x64/chromium_objcopy" } + tool_path {name: "objdump" path: "tool_wrappers/linux_x64/chromium_objdump" } + tool_path {name: "strip" path: "tool_wrappers/linux_x64/chromium_strip" } + tool_path {name: "gcov" path: "/bin/false" } + + # Anticipated future default. + # This makes GCC and Clang do what we want when called through symlinks. + unfiltered_cxx_flag: "-no-canonical-prefixes" + linker_flag: "-no-canonical-prefixes" + + # Make C++ compilation deterministic. Use linkstamping instead of these + # compiler symbols. + unfiltered_cxx_flag: "-Wno-builtin-macro-redefined" + unfiltered_cxx_flag: "-D__DATE__=\"redacted\"" + unfiltered_cxx_flag: "-D__TIMESTAMP__=\"redacted\"" + unfiltered_cxx_flag: "-D__TIME__=\"redacted\"" + + # Security hardening on by default. + # Conservative choice; -D_FORTIFY_SOURCE=2 may be unsafe in some cases. + # We need to undef it before redefining it as some distributions now have + # it enabled by default. + compiler_flag: "-U_FORTIFY_SOURCE" + compiler_flag: "-fstack-protector" + compiler_flag: "-fPIE" + linker_flag: "-pie" + linker_flag: "-Wl,-z,relro,-z,now" + + # Enable coloring even if there's no attached terminal. Bazel removes the + # escape sequences if --nocolor is specified. + compiler_flag: "-fdiagnostics-color=always" + + # All warnings are enabled. Maybe enable -Werror as well? + compiler_flag: "-Wall" + # Enable a few more warnings that aren't part of -Wall. + compiler_flag: "-Wunused-parameter" + # But disable some that are problematic. + compiler_flag: "-Wno-sequence-point" # has false positives + + # Uncomment for debugging. + # compiler_flag: "-v" + # linker_flag: "-v" + + # Keep stack frames for debugging, even in opt mode. + compiler_flag: "-fno-omit-frame-pointer" + + # Stamp the binary with a unique identifier. + linker_flag: "-Wl,--build-id=md5" + linker_flag: "-Wl,--hash-style=gnu" + + # Stamp the binary with a unique identifier. + linker_flag: "-Wl,--build-id=md5" + linker_flag: "-Wl,--hash-style=gnu" + + compilation_mode_flags { + mode: DBG + # Enable debug symbols. + compiler_flag: "-g" + } + compilation_mode_flags { + mode: OPT + + # No debug symbols. + # Maybe we should enable https://gcc.gnu.org/wiki/DebugFission for opt or + # even generally? However, that can't happen here, as it requires special + # handling in Bazel. + compiler_flag: "-g0" + + # Conservative choice for -O + # -O3 can increase binary size and even slow down the resulting binaries. + # Profile first and / or use FDO if you need better performance than this. + compiler_flag: "-O2" + + # Disable assertions + compiler_flag: "-DNDEBUG" + + # Removal of unused code and data at link time (can this increase binary size in some cases?). + compiler_flag: "-ffunction-sections" + compiler_flag: "-fdata-sections" + linker_flag: "-Wl,--gc-sections" + } +} + +# Chromium Clang on OS X +toolchain { + toolchain_identifier: "osx" + abi_version: "local" + abi_libc_version: "local" + builtin_sysroot: "" + compiler: "compiler" + host_system_name: "local" + needsPic: true + target_libc: "macosx" + target_cpu: "darwin" + target_system_name: "local" + + + # Uncomment for debugging. + # compiler_flag: "-v" + + cxx_flag: "-std=c++1y" + linker_flag: "-undefined" + linker_flag: "dynamic_lookup" + linker_flag: "-headerpad_max_install_names" + ar_flag: "-static" + ar_flag: "-s" + ar_flag: "-o" + compiler_flag: "-nostdinc++" + compiler_flag: "-isystem" + compiler_flag: "external/org_chromium_clang_mac/include/c++/v1" + compiler_flag: "-isystem" + compiler_flag: "external/org_chromium_clang_mac/lib/clang/5.0.0/include" + compiler_flag: "-isystem" + compiler_flag: "/usr/include" + cxx_builtin_include_directory: "/usr/include" + cxx_builtin_include_directory: "/System/Library/Frameworks" + objcopy_embed_flag: "-I" + objcopy_embed_flag: "binary" + + # Anticipated future default. + unfiltered_cxx_flag: "-no-canonical-prefixes" + + # Make C++ compilation deterministic. Use linkstamping instead of these + # compiler symbols. + unfiltered_cxx_flag: "-Wno-builtin-macro-redefined" + unfiltered_cxx_flag: "-D__DATE__=\"redacted\"" + unfiltered_cxx_flag: "-D__TIMESTAMP__=\"redacted\"" + unfiltered_cxx_flag: "-D__TIME__=\"redacted\"" + + # Security hardening on by default. + # Conservative choice; -D_FORTIFY_SOURCE=2 may be unsafe in some cases. + compiler_flag: "-D_FORTIFY_SOURCE=1" + compiler_flag: "-fstack-protector" + + # Enable coloring even if there's no attached terminal. Bazel removes the + # escape sequences if --nocolor is specified. + compiler_flag: "-fcolor-diagnostics" + + # All warnings are enabled. Maybe enable -Werror as well? + compiler_flag: "-Wall" + # Enable a few more warnings that aren't part of -Wall. + compiler_flag: "-Wthread-safety" + compiler_flag: "-Wself-assign" + + # Keep stack frames for debugging, even in opt mode. + compiler_flag: "-fno-omit-frame-pointer" + + # Anticipated future default. + linker_flag: "-no-canonical-prefixes" + + tool_path {name: "ld" path: "/usr/bin/ld" } + tool_path {name: "cpp" path: "/usr/bin/cpp" } + tool_path {name: "dwp" path: "/usr/bin/dwp" } + tool_path {name: "gcov" path: "/usr/bin/gcov" } + tool_path {name: "nm" path: "/usr/bin/nm" } + tool_path {name: "objcopy" path: "/usr/bin/objcopy" } + tool_path {name: "objdump" path: "/usr/bin/objdump" } + tool_path {name: "strip" path: "/usr/bin/strip" } + tool_path {name: "gcc" path: "tool_wrappers/mac/osx_clang_wrapper.sh" } + tool_path {name: "ar" path: "/usr/bin/libtool" } + + compilation_mode_flags { + mode: DBG + # Enable debug symbols. + compiler_flag: "-g" + } + compilation_mode_flags { + mode: OPT + # No debug symbols. + # Maybe we should enable https://gcc.gnu.org/wiki/DebugFission for opt or even generally? + # However, that can't happen here, as it requires special handling in Bazel. + compiler_flag: "-g0" + + # Conservative choice for -O + # -O3 can increase binary size and even slow down the resulting binaries. + # Profile first and / or use FDO if you need better performance than this. + compiler_flag: "-O2" + + # Disable assertions + compiler_flag: "-DNDEBUG" + + # Removal of unused code and data at link time (can this increase binary size in some cases?). + compiler_flag: "-ffunction-sections" + compiler_flag: "-fdata-sections" + } + linking_mode_flags { mode: DYNAMIC } +} \ No newline at end of file diff --git a/tools/cpp/tool_wrappers/linux_x64/BUILD b/tools/cpp/tool_wrappers/linux_x64/BUILD new file mode 100755 index 0000000..2f6472c --- /dev/null +++ b/tools/cpp/tool_wrappers/linux_x64/BUILD @@ -0,0 +1,80 @@ +package(default_visibility = ['//tools/cpp:__pkg__']) + +filegroup( + name = "clang", + srcs = [ + "chromium_clang", + "@org_chromium_clang_linux_x64//:clang", + ], +) + +filegroup( + name = "ar", + srcs = [ + "chromium_ar", + "@org_chromium_binutils_linux_x64//:ar", + ], +) + +filegroup( + name = "as", + srcs = [ + "chromium_as", + "@org_chromium_binutils_linux_x64//:as", + ], +) + +filegroup( + name = "ld_and_symlink", + srcs = [ + "chromium_ld", + "ld", + "@org_chromium_binutils_linux_x64//:ld", + ], +) + +filegroup( + name = "nm", + srcs = [ + "chromium_nm", + "@org_chromium_binutils_linux_x64//:ar", + ], +) + +filegroup( + name = "objcopy", + srcs = [ + "chromium_objcopy", + "@org_chromium_binutils_linux_x64//:objcopy", + ], +) + +filegroup( + name = "objdump", + srcs = [ + "chromium_objdump", + "@org_chromium_binutils_linux_x64//:objdump", + ], +) + +filegroup( + name = "strip", + srcs = [ + "chromium_strip", + "@org_chromium_binutils_linux_x64//:strip", + ], +) + +filegroup( + name = "tool-wrappers", + srcs = [ + ":clang", + ":ar", + ":as", + ":ld_and_symlink", + ":nm", + ":objcopy", + ":objdump", + ":strip", + ], +) diff --git a/tools/cpp/tool_wrappers/linux_x64/chromium_ar b/tools/cpp/tool_wrappers/linux_x64/chromium_ar new file mode 100755 index 0000000..66a2f15 --- /dev/null +++ b/tools/cpp/tool_wrappers/linux_x64/chromium_ar @@ -0,0 +1,5 @@ +#!/bin/bash --norc + +exec -a chromium_ar \ + external/org_chromium_binutils_linux_x64/bin/ar \ + "$@" diff --git a/tools/cpp/tool_wrappers/linux_x64/chromium_as b/tools/cpp/tool_wrappers/linux_x64/chromium_as new file mode 100755 index 0000000..2ee68b9 --- /dev/null +++ b/tools/cpp/tool_wrappers/linux_x64/chromium_as @@ -0,0 +1,5 @@ +#!/bin/bash --norc + +exec -a chromium_as \ + external/org_chromium_binutils_linux_x64/bin/as \ + "$@" diff --git a/tools/cpp/tool_wrappers/linux_x64/chromium_clang b/tools/cpp/tool_wrappers/linux_x64/chromium_clang new file mode 100755 index 0000000..481b134 --- /dev/null +++ b/tools/cpp/tool_wrappers/linux_x64/chromium_clang @@ -0,0 +1,2 @@ +#!/bin/bash --norc +exec -a "$0" external/org_chromium_clang_linux_x64/bin/clang "$@" \ No newline at end of file diff --git a/tools/cpp/tool_wrappers/linux_x64/chromium_ld b/tools/cpp/tool_wrappers/linux_x64/chromium_ld new file mode 100755 index 0000000..3a87a25 --- /dev/null +++ b/tools/cpp/tool_wrappers/linux_x64/chromium_ld @@ -0,0 +1,5 @@ +#!/bin/bash --norc + +exec -a chromium_ld \ + external/org_chromium_binutils_linux_x64/bin/ld \ + "$@" diff --git a/tools/cpp/tool_wrappers/linux_x64/chromium_nm b/tools/cpp/tool_wrappers/linux_x64/chromium_nm new file mode 100755 index 0000000..c64dc14 --- /dev/null +++ b/tools/cpp/tool_wrappers/linux_x64/chromium_nm @@ -0,0 +1,5 @@ +#!/bin/bash --norc + +exec -a chromium_nm \ + external/org_chromium_binutils_linux_x64/bin/nm \ + "$@" diff --git a/tools/cpp/tool_wrappers/linux_x64/chromium_objcopy b/tools/cpp/tool_wrappers/linux_x64/chromium_objcopy new file mode 100755 index 0000000..4744ac9 --- /dev/null +++ b/tools/cpp/tool_wrappers/linux_x64/chromium_objcopy @@ -0,0 +1,5 @@ +#!/bin/bash --norc + +exec -a chromium_objcopy \ + external/org_chromium_binutils_linux_x64/bin/objcopy \ + "$@" diff --git a/tools/cpp/tool_wrappers/linux_x64/chromium_objdump b/tools/cpp/tool_wrappers/linux_x64/chromium_objdump new file mode 100755 index 0000000..ee3fbbd --- /dev/null +++ b/tools/cpp/tool_wrappers/linux_x64/chromium_objdump @@ -0,0 +1,5 @@ +#!/bin/bash --norc + +exec -a chromium_objdump \ + external/org_chromium_binutils_linux_x64/bin/objdump \ + "$@" diff --git a/tools/cpp/tool_wrappers/linux_x64/chromium_strip b/tools/cpp/tool_wrappers/linux_x64/chromium_strip new file mode 100755 index 0000000..02fcec8 --- /dev/null +++ b/tools/cpp/tool_wrappers/linux_x64/chromium_strip @@ -0,0 +1,5 @@ +#!/bin/bash --norc + +exec -a chromium_strip \ + external/org_chromium_binutils_linux_x64/bin/strip \ + "$@" diff --git a/tools/cpp/tool_wrappers/linux_x64/ld b/tools/cpp/tool_wrappers/linux_x64/ld new file mode 120000 index 0000000..6602ff7 --- /dev/null +++ b/tools/cpp/tool_wrappers/linux_x64/ld @@ -0,0 +1 @@ +chromium_ld \ No newline at end of file diff --git a/tools/cpp/tool_wrappers/mac/BUILD b/tools/cpp/tool_wrappers/mac/BUILD new file mode 100644 index 0000000..e9a5e57 --- /dev/null +++ b/tools/cpp/tool_wrappers/mac/BUILD @@ -0,0 +1,9 @@ +package(default_visibility = ['//tools/cpp:__pkg__']) + +filegroup( + name = "clang", + srcs = [ + "osx_clang_wrapper.sh", + "@org_chromium_clang_mac//:clang", + ], +) \ No newline at end of file diff --git a/tools/cpp/tool_wrappers/mac/osx_clang_wrapper.sh b/tools/cpp/tool_wrappers/mac/osx_clang_wrapper.sh new file mode 100755 index 0000000..69b96f5 --- /dev/null +++ b/tools/cpp/tool_wrappers/mac/osx_clang_wrapper.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# +# Copyright 2015 The Bazel Authors. All rights reserved. +# Copyright 2017 VSCO. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# OS X relpath is not really working. This is a wrapper script around gcc +# to simulate relpath behavior. +# +# This wrapper uses install_name_tool to replace all paths in the binary +# (bazel-out/.../path/to/original/library.so) by the paths relative to +# the binary. It parses the command line to behave as rpath is supposed +# to work. +# +# See https://blogs.oracle.com/dipol/entry/dynamic_libraries_rpath_and_mac +# on how to set those paths for Mach-O binaries. +# +set -eu + +GCC=external/org_chromium_clang_mac/bin/clang +INSTALL_NAME_TOOL="/usr/bin/install_name_tool" + +LIBS= +LIB_DIRS= +RPATH= +OUTPUT= +# let parse the option list +for i in "$@"; do + if [[ "${OUTPUT}" = "1" ]]; then + OUTPUT=$i + elif [[ "$i" =~ ^-l(.*)$ ]]; then + # lib + LIBS="${BASH_REMATCH[1]} $LIBS" + elif [[ "$i" =~ ^-L(.*)$ ]]; then + # lib + LIB_DIRS="${BASH_REMATCH[1]} $LIB_DIRS" + elif [[ "$i" =~ ^-Wl,-rpath,\$ORIGIN/(.*)$ ]]; then + # rpath + RPATH=${BASH_REMATCH[1]} + elif [[ "$i" = "-o" ]]; then + # output is coming + OUTPUT=1 + fi +done + +# Call gcc +${GCC} "$@" + +function get_library_path() { + for libdir in ${LIB_DIRS}; do + if [ -f ${libdir}/lib$1.so ]; then + echo "${libdir}/lib$1.so" + fi + done +} + +# A convenient method to return the actual path even for non symlinks +# and multi-level symlinks. +function get_realpath() { + local previous="$1" + local next=$(readlink "${previous}") + while [ -n "${next}" ]; do + previous="${next}" + next=$(readlink "${previous}") + done + echo "${previous}" +} + +# Get the path of a lib inside a tool +function get_otool_path() { + # the lib path is the path of the original lib relative to the workspace + get_realpath $1 | sed 's|^.*/bazel-out/|bazel-out/|' +} + +# Do replacements in the output +if [ -n "${RPATH}" ]; then + for lib in ${LIBS}; do + libpath=$(get_library_path ${lib}) + if [ -n "${libpath}" ]; then + ${INSTALL_NAME_TOOL} -change $(get_otool_path "${libpath}") "@loader_path/${RPATH}/lib${lib}.so" "${OUTPUT}" + fi + done +fi \ No newline at end of file