Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions PSCMake/Common/CMake.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,22 @@ $CMakeCandidates = @(
}
)

<#
.Synopsis
Invokes CMake.

.Description
A function wrapping calls to CMake, allowing the calls to be mocked for testing.
#>
function InvokeCMake {
param(
[string] $CMakePath,
[string[]] $Arguments
)
Write-Verbose "CMake Arguments: $Arguments"
& $CMakePath @Arguments
}

<#
.Synopsis
Finds the root of the CMake build - the current or ancestral folder containing a 'CMakePresets.json' file.
Expand Down
132 changes: 75 additions & 57 deletions PSCMake/PSCMake.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,14 @@ function BuildTargetsCompleter {
$null = $CommandAst
$CMakePresetsJson = GetCMakePresets -Silent
$PresetNames = GetBuildPresetNames $CMakePresetsJson
$PresetName = $FakeBoundParameters['Presets'] ?? $PresetNames |
$PresetName = $FakeBoundParameters['Preset'] ?? $PresetNames |
Select-Object -First 1
$BuildPreset, $ConfigurePreset = ResolvePresets $CMakePresetsJson 'buildPresets' $PresetName
$BinaryDirectory = GetBinaryDirectory $CMakePresetsJson $ConfigurePreset
$CMakeCodeModel = Get-CMakeBuildCodeModel $BinaryDirectory

# TODO: See if the $BuildPreset has a configuration.
$ConfigurationName = $FakeBoundParameters['Configurations'] ?? $CMakeCodeModel.configurations.Name |
$ConfigurationName = $FakeBoundParameters['Configuration'] ?? $CMakeCodeModel.configurations.Name |
Select-Object -First 1
$ConfigurationsJson = $CMakeCodeModel.configurations |
Where-Object -Property 'name' -EQ $ConfigurationName
Expand Down Expand Up @@ -166,7 +166,7 @@ function ExecutableTargetsCompleter {

<#
.Synopsis
An argument-completer for `Configure-CMakeBuild`'s `-Presets` parameter.
An argument-completer for `Configure-CMakeBuild`'s `-Preset` parameter.
#>
function ConfigurePresetsCompleter {
param(
Expand Down Expand Up @@ -209,9 +209,8 @@ function ConfigureCMake {
'--log-level=VERBOSE'
}
)
Write-Verbose "CMake Arguments: $CMakeArguments"

& $CMake @CMakeArguments
InvokeCMake $CMake $CMakeArguments
if ($LASTEXITCODE -ne 0) {
Write-Error "Configuration failed. Command line: '$($CMake.Source)' $($CMakeArguments -join ' ')"
}
Expand All @@ -224,41 +223,46 @@ function ConfigureCMake {
.Description
Configures the specified 'configurePresets' entries from a CMakePresets.json file in the current-or-higher folder.

.Parameter Presets
The configure preset names to use.
.Parameter Preset
The configure preset name to use. Multiple presets can be specified.

.Parameter Fresh
A switch specifying whether a 'fresh' configuration is performed - removing any existing cache.

.Example
# Configure the 'windows-x64' and 'windows-x86' CMake builds.
Configure-CMakeBuild -Presets windows-x64,windows-x86
Configure-CMakeBuild -Preset windows-x64,windows-x86
#>
function Configure-CMakeBuild {
[CmdletBinding()]
param(
[Alias('Presets')]
[SupportsWildcards()]
[Parameter()]
[string[]] $Presets,
[string[]] $Preset,

[Parameter()]
[switch] $Fresh
)
$CMakeRoot = FindCMakeRoot
$CMakePresetsJson = GetCMakePresets
$PresetNames = GetConfigurePresetNames $CMakePresetsJson
if (-not $Presets) {
$Presets = $PresetNames | Select-Object -First 1
Write-Information "No preset specified, defaulting to: $Presets"
$ConfigurePresetNames = GetConfigurePresetNames $CMakePresetsJson
$ConfigurePresetNames = if (-not $Preset) {
$ConfigurePresetNames | Select-Object -First 1
} else {
foreach ($CandidatePreset in $Preset) {
$ConfigurePresetNames | Where-Object { $_ -like $CandidatePreset }
}
}

$CMake = GetCMake
Using-Location $CMakeRoot {
foreach ($Preset in $Presets) {
Write-Output "Preset : $Preset"
foreach ($ConfigurePresetName in $ConfigurePresetNames) {
Write-Output "Preset : $ConfigurePresetName"

$ConfigurePreset = $CMakePresetsJson.configurePresets | Where-Object { $_.name -eq $Preset }
$ConfigurePreset = $CMakePresetsJson.configurePresets | Where-Object { $_.name -eq $ConfigurePresetName }
if (-not $ConfigurePreset) {
Write-Error "Unable to find configuration preset '$Preset' in $script:CMakePresetsPath"
Write-Error "Unable to find configuration preset '$ConfigurePresetName' in $script:CMakePresetsPath"
}

ConfigureCMake -CMake $CMake $CMakePresetsJson $ConfigurePreset -Fresh:$Fresh
Expand All @@ -273,11 +277,11 @@ function Configure-CMakeBuild {
.Description
Builds the specified 'buildPresets' entries from a CMakePresets.json file in the current-or-higher folder.

.Parameter Presets
.Parameter Preset

.Parameter Configurations
.Parameter Configuration

.Parameter Targets
.Parameter Target
One or more

.Parameter Configure
Expand All @@ -291,26 +295,31 @@ function Configure-CMakeBuild {

.Example
# Build the 'windows-x64' and 'windows-x86' CMake builds.
Build-CMakeBuild -Presets windows-x64,windows-x86
Build-CMakeBuild -Preset windows-x64,windows-x86

# Build the 'windows-x64' and 'windows-x86' CMake builds, with the 'Release' configuration.
Build-CMakeBuild -Presets windows-x64,windows-x86 -Configurations Release
Build-CMakeBuild -Preset windows-x64,windows-x86 -Configuration Release

# Build the 'HelperLibrary' target, for the 'windows-x64' and 'windows-x86' CMake builds, with the 'Release'
# configuration.
Build-CMakeBuild -Presets windows-x64,windows-x86 -Configurations Release -Targets HelperLibrary
Build-CMakeBuild -Preset windows-x64,windows-x86 -Configuration Release -Target HelperLibrary
#>
function Build-CMakeBuild {
[CmdletBinding()]
param(
[Alias('Presets')]
[SupportsWildcards()]
[Parameter(Position = 0)]
[string[]] $Presets,
[string[]] $Preset,

[Alias('Configurations')]
[SupportsWildcards()]
[Parameter(Position = 1)]
[string[]] $Configurations = @($null),
[string[]] $Configuration,

[Alias('Targets')]
[Parameter(Position = 2)]
[string[]] $Targets,
[string[]] $Target,

[Parameter()]
[switch] $Configure,
Expand All @@ -323,27 +332,30 @@ function Build-CMakeBuild {
)
$CMakeRoot = FindCMakeRoot
$CMakePresetsJson = GetCMakePresets
$PresetNames = GetBuildPresetNames $CMakePresetsJson

if (-not $Presets) {
if (-not $PresetNames) {
$BuildPresetNames = GetBuildPresetNames $CMakePresetsJson
$BuildPresetNames = if (-not $Preset) {
if (-not $BuildPresetNames) {
Write-Error "No Presets values specified, and one could not be inferred."
}
$Presets = $PresetNames | Select-Object -First 1
$BuildPresetNames | Select-Object -First 1
} else {
foreach ($CandidatePreset in $Preset) {
$BuildPresetNames | Where-Object { $_ -like $CandidatePreset }
}
}

# If;
# * no targets were specified, and
# * the current location is different from the cmake root
# Then we're a scoped build!
$ScopedBuild = (-not $Targets) -and ($CMakeRoot -ne ((Get-Location).Path))
$ScopedBuild = (-not $Target) -and ($CMakeRoot -ne ((Get-Location).Path))
$ScopeLocation = (Get-Location).Path
$CMake = GetCMake
Using-Location $CMakeRoot {
foreach ($Preset in $Presets) {
Write-Output "Preset : $Preset"
foreach ($BuildPresetName in $BuildPresetNames) {
Write-Output "Preset : $BuildPresetName"

$BuildPreset, $ConfigurePreset = ResolvePresets $CMakePresetsJson 'buildPresets' $Preset
$BuildPreset, $ConfigurePreset = ResolvePresets $CMakePresetsJson 'buildPresets' $BuildPresetName
$BinaryDirectory = GetBinaryDirectory $CMakePresetsJson $ConfigurePreset
$CMakeCacheFile = Join-Path -Path $BinaryDirectory -ChildPath 'CMakeCache.txt'

Expand All @@ -361,33 +373,39 @@ function Build-CMakeBuild {

$CodeModel = Get-CMakeBuildCodeModel $BinaryDirectory

foreach ($Configuration in $Configurations) {
Write-Output "Configuration : $Configuration"
[string[]] $ConfigurationNames = @($null)
if ($Configuration) {
$ConfigurationNames = foreach ($CandidateConfigurationName in $Configuration) {
$CodeModel.configurations.name | Where-Object { $_ -like $CandidateConfigurationName }
}
}

foreach ($ConfigurationName in $ConfigurationNames) {
Write-Output "Configuration : $ConfigurationName"

if ($ScopedBuild) {
$TargetTuples = GetScopedTargets $CodeModel $Configuration $ScopeLocation
$Targets = if ($TargetTuples) {
$TargetNames = if ($ScopedBuild) {
$TargetTuples = GetScopedTargets $CodeModel $ConfigurationName $ScopeLocation
if ($TargetTuples) {
$TargetTuples.name
} else {
@()
}
Write-Output "Scoped Targets : $Targets"
} else {
$Target
}

$CMakeArguments = @(
'--build'
'--preset', $Preset
'--preset', $BuildPresetName
if ($ConfigurationName) {
'--config', $ConfigurationName
}
if ($TargetNames) {
'--target'
$TargetNames
}
)

if ($Targets) {
$CMakeArguments += '--target'
$CMakeArguments += $Targets
}

Write-Verbose "CMake Arguments: $CMakeArguments"

$StartTime = [datetime]::Now
& $CMake @CMakeArguments (($Configuration)?('--config', $Configuration):$null)
InvokeCMake $CMake $CMakeArguments
if ($LASTEXITCODE -ne 0) {
Write-Error "Build failed. Command line: '$($CMake.Source)' $($CMakeArguments -join ' ')"
}
Expand Down Expand Up @@ -498,7 +516,7 @@ function Invoke-CMakeOutput {
#
$CodeModel = Get-CMakeBuildCodeModel $BinaryDirectory
if (-not $CodeModel) {
Configure-CMakeBuild -Presets $Preset
Configure-CMakeBuild -Preset $Preset
$CodeModel = Get-CMakeBuildCodeModel $BinaryDirectory
}

Expand Down Expand Up @@ -547,11 +565,11 @@ Register-ArgumentCompleter -CommandName Invoke-CMakeOutput -ParameterName Preset
Register-ArgumentCompleter -CommandName Invoke-CMakeOutput -ParameterName Configuration -ScriptBlock $function:BuildConfigurationsCompleter
Register-ArgumentCompleter -CommandName Invoke-CMakeOutput -ParameterName Target -ScriptBlock $function:ExecutableTargetsCompleter

Register-ArgumentCompleter -CommandName Build-CMakeBuild -ParameterName Presets -ScriptBlock $function:BuildPresetsCompleter
Register-ArgumentCompleter -CommandName Build-CMakeBuild -ParameterName Configurations -ScriptBlock $function:BuildConfigurationsCompleter
Register-ArgumentCompleter -CommandName Build-CMakeBuild -ParameterName Targets -ScriptBlock $function:BuildTargetsCompleter
Register-ArgumentCompleter -CommandName Build-CMakeBuild -ParameterName Preset -ScriptBlock $function:BuildPresetsCompleter
Register-ArgumentCompleter -CommandName Build-CMakeBuild -ParameterName Configuration -ScriptBlock $function:BuildConfigurationsCompleter
Register-ArgumentCompleter -CommandName Build-CMakeBuild -ParameterName Target -ScriptBlock $function:BuildTargetsCompleter

Register-ArgumentCompleter -CommandName Configure-CMakeBuild -ParameterName Presets -ScriptBlock $function:ConfigurePresetsCompleter
Register-ArgumentCompleter -CommandName Configure-CMakeBuild -ParameterName Preset -ScriptBlock $function:ConfigurePresetsCompleter

Register-ArgumentCompleter -CommandName Write-CMakeBuild -ParameterName Preset -ScriptBlock $function:BuildPresetsCompleter
Register-ArgumentCompleter -CommandName Write-CMakeBuild -ParameterName Configuration -ScriptBlock $function:BuildConfigurationsCompleter
39 changes: 38 additions & 1 deletion Tests/Build-CMakeBuild.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,55 @@ BeforeAll {
. $PSScriptRoot/TestUtilities.ps1
. $PSScriptRoot/ReferenceBuild.ps1

# Configure the reference build so that there is reference content to work with.
$Properties = PrepareReferenceBuild

$CMake = "$env:ProgramFiles/CMake/bin/cmake.exe"
& $CMake @Properties

Import-Module -Force $PSScriptRoot/../PSCMake/PSCMake.psd1 -DisableNameChecking

# Mock subsequent calls to invoke CMake so that we don't actually try to build anything.
$script:CMakeCalls = @()
Mock -ModuleName PSCMake InvokeCMake {
param(
[string] $CMakePath,
[string[]] $Arguments
)
$script:CMakeCalls += , $Arguments
}
}

Describe 'Build-CMakeBuild' {
BeforeEach {
$script:CMakeCalls = @()
}

It 'Builds with no parameters' {
Using-Location "$PSScriptRoot/ReferenceBuild" {
Build-CMakeBuild
}

$script:CMakeCalls | Should -HaveCount 1
$script:CMakeCalls[0] | Should -Be @('--build', '--preset', 'windows-x64')
}

It 'Builds with wildcard presets' {
Using-Location "$PSScriptRoot/ReferenceBuild" {
Build-CMakeBuild -Preset '*-x64'
}

$CMakeCalls | Should -HaveCount 1
$script:CMakeCalls[0] | Should -Be @('--build', '--preset', 'windows-x64')
}

It 'Builds with wildcard configurations' {
Using-Location "$PSScriptRoot/ReferenceBuild" {
Build-CMakeBuild -Preset 'windows-x64' -Configuration *
}

$CMakeCalls | Should -HaveCount 3
$script:CMakeCalls[0] | Should -Be @('--build', '--preset', 'windows-x64', '--config', 'Debug')
$script:CMakeCalls[1] | Should -Be @('--build', '--preset', 'windows-x64', '--config', 'Release')
$script:CMakeCalls[2] | Should -Be @('--build', '--preset', 'windows-x64', '--config', 'RelWithDebInfo')
}
}
4 changes: 2 additions & 2 deletions Tests/BuildConfigurationsCompleter.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ BeforeAll {

Describe 'BuildConfigurationsCompleter' {
It 'Returns the default configurations when no preset is specified' {
$Completions = Get-CommandCompletion "Build-CMakeBuild -Configurations "
$Completions = Get-CommandCompletion "Build-CMakeBuild -Configuration "
$Completions.CompletionMatches.Count | Should -Be 4
$Completions.CompletionMatches[0].CompletionText | Should -Be 'Release'
$Completions.CompletionMatches[1].CompletionText | Should -Be 'Debug'
Expand All @@ -20,7 +20,7 @@ Describe 'BuildConfigurationsCompleter' {
}

It 'Returns the default configurations when no preset is specified, filtered by the word to complete' {
$Completions = Get-CommandCompletion "Build-CMakeBuild -Configurations D"
$Completions = Get-CommandCompletion "Build-CMakeBuild -Configuration D"
$Completions.CompletionMatches.Count | Should -Be 1
$Completions.CompletionMatches[0].CompletionText | Should -Be 'Debug'
}
Expand Down
Loading