mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
Update use of clang PowerShell
This commit is contained in:
parent
16265273b9
commit
3569b3f375
@ -1,231 +0,0 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Compiles or tidies up code from Visual Studio .vcxproj project files.
|
||||
It sets up the scene required for clang-build.ps1 to do its job, and makes
|
||||
command-line usage for projects and files quicker.
|
||||
|
||||
Before calling sample-clang-build.ps1 you need to set the current directory
|
||||
to the root source directory.
|
||||
|
||||
.PARAMETER aVcxprojToCompile
|
||||
Alias 'proj'. Array of project(s) to compile. If empty, all projects are compiled.
|
||||
If the -literal switch is present, name is matched exactly. Otherwise, regex matching is used,
|
||||
e.g. "msicomp" compiles all msicomp projects.
|
||||
|
||||
Can be passed as comma separated values.
|
||||
|
||||
.PARAMETER aVcxprojToIgnore
|
||||
Alias 'proj-ignore'. Array of project(s) to ignore, from the matched ones.
|
||||
If empty, all already matched projects are compiled.
|
||||
If the -literal switch is present, name is matched exactly. Otherwise, regex matching is used,
|
||||
e.g. "msicomp" compiles all msicomp projects.
|
||||
|
||||
Can be passed as comma separated values.
|
||||
|
||||
.PARAMETER aVcxprojConfigPlatform
|
||||
Alias 'active-config'. The configuration-platform pair, separated by |,
|
||||
to be used when processing project files.
|
||||
|
||||
E.g. 'Debug|Win32'.
|
||||
If not specified, the first configuration-plaform found in the current project is used.
|
||||
|
||||
.PARAMETER aCppToCompile
|
||||
Alias 'file'. What cpp(s) to compile from the found project(s). If empty, all CPPs are compiled.
|
||||
If the -literal switch is present, name is matched exactly. Otherwise, regex matching is used,
|
||||
e.g. "table" compiles all CPPs containing 'table'.
|
||||
|
||||
.PARAMETER aCppToIgnore
|
||||
Alias 'file-ignore'. Array of file(s) to ignore, from the matched ones.
|
||||
If empty, all already matched files are compiled.
|
||||
If the -literal switch is present, name is matched exactly. Otherwise, regex matching is used,
|
||||
e.g. "table" ignores all CPPs containing 'table'.
|
||||
|
||||
Can be passed as comma separated values.
|
||||
|
||||
|
||||
.PARAMETER aContinueOnError
|
||||
Alias 'continue'. Switch to continue project compilation even when errors occur.
|
||||
|
||||
.PARAMETER aClangCompileFlags
|
||||
Alias 'clang-flags'. Flags given to clang++ when compiling project,
|
||||
alongside project-specific defines.
|
||||
|
||||
.PARAMETER aDisableNameRegexMatching
|
||||
Alias 'literal'. Switch to take project and cpp name filters literally, not by regex matching.
|
||||
|
||||
.PARAMETER aTidyFlags
|
||||
Alias 'tidy'. If not empty clang-tidy will be called with given flags, instead of clang++.
|
||||
The tidy operation is applied to whole translation units, meaning all directory headers
|
||||
included in the CPP will be tidied up too. Changes will not be applied, only simulated.
|
||||
|
||||
If aTidyFixFlags is present, it takes precedence over this parameter.
|
||||
|
||||
.PARAMETER aTidyFixFlags
|
||||
Alias 'tidy-fix'. If not empty clang-tidy will be called with given flags, instead of clang++.
|
||||
The tidy operation is applied to whole translation units, meaning all directory headers
|
||||
included in the CPP will be tidied up too. Changes will be applied to the file(s).
|
||||
|
||||
If present, this parameter takes precedence over aTidyFlags.
|
||||
|
||||
.PARAMETER aAfterTidyFixFormatStyle
|
||||
Alias 'format-style'. Used in combination with 'tidy-fix'. If present, clang-tidy will
|
||||
also format the fixed file(s), using the specified style.
|
||||
Possible values: - not present, no formatting will be done
|
||||
- 'file'
|
||||
Literally 'file', not a placeholder.
|
||||
Uses .clang-format file in the closest parent directory.
|
||||
- 'llvm'
|
||||
- 'google'
|
||||
- 'webkit'
|
||||
- 'mozilla'
|
||||
|
||||
.EXAMPLE
|
||||
PS .\sample-clang-build.ps1 -dir -proj foo,bar -file meow -tidy "-*,modernize-*"
|
||||
<Description of example>
|
||||
Runs clang-tidy, using "-*,modernize-*", on all CPPs containing 'meow' in their name from
|
||||
the projects containing 'foo' or 'bar' in their names.
|
||||
|
||||
Doesn't actually apply the clang-tidy module changes to CPPs.
|
||||
It will only print the tidy module output.
|
||||
|
||||
.EXAMPLE
|
||||
PS .\sample-clang-build.ps1 -dir -proj foo,bar -file meow -tidy-fix "-*,modernize-*"
|
||||
<Description of example>
|
||||
Runs clang-tidy, using "-*,modernize-*", on all CPPs containing 'meow' in their name from
|
||||
the projects containing 'foo' or 'bar' in their names.
|
||||
|
||||
It will apply all tidy module changes to CPPs.
|
||||
|
||||
.EXAMPLE
|
||||
PS .\sample-clang-build.ps1 -dir -proj foo -proj-ignore foobar
|
||||
<Description of example>
|
||||
Runs clang++ on all CPPs in foo... projects, except foobar
|
||||
|
||||
.OUTPUTS
|
||||
Will output Clang warnings and errors to screen. The return code will be 0 for success, >0 for failure.
|
||||
|
||||
.NOTES
|
||||
Author: Gabriel Diaconita
|
||||
#>
|
||||
param( [alias("proj")] [Parameter(Mandatory=$false)][string[]] $aVcxprojToCompile
|
||||
, [alias("proj-ignore")] [Parameter(Mandatory=$false)][string[]] $aVcxprojToIgnore
|
||||
, [alias("active-config")][Parameter(Mandatory=$false)][string] $aVcxprojConfigPlatform
|
||||
, [alias("file")] [Parameter(Mandatory=$false)][string] $aCppToCompile
|
||||
, [alias("file-ignore")] [Parameter(Mandatory=$false)][string[]] $aCppToIgnore
|
||||
, [alias("continue")] [Parameter(Mandatory=$false)][switch] $aContinueOnError
|
||||
, [alias("literal")] [Parameter(Mandatory=$false)][switch] $aDisableNameRegexMatching
|
||||
, [alias("tidy")] [Parameter(Mandatory=$false)][string] $aTidyFlags
|
||||
, [alias("tidy-fix")] [Parameter(Mandatory=$false)][string] $aTidyFixFlags
|
||||
, [alias("format-style")] [Parameter(Mandatory=$false)][string] $aAfterTidyFixFormatStyle
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------------------------------------
|
||||
|
||||
Set-Variable -name kClangCompileFlags -Option Constant `
|
||||
-value @( "-Wall"
|
||||
, "-fms-compatibility-version=19.10"
|
||||
, "-Wmicrosoft"
|
||||
, "-Wno-invalid-token-paste"
|
||||
, "-Wno-unknown-pragmas"
|
||||
, "-Wno-unused-variable"
|
||||
, "-Wno-unused-value"
|
||||
, "-Wno-undefined-var-template"
|
||||
, "-Wno-microsoft-enum-value"
|
||||
, "-Wno-inconsistent-missing-override"
|
||||
, "-Wno-extra-tokens"
|
||||
, "-Wno-c99-extensions"
|
||||
, "-Wno-logical-op-parentheses"
|
||||
, "-Wno-invalid-source-encoding"
|
||||
)
|
||||
|
||||
Set-Variable -name kVisualStudioVersion -value "2017" -Option Constant
|
||||
Set-Variable -name kVisualStudioSku -value "Professional" -Option Constant
|
||||
Set-Variable -name localVarUseParallelCompile -value $True -Option Constant
|
||||
Set-Variable -name localVarCppToIgnore -Option Constant `
|
||||
-value @( "gtest"
|
||||
, "moc_"
|
||||
)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------------------------
|
||||
|
||||
Function Merge-Array([string[]] $aArray)
|
||||
{
|
||||
# we need to individually wrap items into quotes as values
|
||||
# can contain PS control characters (e.g. - in -std=c++14)
|
||||
$quotedArray = ($aArray | ForEach-Object { """$_"""})
|
||||
return ($quotedArray -join ",")
|
||||
}
|
||||
|
||||
[string] $scriptDirectory = (Split-Path -parent $PSCommandPath)
|
||||
|
||||
[string] $clangScript = "$scriptDirectory\clang-build.ps1"
|
||||
[string[]] $scriptParams = @("-aSolutionsPath", "'$(Get-Location)'")
|
||||
|
||||
if (![string]::IsNullOrEmpty($aVcxprojToCompile))
|
||||
{
|
||||
$scriptParams += ("-aVcxprojToCompile", (Merge-Array $aVcxprojToCompile))
|
||||
}
|
||||
|
||||
if (![string]::IsNullOrEmpty($aVcxprojToIgnore))
|
||||
{
|
||||
$scriptParams += ("-aVcxprojToIgnore", (Merge-Array $aVcxprojToIgnore))
|
||||
}
|
||||
|
||||
if (![string]::IsNullOrEmpty($aVcxprojConfigPlatform))
|
||||
{
|
||||
$scriptParams += ("-aVcxprojConfigPlatform", (Merge-Array $aVcxprojConfigPlatform))
|
||||
}
|
||||
|
||||
if (![string]::IsNullOrEmpty($aCppToCompile))
|
||||
{
|
||||
$scriptParams += ("-aCppToCompile", (Merge-Array $aCppToCompile))
|
||||
}
|
||||
|
||||
if (![string]::IsNullOrEmpty($localVarCppToIgnore))
|
||||
{
|
||||
$scriptParams += ("-aCppToIgnore", (Merge-Array $localVarCppToIgnore))
|
||||
}
|
||||
|
||||
$scriptParams += ("-aClangCompileFlags", (Merge-Array $kClangCompileFlags))
|
||||
|
||||
if (![string]::IsNullOrEmpty($aTidyFlags))
|
||||
{
|
||||
$scriptParams += ("-aTidyFlags", (Merge-Array (@($aTidyFlags))))
|
||||
}
|
||||
|
||||
if (![string]::IsNullOrEmpty($aTidyFixFlags))
|
||||
{
|
||||
$scriptParams += ("-aTidyFixFlags", (Merge-Array (@($aTidyFixFlags))))
|
||||
}
|
||||
|
||||
if (![string]::IsNullOrEmpty($aAfterTidyFixFormatStyle))
|
||||
{
|
||||
$scriptParams += ("-aAfterTidyFixFormatStyle", $aAfterTidyFixFormatStyle)
|
||||
}
|
||||
|
||||
if ($localVarUseParallelCompile)
|
||||
{
|
||||
$scriptParams += ("-aUseParallelCompile")
|
||||
}
|
||||
|
||||
if ($aContinueOnError)
|
||||
{
|
||||
$scriptParams += ("-aContinueOnError")
|
||||
}
|
||||
|
||||
if ($True)
|
||||
{
|
||||
$scriptParams += ("-aTreatAdditionalIncludesAsSystemIncludes")
|
||||
}
|
||||
|
||||
if ($aDisableNameRegexMatching)
|
||||
{
|
||||
$scriptParams += ("-aDisableNameRegexMatching")
|
||||
}
|
||||
|
||||
$scriptParams += ("-aVisualStudioVersion", $kVisualStudioVersion)
|
||||
$scriptParams += ("-aVisualStudioSku", $kVisualStudioSku)
|
||||
$scriptParams += ("-aTidyHeaderFilter", ".*")
|
||||
|
||||
Invoke-Expression "&'$clangScript' $scriptParams"
|
File diff suppressed because it is too large
Load Diff
41
scripts/cpt.config
Normal file
41
scripts/cpt.config
Normal file
@ -0,0 +1,41 @@
|
||||
<cpt-config>
|
||||
|
||||
<!--
|
||||
|
||||
Clang Power Tools configuration file (SAMPLE)
|
||||
|
||||
Using cpt.config you can specify configuration options for ClangPowerTools,
|
||||
allowing your entire team to share a single CPT configuration.
|
||||
|
||||
This file just has to be put in your codebase directory hierarchy's top level and
|
||||
it'll be automatically picked up.
|
||||
|
||||
All clang-build.ps1 parameters are accepted, either full name or alias, as XML elements.
|
||||
|
||||
-->
|
||||
|
||||
<clang-flags> "-Wall"
|
||||
, "-fms-compatibility-version=19.10"
|
||||
, "-Wmicrosoft"
|
||||
, "-Wno-invalid-token-paste"
|
||||
, "-Wno-unknown-pragmas"
|
||||
, "-Wno-unused-variable"
|
||||
, "-Wno-unused-value"
|
||||
, "-Wno-undefined-var-template"
|
||||
, "-Wno-microsoft-enum-value"
|
||||
, "-Wno-inconsistent-missing-override"
|
||||
, "-Wno-extra-tokens"
|
||||
, "-Wno-c99-extensions"
|
||||
, "-Wno-logical-op-parentheses"
|
||||
, "-Wno-invalid-source-encoding"
|
||||
</clang-flags>
|
||||
|
||||
<header-filter>'.*'</header-filter>
|
||||
|
||||
<treat-sai/>
|
||||
|
||||
<vs-sku>'Professional'</vs-sku>
|
||||
|
||||
<file-ignore>"gtest";"moc_"</file-ignore>
|
||||
|
||||
</cpt-config>
|
@ -1,334 +0,0 @@
|
||||
# Tests for ClangPowerTools MSBUILD Expression/Condition translation
|
||||
|
||||
$Configuration = "Release2"
|
||||
$Platform = "Win32"
|
||||
$UserRootDir = "c:\test"
|
||||
$SolutionDir = "C:\AI Trunk\ClangPowerToolsProblem"
|
||||
$ProjectDir = "C:\AI Trunk\win"
|
||||
$TargetName = "YOLOTest"
|
||||
$varB = 1
|
||||
|
||||
# -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
Set-Variable -name "kMsbuildExpressionToPsRules" -option Constant `
|
||||
-value @(<# backticks are control characters in PS, replace them #>
|
||||
('`' , '''' )`
|
||||
<# Temporarily replace $( #> `
|
||||
, ('\$\s*\(' , '!@#' )`
|
||||
<# Escape $ #> `
|
||||
, ('\$' , '`$' )`
|
||||
<# Put back $( #> `
|
||||
, ('!@#' , '$(' )`
|
||||
<# Various operators #> `
|
||||
, ("([\s\)\'""])!=" , '$1 -ne ' )`
|
||||
, ("([\s\)\'""])<=" , '$1 -le ' )`
|
||||
, ("([\s\)\'""])>=" , '$1 -ge ' )`
|
||||
, ("([\s\)\'""])==" , '$1 -eq ' )`
|
||||
, ("([\s\)\'""])<" , '$1 -lt ' )`
|
||||
, ("([\s\)\'""])>" , '$1 -gt ' )`
|
||||
, ("([\s\)\'""])or" , '$1 -or ' )`
|
||||
, ("([\s\)\'""])and" , '$1 -and ' )`
|
||||
<# Use only double quotes #> `
|
||||
, ("\'" , '"' )`
|
||||
, ("Exists\((.*?)\)(\s|$)" , '(Exists($1))$2' )`
|
||||
, ("HasTrailingSlash\((.*?)\)(\s|$)" , '(HasTrailingSlash($1))$2' )`
|
||||
, ("(\`$\()(Registry:)(.*?)(\))" , '$$(GetRegValue("$3"))' )`
|
||||
)
|
||||
|
||||
Set-Variable -name "kMsbuildConditionToPsRules" -option Constant `
|
||||
-value @(<# Use only double quotes #> `
|
||||
("\'" , '"' )`
|
||||
<# We need to escape double quotes since we will eval() the condition #> `
|
||||
, ('"' , '""' )`
|
||||
)
|
||||
|
||||
function GetRegValue([Parameter(Mandatory=$true)][string] $regPath)
|
||||
{
|
||||
[int] $separatorIndex = $regPath.IndexOf('@')
|
||||
[string] $valueName = ""
|
||||
if ($separatorIndex -gt 0)
|
||||
{
|
||||
[string] $valueName = $regPath.Substring($separatorIndex + 1)
|
||||
$regPath = $regPath.Substring(0, $separatorIndex)
|
||||
}
|
||||
if ([string]::IsNullOrEmpty($valueName))
|
||||
{
|
||||
throw "Cannot retrieve an empty registry value"
|
||||
}
|
||||
$regPath = $regPath -replace "HKEY_LOCAL_MACHINE\\", "HKLM:\"
|
||||
|
||||
if (Test-Path $regPath)
|
||||
{
|
||||
return (Get-Item $regPath).GetValue($valueName)
|
||||
}
|
||||
else
|
||||
{
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
function HasTrailingSlash([Parameter(Mandatory=$true)][string] $str)
|
||||
{
|
||||
return $str.EndsWith('\') -or $str.EndsWith('/')
|
||||
}
|
||||
|
||||
function Exists([Parameter(Mandatory=$false)][string] $path)
|
||||
{
|
||||
if ([string]::IsNullOrEmpty($path))
|
||||
{
|
||||
return $false
|
||||
}
|
||||
return Test-Path $path
|
||||
}
|
||||
|
||||
function Evaluate-MSBuildExpression([string] $expression, [switch] $isCondition)
|
||||
{
|
||||
Write-Debug "Start evaluate MSBuild expression $expression"
|
||||
|
||||
foreach ($rule in $kMsbuildExpressionToPsRules)
|
||||
{
|
||||
$expression = $expression -replace $rule[0], $rule[1]
|
||||
}
|
||||
|
||||
if ( !$isCondition -and ($expression.IndexOf('$') -lt 0))
|
||||
{
|
||||
# we can stop here, further processing is not required
|
||||
return $expression
|
||||
}
|
||||
|
||||
[int] $expressionStartIndex = -1
|
||||
[int] $openParantheses = 0
|
||||
for ([int] $i = 0; $i -lt $expression.Length; $i += 1)
|
||||
{
|
||||
if ($expression.Substring($i, 1) -eq '(')
|
||||
{
|
||||
if ($i -gt 0 -and $expressionStartIndex -lt 0 -and $expression.Substring($i - 1, 1) -eq '$')
|
||||
{
|
||||
$expressionStartIndex = $i - 1
|
||||
}
|
||||
|
||||
if ($expressionStartIndex -ge 0)
|
||||
{
|
||||
$openParantheses += 1
|
||||
}
|
||||
}
|
||||
|
||||
if ($expression.Substring($i, 1) -eq ')' -and $expressionStartIndex -ge 0)
|
||||
{
|
||||
$openParantheses -= 1
|
||||
if ($openParantheses -lt 0)
|
||||
{
|
||||
throw "Parse error"
|
||||
}
|
||||
if ($openParantheses -eq 0)
|
||||
{
|
||||
[string] $content = $expression.Substring($expressionStartIndex + 2,
|
||||
$i - $expressionStartIndex - 2)
|
||||
[int] $initialLength = $content.Length
|
||||
|
||||
if ([regex]::Match($content, "[a-zA-Z_][a-zA-Z0-9_\-]+").Value -eq $content)
|
||||
{
|
||||
# we have a plain property retrieval
|
||||
$content = "`${$content}"
|
||||
}
|
||||
else
|
||||
{
|
||||
# dealing with a more complex expression
|
||||
$content = $content -replace '(^|\s+|\$\()([a-zA-Z_][a-zA-Z0-9_]+)(\.|\)|$)', '$1$$$2$3'
|
||||
}
|
||||
|
||||
$newCond = $expression.Substring(0, $expressionStartIndex + 2) +
|
||||
$content + $expression.Substring($i)
|
||||
$expression = $newCond
|
||||
|
||||
$i += ($content.Length - $initialLength)
|
||||
$expressionStartIndex = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Debug "Intermediate PS expression: $expression"
|
||||
|
||||
try
|
||||
{
|
||||
[string] $toInvoke = "(`$s = ""$expression"")"
|
||||
if ($isCondition)
|
||||
{
|
||||
$toInvoke = "(`$s = ""`$($expression)"")"
|
||||
}
|
||||
|
||||
$res = Invoke-Expression $toInvoke
|
||||
}
|
||||
catch
|
||||
{
|
||||
write-debug $_.Exception.Message
|
||||
}
|
||||
|
||||
Write-Debug "Evaluated expression to: $res"
|
||||
|
||||
return $res
|
||||
}
|
||||
|
||||
function Evaluate-MSBuildCondition([Parameter(Mandatory=$true)][string] $condition)
|
||||
{
|
||||
Write-Debug "Evaluating condition $condition"
|
||||
foreach ($rule in $kMsbuildConditionToPsRules)
|
||||
{
|
||||
$condition = $condition -replace $rule[0], $rule[1]
|
||||
}
|
||||
$expression = Evaluate-MSBuildExpression -expression $condition -isCondition
|
||||
|
||||
if ($expression -ieq "true")
|
||||
{
|
||||
return $true
|
||||
}
|
||||
|
||||
if ($expression -ieq "false")
|
||||
{
|
||||
return $false
|
||||
}
|
||||
|
||||
[bool] $res = $false
|
||||
try
|
||||
{
|
||||
$res = (Invoke-Expression $expression) -eq $true
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Debug $_.Exception.Message
|
||||
}
|
||||
Write-Debug "Evaluated condition to $res"
|
||||
|
||||
return $res
|
||||
}
|
||||
|
||||
Clear-Host
|
||||
|
||||
function Test-Condition([string] $condition, [bool]$expectation, [switch] $expectFailure)
|
||||
{
|
||||
[boolean] $condValue
|
||||
try
|
||||
{
|
||||
$condValue = Evaluate-MSBuildCondition $condition
|
||||
}
|
||||
catch
|
||||
{
|
||||
if ($expectFailure)
|
||||
{
|
||||
Write-Output "TEST OK"
|
||||
return
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Output $_.Exception.Message
|
||||
throw "Test failed"
|
||||
}
|
||||
}
|
||||
|
||||
if ($condValue -ne $expectation)
|
||||
{
|
||||
Write-Output "Expected $expectation | Got $condValue"
|
||||
throw "Test failed"
|
||||
}
|
||||
Write-Output "TEST OK"
|
||||
}
|
||||
|
||||
function Test-Expression($expresion)
|
||||
{
|
||||
$res = Evaluate-MSBuildExpression $expresion
|
||||
Write-output $res
|
||||
}
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
Test-Condition "'`$(ImportDirectoryBuildProps)' == 'true' and exists('`$(DirectoryBuildPropsPath)')" -expectation $false
|
||||
|
||||
Test-Expression '$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\15.0\AD7Metrics\ExpressionEvaluator\{3A12D0B7-C26C-11D0-B442-00A0244A1DD2}\{994B45C4-E6E9-11D2-903F-00C04FA302A1}@LoadInShimManagedEE)'
|
||||
Test-Expression '$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@InstallationFolder)'
|
||||
Test-Expression '$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0@InstallationFolder)'
|
||||
|
||||
Test-Expression '$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A@InstallationFolder)'
|
||||
Test-Expression '$(GetRegValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@InstallationFolder"))'
|
||||
|
||||
|
||||
Test-Condition "'`$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A@InstallationFolder)' != ''" `
|
||||
-expectation $true
|
||||
|
||||
Test-Condition "'`$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DevDiv\vs\Servicing\11.0\professional@Version)' == ''" `
|
||||
-expectation $true
|
||||
|
||||
|
||||
Test-Condition -condition "'`$(Configuration)|`$(Platform)'=='Debug|Win32' or '`$(Configuration)' == 'Release2'" `
|
||||
-expectation $true
|
||||
|
||||
Test-Condition -condition "'`$(Platform)'=='x64' or '`$(Platform)'=='Win32' or '`$(Platform)'=='Durango' or exists('`$(UserRootDir)\Microsoft.Cpp.`$(Platform).user.props2')"`
|
||||
-expectation $true
|
||||
|
||||
Test-Condition -condition "exists('c:\ai trunk')"`
|
||||
-expectation $true
|
||||
|
||||
Test-Condition -condition "'`$(Configuration)|`$(Platform)'=='Release|Win32'"`
|
||||
-expectation $false
|
||||
|
||||
Test-Condition -condition '$(Platform.Replace(" ", "")) and $(testB)'`
|
||||
-expectation $false
|
||||
|
||||
Test-Condition -condition '$(Platform) and $(varB)'`
|
||||
-expectation $true
|
||||
|
||||
Test-Condition -condition "exists('`$(UserRootDir)\Microsoft.Cpp.`$(Platform).user.props')"`
|
||||
-expectation $true
|
||||
|
||||
Test-Expression -expression "`$(SolutionDir)\Tools\PropertySheets\Evolution.Module.props"
|
||||
Test-Expression -expresion "WIN32_LEAN_AND_MEAN and `$(Configuration)"
|
||||
|
||||
Test-Condition -condition "exists('`$([Microsoft.Build.Utilities.ToolLocationHelper]::GetPlatformExtensionSDKLocation(``WindowsMobile, Version=10.0.10240.0``, `$(TargetPlatformIdentifier), `$(TargetPlatformVersion), `$(SDKReferenceDirectoryRoot), `$(SDKExtensionDirectoryRoot), `$(SDKReferenceRegistryRoot)))\DesignTime\CommonConfiguration\Neutral\WindowsMobile.props')"`
|
||||
-expectFailure
|
||||
|
||||
Test-Expression -expression "`$Foo;`$(ProjectDir);..\..;..\..\third-party"
|
||||
|
||||
Test-Condition -condition "`$(TargetName.EndsWith('Test'))"`
|
||||
-expectation $true
|
||||
|
||||
Test-Condition -condition "`$(TargetName.EndsWith('Test2'))"`
|
||||
-expectation $false
|
||||
|
||||
$var = 4
|
||||
Test-Condition -condition '$(var) == 2 and 4 == 4'`
|
||||
-expectation $false
|
||||
|
||||
Test-Expression -expression "%(ASDASD);`$(TargetName)"
|
||||
|
||||
$PkgMicrosoft_Gsl = "..\.."
|
||||
Test-Condition -condition "Exists('`$(PkgMicrosoft_Gsl)\build\native\Microsoft.Gsl.targets') OR ! Exists('`$(PkgMicrosoft_Gsl)\build\native\Microsoft.Gsl.targets')"`
|
||||
-expectation $true
|
||||
|
||||
$myVar = 'TwoThree'
|
||||
$MySelector = "One;Two;Three"
|
||||
Test-Condition -condition "`$(MySelector.Contains(`$(myVar.Substring(3, 3))))"`
|
||||
-expectation $true
|
||||
|
||||
$MySelector = "One;Two;Three"
|
||||
$myVar = "Two"
|
||||
Test-Condition -condition "`$(MySelector.Contains(`$(myVar)))"`
|
||||
-expectation $true
|
||||
|
||||
$MySelector = "One;Two;Three"
|
||||
Test-Condition -condition "`$(MySelector.Contains(Three))"`
|
||||
-expectFailure
|
||||
|
||||
$MySelector = "One;Two;Three"
|
||||
Test-Condition -condition "`$(MySelector.Contains('Three'))"`
|
||||
-expectation $true
|
||||
|
||||
Test-Condition -condition "`$([System.DateTime]::Now.Year) == 2018"`
|
||||
-expectation $true
|
||||
|
||||
Test-Condition -condition "HasTrailingSlash('c:\windows\')"`
|
||||
-expectation $true
|
||||
|
||||
Test-Condition -condition "HasTrailingSlash('c:\windows\') and hasTrailingSlash('c:\temp/')"`
|
||||
-expectation $true
|
||||
|
||||
$prop = "c:\windows\"
|
||||
Test-Condition -condition "hasTrailingSlash(`$(prop))"`
|
||||
-expectation $true
|
213
scripts/psClang/get-header-references.ps1
Normal file
213
scripts/psClang/get-header-references.ps1
Normal file
@ -0,0 +1,213 @@
|
||||
# line limit for scanning files for #include
|
||||
[int] $global:cpt_header_include_line_limit = 30
|
||||
|
||||
# after the line limit, if any includes are still found we
|
||||
# extend the limit with this value
|
||||
[int] $global:cpt_header_include_line_extension = 10
|
||||
|
||||
[string[]] $global:headerExtensions = @('h', 'hh', 'hpp', 'hxx')
|
||||
[string[]] $global:sourceExtensions = @('c', 'cc', 'cpp', 'cxx')
|
||||
|
||||
Function detail:FindHeaderReferences( [Parameter(Mandatory = $false)] [string[]] $headers
|
||||
, [Parameter(Mandatory = $false)] [System.IO.FileInfo[]] $filePool
|
||||
, [Parameter(Mandatory = $false)] [System.Collections.Hashtable] $alreadyFound = @{}
|
||||
)
|
||||
{
|
||||
if (!$headers)
|
||||
{
|
||||
return @()
|
||||
}
|
||||
|
||||
[string] $regexHeaders = ($headers | ForEach-Object { ([System.IO.FileInfo]$_).BaseName } `
|
||||
| Select-Object -Unique `
|
||||
| Where-Object { $_ -ine "stdafx" -and $_ -ine "resource" } `
|
||||
) -join '|'
|
||||
|
||||
if ($regexHeaders.Length -eq 0)
|
||||
{
|
||||
return @()
|
||||
}
|
||||
|
||||
[string] $regex = "[/""]($regexHeaders)\.($($global:headerExtensions -join '|'))"""
|
||||
Write-Debug "Regex for header reference find: $regex`n"
|
||||
|
||||
[string[]] $returnRefs = @()
|
||||
if (!$filePool)
|
||||
{
|
||||
# initialize pool of files that we look into
|
||||
[string[]] $allFileExts = ($global:sourceExtensions + `
|
||||
$global:headerExtensions) | ForEach-Object { "*.$_" }
|
||||
$filePool = Get-ChildItem -recurse -include $allFileExts
|
||||
}
|
||||
|
||||
foreach ($file in $filePool)
|
||||
{
|
||||
if ($alreadyFound.ContainsKey($file.FullName))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
[int] $lineCount = 0
|
||||
[int] $lineLimit = $global:cpt_header_include_line_limit
|
||||
foreach($line in [System.IO.File]::ReadLines($file))
|
||||
{
|
||||
if ([string]::IsNullOrWhiteSpace($line))
|
||||
{
|
||||
# skip empty lines
|
||||
continue
|
||||
}
|
||||
|
||||
if ($line -match $regex)
|
||||
{
|
||||
if ( ! $alreadyFound.ContainsKey($file.FullName))
|
||||
{
|
||||
$alreadyFound[$file.FullName] = $true
|
||||
$returnRefs += $file.FullName
|
||||
}
|
||||
|
||||
if ($lineCount -eq $lineLimit)
|
||||
{
|
||||
# we still have includes to scan
|
||||
$lineLimit += $global:cpt_header_include_line_extension
|
||||
}
|
||||
}
|
||||
|
||||
if ( (++$lineCount) -gt $lineLimit)
|
||||
{
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($returnRefs.Count -gt 0)
|
||||
{
|
||||
[string[]] $headersLeftToSearch = ($returnRefs | Where-Object `
|
||||
{ FileHasExtension -filePath $_ `
|
||||
-ext $global:headerExtensions } )
|
||||
if ($headersLeftToSearch.Count -gt 0)
|
||||
{
|
||||
Write-Debug "[!] Recursive reference detection in progress for: "
|
||||
Write-Debug ($headersLeftToSearch -join "`n")
|
||||
$returnRefs += detail:FindHeaderReferences -headers $headersLeftToSearch `
|
||||
-filePool $filePool `
|
||||
-alreadyFound $alreadyFound
|
||||
}
|
||||
}
|
||||
|
||||
$returnRefs = $returnRefs | Select-Object -Unique
|
||||
Write-Debug "Found header refs (regex $regex)"
|
||||
Write-Debug ($returnRefs -join "`n")
|
||||
return $returnRefs
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Detects source files that reference given headers.
|
||||
|
||||
Returns an array with full paths of files that reference the header(s).
|
||||
.DESCRIPTION
|
||||
When modifying a header, all translation units that include that header
|
||||
have to compiled. This function detects those files that include it.
|
||||
.PARAMETER files
|
||||
Header files of which we want references to be found
|
||||
Any files that are not headers will be ignored.
|
||||
#>
|
||||
Function Get-HeaderReferences([Parameter(Mandatory = $false)][string[]] $files)
|
||||
{
|
||||
if ($files.Count -eq 0)
|
||||
{
|
||||
return @()
|
||||
}
|
||||
|
||||
# we take interest only in files that reference headers
|
||||
$files = $files | Where-Object { FileHasExtension -filePath $_ `
|
||||
-ext $global:headerExtensions }
|
||||
|
||||
[string[]] $refs = @()
|
||||
|
||||
if ($files.Count -gt 0)
|
||||
{
|
||||
Write-Verbose-Timed "Headers changed. Detecting which source files to process..."
|
||||
$refs = detail:FindHeaderReferences -headers $files
|
||||
Write-Verbose-Timed "Finished detecting source files."
|
||||
}
|
||||
|
||||
return $refs
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Detects projects that reference given source files (i.e. cpps).
|
||||
|
||||
Returns an array with full paths of detected projects.
|
||||
.DESCRIPTION
|
||||
When modifying a file, only projects that reference that file should be recompiled.
|
||||
.PARAMETER projectPool
|
||||
Projects in which to look
|
||||
.PARAMETER files
|
||||
Source files to be found in projects.
|
||||
#>
|
||||
Function Get-SourceCodeIncludeProjects([Parameter(Mandatory = $false)][System.IO.FileInfo[]] $projectPool,
|
||||
[Parameter(Mandatory = $false)][string[]] $files)
|
||||
{
|
||||
[System.Collections.Hashtable] $fileCache = @{}
|
||||
foreach ($file in $files)
|
||||
{
|
||||
if ($file)
|
||||
{
|
||||
$fileCache[$file.Trim().ToLower()] = $true
|
||||
}
|
||||
}
|
||||
|
||||
[System.IO.FileInfo[]] $matchedProjects = @()
|
||||
|
||||
[string] $clPrefix = '<ClCompile Include="'
|
||||
[string] $clSuffix = '" />'
|
||||
[string] $endGroupTag = '</ItemGroup>'
|
||||
|
||||
foreach ($proj in $projectPool)
|
||||
{
|
||||
[string] $projDir = $proj.Directory.FullName
|
||||
|
||||
[bool] $inClIncludeSection = $false
|
||||
foreach($line in [System.IO.File]::ReadLines($proj.FullName))
|
||||
{
|
||||
$line = $line.Trim()
|
||||
|
||||
if ($line.StartsWith($clPrefix))
|
||||
{
|
||||
if (!$inClIncludeSection)
|
||||
{
|
||||
$inClIncludeSection = $true
|
||||
}
|
||||
|
||||
[string] $filePath = $line.Substring($clPrefix.Length, `
|
||||
$line.Length - $clPrefix.Length - $clSuffix.Length)
|
||||
if (![System.IO.Path]::IsPathRooted($filePath))
|
||||
{
|
||||
$filePath = Canonize-Path -base $projDir -child $filePath -ignoreErrors
|
||||
}
|
||||
if ([string]::IsNullOrEmpty($filePath))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
[System.IO.FileInfo] $sourceFile = $filePath
|
||||
if ($fileCache.ContainsKey($sourceFile.FullName.Trim().ToLower()) -or `
|
||||
$fileCache.ContainsKey($sourceFile.Name.Trim().ToLower()))
|
||||
{
|
||||
$matchedProjects += $proj
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ($inClIncludeSection -and $line -eq $endGroupTag)
|
||||
{
|
||||
# nothing more to check in this project
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $matchedProjects
|
||||
}
|
238
scripts/psClang/io.ps1
Normal file
238
scripts/psClang/io.ps1
Normal file
@ -0,0 +1,238 @@
|
||||
#Console IO
|
||||
# ------------------------------------------------------------------------------------------------
|
||||
Function Write-Message([parameter(Mandatory = $true)][string] $msg
|
||||
, [Parameter(Mandatory = $true)][System.ConsoleColor] $color)
|
||||
{
|
||||
$foregroundColor = $host.ui.RawUI.ForegroundColor
|
||||
$host.ui.RawUI.ForegroundColor = $color
|
||||
Write-Output $msg
|
||||
$host.ui.RawUI.ForegroundColor = $foregroundColor
|
||||
}
|
||||
|
||||
# Writes an error without the verbose PowerShell extra-info (script line location, etc.)
|
||||
Function Write-Err([parameter(ValueFromPipeline, Mandatory = $true)][string] $msg)
|
||||
{
|
||||
Write-Message -msg $msg -color Red
|
||||
}
|
||||
|
||||
Function Write-Success([parameter(ValueFromPipeline, Mandatory = $true)][string] $msg)
|
||||
{
|
||||
Write-Message -msg $msg -color Green
|
||||
}
|
||||
|
||||
Function Write-Array($array, $name)
|
||||
{
|
||||
Write-Output "$($name):"
|
||||
$array | ForEach-Object { Write-Output " $_" }
|
||||
Write-Output "" # empty line separator
|
||||
}
|
||||
|
||||
Function Write-Verbose-Array($array, $name)
|
||||
{
|
||||
Write-Verbose "$($name):"
|
||||
$array | ForEach-Object { Write-Verbose " $_" }
|
||||
Write-Verbose "" # empty line separator
|
||||
}
|
||||
|
||||
Function Write-Verbose-Timed([parameter(ValueFromPipeline, Mandatory = $true)][string] $msg)
|
||||
{
|
||||
Write-Verbose "$([DateTime]::Now.ToString("[HH:mm:ss]")) $msg"
|
||||
}
|
||||
|
||||
Function Print-InvocationArguments()
|
||||
{
|
||||
$bParams = $PSCmdlet.MyInvocation.BoundParameters
|
||||
if ($bParams)
|
||||
{
|
||||
[string] $paramStr = "clang-build.ps1 invocation args: `n"
|
||||
foreach ($key in $bParams.Keys)
|
||||
{
|
||||
$paramStr += " $($key) = $($bParams[$key]) `n"
|
||||
}
|
||||
Write-Verbose $paramStr
|
||||
}
|
||||
}
|
||||
|
||||
Function Print-CommandParameters([Parameter(Mandatory = $true)][string] $command)
|
||||
{
|
||||
$params = @()
|
||||
foreach ($param in ((Get-Command $command).ParameterSets[0].Parameters))
|
||||
{
|
||||
if (!$param.HelpMessage)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
$params += New-Object PsObject -Prop @{ "Option" = "-$($param.Aliases[0])"
|
||||
; "Description" = $param.HelpMessage
|
||||
}
|
||||
}
|
||||
|
||||
$params | Sort-Object -Property "Option" | Out-Default
|
||||
}
|
||||
|
||||
|
||||
|
||||
# Function that gets the name of a command argument when it is only known by its alias
|
||||
# For streamlining purposes, it also accepts the name itself.
|
||||
Function Get-CommandParameterName([Parameter(Mandatory = $true)][string] $command
|
||||
,[Parameter(Mandatory = $true)][string] $nameOrAlias)
|
||||
{
|
||||
foreach ($param in ((Get-Command $command).ParameterSets[0].Parameters))
|
||||
{
|
||||
if ($param.Name -eq $nameOrAlias -or
|
||||
$param.Aliases -contains $nameOrAlias)
|
||||
{
|
||||
return $param.Name
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
# File IO
|
||||
# ------------------------------------------------------------------------------------------------
|
||||
Function Remove-PathTrailingSlash([Parameter(Mandatory = $true)][string] $path)
|
||||
{
|
||||
return $path -replace '\\$', ''
|
||||
}
|
||||
|
||||
Function Get-FileDirectory([Parameter(Mandatory = $true)][string] $filePath)
|
||||
{
|
||||
return ([System.IO.Path]::GetDirectoryName($filePath) + "\")
|
||||
}
|
||||
|
||||
Function Get-FileName( [Parameter(Mandatory = $true)][string] $path
|
||||
, [Parameter(Mandatory = $false)][switch] $noext)
|
||||
{
|
||||
if ($noext)
|
||||
{
|
||||
return ([System.IO.Path]::GetFileNameWithoutExtension($path))
|
||||
}
|
||||
else
|
||||
{
|
||||
return ([System.IO.Path]::GetFileName($path))
|
||||
}
|
||||
}
|
||||
|
||||
Function IsFileMatchingName( [Parameter(Mandatory = $true)][string] $filePath
|
||||
, [Parameter(Mandatory = $true)][string] $matchName)
|
||||
{
|
||||
if ([System.IO.Path]::IsPathRooted($matchName))
|
||||
{
|
||||
return $filePath -ieq $matchName
|
||||
}
|
||||
|
||||
if ($aDisableNameRegexMatching)
|
||||
{
|
||||
[string] $fileName = (Get-FileName -path $filePath)
|
||||
[string] $fileNameNoExt = (Get-FileName -path $filePath -noext)
|
||||
return (($fileName -eq $matchName) -or ($fileNameNoExt -eq $matchName))
|
||||
}
|
||||
else
|
||||
{
|
||||
return $filePath -match $matchName
|
||||
}
|
||||
}
|
||||
|
||||
Function FileHasExtension( [Parameter(Mandatory = $true)][string] $filePath
|
||||
, [Parameter(Mandatory = $true)][string[]] $ext
|
||||
)
|
||||
{
|
||||
foreach ($e in $ext)
|
||||
{
|
||||
if ($filePath.EndsWith($e))
|
||||
{
|
||||
return $true
|
||||
}
|
||||
}
|
||||
return $false
|
||||
}
|
||||
|
||||
<#
|
||||
.DESCRIPTION
|
||||
Merges an absolute and a relative file path.
|
||||
.EXAMPLE
|
||||
Having base = C:\Windows\System32 and child = .. we get C:\Windows
|
||||
.EXAMPLE
|
||||
Having base = C:\Windows\System32 and child = ..\..\..\.. we get C:\ (cannot go further up)
|
||||
.PARAMETER base
|
||||
The absolute path from which we start.
|
||||
.PARAMETER child
|
||||
The relative path to be merged into base.
|
||||
.PARAMETER ignoreErrors
|
||||
If this switch is not present, an error will be triggered if the resulting path
|
||||
is not present on disk (e.g. c:\Windows\System33).
|
||||
|
||||
If present and the resulting path does not exist, the function returns an empty string.
|
||||
#>
|
||||
Function Canonize-Path( [Parameter(Mandatory = $true)][string] $base
|
||||
, [Parameter(Mandatory = $true)][string] $child
|
||||
, [switch] $ignoreErrors)
|
||||
{
|
||||
[string] $errorAction = If ($ignoreErrors) {"SilentlyContinue"} Else {"Stop"}
|
||||
|
||||
if ([System.IO.Path]::IsPathRooted($child))
|
||||
{
|
||||
if (!(Test-Path $child))
|
||||
{
|
||||
return ""
|
||||
}
|
||||
return $child
|
||||
}
|
||||
else
|
||||
{
|
||||
[string[]] $paths = Join-Path -Path "$base" -ChildPath "$child" -Resolve -ErrorAction $errorAction
|
||||
return $paths
|
||||
}
|
||||
}
|
||||
|
||||
function HasTrailingSlash([Parameter(Mandatory = $true)][string] $str)
|
||||
{
|
||||
return $str.EndsWith('\') -or $str.EndsWith('/')
|
||||
}
|
||||
|
||||
|
||||
function EnsureTrailingSlash([Parameter(Mandatory = $true)][string] $str)
|
||||
{
|
||||
[string] $ret = If (HasTrailingSlash($str)) { $str } else { "$str\" }
|
||||
return $ret
|
||||
}
|
||||
|
||||
function Exists([Parameter(Mandatory = $false)][string] $path)
|
||||
{
|
||||
if ([string]::IsNullOrEmpty($path))
|
||||
{
|
||||
return $false
|
||||
}
|
||||
|
||||
return Test-Path $path
|
||||
}
|
||||
|
||||
function MakePathRelative( [Parameter(Mandatory = $true)][string] $base
|
||||
, [Parameter(Mandatory = $true)][string] $target
|
||||
)
|
||||
{
|
||||
Push-Location "$base\"
|
||||
[string] $relativePath = (Resolve-Path -Relative $target) -replace '^\.\\',''
|
||||
Pop-Location
|
||||
if ( (HasTrailingSlash $target) -or $target.EndsWith('.') )
|
||||
{
|
||||
$relativePath += '\'
|
||||
}
|
||||
return "$relativePath"
|
||||
}
|
||||
|
||||
# Command IO
|
||||
# ------------------------------------------------------------------------------------------------
|
||||
Function Exists-Command([Parameter(Mandatory = $true)][string] $command)
|
||||
{
|
||||
try
|
||||
{
|
||||
Get-Command -name $command -ErrorAction Stop | out-null
|
||||
return $true
|
||||
}
|
||||
catch
|
||||
{
|
||||
return $false
|
||||
}
|
||||
}
|
104
scripts/psClang/io.tests.ps1
Normal file
104
scripts/psClang/io.tests.ps1
Normal file
@ -0,0 +1,104 @@
|
||||
#Clear-Host
|
||||
|
||||
# IMPORT code blocks
|
||||
|
||||
Set-Variable -name "kScriptLocation" `
|
||||
-value (Split-Path -Path $MyInvocation.MyCommand.Definition -Parent) <#`
|
||||
-option Constant#>
|
||||
|
||||
@(
|
||||
, "$kScriptLocation\io.ps1"
|
||||
) | ForEach-Object { . $_ }
|
||||
|
||||
Describe "File IO" {
|
||||
It "Remove-PathTrailingSlash" {
|
||||
Remove-PathTrailingSlash "c:\windows\" | Should -BeExactly "c:\windows"
|
||||
Remove-PathTrailingSlash "c:\windows" | Should -BeExactly "c:\windows"
|
||||
Remove-PathTrailingSlash "..\foo\bar\" | Should -BeExactly "..\foo\bar"
|
||||
}
|
||||
|
||||
It "Get-FileDirectory" {
|
||||
Get-FileDirectory "$env:SystemRoot\explorer.exe" | Should -BeExactly "$env:SystemRoot\"
|
||||
Get-FileDirectory "$env:SystemRoot\explorer.exe" | Should -BeExactly "$env:SystemRoot\"
|
||||
Get-FileDirectory "$env:SystemRoot\foobar.nonexistent" | Should -BeExactly "$env:SystemRoot\"
|
||||
Get-FileDirectory "foo\bar" | Should -BeExactly "foo\"
|
||||
}
|
||||
|
||||
It "Get-FileName" {
|
||||
Get-FileName "$env:SystemRoot\explorer.exe" | Should -BeExactly "explorer.exe"
|
||||
Get-FileName "$env:SystemRoot\foobar.nonexistent" | Should -BeExactly "foobar.nonexistent"
|
||||
}
|
||||
|
||||
It "IsFileMatchingName - no regex" {
|
||||
# Mocking script parameter aDisableNameRegexMatching
|
||||
[bool] $aDisableNameRegexMatching = $true
|
||||
|
||||
$path = "$env:SystemRoot\notepad.exe"
|
||||
IsFileMatchingName -filePath $path -matchName "notepad" | Should -BeExactly $true
|
||||
IsFileMatchingName -filePath $path -matchName "notepad.exe" | Should -BeExactly $true
|
||||
IsFileMatchingName -filePath $path -matchName "notepad.ex" | Should -BeExactly $false
|
||||
IsFileMatchingName -filePath $path -matchName "note" | Should -BeExactly $false
|
||||
IsFileMatchingName -filePath $path -matchName ".*" | Should -BeExactly $false
|
||||
}
|
||||
|
||||
It "IsFileMatchingName - with regex" {
|
||||
# Mocking script parameter aDisableNameRegexMatching
|
||||
[bool] $aDisableNameRegexMatching = $false
|
||||
|
||||
$path = "$env:SystemRoot\notepad.exe"
|
||||
IsFileMatchingName -filePath $path -matchName "notepad" | Should -BeExactly $true
|
||||
IsFileMatchingName -filePath $path -matchName "notepad.exe" | Should -BeExactly $true
|
||||
IsFileMatchingName -filePath $path -matchName "notepad.ex" | Should -BeExactly $true
|
||||
IsFileMatchingName -filePath $path -matchName "note" | Should -BeExactly $true
|
||||
IsFileMatchingName -filePath $path -matchName ".*" | Should -BeExactly $true
|
||||
}
|
||||
|
||||
It "FileHasExtension" {
|
||||
FileHasExtension -filePath "c:\foo.bar" -ext 'bar' | Should -BeExactly $true
|
||||
FileHasExtension -filePath "c:\foo.bar" -ext 'bar2' | Should -BeExactly $false
|
||||
FileHasExtension -filePath "c:\foo.bar" -ext @('bar') | Should -BeExactly $true
|
||||
FileHasExtension -filePath "c:\foo.bar" -ext @('bar2') | Should -BeExactly $false
|
||||
FileHasExtension -filePath "c:\foo.bar" -ext @('bar', 'bar2') | Should -BeExactly $true
|
||||
FileHasExtension -filePath "c:\foo.bar" -ext @('bar2', 'bar') | Should -BeExactly $true
|
||||
FileHasExtension -filePath "c:\foo.bar" -ext @('bar2', 'bar2') | Should -BeExactly $false
|
||||
}
|
||||
|
||||
It "Canonize-Path" {
|
||||
$sysDrive = "$env:SystemDrive\"
|
||||
Canonize-Path -base $sysDrive -child "Windows" | Should -Be $env:SystemRoot
|
||||
{ Canonize-Path -base $sysDrive -child "foobar" } | Should -throw
|
||||
{ Canonize-Path -base $sysDrive -child "foobar" -ignoreErrors } | Should -not -throw
|
||||
Canonize-Path -base $sysDrive -child "foobar" -ignoreErrors | Should -BeExactly $null
|
||||
|
||||
[string[]] $files = Canonize-Path -base $sysDrive -child "*" # get all children
|
||||
$files.Count | Should -BeGreaterThan 1
|
||||
}
|
||||
|
||||
It "Exists" {
|
||||
[string] $winDir = $env:SystemRoot
|
||||
Exists $winDir | should -BeExactly $true
|
||||
Exists "$winDir\notepad.exe" | should -BeExactly $true
|
||||
Exists "$winDir\foobar_surely_nonextant" | should -BeExactly $false
|
||||
}
|
||||
|
||||
It "HasTrailingSlash" {
|
||||
HasTrailingSlash "ab" | should -BeExactly $false
|
||||
HasTrailingSlash "ab\" | should -BeExactly $true
|
||||
HasTrailingSlash "ab/" | should -BeExactly $true
|
||||
HasTrailingSlash "a/b/" | should -BeExactly $true
|
||||
}
|
||||
|
||||
It "EnsureTrailingSlash" {
|
||||
EnsureTrailingSlash "ab" | should -BeExactly "ab\"
|
||||
EnsureTrailingSlash "ab\" | should -BeExactly "ab\"
|
||||
EnsureTrailingSlash "ab/" | should -BeExactly "ab/"
|
||||
EnsureTrailingSlash "a/b/" | should -BeExactly "a/b/"
|
||||
}
|
||||
}
|
||||
|
||||
Describe "Command IO" {
|
||||
It "Exists-Command" {
|
||||
Exists-Command "Get-Process" | Should -BeExactly $true
|
||||
Exists-Command "Get-JiggyWithIt" | Should -BeExactly $false
|
||||
}
|
||||
}
|
208
scripts/psClang/msbuild-expression-eval.ps1
Normal file
208
scripts/psClang/msbuild-expression-eval.ps1
Normal file
@ -0,0 +1,208 @@
|
||||
# REQUIRES io.ps1 to be included
|
||||
|
||||
Set-Variable -name "kMsbuildExpressionToPsRules" <#-option Constant#> `
|
||||
-value @( `
|
||||
<# backticks are control characters in PS, replace them #> `
|
||||
('`' , '''' )`
|
||||
<# Temporarily replace $( #> `
|
||||
, ('\$\s*\(' , '!@#' )`
|
||||
<# Escape $ #> `
|
||||
, ('\$' , '`$' )`
|
||||
<# Put back $( #> `
|
||||
, ('!@#' , '$(' )`
|
||||
<# Various operators #> `
|
||||
, ("([\s\)\'""])!=" , '$1 -ne ' )`
|
||||
, ("([\s\)\'""])<=" , '$1 -le ' )`
|
||||
, ("([\s\)\'""])>=" , '$1 -ge ' )`
|
||||
, ("([\s\)\'""])==" , '$1 -eq ' )`
|
||||
, ("([\s\)\'""])<" , '$1 -lt ' )`
|
||||
, ("([\s\)\'""])>" , '$1 -gt ' )`
|
||||
, ("([\s\)\'""])or" , '$1 -or ' )`
|
||||
, ("([\s\)\'""])and" , '$1 -and ' )`
|
||||
<# Use only double quotes #> `
|
||||
, ("\'" , '"' )`
|
||||
, ("Exists\((.*?)\)(\s|$)" , '(Exists($1))$2' )`
|
||||
, ("HasTrailingSlash\((.*?)\)(\s|$)" , '(HasTrailingSlash($1))$2')`
|
||||
, ("(\`$\()(Registry:)(.*?)(\))" , '$$(GetRegValue("$3"))' )`
|
||||
, ("\[MSBuild\]::GetDirectoryNameOfFileAbove\((.+?),\s*`"?'?((\$.+?\))|(.+?))((|`"|')\))+"`
|
||||
,'GetDirNameOfFileAbove -startDir $1 -targetFile ''$2'')' )`
|
||||
, ("\[MSBuild\]::MakeRelative\((.+?),\s*""?'?((\$.+?\))|(.+?))((|""|')\)\))+"`
|
||||
,'MakePathRelative -base $1 -target "$2")' )`
|
||||
)
|
||||
|
||||
Set-Variable -name "kMsbuildConditionToPsRules" <#-option Constant#> `
|
||||
-value @(<# Use only double quotes #> `
|
||||
,("\'" , '"' )`
|
||||
)
|
||||
|
||||
function GetDirNameOfFileAbove( [Parameter(Mandatory = $true)][string] $startDir
|
||||
, [Parameter(Mandatory = $true)][string] $targetFile
|
||||
)
|
||||
{
|
||||
if ($targetFile.Contains('$'))
|
||||
{
|
||||
$targetFile = Invoke-Expression $targetFile
|
||||
}
|
||||
|
||||
[string] $base = $startDir
|
||||
while ([string]::IsNullOrEmpty((Canonize-Path -base $base `
|
||||
-child $targetFile `
|
||||
-ignoreErrors)))
|
||||
{
|
||||
$base = [System.IO.Path]::GetDirectoryName($base)
|
||||
if ([string]::IsNullOrEmpty($base))
|
||||
{
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return $base
|
||||
}
|
||||
|
||||
function GetRegValue([Parameter(Mandatory = $true)][string] $regPath)
|
||||
{
|
||||
Write-Debug "REG_READ $regPath"
|
||||
|
||||
[int] $separatorIndex = $regPath.IndexOf('@')
|
||||
[string] $valueName = ""
|
||||
if ($separatorIndex -gt 0)
|
||||
{
|
||||
[string] $valueName = $regPath.Substring($separatorIndex + 1)
|
||||
$regPath = $regPath.Substring(0, $separatorIndex)
|
||||
}
|
||||
if ([string]::IsNullOrEmpty($valueName))
|
||||
{
|
||||
throw "Cannot retrieve an empty registry value"
|
||||
}
|
||||
$regPath = $regPath -replace "HKEY_LOCAL_MACHINE\\", "HKLM:\"
|
||||
|
||||
if (Test-Path $regPath)
|
||||
{
|
||||
return (Get-Item $regPath).GetValue($valueName)
|
||||
}
|
||||
else
|
||||
{
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
function Evaluate-MSBuildExpression([string] $expression, [switch] $isCondition)
|
||||
{
|
||||
Write-Debug "Start evaluate MSBuild expression $expression"
|
||||
|
||||
foreach ($rule in $kMsbuildExpressionToPsRules)
|
||||
{
|
||||
$expression = $expression -replace $rule[0], $rule[1]
|
||||
}
|
||||
|
||||
if ( !$isCondition -and ($expression.IndexOf('$') -lt 0))
|
||||
{
|
||||
# we can stop here, further processing is not required
|
||||
return $expression
|
||||
}
|
||||
|
||||
[int] $expressionStartIndex = -1
|
||||
[int] $openParantheses = 0
|
||||
for ([int] $i = 0; $i -lt $expression.Length; $i += 1)
|
||||
{
|
||||
if ($expression[$i] -eq '(')
|
||||
{
|
||||
if ($i -gt 0 -and $expressionStartIndex -lt 0 -and $expression[$i - 1] -eq '$')
|
||||
{
|
||||
$expressionStartIndex = $i - 1
|
||||
}
|
||||
|
||||
if ($expressionStartIndex -ge 0)
|
||||
{
|
||||
$openParantheses += 1
|
||||
}
|
||||
}
|
||||
|
||||
if ($expression[$i] -eq ')' -and $expressionStartIndex -ge 0)
|
||||
{
|
||||
$openParantheses -= 1
|
||||
if ($openParantheses -lt 0)
|
||||
{
|
||||
throw "Parse error"
|
||||
}
|
||||
if ($openParantheses -eq 0)
|
||||
{
|
||||
[string] $content = $expression.Substring($expressionStartIndex + 2,
|
||||
$i - $expressionStartIndex - 2)
|
||||
[int] $initialLength = $content.Length
|
||||
|
||||
if ([regex]::Match($content, "[a-zA-Z_][a-zA-Z0-9_\-]+").Value -eq $content)
|
||||
{
|
||||
# we have a plain property retrieval
|
||||
$content = "`${$content}"
|
||||
}
|
||||
else
|
||||
{
|
||||
# dealing with a more complex expression
|
||||
$content = $content -replace '(^|\s+|\$\()([a-zA-Z_][a-zA-Z0-9_]+)(\.|\)|$)', '$1$$$2$3'
|
||||
}
|
||||
|
||||
$newCond = $expression.Substring(0, $expressionStartIndex + 2) +
|
||||
$content + $expression.Substring($i)
|
||||
$expression = $newCond
|
||||
|
||||
$i += ($content.Length - $initialLength)
|
||||
$expressionStartIndex = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$expression = $expression.replace('"', '""')
|
||||
Write-Debug "Intermediate PS expression: $expression"
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
[string] $toInvoke = "(`$s = ""$expression"")"
|
||||
if ($isCondition)
|
||||
{
|
||||
$toInvoke = "(`$s = ""`$($expression)"")"
|
||||
}
|
||||
|
||||
$res = Invoke-Expression $toInvoke
|
||||
}
|
||||
catch
|
||||
{
|
||||
write-debug $_.Exception.Message
|
||||
}
|
||||
|
||||
Write-Debug "Evaluated expression to: $res"
|
||||
|
||||
return $res
|
||||
}
|
||||
function Evaluate-MSBuildCondition([Parameter(Mandatory = $true)][string] $condition)
|
||||
{
|
||||
Write-Debug "Evaluating condition $condition"
|
||||
foreach ($rule in $kMsbuildConditionToPsRules)
|
||||
{
|
||||
$condition = $condition -replace $rule[0], $rule[1]
|
||||
}
|
||||
$expression = Evaluate-MSBuildExpression -expression $condition -isCondition
|
||||
|
||||
if ($expression -ieq "true")
|
||||
{
|
||||
return $true
|
||||
}
|
||||
|
||||
if ($expression -ieq "false")
|
||||
{
|
||||
return $false
|
||||
}
|
||||
|
||||
[bool] $res = $false
|
||||
try
|
||||
{
|
||||
$res = (Invoke-Expression $expression) -eq $true
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Debug $_.Exception.Message
|
||||
}
|
||||
Write-Debug "Evaluated condition to $res"
|
||||
|
||||
return $res
|
||||
}
|
232
scripts/psClang/msbuild-expression-eval.tests.ps1
Normal file
232
scripts/psClang/msbuild-expression-eval.tests.ps1
Normal file
@ -0,0 +1,232 @@
|
||||
#Clear-Host
|
||||
|
||||
# IMPORT code blocks
|
||||
|
||||
Set-Variable -name "kScriptLocation" `
|
||||
-value (Split-Path -Path $MyInvocation.MyCommand.Definition -Parent) <#`
|
||||
-option Constant#>
|
||||
|
||||
@(
|
||||
, "$kScriptLocation\io.ps1"
|
||||
, "$kScriptLocation\msbuild-expression-eval.ps1"
|
||||
) | ForEach-Object { . $_ }
|
||||
|
||||
Describe "MSBuild - Powershell Expression translation" {
|
||||
It "Plain expressions" {
|
||||
Evaluate-MSBuildExpression "MyProjectString" | Should -BeExactly "MyProjectString"
|
||||
Evaluate-MSBuildExpression "1905" | Should -BeExactly "1905"
|
||||
Evaluate-MSBuildExpression "a;;b;c" | Should -BeExactly "a;;b;c"
|
||||
Evaluate-MSBuildExpression "a-b-c" | Should -BeExactly "a-b-c"
|
||||
Evaluate-MSBuildExpression "1-2-3" | Should -BeExactly "1-2-3"
|
||||
Evaluate-MSBuildExpression "{1-2-3-4}" | Should -BeExactly "{1-2-3-4}"
|
||||
Evaluate-MSBuildExpression "1.2.3.4" | Should -BeExactly "1.2.3.4"
|
||||
Evaluate-MSBuildExpression "c:\foo\bar.ini" | Should -BeExactly "c:\foo\bar.ini"
|
||||
Evaluate-MSBuildExpression "..\foo\bar" | Should -BeExactly "..\foo\bar"
|
||||
}
|
||||
|
||||
It "Arithmetical operators" {
|
||||
Evaluate-MSBuildExpression "`$(1+2+3)" | Should -BeExactly "6"
|
||||
Evaluate-MSBuildExpression "`$(1-2-3)" | Should -BeExactly "-4"
|
||||
Evaluate-MSBuildExpression "`$(1*2*3)" | Should -BeExactly "6"
|
||||
Evaluate-MSBuildExpression "`$(10/2)" | Should -BeExactly "5"
|
||||
}
|
||||
|
||||
It "Read from registry" {
|
||||
$e = '$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion@ProgramFilesDir)'
|
||||
Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles
|
||||
|
||||
$e = '$(GetRegValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion@ProgramFilesDir"))'
|
||||
Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles
|
||||
}
|
||||
|
||||
It "Property expansion" {
|
||||
$ProjectDir = "C:\Users\Default"
|
||||
Evaluate-MSBuildExpression "`$Foo;`$(ProjectDir);..\..;..\..\third-party" `
|
||||
| Should -BeExactly '$Foo;C:\Users\Default;..\..;..\..\third-party'
|
||||
|
||||
$TargetName = "Test"
|
||||
Evaluate-MSBuildExpression "%(ASDASD);`$(TargetName)" | Should -BeExactly "%(ASDASD);Test"
|
||||
|
||||
$prop = "123"
|
||||
Evaluate-MSBuildExpression 'plaintext;"$(prop)"' | Should -BeExactly 'plaintext;"123"'
|
||||
Evaluate-MSBuildExpression 'plaintext;''$(prop)''' | Should -BeExactly 'plaintext;"123"'
|
||||
Evaluate-MSBuildExpression 'plaintext;$(prop)-$(prop)' | Should -BeExactly 'plaintext;123-123'
|
||||
|
||||
$TestDir = $env:ProgramFiles
|
||||
Evaluate-MSBuildExpression '$(TestDir)\first\second' | Should -BeExactly "$env:ProgramFiles\first\second"
|
||||
}
|
||||
|
||||
It "GetDirectoryNameOfFileAbove() MSBuild builtin function" {
|
||||
[string] $MSBuildThisFileDirectory = $env:SystemRoot
|
||||
|
||||
$e = '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), ''Program Files'')Program Files'
|
||||
Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles
|
||||
|
||||
$e = '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), "Program Files")Program Files'
|
||||
Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles
|
||||
|
||||
[string] $whatToFind = "Program Files"
|
||||
$e = '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), ''$(whatToFind)'')Program Files'
|
||||
Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles
|
||||
|
||||
$e = '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Program Files)Program Files'
|
||||
Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles
|
||||
|
||||
[string] $_DirectoryBuildPropsFile = "clang-build.ps1"
|
||||
[string] $MSBuildProjectDirectory = "$PSScriptRoot"
|
||||
[string] $DirParent = [System.IO.Directory]::GetParent($MSBuildProjectDirectory)
|
||||
|
||||
$e = '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), ''$(_DirectoryBuildPropsFile)''))'
|
||||
Evaluate-MSBuildExpression $e | Should -Be "$DirParent"
|
||||
}
|
||||
|
||||
It "MakeRelative() MSBuild builtin function" {
|
||||
$SystemDrive = $env:SystemDrive
|
||||
$SystemRoot = $env:SystemRoot
|
||||
$ProgramFiles = $env:ProgramFiles
|
||||
|
||||
$e = "`$([MSBuild]::MakeRelative('$SystemDrive', '$SystemRoot'))"
|
||||
Evaluate-MSBuildExpression $e | Should -Be "Windows"
|
||||
|
||||
$e = "`$([MSBuild]::MakeRelative(`$(SystemDrive), '$SystemRoot'))"
|
||||
Evaluate-MSBuildExpression $e | Should -Be "Windows"
|
||||
|
||||
$e = '$([MSBuild]::MakeRelative($(SystemDrive), $(SystemRoot)\System32))'
|
||||
Evaluate-MSBuildExpression $e | Should -Be "Windows\System32"
|
||||
|
||||
$e = '$([MSBuild]::MakeRelative($(SystemRoot), $(SystemRoot)\System32))'
|
||||
Evaluate-MSBuildExpression $e | Should -Be "System32"
|
||||
|
||||
$e = '$([MSBuild]::MakeRelative($(ProgramFiles), $(SystemRoot)\System32))'
|
||||
Evaluate-MSBuildExpression $e | Should -Be "..\Windows\System32"
|
||||
}
|
||||
|
||||
It ".NET Method invocation" {
|
||||
$Sys32Folder = "System32"
|
||||
$WinDir = $env:SystemRoot
|
||||
$e = '$([System.IO.Path]::Combine(''$(WinDir)'', ''$(Sys32Folder)''))'
|
||||
Evaluate-MSBuildExpression $e | Should -BeExactly "$WinDir\$Sys32Folder"
|
||||
}
|
||||
}
|
||||
|
||||
Describe "Condition evaluation" {
|
||||
It "Logical operators" {
|
||||
Evaluate-MSBuildCondition '0 != 1' | Should -BeExactly $true
|
||||
Evaluate-MSBuildCondition '1 != 1' | Should -BeExactly $false
|
||||
Evaluate-MSBuildCondition '1 == 1' | Should -BeExactly $true
|
||||
Evaluate-MSBuildCondition '0 == 1' | Should -BeExactly $false
|
||||
Evaluate-MSBuildCondition '0 < 1' | Should -BeExactly $true
|
||||
Evaluate-MSBuildCondition '1 <= 1' | Should -BeExactly $true
|
||||
Evaluate-MSBuildCondition '1 < 0' | Should -BeExactly $false
|
||||
Evaluate-MSBuildCondition '1 <= 0' | Should -BeExactly $false
|
||||
Evaluate-MSBuildCondition '1 > 0' | Should -BeExactly $true
|
||||
Evaluate-MSBuildCondition '1 >= 1' | Should -BeExactly $true
|
||||
Evaluate-MSBuildCondition '1 < 0 or 0 < 1' | Should -BeExactly $true
|
||||
Evaluate-MSBuildCondition '!(1 < 0 or 0 < 1)' | Should -BeExactly $false
|
||||
Evaluate-MSBuildCondition '1 < 0 and 0 < 1' | Should -BeExactly $false
|
||||
Evaluate-MSBuildCondition '1 < 0 and 0 < 1' | Should -BeExactly $false
|
||||
Evaluate-MSBuildCondition '((1 < 0) or (0 < 1)) and !("a"=="b")' | Should -BeExactly $true
|
||||
Evaluate-MSBuildCondition '"apple" == "apple"' | Should -BeExactly $true
|
||||
Evaluate-MSBuildCondition '''apple'' == ''apple''' | Should -BeExactly $true
|
||||
Evaluate-MSBuildCondition '''apple'' == ''pear''' | Should -BeExactly $false
|
||||
Evaluate-MSBuildCondition '"apple" != "pear"' | Should -BeExactly $true
|
||||
}
|
||||
|
||||
It "Registry access" {
|
||||
$c = "'`$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion@ProgramFilesDir)' != ''"
|
||||
Evaluate-MSBuildCondition $c | Should -BeExactly $true
|
||||
|
||||
$ProgramFiles = $env:ProgramFiles
|
||||
$c = "'`$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion@ProgramFilesDir)' == '`$(ProgramFiles)'"
|
||||
Evaluate-MSBuildCondition $c | Should -BeExactly $true
|
||||
|
||||
$c = "'`$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion@NonexistentValue)' == ''"
|
||||
Evaluate-MSBuildCondition $c | Should -BeExactly $true
|
||||
}
|
||||
|
||||
It "Variable expansion" {
|
||||
|
||||
$Configuration = "Release2"
|
||||
$Platform = "Win32"
|
||||
|
||||
Evaluate-MSBuildCondition "'`$(Configuration)|`$(Platform)'=='Debug|Win32' or '`$(Configuration)' == 'Release2'" | Should -BeExactly $true
|
||||
Evaluate-MSBuildCondition "'`$(Configuration)|`$(Platform)'=='Release|Win32'" | Should -BeExactly $false
|
||||
Evaluate-MSBuildCondition '$(Platform.Replace(" ", "")) and $(testB)' | Should -BeExactly $false
|
||||
}
|
||||
|
||||
It "Prop to Bool decay" {
|
||||
$First = "something"
|
||||
$Second = "else"
|
||||
|
||||
Evaluate-MSBuildCondition '$(First) and $(Second)' | Should -BeExactly $true
|
||||
|
||||
Remove-Variable "First"
|
||||
|
||||
Evaluate-MSBuildCondition '$(First) and $(Second)' | Should -BeExactly $false
|
||||
}
|
||||
|
||||
It "Exists() MSBuild builtin function" {
|
||||
|
||||
$WinDir = $env:SystemRoot
|
||||
Evaluate-MSBuildCondition "exists('`$(WinDir)')" | Should -BeExactly $true
|
||||
Evaluate-MSBuildCondition "1 == 1 and exists('`$(WinDir)')" | Should -BeExactly $true
|
||||
Evaluate-MSBuildCondition "exists('`$(WinDir)\System32')" | Should -BeExactly $true
|
||||
|
||||
$WinDir += "gibberish12345"
|
||||
Evaluate-MSBuildCondition "exists('`$(WinDir)')" | Should -BeExactly $false
|
||||
Evaluate-MSBuildCondition "0 == 1 and exists('`$(WinDir)')" | Should -BeExactly $false
|
||||
|
||||
[System.Reflection.Assembly]::LoadWithPartialName("System.IO")
|
||||
$eression = 'Exists("$([System.IO.Directory]::GetCurrentDirectory())")'
|
||||
Evaluate-MSBuildCondition $eression | Should -BeExactly $true
|
||||
$eression = 'Exists("$([System.IO.Directory]::GetCurrentDirectory())\nonexistent12345")'
|
||||
Evaluate-MSBuildCondition $eression | Should -BeExactly $false
|
||||
|
||||
$Sys32 = "$env:SystemRoot\System32"
|
||||
$WinDir = "$Sys32..\.."
|
||||
Evaluate-MSBuildCondition "Exists('`$(Sys32)\..')" | Should -BeExactly $true
|
||||
}
|
||||
|
||||
It "Access to [String] builtin functions" {
|
||||
|
||||
$TargetName = "AnotherTest"
|
||||
Evaluate-MSBuildCondition "`$(TargetName.EndsWith('Test'))" | Should -BeExactly $true
|
||||
Evaluate-MSBuildCondition "`$(TargetName.EndsWith('Test2'))" | Should -BeExactly $false
|
||||
|
||||
$myVar = 'TwoThree'
|
||||
$MySelector = "One;Two;Three"
|
||||
Evaluate-MSBuildCondition "`$(MySelector.Contains(`$(myVar.Substring(3, 3))))"`
|
||||
| Should -BeExactly $true
|
||||
|
||||
$MySelector = "One;Two;Three"
|
||||
$myVar = "Two"
|
||||
Evaluate-MSBuildCondition "`$(MySelector.Contains(`$(myVar)))" | Should -BeExactly $true
|
||||
|
||||
$MySelector = "One;Two;Three"
|
||||
Evaluate-MSBuildCondition "`$(MySelector.Contains('Three'))" | Should -BeExactly $true
|
||||
Evaluate-MSBuildCondition "`$(MySelector.Contains('Four'))" | Should -BeExactly $false
|
||||
}
|
||||
|
||||
It ".NET method invocation" {
|
||||
$year = (Get-Date).Year
|
||||
Evaluate-MSBuildCondition "`$([System.DateTime]::Now.Year) == `$(year)" | Should -BeExactly $true
|
||||
Evaluate-MSBuildCondition "`$([System.DateTime]::Now.Year) != `$(year)" | Should -BeExactly $false
|
||||
}
|
||||
|
||||
It "HasTrailingSlash() MSBuild builtin function" {
|
||||
Evaluate-MSBuildCondition "HasTrailingSlash('c:\windows\')" | Should -BeExactly $true
|
||||
Evaluate-MSBuildCondition "HasTrailingSlash('c:\windows')" | Should -BeExactly $false
|
||||
|
||||
$c = "HasTrailingSlash('c:\windows\') and hasTrailingSlash('c:\temp/')"
|
||||
Evaluate-MSBuildCondition $c | Should -BeExactly $true
|
||||
|
||||
$c = "HasTrailingSlash('c:\windows\') and !hasTrailingSlash('c:\temp/')"
|
||||
Evaluate-MSBuildCondition $c | Should -BeExactly $false
|
||||
|
||||
$prop = "c:\windows\"
|
||||
Evaluate-MSBuildCondition "hasTrailingSlash(`$(prop))" | Should -BeExactly $true
|
||||
|
||||
$prop = "c:\windows"
|
||||
Evaluate-MSBuildCondition "hasTrailingSlash(`$(prop))" | Should -BeExactly $false
|
||||
}
|
||||
}
|
583
scripts/psClang/msbuild-project-data.ps1
Normal file
583
scripts/psClang/msbuild-project-data.ps1
Normal file
@ -0,0 +1,583 @@
|
||||
#-------------------------------------------------------------------------------------------------
|
||||
# PlatformToolset constants
|
||||
|
||||
Set-Variable -name kDefinesUnicode -value @("-DUNICODE"
|
||||
,"-D_UNICODE"
|
||||
) `
|
||||
-option Constant
|
||||
|
||||
Set-Variable -name kDefinesMultiThreaded -value @("-D_MT") `
|
||||
-option Constant
|
||||
|
||||
Set-Variable -name kDefinesClangXpTargeting `
|
||||
-value @("-D_USING_V110_SDK71_") `
|
||||
-option Constant
|
||||
|
||||
Set-Variable -name kIncludePathsXPTargetingSDK `
|
||||
-value "${Env:ProgramFiles(x86)}\Microsoft SDKs\Windows\v7.1A\Include" `
|
||||
-option Constant
|
||||
|
||||
Set-Variable -name kVStudioDefaultPlatformToolset -Value "v141" -option Constant
|
||||
|
||||
Set-Variable -name kClangFlag32BitPlatform -value "-m32" -option Constant
|
||||
|
||||
# ------------------------------------------------------------------------------------------------
|
||||
# Xpath selectors
|
||||
|
||||
Set-Variable -name kVcxprojXpathPreprocessorDefs `
|
||||
-value "ns:Project/ns:ItemDefinitionGroup/ns:ClCompile/ns:PreprocessorDefinitions" `
|
||||
-option Constant
|
||||
|
||||
Set-Variable -name kVcxprojXpathAdditionalIncludes `
|
||||
-value "ns:Project/ns:ItemDefinitionGroup/ns:ClCompile/ns:AdditionalIncludeDirectories" `
|
||||
-option Constant
|
||||
|
||||
Set-Variable -name kVcxprojXpathRuntimeLibrary `
|
||||
-value "ns:Project/ns:ItemDefinitionGroup/ns:ClCompile/ns:RuntimeLibrary" `
|
||||
-option Constant
|
||||
|
||||
Set-Variable -name kVcxprojXpathHeaders `
|
||||
-value "ns:Project/ns:ItemGroup/ns:ClInclude" `
|
||||
-option Constant
|
||||
|
||||
Set-Variable -name kVcxprojXpathCompileFiles `
|
||||
-value "ns:Project/ns:ItemGroup/ns:ClCompile" `
|
||||
-option Constant
|
||||
|
||||
Set-Variable -name kVcxprojXpathWinPlatformVer `
|
||||
-value "ns:Project/ns:PropertyGroup/ns:WindowsTargetPlatformVersion" `
|
||||
-option Constant
|
||||
|
||||
Set-Variable -name kVcxprojXpathForceIncludes `
|
||||
-value "ns:Project/ns:ItemDefinitionGroup/ns:ClCompile/ns:ForcedIncludeFiles" `
|
||||
-option Constant
|
||||
|
||||
Set-Variable -name kVcxprojXpathPCH `
|
||||
-value "ns:Project/ns:ItemGroup/ns:ClCompile/ns:PrecompiledHeader[text()='Create']" `
|
||||
-option Constant
|
||||
|
||||
Set-Variable -name kVcxprojXpathToolset `
|
||||
-value "ns:Project/ns:PropertyGroup[@Label='Configuration']/ns:PlatformToolset" `
|
||||
-option Constant
|
||||
|
||||
Set-Variable -name kVcxprojXpathCppStandard `
|
||||
-value "ns:Project/ns:ItemDefinitionGroup/ns:ClCompile/ns:LanguageStandard" `
|
||||
-option Constant
|
||||
|
||||
|
||||
Set-Variable -name kVcxprojXpathProjectCompileAs `
|
||||
-value "ns:Project/ns:ItemDefinitionGroup/ns:ClCompile/ns:CompileAs" `
|
||||
-option Constant
|
||||
|
||||
# ------------------------------------------------------------------------------------------------
|
||||
# Default platform sdks and standard
|
||||
|
||||
Set-Variable -name kVSDefaultWinSDK -value '8.1' -option Constant
|
||||
Set-Variable -name kVSDefaultWinSDK_XP -value '7.0' -option Constant
|
||||
Set-Variable -name kDefaultCppStd -value "stdcpp14" -option Constant
|
||||
|
||||
# ------------------------------------------------------------------------------------------------
|
||||
Set-Variable -name kCProjectCompile -value "CompileAsC" -option Constant
|
||||
|
||||
Add-Type -TypeDefinition @"
|
||||
public enum UsePch
|
||||
{
|
||||
Use,
|
||||
NotUsing,
|
||||
Create
|
||||
}
|
||||
"@
|
||||
|
||||
Function Should-CompileProject([Parameter(Mandatory = $true)][string] $vcxprojPath)
|
||||
{
|
||||
if ($aVcxprojToCompile -eq $null)
|
||||
{
|
||||
return $true
|
||||
}
|
||||
|
||||
foreach ($projMatch in $aVcxprojToCompile)
|
||||
{
|
||||
if (IsFileMatchingName -filePath $vcxprojPath -matchName $projMatch)
|
||||
{
|
||||
return $true
|
||||
}
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
|
||||
Function Should-IgnoreProject([Parameter(Mandatory = $true)][string] $vcxprojPath)
|
||||
{
|
||||
if ($aVcxprojToIgnore -eq $null)
|
||||
{
|
||||
return $false
|
||||
}
|
||||
|
||||
foreach ($projIgnoreMatch in $aVcxprojToIgnore)
|
||||
{
|
||||
if (IsFileMatchingName -filePath $vcxprojPath -matchName $projIgnoreMatch)
|
||||
{
|
||||
return $true
|
||||
}
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
|
||||
Function Should-CompileFile([Parameter(Mandatory = $false)][System.Xml.XmlNode] $fileNode
|
||||
, [Parameter(Mandatory = $false)][string] $pchCppName
|
||||
)
|
||||
{
|
||||
if ($fileNode -eq $null)
|
||||
{
|
||||
return $false
|
||||
}
|
||||
|
||||
[string] $file = $fileNode.Include
|
||||
|
||||
if (($file -eq $null) -or (![string]::IsNullOrEmpty($pchCppName) -and ($file -eq $pchCppName)))
|
||||
{
|
||||
return $false
|
||||
}
|
||||
|
||||
[System.Xml.XmlNode] $excluded = $fileNode.SelectSingleNode("ns:ExcludedFromBuild", $global:xpathNS)
|
||||
|
||||
if (($excluded -ne $null) -and ($excluded.InnerText -ne $null) -and ($excluded.InnerText -ieq "true"))
|
||||
{
|
||||
return $false
|
||||
}
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
Function Should-IgnoreFile([Parameter(Mandatory = $true)][string] $file)
|
||||
{
|
||||
if ($aCppToIgnore -eq $null)
|
||||
{
|
||||
return $false
|
||||
}
|
||||
|
||||
foreach ($projIgnoreMatch in $aCppToIgnore)
|
||||
{
|
||||
if (IsFileMatchingName -filePath $file -matchName $projIgnoreMatch)
|
||||
{
|
||||
return $true
|
||||
}
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
|
||||
Function Get-ProjectFilesToCompile([Parameter(Mandatory = $false)][string] $pchCppName)
|
||||
{
|
||||
[System.Xml.XmlElement[]] $projectEntries = Select-ProjectNodes($kVcxprojXpathCompileFiles) | `
|
||||
Where-Object { Should-CompileFile -fileNode $_ -pchCppName $pchCppName }
|
||||
|
||||
[System.Collections.ArrayList] $files = @()
|
||||
foreach ($entry in $projectEntries)
|
||||
{
|
||||
[string[]] $matchedFiles = Canonize-Path -base $ProjectDir -child $entry.GetAttribute("Include")
|
||||
[UsePch] $usePch = [UsePch]::Use
|
||||
|
||||
$nodePch = $entry.SelectSingleNode('ns:PrecompiledHeader', $global:xpathNS)
|
||||
if ($nodePch -and ![string]::IsNullOrEmpty($nodePch.'#text'))
|
||||
{
|
||||
switch ($nodePch.'#text')
|
||||
{
|
||||
'NotUsing' { $usePch = [UsePch]::NotUsing }
|
||||
'Create' { $usePch = [UsePch]::Create }
|
||||
}
|
||||
}
|
||||
|
||||
if ($matchedFiles.Count -gt 0)
|
||||
{
|
||||
foreach ($file in $matchedFiles)
|
||||
{
|
||||
$files += New-Object PsObject -Prop @{ "File"= $file;
|
||||
"Pch" = $usePch; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($files.Count -gt 0)
|
||||
{
|
||||
$files = @($files | Where-Object { ! (Should-IgnoreFile -file $_.File) })
|
||||
}
|
||||
|
||||
return $files
|
||||
}
|
||||
|
||||
Function Get-ProjectHeaders()
|
||||
{
|
||||
[string[]] $headers = Select-ProjectNodes($kVcxprojXpathHeaders) | ForEach-Object {$_.Include }
|
||||
|
||||
[string[]] $headerPaths = @()
|
||||
|
||||
foreach ($headerEntry in $headers)
|
||||
{
|
||||
[string[]] $paths = Canonize-Path -base $ProjectDir -child $headerEntry -ignoreErrors
|
||||
if ($paths.Count -gt 0)
|
||||
{
|
||||
$headerPaths += $paths
|
||||
}
|
||||
}
|
||||
return $headerPaths
|
||||
}
|
||||
|
||||
Function Is-CProject()
|
||||
{
|
||||
[string] $compileAs = (Select-ProjectNodes($kVcxprojXpathProjectCompileAs)).InnerText
|
||||
return $compileAs -eq $kCProjectCompile
|
||||
}
|
||||
|
||||
Function Get-Project-SDKVer()
|
||||
{
|
||||
[string] $sdkVer = (Select-ProjectNodes($kVcxprojXpathWinPlatformVer)).InnerText
|
||||
|
||||
If ([string]::IsNullOrEmpty($sdkVer)) { "" } Else { $sdkVer.Trim() }
|
||||
}
|
||||
|
||||
Function Is-Project-MultiThreaded()
|
||||
{
|
||||
$propGroup = Select-ProjectNodes($kVcxprojXpathRuntimeLibrary)
|
||||
|
||||
$runtimeLibrary = $propGroup.InnerText
|
||||
|
||||
return ![string]::IsNullOrEmpty($runtimeLibrary)
|
||||
}
|
||||
|
||||
Function Is-Project-Unicode()
|
||||
{
|
||||
$propGroup = Select-ProjectNodes("ns:Project/ns:PropertyGroup[@Label='Configuration']/ns:CharacterSet")
|
||||
if (! $propGroup)
|
||||
{
|
||||
return $false
|
||||
}
|
||||
return ($propGroup.InnerText -ieq "Unicode")
|
||||
}
|
||||
|
||||
Function Get-Project-CppStandard()
|
||||
{
|
||||
[string] $cachedValueVarName = "ClangPowerTools:CppStd"
|
||||
|
||||
[string] $cachedVar = (Get-Variable $cachedValueVarName -ErrorAction SilentlyContinue -ValueOnly)
|
||||
if (![string]::IsNullOrEmpty($cachedVar))
|
||||
{
|
||||
return $cachedVar
|
||||
}
|
||||
|
||||
[string] $cppStd = ""
|
||||
|
||||
$cppStdNode = Select-ProjectNodes($kVcxprojXpathCppStandard)
|
||||
if ($cppStdNode)
|
||||
{
|
||||
$cppStd = $cppStdNode.InnerText
|
||||
}
|
||||
else
|
||||
{
|
||||
$cppStd = $kDefaultCppStd
|
||||
}
|
||||
|
||||
$cppStdMap = @{ 'stdcpplatest' = 'c++1z'
|
||||
; 'stdcpp14' = 'c++14'
|
||||
; 'stdcpp17' = 'c++17'
|
||||
}
|
||||
|
||||
[string] $cppStdClangValue = $cppStdMap[$cppStd]
|
||||
Set-Var -name $cachedValueVarName -value $cppStdClangValue
|
||||
|
||||
return $cppStdClangValue
|
||||
}
|
||||
|
||||
Function Get-ClangCompileFlags([Parameter(Mandatory = $false)][bool] $isCpp = $true)
|
||||
{
|
||||
[string[]] $flags = $aClangCompileFlags
|
||||
if ($isCpp -and !($flags -match "-std=.*"))
|
||||
{
|
||||
[string] $cppStandard = Get-Project-CppStandard
|
||||
|
||||
$flags = @("-std=$cppStandard") + $flags
|
||||
}
|
||||
|
||||
if ($Platform -ieq "x86" -or $Platform -ieq "Win32")
|
||||
{
|
||||
$flags += @($kClangFlag32BitPlatform)
|
||||
}
|
||||
|
||||
return $flags
|
||||
}
|
||||
|
||||
Function Get-ProjectPlatformToolset()
|
||||
{
|
||||
$propGroup = Select-ProjectNodes($kVcxprojXpathToolset)
|
||||
|
||||
$toolset = $propGroup.InnerText
|
||||
|
||||
if ($toolset)
|
||||
{
|
||||
return $toolset
|
||||
}
|
||||
else
|
||||
{
|
||||
return $kVStudioDefaultPlatformToolset
|
||||
}
|
||||
}
|
||||
|
||||
Function Get-ProjectIncludeDirectories()
|
||||
{
|
||||
[string[]] $returnArray = ($IncludePath -split ";") | `
|
||||
Where-Object { ![string]::IsNullOrWhiteSpace($_) } | `
|
||||
ForEach-Object { Canonize-Path -base $ProjectDir -child $_.Trim() -ignoreErrors } | `
|
||||
Where-Object { ![string]::IsNullOrEmpty($_) } | `
|
||||
ForEach-Object { $_ -replace '\\$', '' }
|
||||
if ($env:CPT_LOAD_ALL -eq '1')
|
||||
{
|
||||
return $returnArray
|
||||
}
|
||||
|
||||
[string] $vsPath = Get-VisualStudio-Path
|
||||
Write-Verbose "Visual Studio location: $vsPath"
|
||||
|
||||
[string] $platformToolset = Get-ProjectPlatformToolset
|
||||
|
||||
if ($global:cptVisualStudioVersion -eq "2015")
|
||||
{
|
||||
$returnArray += Get-VisualStudio-Includes -vsPath $vsPath
|
||||
}
|
||||
else
|
||||
{
|
||||
$mscVer = Get-MscVer -visualStudioPath $vsPath
|
||||
Write-Verbose "MSCVER: $mscVer"
|
||||
|
||||
$returnArray += Get-VisualStudio-Includes -vsPath $vsPath -mscVer $mscVer
|
||||
}
|
||||
|
||||
$sdkVer = Get-Project-SDKVer
|
||||
|
||||
# We did not find a WinSDK version in the vcxproj. We use Visual Studio's defaults
|
||||
if ([string]::IsNullOrEmpty($sdkVer))
|
||||
{
|
||||
if ($platformToolset.EndsWith("xp"))
|
||||
{
|
||||
$sdkVer = $kVSDefaultWinSDK_XP
|
||||
}
|
||||
else
|
||||
{
|
||||
$sdkVer = $kVSDefaultWinSDK
|
||||
}
|
||||
}
|
||||
|
||||
Write-Verbose "WinSDK version: $sdkVer"
|
||||
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
# Windows 10
|
||||
|
||||
if ((![string]::IsNullOrEmpty($sdkVer)) -and ($sdkVer.StartsWith("10")))
|
||||
{
|
||||
$returnArray += @("${Env:ProgramFiles(x86)}\Windows Kits\10\Include\$sdkVer\ucrt")
|
||||
|
||||
if ($platformToolset.EndsWith("xp"))
|
||||
{
|
||||
$returnArray += @($kIncludePathsXPTargetingSDK)
|
||||
}
|
||||
else
|
||||
{
|
||||
$returnArray += @( "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\$sdkVer\um"
|
||||
, "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\$sdkVer\shared"
|
||||
, "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\$sdkVer\winrt"
|
||||
, "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\$sdkVer\cppwinrt"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
# Windows 8 / 8.1
|
||||
|
||||
if ((![string]::IsNullOrEmpty($sdkVer)) -and ($sdkVer.StartsWith("8.")))
|
||||
{
|
||||
$returnArray += @("${Env:ProgramFiles(x86)}\Windows Kits\10\Include\10.0.10240.0\ucrt")
|
||||
|
||||
if ($platformToolset.EndsWith("xp"))
|
||||
{
|
||||
$returnArray += @($kIncludePathsXPTargetingSDK)
|
||||
}
|
||||
else
|
||||
{
|
||||
$returnArray += @( "${Env:ProgramFiles(x86)}\Windows Kits\$sdkVer\Include\um"
|
||||
, "${Env:ProgramFiles(x86)}\Windows Kits\$sdkVer\Include\shared"
|
||||
, "${Env:ProgramFiles(x86)}\Windows Kits\$sdkVer\Include\winrt"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
# Windows 7
|
||||
|
||||
if ((![string]::IsNullOrEmpty($sdkVer)) -and ($sdkVer.StartsWith("7.0")))
|
||||
{
|
||||
$returnArray += @("$vsPath\VC\Auxiliary\VS\include")
|
||||
|
||||
if ($platformToolset.EndsWith("xp"))
|
||||
{
|
||||
$returnArray += @( "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\10.0.10240.0\ucrt"
|
||||
, $kIncludePathsXPTargetingSDK
|
||||
)
|
||||
}
|
||||
else
|
||||
{
|
||||
$returnArray += @( "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\7.0\ucrt")
|
||||
}
|
||||
}
|
||||
|
||||
return ( $returnArray | ForEach-Object { Remove-PathTrailingSlash -path $_ } )
|
||||
}
|
||||
|
||||
<#
|
||||
.DESCRIPTION
|
||||
Retrieve directory in which the PCH CPP resides (e.g. stdafx.cpp, stdafxA.cpp)
|
||||
#>
|
||||
Function Get-Project-PchCpp()
|
||||
{
|
||||
$pchCppRelativePath = Select-ProjectNodes($kVcxprojXpathPCH) |
|
||||
Select-Object -ExpandProperty ParentNode |
|
||||
Select-Object -first 1 |
|
||||
Select-Object -ExpandProperty Include
|
||||
|
||||
return $pchCppRelativePath
|
||||
}
|
||||
|
||||
|
||||
<#
|
||||
.DESCRIPTION
|
||||
Retrieve array of preprocessor definitions for a given project, in Clang format (-DNAME )
|
||||
#>
|
||||
Function Get-ProjectPreprocessorDefines()
|
||||
{
|
||||
[string[]] $tokens = (Select-ProjectNodes $kVcxprojXpathPreprocessorDefs).InnerText -split ";"
|
||||
|
||||
# make sure we add the required prefix and escape double quotes
|
||||
[string[]]$defines = ( $tokens | `
|
||||
ForEach-Object { $_.Trim() } | `
|
||||
Where-Object { $_ } | `
|
||||
ForEach-Object { '"' + $(($kClangDefinePrefix + $_) -replace '"', '\"') + '"' } )
|
||||
|
||||
if (Is-Project-Unicode)
|
||||
{
|
||||
$defines += $kDefinesUnicode
|
||||
}
|
||||
|
||||
if (Is-Project-MultiThreaded)
|
||||
{
|
||||
$defines += $kDefinesMultiThreaded
|
||||
}
|
||||
|
||||
[string] $platformToolset = Get-ProjectPlatformToolset
|
||||
if ($platformToolset.EndsWith("xp"))
|
||||
{
|
||||
$defines += $kDefinesClangXpTargeting
|
||||
}
|
||||
|
||||
return $defines
|
||||
}
|
||||
|
||||
Function Get-ProjectAdditionalIncludes()
|
||||
{
|
||||
[string[]] $tokens = @()
|
||||
|
||||
$data = Select-ProjectNodes $kVcxprojXpathAdditionalIncludes
|
||||
$tokens += ($data).InnerText -split ";"
|
||||
|
||||
foreach ($token in $tokens)
|
||||
{
|
||||
if ([string]::IsNullOrWhiteSpace($token))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
[string] $includePath = Canonize-Path -base $ProjectDir -child $token.Trim() -ignoreErrors
|
||||
if (![string]::IsNullOrEmpty($includePath))
|
||||
{
|
||||
$includePath -replace '\\$', ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Function Get-ProjectForceIncludes()
|
||||
{
|
||||
[System.Xml.XmlElement] $forceIncludes = Select-ProjectNodes $kVcxprojXpathForceIncludes
|
||||
if ($forceIncludes)
|
||||
{
|
||||
return $forceIncludes.InnerText -split ";"
|
||||
}
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
<#
|
||||
.DESCRIPTION
|
||||
Retrieve directory in which stdafx.h resides
|
||||
#>
|
||||
Function Get-ProjectStdafxDir( [Parameter(Mandatory = $true)] [string] $pchHeaderName
|
||||
, [Parameter(Mandatory = $false)] [string[]] $includeDirectories
|
||||
, [Parameter(Mandatory = $false)] [string[]] $additionalIncludeDirectories
|
||||
)
|
||||
{
|
||||
[string] $stdafxPath = ""
|
||||
|
||||
[string[]] $projectHeaders = Get-ProjectHeaders
|
||||
if ($projectHeaders.Count -gt 0)
|
||||
{
|
||||
# we need to use only backslashes so that we can match against file header paths
|
||||
$pchHeaderName = $pchHeaderName.Replace("/", "\")
|
||||
|
||||
$stdafxPath = $projectHeaders | Where-Object { (Get-FileName -path $_) -eq $pchHeaderName }
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrEmpty($stdafxPath))
|
||||
{
|
||||
[string[]] $searchPool = @($ProjectDir);
|
||||
if ($includeDirectories.Count -gt 0)
|
||||
{
|
||||
$searchPool += $includeDirectories
|
||||
}
|
||||
if ($additionalIncludeDirectories.Count -gt 0)
|
||||
{
|
||||
$searchPool += $additionalIncludeDirectories
|
||||
}
|
||||
|
||||
foreach ($dir in $searchPool)
|
||||
{
|
||||
[string] $stdafxPath = Canonize-Path -base $dir -child $pchHeaderName -ignoreErrors
|
||||
if (![string]::IsNullOrEmpty($stdafxPath))
|
||||
{
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrEmpty($stdafxPath))
|
||||
{
|
||||
return ""
|
||||
}
|
||||
else
|
||||
{
|
||||
[string] $stdafxDir = Get-FileDirectory($stdafxPath)
|
||||
return $stdafxDir
|
||||
}
|
||||
}
|
||||
|
||||
Function Get-PchCppIncludeHeader([Parameter(Mandatory = $true)][string] $pchCppFile)
|
||||
{
|
||||
[string] $cppPath = Canonize-Path -base $ProjectDir -child $pchCppFile
|
||||
|
||||
[string[]] $fileLines = Get-Content -path $cppPath
|
||||
foreach ($line in $fileLines)
|
||||
{
|
||||
$regexMatch = [regex]::match($line, '^\s*#include\s+"(\S+)"')
|
||||
if ($regexMatch.Success)
|
||||
{
|
||||
return $regexMatch.Groups[1].Value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
19
scripts/psClang/msbuild-project-data.tests.ps1
Normal file
19
scripts/psClang/msbuild-project-data.tests.ps1
Normal file
@ -0,0 +1,19 @@
|
||||
#Clear-Host
|
||||
|
||||
# IMPORT code blocks
|
||||
|
||||
Set-Variable -name "kScriptLocation" `
|
||||
-value (Split-Path -Path $MyInvocation.MyCommand.Definition -Parent) <#`
|
||||
-option Constant#>
|
||||
|
||||
@(
|
||||
, "$kScriptLocation\io.ps1"
|
||||
, "$kScriptLocation\msbuild-expression-eval.ps1"
|
||||
, "$kScriptLocation\msbuild-project-load.ps1"
|
||||
, "$kScriptLocation\msbuild-project-data.ps1"
|
||||
) | ForEach-Object { . $_ }
|
||||
|
||||
Describe "VC++ Project Data Processing" {
|
||||
It "To be implemented" {
|
||||
}
|
||||
}
|
623
scripts/psClang/msbuild-project-load.ps1
Normal file
623
scripts/psClang/msbuild-project-load.ps1
Normal file
@ -0,0 +1,623 @@
|
||||
#-------------------------------------------------------------------------------------------------
|
||||
# Global variables
|
||||
|
||||
# vcxproj and property sheet files declare MsBuild properties (e.g. $(MYPROP)).
|
||||
# they are used in project xml nodes expressions. we have a
|
||||
# translation engine (MSBUILD-POWERSHELL) for these. it relies on
|
||||
# PowerShell to evaluate these expressions. We have to inject project
|
||||
# properties in the PowerShell runtime context. We keep track of them in
|
||||
# this list, so that each project can know to clean previous vars before loading begins.
|
||||
if (! (Test-Path variable:global:ProjectSpecificVariables))
|
||||
{
|
||||
[System.Collections.ArrayList] $global:ProjectSpecificVariables = @()
|
||||
}
|
||||
|
||||
if (! (Test-Path variable:global:ScriptParameterBackupValues))
|
||||
{
|
||||
[System.Collections.Hashtable] $global:ScriptParameterBackupValues = @{}
|
||||
}
|
||||
|
||||
# current vcxproj and property sheets
|
||||
[xml[]] $global:projectFiles = @();
|
||||
|
||||
# path of current project
|
||||
[string] $global:vcxprojPath = "";
|
||||
|
||||
# namespace of current project vcxproj XML
|
||||
[System.Xml.XmlNamespaceManager] $global:xpathNS = $null;
|
||||
|
||||
|
||||
Set-Variable -name "kRedundantSeparatorsReplaceRules" -option Constant `
|
||||
-value @( <# handle multiple consecutive separators #> `
|
||||
(";+" , ";") `
|
||||
<# handle separator at end #> `
|
||||
, (";$" , "") `
|
||||
<# handle separator at beginning #> `
|
||||
, ("^;" , "") `
|
||||
)
|
||||
|
||||
Function Set-Var([parameter(Mandatory = $false)][string] $name
|
||||
,[parameter(Mandatory = $false)] $value
|
||||
,[parameter(Mandatory = $false)][switch] $asScriptParameter
|
||||
)
|
||||
{
|
||||
if ($asScriptParameter)
|
||||
{
|
||||
if (Test-Path "variable:$name")
|
||||
{
|
||||
$oldVar = Get-Variable $name
|
||||
$oldValue = $oldVar.Value
|
||||
|
||||
if ($oldValue -and
|
||||
$oldValue.GetType() -and
|
||||
$oldValue.GetType().ToString() -eq "System.Management.Automation.SwitchParameter")
|
||||
{
|
||||
$oldValue = $oldValue.ToBool()
|
||||
}
|
||||
|
||||
$global:ScriptParameterBackupValues[$name] = $oldValue
|
||||
}
|
||||
else
|
||||
{
|
||||
$global:ScriptParameterBackupValues[$name] = $null
|
||||
}
|
||||
}
|
||||
|
||||
Write-Verbose "SET_VAR $($name): $value"
|
||||
if ($asScriptParameter)
|
||||
{
|
||||
Set-Variable -name $name -Value $value -Scope Script
|
||||
}
|
||||
else
|
||||
{
|
||||
Set-Variable -name $name -Value $value -Scope Global
|
||||
}
|
||||
|
||||
if (!$asScriptParameter -and !$global:ProjectSpecificVariables.Contains($name))
|
||||
{
|
||||
$global:ProjectSpecificVariables.Add($name) | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
Function Clear-Vars()
|
||||
{
|
||||
Write-Verbose-Array -array $global:ProjectSpecificVariables `
|
||||
-name "Deleting variables initialized by previous project"
|
||||
|
||||
foreach ($var in $global:ProjectSpecificVariables)
|
||||
{
|
||||
Remove-Variable -name $var -scope Global -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
foreach ($varName in $global:ScriptParameterBackupValues.Keys)
|
||||
{
|
||||
Write-Verbose "Restoring $varName to old value $($ScriptParameterBackupValues[$varName])"
|
||||
Set-Variable -name $varName -value $ScriptParameterBackupValues[$varName]
|
||||
}
|
||||
|
||||
$global:ScriptParameterBackupValues.Clear()
|
||||
|
||||
$global:ProjectSpecificVariables.Clear()
|
||||
}
|
||||
|
||||
Function UpdateScriptParameter([Parameter(Mandatory = $true)] [string] $paramName
|
||||
,[Parameter(Mandatory = $false)][string] $paramValue)
|
||||
{
|
||||
[bool] $isSwitch = $false
|
||||
$evalParamValue = "" # no type specified because we don't know it yet
|
||||
|
||||
if ($paramValue) # a parameter
|
||||
{
|
||||
$evalParamValue = Invoke-Expression $paramValue # evaluate expression to get actual value
|
||||
}
|
||||
else # a switch
|
||||
{
|
||||
$isSwitch = $true
|
||||
}
|
||||
|
||||
# the parameter name we detected may be an alias => translate it into the real name
|
||||
[string] $realParamName = Get-CommandParameterName -command "$PSScriptRoot\..\clang-build.ps1" `
|
||||
-nameOrAlias $paramName
|
||||
if (!$realParamName)
|
||||
{
|
||||
Write-Output "OVERVIEW: Clang Power Tools: compiles or tidies up code from Visual Studio .vcxproj project files`n"
|
||||
|
||||
Write-Output "USAGE: clang-build.ps1 [options]`n"
|
||||
|
||||
Write-Output "OPTIONS: "
|
||||
Print-CommandParameters "$PSScriptRoot\..\clang-build.ps1"
|
||||
|
||||
Fail-Script "Unsupported option '$paramName'. Check cpt.config."
|
||||
}
|
||||
|
||||
if ($isSwitch)
|
||||
{
|
||||
Set-Var -name $realParamName -value $true -asScriptParameter
|
||||
}
|
||||
else
|
||||
{
|
||||
Set-Var -name $realParamName -value $evalParamValue -asScriptParameter
|
||||
}
|
||||
}
|
||||
|
||||
Function Get-ConfigFileParameters()
|
||||
{
|
||||
[System.Collections.Hashtable] $retArgs = @{}
|
||||
|
||||
[string] $startDir = If ([string]::IsNullOrWhiteSpace($ProjectDir)) { $aSolutionsPath } else { $ProjectDir }
|
||||
[string] $configFile = (GetDirNameOfFileAbove -startDir $startDir -targetFile "cpt.config") + "\cpt.config"
|
||||
if (!(Test-Path $configFile))
|
||||
{
|
||||
return $retArgs
|
||||
}
|
||||
Write-Verbose "Found cpt.config in $configFile"
|
||||
|
||||
[xml] $configXml = Get-Content $configFile
|
||||
$configXpathNS= New-Object System.Xml.XmlNamespaceManager($configXml.NameTable)
|
||||
$configXpathNS.AddNamespace("ns", $configXml.DocumentElement.NamespaceURI)
|
||||
|
||||
[System.Xml.XmlElement[]] $argElems = $configXml.SelectNodes("/ns:cpt-config/*", $configXpathNS)
|
||||
|
||||
foreach ($argEl in $argElems)
|
||||
{
|
||||
if ($argEl.Name.StartsWith("vsx-"))
|
||||
{
|
||||
continue # settings for the Visual Studio Extension
|
||||
}
|
||||
|
||||
if ($argEl.HasAttribute("Condition"))
|
||||
{
|
||||
[bool] $isApplicable = Evaluate-MSBuildCondition -condition $argEl.GetAttribute("Condition")
|
||||
if (!$isApplicable)
|
||||
{
|
||||
continue
|
||||
}
|
||||
}
|
||||
$retArgs[$argEl.Name] = $argEl.InnerText
|
||||
}
|
||||
|
||||
return $retArgs
|
||||
}
|
||||
|
||||
Function Update-ParametersFromConfigFile()
|
||||
{
|
||||
[System.Collections.Hashtable] $configParams = Get-ConfigFileParameters
|
||||
if (!$configParams)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
foreach ($paramName in $configParams.Keys)
|
||||
{
|
||||
UpdateScriptParameter -paramName $paramName -paramValue $configParams[$paramName]
|
||||
}
|
||||
}
|
||||
|
||||
Function InitializeMsBuildProjectProperties()
|
||||
{
|
||||
Write-Verbose "Importing environment variables into current scope"
|
||||
foreach ($var in (Get-ChildItem Env:))
|
||||
{
|
||||
Set-Var -name $var.Name -value $var.Value
|
||||
}
|
||||
|
||||
Set-Var -name "MSBuildProjectFullPath" -value $global:vcxprojPath
|
||||
Set-Var -name "ProjectDir" -value (Get-FileDirectory -filePath $global:vcxprojPath)
|
||||
Set-Var -name "MSBuildProjectExtension" -value ([IO.Path]::GetExtension($global:vcxprojPath))
|
||||
Set-Var -name "MSBuildProjectFile" -value (Get-FileName -path $global:vcxprojPath)
|
||||
Set-Var -name "MSBuildProjectName" -value (Get-FileName -path $global:vcxprojPath -noext)
|
||||
Set-Var -name "MSBuildProjectDirectory" -value (Get-FileDirectory -filePath $global:vcxprojPath)
|
||||
Set-Var -name "MSBuildProgramFiles32" -value "${Env:ProgramFiles(x86)}"
|
||||
# defaults for projectname and targetname, may be overriden by project settings
|
||||
Set-Var -name "ProjectName" -value $MSBuildProjectName
|
||||
Set-Var -name "TargetName" -value $MSBuildProjectName
|
||||
|
||||
# These would enable full project platform references parsing, experimental right now
|
||||
if ($env:CPT_LOAD_ALL -eq '1')
|
||||
{
|
||||
Set-Var -name "ConfigurationType" -value "Application"
|
||||
Set-Var -name "VCTargetsPath" -value "$(Get-VisualStudio-Path)\Common7\IDE\VC\VCTargets\"
|
||||
Set-Var -name "VsInstallRoot" -value (Get-VisualStudio-Path)
|
||||
Set-Var -name "MSBuildExtensionsPath" -value "$(Get-VisualStudio-Path)\MSBuild"
|
||||
Set-Var -name "LocalAppData" -value $env:LOCALAPPDATA
|
||||
Set-Var -name "UserRootDir" -value "$LocalAppData\Microsoft\MSBuild\v4.0"
|
||||
Set-Var -name "UniversalCRT_IncludePath" -value "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\10.0.10240.0\ucrt"
|
||||
}
|
||||
|
||||
[string] $vsVer = "15.0"
|
||||
if ($global:cptVisualStudioVersion -eq "2015")
|
||||
{
|
||||
$vsVer = "14.0"
|
||||
}
|
||||
Set-Var -name "VisualStudioVersion" -value $vsVer
|
||||
Set-Var -name "MSBuildToolsVersion" -value $vsVer
|
||||
|
||||
[string] $projectSlnPath = Get-ProjectSolution
|
||||
[string] $projectSlnDir = Get-FileDirectory -filePath $projectSlnPath
|
||||
Set-Var -name "SolutionDir" -value $projectSlnDir
|
||||
[string] $projectSlnName = Get-FileName -path $projectSlnPath -noext
|
||||
Set-Var -name "SolutionName" -value $projectSlnName
|
||||
|
||||
Update-ParametersFromConfigFile
|
||||
}
|
||||
|
||||
Function InitializeMsBuildCurrentFileProperties([Parameter(Mandatory = $true)][string] $filePath)
|
||||
{
|
||||
Set-Var -name "MSBuildThisFileFullPath" -value $filePath
|
||||
Set-Var -name "MSBuildThisFileExtension" -value ([IO.Path]::GetExtension($filePath))
|
||||
Set-Var -name "MSBuildThisFile" -value (Get-FileName -path $filePath)
|
||||
Set-Var -name "MSBuildThisFileName" -value (Get-FileName -path $filePath -noext)
|
||||
Set-Var -name "MSBuildThisFileDirectory" -value (Get-FileDirectory -filePath $filePath)
|
||||
}
|
||||
|
||||
<#
|
||||
.DESCRIPTION
|
||||
A wrapper over the XmlDOcument.SelectNodes function. For convenience.
|
||||
Not to be used directly. Please use Select-ProjectNodes instead.
|
||||
#>
|
||||
function Help:Get-ProjectFileNodes([xml] $projectFile, [string] $xpath)
|
||||
{
|
||||
[System.Xml.XmlElement[]] $nodes = $projectFile.SelectNodes($xpath, $global:xpathNS)
|
||||
return $nodes
|
||||
}
|
||||
|
||||
function GetNodeInheritanceToken([System.Xml.XmlNode] $node)
|
||||
{
|
||||
[string] $inheritanceToken = "%($($node.Name))";
|
||||
if ($node.InnerText.Contains($inheritanceToken))
|
||||
{
|
||||
return $inheritanceToken
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
function ReplaceInheritedNodeValue([System.Xml.XmlNode] $currentNode
|
||||
, [System.Xml.XmlNode] $nodeToInheritFrom
|
||||
)
|
||||
{
|
||||
[string] $inheritanceToken = GetNodeInheritanceToken($currentNode)
|
||||
if ([string]::IsNullOrEmpty($inheritanceToken))
|
||||
{
|
||||
# no need to inherit
|
||||
return $false
|
||||
}
|
||||
|
||||
[string] $replaceWith = ""
|
||||
if ($nodeToInheritFrom)
|
||||
{
|
||||
$replaceWith = $nodeToInheritFrom.InnerText
|
||||
}
|
||||
|
||||
[string] $whatToReplace = [regex]::Escape($inheritanceToken);
|
||||
if ([string]::IsNullOrEmpty($replaceWith))
|
||||
{
|
||||
# handle semicolon separators
|
||||
[string] $escTok = [regex]::Escape($inheritanceToken)
|
||||
$whatToReplace = "(;$escTok)|($escTok;)|($escTok)"
|
||||
}
|
||||
|
||||
# replace inherited token and redundant separators
|
||||
$replacementRules = @(, ($whatToReplace, $replaceWith)) + $kRedundantSeparatorsReplaceRules
|
||||
foreach ($rule in $replacementRules)
|
||||
{
|
||||
$currentNode.InnerText = $currentNode.InnerText -replace $rule[0], $rule[1]
|
||||
}
|
||||
|
||||
return $currentNode.InnerText.Contains($inheritanceToken)
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Selects one or more nodes from the project.
|
||||
.DESCRIPTION
|
||||
We often need to access data from the project, e.g. additional includes, Win SDK version.
|
||||
A naive implementation would be to simply look inside the vcxproj, but that leaves out
|
||||
property sheets.
|
||||
|
||||
This function takes care to retrieve the nodes we're searching by looking in both the .vcxproj
|
||||
and property sheets, taking care to inherit values accordingly.
|
||||
.EXAMPLE
|
||||
Give an example of how to use it
|
||||
.EXAMPLE
|
||||
Give another example of how to use it.
|
||||
.PARAMETER xpath
|
||||
XPath we want to use for searching nodes.
|
||||
.PARAMETER fileIndex
|
||||
Optional. Index of the project xml file we want to start our search in.
|
||||
0 = .vcxproj and then, recursively, all property sheets
|
||||
1 = first property sheet and then, recursively, all other property sheets
|
||||
etc.
|
||||
#>
|
||||
function Select-ProjectNodes([Parameter(Mandatory = $true)] [string][string] $xpath
|
||||
, [Parameter(Mandatory = $false)] [int] $fileIndex = 0)
|
||||
{
|
||||
[System.Xml.XmlElement[]] $nodes = @()
|
||||
|
||||
if ($fileIndex -ge $global:projectFiles.Count)
|
||||
{
|
||||
return $nodes
|
||||
}
|
||||
|
||||
$nodes = Help:Get-ProjectFileNodes -projectFile $global:projectFiles[$fileIndex] `
|
||||
-xpath $xpath
|
||||
|
||||
# nothing on this level or we're dealing with an ItemGroup, go above
|
||||
if ($nodes.Count -eq 0 -or $xpath.Contains("ItemGroup"))
|
||||
{
|
||||
[System.Xml.XmlElement[]] $upperNodes = Select-ProjectNodes -xpath $xpath -fileIndex ($fileIndex + 1)
|
||||
if ($upperNodes.Count -gt 0)
|
||||
{
|
||||
$nodes += $upperNodes
|
||||
}
|
||||
return $nodes
|
||||
}
|
||||
|
||||
if ($nodes[$nodes.Count - 1]."#text")
|
||||
{
|
||||
# we found textual settings that can be inherited. see if we should inherit
|
||||
|
||||
[System.Xml.XmlNode] $nodeToReturn = $nodes[$nodes.Count - 1]
|
||||
if ($nodeToReturn.Attributes.Count -gt 0)
|
||||
{
|
||||
throw "Did not expect node to have attributes"
|
||||
}
|
||||
|
||||
[bool] $shouldInheritMore = ![string]::IsNullOrEmpty((GetNodeInheritanceToken -node $nodeToReturn))
|
||||
for ([int] $i = $nodes.Count - 2; ($i -ge 0) -and $shouldInheritMore; $i -= 1)
|
||||
{
|
||||
$shouldInheritMore = ReplaceInheritedNodeValue -currentNode $nodeToReturn -nodeToInheritFrom $nodes[$i]
|
||||
}
|
||||
|
||||
if ($shouldInheritMore)
|
||||
{
|
||||
[System.Xml.XmlElement[]] $inheritedNodes = Select-ProjectNodes -xpath $xpath -fileIndex ($fileIndex + 1)
|
||||
if ($inheritedNodes.Count -gt 1)
|
||||
{
|
||||
throw "Did not expect to inherit more than one node"
|
||||
}
|
||||
if ($inheritedNodes.Count -eq 1)
|
||||
{
|
||||
$shouldInheritMore = ReplaceInheritedNodeValue -currentNode $nodeToReturn -nodeToInheritFrom $inheritedNodes[0]
|
||||
}
|
||||
}
|
||||
|
||||
# we still could have to inherit from parents but when not loading
|
||||
# all MS prop sheets we have nothing to inherit from, delete inheritance token
|
||||
ReplaceInheritedNodeValue -currentNode $nodeToReturn -nodeToInheritFrom $null | Out-Null
|
||||
|
||||
return @($nodeToReturn)
|
||||
}
|
||||
else
|
||||
{
|
||||
# return what we found
|
||||
return $nodes
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.DESCRIPTION
|
||||
Finds the first config-platform pair in the vcxproj.
|
||||
We'll use it for all project data retrievals.
|
||||
|
||||
Items for other config-platform pairs will be removed from the DOM.
|
||||
This is needed so that our XPath selectors don't get confused when looking for data.
|
||||
#>
|
||||
function Detect-ProjectDefaultConfigPlatform([string] $projectValue)
|
||||
{
|
||||
[string]$configPlatformName = ""
|
||||
|
||||
if (![string]::IsNullOrEmpty($aVcxprojConfigPlatform))
|
||||
{
|
||||
$configPlatformName = $aVcxprojConfigPlatform
|
||||
}
|
||||
else
|
||||
{
|
||||
$configPlatformName = $projectValue
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrEmpty($configPlatformName))
|
||||
{
|
||||
throw "Could not automatically detect a configuration platform"
|
||||
}
|
||||
|
||||
[string[]] $configAndPlatform = $configPlatformName.Split('|')
|
||||
Set-Var -Name "Configuration" -Value $configAndPlatform[0]
|
||||
Set-Var -Name "Platform" -Value $configAndPlatform[1]
|
||||
}
|
||||
|
||||
function HandleChooseNode([System.Xml.XmlNode] $aChooseNode)
|
||||
{
|
||||
SanitizeProjectNode $aChooseNode
|
||||
if ($aChooseNode.ChildNodes.Count -eq 0)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
[System.Xml.XmlElement] $selectedChild = $aChooseNode.ChildNodes | `
|
||||
Where-Object { $_.GetType().Name -eq "XmlElement" } | `
|
||||
Select -first 1
|
||||
|
||||
foreach ($selectedGrandchild in $selectedChild.ChildNodes)
|
||||
{
|
||||
$aChooseNode.ParentNode.AppendChild($selectedGrandchild.Clone()) | Out-Null
|
||||
}
|
||||
|
||||
$aChooseNode.ParentNode.RemoveChild($aChooseNode) | Out-Null
|
||||
}
|
||||
|
||||
function SanitizeProjectNode([System.Xml.XmlNode] $node)
|
||||
{
|
||||
if ($node.Name -ieq "#comment")
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
[System.Collections.ArrayList] $nodesToRemove = @()
|
||||
|
||||
if ($node.Name -ieq "#text" -and $node.InnerText.Length -gt 0)
|
||||
{
|
||||
# evaluate node content
|
||||
$node.InnerText = Evaluate-MSBuildExpression $node.InnerText
|
||||
}
|
||||
|
||||
if ($node.Name -ieq "Import")
|
||||
{
|
||||
[string] $relPath = Evaluate-MSBuildExpression $node.GetAttribute("Project")
|
||||
[string[]] $paths = Canonize-Path -base (Get-Location) -child $relPath -ignoreErrors
|
||||
|
||||
foreach ($path in $paths)
|
||||
{
|
||||
if (![string]::IsNullOrEmpty($path) -and (Test-Path $path))
|
||||
{
|
||||
Write-Verbose "Property sheet: $path"
|
||||
[string] $currentFile = $global:currentMSBuildFile
|
||||
SanitizeProjectFile($path)
|
||||
|
||||
$global:currentMSBuildFile = $currentFile
|
||||
InitializeMsBuildCurrentFileProperties -filePath $global:currentMSBuildFile
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose "Could not find property sheet $relPath"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ($node.Name -ieq "ClCompile" -or $node.Name -ieq "ClInclude") -and
|
||||
![string]::IsNullOrEmpty($node.GetAttribute("Include")) )
|
||||
{
|
||||
[string] $expandedAttr = Evaluate-MSBuildExpression $node.GetAttribute("Include")
|
||||
$node.Attributes["Include"].Value = $expandedAttr
|
||||
}
|
||||
|
||||
if ($node.Name -ieq "Choose")
|
||||
{
|
||||
HandleChooseNode $chooseChild
|
||||
}
|
||||
|
||||
if ($node.Name -ieq "Otherwise")
|
||||
{
|
||||
[System.Xml.XmlElement[]] $siblings = $node.ParentNode.ChildNodes | `
|
||||
Where-Object { $_.GetType().Name -ieq "XmlElement" -and $_ -ne $node }
|
||||
if ($siblings.Count -gt 0)
|
||||
{
|
||||
# means there's a <When> element that matched
|
||||
# <Otherwise> should not be evaluated, we could set unwated properties
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if ($node.Name -ieq "ItemGroup" -and $node.GetAttribute("Label") -ieq "ProjectConfigurations")
|
||||
{
|
||||
[System.Xml.XmlElement] $firstChild = $node.ChildNodes | `
|
||||
Where-Object { $_.GetType().Name -ieq "XmlElement" } | `
|
||||
Select-Object -First 1
|
||||
Detect-ProjectDefaultConfigPlatform $firstChild.GetAttribute("Include")
|
||||
}
|
||||
|
||||
if ($node.ParentNode.Name -ieq "PropertyGroup")
|
||||
{
|
||||
# set new property value
|
||||
[string] $propertyName = $node.Name
|
||||
[string] $propertyValue = Evaluate-MSBuildExpression $node.InnerText
|
||||
|
||||
Set-Var -Name $propertyName -Value $propertyValue
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
foreach ($child in $node.ChildNodes)
|
||||
{
|
||||
[bool] $validChild = $true
|
||||
if ($child.GetType().Name -ieq "XmlElement")
|
||||
{
|
||||
if ($child.HasAttribute("Condition"))
|
||||
{
|
||||
# process node condition
|
||||
[string] $nodeCondition = $child.GetAttribute("Condition")
|
||||
$validChild = ((Evaluate-MSBuildCondition($nodeCondition)) -eq $true)
|
||||
if ($validChild)
|
||||
{
|
||||
$child.RemoveAttribute("Condition")
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$validChild)
|
||||
{
|
||||
$nodesToRemove.Add($child) | out-null
|
||||
continue
|
||||
}
|
||||
else
|
||||
{
|
||||
SanitizeProjectNode($child)
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($nodeToRemove in $nodesToRemove)
|
||||
{
|
||||
$nodeToRemove.ParentNode.RemoveChild($nodeToRemove) | out-null
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.DESCRIPTION
|
||||
Sanitizes a project xml file, by removing config-platform pairs different from the
|
||||
one we selected.
|
||||
This is needed so that our XPath selectors don't get confused when looking for data.
|
||||
#>
|
||||
function SanitizeProjectFile([string] $projectFilePath)
|
||||
{
|
||||
Write-Verbose "`nSanitizing $projectFilePath"
|
||||
|
||||
[xml] $fileXml = Get-Content $projectFilePath
|
||||
$global:projectFiles += @($fileXml)
|
||||
$global:xpathNS = New-Object System.Xml.XmlNamespaceManager($fileXml.NameTable)
|
||||
$global:xpathNS.AddNamespace("ns", $fileXml.DocumentElement.NamespaceURI)
|
||||
$global:currentMSBuildFile = $projectFilePath
|
||||
|
||||
Push-Location (Get-FileDirectory -filePath $projectFilePath)
|
||||
|
||||
InitializeMsBuildCurrentFileProperties -filePath $projectFilePath
|
||||
SanitizeProjectNode($fileXml.Project)
|
||||
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
<#
|
||||
.DESCRIPTION
|
||||
Loads vcxproj and property sheets into memory. This needs to be called only once
|
||||
when processing a project. Accessing project nodes can be done using Select-ProjectNodes.
|
||||
#>
|
||||
function LoadProject([string] $vcxprojPath)
|
||||
{
|
||||
# Clean global variables that have been set by a previous project load
|
||||
Clear-Vars
|
||||
|
||||
$global:vcxprojPath = $vcxprojPath
|
||||
|
||||
InitializeMsBuildProjectProperties
|
||||
|
||||
$global:projectFiles = @()
|
||||
|
||||
SanitizeProjectFile -projectFilePath $global:vcxprojPath
|
||||
|
||||
if ($env:CPT_LOAD_ALL -ne "1")
|
||||
{
|
||||
# Tries to find a Directory.Build.props property sheet, starting from the
|
||||
# project directory, going up. When one is found, the search stops.
|
||||
# Multiple Directory.Build.props sheets are not supported.
|
||||
[string] $directoryBuildSheetPath = (GetDirNameOfFileAbove -startDir $ProjectDir `
|
||||
-targetFile "Directory.Build.props") + "\Directory.Build.props"
|
||||
if (Test-Path $directoryBuildSheetPath)
|
||||
{
|
||||
SanitizeProjectFile($directoryBuildSheetPath)
|
||||
}
|
||||
|
||||
[string] $vcpkgIncludePath = "$env:LOCALAPPDATA\vcpkg\vcpkg.user.targets"
|
||||
if (Test-Path $vcpkgIncludePath)
|
||||
{
|
||||
SanitizeProjectFile($vcpkgIncludePath)
|
||||
}
|
||||
}
|
||||
}
|
18
scripts/psClang/msbuild-project-load.tests.ps1
Normal file
18
scripts/psClang/msbuild-project-load.tests.ps1
Normal file
@ -0,0 +1,18 @@
|
||||
#Clear-Host
|
||||
|
||||
# IMPORT code blocks
|
||||
|
||||
Set-Variable -name "kScriptLocation" `
|
||||
-value (Split-Path -Path $MyInvocation.MyCommand.Definition -Parent) <#`
|
||||
-option Constant#>
|
||||
|
||||
@(
|
||||
, "$kScriptLocation\io.ps1"
|
||||
, "$kScriptLocation\msbuild-expression-eval.ps1"
|
||||
, "$kScriptLocation\msbuild-project-load.ps1"
|
||||
) | ForEach-Object { . $_ }
|
||||
|
||||
Describe "VC++ Project Data Loading" {
|
||||
It "To be implemented" {
|
||||
}
|
||||
}
|
102
scripts/psClang/visualstudio-detection.ps1
Normal file
102
scripts/psClang/visualstudio-detection.ps1
Normal file
@ -0,0 +1,102 @@
|
||||
# ------------------------------------------------------------------------------------------------
|
||||
# Helpers for locating Visual Studio on the computer
|
||||
|
||||
# VsWhere is available starting with Visual Studio 2017 version 15.2.
|
||||
Set-Variable -name kVsWhereLocation `
|
||||
-value "${Env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" #`
|
||||
#-option Constant
|
||||
|
||||
# Default installation path of Visual Studio 2017. We'll use when VsWhere isn't available.
|
||||
Set-Variable -name kVs15DefaultLocation `
|
||||
-value "${Env:ProgramFiles(x86)}\Microsoft Visual Studio\$global:cptVisualStudioVersion\$aVisualStudioSku" #`
|
||||
#-option Constant
|
||||
|
||||
# Registry key containing information about Visual Studio 2015 installation path.
|
||||
Set-Variable -name kVs2015RegistryKey `
|
||||
-value "HKLM:SOFTWARE\Wow6432Node\Microsoft\VisualStudio\14.0" #`
|
||||
#-option Constant
|
||||
|
||||
# Default location for v140 toolset when installed as a feature of a VS 2017 installation
|
||||
Set-Variable -name kVs2017Toolset140DiskLocation `
|
||||
-value "${Env:ProgramFiles(x86)}\Microsoft Visual Studio 14.0" #`
|
||||
#-option Constant
|
||||
|
||||
Function Get-MscVer()
|
||||
{
|
||||
return ((Get-Item "$(Get-VisualStudio-Path)\VC\Tools\MSVC\" | Get-ChildItem) | select -last 1).Name
|
||||
}
|
||||
|
||||
Function Get-VisualStudio-Includes([Parameter(Mandatory = $true)][string] $vsPath,
|
||||
[Parameter(Mandatory = $false)][string] $mscVer)
|
||||
{
|
||||
[string] $mscVerToken = ""
|
||||
If (![string]::IsNullOrEmpty($mscVer))
|
||||
{
|
||||
$mscVerToken = "Tools\MSVC\$mscVer\"
|
||||
}
|
||||
|
||||
return @( "$vsPath\VC\$($mscVerToken)include"
|
||||
, "$vsPath\VC\$($mscVerToken)atlmfc\include"
|
||||
)
|
||||
}
|
||||
|
||||
Function Get-VisualStudio-Path()
|
||||
{
|
||||
if ($global:cptVisualStudioVersion -eq "2015")
|
||||
{
|
||||
# try to detect full installation
|
||||
[string] $installLocation = (Get-Item $kVs2015RegistryKey).GetValue("InstallDir")
|
||||
if ($installLocation)
|
||||
{
|
||||
$installLocation = Canonize-Path -base $installLocation -child "..\.." -ignoreErrors
|
||||
}
|
||||
if ($installLocation)
|
||||
{
|
||||
return $installLocation
|
||||
}
|
||||
|
||||
# we may have a VS 2017 installation with v140 toolset feature
|
||||
[string] $iostreamLocation = Canonize-Path -base $kVs2017Toolset140DiskLocation `
|
||||
-child "VC\include\iostream" -ignoreErrors
|
||||
if ($iostreamLocation)
|
||||
{
|
||||
return $kVs2017Toolset140DiskLocation
|
||||
}
|
||||
|
||||
Write-Err "Visual Studio 2015 installation location could not be detected"
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Test-Path $kVsWhereLocation)
|
||||
{
|
||||
|
||||
[string] $product = "*"
|
||||
if (![string]::IsNullOrEmpty($aVisualStudioSku))
|
||||
{
|
||||
$product = "Microsoft.VisualStudio.Product.$aVisualStudioSku"
|
||||
}
|
||||
|
||||
[string[]] $output = (& "$kVsWhereLocation" -nologo `
|
||||
-property installationPath `
|
||||
-products $product `
|
||||
-prerelease)
|
||||
|
||||
# the -prerelease switch is not available on older VS2017 versions
|
||||
if (($output -join "").Contains("0x57")) <# error code for unknown parameter #>
|
||||
{
|
||||
$output = (& "$kVsWhereLocation" -nologo `
|
||||
-property installationPath `
|
||||
-products $product)
|
||||
}
|
||||
|
||||
return $output[0]
|
||||
}
|
||||
|
||||
if (Test-Path -Path $kVs15DefaultLocation)
|
||||
{
|
||||
return $kVs15DefaultLocation
|
||||
}
|
||||
|
||||
throw "Cannot locate Visual Studio location"
|
||||
}
|
||||
}
|
73
scripts/psClang/visualstudio-detection.tests.ps1
Normal file
73
scripts/psClang/visualstudio-detection.tests.ps1
Normal file
@ -0,0 +1,73 @@
|
||||
#Clear-Host
|
||||
|
||||
# IMPORT code blocks
|
||||
|
||||
Set-Variable -name "kScriptLocation" `
|
||||
-value (Split-Path -Path $MyInvocation.MyCommand.Definition -Parent) <#`
|
||||
-option Constant#>
|
||||
|
||||
@(
|
||||
, "$kScriptLocation\io.ps1"
|
||||
, "$kScriptLocation\visualstudio-detection.ps1"
|
||||
) | ForEach-Object { . $_ }
|
||||
|
||||
Describe "Visual Studio detection" {
|
||||
# Mock script parameters
|
||||
$global:cptVisualStudioVersion = "2017"
|
||||
$aVisualStudioSku = "Professional"
|
||||
|
||||
It "Get-MscVer" {
|
||||
[string[]] $mscVer = Get-MscVer
|
||||
$mscVer.Count | Should -BeExactly 1
|
||||
$mscVer[0] | Should -Not -BeNullOrEmpty
|
||||
$mscVer[0].Length | Should -BeGreaterThan 3
|
||||
$mscVer[0].Contains(".") | Should -BeExactly $true
|
||||
}
|
||||
|
||||
It "Get-VisualStudio-Path" {
|
||||
$vsPath = Get-VisualStudio-Path
|
||||
$vsPath | Should -Not -BeNullOrEmpty
|
||||
}
|
||||
|
||||
It "Get-VisualStudio-Path [2015]" {
|
||||
# see first if VS 2015 is installed
|
||||
[Microsoft.Win32.RegistryKey] $vs14Key = Get-Item "HKLM:SOFTWARE\Wow6432Node\Microsoft\VisualStudio\14.0"
|
||||
[bool] $vs2015isInstalled = $vs14Key -and ![string]::IsNullOrEmpty($vs14Key.GetValue("InstallDir"))
|
||||
|
||||
$oldMockValue = $global:cptVisualStudioVersion
|
||||
|
||||
$vsPath = Get-VisualStudio-Path
|
||||
$vsPath | Should -Not -BeNullOrEmpty
|
||||
|
||||
# Re-Mock script parameter
|
||||
$global:cptVisualStudioVersion = "2015"
|
||||
|
||||
# Maybe we have a VS 2017 installation with v140 toolset installed
|
||||
[string] $vs2017ToolsetV140Path = "${Env:ProgramFiles(x86)}\Microsoft Visual Studio 14.0"
|
||||
if (Test-Path "$vs2017ToolsetV140Path\VC\include\iostream")
|
||||
{
|
||||
$vs2015isInstalled = $true
|
||||
}
|
||||
|
||||
if ($vs2015isInstalled)
|
||||
{
|
||||
$vs2015Path = Get-VisualStudio-Path
|
||||
$vs2015Path | Should -Not -BeNullOrEmpty
|
||||
$vs2015Path | Should -Not -Be $vsPath
|
||||
}
|
||||
else
|
||||
{
|
||||
{ Get-VisualStudio-Path } | Should -Throw
|
||||
}
|
||||
|
||||
$global:cptVisualStudioVersion = $oldMockValue
|
||||
}
|
||||
|
||||
It "Get-VisualStudio-Includes" {
|
||||
[string] $vsPath = Get-VisualStudio-Path
|
||||
[string] $mscver = Get-MscVer
|
||||
[string[]] $includes = Get-VisualStudio-Includes -vsPath $vsPath -mscVer $mscver
|
||||
$includes.Count | Should -BeGreaterThan 1
|
||||
$includes | ForEach-Object { [System.IO.Directory]::Exists($_) | Should -BeExactly $true }
|
||||
}
|
||||
}
|
20
scripts/psClang/~advinst.tests.ps1
Normal file
20
scripts/psClang/~advinst.tests.ps1
Normal file
@ -0,0 +1,20 @@
|
||||
. "$PsScriptRoot\io.ps1"
|
||||
Describe "ai" {
|
||||
It "Should build Advanced Installer" {
|
||||
|
||||
[string] $advinstRepo = $env:ADVINST
|
||||
|
||||
if ($advinstRepo)
|
||||
{
|
||||
Push-Location $advinstRepo
|
||||
|
||||
[string] $scriptLocation = Canonize-Path -base "$PSScriptRoot" -child "..\clang-build.ps1"
|
||||
&"$scriptLocation" 2>&1 | Out-Default
|
||||
[int] $exitCode = $LASTEXITCODE
|
||||
Pop-Location
|
||||
|
||||
Write-Output "$PSScriptRoot"
|
||||
$exitCode | Should -BeExactly 0
|
||||
}
|
||||
}
|
||||
}
|
@ -1,225 +0,0 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Compiles or tidies up code from Visual Studio .vcxproj project files.
|
||||
It sets up the scene required for clang-build.ps1 to do its job, and makes
|
||||
command-line usage for projects and files quicker.
|
||||
|
||||
Before calling sample-clang-build.ps1 you need to set the current directory
|
||||
to the root source directory.
|
||||
|
||||
.PARAMETER aVcxprojToCompile
|
||||
Alias 'proj'. Array of project(s) to compile. If empty, all projects are compiled.
|
||||
If the -literal switch is present, name is matched exactly. Otherwise, regex matching is used,
|
||||
e.g. "msicomp" compiles all msicomp projects.
|
||||
|
||||
Can be passed as comma separated values.
|
||||
|
||||
.PARAMETER aVcxprojToIgnore
|
||||
Alias 'proj-ignore'. Array of project(s) to ignore, from the matched ones.
|
||||
If empty, all already matched projects are compiled.
|
||||
If the -literal switch is present, name is matched exactly. Otherwise, regex matching is used,
|
||||
e.g. "msicomp" compiles all msicomp projects.
|
||||
|
||||
Can be passed as comma separated values.
|
||||
|
||||
.PARAMETER aVcxprojConfigPlatform
|
||||
Alias 'active-config'. The configuration-platform pair, separated by |,
|
||||
to be used when processing project files.
|
||||
|
||||
E.g. 'Debug|Win32'.
|
||||
If not specified, the first configuration-plaform found in the current project is used.
|
||||
|
||||
.PARAMETER aCppToCompile
|
||||
Alias 'file'. What cpp(s) to compile from the found project(s). If empty, all CPPs are compiled.
|
||||
If the -literal switch is present, name is matched exactly. Otherwise, regex matching is used,
|
||||
e.g. "table" compiles all CPPs containing 'table'.
|
||||
|
||||
.PARAMETER aCppToIgnore
|
||||
Alias 'file-ignore'. Array of file(s) to ignore, from the matched ones.
|
||||
If empty, all already matched files are compiled.
|
||||
If the -literal switch is present, name is matched exactly. Otherwise, regex matching is used,
|
||||
e.g. "table" ignores all CPPs containing 'table'.
|
||||
|
||||
Can be passed as comma separated values.
|
||||
|
||||
.PARAMETER aUseParallelCompile
|
||||
Alias 'parallel'. Switch to run in parallel mode, on all logical CPU cores.
|
||||
|
||||
.PARAMETER aContinueOnError
|
||||
Alias 'continue'. Switch to continue project compilation even when errors occur.
|
||||
|
||||
.PARAMETER aTreatAdditionalIncludesAsSystemIncludes
|
||||
Alias 'treat-sai'. Switch to treat project additional include directories as system includes.
|
||||
|
||||
.PARAMETER aClangCompileFlags
|
||||
Alias 'clang-flags'. Flags given to clang++ when compiling project,
|
||||
alongside project-specific defines.
|
||||
|
||||
.PARAMETER aDisableNameRegexMatching
|
||||
Alias 'literal'. Switch to take project and cpp name filters literally, not by regex matching.
|
||||
|
||||
.PARAMETER aTidyFlags
|
||||
Alias 'tidy'. If not empty clang-tidy will be called with given flags, instead of clang++.
|
||||
The tidy operation is applied to whole translation units, meaning all directory headers
|
||||
included in the CPP will be tidied up too. Changes will not be applied, only simulated.
|
||||
|
||||
If aTidyFixFlags is present, it takes precedence over this parameter.
|
||||
|
||||
.PARAMETER aTidyFixFlags
|
||||
Alias 'tidy-fix'. If not empty clang-tidy will be called with given flags, instead of clang++.
|
||||
The tidy operation is applied to whole translation units, meaning all directory headers
|
||||
included in the CPP will be tidied up too. Changes will be applied to the file(s).
|
||||
|
||||
If present, this parameter takes precedence over aTidyFlags.
|
||||
|
||||
.PARAMETER aAfterTidyFixFormatStyle
|
||||
Alias 'format-style'. Used in combination with 'tidy-fix'. If present, clang-tidy will
|
||||
also format the fixed file(s), using the specified style.
|
||||
Possible values: - not present, no formatting will be done
|
||||
- 'file'
|
||||
Literally 'file', not a placeholder.
|
||||
Uses .clang-format file in the closest parent directory.
|
||||
- 'llvm'
|
||||
- 'google'
|
||||
- 'webkit'
|
||||
- 'mozilla'
|
||||
|
||||
.EXAMPLE
|
||||
PS .\sample-clang-build.ps1 -dir -proj foo,bar -file meow -tidy "-*,modernize-*"
|
||||
<Description of example>
|
||||
Runs clang-tidy, using "-*,modernize-*", on all CPPs containing 'meow' in their name from
|
||||
the projects containing 'foo' or 'bar' in their names.
|
||||
|
||||
Doesn't actually apply the clang-tidy module changes to CPPs.
|
||||
It will only print the tidy module output.
|
||||
|
||||
.EXAMPLE
|
||||
PS .\sample-clang-build.ps1 -dir -proj foo,bar -file meow -tidy-fix "-*,modernize-*"
|
||||
<Description of example>
|
||||
Runs clang-tidy, using "-*,modernize-*", on all CPPs containing 'meow' in their name from
|
||||
the projects containing 'foo' or 'bar' in their names.
|
||||
|
||||
It will apply all tidy module changes to CPPs.
|
||||
|
||||
.EXAMPLE
|
||||
PS .\sample-clang-build.ps1 -dir -proj foo -proj-ignore foobar
|
||||
<Description of example>
|
||||
Runs clang++ on all CPPs in foo... projects, except foobar
|
||||
|
||||
.OUTPUTS
|
||||
Will output Clang warnings and errors to screen. The return code will be 0 for success, >0 for failure.
|
||||
|
||||
.NOTES
|
||||
Author: Gabriel Diaconita
|
||||
#>
|
||||
param( [alias("proj")] [Parameter(Mandatory=$false)][string[]] $aVcxprojToCompile
|
||||
, [alias("proj-ignore")] [Parameter(Mandatory=$false)][string[]] $aVcxprojToIgnore
|
||||
, [alias("active-config")][Parameter(Mandatory=$false)][string] $aVcxprojConfigPlatform
|
||||
, [alias("file")] [Parameter(Mandatory=$false)][string] $aCppToCompile
|
||||
, [alias("file-ignore")] [Parameter(Mandatory=$false)][string[]] $aCppToIgnore
|
||||
, [alias("parallel")] [Parameter(Mandatory=$false)][switch] $aUseParallelCompile
|
||||
, [alias("continue")] [Parameter(Mandatory=$false)][switch] $aContinueOnError
|
||||
, [alias("treat-sai")] [Parameter(Mandatory=$false)][switch] $aTreatAdditionalIncludesAsSystemIncludes
|
||||
, [alias("literal")] [Parameter(Mandatory=$false)][switch] $aDisableNameRegexMatching
|
||||
, [alias("tidy")] [Parameter(Mandatory=$false)][string] $aTidyFlags
|
||||
, [alias("tidy-fix")] [Parameter(Mandatory=$false)][string] $aTidyFixFlags
|
||||
, [alias("format-style")] [Parameter(Mandatory=$false)][string] $aAfterTidyFixFormatStyle
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------------------------------------
|
||||
|
||||
Set-Variable -name kClangCompileFlags -Option Constant `
|
||||
-value @( "-Werror"
|
||||
, "-Wall"
|
||||
, "-fms-compatibility-version=19.10"
|
||||
, "-Wmicrosoft"
|
||||
, "-Wno-invalid-token-paste"
|
||||
, "-Wno-unknown-pragmas"
|
||||
, "-Wno-unused-value"
|
||||
)
|
||||
|
||||
Set-Variable -name kVisualStudioVersion -value "2017" -Option Constant
|
||||
Set-Variable -name kVisualStudioSku -value "Professional" -Option Constant
|
||||
|
||||
# ------------------------------------------------------------------------------------------------
|
||||
|
||||
Function Merge-Array([string[]] $aArray)
|
||||
{
|
||||
# we need to individually wrap items into quotes as values
|
||||
# can contain PS control characters (e.g. - in -std=c++14)
|
||||
$quotedArray = ($aArray | ForEach-Object { """$_"""})
|
||||
return ($quotedArray -join ",")
|
||||
}
|
||||
|
||||
[string] $scriptDirectory = (Split-Path -parent $PSCommandPath)
|
||||
|
||||
[string] $clangScript = "$scriptDirectory\clang-build.ps1"
|
||||
[string[]] $scriptParams = @("-aSolutionsPath", "'$(Get-Location)'")
|
||||
|
||||
if (![string]::IsNullOrEmpty($aVcxprojToCompile))
|
||||
{
|
||||
$scriptParams += ("-aVcxprojToCompile", (Merge-Array $aVcxprojToCompile))
|
||||
}
|
||||
|
||||
if (![string]::IsNullOrEmpty($aVcxprojToIgnore))
|
||||
{
|
||||
$scriptParams += ("-aVcxprojToIgnore", (Merge-Array $aVcxprojToIgnore))
|
||||
}
|
||||
|
||||
if (![string]::IsNullOrEmpty($aVcxprojConfigPlatform))
|
||||
{
|
||||
$scriptParams += ("-aVcxprojConfigPlatform", (Merge-Array $aVcxprojConfigPlatform))
|
||||
}
|
||||
|
||||
if (![string]::IsNullOrEmpty($aCppToCompile))
|
||||
{
|
||||
$scriptParams += ("-aCppToCompile", (Merge-Array $aCppToCompile))
|
||||
}
|
||||
|
||||
if (![string]::IsNullOrEmpty($aCppToIgnore))
|
||||
{
|
||||
$scriptParams += ("-aCppToIgnore", (Merge-Array $aCppToIgnore))
|
||||
}
|
||||
|
||||
$scriptParams += ("-aClangCompileFlags", (Merge-Array $kClangCompileFlags))
|
||||
|
||||
if (![string]::IsNullOrEmpty($aTidyFlags))
|
||||
{
|
||||
$scriptParams += ("-aTidyFlags", (Merge-Array (@($aTidyFlags))))
|
||||
}
|
||||
|
||||
if (![string]::IsNullOrEmpty($aTidyFixFlags))
|
||||
{
|
||||
$scriptParams += ("-aTidyFixFlags", (Merge-Array (@($aTidyFixFlags))))
|
||||
}
|
||||
|
||||
if (![string]::IsNullOrEmpty($aAfterTidyFixFormatStyle))
|
||||
{
|
||||
$scriptParams += ("-aAfterTidyFixFormatStyle", $aAfterTidyFixFormatStyle)
|
||||
}
|
||||
|
||||
if ($aUseParallelCompile)
|
||||
{
|
||||
$scriptParams += ("-aUseParallelCompile")
|
||||
}
|
||||
|
||||
if ($aContinueOnError)
|
||||
{
|
||||
$scriptParams += ("-aContinueOnError")
|
||||
}
|
||||
|
||||
if ($aTreatAdditionalIncludesAsSystemIncludes)
|
||||
{
|
||||
$scriptParams += ("-aTreatAdditionalIncludesAsSystemIncludes")
|
||||
}
|
||||
|
||||
if ($aDisableNameRegexMatching)
|
||||
{
|
||||
$scriptParams += ("-aDisableNameRegexMatching")
|
||||
}
|
||||
|
||||
$scriptParams += ("-aVisualStudioVersion", $kVisualStudioVersion)
|
||||
$scriptParams += ("-aVisualStudioSku", $kVisualStudioSku)
|
||||
$scriptParams += ("-aTidyHeaderFilter", ".*")
|
||||
|
||||
Invoke-Expression "&'$clangScript' $scriptParams"
|
Loading…
Reference in New Issue
Block a user