blob: 9743872a31bc28b7ee3a1846f9f4f82770f120a9 [file] [log] [blame]
David 'Digit' Turner063cfe12013-02-19 17:08:14 +01001#!/bin/sh
2#
3
4set -e
5export LANG=C
6export LC_ALL=C
7
8PROGDIR=$(dirname "$0")
9PROGNAME=$(basename "$0")
10
11panic () {
12 echo "ERROR: $@"
13 exit 1
14}
15
16VERBOSE=1
17
18# Dump message is $VERBOSE >= $1
19# $1+: message.
20dump_n () {
21 local LOG_LEVEL=$1
22 shift
23 if [ "$VERBOSE" -ge "$LOG_LEVEL" ]; then
24 printf "%s\n" "$@"
25 fi
26}
27
28# Dump a message unless --quiet is used.
29# $1+: message.
30dump () {
31 dump_n 1 "$@"
32}
33
34# Dump a message if --verbose is used only.
35# $1+: message.
36log () {
37 dump_n 2 "$@"
38}
39
40# Run a command silently, unless --verbose or '--verbose --verbose'
41# is used.
42# $1+: Command
43# Return: command status.
44run () {
45 log "COMMAND: $*"
46 case $VERBOSE in
47 0)
48 "$@" >/dev/null 2>&1 || return $?
49 ;;
50 1)
51 "$@" >/dev/null || return $?
52 ;;
53 *)
54 "$@" || return $?
55 ;;
56 esac
57}
58
59# $1: string
60# Out: input string, with capital letters replaced by small ones.
61tolower () {
62 echo "$1" | tr '[A-Z]' '[a-z]'
63}
64
65# Return value of a given variable.
66# $1: Variable name
67var_value () {
68 eval printf \"%s\" \"\$$1\"
69}
70
71# Remove some items from a list
72# $1: input space-separated list
73# $2: space-separated list of items to remove from 1
74# Out: items of $1 without items of $2
75filter_out () {
76 local TMP=$(mktemp)
77 local RESULT
78 printf "" > $TMP
79 echo "$2" | tr ' ' '\n' > $TMP
80 RESULT=$(echo "$1" | tr ' ' '\n' | fgrep -x -v -f $TMP | tr '\n' ' ')
81 rm -f $TMP
82 echo "$RESULT"
83}
84
85src_to_obj () {
86 case $1 in
87 *.c)
88 echo ${1%%.c}.o
89 ;;
90 *.S)
91 echo ${1%%.S}.o
92 ;;
93 *)
94 echo $1
95 ;;
96 esac
97}
98
99# Determine host operating system.
100HOST_OS=$(uname -s)
101case $HOST_OS in
102 Linux)
103 HOST_OS=linux
104 ;;
105 Darwin)
106 HOST_OS=darwin
107 ;;
108esac
109
110# Determine host architecture
111HOST_ARCH=$(uname -m)
112case $HOST_ARCH in
113 i?86)
114 HOST_ARCH=x86
115 ;;
116esac
117
118ANDROID_HOST_TAG=$HOST_OS-$HOST_ARCH
119
120case $ANDROID_HOST_TAG in
121 linux-x86_64|darwin-x86-64)
122 ANDROID_HOST_TAG=$HOST_OS-x86
123 ;;
124 *)
125 panic "Sorry, this script can only run on 64-bit Linux or Darwin"
126esac
127
128# Determine number of cores
129case $HOST_OS in
130 linux)
131 NUM_CORES=$(grep -c "processor" /proc/cpuinfo)
132 ;;
133 darwin)
134 NUM_CORES=$(sysctl -n hw.ncpu)
135 ;;
136 *)
137 NUM_CORES=1
138 ;;
139esac
140
141# The list of supported Android target architectures.
David 'Digit' Turner463519a2014-01-30 18:21:25 +0100142
143# NOTE: x86_64 is not ready yet, while the toolchain is in
144# prebuilts/ it doesn't have a sysroot which means it requires
145# a platform build to get Bionic and stuff.
Kenny Root8ad690d2014-06-19 03:26:58 -0700146ANDROID_ARCHS="arm arm64 x86 x86_64 mips"
David 'Digit' Turner063cfe12013-02-19 17:08:14 +0100147
148BUILD_TYPES=
149for ARCH in $ANDROID_ARCHS; do
150 BUILD_TYPES="$BUILD_TYPES android-$ARCH"
151done
152ANDROID_BUILD_TYPES=$BUILD_TYPES
153
David 'Digit' Turner063cfe12013-02-19 17:08:14 +0100154HOST_BUILD_TYPES="$HOST_OS-x86 $HOST_OS-generic32 $HOST_OS-generic64"
David 'Digit' Turner463519a2014-01-30 18:21:25 +0100155HOST_BUILD_TYPES="$HOST_BUILD_TYPES $HOST_OS-x86_64"
David 'Digit' Turner063cfe12013-02-19 17:08:14 +0100156
157BUILD_TYPES="$ANDROID_BUILD_TYPES $HOST_BUILD_TYPES"
158
159# Parse command-line
160DO_HELP=
161SRC_DIR=$(cd $PROGDIR && pwd)
162OUT_DIR=out
163BUILD_DIR=
164BUILD_TYPES=
165NUM_JOBS=$NUM_CORES
166ANDROID_BUILD_TOP=$(cd $PROGDIR/../.. && pwd)
167for OPT; do
168 case $OPT in
169 --help|-h|-?)
170 DO_HELP=true
171 ;;
172 --build-dir=*)
173 BUILD_DIR=${OPT##--build-dir=}
174 ;;
175 --verbose)
176 VERBOSE=$(( $VERBOSE + 1 ))
177 ;;
178 --jobs=*)
179 NUM_JOBS=${OPT##--jobs=}
180 ;;
181 --quiet)
182 VERBOSE=$(( $VERBOSE - 1 ))
183 ;;
184 -j*)
185 NUM_JOBS=${OPT##-j}
186 ;;
187 -*)
188 panic "Unknown option '$OPT', see --help for details."
189 ;;
190 *)
191 BUILD_TYPES="$BUILD_TYPES $OPT"
192 ;;
193 esac
194done
195
196# Print help when needed.
197if [ "$DO_HELP" ]; then
198 echo \
199"Usage: $PROGNAME [options] [<build-type> ...]
200
201This script is used to ensure that all OpenSSL build variants compile
202properly. It can be used after modifying external/openssl/openssl.config
203and re-running import_openssl.sh to check that any changes didn't break
204the build.
205
206A <build-type> is a description of a given build of the library and its
207program. Its format is:
208
209 <compiler>-<system>-<arch>
210
211Where: <compiler> is either 'gcc' or 'clang'.
212 <system> is 'android', 'linux' or 'darwin'.
213 <arch> is 'arm', 'x86' or 'mips'.
214
215By default, it rebuilds the sources for the following build types:
216"
217 for BUILD_TYPE in $BUILD_TYPES; do
218 echo " $BUILD_TYPE"
219 done
220
221 echo \
222"However, you can pass custom values on the command-line instead.
223
224This scripts generates a custom Makefile in a temporary directory, then
225launches 'make' in it to build all binaries in parallel. In case of
226problem, you can use the --build-dir=<path> option to specify a custom
227build-directory, which will _not_ be removed when the script exits.
228
229For example, to better see why a build fails:
230
231 ./$PROGNAME --build-dir=/tmp/mydir
232 make -C /tmp/mydir V=1
233
234Valid options:
235
236 --help|-h|-? Print this message.
237 --build-dir=<path> Specify build directory.
238 --jobs=<count> Run <count> parallel build jobs [$NUM_JOBS].
239 -j<count> Same as --jobs=<count>.
240 --verbose Increase verbosity.
241 --quiet Decrease verbosity.
242"
243 exit 0
244fi
245
246log "Host OS: $HOST_OS"
247log "Host arch: $HOST_ARCH"
248log "Host CPU count: $NUM_CORES"
249
250if [ -z "$BUILD_TYPES" ]; then
251 BUILD_TYPES="$ANDROID_BUILD_TYPES $HOST_BUILD_TYPES"
252fi
253log "Build types: $BUILD_TYPES"
254
255if [ -z "$BUILD_DIR" ]; then
256 # Create a temporary directory, ensure it gets destroyed properly
257 # when the script exits.
258 BUILD_DIR=$(mktemp -d)
259 clean_build_dir () {
260 log "Cleaning up temporary directory: $BUILD_DIR"
261 rm -rf "$BUILD_DIR"
262 exit $1
263 }
264 trap "clean_build_dir 0" EXIT
265 trap "clean_build_dir \$?" INT HUP QUIT TERM
266 log "Using temporary build directory: $BUILD_DIR"
267else
268 log "Using user build directory: $BUILD_DIR"
269fi
270
271mkdir -p "$BUILD_DIR" && rm -rf "$BUILD_DIR"/*
272
273MAKEFILE=$BUILD_DIR/GNUmakefile
274
275# Return source files for a given module and architecture.
276# $1: module prefix (e.g. CRYPTO)
277# $2: build arch.
278get_module_src_files_for_arch () {
279 local prefix=$1
280 local arch=$2
281 local src_files="$(var_value OPENSSL_${prefix}_SOURCES)"
282 src_files="$src_files $(var_value OPENSSL_${prefix}_SOURCES_${arch})"
283 local exclude_files="$(var_value OPENSSL_${prefix}_SOURCES_EXCLUDES_${arch})"
284 src_files=$(filter_out "$src_files" "$exclude_files")
285 echo "$src_files"
286}
287
288# Return the compiler defines for a given module and architecture
289# $1: module prefix (e.g. CRYPTO)
290# $2 build arch.
291get_module_defines_for_arch () {
292 local prefix=$1
293 local arch=$2
294 local defines="$(var_value OPENSSL_${prefix}_DEFINES)"
295 defines="$defines $(var_value OPENSSL_${prefix}_DEFINES_${arch})"
296 echo "$defines"
297}
298
299# $1: module prefix (e.g. CRYPTO)
300get_module_c_includes () {
301 var_value OPENSSL_$1_INCLUDES
302}
303
304# $1: build type (e.g. gcc-android-arm)
305# Out: build arch.
306get_build_arch () {
307 echo "$1" | cut -d- -f3
308}
309
310# $1: build arch
311# Out: GNU configuration target (e.g. arm-linux-androideabi)
312get_build_arch_target () {
313 case $1 in
Kenny Root8ad690d2014-06-19 03:26:58 -0700314 arm64)
315 echo "aarch64-linux-android"
316 ;;
David 'Digit' Turner063cfe12013-02-19 17:08:14 +0100317 arm)
318 echo "arm-linux-androideabi"
319 ;;
320 x86)
Kenny Root8ad690d2014-06-19 03:26:58 -0700321 echo "x86_64-linux-android"
David 'Digit' Turner063cfe12013-02-19 17:08:14 +0100322 ;;
David 'Digit' Turner463519a2014-01-30 18:21:25 +0100323 x86_64)
324 echo "x86_64-linux-android"
325 ;;
David 'Digit' Turner063cfe12013-02-19 17:08:14 +0100326 mips)
327 echo "mipsel-linux-android"
328 ;;
329 *)
330 echo "$1-linux-android"
331 ;;
332 esac
333}
334
Kenny Root8ad690d2014-06-19 03:26:58 -0700335GCC_VERSION=4.8
336CLANG_VERSION=3.2
David 'Digit' Turner063cfe12013-02-19 17:08:14 +0100337
338get_prebuilt_gcc_dir_for_arch () {
339 local arch=$1
340 local target=$(get_build_arch_target $arch)
David 'Digit' Turner463519a2014-01-30 18:21:25 +0100341 # Adjust $arch for x86_64 because the prebuilts are actually
342 # under prebuilts/gcc/<host>/x86/
343 case $arch in
344 x86_64)
345 arch=x86
346 ;;
Kenny Root8ad690d2014-06-19 03:26:58 -0700347 arm64)
348 arch=aarch64
349 ;;
David 'Digit' Turner463519a2014-01-30 18:21:25 +0100350 esac
David 'Digit' Turner063cfe12013-02-19 17:08:14 +0100351 echo "$ANDROID_BUILD_TOP/prebuilts/gcc/$ANDROID_HOST_TAG/$arch/$target-$GCC_VERSION"
352}
353
354get_prebuilt_clang () {
355 echo "$ANDROID_BUILD_TOP/prebuilts/clang/$ANDROID_HOST_TAG/$CLANG_VERSION/clang"
356}
357
358get_prebuilt_ndk_sysroot_for_arch () {
359 echo "$ANDROID_BUILD_TOP/prebuilts/ndk/current/platforms/android-9/arch-$1"
360}
361
362get_c_runtime_file () {
363 local build_type=$1
364 local arch=$(get_build_arch $build_type)
365 local filename=$2
366 echo "$(get_prebuilt_ndk_sysroot_for_arch $arch)/usr/lib/$filename"
367}
368
369# $1: build type (e.g. gcc-android-arm)
370get_build_compiler () {
371 local arch=$(get_build_arch $1)
372 local target=$(get_build_arch_target $arch)
373 local gcc_dir=$(get_prebuilt_gcc_dir_for_arch $arch);
374 local result
375
376 # Get the toolchain binary.
377 case $1 in
378 gcc-android-*)
379 result="$gcc_dir/bin/$target-gcc"
380 ;;
381 clang-android-*)
382 result="$(get_prebuilt_clang) -target $target -B$gcc_dir/$target/bin -I$gcc_dir/lib/gcc/$target/$GCC_VERSION/include"
383 ;;
384 gcc-*)
385 result=gcc
386 ;;
387 clang-*) # Must have host clang compiler.
388 result=clang
389 ;;
390 esac
391
392 compiler_check=$(which $result 2>/dev/null || echo "")
393 if [ -z "$compiler_check" ]; then
394 panic "Could not find compiler: $result"
395 fi
396
397 # Get the Android sysroot if needed.
398 case $1 in
399 *-android-*)
400 result="$result --sysroot=$(get_prebuilt_ndk_sysroot_for_arch $arch)"
401 ;;
402 esac
403
404 # Force -m32 flag when needed for 32-bit builds.
405 case $1 in
Kenny Root8ad690d2014-06-19 03:26:58 -0700406 *-x86|*-generic32)
David 'Digit' Turner063cfe12013-02-19 17:08:14 +0100407 result="$result -m32"
408 ;;
409 esac
410 echo "$result"
411}
412
413# $1: build type.
414# Out: common compiler flags for this build.
415get_build_c_flags () {
416 local result="-O2 -fPIC"
417 case $1 in
418 *-android-arm)
419 result="$result -march=armv7-a -mfpu=vfpv3-d16"
420 ;;
421 esac
422
423 case $1 in
424 *-generic32|*-generic64)
425 # Generic builds do not compile without this flag.
426 result="$result -DOPENSSL_NO_ASM"
427 ;;
428 esac
429 echo "$result"
430}
431
432# $1: build type.
433# Out: linker for this build.
434get_build_linker () {
435 get_build_compiler $1
436}
437
438clear_sources () {
439 g_all_objs=""
440}
441
442# Generate build instructions to compile source files.
443# Also update g_all_objs.
444# $1: module prefix (e.g. CRYPTO)
445# $2: build type
446build_sources () {
447 local prefix=$1
448 local build_type=$2
449 echo "## build_sources prefix='$prefix' build_type='$build_type'"
450 local arch=$(get_build_arch $build_type)
451 local src_files=$(get_module_src_files_for_arch $prefix $arch)
452 local c_defines=$(get_module_defines_for_arch $prefix $arch)
453 local c_includes=$(get_module_c_includes $prefix "$SRC_DIR")
454 local build_cc=$(get_build_compiler $build_type)
455 local build_cflags=$(get_build_c_flags $build_type)
456 local build_linker=$(get_build_linker $build_type)
457 local src obj def inc
458
459 printf "OUT_DIR := $OUT_DIR/$build_type\n\n"
460 printf "BUILD_CC := $build_cc\n\n"
461 printf "BUILD_LINKER := $build_linker\n\n"
462 printf "BUILD_CFLAGS := $build_cflags"
463 for inc in $c_includes; do
464 printf " -I\$(SRC_DIR)/$inc"
465 done
466 for def in $c_defines; do
467 printf " -D$def"
468 done
469 printf "\n\n"
470 printf "BUILD_OBJECTS :=\n\n"
471
472 case $build_type in
473 clang-android-*)
474 # The version of clang that comes with the platform build doesn't
475 # support simple linking of shared libraries and executables. One
476 # has to provide the C runtime files explicitely.
477 local crtbegin_so=$(get_c_runtime_file $build_type crtbegin_so.o)
478 local crtend_so=$(get_c_runtime_file $build_type crtend_so.o)
479 local crtbegin_exe=$(get_c_runtime_file $build_type crtbegin_dynamic.o)
480 local crtend_exe=$(get_c_runtime_file $build_type crtend_android.o)
481 printf "CRTBEGIN_SO := $crtbegin_so\n"
482 printf "CRTEND_SO := $crtend_so\n"
483 printf "CRTBEGIN_EXE := $crtbegin_exe\n"
484 printf "CRTEND_EXE := $crtend_exe\n"
485 printf "\n"
486 ;;
487 esac
488
489 for src in $src_files; do
490 obj=$(src_to_obj $src)
491 g_all_objs="$g_all_objs $obj"
492 printf "OBJ := \$(OUT_DIR)/$obj\n"
493 printf "BUILD_OBJECTS += \$(OBJ)\n"
494 printf "\$(OBJ): PRIVATE_CC := \$(BUILD_CC)\n"
495 printf "\$(OBJ): PRIVATE_CFLAGS := \$(BUILD_CFLAGS)\n"
496 printf "\$(OBJ): \$(SRC_DIR)/$src\n"
497 printf "\t@echo [$build_type] CC $src\n"
498 printf "\t@mkdir -p \$\$(dirname \$@)\n"
499 printf "\t\$(hide) \$(PRIVATE_CC) \$(PRIVATE_CFLAGS) -c -o \$@ \$<\n"
500 printf "\n"
501 done
502 printf "\n"
503}
504
505# $1: library name (e.g. crypto).
506# $2: module prefix (e.g. CRYPTO).
507# $3: build type.
508# $4: source directory.
509# $5: output directory.
510build_shared_library () {
511 local name=$1
512 local prefix=$2
513 local build_type=$3
514 local src_dir="$4"
515 local out_dir="$5"
516 local shlib="lib${name}.so"
517 local build_linker=$(get_build_linker $build_type)
518 clear_sources
519 build_sources $prefix $build_type
520
521 # TODO(digit): Make the clang build link properly.
522 printf "SHLIB=\$(OUT_DIR)/$shlib\n"
523 printf "\$(SHLIB): PRIVATE_LINKER := \$(BUILD_LINKER)\n"
524 case $build_type in
525 clang-android-*)
526 printf "\$(SHLIB): PRIVATE_CRTBEGIN := \$(CRTBEGIN_SO)\n"
527 printf "\$(SHLIB): PRIVATE_CRTEND := \$(CRTEND_SO)\n"
528 ;;
529 esac
530 printf "\$(SHLIB): \$(BUILD_OBJECTS)\n"
531 printf "\t@echo [$build_type] SHARED_LIBRARY $(basename $shlib)\n"
532 printf "\t@mkdir -p \$\$(dirname \$@)\n"
533 case $build_type in
534 clang-android-*)
535 printf "\t\$(hide) \$(PRIVATE_LINKER) -nostdlib -shared -o \$@ \$(PRIVATE_CRTBEGIN) \$^ \$(PRIVATE_CRTEND)\n"
536 ;;
537 *)
538 printf "\t\$(hide) \$(PRIVATE_LINKER) -shared -o \$@ \$^\n"
539 ;;
540 esac
541 printf "\n"
542}
543
544# $1: executable name.
545# $2: module prefix (e.g. APPS).
546# $3: build type.
547# $4: source directory.
548# $5: output directory.
549# $6: dependent shared libraries (e.g. 'crypto ssl')
550build_executable () {
551 local name=$1
552 local prefix=$2
553 local build_type=$3
554 local src_dir="$4"
555 local out_dir="$5"
556 local shlibs="$6"
557 local build_linker=$(get_build_linker $build_type)
558 clear_sources
559 build_sources $prefix $build_type
560
561 # TODO(digit): Make the clang build link properly.
562 exec=$name
563 all_shlibs=
564 printf "EXEC := \$(OUT_DIR)/$name\n"
565 printf "openssl_all: \$(EXEC)\n"
566 printf "\$(EXEC): PRIVATE_LINKER := \$(BUILD_LINKER)\n"
567 printf "\$(EXEC): \$(BUILD_OBJECTS)"
568 for lib in $shlibs; do
569 printf " \$(OUT_DIR)/lib${lib}.so"
570 done
571 printf "\n"
572 printf "\t@echo [$build_type] EXECUTABLE $name\n"
573 printf "\t@mkdir -p \$\$(dirname \$@)\n"
574 printf "\t\$(hide) \$(PRIVATE_LINKER) -o \$@ \$^\n"
575 printf "\n"
576}
577
578ALL_BUILDS=
579
580generate_openssl_build () {
581 local build_type=$1
582 local out="$OUT_DIR/$build_type"
583 ALL_BUILDS="$ALL_BUILDS $build_type"
584 echo "# Build type: $build_type"
585 build_shared_library crypto CRYPTO $build_type "$SRC_DIR" "$out"
586 build_shared_library ssl SSL $build_type "$SRC_DIR" "$out"
587 build_executable openssl APPS $build_type "$SRC_DIR" "$out" "crypto ssl"
588}
589
590generate_makefile () {
591 echo \
592"# Auto-generated by $PROGDIR - do not edit
593
594.PHONY: openssl_all
595
596all: openssl_all
597
598# Use 'make V=1' to print build commands.
599ifeq (1,\$(V))
600hide :=
601else
602hide := @
603endif
604
605SRC_DIR=$SRC_DIR
606OUT_DIR=$OUT_DIR
607"
608
609 for BUILD_TYPE in $BUILD_TYPES; do
610 generate_openssl_build gcc-$BUILD_TYPE
611 done
612
613# TODO(digit): Make the Clang build run.
614# for BUILD_TYPE in $ANDROID_BUILD_TYPES; do
615# generate_openssl_build clang-$BUILD_TYPE
616# done
617}
618
619. $SRC_DIR/openssl.config
620
621
622
623dump "Generating Makefile"
624log "Makefile path: $MAKEFILE"
625generate_makefile > $MAKEFILE
626
627dump "Building libraries with $NUM_JOBS jobs"
628dump "For the following builds:"
629for BUILD in $ALL_BUILDS; do
630 dump " $BUILD"
631done
632MAKE_FLAGS="-j$NUM_JOBS"
633if [ "$VERBOSE" -gt 2 ]; then
634 MAKE_FLAGS="$MAKE_FLAGS V=1"
635fi
636run make $MAKE_FLAGS -f "$MAKEFILE" -C "$BUILD_DIR"
637case $? in
638 0)
639 dump "All OK, congratulations!"
640 ;;
641 *)
642 dump "Error, try doing the following to inspect the issues:"
643 dump " $PROGNAME --build-dir=/tmp/mybuild"
644 dump " make -C /tmp/mybuild V=1"
David 'Digit' Turner463519a2014-01-30 18:21:25 +0100645 dump " "
David 'Digit' Turner063cfe12013-02-19 17:08:14 +0100646 ;;
647esac