1#!/bin/bash 2# 3# Execute this tool to setup the environment and build binary releases 4# for Percona-Server starting from a fresh tree. 5# 6# Usage: build-binary.sh [target dir] 7# The default target directory is the current directory. If it is not 8# supplied and the current directory is not empty, it will issue an error in 9# order to avoid polluting the current directory after a test run. 10# 11 12# Bail out on errors, be strict 13set -ue 14 15# Examine parameters 16TARGET="$(uname -m)" 17TARGET_CFLAGS='' 18QUIET='VERBOSE=1' 19WITH_JEMALLOC='' 20WITH_MECAB_OPTION='' 21DEBUG_EXTRA='' 22WITH_SSL='/usr' 23WITH_SSL_TYPE='system' 24OPENSSL_INCLUDE='' 25OPENSSL_LIBRARY='' 26CRYPTO_LIBRARY='' 27TAG='' 28# 29CMAKE_BUILD_TYPE='' 30COMMON_FLAGS='' 31# 32TOKUDB_BACKUP_VERSION='' 33# enable asan 34ENABLE_ASAN=0 35# 36# Some programs that may be overriden 37TAR=${TAR:-tar} 38 39# Check if we have a functional getopt(1) 40if ! getopt --test 41then 42 go_out="$(getopt --options=iqdvj:m:t: \ 43 --longoptions=i686,quiet,debug,valgrind,with-jemalloc:,with-mecab:,with-yassl,with-ssl:,tag: \ 44 --name="$(basename "$0")" -- "$@")" 45 test $? -eq 0 || exit 1 46 eval set -- $go_out 47fi 48 49for arg 50do 51 case "$arg" in 52 -- ) shift; break;; 53 -i | --i686 ) 54 shift 55 TARGET="i686" 56 TARGET_CFLAGS="-m32 -march=i686" 57 ;; 58 -d | --debug ) 59 shift 60 CMAKE_BUILD_TYPE='Debug' 61 BUILD_COMMENT="${BUILD_COMMENT:-}-debug" 62 TARBALL_SUFFIX="-debug" 63 DEBUG_EXTRA="-DDEBUG_EXTNAME=OFF -DWITH_DEBUG=ON" 64 ;; 65 -a | --asan ) 66 shift 67 ENABLE_ASAN=1 68 ;; 69 -v | --valgrind ) 70 shift 71 CMAKE_OPTS="${CMAKE_OPTS:-} -DWITH_VALGRIND=ON" 72 BUILD_COMMENT="${BUILD_COMMENT:-}-valgrind" 73 ;; 74 -q | --quiet ) 75 shift 76 QUIET='' 77 ;; 78 -j | --with-jemalloc ) 79 shift 80 WITH_JEMALLOC="$1" 81 shift 82 ;; 83 -m | --with-mecab ) 84 shift 85 WITH_MECAB_OPTION="-DWITH_MECAB=$1" 86 shift 87 ;; 88 --with-yassl ) 89 shift 90 WITH_SSL_TYPE="bundled" 91 ;; 92 --with-ssl ) 93 shift 94 WITH_SSL="$1" 95 shift 96 # Set openssl and crypto library path 97 if test -e "$WITH_SSL/lib/libssl.a" 98 then 99 OPENSSL_INCLUDE="-DOPENSSL_INCLUDE_DIR=$WITH_SSL/include" 100 OPENSSL_LIBRARY="-DOPENSSL_LIBRARY=$WITH_SSL/lib/libssl.a" 101 CRYPTO_LIBRARY="-DCRYPTO_LIBRARY=$WITH_SSL/lib/libcrypto.a" 102 elif test -e "$WITH_SSL/lib64/libssl.a" 103 then 104 OPENSSL_INCLUDE="-DOPENSSL_INCLUDE_DIR=$WITH_SSL/include" 105 OPENSSL_LIBRARY="-DOPENSSL_LIBRARY=$WITH_SSL/lib64/libssl.a" 106 CRYPTO_LIBRARY="-DCRYPTO_LIBRARY=$WITH_SSL/lib64/libcrypto.a" 107 else 108 echo >&2 "Cannot find libssl.a in $WITH_SSL" 109 exit 3 110 fi 111 ;; 112 -t | --tag ) 113 shift 114 TAG="$1" 115 shift 116 ;; 117 esac 118done 119 120# Working directory 121if test "$#" -eq 0 122then 123 WORKDIR="$(pwd)" 124 125 # Check that the current directory is not empty 126 if test "x$(echo *)" != "x*" 127 then 128 echo >&2 \ 129 "Current directory is not empty. Use $0 . to force build in ." 130 exit 1 131 fi 132elif test "$#" -eq 1 133then 134 WORKDIR="$1" 135 136 # Check that the provided directory exists and is a directory 137 if ! test -d "$WORKDIR" 138 then 139 echo >&2 "$WORKDIR is not a directory" 140 exit 1 141 fi 142else 143 echo >&2 "Usage: $0 [target dir]" 144 exit 1 145fi 146 147WORKDIR_ABS="$(cd "$WORKDIR"; pwd)" 148 149SOURCEDIR="$(cd $(dirname "$0"); cd ..; pwd)" 150test -e "$SOURCEDIR/MYSQL_VERSION" || exit 2 151 152# The number of processors is a good default for -j 153if test -e "/proc/cpuinfo" 154then 155 PROCESSORS="$(grep -c ^processor /proc/cpuinfo)" 156else 157 PROCESSORS=4 158fi 159 160# Extract version from the VERSION file 161source "$SOURCEDIR/MYSQL_VERSION" 162MYSQL_VERSION="$MYSQL_VERSION_MAJOR.$MYSQL_VERSION_MINOR.$MYSQL_VERSION_PATCH" 163PERCONA_SERVER_VERSION="$(echo $MYSQL_VERSION_EXTRA | sed 's/^-//')" 164PRODUCT="Percona-Server-$MYSQL_VERSION-$PERCONA_SERVER_VERSION" 165TOKUDB_BACKUP_VERSION="${MYSQL_VERSION}${MYSQL_VERSION_EXTRA}" 166 167# Build information 168if test -e "$SOURCEDIR/Docs/INFO_SRC" 169then 170 REVISION="$(cd "$SOURCEDIR"; grep '^short: ' Docs/INFO_SRC |sed -e 's/short: //')" 171elif [ -n "$(which git)" -a -d "$SOURCEDIR/.git" ]; 172then 173 REVISION="$(git rev-parse --short HEAD)" 174else 175 REVISION="" 176fi 177PRODUCT_FULL="Percona-Server-$MYSQL_VERSION-$PERCONA_SERVER_VERSION" 178PRODUCT_FULL="$PRODUCT_FULL-$TAG$(uname -s)${DIST_NAME:-}.$TARGET${GLIBC_VER:-}${TARBALL_SUFFIX:-}" 179COMMENT="Percona Server (GPL), Release ${MYSQL_VERSION_EXTRA#-}" 180COMMENT="$COMMENT, Revision $REVISION${BUILD_COMMENT:-}" 181 182# Compilation flags 183export CC=${CC:-gcc} 184export CXX=${CXX:-g++} 185 186# If gcc >= 4.8 we can use ASAN in debug build but not if valgrind build also 187if [[ $ENABLE_ASAN -eq 1 ]]; then 188 if [[ "$CMAKE_BUILD_TYPE" == "Debug" ]] && [[ "${CMAKE_OPTS:-}" != *WITH_VALGRIND=ON* ]]; then 189 GCC_VERSION=$(${CC} -dumpversion) 190 GT_VERSION=$(echo -e "4.8.0\n${GCC_VERSION}" | sort -t. -k1,1nr -k2,2nr -k3,3nr | head -1) 191 if [ "${GT_VERSION}" = "${GCC_VERSION}" ]; then 192 DEBUG_EXTRA="${DEBUG_EXTRA} -DWITH_ASAN=ON" 193 fi 194 fi 195fi 196 197# TokuDB cmake flags 198if test -d "$SOURCEDIR/storage/tokudb" 199then 200 CMAKE_OPTS="${CMAKE_OPTS:-} -DBUILD_TESTING=OFF -DUSE_GTAGS=OFF -DUSE_CTAGS=OFF -DUSE_ETAGS=OFF -DUSE_CSCOPE=OFF -DTOKUDB_BACKUP_PLUGIN_VERSION=${TOKUDB_BACKUP_VERSION}" 201 202 if test "x$CMAKE_BUILD_TYPE" != "xDebug" 203 then 204 CMAKE_OPTS="${CMAKE_OPTS:-} -DTOKU_DEBUG_PARANOID=OFF" 205 else 206 CMAKE_OPTS="${CMAKE_OPTS:-} -DTOKU_DEBUG_PARANOID=ON" 207 fi 208 209 if [[ $CMAKE_OPTS == *WITH_VALGRIND=ON* ]] 210 then 211 CMAKE_OPTS="${CMAKE_OPTS:-} -DUSE_VALGRIND=ON" 212 fi 213fi 214 215# 216# Attempt to remove any optimisation flags from the debug build 217# BLD-238 - bug1408232 218if [ -n "$(which rpm)" ]; then 219 export COMMON_FLAGS=$(rpm --eval %optflags | sed -e "s|march=i386|march=i686|g") 220 if test "x$CMAKE_BUILD_TYPE" = "xDebug" 221 then 222 COMMON_FLAGS=`echo " ${COMMON_FLAGS} " | \ 223 sed -e 's/ -O[0-9]* / /' \ 224 -e 's/-Wp,-D_FORTIFY_SOURCE=2/ /' \ 225 -e 's/ -unroll2 / /' \ 226 -e 's/ -ip / /' \ 227 -e 's/^ //' \ 228 -e 's/ $//'` 229 fi 230fi 231# 232export COMMON_FLAGS="$COMMON_FLAGS -DPERCONA_INNODB_VERSION=$PERCONA_SERVER_VERSION" 233export CFLAGS="$COMMON_FLAGS ${CFLAGS:-}" 234export CXXFLAGS="$COMMON_FLAGS ${CXXFLAGS:-}" 235# 236export MAKE_JFLAG="${MAKE_JFLAG:--j$PROCESSORS}" 237# 238# Create a temporary working directory 239INSTALLDIR="$(cd "$WORKDIR" && TMPDIR="$WORKDIR_ABS" mktemp -d percona-build.XXXXXX)" 240INSTALLDIR="$WORKDIR_ABS/$INSTALLDIR" # Make it absolute 241 242# Test jemalloc directory 243if test "x$WITH_JEMALLOC" != "x" 244then 245 if ! test -d "$WITH_JEMALLOC" 246 then 247 echo >&2 "Jemalloc dir $WITH_JEMALLOC does not exist" 248 exit 1 249 fi 250 251 JEMALLOCDIR="$(cd "$WITH_JEMALLOC"; pwd)" 252fi 253 254# Build 255( 256 rm -rf "$WORKDIR_ABS/bld" 257 mkdir "$WORKDIR_ABS/bld" 258 cd "$WORKDIR_ABS/bld" 259 260 cmake $SOURCEDIR ${CMAKE_OPTS:-} -DBUILD_CONFIG=mysql_release \ 261 -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE:-RelWithDebInfo} \ 262 $DEBUG_EXTRA \ 263 -DWITH_EMBEDDED_SERVER=OFF \ 264 -DFEATURE_SET=community \ 265 -DENABLE_DTRACE=OFF \ 266 -DWITH_SSL="$WITH_SSL_TYPE" \ 267 -DWITH_ZLIB=system \ 268 -DCMAKE_INSTALL_PREFIX="/usr/local/$PRODUCT_FULL" \ 269 -DMYSQL_DATADIR="/usr/local/$PRODUCT_FULL/data" \ 270 -DCOMPILATION_COMMENT="$COMMENT" \ 271 -DWITH_PAM=ON \ 272 -DWITH_ROCKSDB=ON \ 273 -DROCKSDB_DISABLE_MARCH_NATIVE=1 \ 274 -DROCKSDB_DISABLE_AVX2=1 \ 275 -DWITH_INNODB_MEMCACHED=ON \ 276 -DDOWNLOAD_BOOST=1 \ 277 -DWITH_SCALABILITY_METRICS=ON \ 278 -DWITH_BOOST="$WORKDIR_ABS/libboost" \ 279 $WITH_MECAB_OPTION $OPENSSL_INCLUDE $OPENSSL_LIBRARY $CRYPTO_LIBRARY 280 281 make $MAKE_JFLAG $QUIET 282 make DESTDIR="$INSTALLDIR" install 283 284 # Build jemalloc 285 if test "x$WITH_JEMALLOC" != x 286 then 287 ( 288 cd "$JEMALLOCDIR" 289 290 unset CFLAGS 291 unset CXXFLAGS 292 293 ./autogen.sh 294 ./configure --prefix="/usr/local/$PRODUCT_FULL/" \ 295 --libdir="/usr/local/$PRODUCT_FULL/lib/mysql/" 296 make $MAKE_JFLAG 297 make DESTDIR="$INSTALLDIR" install_lib_shared 298 299 # Copy COPYING file 300 cp COPYING "$INSTALLDIR/usr/local/$PRODUCT_FULL/COPYING-jemalloc" 301 ) 302 fi 303) 304 305# Patch needed libraries 306( 307 LIBLIST="libcrypto.so libssl.so libreadline.so libtinfo.so libsasl2.so libssl3.so libsmime3.so libnss3.so libnssutil3.so libplds4.so libplc4.so libnspr4.so libncurses.so" 308 DIRLIST="bin lib lib/private lib/mysql/plugin" 309 310 LIBPATH="" 311 312 function gather_libs { 313 local elf_path=$1 314 for lib in ${LIBLIST}; do 315 for elf in $(find ${elf_path} -maxdepth 1 -exec file {} \; | grep 'ELF ' | cut -d':' -f1); do 316 IFS=$'\n' 317 for libfromelf in $(ldd ${elf} | grep ${lib} | awk '{print $3}'); do 318 lib_realpath="$(readlink -f ${libfromelf})" 319 lib_realpath_basename="$(basename $(readlink -f ${libfromelf}))" 320 lib_without_version_suffix=$(echo ${lib_realpath_basename} | awk -F"." 'BEGIN { OFS = "." }{ print $1, $2}') 321 322 if [ ! -f "lib/private/${lib_realpath_basename}" ] && [ ! -L "lib/private/${lib_without_version_suffix}" ]; then 323 324 echo "Copying lib ${lib_realpath_basename}" 325 cp ${lib_realpath} lib/private 326 327 echo "Symlinking lib from ${lib_realpath_basename} to ${lib_without_version_suffix}" 328 cd lib/ 329 ln -s private/${lib_realpath_basename} ${lib_without_version_suffix} 330 cd - 331 if [ ${lib_realpath_basename} != ${lib_without_version_suffix} ]; then 332 cd lib/private 333 ln -s ${lib_realpath_basename} ${lib_without_version_suffix} 334 cd - 335 fi 336 337 patchelf --set-soname ${lib_without_version_suffix} lib/private/${lib_realpath_basename} 338 339 LIBPATH+=" $(echo ${libfromelf} | grep -v $(pwd))" 340 fi 341 done 342 unset IFS 343 done 344 done 345 } 346 347 function set_runpath { 348 # Set proper runpath for bins but check before doing anything 349 local elf_path=$1 350 local r_path=$2 351 for elf in $(find ${elf_path} -maxdepth 1 -exec file {} \; | grep 'ELF ' | cut -d':' -f1); do 352 echo "Checking LD_RUNPATH for ${elf}" 353 if [ -z $(patchelf --print-rpath ${elf}) ]; then 354 echo "Changing RUNPATH for ${elf}" 355 patchelf --set-rpath ${r_path} ${elf} 356 fi 357 done 358 } 359 360 function replace_libs { 361 local elf_path=$1 362 for libpath_sorted in ${LIBPATH}; do 363 for elf in $(find ${elf_path} -maxdepth 1 -exec file {} \; | grep 'ELF ' | cut -d':' -f1); do 364 LDD=$(ldd ${elf} | grep ${libpath_sorted}|head -n1|awk '{print $1}') 365 lib_realpath_basename="$(basename $(readlink -f ${libpath_sorted}))" 366 lib_without_version_suffix="$(echo ${lib_realpath_basename} | awk -F"." 'BEGIN { OFS = "." }{ print $1, $2}')" 367 if [[ ! -z $LDD ]]; then 368 echo "Replacing lib ${lib_realpath_basename} to ${lib_without_version_suffix} for ${elf}" 369 patchelf --replace-needed ${LDD} ${lib_without_version_suffix} ${elf} 370 fi 371 done 372 done 373 } 374 375 function check_libs { 376 local elf_path=$1 377 for elf in $(find ${elf_path} -maxdepth 1 -exec file {} \; | grep 'ELF ' | cut -d':' -f1); do 378 if ! ldd ${elf}; then 379 exit 1 380 fi 381 done 382 } 383 384 function link { 385 if [ ! -d lib/private ]; then 386 mkdir -p lib/private 387 fi 388 # Gather libs 389 for DIR in $DIRLIST; do 390 gather_libs ${DIR} 391 done 392 # Set proper runpath 393 set_runpath bin '$ORIGIN/../lib/private/' 394 set_runpath lib '$ORIGIN/private/' 395 set_runpath lib/mysql/plugin '$ORIGIN/../../private/' 396 set_runpath lib/private '$ORIGIN' 397 # Replace libs 398 for DIR in $DIRLIST; do 399 replace_libs ${DIR} 400 done 401 # Make final check in order to determine any error after linkage 402 for DIR in $DIRLIST; do 403 check_libs ${DIR} 404 done 405 } 406 407 if [[ $CMAKE_BUILD_TYPE != "Debug" ]]; then 408 mkdir $INSTALLDIR/usr/local/minimal 409 cp -r "$INSTALLDIR/usr/local/$PRODUCT_FULL" "$INSTALLDIR/usr/local/minimal/$PRODUCT_FULL-minimal" 410 fi 411 412 # NORMAL TARBALL 413 cd "$INSTALLDIR/usr/local/$PRODUCT_FULL" 414 link 415 416 # MIN TARBALL 417 if [[ $CMAKE_BUILD_TYPE != "Debug" ]]; then 418 cd "$INSTALLDIR/usr/local/minimal/$PRODUCT_FULL-minimal" 419 rm -rf mysql-test 2> /dev/null 420 find . -type f -exec file '{}' \; | grep ': ELF ' | cut -d':' -f1 | xargs strip --strip-unneeded 421 link 422 fi 423) 424 425# Package the archive 426( 427 cd "$INSTALLDIR/usr/local/" 428 #PS-4854 Percona Server for MySQL tarball without AGPLv3 dependency/license 429 find $PRODUCT_FULL -type f -name 'COPYING.AGPLv3' -delete 430 $TAR --owner=0 --group=0 -czf "$WORKDIR_ABS/$PRODUCT_FULL.tar.gz" $PRODUCT_FULL 431 432 if [[ $CMAKE_BUILD_TYPE != "Debug" ]]; then 433 cd "$INSTALLDIR/usr/local/minimal/" 434 find $PRODUCT_FULL-minimal -type f -name 'COPYING.AGPLv3' -delete 435 $TAR --owner=0 --group=0 -czf "$WORKDIR_ABS/$PRODUCT_FULL-minimal.tar.gz" $PRODUCT_FULL-minimal 436 fi 437) 438 439# Clean up 440rm -rf "$INSTALLDIR" 441rm -rf "$WORKDIR_ABS/libboost" 442rm -rf "$WORKDIR_ABS/bld" 443 444