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

build: support linking against libc++ on Linux. #5563

Merged
merged 19 commits into from
Jan 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,13 @@ build:clang-msan --define tcmalloc=disabled
build:clang-msan --copt -fsanitize-memory-track-origins=2
build:clang-msan --linkopt -fuse-ld=lld

# Clang with libc++
build:libc++ --action_env=CC
build:libc++ --action_env=CXX
build:libc++ --action_env=CXXFLAGS=-stdlib=libc++
build:libc++ --action_env=PATH
build:libc++ --define force_libcpp=enabled
build:libc++ --linkopt -fuse-ld=lld

# Test options
test --test_env=HEAPCHECK=normal --test_env=PPROF_PATH
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ executors:
ubuntu-build:
description: "A regular build executor based on ubuntu image"
docker:
- image: envoyproxy/envoy-build:284769e833cc7752812f076a8b7a12e79c948df9
- image: envoyproxy/envoy-build:c1fde9909df98373be1fd2cc0733caf1f91917a6
resource_class: xlarge
working_directory: /source

Expand Down
12 changes: 12 additions & 0 deletions bazel/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,18 @@ Bazel can also be built with the Docker image used for CI, by installing Docker
See also the [documentation](https://github.com/envoyproxy/envoy/tree/master/ci) for developer use of the
CI Docker image.

## Linking against libc++ on Linux

To link Envoy against libc++, use the following commands:
```
export CC=clang
export CXX=clang++
bazel build --config=libc++ //source/exe:envoy-static
```
Note: this assumes that both: clang compiler and libc++ library are installed in the system,
and that `clang` and `clang++` are available in `$PATH`. On some systems, exports might need
to be changed to versioned binaries, e.g. `CC=clang-7` and `CXX=clang++-7`.

## Using a compiler toolchain in a non-standard location

By setting the `CC` and `LD_LIBRARY_PATH` in the environment that Bazel executes from as
Expand Down
13 changes: 8 additions & 5 deletions bazel/cc_configure.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def _build_envoy_cc_wrapper(repository_ctx):
repository_ctx.template("extra_tools/envoy_cc_wrapper", repository_ctx.attr._envoy_cc_wrapper, {
"{ENVOY_REAL_CC}": repr(str(real_cc)),
"{ENVOY_REAL_CXX}": repr(str(real_cxx)),
"{ENVOY_CXXFLAGS}": repr(str(repository_ctx.os.environ.get("CXXFLAGS", ""))),
})
return repository_ctx.path("extra_tools/envoy_cc_wrapper")

Expand Down Expand Up @@ -91,25 +92,27 @@ cc_autoconf = repository_rule(
"ABI_VERSION",
"BAZEL_COMPILER",
"BAZEL_HOST_SYSTEM",
"BAZEL_LINKOPTS",
"BAZEL_PYTHON",
"BAZEL_SH",
"BAZEL_TARGET_CPU",
"BAZEL_TARGET_LIBC",
"BAZEL_TARGET_SYSTEM",
"BAZEL_USE_CPP_ONLY_TOOLCHAIN",
"BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN",
"BAZEL_USE_LLVM_NATIVE_COVERAGE",
"BAZEL_VC",
"BAZEL_VS",
"BAZEL_LLVM",
"USE_CLANG_CL",
"CC",
"CXX",
"CXXFLAGS",
"CC_CONFIGURE_DEBUG",
"CC_TOOLCHAIN_NAME",
"CPLUS_INCLUDE_PATH",
"CUDA_COMPUTE_CAPABILITIES",
"CUDA_PATH",
"GCOV",
"HOMEBREW_RUBY_PATH",
"NO_WHOLE_ARCHIVE_OPTION",
"USE_DYNAMIC_CRT",
"USE_MSVC_WRAPPER",
"SYSTEMROOT",
"VS90COMNTOOLS",
"VS100COMNTOOLS",
Expand Down
34 changes: 21 additions & 13 deletions bazel/cc_wrapper.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#!/usr/bin/python
import contextlib
import os
import shlex
import sys
import tempfile

envoy_real_cc = {ENVOY_REAL_CC}
envoy_real_cxx = {ENVOY_REAL_CXX}
envoy_cxxflags = {ENVOY_CXXFLAGS}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will change the content of the compiler wrapper when $CXXFLAGS changes, which will have significant negative impact on build caching.

When the crosstool bootstrap runs this script, does it propagate environment variables? If yes, then you can use envoy_cxxflags = os.environ.get("CXXFLAGS", "")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, that's kind of the point, isn't it? Same is true for changing $CC and $CXX.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bazel won't cache when flags changed so I don't think it is negative anyway?



@contextlib.contextmanager
Expand All @@ -21,20 +23,14 @@ def sanitize_flagfile(in_path, out_fd):
for line in in_fp:
if line != "-lstdc++\n":
os.write(out_fd, line)
elif "-stdlib=libc++" in envoy_cxxflags:
os.write(out_fd, "-lc++\n")


def main():
compiler = envoy_real_cc

# Debian's packaging of Clang requires `-no-canonical-prefixes` to print
# consistent include paths, but Bazel 0.10 only sets that option at compile
# time. We inject it here for the configuration of `@local_config_cc//`.
#
# https://github.com/bazelbuild/bazel/issues/3977
# https://github.com/bazelbuild/bazel/issues/4572
# https://bazel-review.googlesource.com/c/bazel/+/39951
if sys.argv[1:] == ["-E", "-xc++", "-", "-v"] and "clang" in compiler:
os.execv(envoy_real_cxx, [envoy_real_cxx, "-E", "-", "-v", "-no-canonical-prefixes"])
# Append CXXFLAGS to correctly detect include paths for either libstdc++ or libc++.
if sys.argv[1:5] == ["-E", "-xc++", "-", "-v"]:
os.execv(envoy_real_cxx, [envoy_real_cxx] + sys.argv[1:] + shlex.split(envoy_cxxflags))

# `g++` and `gcc -lstdc++` have similar behavior and Bazel treats them as
# interchangeable, but `gcc` will ignore the `-static-libstdc++` flag.
Expand All @@ -45,10 +41,22 @@ def main():
# it in the same test.
if "-static-libstdc++" in sys.argv[1:] or "-stdlib=libc++" in sys.argv[1:]:
compiler = envoy_real_cxx
argv = []
else:
compiler = envoy_real_cc

# Either:
# a) remove all occurrences of -lstdc++ (when statically linking against libstdc++),
# b) replace all occurrences of -lstdc++ with -lc++ (when linking against libc++).
if "-static-libstdc++" in sys.argv[1:] or "-stdlib=libc++" in envoy_cxxflags:
# Append CXXFLAGS to all C++ targets (this is mostly for dependencies).
if envoy_cxxflags and "-std=c++" in str(sys.argv[1:]):
argv = shlex.split(envoy_cxxflags)
else:
argv = []
for arg in sys.argv[1:]:
if arg == "-lstdc++":
pass
if "-stdlib=libc++" in envoy_cxxflags:
arg.append("-lc++")
elif arg.startswith("-Wl,@"):
# tempfile.mkstemp will write to the out-of-sandbox tempdir
# unless the user has explicitly set environment variables
Expand Down
4 changes: 3 additions & 1 deletion bazel/envoy_build_system.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ def envoy_copts(repository, test = False):

def envoy_static_link_libstdcpp_linkopts():
return envoy_select_force_libcpp(
# TODO(PiotrSikora): statically link libc++ once that's possible.
# See: https://reviews.llvm.org/D53238
["-stdlib=libc++"],
["-static-libstdc++", "-static-libgcc"],
)
Expand Down Expand Up @@ -161,7 +163,7 @@ def envoy_test_linkopts():
# TODO(mattklein123): It's not great that we universally link against the following libs.
# In particular, -latomic and -lrt are not needed on all platforms. Make this more granular.
"//conditions:default": ["-pthread", "-lrt", "-ldl"],
}) + envoy_select_force_libcpp(["-lc++experimental"], ["-lstdc++fs", "-latomic"])
}) + envoy_select_force_libcpp(["-lc++fs"], ["-lstdc++fs", "-latomic"])

# References to Envoy external dependencies should be wrapped with this function.
def envoy_external_dep_path(dep):
Expand Down
4 changes: 2 additions & 2 deletions ci/build_container/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ CC ?= gcc
CXX ?= g++

# Common compiler flags
CXXFLAGS ?= -ggdb3 -fno-omit-frame-pointer -O2
CFLAGS ?= -ggdb3 -fno-omit-frame-pointer -O2
CXXFLAGS += -ggdb3 -fno-omit-frame-pointer -O2
CFLAGS += -ggdb3 -fno-omit-frame-pointer -O2
CPPFLAGS ?= -DNDEBUG

# Keep track of the env vars we depend upon for $(THIRDPARTY_DEPS)/%.dep.env. If the list (captured
Expand Down
7 changes: 5 additions & 2 deletions ci/build_container/build_recipes/gperftools.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,8 @@ curl https://github.com/gperftools/gperftools/releases/download/gperftools-"$VER
tar xf gperftools-"$VERSION".tar.gz
cd gperftools-"$VERSION"

LDFLAGS="-lpthread" ./configure --prefix="$THIRDPARTY_BUILD" --enable-shared=no --enable-frame-pointers --disable-libunwind
make V=1 install
export LDFLAGS="${LDFLAGS} -lpthread"
./configure --prefix="$THIRDPARTY_BUILD" --enable-shared=no --enable-frame-pointers --disable-libunwind

# Don't build tests, since malloc_extension_c_test hardcodes -lstdc++, which breaks build when linking against libc++.
make V=1 install-libLTLIBRARIES install-perftoolsincludeHEADERS
6 changes: 4 additions & 2 deletions ci/do_ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -152,17 +152,19 @@ elif [[ "$1" == "bazel.compile_time_options" ]]; then
# Right now, none of the available compile-time options conflict with each other. If this
# changes, this build type may need to be broken up.
COMPILE_TIME_OPTIONS="\
--config libc++ \
--define signal_trace=disabled \
--define hot_restart=disabled \
--define google_grpc=disabled \
--define boringssl=fips \
--define log_debug_assert_in_release=enabled \
--define=tcmalloc=debug \
--define tcmalloc=debug \
"
setup_clang_toolchain
# This doesn't go into CI but is available for developer convenience.
echo "bazel with different compiletime options build with tests..."
cd "${ENVOY_CI_DIR}"
# Building all the dependencies from scratch to link them against libc++.
cd "${ENVOY_SRCDIR}"
echo "Building..."
bazel build ${BAZEL_BUILD_OPTIONS} ${COMPILE_TIME_OPTIONS} -c dbg //source/exe:envoy-static
echo "Building and testing..."
Expand Down
2 changes: 1 addition & 1 deletion test/common/upstream/ring_hash_lb_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ TEST_P(RingHashFailoverTest, BasicFailover) {
EXPECT_EQ(failover_host_set_.healthy_hosts_[0], lb->chooseHost(nullptr));
}

#ifndef __APPLE__
#if __GLIBCXX__ >= 20130411 && __GLIBCXX__ <= 20180726
// Run similar tests with the default hash algorithm for GCC 5.
// TODO(danielhochman): After v1 is deprecated this test can be deleted since std::hash will no
// longer be in use.
Expand Down
4 changes: 3 additions & 1 deletion test/exe/envoy_static_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ fi
if [[ ${DYNLIBS} =~ "libc++" ]]; then
echo "libc++ is dynamically linked:"
echo "${DYNLIBS}"
exit 1
# TODO(PiotrSikora): enforce this once there is a way to statically link libc++.
# See: https://reviews.llvm.org/D53238
exit 0
fi

if [[ ${DYNLIBS} =~ "libstdc++" || ${DYNLIBS} =~ "libgcc" ]]; then
Expand Down