ladybird.sh 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. #!/usr/bin/env bash
  2. set -e
  3. BUILD_PRESET=${BUILD_PRESET:-default}
  4. ARG0=$0
  5. print_help() {
  6. NAME=$(basename "$ARG0")
  7. cat <<EOF
  8. Usage: $NAME COMMAND [ARGS...]
  9. Supported COMMANDs:
  10. build: Compiles the target binaries, [ARGS...] are passed through to ninja
  11. install: Installs the target binary
  12. run: $NAME run EXECUTABLE [ARGS...]
  13. Runs the EXECUTABLE on the build host, e.g.
  14. 'shell' or 'js', [ARGS...] are passed through to the executable
  15. gdb: Same as run, but also starts a gdb remote session.
  16. $NAME gdb EXECUTABLE [-ex 'any gdb command']...
  17. Passes through '-ex' commands to gdb
  18. vcpkg: Ensure that dependencies are available
  19. test: $NAME test [TEST_NAME_PATTERN]
  20. Runs the unit tests on the build host, or if TEST_NAME_PATTERN
  21. is specified tests matching it.
  22. delete: Removes the build environment
  23. rebuild: Deletes and re-creates the build environment, and compiles the project
  24. addr2line: $NAME addr2line BINARY_FILE ADDRESS
  25. Resolves the ADDRESS in BINARY_FILE to a file:line. It will
  26. attempt to find the BINARY_FILE in the appropriate build directory
  27. Examples:
  28. $NAME run ladybird
  29. Runs the Ladybird browser
  30. $NAME run js -A
  31. Runs the js(1) REPL
  32. $NAME test
  33. Runs the unit tests on the build host
  34. $NAME addr2line RequestServer 0x12345678
  35. Resolves the address 0x12345678 in the RequestServer binary
  36. EOF
  37. }
  38. usage() {
  39. >&2 print_help
  40. exit 1
  41. }
  42. CMD=$1
  43. [ -n "$CMD" ] || usage
  44. shift
  45. if [ "$CMD" = "help" ]; then
  46. print_help
  47. exit 0
  48. fi
  49. DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
  50. # shellcheck source=/dev/null
  51. . "${DIR}/shell_include.sh"
  52. exit_if_running_as_root "Do not run ladybird.sh as root, your Build directory will become root-owned"
  53. # shellcheck source=/dev/null
  54. . "${DIR}/find_compiler.sh"
  55. CMAKE_ARGS=()
  56. CMD_ARGS=( "$@" )
  57. if [ "$(uname -s)" = Linux ] && [ "$(uname -m)" = "aarch64" ]; then
  58. PKGCONFIG=$(which pkg-config)
  59. GN=$(command -v gn || echo "")
  60. CMAKE_ARGS+=("-DPKG_CONFIG_EXECUTABLE=$PKGCONFIG")
  61. # https://github.com/LadybirdBrowser/ladybird/issues/261
  62. if [ "$(getconf PAGESIZE)" != "4096" ]; then
  63. if [ -z "$GN" ]; then
  64. die "GN not found! Please build GN from source and put it in \$PATH"
  65. fi
  66. fi
  67. cat <<- EOF > Meta/CMake/vcpkg/user-variables.cmake
  68. set(PKGCONFIG $PKGCONFIG)
  69. set(GN $GN)
  70. EOF
  71. fi
  72. create_build_dir() {
  73. check_program_version_at_least CMake cmake 3.25 || exit 1
  74. cmake --preset "$BUILD_PRESET" "${CMAKE_ARGS[@]}" -S "$LADYBIRD_SOURCE_DIR" -B "$BUILD_DIR"
  75. }
  76. cmd_with_target() {
  77. pick_host_compiler
  78. CMAKE_ARGS+=("-DCMAKE_C_COMPILER=${CC}")
  79. CMAKE_ARGS+=("-DCMAKE_CXX_COMPILER=${CXX}")
  80. ensure_ladybird_source_dir
  81. BUILD_DIR=$(get_build_dir "$BUILD_PRESET")
  82. CMAKE_ARGS+=("-DCMAKE_INSTALL_PREFIX=$LADYBIRD_SOURCE_DIR/Build/ladybird-install-${BUILD_PRESET}")
  83. export PATH="$LADYBIRD_SOURCE_DIR/Toolchain/Local/cmake/bin:$LADYBIRD_SOURCE_DIR/Toolchain/Local/vcpkg/bin:$PATH"
  84. export VCPKG_ROOT="$LADYBIRD_SOURCE_DIR/Toolchain/Tarballs/vcpkg"
  85. }
  86. ensure_target() {
  87. [ -f "$BUILD_DIR/build.ninja" ] || create_build_dir
  88. }
  89. run_tests() {
  90. local TEST_NAME="$1"
  91. local CTEST_ARGS=("--preset" "$BUILD_PRESET" "--output-on-failure" "--test-dir" "$BUILD_DIR")
  92. if [ -n "$TEST_NAME" ]; then
  93. if [ "$TEST_NAME" = "WPT" ]; then
  94. CTEST_ARGS+=("-C" "Integration")
  95. fi
  96. CTEST_ARGS+=("-R" "$TEST_NAME")
  97. fi
  98. ctest "${CTEST_ARGS[@]}"
  99. }
  100. build_target() {
  101. # Get either the environment MAKEJOBS or all processors via CMake
  102. [ -z "$MAKEJOBS" ] && MAKEJOBS=$(cmake -P "$LADYBIRD_SOURCE_DIR/Meta/CMake/processor-count.cmake")
  103. # With zero args, we are doing a standard "build"
  104. # With multiple args, we are doing an install/run
  105. if [ $# -eq 0 ]; then
  106. CMAKE_BUILD_PARALLEL_LEVEL="$MAKEJOBS" cmake --build "$BUILD_DIR"
  107. else
  108. ninja -j "$MAKEJOBS" -C "$BUILD_DIR" -- "$@"
  109. fi
  110. }
  111. delete_target() {
  112. [ ! -d "$BUILD_DIR" ] || rm -rf "$BUILD_DIR"
  113. # Delete the vcpkg user variables created by this script if they exist
  114. VCPKG_USER_VARS="$LADYBIRD_SOURCE_DIR/Meta/CMake/vcpkg/user-variables.cmake"
  115. [ ! -f "$VCPKG_USER_VARS" ] || rm "$VCPKG_USER_VARS"
  116. }
  117. build_vcpkg() {
  118. ( cd "$LADYBIRD_SOURCE_DIR/Toolchain" && python3 ./BuildVcpkg.py )
  119. }
  120. ensure_toolchain() {
  121. build_vcpkg
  122. }
  123. run_gdb() {
  124. local GDB_ARGS=()
  125. local PASS_ARG_TO_GDB=""
  126. local LAGOM_EXECUTABLE=""
  127. local GDB=gdb
  128. if ! command -v "$GDB" > /dev/null 2>&1; then
  129. GDB=lldb
  130. if ! command -v "$GDB" > /dev/null 2>&1; then
  131. die "Please install gdb or lldb!"
  132. fi
  133. fi
  134. for arg in "${CMD_ARGS[@]}"; do
  135. if [ "$PASS_ARG_TO_GDB" != "" ]; then
  136. GDB_ARGS+=( "$PASS_ARG_TO_GDB" "$arg" )
  137. PASS_ARG_TO_GDB=""
  138. elif [ "$arg" = "-ex" ]; then
  139. PASS_ARG_TO_GDB="$arg"
  140. elif [[ "$arg" =~ ^-.*$ ]]; then
  141. die "Don't know how to handle argument: $arg"
  142. else
  143. if [ "$LAGOM_EXECUTABLE" != "" ]; then
  144. die "Lagom executable can't be specified more than once"
  145. fi
  146. LAGOM_EXECUTABLE="$arg"
  147. fi
  148. done
  149. if [ "$PASS_ARG_TO_GDB" != "" ]; then
  150. GDB_ARGS+=( "$PASS_ARG_TO_GDB" )
  151. fi
  152. if [ "$LAGOM_EXECUTABLE" = "ladybird" ]; then
  153. if [ "$(uname -s)" = "Darwin" ]; then
  154. LAGOM_EXECUTABLE="Ladybird.app"
  155. else
  156. LAGOM_EXECUTABLE="Ladybird"
  157. fi
  158. fi
  159. "$GDB" "$BUILD_DIR/bin/$LAGOM_EXECUTABLE" "${GDB_ARGS[@]}"
  160. }
  161. build_and_run_lagom_target() {
  162. local lagom_target="${CMD_ARGS[0]}"
  163. local lagom_args=("${CMD_ARGS[@]:1}")
  164. if [ -z "$lagom_target" ]; then
  165. lagom_target="Ladybird"
  166. fi
  167. if [ "$lagom_target" = "ladybird" ]; then
  168. lagom_target="Ladybird"
  169. fi
  170. # FIXME: Find some way to centralize these b/w CMakePresets.json, CI files, Documentation and here.
  171. if [ "$BUILD_PRESET" = "Sanitizer" ]; then
  172. export ASAN_OPTIONS=${ASAN_OPTIONS:-"strict_string_checks=1:check_initialization_order=1:strict_init_order=1:detect_stack_use_after_return=1:allocator_may_return_null=1"}
  173. export UBSAN_OPTIONS=${UBSAN_OPTIONS:-"print_stacktrace=1:print_summary=1:halt_on_error=1"}
  174. fi
  175. build_target "${lagom_target}"
  176. if [[ "$lagom_target" =~ ^(headless-browser|ImageDecoder|Ladybird|RequestServer|WebContent|WebDriver|WebWorker)$ ]] && [ "$(uname -s)" = "Darwin" ]; then
  177. "$BUILD_DIR/bin/Ladybird.app/Contents/MacOS/$lagom_target" "${lagom_args[@]}"
  178. else
  179. "$BUILD_DIR/bin/$lagom_target" "${lagom_args[@]}"
  180. fi
  181. }
  182. if [[ "$CMD" =~ ^(build|install|run|gdb|test|rebuild|recreate|addr2line)$ ]]; then
  183. cmd_with_target
  184. [[ "$CMD" != "recreate" && "$CMD" != "rebuild" ]] || delete_target
  185. ensure_toolchain
  186. ensure_target
  187. case "$CMD" in
  188. build)
  189. build_target "${CMD_ARGS[@]}"
  190. ;;
  191. install)
  192. build_target
  193. build_target install
  194. ;;
  195. run)
  196. build_and_run_lagom_target
  197. ;;
  198. gdb)
  199. [ $# -ge 1 ] || usage
  200. build_target "${CMD_ARGS[@]}"
  201. run_gdb "${CMD_ARGS[@]}"
  202. ;;
  203. test)
  204. build_target
  205. run_tests "${CMD_ARGS[0]}"
  206. ;;
  207. rebuild)
  208. build_target "${CMD_ARGS[@]}"
  209. ;;
  210. recreate)
  211. ;;
  212. addr2line)
  213. build_target
  214. [ $# -ge 2 ] || usage
  215. BINARY_FILE="$1"; shift
  216. BINARY_FILE_PATH="$BUILD_DIR/$BINARY_FILE"
  217. command -v addr2line >/dev/null 2>&1 || die "Please install addr2line!"
  218. ADDR2LINE=addr2line
  219. if [ -x "$BINARY_FILE_PATH" ]; then
  220. "$ADDR2LINE" -e "$BINARY_FILE_PATH" "$@"
  221. else
  222. find "$BUILD_DIR" -name "$BINARY_FILE" -executable -type f -exec "$ADDR2LINE" -e {} "$@" \;
  223. fi
  224. ;;
  225. *)
  226. build_target "$CMD" "${CMD_ARGS[@]}"
  227. ;;
  228. esac
  229. elif [ "$CMD" = "delete" ]; then
  230. cmd_with_target
  231. delete_target
  232. elif [ "$CMD" = "vcpkg" ]; then
  233. cmd_with_target
  234. ensure_toolchain
  235. else
  236. >&2 echo "Unknown command: $CMD"
  237. usage
  238. fi