illwieckz

less long build-relese

Aug 1st, 2021 (edited)
1,262
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #! /usr/bin/env bash
  2. set -e -u
  3. throwError () { local error_keyword="${1}" ; local error_message="${2}"
  4.     local error_code
  5.     case "${error_keyword}" in
  6.         'BADREQUEST') error_code=2 ;;
  7.         'INTERNAL') error_code=3 ;;
  8.         'NOTIMPLEMENTED') error_code=4 ;;
  9.     esac
  10.     printf 'ERROR %s: %s\n' "${error_keyword}" "${error_message}" >&2
  11.     exit "${error_code}"
  12. }
  13. printHelp () {
  14.     local prog_name="$(basename "${0}")"
  15.     sed -e 's|\\t|\t|g;s|\\n|\n|g' <<-EOF
  16.     ${prog_name}: a tool to build game for release purpose.\n
  17.     Usage:\n
  18.     \t${prog_name} [option] <target>\n
  19.     The script must be called within game source directory,
  20.     but can be called from everywhere in source directory.\n
  21.     Option can be:\n
  22.     \t-j<NUMBER>
  23.     \t\twith NUMBER the number of parallel compilation jobs\n
  24.     \t-p
  25.     \t\tbuild multiple targets at once in parallel
  26.     \t\tbeware: return code will be inaccurate\n
  27.     \t-v
  28.     \t\twrite package version strings\n
  29.     Target can be:\n
  30.     \tvm
  31.     \t\tbuild virtual machine\n
  32.     \tlinux-i686
  33.     \t\tbuild linux x86 engine\n
  34.     \tlinux-amd64
  35.     \t\tbuild linux x86_64 engine\n
  36.     \tmacos-amd64
  37.     \t\tbuild mac x86_64 engine\n
  38.     \twindows-i686
  39.     \t\tbuild windows x86 engine\n
  40.     \twindows-amd64
  41.     \t\tbuild windows x86_64 engine\n
  42.     Example:\n
  43.     \t${prog_name} vm linux-amd64\n
  44.     EOF
  45.     exit
  46. }
  47. getUserName () {
  48.     whoami | tr '[:upper:]' '[:lower:]' | tr -d '[:blank:]' | tr -d '[:punct:]' | cut -c'1-10'
  49. }
  50. getBinPath () { local system_windows="${1}" ; local bin_name="${2}"
  51.     if "${system_windows}" ; then
  52.         echo "${bin_name}.exe"
  53.     else
  54.         echo "${bin_name}"
  55.     fi
  56. }
  57. dumpSymbols () { local dumpsyms_bin="${1}" ; local symbol_dir="${2}" ; local exec_file="${3}"
  58.     local temp_file="$(mktemp)"
  59.     "${dumpsyms_bin}" "${exec_file}" > "${temp_file}"
  60.     local symbol_basename="$(head -n'1' "${temp_file}" | cut -f'5' -d' ')"
  61.     local build_id="$(head -n'1' "${temp_file}" | cut -f'4' -d' ')"
  62.     local exec_symbol_dir="${symbol_dir}/${symbol_basename}/${build_id}"
  63.     mkdir -pv "${exec_symbol_dir}"
  64.     mv "${temp_file}" "${exec_symbol_dir}/${symbol_basename}.sym"
  65. }
  66. findDll () { local mingw_arch="${1}" local dll_name="${2}"
  67.     if [ -z "${mingw_arch}" ]; then
  68.         find "${MINGW_PREFIX}/bin/${dll_name}"
  69.         return
  70.     fi
  71.     find '/usr' -name "${dll_name}" -type f | sort | grep --max-count=1 "${mingw_arch}" || throwError INTERNAL "couldn't find DLL ${dll_name}"
  72. }
  73. cleanSymbols () { local symbol_dir="${1}" ; local symbol_archive_filename="${2}"
  74.     if [ -e "${symbol_dir}" ] ; then
  75.         find "${symbol_dir}" -type f -name '*.sym' -exec rm -v {} \;
  76.         find "${symbol_dir}" -depth -type d -exec rmdir {} \;
  77.     fi
  78.     if [ -f "${symbol_archive_filename}" ] ; then
  79.         rm "${symbol_archive_filename}"
  80.     fi
  81. }
  82. cleanEngineBuildDir () { local content_dir="${1}"
  83.     if [ -e "${content_dir}" ] ; then
  84.         find "${content_dir}" -type f -exec rm -v {} \;
  85.         find "${content_dir}" -depth -type d -exec rmdir {} \;
  86.     fi
  87. }
  88. cleanVmBuildDir () { local content_dir="${1}" ; local symbol_archive_basename="${2}"
  89.     if [ -e "${content_dir}" ] ; then
  90.         find "${content_dir}" -type f -name '?game-*.nexe' -exec rm -v {} \;
  91.         find "${content_dir}" -type f -name "${symbol_archive_basename}.*" -exec rm -v {} \;
  92.         find "${content_dir}" -depth -type d -exec rmdir {} \;
  93.     fi
  94. }
  95. package () { local archive_format="${1}" ; local archive_filename="${2}" ; local content_dir="${3}"
  96.     (   cd "${content_dir}"
  97.         [ -f "${archive_filename}" ] && rm -v "${archive_filename}"
  98.         7z -mx='9' -t"${archive_format}" a "${archive_filename}" .
  99.     )
  100. }
  101. build () { local job_count="${1}" ; local write_version_string="${2}" ; local root_dir="${3}" ; local target="${4}"
  102.     local symbol_archive_basename='symbols'
  103.     local vmpak_archive_basename=''
  104.     local engine_archive_basename=''
  105.     local engine_archive_format='zip'
  106.     local symbol_archive_format='7z'
  107.     local vmpak_archive_format='zip'
  108.     local vmpak_archive_extension='dpk'
  109.     local build_dir="${root_dir}/build"
  110.     local release_dir="${build_dir}/release"
  111.     local vm_kind_list='cgame sgame'
  112.     local vm_arch_list='x86 x86_64'
  113.     local main_nexe='main.nexe'
  114.     local engine_file_list=''
  115.     local engine_strip_list=''
  116.     local engine_symbolize_list=''
  117.     local build_vm='false'
  118.     local build_engine='false'
  119.     local system_linux='false'
  120.     local system_macos='false'
  121.     local system_windows='false'
  122.     local dumpsyms_relpath=''
  123.     local arch_amd64='false'
  124.     local arch_i686='false'
  125.     local host_linux='false'
  126.     local host_mac='false'
  127.     local host_windows='false'
  128.     local mingw_arch_prefix=''
  129.     case "${target}" in
  130.         'vm') build_vm='true'
  131.             dumpsyms_relpath=linux/dump_syms/dump_syms ;;
  132.         'linux-'*) build_engine='true' ; system_linux='true'
  133.             dumpsyms_relpath=linux/dump_syms/dump_syms ;;
  134.         'macos-'*) build_engine='true' ; system_macos='true'
  135.             dumpsyms_relpath=mac/dump_syms/dump_syms_mac ;;
  136.         'windows-'*) build_engine='true' ; system_windows='true'
  137.             dumpsyms_relpath=windows/dump_syms_dwarf/dump_syms ;;
  138.     esac
  139.     case "${target}" in
  140.         *'-amd64')
  141.             arch_amd64='true'
  142.             engine_file_list="${engine_file_list} irt_core-x86_64.nexe" ;;
  143.         *'-i686')
  144.             arch_i686='true'
  145.             engine_file_list="${engine_file_list} irt_core-x86.nexe" ;;
  146.     esac
  147.     local target_root_dir="${build_dir}/target"
  148.     local target_build_dir="${target_root_dir}/${target}"
  149.     local content_dir="${target_build_dir}/content"
  150.     local symbol_dir="${target_build_dir}/${symbol_archive_basename}"
  151.     local symbol_archive_filename="${target_build_dir}/${symbol_archive_basename}.${symbol_archive_format}"
  152.     local uname_system="$(uname -s)"
  153.     case "${uname_system}" in
  154.         'Linux'*) host_linux='true' ;;
  155.         'Darwin'*) host_mac='true' ;;
  156.         'CYGWIN'*|'MINGW'*) host_windows='true' ;;
  157.         *) throwError NOTIMPLEMENTED "unknown system: ${uname_system}" ;;
  158.     esac
  159.     if "${write_version_string}" ; then
  160.         git_last_commit="$(git rev-list HEAD | head -n 1)"
  161.         git_last_commit_short="$(git rev-list HEAD | head -n 1 | cut -c1-7)"
  162.         git_ref="$(git describe --tags --match 'v*' | cut -c2-)"
  163.         git_last_tag="$(git describe --tags --match 'v*' | cut -f1 -d'-' | cut -c2-)"
  164.         git_last_date="$(date --date="@$(git log -1 '--pretty=format:%ct')" -u '+%Y%m%d-%H%M%S')"
  165.         if [ "${git_ref}" = "${git_last_tag}" ] ; then
  166.             build_version="${git_ref}"
  167.         else
  168.             build_version="${git_last_tag}+${git_last_date}+${git_last_commit_short}+$(getUserName)"
  169.         fi
  170.         vmpak_version_string="_${build_version}"
  171.         engine_version_string="_${build_version}"
  172.     else
  173.         vmpak_version_string='_0'
  174.         engine_version_string=''
  175.     fi
  176.     if [ -z "${job_count}" ] ; then
  177.         if command -v 'nproc' >/dev/null ; then
  178.             job_count="$(nproc)"
  179.         elif command -v 'sysctl' >/dev/null ; then
  180.             job_count="$(sysctl -n 'hw.ncpu')"
  181.         else
  182.             job_count='4'
  183.         fi
  184.     fi
  185.     if [ -d "${target_build_dir}" ] ; then
  186.         echo "Removing '${target_build_dir}' and contents"
  187.         rm -r "${target_build_dir}"
  188.     fi
  189.     mkdir -pv "${target_build_dir}"
  190.     mkdir -pv "${release_dir}"
  191.     local cmake_opts='-DBUILD_GAME_NATIVE_DLL=OFF -DBUILD_GAME_NATIVE_EXE=OFF'
  192.     local cmake_cflags=''
  193.     if "${system_macos}" ; then
  194.         PATH="${PATH}:/Applications/CMake.app/Contents/bin"
  195.         cmake_opts="${cmake_opts} -DCMAKE_OSX_DEPLOYMENT_TARGET=10.9 -DCMAKE_BUILD_TYPE=Release -DUSE_BREAKPAD=OFF -DGMP_LIBRARY=${target_build_dir}/external_deps/macosx64-5/lib/libgmp.a"
  196.         produce_symbols=false
  197.     else
  198.         cmake_opts="${cmake_opts} -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUSE_BREAKPAD=ON"
  199.         produce_symbols=true
  200.     fi
  201.     if "${system_macos}" && "${arch_amd64}" ; then
  202.         cmake_opts="${cmake_opts} -DCMAKE_OSX_ARCHITECTURES=x86_64"
  203.     fi
  204.     if "${build_vm}" ; then
  205.         vmpak_archive_basename='vm'
  206.         cmake_opts="${cmake_opts} -DBUILD_GAME_NACL=ON -DBUILD_GAME_NACL_NEXE=ON -DBUILD_CGAME=ON -DBUILD_SGAME=ON -DBUILD_CLIENT=OFF -DBUILD_TTY_CLIENT=OFF -DBUILD_SERVER=OFF"
  207.     fi
  208.     if "${build_engine}" ; then
  209.         engine_archive_basename="${target}"
  210.         cmake_opts="${cmake_opts} -DUSE_LTO=ON -DBUILD_CLIENT=ON -DBUILD_SERVER=ON -DBUILD_TTY_CLIENT=ON -DBUILD_GAME_NACL=OFF -DBUILD_GAME_NACL_NEXE=OFF -DBUILD_CGAME=OFF -DBUILD_SGAME=OFF -DUSE_HARDENING=1"
  211.         local strip='strip'
  212.         if "${system_windows}" && ! "${host_windows}" ; then
  213.             if "${arch_i686}" ; then
  214.                 bitness='32' ; mingw_arch_prefix='i686'
  215.             else
  216.                 bitness='64' ; mingw_arch_prefix='x86_64'
  217.             fi
  218.             strip="${mingw_arch_prefix}-w64-mingw32-strip"
  219.             cmake_opts="${cmake_opts} -DCMAKE_TOOLCHAIN_FILE=${root_dir}/daemon/cmake/cross-toolchain-mingw${bitness}.cmake"
  220.         fi
  221.         if ${system_linux} ; then
  222.             cmake_opts="${cmake_opts} -DUSE_STATIC_LIBS=1 -DOpenGL_GL_PREFERENCE=LEGACY"
  223.             engine_file_list="${engine_file_list} daemon daemonded daemon-tty crash_server nacl_helper_bootstrap nacl_loader"
  224.             engine_symbolize_list='daemon daemonded daemon-tty'
  225.             engine_strip_list='daemon daemonded daemon-tty crash_server'
  226.             if "${arch_i686}" ; then
  227.                 cmake_opts="${cmake_opts} -DCMAKE_TOOLCHAIN_FILE=${root_dir}/daemon/cmake/cross-toolchain-linux32.cmake"
  228.             fi
  229.         fi
  230.         if "${system_macos}" ; then
  231.             engine_file_list="${engine_file_list} daemon daemonded daemon-tty nacl_loader libGLEW.2.2.0.dylib libopenal.1.18.2.dylib"
  232.         fi
  233.         if "${system_windows}" ; then
  234.             if "${arch_i686}" ; then
  235.                 if "${host_windows}" ; then
  236.                     special_dll='libgcc_s_dw2-1.dll'
  237.                 else
  238.                     special_dll='libgcc_s_sjlj-1.dll'
  239.                 fi
  240.             else
  241.                 special_dll='libgcc_s_seh-1.dll'
  242.             fi
  243.             extra_dll_list="${special_dll} libstdc++-6.dll libwinpthread-1.dll libssp-0.dll"
  244.             engine_file_list="${engine_file_list} daemon.exe daemonded.exe daemon-tty.exe crash_server.exe nacl_loader.exe"
  245.             engine_symbolize_list='daemon.exe daemonded.exe daemon-tty.exe'
  246.             engine_strip_list='daemon.exe daemonded.exe daemon-tty.exe crash_server.exe'
  247.             for dll_name in ${extra_dll_list} ; do
  248.                 dll_location="$(findDll "${mingw_arch_prefix}" "${dll_name}")"
  249.                 cp -av "${dll_location}" "${target_build_dir}/"
  250.             done
  251.         fi
  252.         local strip='strip'
  253.         if "${system_windows}" && ! "${host_windows}" ; then
  254.             if "${arch_i686}" ; then
  255.                 bitness='32' ; mingw_arch_prefix='i686'
  256.             else
  257.                 bitness='64' ; mingw_arch_prefix='x86_64'
  258.             fi
  259.             strip="${mingw_arch_prefix}-w64-mingw32-strip"
  260.             cmake_opts="${cmake_opts} -DCMAKE_TOOLCHAIN_FILE=${root_dir}/daemon/cmake/cross-toolchain-mingw${bitness}.cmake"
  261.         fi
  262.     fi
  263.     if "${build_vm}" ; then
  264.         cmake -H"${root_dir}" -B"${target_build_dir}" -G"Unix Makefiles" ${cmake_opts} || throwError INTERNAL "${target} cmake failed"
  265.     fi
  266.     if "${build_engine}" ; then
  267.         cmake -H"${root_dir}" -B"${target_build_dir}" -G"Unix Makefiles" -D"CMAKE_C_FLAGS=${cmake_cflags}" -D"CMAKE_CXX_FLAGS=${cmake_cflags}" -D"CMAKE_EXE_LINKER_FLAGS=${cmake_cflags}" ${cmake_opts} || throwError INTERNAL "${target} cmake failed"
  268.     fi
  269.     if "${build_vm}" || "${build_engine}" ; then
  270.         daemon_dir="$(cmake -H"${root_dir}" -B"${target_build_dir}" -LH | grep '^DAEMON_DIR:' | sed -e 's/[^=]*=//')"
  271.     fi
  272.     if "${system_macos}" ; then
  273.         mkdir -v "${target_build_dir}/external_deps"
  274.         (   cd "${target_build_dir}/external_deps"
  275.             "${daemon_dir}/external_deps/build.sh" macosx64 gmp
  276.             "${daemon_dir}/external_deps/build.sh" macosx64 install
  277.         )
  278.     fi
  279.     if "${build_vm}" ; then
  280.         cmake --build "${target_build_dir}" -- -j"${job_count}" nacl-vms || throwError INTERNAL "${target} build failed"
  281.     fi
  282.     if "${build_engine}" ; then
  283.         cmake --build "${target_build_dir}" -- -j"${job_count}" || throwError INTERNAL "${target} build failed"
  284.         if "${system_windows}" ; then
  285.             engine_file_list="${engine_file_list} $(cd "${target_build_dir}" && ls *.dll)"
  286.         fi
  287.     fi
  288.     if "${produce_symbols}" ; then
  289.         local breakpad_dir="${daemon_dir}/libs/breakpad"
  290.         local dumpsyms_bin="$(getBinPath ${host_windows} ${breakpad_dir}/src/tools/${dumpsyms_relpath})"
  291.         if ! [ -d "${breakpad_dir}" ] ; then
  292.             throwError INTERNAL "breakpad dir missing: ${breakpad_dir}"
  293.         fi
  294.         set +e
  295.         "${dumpsyms_bin}" --help 2>/dev/null
  296.         local exitcode=$?
  297.         set -e
  298.         if [ "${exitcode}" -gt 1 ] ; then
  299.             (   cd "${breakpad_dir}"
  300.                 autoreconf -fvi && ./configure || throwError INTERNAL 'breakpad configure failed'
  301.             )
  302.             make -C"${breakpad_dir}" clean || true
  303.             local make_targets=''
  304.             if "${host_windows}" ; then
  305.                 make_targets='src/tools/windows/dump_syms_dwarf/dump_syms.exe'
  306.             fi
  307.             make -j"${job_count}" -C"${breakpad_dir}" $make_targets || throwError INTERNAL 'breakpad build failed'
  308.         fi
  309.     fi
  310.     if "${build_vm}" ; then
  311.         cleanSymbols "${symbol_dir}" "${symbol_archive_filename}"
  312.         for vm in ${vm_kind_list} ; do
  313.             for arch in ${vm_arch_list} ; do
  314.                 (   cd "${target_build_dir}"
  315.                     local vm_file="${vm}-${arch}.nexe"
  316.                     local stripped_vm_file="${vm}-${arch}-stripped.nexe"
  317.                     printf 'extracting symbols from %s\n' "${vm_file}"
  318.                     if ! [ -f "${vm_file}" ] ; then
  319.                         throwError INTERNAL "missing: ${vm_file}"
  320.                     fi
  321.                     if [ -f "${main_nexe}" ] ; then
  322.                         rm "${main_nexe}"
  323.                     fi
  324.                     ln -s "${vm_file}" 'main.nexe'
  325.                     dumpSymbols "${dumpsyms_bin}" "${symbol_dir}" "${main_nexe}"
  326.                     mkdir -pv "${content_dir}"
  327.                     cp -v "${stripped_vm_file}" "${content_dir}/${vm_file}"
  328.                 )
  329.             done
  330.         done
  331.         package "${symbol_archive_format}" "${symbol_archive_filename}" "${symbol_dir}"
  332.         cp -v "${symbol_archive_filename}" "${content_dir}/${symbol_archive_basename}.${symbol_archive_format}"
  333.         vmpak_archive_filename="${release_dir}/${vmpak_archive_basename}${vmpak_version_string}.${vmpak_archive_extension}"
  334.         if [ -f "${vmpak_archive_filename}" ] ; then
  335.             rm -v "${vmpak_archive_filename}"
  336.         fi
  337.         package "${vmpak_archive_format}" "${vmpak_archive_filename}" "${content_dir}"
  338.         cleanSymbols "${symbol_dir}" "${symbol_archive_filename}"
  339.         cleanVmBuildDir "${content_dir}" "${symbol_archive_basename}"
  340.     fi
  341.     if "${build_engine}" ; then
  342.         cleanSymbols "${symbol_dir}" "${symbol_archive_filename}"
  343.         mkdir -pv "${content_dir}"
  344.         if "${produce_symbols}" ; then
  345.             for bin in ${engine_symbolize_list} ; do
  346.                 local bin_path="${target_build_dir}/${bin}"
  347.                 printf 'extracting symbols from %s\n' "${bin_path}"
  348.                 dumpSymbols "${dumpsyms_bin}" "${symbol_dir}" "${bin_path}"
  349.             done
  350.         fi
  351.         local engine_file_dest="${content_dir}"
  352.         if "${system_macos}" ; then
  353.             engine_file_dest="${content_dir}/Unvanquished.app/Contents/MacOS"
  354.             mkdir -pv "${engine_file_dest}"
  355.             cp -v "${root_dir}/macosx/unvanquished.sh" "${engine_file_dest}"
  356.             cp -av "${target_build_dir}/SDL2.framework" "${engine_file_dest}"
  357.             rm -rv "${engine_file_dest}/SDL2.framework/Headers"
  358.             rm -rv "${engine_file_dest}/SDL2.framework/Versions/A/Headers"
  359.             rm -rv "${engine_file_dest}/SDL2.framework/Versions/Current/Headers"
  360.             cp -v "${root_dir}/macosx/Info.plist" "${content_dir}/Unvanquished.app/Contents"
  361.             mkdir -v "${content_dir}/Unvanquished.app/Contents/Resources"
  362.             cp -v "${root_dir}/macosx/Unvanquished.icns" "${content_dir}/Unvanquished.app/Contents/Resources"
  363.         fi
  364.         for file in ${engine_file_list} ; do
  365.             cp -v "${target_build_dir}/${file}" "${engine_file_dest}/${file}"
  366.         done
  367.         for file in ${engine_strip_list} ; do
  368.             echo "Stripping ${file}"
  369.             "${strip}" "${engine_file_dest}/${file}"
  370.         done
  371.         if "${produce_symbols}" ; then
  372.             package "${symbol_archive_format}" "${symbol_archive_filename}" "${symbol_dir}"
  373.             cp -v "${symbol_archive_filename}" "${content_dir}/${symbol_archive_basename}-${target}.${symbol_archive_format}"
  374.         fi
  375.         engine_archive_filename="${release_dir}/${engine_archive_basename}${engine_version_string}.${engine_archive_format}"
  376.         if [ -f "${engine_archive_filename}" ] ; then
  377.             rm -v "${engine_archive_filename}"
  378.         fi
  379.         package "${engine_archive_format}" "${engine_archive_filename}" "${content_dir}"
  380.         cleanSymbols "${symbol_dir}" "${symbol_archive_filename}"
  381.         cleanEngineBuildDir "${content_dir}"
  382.     fi
  383. }
  384. root_dir="$(git rev-parse --show-toplevel)"
  385. [ -f "${root_dir}/src/cgame/cg_main.cpp" ] || throwError INTERNAL "must be called from game source tree"
  386. [ -z "${1:-}" ] && throwError BADREQUEST 'missing target'
  387. job_count=''
  388. parallel_target='false'
  389. write_version_string='false'
  390. target_list=''
  391. while [ -n "${1:-}" ] ; do
  392.     case "${1}" in
  393.     'vm'|'linux-amd64'|'linux-i686'|'macos-amd64'|'windows-amd64'|'windows-i686')
  394.             target_list="${target_list} ${1}" ; shift ;;
  395.         'macos-i686') throwError NOTIMPLEMENTED "unsupported target: ${1}" ;;
  396.         '-d') set -x ; shift ;;
  397.         '-j'*) job_count="${1:2}" ; shift ;;
  398.         '-p') parallel_target='true' ; shift ;;
  399.         '-v') write_version_string='true' ; shift ;;
  400.         '-h'|'--help') printHelp ;;
  401.         '-'*) throwError BADREQUEST "unknown option: ${1}" ;;
  402.         *) throwError BADREQUEST "unknown target: ${1}" ;;
  403.     esac
  404. done
  405. for target in ${target_list} ; do
  406.     if "${parallel_target}" ; then
  407.         build "${job_count}" "${write_version_string}" "${root_dir}" "${target}" &
  408.     else
  409.         build "${job_count}" "${write_version_string}" "${root_dir}" "${target}"
  410.     fi
  411. done ; wait
RAW Paste Data