2
0

build.sh 14 KB

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