build.ps1 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. #requires -version 5
  2. <#
  3. .SYNOPSIS
  4. Builds this repository.
  5. .DESCRIPTION
  6. This build script installs required tools and runs an MSBuild command on this repository.
  7. This script can be used to invoke various targets, such as targets to produce packages,
  8. build projects, run tests, and generate code.
  9. .PARAMETER CI
  10. Sets up CI specific settings and variables.
  11. .PARAMETER Restore
  12. Run restore.
  13. .PARAMETER NoRestore
  14. Suppress running restore on projects.
  15. .PARAMETER NoBuild
  16. Suppress re-compile projects. (Implies -NoRestore)
  17. .PARAMETER NoBuildDeps
  18. Do not build project-to-project references and only build the specified project.
  19. .PARAMETER NoBuildRepoTasks
  20. Skip building eng/tools/RepoTasks/
  21. .PARAMETER Pack
  22. Produce packages.
  23. .PARAMETER Test
  24. Run tests.
  25. .PARAMETER Sign
  26. Run code signing.
  27. .PARAMETER Configuration
  28. Debug or Release
  29. .PARAMETER Architecture
  30. The CPU architecture to build for (x64, x86, arm). Default=x64
  31. .PARAMETER Projects
  32. A list of projects to build. Globbing patterns are supported, such as "$(pwd)/**/*.csproj"
  33. .PARAMETER All
  34. Build all project types.
  35. .PARAMETER BuildManaged
  36. Build managed projects (C#, F#, VB).
  37. You can also use -NoBuildManaged to suppress this project type.
  38. .PARAMETER BuildNative
  39. Build native projects (C++).
  40. You can also use -NoBuildNative to suppress this project type.
  41. .PARAMETER BuildNodeJS
  42. Build NodeJS projects (TypeScript, JS).
  43. You can also use -NoBuildNodeJS to suppress this project type.
  44. .PARAMETER BuildJava
  45. Build Java projects.
  46. You can also use -NoBuildJava to suppress this project type.
  47. .PARAMETER BuildInstallers
  48. Build Windows Installers. Required .NET 3.5 to be installed (WiX toolset requirement).
  49. You can also use -NoBuildInstallers to suppress this project type.
  50. .PARAMETER BinaryLog
  51. Enable the binary logger
  52. .PARAMETER Verbosity
  53. MSBuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]
  54. .PARAMETER MSBuildArguments
  55. Additional MSBuild arguments to be passed through.
  56. .EXAMPLE
  57. Building both native and managed projects.
  58. build.ps1 -BuildManaged -BuildNative
  59. .EXAMPLE
  60. Building a subfolder of code.
  61. build.ps1 -projects "$(pwd)/src/SomeFolder/**/*.csproj"
  62. .EXAMPLE
  63. Running tests.
  64. build.ps1 -test
  65. .LINK
  66. Online version: https://github.com/dotnet/aspnetcore/blob/master/docs/BuildFromSource.md
  67. #>
  68. [CmdletBinding(PositionalBinding = $false, DefaultParameterSetName='Groups')]
  69. param(
  70. [switch]$CI,
  71. # Build lifecycle options
  72. [switch]$Restore,
  73. [switch]$NoRestore, # Suppress restore
  74. [switch]$NoBuild, # Suppress compiling
  75. [switch]$NoBuildDeps, # Suppress project to project dependencies
  76. [switch]$Pack, # Produce packages
  77. [switch]$Test, # Run tests
  78. [switch]$Sign, # Code sign
  79. [Alias('c')]
  80. [ValidateSet('Debug', 'Release')]
  81. $Configuration,
  82. [ValidateSet('x64', 'x86', 'arm')]
  83. $Architecture = 'x64',
  84. # A list of projects which should be built.
  85. [string]$Projects,
  86. # Project selection
  87. [switch]$All, # Build everything
  88. # Build a specified set of project groups
  89. [switch]$BuildManaged,
  90. [switch]$BuildNative,
  91. [switch]$BuildNodeJS,
  92. [switch]$BuildJava,
  93. [switch]$BuildInstallers,
  94. # Inverse of the previous switches because specifying '-switch:$false' is not intuitive for most command line users
  95. [switch]$NoBuildManaged,
  96. [switch]$NoBuildNative,
  97. [switch]$NoBuildNodeJS,
  98. [switch]$NoBuildJava,
  99. [switch]$NoBuildInstallers,
  100. [switch]$NoBuildRepoTasks,
  101. # By default, Windows builds will use MSBuild.exe. Passing this will force the build to run on
  102. # dotnet.exe instead, which may cause issues if you invoke build on a project unsupported by
  103. # MSBuild for .NET Core
  104. [switch]$ForceCoreMsbuild,
  105. # Diagnostics
  106. [Alias('bl')]
  107. [switch]$BinaryLog,
  108. [Alias('v')]
  109. [string]$Verbosity = 'minimal',
  110. [switch]$DumpProcesses, # Capture all running processes and dump them to a file.
  111. # Other lifecycle targets
  112. [switch]$Help, # Show help
  113. # Capture the rest
  114. [Parameter(ValueFromRemainingArguments = $true)]
  115. [string[]]$MSBuildArguments
  116. )
  117. Set-StrictMode -Version 2
  118. $ErrorActionPreference = 'Stop'
  119. if ($Help) {
  120. Get-Help $PSCommandPath
  121. exit 1
  122. }
  123. if ($DumpProcesses -or $CI) {
  124. # Dump running processes
  125. Start-Job -Name DumpProcesses -FilePath $PSScriptRoot\eng\scripts\dump_process.ps1 -ArgumentList $PSScriptRoot
  126. }
  127. # Project selection
  128. if ($All) {
  129. $MSBuildArguments += '/p:BuildAllProjects=true'
  130. }
  131. elseif ($Projects) {
  132. if (![System.IO.Path]::IsPathRooted($Projects))
  133. {
  134. $Projects = Join-Path (Get-Location) $Projects
  135. }
  136. $MSBuildArguments += "/p:ProjectToBuild=$Projects"
  137. }
  138. # When adding new sub-group build flags, add them to this check.
  139. elseif((-not $BuildNative) -and (-not $BuildManaged) -and (-not $BuildNodeJS) -and (-not $BuildInstallers) -and (-not $BuildJava)) {
  140. Write-Warning "No default group of projects was specified, so building the 'managed' and its dependent subsets of projects. Run ``build.cmd -help`` for more details."
  141. # This goal of this is to pick a sensible default for `build.cmd` with zero arguments.
  142. # Now that we support subfolder invokations of build.cmd, we will be pushing to have build.cmd build everything (-all) by default
  143. $BuildManaged = $true
  144. }
  145. if ($BuildManaged -or ($All -and (-not $NoBuildManaged))) {
  146. if ((-not $BuildNodeJS) -and (-not $NoBuildNodeJS)) {
  147. $node = Get-Command node -ErrorAction Ignore -CommandType Application
  148. if ($node) {
  149. $nodeHome = Split-Path -Parent (Split-Path -Parent $node.Path)
  150. Write-Host -f Magenta "Building of C# project is enabled and has dependencies on NodeJS projects. Building of NodeJS projects is enabled since node is detected in $nodeHome."
  151. }
  152. else {
  153. Write-Host -f Magenta "Building of NodeJS projects is disabled since node is not detected on Path and no BuildNodeJs or NoBuildNodeJs setting is set explicitly."
  154. $NoBuildNodeJS = $true
  155. }
  156. }
  157. if ($NoBuildNodeJS){
  158. Write-Warning "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."
  159. }
  160. }
  161. if ($BuildInstallers) { $MSBuildArguments += "/p:BuildInstallers=true" }
  162. if ($BuildManaged) { $MSBuildArguments += "/p:BuildManaged=true" }
  163. if ($BuildNative) { $MSBuildArguments += "/p:BuildNative=true" }
  164. if ($BuildNodeJS) { $MSBuildArguments += "/p:BuildNodeJS=true" }
  165. if ($BuildJava) { $MSBuildArguments += "/p:BuildJava=true" }
  166. if ($NoBuildDeps) { $MSBuildArguments += "/p:BuildProjectReferences=false" }
  167. if ($NoBuildInstallers) { $MSBuildArguments += "/p:BuildInstallers=false" }
  168. if ($NoBuildManaged) { $MSBuildArguments += "/p:BuildManaged=false" }
  169. if ($NoBuildNative) { $MSBuildArguments += "/p:BuildNative=false" }
  170. if ($NoBuildNodeJS) { $MSBuildArguments += "/p:BuildNodeJS=false" }
  171. if ($NoBuildJava) { $MSBuildArguments += "/p:BuildJava=false" }
  172. $RunBuild = if ($NoBuild) { $false } else { $true }
  173. # Run restore by default unless -NoRestore is set.
  174. # -NoBuild implies -NoRestore, unless -Restore is explicitly set (as in restore.cmd)
  175. $RunRestore = if ($NoRestore) { $false }
  176. elseif ($Restore) { $true }
  177. elseif ($NoBuild) { $false }
  178. else { $true }
  179. # Target selection
  180. $MSBuildArguments += "/p:Restore=$RunRestore"
  181. $MSBuildArguments += "/p:Build=$RunBuild"
  182. if (-not $RunBuild) {
  183. $MSBuildArguments += "/p:NoBuild=true"
  184. }
  185. $MSBuildArguments += "/p:Pack=$Pack"
  186. $MSBuildArguments += "/p:Test=$Test"
  187. $MSBuildArguments += "/p:Sign=$Sign"
  188. $MSBuildArguments += "/p:TargetArchitecture=$Architecture"
  189. $MSBuildArguments += "/p:TargetOsName=win"
  190. if (-not $Configuration) {
  191. $Configuration = if ($CI) { 'Release' } else { 'Debug' }
  192. }
  193. $MSBuildArguments += "/p:Configuration=$Configuration"
  194. $foundJdk = $false
  195. $javac = Get-Command javac -ErrorAction Ignore -CommandType Application
  196. $localJdkPath = "$PSScriptRoot\.tools\jdk\win-x64\"
  197. if (Test-Path "$localJdkPath\bin\javac.exe") {
  198. $foundJdk = $true
  199. Write-Host -f Magenta "Detected JDK in $localJdkPath (via local repo convention)"
  200. $env:JAVA_HOME = $localJdkPath
  201. }
  202. elseif ($env:JAVA_HOME) {
  203. if (-not (Test-Path "${env:JAVA_HOME}\bin\javac.exe")) {
  204. Write-Error "The environment variable JAVA_HOME was set, but ${env:JAVA_HOME}\bin\javac.exe does not exist. Remove JAVA_HOME or update it to the correct location for the JDK. See https://www.bing.com/search?q=java_home for details."
  205. }
  206. else {
  207. Write-Host -f Magenta "Detected JDK in ${env:JAVA_HOME} (via JAVA_HOME)"
  208. $foundJdk = $true
  209. }
  210. }
  211. elseif ($javac) {
  212. $foundJdk = $true
  213. $javaHome = Split-Path -Parent (Split-Path -Parent $javac.Path)
  214. $env:JAVA_HOME = $javaHome
  215. Write-Host -f Magenta "Detected JDK in $javaHome (via PATH)"
  216. }
  217. else {
  218. try {
  219. $jdkRegistryKeys = @(
  220. "HKLM:\SOFTWARE\JavaSoft\JDK", # for JDK 10+
  221. "HKLM:\SOFTWARE\JavaSoft\Java Development Kit" # fallback for JDK 8
  222. )
  223. $jdkRegistryKey = $jdkRegistryKeys | Where-Object { Test-Path $_ } | Select-Object -First 1
  224. if ($jdkRegistryKey) {
  225. $jdkVersion = (Get-Item $jdkRegistryKey | Get-ItemProperty -name CurrentVersion).CurrentVersion
  226. $javaHome = (Get-Item $jdkRegistryKey\$jdkVersion | Get-ItemProperty -Name JavaHome).JavaHome
  227. if (Test-Path "${javaHome}\bin\javac.exe") {
  228. $env:JAVA_HOME = $javaHome
  229. Write-Host -f Magenta "Detected JDK $jdkVersion in $env:JAVA_HOME (via registry)"
  230. $foundJdk = $true
  231. }
  232. }
  233. }
  234. catch {
  235. Write-Verbose "Failed to detect Java: $_"
  236. }
  237. }
  238. if ($env:PATH -notlike "*${env:JAVA_HOME}*") {
  239. $env:PATH = "$(Join-Path $env:JAVA_HOME bin);${env:PATH}"
  240. }
  241. if (-not $foundJdk -and $RunBuild -and ($All -or $BuildJava) -and -not $NoBuildJava) {
  242. Write-Error "Could not find the JDK. Either run $PSScriptRoot\eng\scripts\InstallJdk.ps1 to install for this repo, or install the JDK globally on your machine (see $PSScriptRoot\docs\BuildFromSource.md for details)."
  243. }
  244. # Initialize global variables need to be set before the import of Arcade is imported
  245. $restore = $RunRestore
  246. # Though VS Code may indicate $nodeReuse, $warnAsError and $msbuildEngine are unused, tools.ps1 uses them.
  247. # Disable node reuse - Workaround perpetual issues in node reuse and custom task assemblies
  248. $nodeReuse = $false
  249. $env:MSBUILDDISABLENODEREUSE=1
  250. # Our build often has warnings that we can't fix, like "MSB3026: Could not copy" due to race
  251. # conditions in building C++
  252. # Fixing this is tracked by https://github.com/dotnet/aspnetcore-internal/issues/601
  253. $warnAsError = $false
  254. if ($ForceCoreMsbuild) {
  255. $msbuildEngine = 'dotnet'
  256. }
  257. # Workaround Arcade check which asserts BinaryLog is true on CI.
  258. # We always use binlogs on CI, but we customize the name of the log file
  259. $tmpBinaryLog = $BinaryLog
  260. if ($CI) {
  261. $BinaryLog = $true
  262. }
  263. # tools.ps1 corrupts global state, so reset these values in case they carried over from a previous build
  264. Remove-Item variable:global:_BuildTool -ea Ignore
  265. Remove-Item variable:global:_DotNetInstallDir -ea Ignore
  266. Remove-Item variable:global:_ToolsetBuildProj -ea Ignore
  267. Remove-Item variable:global:_MSBuildExe -ea Ignore
  268. # Import Arcade
  269. . "$PSScriptRoot/eng/common/tools.ps1"
  270. if ($tmpBinaryLog) {
  271. $MSBuildArguments += "/bl:$LogDir/Build.binlog"
  272. }
  273. # Capture MSBuild crash logs
  274. $env:MSBUILDDEBUGPATH = $LogDir
  275. $local:exit_code = $null
  276. try {
  277. # Import custom tools configuration, if present in the repo.
  278. # Note: Import in global scope so that the script set top-level variables without qualification.
  279. $configureToolsetScript = Join-Path $EngRoot "configure-toolset.ps1"
  280. if (Test-Path $configureToolsetScript) {
  281. . $configureToolsetScript
  282. }
  283. # Set this global property so Arcade will always initialize the toolset. The error message you get when you build on a clean machine
  284. # with -norestore is not obvious about what to do to fix it. As initialization takes very little time, we think always initializing
  285. # the toolset is a better default behavior.
  286. $tmpRestore = $restore
  287. $restore = $true
  288. $toolsetBuildProj = InitializeToolset
  289. $restore = $tmpRestore
  290. if ($ci) {
  291. $global:VerbosePreference = 'Continue'
  292. }
  293. if (-not $NoBuildRepoTasks) {
  294. MSBuild $toolsetBuildProj `
  295. /p:RepoRoot=$RepoRoot `
  296. /p:Projects=$EngRoot\tools\RepoTasks\RepoTasks.csproj `
  297. /p:Configuration=Release `
  298. /p:Restore=$RunRestore `
  299. /p:Build=true `
  300. /clp:NoSummary
  301. }
  302. MSBuild $toolsetBuildProj `
  303. /p:RepoRoot=$RepoRoot `
  304. @MSBuildArguments
  305. }
  306. catch {
  307. Write-Host $_.ScriptStackTrace
  308. Write-PipelineTaskError -Message $_
  309. $exit_code = 1
  310. }
  311. finally {
  312. if (! $exit_code) {
  313. $exit_code = $LASTEXITCODE
  314. }
  315. # tools.ps1 corrupts global state, so reset these values so they don't carry between invocations of build.ps1
  316. Remove-Item variable:global:_BuildTool -ea Ignore
  317. Remove-Item variable:global:_DotNetInstallDir -ea Ignore
  318. Remove-Item variable:global:_ToolsetBuildProj -ea Ignore
  319. Remove-Item variable:global:_MSBuildExe -ea Ignore
  320. if ($DumpProcesses -or $ci) {
  321. Stop-Job -Name DumpProcesses
  322. Remove-Job -Name DumpProcesses
  323. }
  324. if ($ci) {
  325. & "$PSScriptRoot/eng/scripts/KillProcesses.ps1"
  326. }
  327. }
  328. ExitWithExitCode $exit_code