aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools
diff options
context:
space:
mode:
authorGravatar Damien Martin-Guillerez <dmarting@google.com>2016-03-02 16:24:13 +0000
committerGravatar Kristina Chodorow <kchodorow@google.com>2016-03-02 17:55:47 +0000
commit8fa5ae6a6364100f2a7f9130e62eb0edb447339a (patch)
treecc216ad18cd748b79ee9e9debbb399aeb54ac4a3 /tools
parentbe5b2ebcf70b5e89cb87060cee045a9773b496f4 (diff)
Add a cc_configure rule to auto-configure C++ crosstool
This is the last step of http://goo.gl/fD4ZsY (issue #893). Tests are in a separate change because they requires pretty complex setup. -- MOS_MIGRATED_REVID=116141979
Diffstat (limited to 'tools')
-rw-r--r--tools/cpp/BUILD.tpl54
-rw-r--r--tools/cpp/CROSSTOOL2
-rw-r--r--tools/cpp/CROSSTOOL.tpl63
-rw-r--r--tools/cpp/cc_configure.bzl268
-rwxr-xr-xtools/cpp/osx_cc_wrapper.sh (renamed from tools/cpp/osx_gcc_wrapper.sh)8
-rw-r--r--tools/cpp/osx_cc_wrapper.sh.tpl93
6 files changed, 483 insertions, 5 deletions
diff --git a/tools/cpp/BUILD.tpl b/tools/cpp/BUILD.tpl
new file mode 100644
index 0000000000..3079485099
--- /dev/null
+++ b/tools/cpp/BUILD.tpl
@@ -0,0 +1,54 @@
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+ name = "malloc",
+)
+
+cc_library(
+ name = "stl",
+)
+
+filegroup(
+ name = "empty",
+ srcs = [],
+)
+
+# This is the entry point for --crosstool_top. Toolchains are found
+# by lopping off the name of --crosstool_top and searching for
+# the "${CPU}" entry in the toolchains attribute.
+cc_toolchain_suite(
+ name = "toolchain",
+ toolchains = {
+ "%{name}": ":cc-compiler-%{name}",
+ },
+)
+
+cc_toolchain(
+ name = "cc-compiler-%{name}",
+ all_files = ":empty",
+ compiler_files = ":empty",
+ cpu = "local",
+ dwp_files = ":empty",
+ dynamic_runtime_libs = [":empty"],
+ linker_files = ":empty",
+ objcopy_files = ":empty",
+ static_runtime_libs = [":empty"],
+ strip_files = ":empty",
+ supports_param_files = %{supports_param_files},
+)
+
+
+# Android tooling requires a default toolchain for the armeabi-v7a cpu.
+cc_toolchain(
+ name = "cc-compiler-armeabi-v7a",
+ all_files = ":empty",
+ compiler_files = ":empty",
+ cpu = "local",
+ dwp_files = ":empty",
+ dynamic_runtime_libs = [":empty"],
+ linker_files = ":empty",
+ objcopy_files = ":empty",
+ static_runtime_libs = [":empty"],
+ strip_files = ":empty",
+ supports_param_files = 1,
+)
diff --git a/tools/cpp/CROSSTOOL b/tools/cpp/CROSSTOOL
index 6846d70b74..a668263a19 100644
--- a/tools/cpp/CROSSTOOL
+++ b/tools/cpp/CROSSTOOL
@@ -205,7 +205,7 @@ toolchain {
tool_path { name: "compat-ld" path: "/usr/bin/ld" }
tool_path { name: "cpp" path: "/usr/bin/cpp" }
tool_path { name: "dwp" path: "/usr/bin/dwp" }
- tool_path { name: "gcc" path: "osx_gcc_wrapper.sh" }
+ tool_path { name: "gcc" path: "osx_cc_wrapper.sh" }
cxx_flag: "-std=c++0x"
ar_flag: "-static"
ar_flag: "-s"
diff --git a/tools/cpp/CROSSTOOL.tpl b/tools/cpp/CROSSTOOL.tpl
new file mode 100644
index 0000000000..82184bcfd9
--- /dev/null
+++ b/tools/cpp/CROSSTOOL.tpl
@@ -0,0 +1,63 @@
+major_version: "local"
+minor_version: ""
+default_target_cpu: "same_as_host"
+
+default_toolchain {
+ cpu: "%{cpu}"
+ toolchain_identifier: "local"
+}
+
+default_toolchain {
+ cpu: "armeabi-v7a"
+ toolchain_identifier: "stub_armeabi-v7a"
+}
+
+# Android tooling requires a default toolchain for the armeabi-v7a cpu.
+toolchain {
+ abi_version: "armeabi-v7a"
+ abi_libc_version: "armeabi-v7a"
+ builtin_sysroot: ""
+ compiler: "compiler"
+ host_system_name: "armeabi-v7a"
+ needsPic: true
+ supports_gold_linker: false
+ supports_incremental_linker: false
+ supports_fission: false
+ supports_interface_shared_objects: false
+ supports_normalizing_ar: false
+ supports_start_end_lib: false
+ supports_thin_archives: false
+ target_libc: "armeabi-v7a"
+ target_cpu: "armeabi-v7a"
+ target_system_name: "armeabi-v7a"
+ toolchain_identifier: "stub_armeabi-v7a"
+
+ tool_path { name: "ar" path: "/bin/false" }
+ tool_path { name: "compat-ld" path: "/bin/false" }
+ tool_path { name: "cpp" path: "/bin/false" }
+ tool_path { name: "dwp" path: "/bin/false" }
+ tool_path { name: "gcc" path: "/bin/false" }
+ tool_path { name: "gcov" path: "/bin/false" }
+ tool_path { name: "ld" path: "/bin/false" }
+
+ tool_path { name: "nm" path: "/bin/false" }
+ tool_path { name: "objcopy" path: "/bin/false" }
+ tool_path { name: "objdump" path: "/bin/false" }
+ tool_path { name: "strip" path: "/bin/false" }
+ linking_mode_flags { mode: DYNAMIC }
+}
+
+toolchain {
+ toolchain_identifier: "local"
+%{content}
+
+ compilation_mode_flags {
+ mode: DBG
+%{dbg_content}
+ }
+ compilation_mode_flags {
+ mode: OPT
+%{opt_content}
+ }
+ linking_mode_flags { mode: DYNAMIC }
+}
diff --git a/tools/cpp/cc_configure.bzl b/tools/cpp/cc_configure.bzl
new file mode 100644
index 0000000000..0f70247791
--- /dev/null
+++ b/tools/cpp/cc_configure.bzl
@@ -0,0 +1,268 @@
+# Copyright 2016 The Bazel Authors. 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.
+"""Rules for configuring the C++ toolchain (experimental)."""
+
+
+def _get_value(it):
+ """Convert `it` in serialized protobuf format."""
+ if type(it) == "int":
+ return str(it)
+ elif type(it) == "bool":
+ return "true" if it else "false"
+ else:
+ return "\"%s\"" % it
+
+
+def _build_crosstool(d, prefix=" "):
+ """Convert `d` to a string version of a CROSSTOOL file content."""
+ lines = []
+ for k in d:
+ if type(d[k]) == "list":
+ for it in d[k]:
+ lines.append("%s%s: %s" % (prefix, k, _get_value(it)))
+ else:
+ lines.append("%s%s: %s" % (prefix, k, _get_value(d[k])))
+ return "\n".join(lines)
+
+
+def _build_tool_path(d):
+ """Build the list of tool_path for the CROSSTOOL file."""
+ lines = []
+ for k in d:
+ lines.append(" tool_path {name: \"%s\" path: \"%s\" }" % (k, d[k]))
+ return "\n".join(lines)
+
+
+def _which(ctx, cmd, default):
+ """A wrapper around ctx.which() to provide a fallback value."""
+ result = ctx.which(cmd)
+ return default if result == None else str(result)
+
+
+def _get_tool_paths(ctx, darwin, cc):
+ """Compute the path to the various tools."""
+ return {k: _which(ctx, k, "/usr/bin/" + k)
+ for k in [
+ "ld",
+ "cpp",
+ "dwp",
+ "gcov",
+ "nm",
+ "objcopy",
+ "objdump",
+ "strip",
+ ]} + {
+ "gcc": cc,
+ "ar": "/usr/bin/libtool"
+ if darwin else _which(ctx, "ar", "/usr/bin/ar")
+ }
+
+
+def _ld_library_paths(ctx):
+ """Use ${LD_LIBRARY_PATH} to compute the list -Wl,rpath flags."""
+ if "LD_LIBRARY_PATH" in ctx.os.environ:
+ result = []
+ for p in ctx.os.environ["LD_LIBRARY_PATH"].split(":"):
+ p = ctx.path(p) # Normalize the path
+ result.append("-Wl,rpath," + p)
+ result.append("-L" + p)
+ return result
+ else:
+ return []
+
+
+def _get_cpu_value(ctx):
+ """Compute the cpu_value based on the OS name."""
+ return "darwin" if ctx.os.name.lower().startswith("mac os") else "local"
+
+
+_INC_DIR_MARKER_BEGIN = "#include <...> search starts here:"
+_INC_DIR_MARKER_END = "End of search list."
+
+
+def _get_cxx_inc_directories(ctx, cc):
+ """Compute the list of default C++ include directories."""
+ result = ctx.execute([cc, "-E", "-xc++", "-", "-v"])
+ index1 = result.stderr.find(_INC_DIR_MARKER_BEGIN)
+ if index1 == -1:
+ return []
+ index2 = result.stderr.find(_INC_DIR_MARKER_END, index1)
+ if index2 == -1:
+ return []
+ inc_dirs = result.stderr[index1 + len(_INC_DIR_MARKER_BEGIN):index2].strip()
+ return [ctx.path(p.strip()) for p in inc_dirs.split("\n")]
+
+
+def _add_option_if_supported(ctx, cc, option):
+ """Checks that `option` is supported by the C compiler."""
+ result = ctx.execute([cc, option])
+ return [option] if result.stderr.find(option) == -1 else []
+
+
+def _crosstool_content(ctx, cc, cpu_value, darwin):
+ """Return the content for the CROSSTOOL file, in a dictionary."""
+ return {
+ "abi_version": "local",
+ "abi_libc_version": "local",
+ "builtin_sysroot": "",
+ "compiler": "compiler",
+ "host_system_name": "local",
+ "needsPic": True,
+ "supports_gold_linker": False,
+ "supports_incremental_linker": False,
+ "supports_fission": False,
+ "supports_interface_shared_objects": False,
+ "supports_normalizing_ar": False,
+ "supports_start_end_lib": False,
+ "supports_thin_archives": False,
+ "target_libc": "macosx" if darwin else "local",
+ "target_cpu": cpu_value,
+ "target_system_name": "local",
+ "cxx_flag": "-std=c++0x",
+ "linker_flag": [
+ "-lstdc++",
+ # Anticipated future default.
+ "-no-canonical-prefixes"
+ ] + (["-undefined", "dynamic_lookup"] if darwin else [
+ "-B/usr/bin",
+ # Have gcc return the exit code from ld.
+ "-pass-exit-codes",
+ # Stamp the binary with a unique identifier.
+ "-Wl,--build-id=md5",
+ "-Wl,--hash-style=gnu"
+ # Gold linker only? Can we enable this by default?
+ # "-Wl,--warn-execstack",
+ # "-Wl,--detect-odr-violations"
+ ]) + _ld_library_paths(ctx),
+ "ar_flag": ["-static", "-s", "-o"] if darwin else [],
+ "cxx_builtin_include_directory": _get_cxx_inc_directories(ctx, cc),
+ "objcopy_embed_flag": ["-I", "binary"],
+ "unfiltered_cxx_flag": [
+ # Anticipated future default.
+ "-no-canonical-prefixes",
+ ] + ([] if darwin else ["-fno-canonical-system-headers"]) + [
+ # Make C++ compilation deterministic. Use linkstamping instead of these
+ # compiler symbols.
+ "-Wno-builtin-macro-redefined",
+ "-D__DATE__=\\\"redacted\\\"",
+ "-D__TIMESTAMP__=\\\"redacted\\\"",
+ "-D__TIME__=\\\"redacted\\\""
+ ],
+ "compiler_flag": [
+ # 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.
+ "-U_FORTIFY_SOURCE",
+ "-D_FORTIFY_SOURCE=1",
+ "-fstack-protector",
+ # All warnings are enabled. Maybe enable -Werror as well?
+ "-Wall",
+ # Enable a few more warnings that aren't part of -Wall.
+ ] + (["-Wthread-safety", "-Wself-assign"] if darwin else [
+ "-Wunused-but-set-parameter",
+ # Disable some that are problematic.
+ "-Wno-free-nonheap-object", # has false positives
+ "-Wl,-z,-relro,-z,now"
+ ]) + (
+ # Enable coloring even if there's no attached terminal. Bazel removes the
+ # escape sequences if --nocolor is specified.
+ _add_option_if_supported(ctx, cc, "-fcolor-diagnostics")) + [
+ # Keep stack frames for debugging, even in opt mode.
+ "-fno-omit-frame-pointer",
+ ],
+ }
+
+
+def _opt_content(darwin):
+ """Return the content of the opt specific section of the CROSSTOOL file."""
+ return {
+ "compiler_flag": [
+ # 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.
+ "-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.
+ "-O2",
+
+ # Disable assertions
+ "-DNDEBUG",
+
+ # Removal of unused code and data at link time (can this increase binary size in some cases?).
+ "-ffunction-sections",
+ "-fdata-sections"
+ ],
+ "linker_flag": [] if darwin else ["-Wl,--gc-sections"]
+ }
+
+
+def _dbg_content():
+ """Return the content of the dbg specific section of the CROSSTOOL file."""
+ # Enable debug symbols
+ return {"compiler_flag": "-g"}
+
+
+def _find_cc(ctx):
+ """Find the C++ compiler."""
+ if "CC" in ctx.os.environ:
+ return ctx.path(ctx.os.environ["CC"])
+ else:
+ cc = ctx.which("gcc")
+ if cc == None:
+ fail(
+ "Cannot find gcc, either correct your path or set the CC environment"
+ " variable")
+ return cc
+
+
+def _tpl(ctx, tpl, substitutions={}):
+ ctx.template(tpl, Label("@bazel_tools//tools/cpp:%s.tpl" % tpl),
+ substitutions)
+
+
+def _impl(ctx):
+ cpu_value = _get_cpu_value(ctx)
+ darwin = cpu_value == "darwin"
+ cc = _find_cc(ctx)
+ crosstool_cc = "osx_cc_wrapper.sh" if darwin else str(cc)
+ darwin = cpu_value == "darwin"
+ tool_paths = _get_tool_paths(ctx, darwin, crosstool_cc)
+ crosstool_content = _crosstool_content(ctx, cc, cpu_value, darwin)
+ opt_content = _opt_content(darwin)
+ dbg_content = _dbg_content()
+ _tpl(ctx, "BUILD", {
+ "%{name}": cpu_value,
+ "%{supports_param_files}": "0" if darwin else "1"
+ })
+ _tpl(ctx, "osx_gcc_wrapper.sh", {"%{cc}": str(cc)})
+ _tpl(ctx, "CROSSTOOL", {
+ "%{cpu}": cpu_value,
+ "%{content}": _build_crosstool(crosstool_content) + "\n" +
+ _build_tool_path(tool_paths),
+ "%{opt_content}": _build_crosstool(opt_content, " "),
+ "%{dbg_content}": _build_crosstool(dbg_content, " "),
+ })
+
+
+cc_autoconf = repository_rule(_impl, local=True)
+
+
+def cc_configure():
+ """A C++ configuration rules that generate the crosstool file."""
+ cc_autoconf(name="local_config_cc")
+ native.bind(name="cc_toolchain", actual="@local_config_cc//:toolchain")
diff --git a/tools/cpp/osx_gcc_wrapper.sh b/tools/cpp/osx_cc_wrapper.sh
index c822836922..739fca5de6 100755
--- a/tools/cpp/osx_gcc_wrapper.sh
+++ b/tools/cpp/osx_cc_wrapper.sh
@@ -14,12 +14,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-# OS X rpath is not really working. This is a wrapper script around gcc
-# to simulate rpath behavior.
+# 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 behaves as rpath is supposed
+# 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
@@ -27,7 +27,7 @@
#
set -eu
-GCC="/usr/bin/gcc"
+GCC=/usr/bin/gcc
INSTALL_NAME_TOOL="/usr/bin/install_name_tool"
LIBS=
diff --git a/tools/cpp/osx_cc_wrapper.sh.tpl b/tools/cpp/osx_cc_wrapper.sh.tpl
new file mode 100644
index 0000000000..5e66680f6a
--- /dev/null
+++ b/tools/cpp/osx_cc_wrapper.sh.tpl
@@ -0,0 +1,93 @@
+#!/bin/bash
+#
+# Copyright 2015 The Bazel Authors. 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
+
+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 the C++ compiler
+%{cc} "$@"
+
+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
+