1#!/bin/bash
2#
3# Execute this tool to setup the environment and build binary releases
4# for xtrabackup 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=''
18
19# Some programs that may be overriden
20TAR=${TAR:-tar}
21
22# Check if we have a functional getopt(1)
23if ! getopt --test
24then
25    go_out="$(getopt --options="i" --longoptions=i686 \
26        --name="$(basename "$0")" -- "$@")"
27    test $? -eq 0 || exit 1
28    eval set -- $go_out
29fi
30
31for arg
32do
33    case "$arg" in
34    -- ) shift; break;;
35    -i | --i686 )
36        shift
37        TARGET="i686"
38        TARGET_CFLAGS="-m32 -march=i686"
39        ;;
40    esac
41done
42
43# Working directory
44if test "$#" -eq 0
45then
46    WORKDIR="$(readlink -f $(dirname $0)/../../../../)"
47
48    # Check that the current directory is not empty
49    if test "x$(echo *)" != "x*"
50    then
51        echo >&2 \
52            "Current directory is not empty. Use $0 . to force build in ."
53        exit 1
54    fi
55
56    WORKDIR_ABS="$(cd "$WORKDIR"; pwd)"
57
58elif test "$#" -eq 1
59then
60    WORKDIR="$1"
61
62    # Check that the provided directory exists and is a directory
63    if ! test -d "$WORKDIR"
64    then
65        echo >&2 "$WORKDIR is not a directory"
66        exit 1
67    fi
68
69    WORKDIR_ABS="$(cd "$WORKDIR"; pwd)"
70
71else
72    echo >&2 "Usage: $0 [target dir]"
73    exit 1
74
75fi
76
77SOURCEDIR="$(cd $(dirname "$0"); cd ../../../../; pwd)"
78test -e "$SOURCEDIR/XB_VERSION" || exit 2
79
80# Read version info from the XB_VERSION file
81. $SOURCEDIR/XB_VERSION
82
83XTRABACKUP_VERSION="${XB_VERSION_MAJOR}.${XB_VERSION_MINOR}.${XB_VERSION_PATCH}${XB_VERSION_EXTRA}"
84
85# Compilation flags
86export CC=${CC:-gcc}
87export CXX=${CXX:-g++}
88export CFLAGS=${CFLAGS:-}
89export CXXFLAGS=${CXXFLAGS:-}
90export MAKE_JFLAG=-j4
91
92# Create a temporary working directory
93PRODUCT_FULL="percona-xtrabackup-$XTRABACKUP_VERSION-$(uname -s)-$(uname -m)$GLIBC_VER"
94BASEINSTALLDIR="$(cd "$WORKDIR" && TMPDIR="$WORKDIR_ABS" mktemp -d xtrabackup-build.XXXXXX)"
95INSTALLDIR="$WORKDIR_ABS/$BASEINSTALLDIR/$PRODUCT_FULL"   # Make it absolute
96
97mkdir "$INSTALLDIR"
98
99# Build
100(
101    cd "$WORKDIR"
102
103    # Build proper
104    (
105	cd $SOURCEDIR
106
107        # Install the files
108        mkdir -p "$INSTALLDIR"
109        cmake -DBUILD_CONFIG=xtrabackup_release -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" \
110          -DINSTALL_MYSQLTESTDIR=percona-xtrabackup-${XB_VERSION_MAJOR}.${XB_VERSION_MINOR}-test -DINSTALL_MANDIR=${INSTALLDIR}/man \
111          -DDOWNLOAD_BOOST=1 -DWITH_BOOST=${WORKDIR_ABS}/libboost \
112          -DMYSQL_UNIX_ADDR=/var/run/mysqld/mysqld.sock .
113        make $MAKE_JFLAG
114        make install
115
116    )
117    exit_value=$?
118
119    if test "x$exit_value" = "x0"
120    then
121    cd $INSTALLDIR
122
123    LIBLIST="libgcrypt.so libcrypto.so libssl.so libsasl2.so libssl3.so libsmime3.so libnss3.so libnssutil3.so libplds4.so libplc4.so libnspr4.so"
124    DIRLIST="bin lib/private lib/plugin"
125
126    LIBPATH=""
127
128    function gather_libs {
129        local elf_path=$1
130        for lib in ${LIBLIST}; do
131            for elf in $(find ${elf_path} -maxdepth 1 -exec file {} \; | grep 'ELF ' | cut -d':' -f1); do
132                IFS=$'\n'
133                for libfromelf in $(ldd ${elf} | grep ${lib} | awk '{print $3}'); do
134                    lib_realpath="$(readlink -f ${libfromelf})"
135                    lib_realpath_basename="$(basename $(readlink -f ${libfromelf}))"
136                    lib_without_version_suffix=$(echo ${lib_realpath_basename} | awk -F"." 'BEGIN { OFS = "." }{ print $1, $2}')
137
138                    if [ ! -f "lib/private/${lib_realpath_basename}" ] && [ ! -L "lib/private/${lib_without_version_suffix}" ]; then
139
140                        echo "Copying lib ${lib_realpath_basename}"
141                        cp ${lib_realpath} lib/private
142
143                        if [ ${lib_realpath_basename} != ${lib_without_version_suffix} ]; then
144                            echo "Symlinking lib from ${lib_realpath_basename} to ${lib_without_version_suffix}"
145                            cd lib/private
146                            ln -s ${lib_realpath_basename} ${lib_without_version_suffix}
147                            cd -
148                        fi
149
150                        patchelf --set-soname ${lib_without_version_suffix} lib/private/${lib_realpath_basename}
151
152                        LIBPATH+=" $(echo ${libfromelf} | grep -v $(pwd))"
153                    fi
154                done
155                unset IFS
156            done
157        done
158        }
159
160    function set_runpath {
161        # Set proper runpath for bins but check before doing anything
162        local elf_path=$1
163        local r_path=$2
164        for elf in $(find ${elf_path} -maxdepth 1 -exec file {} \; | grep 'ELF ' | cut -d':' -f1); do
165            echo "Checking LD_RUNPATH for ${elf}"
166            if [ -z $(patchelf --print-rpath ${elf}) ]; then
167                echo "Changing RUNPATH for ${elf}"
168                patchelf --set-rpath ${r_path} ${elf}
169            fi
170        done
171    }
172
173    function replace_libs {
174        local elf_path=$1
175        for libpath_sorted in ${LIBPATH}; do
176            for elf in $(find ${elf_path} -maxdepth 1 -exec file {} \; | grep 'ELF ' | cut -d':' -f1); do
177                LDD=$(ldd ${elf} | grep ${libpath_sorted}|head -n1|awk '{print $1}')
178                lib_realpath_basename="$(basename $(readlink -f ${libpath_sorted}))"
179                lib_without_version_suffix="$(echo ${lib_realpath_basename} | awk -F"." 'BEGIN { OFS = "." }{ print $1, $2}')"
180                if [[ ! -z $LDD  ]]; then
181                    echo "Replacing lib ${lib_realpath_basename} to ${lib_without_version_suffix} for ${elf}"
182                    patchelf --replace-needed ${LDD} ${lib_without_version_suffix} ${elf}
183                fi
184            done
185        done
186    }
187
188    function check_libs {
189        local elf_path=$1
190        for elf in $(find ${elf_path} -maxdepth 1 -exec file {} \; | grep 'ELF ' | cut -d':' -f1); do
191            if ! ldd ${elf}; then
192                exit 1
193            fi
194        done
195    }
196
197    function link {
198        if [ ! -d lib/private ]; then
199            mkdir -p lib/private
200        fi
201        # Gather libs
202        for DIR in ${DIRLIST}; do
203            gather_libs ${DIR}
204        done
205
206        # Set proper runpath
207        set_runpath bin '$ORIGIN/../lib/private/'
208        set_runpath lib '$ORIGIN/private/'
209        set_runpath lib/plugin '$ORIGIN/../private/'
210        set_runpath lib/private '$ORIGIN'
211
212        # Replace libs
213        for DIR in ${DIRLIST}; do
214            replace_libs ${DIR}
215        done
216
217        # Make final check in order to determine any error after linkage
218        for DIR in ${DIRLIST}; do
219            check_libs ${DIR}
220        done
221    }
222
223    cd "$WORKDIR"
224
225    mkdir "$WORKDIR_ABS/$BASEINSTALLDIR/minimal"
226    cp -r "$WORKDIR_ABS/$BASEINSTALLDIR/$PRODUCT_FULL" "$WORKDIR_ABS/$BASEINSTALLDIR/minimal/$PRODUCT_FULL-minimal"
227
228    # NORMAL TARBALL
229    cd "$INSTALLDIR"
230    link
231
232    cd "$WORKDIR_ABS/$BASEINSTALLDIR/minimal/$PRODUCT_FULL-minimal"
233    rm -rf percona-xtrabackup-2.4-test 2> /dev/null
234    find . -type f -exec file '{}' \; | grep ': ELF ' | cut -d':' -f1 | xargs strip --strip-unneeded
235    link
236
237    cd "$WORKDIR"
238    $TAR czf "percona-xtrabackup-$XTRABACKUP_VERSION-$(uname -s)-$(uname -m)$GLIBC_VER.tar.gz" \
239        --owner=0 --group=0 -C "$INSTALLDIR/../" \
240        "percona-xtrabackup-$XTRABACKUP_VERSION-$(uname -s)-$(uname -m)$GLIBC_VER"
241
242    $TAR czf "percona-xtrabackup-$XTRABACKUP_VERSION-$(uname -s)-$(uname -m)$GLIBC_VER-minimal.tar.gz" \
243        --owner=0 --group=0 -C "$INSTALLDIR/../minimal/" \
244        "percona-xtrabackup-$XTRABACKUP_VERSION-$(uname -s)-$(uname -m)$GLIBC_VER-minimal"
245    fi
246
247    # Clean up build dir
248    rm -rf "percona-xtrabackup-$XTRABACKUP_VERSION-$(uname -s)-$(uname -m)$GLIBC_VER"
249
250    exit $exit_value
251
252)
253exit_value=$?
254
255# Clean up
256rm -rf "$WORKDIR_ABS/$BASEINSTALLDIR"
257
258exit $exit_value
259
260