-
Notifications
You must be signed in to change notification settings - Fork 2
/
build_grpc.sh
executable file
·285 lines (242 loc) · 9.72 KB
/
build_grpc.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
#!/usr/bin/env bash
# Script to build gRPC with support for Travis
# Script parameters:
# 1st arg [optional]: gRPC version (tag/branch) to clone, ex: v1.0.1 (default: master)
GRPCTAG=${1-master}
# 2nd arg [optional]: pass value 'envsetup-only' to do all the build preparation (git clone, cmake download, ...) without doing any build.
readonly BUILD_TYPE=${2-full}
# change default compiler (gcc) via CC/CXX env var
readonly CC=${CC-gcc}
readonly CXX=${CXX-g++}
function exit_failure {
echo "================"
echo -e "\e[31mERROR: ${1:-"something failed!"}\e[39m" 1>&2
exit 1
}
function print_info {
echo -e "\e[36m$1\e[39m"
}
readonly GRPCDIR=`pwd`/grpc
readonly ARCH=`uname -m`
declare COMPILER=$CC
function check_compiler {
if [[ "$CC" == "gcc"* ]]; then
local GCCVER=`$CC -v 2>&1 | grep "gcc version" | awk '{print $3}'`
print_info "Detected gcc version $GCCVER"
# build fails with gcc < 4.8
if [[ ! $GCCVER =~ [5-9].[0-9].[0-9] ]] && [[ ! $GCCVER =~ 4.[8-9].[0-9] ]]; then
exit_failure "GCC >= 4.8 is required! Restart the script with 'env CC=gcc-5 CXX=g++-5' or similar."
fi
COMPILER="gcc-$GCCVER"
elif [[ "$CC" == "clang"* ]]; then
# build fails with clang < 3.5
local CLANGVER=`$CC -v 2>&1 | grep "clang version" | sed 's/^.*clang version *//' | sed 's/-.*//'`
print_info "Detected clang version $CLANGVER"
if [[ ! $CLANGVER =~ 3.[5-9].[0-9] ]]; then
exit_failure "clang >= 3.5 is required! Restart the script with 'env CC=clang-3.5 CXX=clang-3.5' or similar."
fi
COMPILER="clang-$CLANGVER"
else
exit_failure "Update the script to support compiler '$CC'"
fi
print_info "Detected compiler $COMPILER"
}
function check_go {
go version &> /dev/null || exit_failure "go is missing! run 'sudo apt-get install -y golang'"
}
function check_cmake {
if ! cmake -version &> /dev/null ; then
print_info "CMake was not found on the system"
else
local CMAKE_VER=`cmake -version | head -n 1`
fi
# if no local cmake available, check that global cmake version is 3.x
# as required to build grpc
if [[ "$CMAKE_VER" != *"version 3."* ]]; then
print_info "CMake is missing or existing version is too old, using a local version"
if [[ ! -d "cmake" ]]; then
./install_local_cmake.sh
fi
if [[ -f "cmake/bin/cmake" ]]; then
print_info "Found local cmake"
PATH=`pwd`/cmake/bin:$PATH
else
exit_failure "local cmake version not found!"
fi
else
print_info "Using global (system) cmake"
fi
# print cmake version
local CMAKE_VER=`cmake -version | head -n 1`
print_info "CMake: $CMAKE_VER"
}
function get_grpc_source_code {
# clone the repo + the submodules
if [[ ! -d $GRPCDIR ]]; then
print_info "Could not find grpc source dir, cloning $GRPCTAG from repo"
git clone -b $GRPCTAG --depth 1 --recursive https://github.com/grpc/grpc.git || exit_failure
else
GRPCTAG=`cd $GRPCDIR && git tag`
if [[ "$GRPCTAG" == "" ]]; then
GRPCTAG=`cd $GRPCDIR && git rev-parse --abbrev-ref HEAD`
fi
fi
print_info "gRPC source version $GRPCTAG"
}
function patch_for_arm_support {
# the CMakeFile of boringssl accepts only "armv6" and "armv7-a"
# which makes it fails with standard values "armv6l" and "armv7l"
if [[ "$ARCH" == "armv"* ]]; then
print_info "ARM detected ($ARCH): patching boringssl for better support"
local CMFILE=$GRPCDIR/third_party/boringssl/CMakeLists.txt
sed -i -- 's/STREQUAL "armv6"/MATCHES "^armv6*"/g' $CMFILE || exit_failure
sed -i -- 's/STREQUAL "armv7-a"/MATCHES "^armv7*"/g' $CMFILE || exit_failure
fi
}
function patch_zlib_makefile {
# For some reason, when grpc/third_party/zlib/CMakeLists.txt is triggered from grpc build
# it will make the zlib examples to be built with the system headers of zlib (/usr/include/zlib.h)
# instead of the local header file.
# And on old system like on Travis-CI VMs (Ubuntu 14.04) the installed zlib is too old and will make
# the build to fail. So the quick fix here is to simply remove the build of those examples.
local CMFILE=$GRPCDIR/third_party/zlib/CMakeLists.txt
# 1st step: find the line number of the text marking the begining of the example stuff
local LINE_NUMBER=`awk '/Example binaries/{ print NR; exit }' $CMFILE`
if [[ "$LINE_NUMBER" != "" ]]; then
print_info "Patching file '$CMFILE' to fix possible build issue"
sed -i -n "1,$((LINE_NUMBER-1)) p" $CMFILE
fi
}
function patch_grpc_makefile {
# fix missing lib in cmake file (causing link errors on ubuntu 14.04):
# libgpr.a(time_posix.c.o): In function `now_impl':
# time_posix.c:(.text+0xe2): undefined reference to `clock_gettime'
local CMFILE=$GRPCDIR/CMakeLists.txt
local STR="target_link_libraries(gpr rt)"
if ! grep -q "$STR" "$CMFILE"; then # avoid applying the patch several times
echo $STR >> $CMFILE
fi
}
function patch_protobuf_install_path {
# fix "make install" issue with protobuf
local CMFILE=$GRPCDIR/third_party/protobuf/cmake/install.cmake
#local STR="install(DIRECTORY ${CMAKE_BINARY_DIR}\/${CMAKE_INSTALL_CMAKEDIR}"
local STR1="install(DIRECTORY \${CMAKE_BINARY_DIR}\/\${"
local STR2="install(DIRECTORY \${CMAKE_BINARY_DIR}\/third_party\/protobuf\/\${"
sed -i "s/$STR1/$STR2/g" $CMFILE
}
function create_build_info_file {
# add some infos about the build env that was used to build this package
echo "# System used to build this package" > $PCKGDIR/about.txt
echo "" >> $PCKGDIR/about.txt
uname -a >> $PCKGDIR/about.txt
echo "" >> $PCKGDIR/about.txt
echo "# Build time (cmake + make)" >> $PCKGDIR/about.txt
echo "" >> $PCKGDIR/about.txt
echo "Debug: $DEBUG_BUILD_TIME" >> $PCKGDIR/about.txt
echo "Release: $RELEASE_BUILD_TIME" >> $PCKGDIR/about.txt
echo "Total: $TOTAL_BUILD_TIME" >> $PCKGDIR/about.txt
echo "using $NPROC parallel job(s)" >> $PCKGDIR/about.txt
echo "" >> $PCKGDIR/about.txt
echo "# Compiler" >> $PCKGDIR/about.txt
echo "" >> $PCKGDIR/about.txt
$CC -v &>> $PCKGDIR/about.txt
echo "" >> $PCKGDIR/about.txt
echo "# CPU" >> $PCKGDIR/about.txt
echo "" >> $PCKGDIR/about.txt
lscpu >> $PCKGDIR/about.txt
}
function create_grpc_package {
local PCKGDIR=grpc-$GRPCTAG-linux-$COMPILER-$ARCH
print_info "Preparing package structure '$PCKGDIR'"
mkdir -p $PCKGDIR/bin || exit_failure
cp release/grpc_*_plugin $PCKGDIR/bin/
cp release/third_party/protobuf/protoc $PCKGDIR/bin/
cp -R $GRPCDIR/include/ $PCKGDIR/include/ || exit_failure
# add protobud includes + compiler
mv release/$PROTOBUF_INSTALLDIR/include/* $PCKGDIR/include/ || exit_failure
mv release/$PROTOBUF_INSTALLDIR/bin/* $PCKGDIR/bin/ || exit_failure
for CFG in debug release
do
mkdir -p $PCKGDIR/lib/$CFG
cp $CFG/*.a $PCKGDIR/lib/$CFG/
rm $PCKGDIR/lib/$CFG/libgrpc_cronet.a
rm $PCKGDIR/lib/$CFG/libgrpc_csharp_ext.a
rm $PCKGDIR/lib/$CFG/libgrpc_plugin_support.a
cp $CFG/third_party/zlib/libz.a $PCKGDIR/lib/$CFG/
cp $CFG/third_party/boringssl/ssl/libssl.a $PCKGDIR/lib/$CFG/
# add protobuf libs
cp $CFG/$PROTOBUF_INSTALLDIR/lib/*.a $PCKGDIR/lib/$CFG/
done
create_build_info_file
# compress package
print_info "Compressing to $PCKGDIR.tar.gz..."
GZIP=-9 tar czf $PCKGDIR.tar.gz $PCKGDIR || exit_failure
mv -f $PCKGDIR.tar.gz ..
popd
}
function share_build_times {
local FILE=build-times.md
if [[ ! -f $FILE ]]; then
echo "| compiler | total | debug | release" > $FILE
echo "|-------------|------------|-------------|-------------" >> $FILE
fi
echo "| $COMPILER | $TOTAL_BUILD_TIME | $DEBUG_BUILD_TIME | $RELEASE_BUILD_TIME" >> $FILE
}
print_info "Starting build type=$BUILD_TYPE"
check_compiler
check_cmake
check_go
get_grpc_source_code
patch_zlib_makefile
patch_grpc_makefile
patch_for_arm_support
patch_protobuf_install_path
print_info "Build env setup complete"
if [[ "$BUILD_TYPE" == "envsetup-only" ]]; then
print_info "Stopping here because build type=$BUILD_TYPE"
exit 0
fi
print_info "Compiler variables: CC=$CC CXX=$CXX"
# run make in parallel if possible
readonly NPROC=`nproc --all`
if [[ "$NPROC" -gt "1" ]]; then
MAKEJ="-j $NPROC"
print_info "Enabling parallel build for $NPROC cores"
fi
readonly BUILDDIR=grpc-build
readonly PROTOBUF_INSTALLDIR=protobuf-install
# create new build dir
if [[ -d $BUILDDIR ]]; then
print_info "Cleaning previous build dir"
rm -rf $BUILDDIR
fi
mkdir $BUILDDIR || exit_failure
pushd $BUILDDIR
# build in debug
mkdir debug && pushd debug
cmake -DCMAKE_INSTALL_PREFIX=`pwd`/$PROTOBUF_INSTALLDIR -DCMAKE_BUILD_TYPE=Debug $GRPCDIR || exit_failure
SECONDS=0
make $MAKEJ || exit_failure
TOTAL_SECONDS=$SECONDS
readonly DEBUG_BUILD_TIME="$(($SECONDS / 60)) min $(($SECONDS % 60)) sec"
make install || exit_failure # protobuf
print_info "Debug build time: $DEBUG_BUILD_TIME"
popd
# build in release
mkdir release && pushd release
cmake -DCMAKE_INSTALL_PREFIX=`pwd`/$PROTOBUF_INSTALLDIR -DCMAKE_BUILD_TYPE=Release $GRPCDIR || exit_failure
SECONDS=0
make $MAKEJ || exit_failure
readonly RELEASE_BUILD_TIME="$(($SECONDS / 60)) min $(($SECONDS % 60)) sec"
TOTAL_SECONDS=$((TOTAL_SECONDS + SECONDS))
make install || exit_failure # protobuf
readonly TOTAL_BUILD_TIME="$(($TOTAL_SECONDS / 60)) min $(($TOTAL_SECONDS % 60)) sec"
print_info "Release build time: $RELEASE_BUILD_TIME"
print_info "Total build time: $TOTAL_BUILD_TIME"
popd
create_grpc_package
share_build_times
print_info "Cleaning..."
rm -rf $BUILDDIR
print_info "Done!"