#!/usr/bin/env bash # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. ################################################################################ # # This script builds NSS with gyp and ninja. # # This build system is still under development. It does not yet support all # the features or platforms that NSS supports. set -e cwd=$(cd $(dirname $0); pwd -P) dist_dir="$cwd/../dist" argsfile="$dist_dir/build_args" source "$cwd/coreconf/nspr.sh" source "$cwd/coreconf/sanitizers.sh" GYP=${GYP:-gyp} # Usage info show_help() { cat "$cwd/help.txt" } run_verbose() { if [ "$verbose" = 1 ]; then echo "$@" exec 3>&1 else exec 3>/dev/null fi "$@" 1>&3 2>&3 exec 3>&- } # The prehistoric bash on Mac doesn't support @Q quoting. # The consequences aren't that serious, unless there are odd arrangements of spaces. if /usr/bin/env bash -c 'x=1;echo "${x@Q}"' >/dev/null 2>&1; then Q() { echo "${@@Q}"; } else Q() { echo "$@"; } fi if [ -n "$CCC" ] && [ -z "$CXX" ]; then export CXX="$CCC" fi opt_build=0 build_64=0 clean=0 rebuild_gyp=0 rebuild_nspr=0 build_nspr_tests=0 run_nspr_tests=0 exit_after_nspr=0 target=Debug verbose=0 fuzz=0 fuzz_tls=0 fuzz_oss=0 no_local_nspr=0 sslkeylogfile=1 gyp_params=(--depth="$cwd" --generator-output=".") ninja_params=() # Assume that the target architecture is the same as the host by default. host_arch=$(python "$cwd/coreconf/detect_host_arch.py") target_arch=$host_arch # Assume that MSVC is wanted if this is running on windows. platform=$(uname -s) if [ "${platform%-*}" = "MINGW32_NT" -o "${platform%-*}" = "MINGW64_NT" ]; then msvc=1 fi # Parse command line arguments. all_args=("$@") while [ $# -gt 0 ]; do case "$1" in --rebuild) if [[ ! -e "$argsfile" ]]; then echo "Unable to rebuild" 1>&2 exit 2 fi IFS=$'\r\n' GLOBIGNORE='*' command eval 'previous_args=($(<"$argsfile"))' exec /usr/bin/env bash -c "$(Q "$0")"' "$@"' "$0" "${previous_args[@]}" ;; -c) clean=1 ;; -cc) clean_only=1 ;; -v) ninja_params+=(-v); verbose=1 ;; -j) ninja_params+=(-j "$2"); shift ;; --gyp|-g) rebuild_gyp=1 ;; --opt|-o) opt_build=1 ;; -m32|--m32) target_arch=ia32; echo 'Warning: use -t instead of -m32' 1>&2 ;; -t|--target) target_arch="$2"; shift ;; --target=*) target_arch="${1#*=}" ;; --clang) export CC=clang; export CCC=clang++; export CXX=clang++; msvc=0 ;; --gcc) export CC=gcc; export CCC=g++; export CXX=g++; msvc=0 ;; --msvc) msvc=1 ;; --scan-build) enable_scanbuild ;; --scan-build=?*) enable_scanbuild "${1#*=}" ;; --disable-tests) gyp_params+=(-Ddisable_tests=1) ;; --pprof) gyp_params+=(-Duse_pprof=1) ;; --asan) enable_sanitizer asan ;; --msan) enable_sanitizer msan ;; --ubsan) enable_ubsan ;; --ubsan=?*) enable_ubsan "${1#*=}" ;; --fuzz) fuzz=1 ;; --fuzz=oss) fuzz=1; fuzz_oss=1 ;; --fuzz=tls) fuzz=1; fuzz_tls=1 ;; --sancov) enable_sancov; gyp_params+=(-Dcoverage=1) ;; --sancov=?*) enable_sancov "${1#*=}"; gyp_params+=(-Dcoverage=1) ;; --emit-llvm) gyp_params+=(-Demit_llvm=1 -Dsign_libs=0) ;; --no-zdefs) gyp_params+=(-Dno_zdefs=1) ;; --static) gyp_params+=(-Dstatic_libs=1) ;; --ct-verif) gyp_params+=(-Dct_verif=1) ;; --nspr) nspr_clean; rebuild_nspr=1 ;; --nspr-test-build) build_nspr_tests=1 ;; --nspr-test-run) run_nspr_tests=1 ;; --nspr-only) exit_after_nspr=1 ;; --with-nspr=?*) set_nspr_path "${1#*=}"; no_local_nspr=1 ;; --system-nspr) set_nspr_path "/usr/include/nspr/:"; no_local_nspr=1 ;; --system-sqlite) gyp_params+=(-Duse_system_sqlite=1) ;; --enable-fips) gyp_params+=(-Ddisable_fips=0) ;; --enable-libpkix) gyp_params+=(-Ddisable_libpkix=0) ;; --mozpkix-only) gyp_params+=(-Dmozpkix_only=1 -Ddisable_tests=1 -Dsign_libs=0) ;; --disable-keylog) sslkeylogfile=0 ;; --enable-legacy-db) gyp_params+=(-Ddisable_dbm=0) ;; --mozilla-central) gyp_params+=(-Dmozilla_central=1) ;; -D*) gyp_params+=("$1") ;; *) show_help; exit 2 ;; esac shift done # Set the target architecture and build type. gyp_params+=(-Dtarget_arch="$target_arch") if [ "$opt_build" = 1 ]; then target=Release else target=Debug fi gyp_params+=(-Denable_sslkeylogfile="$sslkeylogfile") # Do special setup. if [ "$fuzz" = 1 ]; then source "$cwd/coreconf/fuzz.sh" fi nspr_set_flags $sanitizer_flags if [ ! -z "$sanitizer_flags" ]; then gyp_params+=(-Dsanitizer_flags="$sanitizer_flags") fi if [ "$msvc" = 1 ]; then source "$cwd/coreconf/msvc.sh" fi # -c = clean first if [ "$clean" = 1 -o "$clean_only" = 1 ]; then nspr_clean rm -rf "$cwd/out" rm -rf "$dist_dir" # -cc = only clean, don't build if [ "$clean_only" = 1 ]; then echo "Cleaned" exit 0 fi fi # Setup build paths. target_dir="$cwd/out/$target" mkdir -p "$target_dir" dist_dir=$(mkdir -p "$dist_dir"; cd "$dist_dir"; pwd -P) gyp_params+=(-Dnss_dist_dir="$dist_dir") # This saves a canonical representation of arguments that we are passing to gyp # or the NSPR build so that we can work out if a rebuild is needed. # Caveat: This can fail for arguments that are position-dependent. # e.g., "-e 2 -f 1" and "-e 1 -f 2" canonicalize the same. check_config() { local newconf="$1".new oldconf="$1" shift mkdir -p $(dirname "$newconf") echo CC="$(Q "$CC")" >"$newconf" echo CCC="$(Q "$CCC")" >>"$newconf" echo CXX="$(Q "$CXX")" >>"$newconf" echo target_arch="$(Q "$target_arch")" >>"$newconf" for i in "$@"; do echo "$i"; done | sort >>"$newconf" # Note: The following diff fails if $oldconf isn't there as well, which # happens if we don't have a previous successful build. ! diff -q "$newconf" "$oldconf" >/dev/null 2>&1 } gyp_config="$cwd/out/gyp_config" nspr_config="$cwd/out/$target/nspr_config" # Now check what needs to be rebuilt. # If we don't have a build directory make sure that we rebuild. if [ ! -d "$target_dir" ]; then rebuild_nspr=1 rebuild_gyp=1 elif [ ! -d "$dist_dir/$target" ]; then rebuild_nspr=1 fi if check_config "$nspr_config" \ nspr_cflags="$(Q "$nspr_cflags")" \ nspr_cxxflags="$(Q "$nspr_cxxflags")" \ nspr_ldflags="$(Q "$nspr_ldflags")"; then rebuild_nspr=1 fi if check_config "$gyp_config" "$(Q "${gyp_params[@]}")"; then rebuild_gyp=1 fi # Save the chosen target. echo "$target" > "$dist_dir/latest" for i in "${all_args[@]}"; do echo "$i"; done > "$argsfile" # Build. # NSPR. if [[ "$rebuild_nspr" = 1 && "$no_local_nspr" = 0 ]]; then nspr_clean nspr_build mv -f "$nspr_config.new" "$nspr_config" fi if [ "$exit_after_nspr" = 1 ]; then exit 0 fi # gyp. if [ "$rebuild_gyp" = 1 ]; then if ! hash "$GYP" 2> /dev/null; then echo "Building NSS requires an installation of gyp: https://gyp.gsrc.io/" 1>&2 exit 3 fi # These extra arguments aren't used in determining whether to rebuild. obj_dir="$dist_dir/$target" gyp_params+=(-Dnss_dist_obj_dir="$obj_dir") if [ "$no_local_nspr" = 0 ]; then set_nspr_path "$obj_dir/include/nspr:$obj_dir/lib" fi run_verbose run_scanbuild ${GYP} -f ninja "${gyp_params[@]}" "$cwd/nss.gyp" mv -f "$gyp_config.new" "$gyp_config" fi # ninja. if hash ninja-build 2>/dev/null; then ninja=ninja-build elif hash ninja 2>/dev/null; then ninja=ninja else echo "Building NSS requires an installation of ninja: https://ninja-build.org/" 1>&2 exit 3 fi run_scanbuild "$ninja" -C "$target_dir" "${ninja_params[@]}"