From 92a37b4675f3735e5fd01daa2be039fc35be417e Mon Sep 17 00:00:00 2001 From: Francisco Gamino Date: Fri, 29 Jul 2016 10:00:46 -0700 Subject: [PATCH 1/8] Enable crossgen for PowerShell binaries on Windows --- build.psm1 | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 134 insertions(+), 5 deletions(-) diff --git a/build.psm1 b/build.psm1 index c1baffc74..115a71cb0 100644 --- a/build.psm1 +++ b/build.psm1 @@ -45,9 +45,6 @@ function Start-PSBuild { # it's useful for development, to do a quick changes in the engine [switch]$SMAOnly, - [Parameter(ParameterSetName='CoreCLR')] - [switch]$Publish, - # These runtimes must match those in project.json # We do not use ValidateScript since we want tab completion [ValidateSet("ubuntu.14.04-x64", @@ -71,7 +68,16 @@ function Start-PSBuild { [string]$NativeHostArch = "x64", [ValidateSet('Linux', 'Debug', 'Release', '')] # We might need "Checked" as well - [string]$Configuration + [string]$Configuration, + + [Parameter(ParameterSetName='CrossGen', Mandatory=$true)] + [switch]$Publish, + + [Parameter(ParameterSetName='CrossGen', Mandatory=$true)] + [switch]$CrossGen, + + [Parameter(ParameterSetName='CrossGen', Mandatory=$true)] + [switch]$RemoveILs ) function Stop-DevPowerShell @@ -328,7 +334,17 @@ cmd.exe /C cd /d "$location" "&" "$($vcVarsPath)\vcvarsall.bat" "$NativeHostArch Push-Location $Options.Top log "Run dotnet $Arguments from $pwd" Start-NativeExecution { dotnet $Arguments } - log "PowerShell output: $($Options.Output)" + + if ($CrossGen -and $IsWindows) + { + $publishPath = Split-Path $Options.Output + Start-CrossGen -PublishPath $publishPath -RemoveILs:$RemoveILs + log "PowerShell.exe with ngen binaries is available at $($Options.Output)" + } + else + { + log "PowerShell output: $($Options.Output)" + } } finally { Pop-Location } @@ -1917,3 +1933,116 @@ $script:RESX_TEMPLATE = @' {0} '@ + + +function Start-CrossGen { + + param ( + [Parameter(Mandatory= $true)] + [ValidateNotNullOrEmpty()] + [String] + $PublishPath, + [switch]$RemoveILs + ) + + # Helper functions + + function Get-PSCoreAssemblyList { + + $psAssemblies = @() + $psAssemblies += "Microsoft.PowerShell.Commands.Utility.dll" + $psAssemblies += "Microsoft.PowerShell.Commands.Management.dll" + $psAssemblies += "Microsoft.PowerShell.Security.dll" + $psAssemblies += "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll" + $psAssemblies += "Microsoft.PowerShell.CoreCLR.Eventing.dll" + $psAssemblies += "Microsoft.PowerShell.ConsoleHost.dll" + $psAssemblies += "Microsoft.PowerShell.LocalAccounts.dll" + $psAssemblies += "Microsoft.PowerShell.Commands.Diagnostics.dll" + $psAssemblies += "Microsoft.Management.Infrastructure.CimCmdlets.dll" + $psAssemblies += "System.Management.Automation.dll" + + # TODO: These need to be enable once they are ported to OPS. + #$psAssemblies += "Microsoft.WSMan.Management.dll" + #$psAssemblies += "Microsoft.WSMan.Runtime.dll" + #$psAssemblies += "Microsoft.PowerShell.ConsoleHost.dll" + + return $psAssemblies + } + + function Generate-CrossGenAssembly { + + param ( + [Parameter(Mandatory= $true)] + [ValidateNotNullOrEmpty()] + [String] + $AssemblyPath, + [Parameter(Mandatory= $true)] + [ValidateNotNullOrEmpty()] + [String] + $CrossgenPath + ) + + $outputAssembly = $AssemblyPath.Replace(".dll", ".ni.dll") + $platformAssembliesPath = Split-Path $AssemblyPath -Parent + $crossgenFolder = Split-Path $CrossgenPath + $niAssemblyName = Split-Path $outputAssembly -Leaf + + try + { + Push-Location $crossgenFolder + + # Generate the ngen binary + Write-Host "Generating assembly $niAssemblyName ..." + $null = & $CrossgenPath /MissingDependenciesOK /in $AssemblyPath /out $outputAssembly /Platform_Assemblies_Paths $platformAssembliesPath + + # TODO: Generate the pdb for the ngen binary - currently, there is a hard dependency on diasymreader.dll, which is available at %windir%\Microsoft.NET\Framework\v4.0.30319. + # However, we still need to figure out the prerequisites on Linux. + # & $CrossgenPath /Platform_Assemblies_Paths $platformAssembliesPath /CreatePDB $platformAssembliesPath /lines $platformAssembliesPath $niAssemblyName + } + finally + { + Pop-Location + } + } + + if (-not (Test-Path $PublishPath)) + { + throw "Path '$PublishPath' does not exist." + } + + # Get the path to crossgen.exe. + $crossGenPath = Get-ChildItem "$PSScriptRoot\Packages\*crossgen.exe" -Recurse | Where-Object {$_.FullName -match 'x64'} | select -First 1 | % {$_.FullName} + if (-not $crossGenPath) + { + throw "Unable to find latest version of crossgen.exe. 'Please run Start-PSBuild -Clean' first, and then try again." + } + + # Crossgen.exe requires the following assemblies: + # mscorlib.dll + # System.Private.CoreLib.dll + # clrjit.dll + $crossGenRequiredAssemblies = @("mscorlib.dll", "System.Private.CoreLib.dll", "clrjit.dll") + $crossGenFolder = Split-Path $crossGenPath + + # Make sure that all dependencies required by crossgen.exe are at the directory. + foreach ($assemblyName in $crossGenRequiredAssemblies) + { + if (-not (Test-Path "$crossGenFolder\$assemblyName")) + { + Copy-Item -Path "$PublishPath\$assemblyName" -Destination $crossGenFolder + } + } + + # Get a list of ps assemblies to ngen. + $psCoreAssemblies = Get-PSCoreAssemblyList + foreach ($assemblyName in $psCoreAssemblies) + { + $assemblyPath = Join-Path $PublishPath $assemblyName + Generate-CrossGenAssembly -CrossgenPath $crossGenPath -AssemblyPath $assemblyPath + + if ($RemoveILs) + { + Remove-Item $assemblyPath -Force + } + } +} \ No newline at end of file From 733c9f0ab9a4774f5cc46761d712de2e4115eb4c Mon Sep 17 00:00:00 2001 From: Francisco Gamino Date: Tue, 2 Aug 2016 10:38:12 -0700 Subject: [PATCH 2/8] Enable crossgen for PowerShell assemblies on Linux --- build.psm1 | 138 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 85 insertions(+), 53 deletions(-) diff --git a/build.psm1 b/build.psm1 index 115a71cb0..f2f5212a3 100644 --- a/build.psm1 +++ b/build.psm1 @@ -70,14 +70,11 @@ function Start-PSBuild { [ValidateSet('Linux', 'Debug', 'Release', '')] # We might need "Checked" as well [string]$Configuration, - [Parameter(ParameterSetName='CrossGen', Mandatory=$true)] + [Parameter(ParameterSetName='Publish')] [switch]$Publish, - [Parameter(ParameterSetName='CrossGen', Mandatory=$true)] - [switch]$CrossGen, - - [Parameter(ParameterSetName='CrossGen', Mandatory=$true)] - [switch]$RemoveILs + [Parameter(ParameterSetName='Publish')] + [switch]$CrossGen ) function Stop-DevPowerShell @@ -335,11 +332,11 @@ cmd.exe /C cd /d "$location" "&" "$($vcVarsPath)\vcvarsall.bat" "$NativeHostArch log "Run dotnet $Arguments from $pwd" Start-NativeExecution { dotnet $Arguments } - if ($CrossGen -and $IsWindows) + if ($CrossGen) { $publishPath = Split-Path $Options.Output - Start-CrossGen -PublishPath $publishPath -RemoveILs:$RemoveILs - log "PowerShell.exe with ngen binaries is available at $($Options.Output)" + Start-NativeExecution { Start-CrossGen -PublishPath $publishPath } + log "PowerShell.exe with ngen binaries is available at: $($Options.Output)" } else { @@ -1934,43 +1931,18 @@ $script:RESX_TEMPLATE = @' '@ - function Start-CrossGen { - - param ( - [Parameter(Mandatory= $true)] - [ValidateNotNullOrEmpty()] - [String] - $PublishPath, - [switch]$RemoveILs + [CmdletBinding()] + param( + [Parameter(Mandatory= $true)] + [ValidateNotNullOrEmpty()] + [String] + $PublishPath ) # Helper functions - - function Get-PSCoreAssemblyList { - - $psAssemblies = @() - $psAssemblies += "Microsoft.PowerShell.Commands.Utility.dll" - $psAssemblies += "Microsoft.PowerShell.Commands.Management.dll" - $psAssemblies += "Microsoft.PowerShell.Security.dll" - $psAssemblies += "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll" - $psAssemblies += "Microsoft.PowerShell.CoreCLR.Eventing.dll" - $psAssemblies += "Microsoft.PowerShell.ConsoleHost.dll" - $psAssemblies += "Microsoft.PowerShell.LocalAccounts.dll" - $psAssemblies += "Microsoft.PowerShell.Commands.Diagnostics.dll" - $psAssemblies += "Microsoft.Management.Infrastructure.CimCmdlets.dll" - $psAssemblies += "System.Management.Automation.dll" - - # TODO: These need to be enable once they are ported to OPS. - #$psAssemblies += "Microsoft.WSMan.Management.dll" - #$psAssemblies += "Microsoft.WSMan.Runtime.dll" - #$psAssemblies += "Microsoft.PowerShell.ConsoleHost.dll" - - return $psAssemblies - } function Generate-CrossGenAssembly { - param ( [Parameter(Mandatory= $true)] [ValidateNotNullOrEmpty()] @@ -1991,9 +1963,14 @@ function Start-CrossGen { { Push-Location $crossgenFolder - # Generate the ngen binary + # Generate the ngen assembly Write-Host "Generating assembly $niAssemblyName ..." $null = & $CrossgenPath /MissingDependenciesOK /in $AssemblyPath /out $outputAssembly /Platform_Assemblies_Paths $platformAssembliesPath + + if ($LASTEXITCODE -ne 0) + { + throw "Fail to ngen assembly '$AssemblyPath'" + } # TODO: Generate the pdb for the ngen binary - currently, there is a hard dependency on diasymreader.dll, which is available at %windir%\Microsoft.NET\Framework\v4.0.30319. # However, we still need to figure out the prerequisites on Linux. @@ -2010,8 +1987,19 @@ function Start-CrossGen { throw "Path '$PublishPath' does not exist." } - # Get the path to crossgen.exe. - $crossGenPath = Get-ChildItem "$PSScriptRoot\Packages\*crossgen.exe" -Recurse | Where-Object {$_.FullName -match 'x64'} | select -First 1 | % {$_.FullName} + $runTime = (New-PSOptions).Runtime + if (-not $runTime) + { + throw "Unable to determine Runtime Identifier, please update dotnet." + } + + # Get the path to crossgen.exe on Windows and crossgen on Linux. + $crossGenPath = if ($IsWindows) { + Get-ChildItem "$PSScriptRoot\Packages\*crossgen.exe" -Recurse | Where-Object {$_.FullName -match 'x64'} | select -First 1 | % {$_.FullName} + } else { + Get-ChildItem "~/.nuget/packages/*crossgen" -Recurse | Where-Object {$_.FullName -match $runTime} | % {$_.FullName} + } + if (-not $crossGenPath) { throw "Unable to find latest version of crossgen.exe. 'Please run Start-PSBuild -Clean' first, and then try again." @@ -2020,11 +2008,16 @@ function Start-CrossGen { # Crossgen.exe requires the following assemblies: # mscorlib.dll # System.Private.CoreLib.dll - # clrjit.dll - $crossGenRequiredAssemblies = @("mscorlib.dll", "System.Private.CoreLib.dll", "clrjit.dll") - $crossGenFolder = Split-Path $crossGenPath - + # clrjit.dll on Windows or libclrjit.so on Linux + # + $crossGenRequiredAssemblies = if ($IsWindows) { + "mscorlib.dll", "System.Private.CoreLib.dll", "clrjit.dll" + } else { + "mscorlib.dll", "System.Private.CoreLib.dll", "libclrjit.so" + } + # Make sure that all dependencies required by crossgen.exe are at the directory. + $crossGenFolder = Split-Path $crossGenPath foreach ($assemblyName in $crossGenRequiredAssemblies) { if (-not (Test-Path "$crossGenFolder\$assemblyName")) @@ -2033,16 +2026,55 @@ function Start-CrossGen { } } + <# # Get a list of ps assemblies to ngen. - $psCoreAssemblies = Get-PSCoreAssemblyList - foreach ($assemblyName in $psCoreAssemblies) + # TODO: These need to be enable once they are ported to OSPS. + "Microsoft.WSMan.Management.dll", + "Microsoft.WSMan.Runtime.dll", + "Microsoft.PowerShell.ConsoleHost.dll" + #> + + $script:psCoreAssemblyList = if ($IsWindows) { + "Microsoft.PowerShell.Commands.Utility.dll", + "Microsoft.PowerShell.Commands.Management.dll", + "Microsoft.PowerShell.Security.dll", + "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll", + "Microsoft.PowerShell.CoreCLR.Eventing.dll", + "Microsoft.PowerShell.ConsoleHost.dll", + "Microsoft.PowerShell.LocalAccounts.dll", + "Microsoft.PowerShell.Commands.Diagnostics.dll", + "Microsoft.Management.Infrastructure.CimCmdlets.dll", + "Microsoft.PowerShell.PackageManagement.dll", + "Microsoft.PowerShell.PSReadLine.dll", + "System.Management.Automation.dll" + } else { + "Microsoft.PowerShell.Commands.Utility.dll", + "Microsoft.PowerShell.Commands.Management.dll", + "Microsoft.PowerShell.Security.dll", + "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll", + "Microsoft.PowerShell.CoreCLR.Eventing.dll", + "Microsoft.PowerShell.ConsoleHost.dll", + "Microsoft.PowerShell.PackageManagement.dll", + "Microsoft.PowerShell.PSReadLine.dll", + "System.Management.Automation.dll" + + # These are not present on Linux yet. + # "Microsoft.PowerShell.LocalAccounts.dll" + # "Microsoft.PowerShell.Commands.Diagnostics.dll" + # "Microsoft.Management.Infrastructure.CimCmdlets.dll" + } + + foreach ($assemblyName in $script:psCoreAssemblyList) { $assemblyPath = Join-Path $PublishPath $assemblyName Generate-CrossGenAssembly -CrossgenPath $crossGenPath -AssemblyPath $assemblyPath - if ($RemoveILs) - { - Remove-Item $assemblyPath -Force - } + # After the assembly is generated sucessfully, remove the IL assembly and symbols. + $symbolsPath = $assemblyPath.Replace(".dll", ".pdb") + Remove-Item $assemblyPath -Force -ErrorAction SilentlyContinue + Remove-Item $symbolsPath -Force -ErrorAction SilentlyContinue } + + # Let the user know that the IL assemblies have been deleted. + Write-Verbose "PowerShell Ngen assemblies have been generated, and ILs have been deleted." -Verbose } \ No newline at end of file From 58e7f480c44cd5b65602b106ee3c68cefbd40cd0 Mon Sep 17 00:00:00 2001 From: Francisco Gamino Date: Tue, 2 Aug 2016 13:33:51 -0700 Subject: [PATCH 3/8] Addressing code review comments --- build.psm1 | 296 ++++++++++++++++++++++++++--------------------------- 1 file changed, 146 insertions(+), 150 deletions(-) diff --git a/build.psm1 b/build.psm1 index f2f5212a3..71e8f9732 100644 --- a/build.psm1 +++ b/build.psm1 @@ -70,7 +70,7 @@ function Start-PSBuild { [ValidateSet('Linux', 'Debug', 'Release', '')] # We might need "Checked" as well [string]$Configuration, - [Parameter(ParameterSetName='Publish')] + [Parameter(ParameterSetName='Publish', Mandatory=$true)] [switch]$Publish, [Parameter(ParameterSetName='Publish')] @@ -335,7 +335,7 @@ cmd.exe /C cd /d "$location" "&" "$($vcVarsPath)\vcvarsall.bat" "$NativeHostArch if ($CrossGen) { $publishPath = Split-Path $Options.Output - Start-NativeExecution { Start-CrossGen -PublishPath $publishPath } + Start-CrossGen -PublishPath $publishPath log "PowerShell.exe with ngen binaries is available at: $($Options.Output)" } else @@ -1806,6 +1806,150 @@ function New-AppxPackage return $appxPackagePath } +function Start-CrossGen { + [CmdletBinding()] + param( + [Parameter(Mandatory= $true)] + [ValidateNotNullOrEmpty()] + [String] + $PublishPath + ) + + function Generate-CrossGenAssembly { + param ( + [Parameter(Mandatory= $true)] + [ValidateNotNullOrEmpty()] + [String] + $AssemblyPath, + [Parameter(Mandatory= $true)] + [ValidateNotNullOrEmpty()] + [String] + $CrossgenPath + ) + + $outputAssembly = $AssemblyPath.Replace(".dll", ".ni.dll") + $platformAssembliesPath = Split-Path $AssemblyPath -Parent + $crossgenFolder = Split-Path $CrossgenPath + $niAssemblyName = Split-Path $outputAssembly -Leaf + + try + { + Push-Location $crossgenFolder + + # Generate the ngen assembly + Write-Host "Generating assembly $niAssemblyName ..." + Start-NativeExecution { + & $CrossgenPath /MissingDependenciesOK /in $AssemblyPath /out $outputAssembly /Platform_Assemblies_Paths $platformAssembliesPath | Write-Verbose + } + + <# + # TODO: Generate the pdb for the ngen binary - currently, there is a hard dependency on diasymreader.dll, which is available at %windir%\Microsoft.NET\Framework\v4.0.30319. + # However, we still need to figure out the prerequisites on Linux. + Start-NativeExecution { + & $CrossgenPath /Platform_Assemblies_Paths $platformAssembliesPath /CreatePDB $platformAssembliesPath /lines $platformAssembliesPath $niAssemblyName | Write-Verbose + } + #> + } + finally + { + Pop-Location + } + } + + if (-not (Test-Path $PublishPath)) + { + throw "Path '$PublishPath' does not exist." + } + + $runtime = (New-PSOptions).Runtime + if (-not $runtime) + { + throw "Unable to determine Runtime Identifier, please update dotnet." + } + + # Get the path to crossgen.exe on Windows and crossgen on Linux. + $crossGenPath = if ($IsWindows) { + Get-ChildItem "$PSScriptRoot\Packages\*crossgen.exe" -Recurse | Where-Object {$_.FullName -match 'x64'} | select -First 1 | % {$_.FullName} + } else { + Get-ChildItem "~/.nuget/packages/*crossgen" -Recurse | Where-Object {$_.FullName -match $runtime} | % {$_.FullName} + } + + if (-not $crossGenPath) + { + throw "Unable to find latest version of crossgen.exe. 'Please run Start-PSBuild -Clean' first, and then try again." + } + + # Crossgen.exe requires the following assemblies: + # mscorlib.dll + # System.Private.CoreLib.dll + # clrjit.dll on Windows or libclrjit.so on Linux + # + $crossGenRequiredAssemblies = @("mscorlib.dll", "System.Private.CoreLib.dll") + + if ($IsWindows) + { + $crossGenRequiredAssemblies += "clrjit.dll" + } + else + { + $crossGenRequiredAssemblies += "libclrjit.so" + } + + # Make sure that all dependencies required by crossgen.exe are at the directory. + $crossGenFolder = Split-Path $crossGenPath + foreach ($assemblyName in $crossGenRequiredAssemblies) + { + if (-not (Test-Path "$crossGenFolder\$assemblyName")) + { + Copy-Item -Path "$PublishPath\$assemblyName" -Destination $crossGenFolder -Force -ErrorAction Stop + } + } + + <# + # Get a list of ps assemblies to ngen. + # TODO: These need to be enable once they are ported to OSPS. + "Microsoft.WSMan.Management.dll", + "Microsoft.WSMan.Runtime.dll", + "Microsoft.PowerShell.ConsoleHost.dll" + #> + + # System.Management.Automation.dll needs to be added at the end of the list + # because it is required by the other PS assemblies for crossgen. + # Note that after an assembly has been ngen, we delete the IL assembly. + $script:psCoreAssemblyList = @() + + if ($IsWindows) + { + # These are not present on Linux yet. + $script:psCoreAssemblyList += "Microsoft.PowerShell.LocalAccounts.dll", + "Microsoft.PowerShell.Commands.Diagnostics.dll", + "Microsoft.Management.Infrastructure.CimCmdlets.dll" + } + + $script:psCoreAssemblyList += "Microsoft.PowerShell.Commands.Utility.dll", + "Microsoft.PowerShell.Commands.Management.dll", + "Microsoft.PowerShell.Security.dll", + "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll", + "Microsoft.PowerShell.CoreCLR.Eventing.dll", + "Microsoft.PowerShell.ConsoleHost.dll", + "Microsoft.PowerShell.PackageManagement.dll", + "Microsoft.PowerShell.PSReadLine.dll", + "System.Management.Automation.dll" + + foreach ($assemblyName in $script:psCoreAssemblyList) + { + $assemblyPath = Join-Path $PublishPath $assemblyName + Generate-CrossGenAssembly -CrossgenPath $crossGenPath -AssemblyPath $assemblyPath + + # After the assembly is generated sucessfully, remove the IL assembly and symbols. + $symbolsPath = $assemblyPath.Replace(".dll", ".pdb") + Remove-Item $assemblyPath -Force -ErrorAction SilentlyContinue + Remove-Item $symbolsPath -Force -ErrorAction SilentlyContinue + } + + # Let the user know that the IL assemblies have been deleted. + Write-Verbose "PowerShell Ngen assemblies have been generated, and ILs have been deleted." -Verbose +} $script:RESX_TEMPLATE = @' @@ -1930,151 +2074,3 @@ $script:RESX_TEMPLATE = @' {0} '@ - -function Start-CrossGen { - [CmdletBinding()] - param( - [Parameter(Mandatory= $true)] - [ValidateNotNullOrEmpty()] - [String] - $PublishPath - ) - - # Helper functions - - function Generate-CrossGenAssembly { - param ( - [Parameter(Mandatory= $true)] - [ValidateNotNullOrEmpty()] - [String] - $AssemblyPath, - [Parameter(Mandatory= $true)] - [ValidateNotNullOrEmpty()] - [String] - $CrossgenPath - ) - - $outputAssembly = $AssemblyPath.Replace(".dll", ".ni.dll") - $platformAssembliesPath = Split-Path $AssemblyPath -Parent - $crossgenFolder = Split-Path $CrossgenPath - $niAssemblyName = Split-Path $outputAssembly -Leaf - - try - { - Push-Location $crossgenFolder - - # Generate the ngen assembly - Write-Host "Generating assembly $niAssemblyName ..." - $null = & $CrossgenPath /MissingDependenciesOK /in $AssemblyPath /out $outputAssembly /Platform_Assemblies_Paths $platformAssembliesPath - - if ($LASTEXITCODE -ne 0) - { - throw "Fail to ngen assembly '$AssemblyPath'" - } - - # TODO: Generate the pdb for the ngen binary - currently, there is a hard dependency on diasymreader.dll, which is available at %windir%\Microsoft.NET\Framework\v4.0.30319. - # However, we still need to figure out the prerequisites on Linux. - # & $CrossgenPath /Platform_Assemblies_Paths $platformAssembliesPath /CreatePDB $platformAssembliesPath /lines $platformAssembliesPath $niAssemblyName - } - finally - { - Pop-Location - } - } - - if (-not (Test-Path $PublishPath)) - { - throw "Path '$PublishPath' does not exist." - } - - $runTime = (New-PSOptions).Runtime - if (-not $runTime) - { - throw "Unable to determine Runtime Identifier, please update dotnet." - } - - # Get the path to crossgen.exe on Windows and crossgen on Linux. - $crossGenPath = if ($IsWindows) { - Get-ChildItem "$PSScriptRoot\Packages\*crossgen.exe" -Recurse | Where-Object {$_.FullName -match 'x64'} | select -First 1 | % {$_.FullName} - } else { - Get-ChildItem "~/.nuget/packages/*crossgen" -Recurse | Where-Object {$_.FullName -match $runTime} | % {$_.FullName} - } - - if (-not $crossGenPath) - { - throw "Unable to find latest version of crossgen.exe. 'Please run Start-PSBuild -Clean' first, and then try again." - } - - # Crossgen.exe requires the following assemblies: - # mscorlib.dll - # System.Private.CoreLib.dll - # clrjit.dll on Windows or libclrjit.so on Linux - # - $crossGenRequiredAssemblies = if ($IsWindows) { - "mscorlib.dll", "System.Private.CoreLib.dll", "clrjit.dll" - } else { - "mscorlib.dll", "System.Private.CoreLib.dll", "libclrjit.so" - } - - # Make sure that all dependencies required by crossgen.exe are at the directory. - $crossGenFolder = Split-Path $crossGenPath - foreach ($assemblyName in $crossGenRequiredAssemblies) - { - if (-not (Test-Path "$crossGenFolder\$assemblyName")) - { - Copy-Item -Path "$PublishPath\$assemblyName" -Destination $crossGenFolder - } - } - - <# - # Get a list of ps assemblies to ngen. - # TODO: These need to be enable once they are ported to OSPS. - "Microsoft.WSMan.Management.dll", - "Microsoft.WSMan.Runtime.dll", - "Microsoft.PowerShell.ConsoleHost.dll" - #> - - $script:psCoreAssemblyList = if ($IsWindows) { - "Microsoft.PowerShell.Commands.Utility.dll", - "Microsoft.PowerShell.Commands.Management.dll", - "Microsoft.PowerShell.Security.dll", - "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll", - "Microsoft.PowerShell.CoreCLR.Eventing.dll", - "Microsoft.PowerShell.ConsoleHost.dll", - "Microsoft.PowerShell.LocalAccounts.dll", - "Microsoft.PowerShell.Commands.Diagnostics.dll", - "Microsoft.Management.Infrastructure.CimCmdlets.dll", - "Microsoft.PowerShell.PackageManagement.dll", - "Microsoft.PowerShell.PSReadLine.dll", - "System.Management.Automation.dll" - } else { - "Microsoft.PowerShell.Commands.Utility.dll", - "Microsoft.PowerShell.Commands.Management.dll", - "Microsoft.PowerShell.Security.dll", - "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll", - "Microsoft.PowerShell.CoreCLR.Eventing.dll", - "Microsoft.PowerShell.ConsoleHost.dll", - "Microsoft.PowerShell.PackageManagement.dll", - "Microsoft.PowerShell.PSReadLine.dll", - "System.Management.Automation.dll" - - # These are not present on Linux yet. - # "Microsoft.PowerShell.LocalAccounts.dll" - # "Microsoft.PowerShell.Commands.Diagnostics.dll" - # "Microsoft.Management.Infrastructure.CimCmdlets.dll" - } - - foreach ($assemblyName in $script:psCoreAssemblyList) - { - $assemblyPath = Join-Path $PublishPath $assemblyName - Generate-CrossGenAssembly -CrossgenPath $crossGenPath -AssemblyPath $assemblyPath - - # After the assembly is generated sucessfully, remove the IL assembly and symbols. - $symbolsPath = $assemblyPath.Replace(".dll", ".pdb") - Remove-Item $assemblyPath -Force -ErrorAction SilentlyContinue - Remove-Item $symbolsPath -Force -ErrorAction SilentlyContinue - } - - # Let the user know that the IL assemblies have been deleted. - Write-Verbose "PowerShell Ngen assemblies have been generated, and ILs have been deleted." -Verbose -} \ No newline at end of file From 65eef96bf1c8fc5b9bbfaea197e5d4fa0579743a Mon Sep 17 00:00:00 2001 From: Francisco Gamino Date: Tue, 2 Aug 2016 13:55:20 -0700 Subject: [PATCH 4/8] Update Commands.Utility.csproj for WebCmdlet files --- ...crosoft.PowerShell.Commands.Utility.csproj | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 61dda3786..2df153eab 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -141,26 +141,43 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - From c16209e39d4dc0f17d813032c8da65ec94d77e7d Mon Sep 17 00:00:00 2001 From: Francisco Gamino Date: Wed, 3 Aug 2016 00:19:39 -0700 Subject: [PATCH 5/8] Enable crossgen on CI --- appveyor.yml | 2 +- build.psm1 | 81 +++++++++++++++++++++++++------------------------ tools/travis.sh | 4 +-- 3 files changed, 45 insertions(+), 42 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 071ae8d5d..f53c786d2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,7 +28,7 @@ build_script: $result.Warnings throw "Tags must be CI, Feature, Scenario, or Slow" } - Start-PSBuild -Publish + Start-PSBuild -CrossGen Start-PSBuild -FullCLR test_script: diff --git a/build.psm1 b/build.psm1 index 71e8f9732..f97371699 100644 --- a/build.psm1 +++ b/build.psm1 @@ -70,10 +70,10 @@ function Start-PSBuild { [ValidateSet('Linux', 'Debug', 'Release', '')] # We might need "Checked" as well [string]$Configuration, - [Parameter(ParameterSetName='Publish', Mandatory=$true)] + [Parameter(ParameterSetName='CoreCLR')] [switch]$Publish, - [Parameter(ParameterSetName='Publish')] + [Parameter(ParameterSetName='CoreCLR')] [switch]$CrossGen ) @@ -89,6 +89,12 @@ function Start-PSBuild { Stop-Process -Verbose } + if ($CrossGen -and !$Publish) + { + # By specifying -CrossGen, we implicitly set -Publish to $true, if not already specified. + $Publish = $true + } + if ($Clean) { log "Cleaning your working directory. You can also do it with 'git clean -fdX'" @@ -1839,15 +1845,15 @@ function Start-CrossGen { # Generate the ngen assembly Write-Host "Generating assembly $niAssemblyName ..." Start-NativeExecution { - & $CrossgenPath /MissingDependenciesOK /in $AssemblyPath /out $outputAssembly /Platform_Assemblies_Paths $platformAssembliesPath | Write-Verbose - } + & $CrossgenPath /MissingDependenciesOK /in $AssemblyPath /out $outputAssembly /Platform_Assemblies_Paths $platformAssembliesPath + } | Write-Verbose <# # TODO: Generate the pdb for the ngen binary - currently, there is a hard dependency on diasymreader.dll, which is available at %windir%\Microsoft.NET\Framework\v4.0.30319. # However, we still need to figure out the prerequisites on Linux. Start-NativeExecution { - & $CrossgenPath /Platform_Assemblies_Paths $platformAssembliesPath /CreatePDB $platformAssembliesPath /lines $platformAssembliesPath $niAssemblyName | Write-Verbose - } + & $CrossgenPath /Platform_Assemblies_Paths $platformAssembliesPath /CreatePDB $platformAssembliesPath /lines $platformAssembliesPath $niAssemblyName + } | Write-Verbose #> } finally @@ -1869,9 +1875,11 @@ function Start-CrossGen { # Get the path to crossgen.exe on Windows and crossgen on Linux. $crossGenPath = if ($IsWindows) { - Get-ChildItem "$PSScriptRoot\Packages\*crossgen.exe" -Recurse | Where-Object {$_.FullName -match 'x64'} | select -First 1 | % {$_.FullName} + Get-ChildItem "$PSScriptRoot\Packages\*crossgen.exe" -Recurse | Where-Object {$_.FullName -like '*win*x64*'} | select -First 1 | % {$_.FullName} + } elseif ($IsOSX) { + Get-ChildItem "~/.nuget/packages/*crossgen" -Recurse | Where-Object {$_.FullName -match 'osx.10.10-x64'} | select -First 1 | % {$_.FullName} } else { - Get-ChildItem "~/.nuget/packages/*crossgen" -Recurse | Where-Object {$_.FullName -match $runtime} | % {$_.FullName} + Get-ChildItem "~/.nuget/packages/*crossgen" -Recurse | Where-Object {$_.FullName -match $runtime} | select -First 1 | % {$_.FullName} } if (-not $crossGenPath) @@ -1905,50 +1913,45 @@ function Start-CrossGen { } } - <# - # Get a list of ps assemblies to ngen. - # TODO: These need to be enable once they are ported to OSPS. - "Microsoft.WSMan.Management.dll", - "Microsoft.WSMan.Runtime.dll", - "Microsoft.PowerShell.ConsoleHost.dll" - #> - - # System.Management.Automation.dll needs to be added at the end of the list - # because it is required by the other PS assemblies for crossgen. - # Note that after an assembly has been ngen, we delete the IL assembly. - $script:psCoreAssemblyList = @() + # The list of ps assemblies to ngen. + $psCoreAssemblyList = @( + "Microsoft.PowerShell.Commands.Utility.dll", + "Microsoft.PowerShell.Commands.Management.dll", + "Microsoft.PowerShell.Security.dll", + "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll", + "Microsoft.PowerShell.CoreCLR.Eventing.dll", + "Microsoft.PowerShell.ConsoleHost.dll", + "Microsoft.PowerShell.PackageManagement.dll", + "Microsoft.PowerShell.PSReadLine.dll", + "System.Management.Automation.dll" + ) if ($IsWindows) { # These are not present on Linux yet. - $script:psCoreAssemblyList += "Microsoft.PowerShell.LocalAccounts.dll", - "Microsoft.PowerShell.Commands.Diagnostics.dll", - "Microsoft.Management.Infrastructure.CimCmdlets.dll" + $psCoreAssemblyList += @( + "Microsoft.WSMan.Management.dll", + "Microsoft.WSMan.Runtime.dll", + "Microsoft.PowerShell.LocalAccounts.dll", + "Microsoft.PowerShell.Commands.Diagnostics.dll", + "Microsoft.Management.Infrastructure.CimCmdlets.dll" + ) } - $script:psCoreAssemblyList += "Microsoft.PowerShell.Commands.Utility.dll", - "Microsoft.PowerShell.Commands.Management.dll", - "Microsoft.PowerShell.Security.dll", - "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll", - "Microsoft.PowerShell.CoreCLR.Eventing.dll", - "Microsoft.PowerShell.ConsoleHost.dll", - "Microsoft.PowerShell.PackageManagement.dll", - "Microsoft.PowerShell.PSReadLine.dll", - "System.Management.Automation.dll" - - foreach ($assemblyName in $script:psCoreAssemblyList) + foreach ($assemblyName in $psCoreAssemblyList) { $assemblyPath = Join-Path $PublishPath $assemblyName - Generate-CrossGenAssembly -CrossgenPath $crossGenPath -AssemblyPath $assemblyPath + Generate-CrossGenAssembly -CrossgenPath $crossGenPath -AssemblyPath $assemblyPath + } - # After the assembly is generated sucessfully, remove the IL assembly and symbols. + Write-Verbose "PowerShell Ngen assemblies have been generated, deleting ILs..." -Verbose + foreach ($assemblyName in $psCoreAssemblyList) + { + # Remove the IL assembly and its symbols. $symbolsPath = $assemblyPath.Replace(".dll", ".pdb") Remove-Item $assemblyPath -Force -ErrorAction SilentlyContinue Remove-Item $symbolsPath -Force -ErrorAction SilentlyContinue } - - # Let the user know that the IL assemblies have been deleted. - Write-Verbose "PowerShell Ngen assemblies have been generated, and ILs have been deleted." -Verbose } $script:RESX_TEMPLATE = @' diff --git a/tools/travis.sh b/tools/travis.sh index bcbc560a1..1fac7631f 100755 --- a/tools/travis.sh +++ b/tools/travis.sh @@ -1,7 +1,7 @@ ulimit -n 4096 # Only build packages for branches, not pull requests if [[ $TRAVIS_PULL_REQUEST == false ]]; then - powershell -c "Import-Module ./build.psm1; Start-PSBootstrap -Package; Start-PSBuild -Publish; Start-PSPackage; Start-PSPester; Start-PSxUnit" + powershell -c "Import-Module ./build.psm1; Start-PSBootstrap -Package; Start-PSBuild -CrossGen; Start-PSPackage; Start-PSPester; Start-PSxUnit" else - powershell -c "Import-Module ./build.psm1; Start-PSBootstrap; Start-PSBuild; Start-PSPester; Start-PSxUnit" + powershell -c "Import-Module ./build.psm1; Start-PSBootstrap; Start-PSBuild -CrossGen; Start-PSPester; Start-PSxUnit" fi From 9c205c6158311ee7daf902ded3d4e0de18f036b6 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 3 Aug 2016 12:05:26 -0700 Subject: [PATCH 6/8] Fix crossgen search for Ubuntu/CentOS --- build.psm1 | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/build.psm1 b/build.psm1 index f97371699..a12651593 100644 --- a/build.psm1 +++ b/build.psm1 @@ -1874,16 +1874,31 @@ function Start-CrossGen { } # Get the path to crossgen.exe on Windows and crossgen on Linux. - $crossGenPath = if ($IsWindows) { - Get-ChildItem "$PSScriptRoot\Packages\*crossgen.exe" -Recurse | Where-Object {$_.FullName -like '*win*x64*'} | select -First 1 | % {$_.FullName} - } elseif ($IsOSX) { - Get-ChildItem "~/.nuget/packages/*crossgen" -Recurse | Where-Object {$_.FullName -match 'osx.10.10-x64'} | select -First 1 | % {$_.FullName} + $crossGenSearchPath = if ($IsWindows) { + "$PSScriptRoot\Packages\*crossgen.exe" } else { - Get-ChildItem "~/.nuget/packages/*crossgen" -Recurse | Where-Object {$_.FullName -match $runtime} | select -First 1 | % {$_.FullName} + "~/.nuget/packages/*crossgen" } - if (-not $crossGenPath) - { + # The crossgen tool is only published for these particular runtimes + $crossGenRuntime = if ($IsWindows) { + "win7-x64" + } elseif ($IsLinux) { + if ($IsUbuntu) { + "ubuntu.14.04-x64" + } elseif ($IsCentOS) { + "rhel.7-x64" + } + } elseif ($IsOSX) { + "osx.10.10-x64" + } + + if (-not $crossGenRuntime) { + throw "crossgen is not available for this platform" + } + + $crossGenPath = Get-ChildItem $crossGenSearchPath -Recurse | ? { $_.FullName -match $crossGenRuntime } | select -First 1 | % { $_.FullName } + if (-not $crossGenPath) { throw "Unable to find latest version of crossgen.exe. 'Please run Start-PSBuild -Clean' first, and then try again." } From c35c9e5ef22578f33d482bd5f7c6f9e2e9e9af04 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 3 Aug 2016 12:35:58 -0700 Subject: [PATCH 7/8] Fix libclrjit name for OS X It's a dylib, not a so. --- build.psm1 | 65 ++++++++++++++++++++---------------------------------- 1 file changed, 24 insertions(+), 41 deletions(-) diff --git a/build.psm1 b/build.psm1 index a12651593..a25abaa0e 100644 --- a/build.psm1 +++ b/build.psm1 @@ -1820,7 +1820,7 @@ function Start-CrossGen { [String] $PublishPath ) - + function Generate-CrossGenAssembly { param ( [Parameter(Mandatory= $true)] @@ -1838,16 +1838,15 @@ function Start-CrossGen { $crossgenFolder = Split-Path $CrossgenPath $niAssemblyName = Split-Path $outputAssembly -Leaf - try - { + try { Push-Location $crossgenFolder # Generate the ngen assembly - Write-Host "Generating assembly $niAssemblyName ..." + Write-Verbose "Generating assembly $niAssemblyName" Start-NativeExecution { & $CrossgenPath /MissingDependenciesOK /in $AssemblyPath /out $outputAssembly /Platform_Assemblies_Paths $platformAssembliesPath } | Write-Verbose - + <# # TODO: Generate the pdb for the ngen binary - currently, there is a hard dependency on diasymreader.dll, which is available at %windir%\Microsoft.NET\Framework\v4.0.30319. # However, we still need to figure out the prerequisites on Linux. @@ -1855,25 +1854,16 @@ function Start-CrossGen { & $CrossgenPath /Platform_Assemblies_Paths $platformAssembliesPath /CreatePDB $platformAssembliesPath /lines $platformAssembliesPath $niAssemblyName } | Write-Verbose #> - } - finally - { + } finally { Pop-Location } } - if (-not (Test-Path $PublishPath)) - { + if (-not (Test-Path $PublishPath)) { throw "Path '$PublishPath' does not exist." } - $runtime = (New-PSOptions).Runtime - if (-not $runtime) - { - throw "Unable to determine Runtime Identifier, please update dotnet." - } - - # Get the path to crossgen.exe on Windows and crossgen on Linux. + # Get the path to crossgen $crossGenSearchPath = if ($IsWindows) { "$PSScriptRoot\Packages\*crossgen.exe" } else { @@ -1905,30 +1895,26 @@ function Start-CrossGen { # Crossgen.exe requires the following assemblies: # mscorlib.dll # System.Private.CoreLib.dll - # clrjit.dll on Windows or libclrjit.so on Linux - # + # clrjit.dll on Windows or libclrjit.so/dylib on Linux/OS X $crossGenRequiredAssemblies = @("mscorlib.dll", "System.Private.CoreLib.dll") - - if ($IsWindows) - { - $crossGenRequiredAssemblies += "clrjit.dll" + + $crossGenRequiredAssemblies += if ($IsWindows) { + "clrjit.dll" + } elseif ($IsLinux) { + "libclrjit.so" + } elseif ($IsOSX) { + "libclrjit.dylib" } - else - { - $crossGenRequiredAssemblies += "libclrjit.so" - } - - # Make sure that all dependencies required by crossgen.exe are at the directory. + + # Make sure that all dependencies required by crossgen are at the directory. $crossGenFolder = Split-Path $crossGenPath - foreach ($assemblyName in $crossGenRequiredAssemblies) - { - if (-not (Test-Path "$crossGenFolder\$assemblyName")) - { + foreach ($assemblyName in $crossGenRequiredAssemblies) { + if (-not (Test-Path "$crossGenFolder\$assemblyName")) { Copy-Item -Path "$PublishPath\$assemblyName" -Destination $crossGenFolder -Force -ErrorAction Stop } } - # The list of ps assemblies to ngen. + # Common PowerShell libraries to crossgen $psCoreAssemblyList = @( "Microsoft.PowerShell.Commands.Utility.dll", "Microsoft.PowerShell.Commands.Management.dll", @@ -1941,9 +1927,8 @@ function Start-CrossGen { "System.Management.Automation.dll" ) - if ($IsWindows) - { - # These are not present on Linux yet. + # Add Windows specific libraries + if ($IsWindows) { $psCoreAssemblyList += @( "Microsoft.WSMan.Management.dll", "Microsoft.WSMan.Runtime.dll", @@ -1953,15 +1938,13 @@ function Start-CrossGen { ) } - foreach ($assemblyName in $psCoreAssemblyList) - { + foreach ($assemblyName in $psCoreAssemblyList) { $assemblyPath = Join-Path $PublishPath $assemblyName Generate-CrossGenAssembly -CrossgenPath $crossGenPath -AssemblyPath $assemblyPath } Write-Verbose "PowerShell Ngen assemblies have been generated, deleting ILs..." -Verbose - foreach ($assemblyName in $psCoreAssemblyList) - { + foreach ($assemblyName in $psCoreAssemblyList) { # Remove the IL assembly and its symbols. $symbolsPath = $assemblyPath.Replace(".dll", ".pdb") Remove-Item $assemblyPath -Force -ErrorAction SilentlyContinue From f866f8b06f86e859a58df8d2a051b331e917f443 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Wed, 3 Aug 2016 13:23:21 -0700 Subject: [PATCH 8/8] Fix inconsistent braces and whitespace in build.psm1 --- build.psm1 | 431 +++++++++++++++++++---------------------------------- 1 file changed, 157 insertions(+), 274 deletions(-) diff --git a/build.psm1 b/build.psm1 index a25abaa0e..a419b7c48 100644 --- a/build.psm1 +++ b/build.psm1 @@ -77,34 +77,28 @@ function Start-PSBuild { [switch]$CrossGen ) - function Stop-DevPowerShell - { + function Stop-DevPowerShell { Get-Process powershell* | - Where-Object { - $_.Modules | - Where-Object { + Where-Object { + $_.Modules | + Where-Object { $_.FileName -eq (Resolve-Path $script:Options.Output).Path - } - } | + } + } | Stop-Process -Verbose } - if ($CrossGen -and !$Publish) - { - # By specifying -CrossGen, we implicitly set -Publish to $true, if not already specified. + if ($CrossGen -and !$Publish) { + # By specifying -CrossGen, we implicitly set -Publish to $true, if not already specified. $Publish = $true } - if ($Clean) - { + if ($Clean) { log "Cleaning your working directory. You can also do it with 'git clean -fdX'" Push-Location $PSScriptRoot - try - { + try { git clean -fdX - } - finally - { + } finally { Pop-Location } } @@ -142,29 +136,22 @@ function Start-PSBuild { } $vcVarsPath = (Get-Item(Join-Path -Path "$env:VS140COMNTOOLS" -ChildPath '../../vc')).FullName - if ((Test-Path -Path $vcVarsPath\vcvarsall.bat) -eq $false) - { + if ((Test-Path -Path $vcVarsPath\vcvarsall.bat) -eq $false) { throw "Could not find Visual Studio vcvarsall.bat at" + $vcVarsPath } # setup msbuild configuration - if ($Configuration -eq 'Debug' -or $Configuration -eq 'Release') - { + if ($Configuration -eq 'Debug' -or $Configuration -eq 'Release') { $msbuildConfiguration = $Configuration - } - else - { + } else { $msbuildConfiguration = 'Release' } # setup cmakeGenerator - if ($NativeHostArch -eq 'x86') - { - $cmakeGenerator = 'Visual Studio 14 2015' - } - else - { - $cmakeGenerator = 'Visual Studio 14 2015 Win64' + if ($NativeHostArch -eq 'x86') { + $cmakeGenerator = 'Visual Studio 14 2015' + } else { + $cmakeGenerator = 'Visual Studio 14 2015 Win64' } } elseif ($IsLinux -or $IsOSX) { @@ -190,8 +177,7 @@ function Start-PSBuild { } $script:Options = New-PSOptions @OptionsArguments - if ($StopDevPowerShell) - { + if ($StopDevPowerShell) { Stop-DevPowerShell } @@ -231,16 +217,14 @@ function Start-PSBuild { # handle ResGen # Heuristic to run ResGen on the fresh machine - if ($ResGen -or -not (Test-Path "$PSScriptRoot/src/Microsoft.PowerShell.ConsoleHost/gen")) - { + if ($ResGen -or -not (Test-Path "$PSScriptRoot/src/Microsoft.PowerShell.ConsoleHost/gen")) { log "Run ResGen (generating C# bindings for resx files)" Start-ResGen } # handle xaml files # Heuristic to resolve xaml on the fresh machine - if ($FullCLR -and ($XamlGen -or -not (Test-Path "$PSScriptRoot/src/Microsoft.PowerShell.Activities/gen/*.g.cs"))) - { + if ($FullCLR -and ($XamlGen -or -not (Test-Path "$PSScriptRoot/src/Microsoft.PowerShell.Activities/gen/*.g.cs"))) { log "Run XamlGen (generating .g.cs and .resources for .xaml files)" Start-XamlGen -MSBuildConfiguration $msbuildConfiguration } @@ -286,18 +270,17 @@ cmd.exe /C cd /d "(Get-Location)" "&" "$($vcVarsPath)\vcvarsall.bat" "$NativeHos Start-NativeExecution { Invoke-Expression -Command:$command } } } - -# Disabling until I figure out if it is necessary -# $overrideFlags = "-DCMAKE_USER_MAKE_RULES_OVERRIDE=$PSScriptRoot\src\powershell-native\windows-compiler-override.txt" + +# Disabling until I figure out if it is necessary +# $overrideFlags = "-DCMAKE_USER_MAKE_RULES_OVERRIDE=$PSScriptRoot\src\powershell-native\windows-compiler-override.txt" $overrideFlags = "" $location = Get-Location # # BUILD_ONECORE # - + $BuildOneCoreValues = @("ON","OFF") - foreach ($oneCoreValue in $BuildOneCoreValues) - { + foreach ($oneCoreValue in $BuildOneCoreValues) { $command = @" cmd.exe /C cd /d "$location" "&" "$($vcVarsPath)\vcvarsall.bat" "$NativeHostArch" "&" cmake "$overrideFlags" -DBUILD_ONECORE=$oneCoreValue -G "$cmakeGenerator" . "&" msbuild ALL_BUILD.vcxproj "/p:Configuration=$msbuildConfiguration" "@ @@ -326,8 +309,7 @@ cmd.exe /C cd /d "$location" "&" "$($vcVarsPath)\vcvarsall.bat" "$NativeHostArch } # handle TypeGen - if ($TypeGen -or -not (Test-Path "$PSScriptRoot/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CorePsTypeCatalog.cs")) - { + if ($TypeGen -or -not (Test-Path "$PSScriptRoot/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CorePsTypeCatalog.cs")) { log "Run TypeGen (generating CorePsTypeCatalog.cs)" Start-TypeGen } @@ -338,14 +320,11 @@ cmd.exe /C cd /d "$location" "&" "$($vcVarsPath)\vcvarsall.bat" "$NativeHostArch log "Run dotnet $Arguments from $pwd" Start-NativeExecution { dotnet $Arguments } - if ($CrossGen) - { + if ($CrossGen) { $publishPath = Split-Path $Options.Output Start-CrossGen -PublishPath $publishPath log "PowerShell.exe with ngen binaries is available at: $($Options.Output)" - } - else - { + } else { log "PowerShell output: $($Options.Output)" } } finally { @@ -505,11 +484,11 @@ function Get-PesterTag { $warnings += "TAGS must be static strings, error in ${fullname}, line $lineno" } $values = $vAst.FindAll({$args[0] -is "System.Management.Automation.Language.StringConstantExpressionAst"},$true).Value - $values | %{ + $values | %{ if ( $_ -notmatch "CI|FEATURE|SCENARIO|SLOW" ) { $warnings += "${fullname} includes improper tag '$_', line '$lineno'" } - $alltags[$_]++ + $alltags[$_]++ } $foundTag = $true } @@ -526,7 +505,7 @@ function Get-PesterTag { $alltags['Result'] = "Pass" } $alltags['Warnings'] = $warnings - $o = [pscustomobject]$alltags + $o = [pscustomobject]$alltags $o.psobject.TypeNames.Add("DescribeTagsInUse") $o } @@ -702,82 +681,59 @@ function Start-PSBootstrap { # Install chocolatey $chocolateyPath = "$env:AllUsersProfile\chocolatey\bin" - - if(precheck 'choco' $null) - { + + if(precheck 'choco' $null) { log "Chocolatey is already installed. Skipping installation." } - elseif(($cmakePresent -eq $false) -or ($sdkPresent -eq $false)) - { + elseif(($cmakePresent -eq $false) -or ($sdkPresent -eq $false)) { log "Chocolatey not present. Installing chocolatey." - if ($Force -or $PSCmdlet.ShouldProcess("Install chocolatey via https://chocolatey.org/install.ps1")) - { + if ($Force -or $PSCmdlet.ShouldProcess("Install chocolatey via https://chocolatey.org/install.ps1")) { Invoke-Expression ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')) - - if (-not ($machinePath.ToLower().Contains($chocolateyPath.ToLower()))) - { + if (-not ($machinePath.ToLower().Contains($chocolateyPath.ToLower()))) { log "Adding $chocolateyPath to Path environment variable" $env:Path += ";$chocolateyPath" - $newMachineEnvironmentPath += ";$chocolateyPath" - } - else - { + $newMachineEnvironmentPath += ";$chocolateyPath" + } else { log "$chocolateyPath already present in Path environment variable" } - } - else - { + } else { Write-Error "Chocolatey is required to install missing dependencies. Please install it from https://chocolatey.org/ manually. Alternatively, install cmake and Windows 10 SDK." return $null } - } - else - { + } else { log "Skipping installation of chocolatey, cause both cmake and Win 10 SDK are present." } # Install cmake $cmakePath = "${env:ProgramFiles(x86)}\CMake\bin" - if($cmakePresent) - { + if($cmakePresent) { log "Cmake is already installed. Skipping installation." - } - else - { + } else { log "Cmake not present. Installing cmake." choco install cmake.portable -y --version 3.6.0 - - if (-not ($machinePath.ToLower().Contains($cmakePath.ToLower()))) - { + if (-not ($machinePath.ToLower().Contains($cmakePath.ToLower()))) { log "Adding $cmakePath to Path environment variable" $env:Path += ";$cmakePath" $newMachineEnvironmentPath = "$cmakePath;$newMachineEnvironmentPath" - } - else - { + } else { log "$cmakePath already present in Path environment variable" } } - # Install Windows 10 SDK + # Install Windows 10 SDK $packageName = "windows-sdk-10.0" - if (-not $sdkPresent) - { + if (-not $sdkPresent) { log "Windows 10 SDK not present. Installing $packageName." choco install windows-sdk-10.0 -y - } - else - { + } else { log "Windows 10 SDK present. Skipping installation." } - + # Update path machine environment variable - if ($newMachineEnvironmentPath -ne $machinePath) - { + if ($newMachineEnvironmentPath -ne $machinePath) { log "Updating Path machine environment variable" - if ($Force -or $PSCmdlet.ShouldProcess("Update Path machine environment variable to $newMachineEnvironmentPath")) - { + if ($Force -or $PSCmdlet.ShouldProcess("Update Path machine environment variable to $newMachineEnvironmentPath")) { [Environment]::SetEnvironmentVariable('Path', $newMachineEnvironmentPath, 'MACHINE') } } @@ -817,7 +773,6 @@ Built upon .NET Core, it is also a C# REPL. Write-Verbose "Packaging $Source" if ($IsWindows) { - # Product Guid needs to be unique for every PowerShell version to allow SxS install $productGuid = [guid]::NewGuid() $msiPackagePath = New-MSIPackage -ProductSourcePath $Source -ProductVersion $Version -AssetsPath "$PSScriptRoot\Assets" -ProductGuid $productGuid @@ -951,12 +906,9 @@ function Publish-NuGetFeed 'Microsoft.PowerShell.CoreCLR.Eventing', 'Microsoft.PowerShell.SDK' ) | % { - if ($VersionSuffix) - { + if ($VersionSuffix) { dotnet pack "src/$_" --output $OutputPath --version-suffix $VersionSuffix - } - else - { + } else { dotnet pack "src/$_" --output $OutputPath } } @@ -975,8 +927,7 @@ function Start-DevPowerShell { ) try { - if ((-not $NoNewWindow) -and ($IsCoreCLR)) - { + if ((-not $NoNewWindow) -and ($IsCoreCLR)) { Write-Warning "Start-DevPowerShell -NoNewWindow is currently implied in PowerShellCore edition https://github.com/PowerShell/PowerShell/issues/1543" $NoNewWindow = $true } @@ -985,18 +936,14 @@ function Start-DevPowerShell { $ArgumentList = @('-noprofile') + $ArgumentList } - if (-not $KeepPSModulePath) - { - if (-not $Command) - { + if (-not $KeepPSModulePath) { + if (-not $Command) { $ArgumentList = @('-NoExit') + $ArgumentList } - $Command = '$env:PSMODULEPATH = Join-Path $env:DEVPATH Modules; ' + $Command - } + } - if ($Command) - { + if ($Command) { $ArgumentList = $ArgumentList + @("-command $Command") } @@ -1039,7 +986,7 @@ function Start-DevPowerShell { <# -.EXAMPLE +.EXAMPLE PS C:> Copy-MappedFiles -PslMonadRoot .\src\monad copy files FROM .\src\monad (old location of submodule) TO src/ folders @@ -1056,28 +1003,20 @@ function Copy-MappedFiles { [switch]$WhatIf ) - begin - { - function MaybeTerminatingWarning - { + begin { + function MaybeTerminatingWarning { param([string]$Message) - if ($Force) - { + if ($Force) { Write-Warning "$Message : ignoring (-Force)" - } - elseif ($WhatIf) - { - Write-Warning "$Message : ignoring (-WhatIf)" - } - else - { + } elseif ($WhatIf) { + Write-Warning "$Message : ignoring (-WhatIf)" + } else { throw "$Message : use -Force to ignore" } } - if (-not (Test-Path -PathType Container $PslMonadRoot)) - { + if (-not (Test-Path -PathType Container $PslMonadRoot)) { throw "$pslMonadRoot is not a valid folder" } @@ -1085,52 +1024,39 @@ function Copy-MappedFiles { # finding base-line CL $cl = git --git-dir="$PSScriptRoot/.git" tag | % {if ($_ -match 'SD.(\d+)$') {[int]$Matches[1]} } | Sort-Object -Descending | Select-Object -First 1 - if ($cl) - { + if ($cl) { log "Current base-line CL is SD:$cl (based on tags)" - } - else - { + } else { MaybeTerminatingWarning "Could not determine base-line CL based on tags" } - try - { + try { Push-Location $PslMonadRoot - if (git status --porcelain -uno) - { + if (git status --porcelain -uno) { MaybeTerminatingWarning "$pslMonadRoot has changes" } - if (git log --grep="SD:$cl" HEAD^..HEAD) - { + if (git log --grep="SD:$cl" HEAD^..HEAD) { log "$pslMonadRoot HEAD matches [SD:$cl]" - } - else - { - Write-Warning "Try to checkout this commit in $pslMonadRoot :" + } else { + Write-Warning "Try to checkout this commit in $pslMonadRoot :" git log --grep="SD:$cl" | Write-Warning MaybeTerminatingWarning "$pslMonadRoot HEAD doesn't match [SD:$cl]" } - } - finally - { + } finally { Pop-Location } $map = @{} } - process - { + process { $map += Get-Mappings $Path -Root $PslMonadRoot } - end - { + end { $map.GetEnumerator() | % { New-Item -ItemType Directory (Split-Path $_.Value) -ErrorAction SilentlyContinue > $null - Copy-Item $_.Key $_.Value -Verbose:([bool]$PSBoundParameters['Verbose']) -WhatIf:$WhatIf } } @@ -1146,27 +1072,21 @@ function Get-Mappings [switch]$KeepRelativePaths ) - begin - { + begin { $mapFiles = @() } - process - { + process { Write-Verbose "Discovering map files in $Path" $count = $mapFiles.Count - if (-not (Test-Path $Path)) - { + if (-not (Test-Path $Path)) { throw "Mapping file not found in $mappingFilePath" } - if (Test-Path -PathType Container $Path) - { + if (Test-Path -PathType Container $Path) { $mapFiles += Get-ChildItem -Recurse $Path -Filter 'map.json' -File - } - else - { + } else { # it exists and it's a file, don't check the name pattern $mapFiles += Get-ChildItem $Path } @@ -1174,23 +1094,18 @@ function Get-Mappings Write-Verbose "Found $($mapFiles.Count - $count) map files in $Path" } - end - { + end { $map = @{} $mapFiles | % { $file = $_ - try - { + try { $rawHashtable = $_ | Get-Content -Raw | ConvertFrom-Json | Convert-PSObjectToHashtable - } - catch - { + } catch { Write-Error "Exception, when processing $($file.FullName): $_" } $mapRoot = Split-Path $_.FullName - if ($KeepRelativePaths) - { + if ($KeepRelativePaths) { # not very elegant way to find relative for the current directory path $mapRoot = $mapRoot.Substring($PSScriptRoot.Length + 1) # keep original unix-style paths for git @@ -1199,7 +1114,7 @@ function Get-Mappings $rawHashtable.GetEnumerator() | % { $newKey = if ($Root) { Join-Path $Root $_.Key } else { $_.Key } - $newValue = if ($KeepRelativePaths) { ($mapRoot + '/' + $_.Value) } else { Join-Path $mapRoot $_.Value } + $newValue = if ($KeepRelativePaths) { ($mapRoot + '/' + $_.Value) } else { Join-Path $mapRoot $_.Value } $map[$newKey] = $newValue } } @@ -1270,22 +1185,16 @@ function Start-TypeGen Find-Dotnet Push-Location "$PSScriptRoot/src/TypeCatalogParser" - try - { + try { dotnet run - } - finally - { + } finally { Pop-Location } Push-Location "$PSScriptRoot/src/TypeCatalogGen" - try - { + try { dotnet run ../Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CorePsTypeCatalog.cs powershell.inc - } - finally - { + } finally { Pop-Location } } @@ -1299,12 +1208,9 @@ function Start-ResGen Find-Dotnet Push-Location "$PSScriptRoot/src/ResGen" - try - { + try { Start-NativeExecution { dotnet run } | Write-Verbose - } - finally - { + } finally { Pop-Location } } @@ -1338,8 +1244,7 @@ function Convert-TxtResourceToXml [string[]]$Path ) - process - { + process { $Path | % { Get-ChildItem $_ -Filter "*.txt" | % { $txtFile = $_.FullName @@ -1370,11 +1275,9 @@ function Start-XamlGen Use-MSBuild Get-ChildItem -Path "$PSScriptRoot/src" -Directory | % { - $XamlDir = Join-Path -Path $_.FullName -ChildPath Xamls if ((Test-Path -Path $XamlDir -PathType Container) -and - (@(Get-ChildItem -Path "$XamlDir\*.xaml").Count -gt 0)) - { + (@(Get-ChildItem -Path "$XamlDir\*.xaml").Count -gt 0)) { $OutputDir = Join-Path -Path $env:TEMP -ChildPath "_Resolve_Xaml_" Remove-Item -Path $OutputDir -Recurse -Force -ErrorAction SilentlyContinue mkdir -Path $OutputDir -Force > $null @@ -1382,11 +1285,10 @@ function Start-XamlGen # we will get failures, but it's ok: we only need to copy *.g.cs files in the dotnet cli project. $SourceDir = ConvertFrom-Xaml -Configuration $MSBuildConfiguration -OutputDir $OutputDir -XamlDir $XamlDir -IgnoreMsbuildFailure:$true $DestinationDir = Join-Path -Path $_.FullName -ChildPath gen - + New-Item -ItemType Directory $DestinationDir -ErrorAction SilentlyContinue > $null $filesToCopy = Get-Item "$SourceDir\*.cs", "$SourceDir\*.g.resources" - if (-not $filesToCopy) - { + if (-not $filesToCopy) { throw "No .cs or .g.resources files are generated for $XamlDir, something went wrong. Run 'Start-XamlGen -Verbose' for details." } @@ -1463,15 +1365,11 @@ function script:ConvertFrom-Xaml { msbuild $XamlProjPath | Write-Verbose - if ($LASTEXITCODE -ne 0) - { + if ($LASTEXITCODE -ne 0) { $message = "When processing $XamlDir 'msbuild $XamlProjPath > `$null' failed with exit code $LASTEXITCODE" - if ($IgnoreMsbuildFailure) - { + if ($IgnoreMsbuildFailure) { Write-Verbose $message - } - else - { + } else { throw $message } } @@ -1486,14 +1384,12 @@ function script:Use-MSBuild { $frameworkMsBuildLocation = "${env:SystemRoot}\Microsoft.Net\Framework\v4.0.30319\msbuild" $msbuild = get-command msbuild -ErrorAction SilentlyContinue - if ($msbuild) - { + if ($msbuild) { # all good, nothing to do return } - if (-not (Test-Path $frameworkMsBuildLocation)) - { + if (-not (Test-Path $frameworkMsBuildLocation)) { throw "msbuild not found in '$frameworkMsBuildLocation'. Install Visual Studio 2015." } @@ -1504,7 +1400,7 @@ function script:Use-MSBuild { function script:log([string]$message) { Write-Host -Foreground Green $message #reset colors for older package to at return to default after error message on a compiliation error - [console]::ResetColor() + [console]::ResetColor() } function script:precheck([string]$command, [string]$missedMessage) { @@ -1557,8 +1453,7 @@ function script:Convert-PSObjectToHashtable { } elseif ($InputObject -is [psobject]) { $hash = @{} - foreach ($property in $InputObject.PSObject.Properties) - { + foreach ($property in $InputObject.PSObject.Properties) { $hash[$property.Name] = Convert-PSObjectToHashtable $property.Value } @@ -1575,18 +1470,14 @@ function script:Start-NativeExecution([scriptblock]$sb) { $backupEAP = $script:ErrorActionPreference $script:ErrorActionPreference = "Continue" - try - { + try { & $sb # note, if $sb doens't have a native invocation, $LASTEXITCODE will # point to the obsolete value - if ($LASTEXITCODE -ne 0) - { + if ($LASTEXITCODE -ne 0) { throw "Execution of {$sb} failed with exit code $LASTEXITCODE" } - } - finally - { + } finally { $script:ErrorActionPreference = $backupEAP } } @@ -1607,13 +1498,10 @@ function Get-PackageVersionAsMajorMinorBuildRevision $packageVersionTokens = $Version.Split('-') $packageVersion = ([regex]::matches($Version, "\d+(\.\d+)+"))[0].value - if (1 -eq $packageVersionTokens.Count) - { + if (1 -eq $packageVersionTokens.Count) { # In case the input is of the form a.b.c, add a '0' at the end for revision field $packageVersion = $packageVersion + '.0' - } - elseif (1 -lt $packageVersionTokens.Count) - { + } elseif (1 -lt $packageVersionTokens.Count) { # We have all the four fields $packageBuildTokens = ([regex]::Matches($packageVersionTokens[1], "\d+"))[0].value $packageVersion = $packageVersion + '.' + $packageBuildTokens[0] @@ -1626,10 +1514,9 @@ function New-MSIPackage { [CmdletBinding()] param ( - # Name of the Product [ValidateNotNullOrEmpty()] - [string] $ProductName = 'PowerShell', + [string] $ProductName = 'PowerShell', # Version of the Product [Parameter(Mandatory = $true)] @@ -1652,15 +1539,14 @@ function New-MSIPackage # Path to Assets folder containing artifacts such as icons, images [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [string] $AssetsPath + [string] $AssetsPath - ) + ) $wixToolsetBinPath = "${env:ProgramFiles(x86)}\WiX Toolset v3.10\bin" Write-Verbose "Ensure Wix Toolset is present on the machine @ $wixToolsetBinPath" - if (-not (Test-Path $wixToolsetBinPath)) - { + if (-not (Test-Path $wixToolsetBinPath)) { throw "Install Wix Toolset prior to running this script - https://wix.codeplex.com/downloads/get/1540240" } @@ -1670,13 +1556,13 @@ function New-MSIPackage $wixLightExePath = Join-Path $wixToolsetBinPath "Light.exe" $ProductVersion = Get-PackageVersionAsMajorMinorBuildRevision -Version $ProductVersion -Verbose - + $assetsInSourcePath = "$ProductSourcePath" + '\assets' New-Item $assetsInSourcePath -type directory -Force | Write-Verbose $assetsInSourcePath = Join-Path $ProductSourcePath 'assets' - Write-Verbose "Place dependencies such as icons to $assetsInSourcePath" + Write-Verbose "Place dependencies such as icons to $assetsInSourcePath" Copy-Item "$AssetsPath\*.ico" $assetsInSourcePath -Force $productVersionWithName = $ProductName + "_" + $ProductVersion @@ -1691,14 +1577,14 @@ function New-MSIPackage $wixFragmentPath = (Join-path $env:Temp "Fragment.wxs") $wixObjProductPath = (Join-path $env:Temp "Product.wixobj") $wixObjFragmentPath = (Join-path $env:Temp "Fragment.wixobj") - - $msiLocationPath = Join-Path $pwd "$productVersionWithName.msi" + + $msiLocationPath = Join-Path $pwd "$productVersionWithName.msi" Remove-Item -ErrorAction SilentlyContinue $msiLocationPath -Force & $wixHeatExePath dir $ProductSourcePath -dr $productVersionWithName -cg $productVersionWithName -gg -sfrag -srd -scom -sreg -out $wixFragmentPath -var env.ProductSourcePath -v | Write-Verbose & $wixCandleExePath "$ProductWxsPath" "$wixFragmentPath" -out (Join-Path "$env:Temp" "\\") -arch x64 -v | Write-Verbose & $wixLightExePath -out "$productVersionWithName.msi" $wixObjProductPath $wixObjFragmentPath -ext WixUIExtension -v | Write-Verbose - + Remove-Item -ErrorAction SilentlyContinue *.wixpdb -Force Write-Verbose "You can find the MSI @ $msiLocationPath" @@ -1710,15 +1596,15 @@ function New-AppxPackage { [CmdletBinding()] param ( - + # Name of the Package [ValidateNotNullOrEmpty()] - [string] $PackageName = 'PowerShell', + [string] $PackageName = 'PowerShell', # Version of the Package [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [string] $PackageVersion, + [string] $PackageVersion, # Source Path to the Binplaced Files [Parameter(Mandatory = $true)] @@ -1728,32 +1614,29 @@ function New-AppxPackage # Path to Assets folder containing Appx specific artifacts [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [string] $AssetsPath + [string] $AssetsPath ) - + $PackageVersion = Get-PackageVersionAsMajorMinorBuildRevision -Version $PackageVersion -Verbose Write-Verbose "Package Version is $PackageVersion" $win10sdkBinPath = "${env:ProgramFiles(x86)}\Windows Kits\10\bin\x64" Write-Verbose "Ensure Win10 SDK is present on the machine @ $win10sdkBinPath" - if (-not (Test-Path $win10sdkBinPath)) - { + if (-not (Test-Path $win10sdkBinPath)) { throw "Install Win10 SDK prior to running this script - https://go.microsoft.com/fwlink/p/?LinkID=698771" } Write-Verbose "Ensure Source Path is valid - $SourcePath" - if (-not (Test-Path $SourcePath)) - { + if (-not (Test-Path $SourcePath)) { throw "Invalid SourcePath - $SourcePath" } Write-Verbose "Ensure Assets Path is valid - $AssetsPath" - if (-not (Test-Path $AssetsPath)) - { + if (-not (Test-Path $AssetsPath)) { throw "Invalid AssetsPath - $AssetsPath" } - + Write-Verbose "Initialize MakeAppx executable path" $makeappxExePath = Join-Path $win10sdkBinPath "MakeAppx.exe" @@ -1791,21 +1674,21 @@ function New-AppxPackage Write-Verbose "Place Appx Manifest in $SourcePath" $appxManifest | Out-File "$SourcePath\AppxManifest.xml" -Force - + $assetsInSourcePath = "$SourcePath" + '\Assets' New-Item $assetsInSourcePath -type directory -Force | Out-Null $assetsInSourcePath = Join-Path $SourcePath 'Assets' - Write-Verbose "Place AppxManifest dependencies such as images to $assetsInSourcePath" + Write-Verbose "Place AppxManifest dependencies such as images to $assetsInSourcePath" Copy-Item "$AssetsPath\*.png" $assetsInSourcePath -Force - + $appxPackageName = $PackageName + "_" + $PackageVersion $appxPackagePath = "$pwd\$appxPackageName.appx" Write-Verbose "Calling MakeAppx from $makeappxExePath to create the package @ $appxPackagePath" & $makeappxExePath pack /o /v /d $SourcePath /p $appxPackagePath | Write-Verbose - Write-Verbose "Clean-up Appx artifacts and Assets from $SourcePath" + Write-Verbose "Clean-up Appx artifacts and Assets from $SourcePath" Remove-Item $assetsInSourcePath -Recurse -Force -ErrorAction SilentlyContinue Remove-Item "$SourcePath\AppxManifest.xml" -Force -ErrorAction SilentlyContinue @@ -1955,18 +1838,18 @@ function Start-CrossGen { $script:RESX_TEMPLATE = @' -