From 41125a0a34635457ce7beb1786af1313a594255a Mon Sep 17 00:00:00 2001 From: seelabs Date: Wed, 3 Feb 2016 16:27:46 -0500 Subject: [PATCH] Support for clang specific boost and protobuf dirs: Clang does not understand gcc 5's new ABI. On linux systems that default to the new ABI (such as ubuntu 15.10), building with clang requires using C++ libraries built with the the old gcc ABI. When building with the clang protobuf lib, a common error is to load the gcc protobuf library at run time. When set, PROTOBUF_ROOT is added to rpath to make sure the correct lib is loaded. Adds a script to install clang and download and build boost and protobuf with boost. --- Builds/Ubuntu/build_clang_libs.sh | 79 +++++++++++++++++++++++++++++++ SConstruct | 76 ++++++++++++++++++----------- 2 files changed, 128 insertions(+), 27 deletions(-) create mode 100755 Builds/Ubuntu/build_clang_libs.sh diff --git a/Builds/Ubuntu/build_clang_libs.sh b/Builds/Ubuntu/build_clang_libs.sh new file mode 100755 index 000000000..dd2294c1d --- /dev/null +++ b/Builds/Ubuntu/build_clang_libs.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash + +# +# This scripts installs boost and protobuf built with clang. This is needed on +# ubuntu 15.10 when building with clang +# It will build these in a 'clang' subdirectory that it creates below the directory +# this script is run from. If a clang directory already exists the script will refuse +# to run. + +if hash lsb_release 2>/dev/null; then + if [ $(lsb_release -si) == "Ubuntu" ]; then + ubuntu_release=$(lsb_release -sr) + fi +fi + +if [ -z "${ubuntu_release}" ]; then + echo "System not supported" + exit 1 +fi + +if ! hash clang 2>/dev/null; then + clang_version=3.7 + sudo apt-get -y install clang-${clang_version} + update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${clang_version} 99 clang++ + hash -r + if ! hash clang 2>/dev/null; then + echo "Please install clang" + exit 1 + fi +fi + +if [ ${ubuntu_release} != "15.10" ]; then + echo "clang specific boost and protobuf not needed" + exit 0 +fi + +if [ -d clang ]; then + echo "clang directory already exists. Cowardly refusing to run" + exit 1 +fi + +if ! hash wget 2>/dev/null; then + sudo apt-get -y install wget + hash -r + if ! hash wget 2>/dev/null; then + echo "Please install wget" + exit 1 + fi +fi + +num_procs=$(lscpu -p | grep -v '^#' | sort -u -t, -k 2,4 | wc -l) # pysical cores + +mkdir clang +pushd clang > /dev/null + +# Install protobuf +pb=protobuf-2.6.1 +pb_tar=${pb}.tar.gz +wget -O ${pb_tar} https://github.com/google/protobuf/releases/download/v2.6.1/${pb_tar} +tar xf ${pb_tar} +rm ${pb_tar} +pushd ${pb} > /dev/null +./configure CC=clang CXX=clang++ CXXFLAGS='-std=c++14 -O3 -g' +make -j${num_procs} +popd > /dev/null + +# Install boost +boost_ver=1.60.0 +bd=boost_${boost_ver//./_} +bd_tar=${bd}.tar.gz +wget -O ${bd_tar} http://sourceforge.net/projects/boost/files/boost/${boost_ver}/${bd_tar} +tar xf ${bd_tar} +rm ${bd_tar} +pushd ${bd} > /dev/null +./bootstrap.sh +./b2 toolset=clang -j${num_procs} +popd > /dev/null + +popd > /dev/null diff --git a/SConstruct b/SConstruct index 0febe1e15..4042d52c2 100644 --- a/SConstruct +++ b/SConstruct @@ -61,10 +61,16 @@ The following environment variables modify the build environment: Path to the boost directory. OPENSSL_ROOT Path to the openssl directory. - PROTOBUF_DIR - Path to the protobuf directory. This is usually only needed when - the installed protobuf library uses a different ABI than clang - (as with ubuntu 15.10). + PROTOBUF_ROOT + Path to the protobuf directory. + CLANG_PROTOBUF_ROOT + Override the path to the protobuf directory for the clang toolset. This is + usually only needed when the installed protobuf library uses a different + ABI than clang (as with ubuntu 15.10). + CLANG_BOOST_ROOT + Override the path to the boost directory for the clang toolset. This is + usually only needed when the installed protobuf library uses a different + ABI than clang (as with ubuntu 15.10). The following extra options may be used: --ninja Generate a `build.ninja` build file for the specified target @@ -356,21 +362,6 @@ def config_base(env): ,'-DBOOST_NO_AUTO_PTR' ]) - try: - BOOST_ROOT = os.path.normpath(os.environ['BOOST_ROOT']) - env.Append(LIBPATH=[ - os.path.join(BOOST_ROOT, 'stage', 'lib'), - ]) - env['BOOST_ROOT'] = BOOST_ROOT - except KeyError: - pass - - try: - protobuf_dir = os.environ['PROTOBUF_DIR'] - env.Append(LIBPATH=[protobuf_dir]) - except KeyError: - pass - if Beast.system.windows: try: OPENSSL_ROOT = os.path.normpath(os.environ['OPENSSL_ROOT']) @@ -444,21 +435,52 @@ def add_sanitizer (toolchain, env): add_static_libs(env, [san_to_lib[san]]) env.Append(CPPDEFINES=['SANITIZER='+san_to_lib[san].upper()]) -# Set toolchain and variant specific construction variables -def config_env(toolchain, variant, env): - if is_debug_variant(variant): - env.Append(CPPDEFINES=['DEBUG', '_DEBUG']) +def add_boost_and_protobuf(toolchain, env): + def get_environ_value(candidates): + for c in candidates: + try: + return os.environ[c] + except KeyError: + pass + raise KeyError('Environment variable not set') - elif variant == 'release' or variant == 'profile': - env.Append(CPPDEFINES=['NDEBUG']) - - if 'BOOST_ROOT' in env: + try: + br_cands = ['CLANG_BOOST_ROOT'] if toolchain == 'clang' else [] + br_cands.append('BOOST_ROOT') + BOOST_ROOT = os.path.normpath(get_environ_value(br_cands)) + env.Append(LIBPATH=[ + os.path.join(BOOST_ROOT, 'stage', 'lib'), + ]) + env['BOOST_ROOT'] = BOOST_ROOT if toolchain == 'gcc': env.Append(CCFLAGS=['-isystem' + env['BOOST_ROOT']]) else: env.Append(CPPPATH=[ env['BOOST_ROOT'], ]) + except KeyError: + pass + + try: + pb_cands = ['CLANG_PROTOBUF_ROOT'] if toolchain == 'clang' else [] + pb_cands.append('PROTOBUF_ROOT') + PROTOBUF_ROOT = os.path.normpath(get_environ_value(pb_cands)) + env.Append(LIBPATH=[PROTOBUF_ROOT + '/src/.libs']) + if not should_link_static() and toolchain in['clang', 'gcc']: + env.Append(LINKFLAGS=['-Wl,-rpath,' + PROTOBUF_ROOT + '/src/.libs']) + env['PROTOBUF_ROOT'] = PROTOBUF_ROOT + env.Append(CPPPATH=[env['PROTOBUF_ROOT'] + '/src',]) + except KeyError: + pass + +# Set toolchain and variant specific construction variables +def config_env(toolchain, variant, env): + add_boost_and_protobuf(toolchain, env) + if is_debug_variant(variant): + env.Append(CPPDEFINES=['DEBUG', '_DEBUG']) + + elif variant == 'release' or variant == 'profile': + env.Append(CPPDEFINES=['NDEBUG']) if should_link_static() and not Beast.system.linux: raise Exception("Static linking is only implemented for linux.")