build.sh 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. #!/usr/bin/env bash
  2. set -euo pipefail
  3. #
  4. # variables
  5. #
  6. RESET="\033[0m"
  7. RED="\033[0;31m"
  8. YELLOW="\033[0;33m"
  9. DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
  10. target_os_name=''
  11. ci=false
  12. binary_log=false
  13. exclude_ci_binary_log=false
  14. verbosity='minimal'
  15. run_restore=''
  16. run_build=true
  17. run_pack=false
  18. run_tests=false
  19. build_all=false
  20. build_deps=true
  21. build_repo_tasks=true
  22. build_managed=''
  23. build_native=''
  24. build_nodejs=''
  25. build_java=''
  26. build_installers=''
  27. build_projects=''
  28. target_arch='x64'
  29. configuration=''
  30. runtime_source_feed=''
  31. runtime_source_feed_key=''
  32. if [ "$(uname)" = "Darwin" ]; then
  33. target_os_name='osx'
  34. else
  35. target_os_name='linux'
  36. fi
  37. msbuild_args=()
  38. #
  39. # Functions
  40. #
  41. __usage() {
  42. echo "Usage: $(basename "${BASH_SOURCE[0]}") [options] [[--] <Arguments>...]
  43. Arguments:
  44. <Arguments>... Arguments passed to the command. Variable number of arguments allowed.
  45. Options:
  46. --configuration|-c The build configuration (Debug, Release). Default=Debug
  47. --arch The CPU architecture to build for (x64, arm, arm64). Default=$target_arch
  48. --os-name The base runtime identifier to build for (linux, osx, linux-musl). Default=$target_os_name
  49. --[no-]restore Run restore.
  50. --[no-]build Compile projects. (Implies --no-restore)
  51. --[no-]pack Produce packages.
  52. --[no-]test Run tests.
  53. --projects A list of projects to build. (Must be an absolute path.)
  54. Globbing patterns are supported, such as \"$(pwd)/**/*.csproj\".
  55. --no-build-deps Do not build project-to-project references and only build the specified project.
  56. --no-build-repo-tasks Suppress building RepoTasks.
  57. --all Build all project types.
  58. --[no-]build-native Build native projects (C, C++). Ignored in most cases i.e. with `dotnet msbuild`.
  59. --[no-]build-managed Build managed projects (C#, F#, VB).
  60. --[no-]build-nodejs Build NodeJS projects (TypeScript, JS).
  61. --[no-]build-java Build Java projects.
  62. --[no-]build-installers Build Java projects.
  63. --ci Apply CI specific settings and environment variables.
  64. --binarylog|-bl Use a binary logger
  65. --excludeCIBinarylog Don't output binary log by default in CI builds (short: -nobl).
  66. --verbosity|-v MSBuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]
  67. --runtime-source-feed Additional feed that can be used when downloading .NET runtimes and SDKs
  68. --runtime-source-feed-key Key for feed that can be used when downloading .NET runtimes and SDKs
  69. Description:
  70. This build script installs required tools and runs an MSBuild command on this repository
  71. This script can be used to invoke various targets, such as targets to produce packages
  72. build projects, run tests, and generate code.
  73. "
  74. if [[ "${1:-}" != '--no-exit' ]]; then
  75. exit 2
  76. fi
  77. }
  78. __error() {
  79. echo -e "${RED}error: $*${RESET}" 1>&2
  80. }
  81. __warn() {
  82. echo -e "${YELLOW}warning: $*${RESET}"
  83. }
  84. #
  85. # main
  86. #
  87. while [[ $# -gt 0 ]]; do
  88. opt="$(echo "${1/#--/-}" | awk '{print tolower($0)}')"
  89. case "$opt" in
  90. -\?|-h|-help)
  91. __usage --no-exit
  92. exit 0
  93. ;;
  94. -configuration|-c)
  95. shift
  96. configuration="${1:-}"
  97. [ -z "$configuration" ] && __error "Missing value for parameter --configuration" && __usage
  98. ;;
  99. -arch)
  100. shift
  101. target_arch="${1:-}"
  102. [ -z "$target_arch" ] && __error "Missing value for parameter --arch" && __usage
  103. ;;
  104. -os-name|-osname)
  105. shift
  106. target_os_name="${1:-}"
  107. [ -z "$target_os_name" ] && __error "Missing value for parameter --os-name" && __usage
  108. ;;
  109. -restore|-r)
  110. run_restore=true
  111. ;;
  112. -no-restore|-norestore)
  113. run_restore=false
  114. ;;
  115. -build|-b)
  116. run_build=true
  117. ;;
  118. -no-build|-nobuild)
  119. run_build=false
  120. # --no-build implies --no-restore
  121. [ -z "$run_restore" ] && run_restore=false
  122. ;;
  123. -no-build-deps|-nobuilddeps)
  124. build_deps=false
  125. ;;
  126. -pack)
  127. run_pack=true
  128. ;;
  129. -no-pack|-nopack)
  130. run_pack=false
  131. ;;
  132. -test|-t)
  133. run_tests=true
  134. ;;
  135. -no-test|-notest)
  136. run_tests=false
  137. ;;
  138. -projects)
  139. shift
  140. build_projects="${1:-}"
  141. [ -z "$build_projects" ] && __error "Missing value for parameter --projects" && __usage
  142. ;;
  143. -all)
  144. build_all=true
  145. ;;
  146. -build-managed|-buildmanaged)
  147. build_managed=true
  148. ;;
  149. -no-build-managed|-nobuildmanaged)
  150. build_managed=false
  151. ;;
  152. -build-nodejs|-buildnodejs)
  153. build_nodejs=true
  154. ;;
  155. -no-build-nodejs|-nobuildnodejs)
  156. build_nodejs=false
  157. ;;
  158. -build-java|-buildjava)
  159. build_java=true
  160. ;;
  161. -no-build-java|-nobuildjava)
  162. build_java=false
  163. ;;
  164. -build-native|-buildnative)
  165. build_native=true
  166. ;;
  167. -no-build-native|-nobuildnative)
  168. build_native=false
  169. ;;
  170. -build-installers|-buildinstallers)
  171. build_installers=true
  172. ;;
  173. -no-build-installers|-nobuildinstallers)
  174. build_installers=false
  175. ;;
  176. -no-build-repo-tasks|-nobuildrepotasks)
  177. build_repo_tasks=false
  178. ;;
  179. -arch)
  180. shift
  181. target_arch="${1:-}"
  182. [ -z "$target_arch" ] && __error "Missing value for parameter --arch" && __usage
  183. ;;
  184. -ci)
  185. ci=true
  186. ;;
  187. -binarylog|-bl)
  188. binary_log=true
  189. ;;
  190. -excludeCIBinarylog|-nobl)
  191. exclude_ci_binary_log=true
  192. ;;
  193. -dotnet-runtime-source-feed|-dotnetruntimesourcefeed|-runtime-source-feed|-runtimesourcefeed)
  194. shift
  195. [ -z "${1:-}" ] && __error "Missing value for parameter --runtime-source-feed" && __usage
  196. runtime_source_feed="${1:-}"
  197. ;;
  198. -dotnet-runtime-source-feed-key|-dotnetruntimesourcefeedkey|-runtime-source-feed-key|-runtimesourcefeedkey)
  199. shift
  200. [ -z "${1:-}" ] && __error "Missing value for parameter --runtime-source-feed-key" && __usage
  201. runtime_source_feed_key="${1:-}"
  202. ;;
  203. *)
  204. msbuild_args[${#msbuild_args[*]}]="$1"
  205. ;;
  206. esac
  207. shift
  208. done
  209. if [ "$build_all" = true ]; then
  210. msbuild_args[${#msbuild_args[*]}]="-p:BuildAllProjects=true"
  211. fi
  212. if [ ! -z "$build_projects" ]; then
  213. msbuild_args[${#msbuild_args[*]}]="-p:ProjectToBuild=$build_projects"
  214. elif [ "$build_all" != true ] && [ -z "$build_managed$build_nodejs$build_java$build_native$build_installers" ]; then
  215. # This goal of this is to pick a sensible default for `build.sh` with zero arguments.
  216. # We believe the most common thing our contributors will work on is C#, so if no other build group was picked, build the C# projects.
  217. __warn "No default group of projects was specified, so building the 'managed' and its dependent subset of projects. Run ``build.sh --help`` for more details."
  218. build_managed=true
  219. fi
  220. if [ "$build_deps" = false ]; then
  221. msbuild_args[${#msbuild_args[*]}]="-p:BuildProjectReferences=false"
  222. fi
  223. if [ "$build_managed" = true ] || ([ "$build_all" = true ] && [ "$build_managed" != false ]); then
  224. if [ -z "$build_nodejs" ]; then
  225. if [ -x "$(command -v node)" ]; then
  226. __warn "Building of C# project is enabled and has dependencies on NodeJS projects. Building of NodeJS projects is enabled since node is detected on PATH."
  227. else
  228. __warn "Building of NodeJS projects is disabled since node is not detected on Path and no BuildNodeJs or NoBuildNodeJs setting is set explicitly."
  229. build_nodejs=false
  230. fi
  231. fi
  232. if [ "$build_nodejs" = false ]; then
  233. __warn "Some managed projects depend on NodeJS projects. Building NodeJS is disabled so the managed projects will fallback to using the output from previous builds. The output may not be correct or up to date."
  234. fi
  235. fi
  236. # Only set these MSBuild properties if they were explicitly set by build parameters.
  237. [ ! -z "$build_java" ] && msbuild_args[${#msbuild_args[*]}]="-p:BuildJava=$build_java"
  238. [ ! -z "$build_native" ] && msbuild_args[${#msbuild_args[*]}]="-p:BuildNative=$build_native"
  239. [ ! -z "$build_nodejs" ] && msbuild_args[${#msbuild_args[*]}]="-p:BuildNodeJS=$build_nodejs"
  240. [ ! -z "$build_managed" ] && msbuild_args[${#msbuild_args[*]}]="-p:BuildManaged=$build_managed"
  241. [ ! -z "$build_installers" ] && msbuild_args[${#msbuild_args[*]}]="-p:BuildInstallers=$build_installers"
  242. # Run restore by default unless --no-restore or --no-build was specified.
  243. [ -z "$run_restore" ] && run_restore=true
  244. msbuild_args[${#msbuild_args[*]}]="-p:Restore=$run_restore"
  245. msbuild_args[${#msbuild_args[*]}]="-p:Build=$run_build"
  246. if [ "$run_build" = false ]; then
  247. msbuild_args[${#msbuild_args[*]}]="-p:NoBuild=true"
  248. fi
  249. msbuild_args[${#msbuild_args[*]}]="-p:Pack=$run_pack"
  250. msbuild_args[${#msbuild_args[*]}]="-p:Test=$run_tests"
  251. msbuild_args[${#msbuild_args[*]}]="-p:TargetArchitecture=$target_arch"
  252. msbuild_args[${#msbuild_args[*]}]="-p:TargetOsName=$target_os_name"
  253. if [ -z "$configuration" ]; then
  254. if [ "$ci" = true ]; then
  255. configuration='Release'
  256. else
  257. configuration='Debug'
  258. fi
  259. fi
  260. msbuild_args[${#msbuild_args[*]}]="-p:Configuration=$configuration"
  261. # Set up additional runtime args
  262. toolset_build_args=()
  263. if [ ! -z "$runtime_source_feed$runtime_source_feed_key" ]; then
  264. runtimeFeedArg="/p:DotNetRuntimeSourceFeed=$runtime_source_feed"
  265. runtimeFeedKeyArg="/p:DotNetRuntimeSourceFeedKey=$runtime_source_feed_key"
  266. msbuild_args[${#msbuild_args[*]}]=$runtimeFeedArg
  267. msbuild_args[${#msbuild_args[*]}]=$runtimeFeedKeyArg
  268. toolset_build_args[${#toolset_build_args[*]}]=$runtimeFeedArg
  269. toolset_build_args[${#toolset_build_args[*]}]=$runtimeFeedKeyArg
  270. fi
  271. # Initialize global variables need to be set before the import of Arcade is imported
  272. restore=$run_restore
  273. # Disable node reuse - Workaround perpetual issues in node reuse and custom task assemblies
  274. nodeReuse=false
  275. export MSBUILDDISABLENODEREUSE=1
  276. # Ensure passing neither --bl nor --nobl on CI avoids errors in tools.sh. This is needed because we set both variables
  277. # to false by default i.e. they always exist. (We currently avoid binary logs but that is made visible in the YAML.)
  278. if [[ "$ci" == true && "$exclude_ci_binary_log" == false ]]; then
  279. binary_log=true
  280. fi
  281. # increase file descriptor limit on macOS
  282. if [ "$(uname)" = "Darwin" ]; then
  283. ulimit -n 10000
  284. fi
  285. # Import Arcade
  286. . "$DIR/eng/common/tools.sh"
  287. # Add default .binlog location if not already on the command line. tools.sh does not handle this; it just checks
  288. # $binary_log, $ci and $exclude_ci_binary_log values for an error case.
  289. if [[ "$binary_log" == true ]]; then
  290. found=false
  291. for arg in "${msbuild_args[@]}"; do
  292. opt="$(echo "${arg/#--/-}" | awk '{print tolower($0)}')"
  293. if [[ "$opt" == [-/]bl:* || "$opt" == [-/]binarylogger:* ]]; then
  294. found=true
  295. break
  296. fi
  297. done
  298. if [[ "$found" == false ]]; then
  299. msbuild_args[${#msbuild_args[*]}]="/bl:$log_dir/Build.binlog"
  300. fi
  301. elif [[ "$ci" == true ]]; then
  302. # Ensure the artifacts/log directory isn't empty to avoid warnings.
  303. touch "$log_dir/empty.log"
  304. fi
  305. # Capture MSBuild crash logs
  306. export MSBUILDDEBUGPATH="$log_dir"
  307. # Set this global property so Arcade will always initialize the toolset. The error message you get when you build on a clean machine
  308. # with -norestore is not obvious about what to do to fix it. As initialization takes very little time, we think always initializing
  309. # the toolset is a better default behavior.
  310. _tmp_restore=$restore
  311. restore=true
  312. InitializeToolset
  313. restore=$_tmp_restore=
  314. if [ "$build_repo_tasks" = true ]; then
  315. MSBuild $_InitializeToolset \
  316. -p:RepoRoot="$repo_root" \
  317. -p:Projects="$DIR/eng/tools/RepoTasks/RepoTasks.csproj" \
  318. -p:Configuration=Release \
  319. -p:Restore=$run_restore \
  320. -p:Build=true \
  321. -clp:NoSummary \
  322. ${toolset_build_args[@]+"${toolset_build_args[@]}"}
  323. fi
  324. # This incantation avoids unbound variable issues if msbuild_args is empty
  325. # https://stackoverflow.com/questions/7577052/bash-empty-array-expansion-with-set-u
  326. MSBuild $_InitializeToolset -p:RepoRoot="$repo_root" ${msbuild_args[@]+"${msbuild_args[@]}"}
  327. ExitWithExitCode 0