diff --git a/.vscode/settings.json b/.vscode/settings.json
index 91244032f3..a70510a40a 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -85,7 +85,6 @@
"resharper.build.useResharperBuild": false,
"resharper.build.restorePackagesOnBuild": true,
"resharper.build.smartNugetRestore": true,
- "resharper.build.customMsbuildPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\amd64\\MSBuild.exe",
// Git Graph extension settings
"git-graph.dialog.merge.noFastForward": false,
"git-graph.dialog.merge.squashCommits": false,
@@ -132,4 +131,4 @@
// - Agent: Apply change-log (modifies files)
// - Installer: Setup for patch (downloads artifacts)
// ============================================================================
-}
\ No newline at end of file
+}
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 8e14bcddb2..c906460e45 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -334,7 +334,7 @@
{
"label": "Test (native)",
"type": "shell",
- "command": "./test.ps1 -Native -Configuration ${input:testConfiguration}",
+ "command": "./test.ps1 -SkipManaged -Configuration ${input:testConfiguration}",
"group": "test",
"detail": "Run native tests via test.ps1 (dispatches to Build/scripts/Invoke-CppTest.ps1)",
"options": {
@@ -348,7 +348,7 @@
{
"label": "Test (native, no build)",
"type": "shell",
- "command": "./test.ps1 -Native -NoBuild -Configuration ${input:testConfiguration}",
+ "command": "./test.ps1 -SkipManaged -NoBuild -Configuration ${input:testConfiguration}",
"group": "test",
"detail": "Run native tests via test.ps1 without rebuilding",
"options": {
@@ -530,4 +530,3 @@
}
]
}
-
diff --git a/Build/Agent/FwBuildEnvironment.psm1 b/Build/Agent/FwBuildEnvironment.psm1
index 5b73699100..3f6b881818 100644
--- a/Build/Agent/FwBuildEnvironment.psm1
+++ b/Build/Agent/FwBuildEnvironment.psm1
@@ -1,148 +1,441 @@
<#
.SYNOPSIS
- Visual Studio and build tool environment helpers for FieldWorks.
+ Visual Studio and build tool environment helpers for FieldWorks.
.DESCRIPTION
- Provides VS environment initialization, MSBuild execution, and
- VSTest path discovery.
+ Provides VS environment initialization, MSBuild execution, and
+ VSTest path discovery.
.NOTES
- Used by FwBuildHelpers.psm1 - do not import directly.
+ Used by FwBuildHelpers.psm1 - do not import directly.
#>
# =============================================================================
# VS Environment Functions
# =============================================================================
+function Get-VsWherePath {
+ <#
+ .SYNOPSIS
+ Returns the path to the Microsoft-provided vswhere executable.
+ #>
+ $candidates = @()
+ if ($env:ProgramFiles) {
+ $candidates += (Join-Path -Path $env:ProgramFiles -ChildPath 'Microsoft Visual Studio\Installer\vswhere.exe')
+ }
+
+ $programFilesX86 = ${env:ProgramFiles(x86)}
+ if ($programFilesX86) {
+ $candidates += (Join-Path -Path $programFilesX86 -ChildPath 'Microsoft Visual Studio\Installer\vswhere.exe')
+ }
+
+ foreach ($candidate in $candidates | Select-Object -Unique) {
+ if (Test-Path $candidate) {
+ return $candidate
+ }
+ }
+
+ return $null
+}
+
+function Get-FwToolchainPolicy {
+ <#
+ .SYNOPSIS
+ Returns the repo-controlled FieldWorks toolchain policy.
+ #>
+ if ($script:FwToolchainPolicy) {
+ return $script:FwToolchainPolicy
+ }
+
+ $policyPath = Join-Path (Split-Path -Parent $PSScriptRoot) 'FieldWorks.Toolchain.props'
+ $defaults = [ordered]@{
+ VisualStudioMajor = '17'
+ VisualStudioVersionRange = '[17.0,18.0)'
+ VCTargetsVersion = 'v170'
+ PlatformToolset = 'v143'
+ DotNetFrameworkSdkVisualStudioVersion = '17.0'
+ }
+
+ if (-not (Test-Path $policyPath)) {
+ $script:FwToolchainPolicy = [pscustomobject]$defaults
+ return $script:FwToolchainPolicy
+ }
+
+ [xml]$policyXml = Get-Content -LiteralPath $policyPath -Raw
+ $propertyGroups = @($policyXml.Project.PropertyGroup)
+
+ function Get-PolicyValue {
+ param(
+ [string]$Name,
+ [string]$DefaultValue
+ )
+
+ foreach ($propertyGroup in $propertyGroups) {
+ $node = $propertyGroup.$Name
+ if (-not $node) {
+ continue
+ }
+
+ $value = $node.'#text'
+ if (-not [string]::IsNullOrWhiteSpace($value)) {
+ return $value.Trim()
+ }
+ }
+
+ return $DefaultValue
+ }
+
+ $script:FwToolchainPolicy = [pscustomobject]@{
+ VisualStudioMajor = Get-PolicyValue -Name 'FwVisualStudioMajor' -DefaultValue $defaults.VisualStudioMajor
+ VisualStudioVersionRange = Get-PolicyValue -Name 'FwVisualStudioVersionRange' -DefaultValue $defaults.VisualStudioVersionRange
+ VCTargetsVersion = Get-PolicyValue -Name 'FwVCTargetsVersion' -DefaultValue $defaults.VCTargetsVersion
+ PlatformToolset = Get-PolicyValue -Name 'FwPlatformToolset' -DefaultValue $defaults.PlatformToolset
+ DotNetFrameworkSdkVisualStudioVersion = Get-PolicyValue -Name 'FwDotNetFrameworkSdkVisualStudioVersion' -DefaultValue $defaults.DotNetFrameworkSdkVisualStudioVersion
+ }
+
+ return $script:FwToolchainPolicy
+}
+
+function Get-VsInstallationInfo {
+ <#
+ .SYNOPSIS
+ Returns installation metadata for the latest matching Visual Studio instance.
+ #>
+ param(
+ [string[]]$Requires = @(),
+ [string]$VersionRange = ''
+ )
+
+ $vsWhere = Get-VsWherePath
+ if (-not $vsWhere) {
+ return $null
+ }
+
+ if ([string]::IsNullOrWhiteSpace($VersionRange)) {
+ $VersionRange = (Get-FwToolchainPolicy).VisualStudioVersionRange
+ }
+
+ $vsWhereArgs = @('-latest', '-products', '*')
+ if (-not [string]::IsNullOrWhiteSpace($VersionRange)) {
+ $vsWhereArgs += '-version'
+ $vsWhereArgs += $VersionRange
+ }
+
+ if ($Requires -and $Requires.Count -gt 0) {
+ $vsWhereArgs += '-requires'
+ $vsWhereArgs += $Requires
+ }
+
+ $installationPath = & $vsWhere @vsWhereArgs -property installationPath
+ if (-not $installationPath) {
+ return $null
+ }
+
+ $displayVersion = & $vsWhere @vsWhereArgs -property catalog_productDisplayVersion
+
+ return [pscustomobject]@{
+ VsWherePath = $vsWhere
+ InstallationPath = $installationPath
+ DisplayVersion = $displayVersion
+ }
+}
+
+function Get-VsToolchainInfo {
+ <#
+ .SYNOPSIS
+ Returns derived toolchain paths for the latest matching Visual Studio instance.
+ #>
+ param(
+ [string[]]$Requires = @('Microsoft.Component.MSBuild')
+ )
+
+ $vsInfo = Get-VsInstallationInfo -Requires $Requires
+ if (-not $vsInfo) {
+ return $null
+ }
+
+ $toolchainPolicy = Get-FwToolchainPolicy
+
+ $installationPath = $vsInfo.InstallationPath
+ $vsDevCmdPath = Join-Path $installationPath 'Common7\Tools\VsDevCmd.bat'
+ if (-not (Test-Path $vsDevCmdPath)) {
+ $vsDevCmdPath = $null
+ }
+
+ $msbuildCandidates = @(
+ (Join-Path $installationPath 'MSBuild\Current\Bin\amd64\MSBuild.exe'),
+ (Join-Path $installationPath 'MSBuild\Current\Bin\MSBuild.exe')
+ )
+ $msbuildPath = $msbuildCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1
+
+ $vsTestPath = Join-Path $installationPath 'Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe'
+ if (-not (Test-Path $vsTestPath)) {
+ $vsTestPath = $null
+ }
+
+ $vcInstallDir = Join-Path $installationPath 'VC'
+ if (-not (Test-Path $vcInstallDir)) {
+ $vcInstallDir = $null
+ }
+
+ $vcTargetsPath = $null
+ if (-not [string]::IsNullOrWhiteSpace($toolchainPolicy.VCTargetsVersion)) {
+ $vcTargetsPath = Join-Path $installationPath (Join-Path 'MSBuild\Microsoft\VC' $toolchainPolicy.VCTargetsVersion)
+ if (-not (Test-Path $vcTargetsPath)) {
+ $vcTargetsPath = $null
+ }
+ }
+
+ return [pscustomobject]@{
+ VsWherePath = $vsInfo.VsWherePath
+ InstallationPath = $installationPath
+ DisplayVersion = $vsInfo.DisplayVersion
+ VisualStudioVersionRange = $toolchainPolicy.VisualStudioVersionRange
+ VsDevCmdPath = $vsDevCmdPath
+ MSBuildPath = $msbuildPath
+ VSTestPath = $vsTestPath
+ VcInstallDir = $vcInstallDir
+ VCTargetsPath = $vcTargetsPath
+ PlatformToolset = $toolchainPolicy.PlatformToolset
+ DotNetFrameworkSdkVisualStudioVersion = $toolchainPolicy.DotNetFrameworkSdkVisualStudioVersion
+ }
+}
+
+function Get-VsDevEnvironmentVariables {
+ <#
+ .SYNOPSIS
+ Returns the environment variables produced by VsDevCmd.bat.
+ #>
+ param(
+ [string]$Architecture = 'amd64',
+ [string]$HostArchitecture = 'amd64',
+ [string[]]$Requires = @('Microsoft.Component.MSBuild', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64')
+ )
+
+ $toolchain = Get-VsToolchainInfo -Requires $Requires
+ if (-not $toolchain) {
+ return $null
+ }
+
+ if (-not $toolchain.VsDevCmdPath) {
+ throw "Unable to locate VsDevCmd.bat under '$($toolchain.InstallationPath)'."
+ }
+
+ $cmdArgs = "`"$($toolchain.VsDevCmdPath)`" -no_logo -arch=$Architecture -host_arch=$HostArchitecture && set"
+ $envOutput = & cmd.exe /c $cmdArgs 2>&1
+ if ($LASTEXITCODE -ne 0) {
+ throw 'Failed to initialize Visual Studio environment'
+ }
+
+ $variables = [ordered]@{}
+ foreach ($line in $envOutput) {
+ $parts = $line -split '=', 2
+ if ($parts.Length -eq 2 -and $parts[0]) {
+ $variables[$parts[0]] = $parts[1]
+ }
+ }
+
+ return [pscustomobject]@{
+ Toolchain = $toolchain
+ Variables = [pscustomobject]$variables
+ }
+}
+
+function Get-ActiveVcToolBinPath {
+ <#
+ .SYNOPSIS
+ Returns the HostX64\x64 tool bin directory for the active VC toolset.
+ #>
+ if (-not [string]::IsNullOrWhiteSpace($env:VCToolsInstallDir)) {
+ $preferred = Join-Path $env:VCToolsInstallDir 'bin\HostX64\x64'
+ if (Test-Path (Join-Path $preferred 'cl.exe')) {
+ return $preferred
+ }
+ }
+
+ if (-not [string]::IsNullOrWhiteSpace($env:VCINSTALLDIR)) {
+ $legacy = Join-Path $env:VCINSTALLDIR 'bin'
+ if (Test-Path (Join-Path $legacy 'cl.exe')) {
+ return $legacy
+ }
+ }
+
+ return $null
+}
+
+function Test-VsDevEnvironmentActive {
+ <#
+ .SYNOPSIS
+ Returns true when a full VsDevCmd environment is already active.
+ #>
+ if ($env:OS -ne 'Windows_NT') {
+ return $false
+ }
+
+ if ([string]::IsNullOrWhiteSpace($env:VSCMD_VER) -or [string]::IsNullOrWhiteSpace($env:VCToolsInstallDir)) {
+ return $false
+ }
+
+ $activeVcToolPath = Get-ActiveVcToolBinPath
+ if (-not $activeVcToolPath) {
+ return $false
+ }
+
+ $cl = Get-Command 'cl.exe' -ErrorAction SilentlyContinue
+ $nmake = Get-Command 'nmake.exe' -ErrorAction SilentlyContinue
+ if (-not $cl -or -not $nmake) {
+ return $false
+ }
+
+ $normalizedToolPath = $activeVcToolPath.TrimEnd('\')
+ $clDirectory = (Split-Path -Parent $cl.Source).TrimEnd('\')
+ $nmakeDirectory = (Split-Path -Parent $nmake.Source).TrimEnd('\')
+
+ return [string]::Equals($clDirectory, $normalizedToolPath, [System.StringComparison]::OrdinalIgnoreCase) -and
+ [string]::Equals($nmakeDirectory, $normalizedToolPath, [System.StringComparison]::OrdinalIgnoreCase)
+}
+
+function Ensure-PreferredVcToolPath {
+ <#
+ .SYNOPSIS
+ Moves the active HostX64\x64 MSVC bin directory to the front of PATH.
+ #>
+ $preferred = Get-ActiveVcToolBinPath
+ if (-not $preferred) {
+ return
+ }
+
+ $pathEntries = @()
+ if (-not [string]::IsNullOrWhiteSpace($env:PATH)) {
+ $pathEntries = $env:PATH -split ';' | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
+ }
+
+ $filteredEntries = $pathEntries | Where-Object {
+ -not [string]::Equals($_.TrimEnd('\'), $preferred.TrimEnd('\'), [System.StringComparison]::OrdinalIgnoreCase)
+ }
+
+ $env:PATH = (@($preferred) + $filteredEntries) -join ';'
+}
+
function Initialize-VsDevEnvironment {
- <#
- .SYNOPSIS
- Initializes the Visual Studio Developer environment.
- .DESCRIPTION
- Sets up environment variables for native C++ compilation (x64 only).
- Safe to call multiple times - will skip if already initialized.
- #>
- if ($env:OS -ne 'Windows_NT') {
- return
- }
-
- if ($env:VCINSTALLDIR) {
- Write-Host '[OK] Visual Studio environment already initialized' -ForegroundColor Green
- return
- }
-
- Write-Host 'Initializing Visual Studio Developer environment...' -ForegroundColor Yellow
-
- $vswhereCandidates = @()
- if ($env:ProgramFiles) {
- $pfVswhere = Join-Path -Path $env:ProgramFiles -ChildPath 'Microsoft Visual Studio\Installer\vswhere.exe'
- if (Test-Path $pfVswhere) { $vswhereCandidates += $pfVswhere }
- }
- $programFilesX86 = ${env:ProgramFiles(x86)}
- if ($programFilesX86) {
- $pf86Vswhere = Join-Path -Path $programFilesX86 -ChildPath 'Microsoft Visual Studio\Installer\vswhere.exe'
- if (Test-Path $pf86Vswhere) { $vswhereCandidates += $pf86Vswhere }
- }
-
- if (-not $vswhereCandidates) {
- Write-Host ''
- Write-Host '[ERROR] Visual Studio 2017+ not found' -ForegroundColor Red
- Write-Host ' Install from: https://visualstudio.microsoft.com/downloads/' -ForegroundColor Yellow
- throw 'Visual Studio not found'
- }
-
- $vsInstallPath = & $vswhereCandidates[0] -latest -requires Microsoft.Component.MSBuild Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -products * -property installationPath
- if (-not $vsInstallPath) {
- Write-Host ''
- Write-Host '[ERROR] Visual Studio found but missing required C++ tools' -ForegroundColor Red
- Write-Host ' Please install the "Desktop development with C++" workload' -ForegroundColor Yellow
- throw 'Visual Studio C++ tools not found'
- }
-
- $vsDevCmd = Join-Path -Path $vsInstallPath -ChildPath 'Common7\Tools\VsDevCmd.bat'
- if (-not (Test-Path $vsDevCmd)) {
- throw "Unable to locate VsDevCmd.bat under '$vsInstallPath'."
- }
-
- # x64-only build
- $arch = 'amd64'
- $vsVersion = Split-Path (Split-Path (Split-Path (Split-Path $vsInstallPath))) -Leaf
- Write-Host " Found Visual Studio $vsVersion at: $vsInstallPath" -ForegroundColor Gray
- Write-Host " Setting up environment for $arch..." -ForegroundColor Gray
-
- $cmdArgs = "`"$vsDevCmd`" -no_logo -arch=$arch -host_arch=$arch && set"
- $envOutput = & cmd.exe /c $cmdArgs 2>&1
- if ($LASTEXITCODE -ne 0) {
- throw 'Failed to initialize Visual Studio environment'
- }
-
- foreach ($line in $envOutput) {
- $parts = $line -split '=', 2
- if ($parts.Length -eq 2 -and $parts[0]) {
- Set-Item -Path "Env:$($parts[0])" -Value $parts[1]
- }
- }
-
- if (-not $env:VCINSTALLDIR) {
- throw 'Visual Studio C++ environment not configured'
- }
-
- Write-Host '[OK] Visual Studio environment initialized successfully' -ForegroundColor Green
- Write-Host " VCINSTALLDIR: $env:VCINSTALLDIR" -ForegroundColor Gray
+ <#
+ .SYNOPSIS
+ Initializes the Visual Studio Developer environment.
+ .DESCRIPTION
+ Sets up environment variables for native C++ compilation (x64 only).
+ Safe to call multiple times - will skip if already initialized.
+ #>
+ if ($env:OS -ne 'Windows_NT') {
+ return
+ }
+
+ if (Test-VsDevEnvironmentActive) {
+ Ensure-PreferredVcToolPath
+ Write-Host '[OK] Visual Studio environment already initialized' -ForegroundColor Green
+ return
+ }
+
+ if ($env:VCINSTALLDIR -or $env:VCToolsInstallDir -or $env:VSCMD_VER) {
+ Write-Host '[WARN] Partial Visual Studio environment detected. Reinitializing...' -ForegroundColor Yellow
+ }
+
+ Write-Host 'Initializing Visual Studio Developer environment...' -ForegroundColor Yellow
+
+ $vsToolchain = Get-VsToolchainInfo -Requires @('Microsoft.Component.MSBuild', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64')
+
+ if (-not $vsToolchain) {
+ $vsWhere = Get-VsWherePath
+ Write-Host ''
+ if (-not $vsWhere) {
+ Write-Host '[ERROR] Visual Studio 2017+ not found' -ForegroundColor Red
+ Write-Host ' Install from: https://visualstudio.microsoft.com/downloads/' -ForegroundColor Yellow
+ throw 'Visual Studio not found'
+ }
+
+ Write-Host '[ERROR] Visual Studio found but missing required C++ tools' -ForegroundColor Red
+ Write-Host ' Please install the "Desktop development with C++" workload' -ForegroundColor Yellow
+ throw 'Visual Studio C++ tools not found'
+ }
+
+ # x64-only build
+ $arch = 'amd64'
+ $vsInstallPath = $vsToolchain.InstallationPath
+ $vsVersion = if ([string]::IsNullOrWhiteSpace($vsToolchain.DisplayVersion)) {
+ Split-Path (Split-Path (Split-Path (Split-Path $vsInstallPath))) -Leaf
+ }
+ else {
+ $vsToolchain.DisplayVersion
+ }
+ Write-Host " Found Visual Studio $vsVersion at: $vsInstallPath" -ForegroundColor Gray
+ Write-Host " Setting up environment for $arch..." -ForegroundColor Gray
+
+ $vsEnvironment = Get-VsDevEnvironmentVariables -Architecture $arch -HostArchitecture $arch
+ foreach ($variable in $vsEnvironment.Variables.PSObject.Properties) {
+ Set-Item -Path "Env:$($variable.Name)" -Value $variable.Value
+ }
+
+ if (-not (Test-VsDevEnvironmentActive)) {
+ throw 'Visual Studio C++ environment not configured'
+ }
+
+ Ensure-PreferredVcToolPath
+
+ Write-Host '[OK] Visual Studio environment initialized successfully' -ForegroundColor Green
+ Write-Host " VCINSTALLDIR: $env:VCINSTALLDIR" -ForegroundColor Gray
}
function Get-CvtresDiagnostics {
- <#
- .SYNOPSIS
- Returns details about the cvtres.exe resolved in the current session.
- #>
- $result = [ordered]@{
- Path = $null
- IsVcToolset = $false
- IsDotNetFramework = $false
- }
-
- $cmd = Get-Command "cvtres.exe" -ErrorAction SilentlyContinue
- if ($cmd) {
- $result.Path = $cmd.Source
- $lower = $result.Path.ToLowerInvariant()
- $result.IsVcToolset = $lower -match "[\\/]vc[\\/]tools[\\/]msvc[\\/][^\\/]+[\\/]bin[\\/]hostx64[\\/]x64[\\/]cvtres\.exe$"
- $result.IsDotNetFramework = $lower -match "windows[\\/]microsoft\.net[\\/]framework"
- return $result
- }
-
- if ($env:VCINSTALLDIR) {
- $candidates = Get-ChildItem -Path (Join-Path $env:VCINSTALLDIR "Tools\MSVC\*") -Filter cvtres.exe -Recurse -ErrorAction SilentlyContinue |
- Sort-Object FullName -Descending
- if ($candidates -and $candidates.Count -gt 0) {
- $result.Path = $candidates[0].FullName
- $lower = $result.Path.ToLowerInvariant()
- $result.IsVcToolset = $lower -match "[\\/]vc[\\/]tools[\\/]msvc[\\/][^\\/]+[\\/]bin[\\/]hostx64[\\/]x64[\\/]cvtres\.exe$"
- $result.IsDotNetFramework = $lower -match "windows[\\/]microsoft\.net[\\/]framework"
- }
- }
-
- return $result
+ <#
+ .SYNOPSIS
+ Returns details about the cvtres.exe resolved in the current session.
+ #>
+ $result = [ordered]@{
+ Path = $null
+ IsVcToolset = $false
+ IsDotNetFramework = $false
+ }
+
+ $cmd = Get-Command "cvtres.exe" -ErrorAction SilentlyContinue
+ if ($cmd) {
+ $result.Path = $cmd.Source
+ $lower = $result.Path.ToLowerInvariant()
+ $result.IsVcToolset = $lower -match "[\\/]vc[\\/]tools[\\/]msvc[\\/][^\\/]+[\\/]bin[\\/]hostx64[\\/]x64[\\/]cvtres\.exe$"
+ $result.IsDotNetFramework = $lower -match "windows[\\/]microsoft\.net[\\/]framework"
+ return $result
+ }
+
+ if ($env:VCINSTALLDIR) {
+ $candidates = Get-ChildItem -Path (Join-Path $env:VCINSTALLDIR "Tools\MSVC\*") -Filter cvtres.exe -Recurse -ErrorAction SilentlyContinue |
+ Sort-Object FullName -Descending
+ if ($candidates -and $candidates.Count -gt 0) {
+ $result.Path = $candidates[0].FullName
+ $lower = $result.Path.ToLowerInvariant()
+ $result.IsVcToolset = $lower -match "[\\/]vc[\\/]tools[\\/]msvc[\\/][^\\/]+[\\/]bin[\\/]hostx64[\\/]x64[\\/]cvtres\.exe$"
+ $result.IsDotNetFramework = $lower -match "windows[\\/]microsoft\.net[\\/]framework"
+ }
+ }
+
+ return $result
}
function Test-CvtresCompatibility {
- <#
- .SYNOPSIS
- Emits warnings if cvtres.exe resolves to a non-VC toolset binary.
- #>
- $diag = Get-CvtresDiagnostics
-
- if (-not $diag.Path) {
- Write-Host "[WARN] cvtres.exe not found after VS environment setup. Toolchain may be incomplete." -ForegroundColor Yellow
- return
- }
-
- if ($diag.IsDotNetFramework) {
- Write-Host "[WARN] cvtres.exe resolves to a .NET Framework path. Prefer the VC toolset version (Hostx64\\x64). $($diag.Path)" -ForegroundColor Yellow
- }
- elseif (-not $diag.IsVcToolset) {
- Write-Host "[WARN] cvtres.exe is not from the VC toolset Hostx64\\x64 folder. Confirm PATH ordering. $($diag.Path)" -ForegroundColor Yellow
- }
+ <#
+ .SYNOPSIS
+ Emits warnings if cvtres.exe resolves to a non-VC toolset binary.
+ #>
+ $diag = Get-CvtresDiagnostics
+
+ if (-not $diag.Path) {
+ Write-Host "[WARN] cvtres.exe not found after VS environment setup. Toolchain may be incomplete." -ForegroundColor Yellow
+ return
+ }
+
+ if ($diag.IsDotNetFramework) {
+ Write-Host "[WARN] cvtres.exe resolves to a .NET Framework path. Prefer the VC toolset version (Hostx64\\x64). $($diag.Path)" -ForegroundColor Yellow
+ }
+ elseif (-not $diag.IsVcToolset) {
+ Write-Host "[WARN] cvtres.exe is not from the VC toolset Hostx64\\x64 folder. Confirm PATH ordering. $($diag.Path)" -ForegroundColor Yellow
+ }
}
# =============================================================================
@@ -150,89 +443,95 @@ function Test-CvtresCompatibility {
# =============================================================================
function Get-MSBuildPath {
- <#
- .SYNOPSIS
- Gets the path to MSBuild.exe.
- .DESCRIPTION
- Returns the MSBuild command, either from PATH or 'msbuild' as fallback.
- #>
- $msbuildCmd = Get-Command msbuild -ErrorAction SilentlyContinue
- if ($msbuildCmd) {
- return $msbuildCmd.Source
- }
- return 'msbuild'
+ <#
+ .SYNOPSIS
+ Gets the path to MSBuild.exe.
+ .DESCRIPTION
+ Returns the MSBuild command, either from PATH or 'msbuild' as fallback.
+ #>
+ $msbuildCmd = Get-Command msbuild -ErrorAction SilentlyContinue
+ if ($msbuildCmd) {
+ return $msbuildCmd.Source
+ }
+
+ $toolchain = Get-VsToolchainInfo -Requires @('Microsoft.Component.MSBuild')
+ if ($toolchain -and $toolchain.MSBuildPath) {
+ return $toolchain.MSBuildPath
+ }
+
+ return 'msbuild'
}
function Invoke-MSBuild {
- <#
- .SYNOPSIS
- Executes MSBuild with proper error handling.
- .DESCRIPTION
- Runs MSBuild with the specified arguments and handles errors appropriately.
- .PARAMETER Arguments
- Array of arguments to pass to MSBuild.
- .PARAMETER Description
- Human-readable description of the build step.
- .PARAMETER LogPath
- Optional path to write build output to a log file.
- .PARAMETER TailLines
- If specified, only displays the last N lines of output.
- #>
- param(
- [Parameter(Mandatory)]
- [string[]]$Arguments,
- [Parameter(Mandatory)]
- [string]$Description,
- [string]$LogPath = '',
- [int]$TailLines = 0
- )
-
- $msbuildCmd = Get-MSBuildPath
- Write-Host "Running $Description..." -ForegroundColor Cyan
-
- if ($TailLines -gt 0) {
- # Capture all output, optionally log to file, then display tail
- $output = & $msbuildCmd $Arguments 2>&1 | ForEach-Object { $_.ToString() }
- $exitCode = $LASTEXITCODE
-
- if ($LogPath) {
- $logDir = Split-Path -Parent $LogPath
- if ($logDir -and -not (Test-Path $logDir)) {
- New-Item -Path $logDir -ItemType Directory -Force | Out-Null
- }
- $output | Out-File -FilePath $LogPath -Encoding utf8
- }
-
- # Display last N lines
- $totalLines = $output.Count
- if ($totalLines -gt $TailLines) {
- Write-Host "... ($($totalLines - $TailLines) lines omitted, showing last $TailLines) ..." -ForegroundColor DarkGray
- $output | Select-Object -Last $TailLines | ForEach-Object { Write-Host $_ }
- }
- else {
- $output | ForEach-Object { Write-Host $_ }
- }
-
- $LASTEXITCODE = $exitCode
- }
- elseif ($LogPath) {
- $logDir = Split-Path -Parent $LogPath
- if ($logDir -and -not (Test-Path $logDir)) {
- New-Item -Path $logDir -ItemType Directory -Force | Out-Null
- }
- & $msbuildCmd $Arguments | Tee-Object -FilePath $LogPath
- }
- else {
- & $msbuildCmd $Arguments
- }
-
- if ($LASTEXITCODE -ne 0) {
- $errorMsg = "MSBuild failed during $Description with exit code $LASTEXITCODE"
- if ($LASTEXITCODE -eq -1073741819) {
- $errorMsg += " (0xC0000005 - Access Violation). This indicates a crash in native code during build."
- }
- throw $errorMsg
- }
+ <#
+ .SYNOPSIS
+ Executes MSBuild with proper error handling.
+ .DESCRIPTION
+ Runs MSBuild with the specified arguments and handles errors appropriately.
+ .PARAMETER Arguments
+ Array of arguments to pass to MSBuild.
+ .PARAMETER Description
+ Human-readable description of the build step.
+ .PARAMETER LogPath
+ Optional path to write build output to a log file.
+ .PARAMETER TailLines
+ If specified, only displays the last N lines of output.
+ #>
+ param(
+ [Parameter(Mandatory)]
+ [string[]]$Arguments,
+ [Parameter(Mandatory)]
+ [string]$Description,
+ [string]$LogPath = '',
+ [int]$TailLines = 0
+ )
+
+ $msbuildCmd = Get-MSBuildPath
+ Write-Host "Running $Description..." -ForegroundColor Cyan
+
+ if ($TailLines -gt 0) {
+ # Capture all output, optionally log to file, then display tail
+ $output = & $msbuildCmd $Arguments 2>&1 | ForEach-Object { $_.ToString() }
+ $exitCode = $LASTEXITCODE
+
+ if ($LogPath) {
+ $logDir = Split-Path -Parent $LogPath
+ if ($logDir -and -not (Test-Path $logDir)) {
+ New-Item -Path $logDir -ItemType Directory -Force | Out-Null
+ }
+ $output | Out-File -FilePath $LogPath -Encoding utf8
+ }
+
+ # Display last N lines
+ $totalLines = $output.Count
+ if ($totalLines -gt $TailLines) {
+ Write-Host "... ($($totalLines - $TailLines) lines omitted, showing last $TailLines) ..." -ForegroundColor DarkGray
+ $output | Select-Object -Last $TailLines | ForEach-Object { Write-Host $_ }
+ }
+ else {
+ $output | ForEach-Object { Write-Host $_ }
+ }
+
+ $LASTEXITCODE = $exitCode
+ }
+ elseif ($LogPath) {
+ $logDir = Split-Path -Parent $LogPath
+ if ($logDir -and -not (Test-Path $logDir)) {
+ New-Item -Path $logDir -ItemType Directory -Force | Out-Null
+ }
+ & $msbuildCmd $Arguments | Tee-Object -FilePath $LogPath
+ }
+ else {
+ & $msbuildCmd $Arguments
+ }
+
+ if ($LASTEXITCODE -ne 0) {
+ $errorMsg = "MSBuild failed during $Description with exit code $LASTEXITCODE"
+ if ($LASTEXITCODE -eq -1073741819) {
+ $errorMsg += " (0xC0000005 - Access Violation). This indicates a crash in native code during build."
+ }
+ throw $errorMsg
+ }
}
# =============================================================================
@@ -240,42 +539,25 @@ function Invoke-MSBuild {
# =============================================================================
function Get-VSTestPath {
- <#
- .SYNOPSIS
- Finds vstest.console.exe in PATH or known locations.
- .DESCRIPTION
- First checks PATH, then falls back to known VS installation paths.
- #>
-
- # Try PATH first (setup scripts add vstest to PATH)
- $vstestFromPath = Get-Command "vstest.console.exe" -ErrorAction SilentlyContinue
- if ($vstestFromPath) {
- return $vstestFromPath.Source
- }
-
- # Fall back to known installation paths
- $programFilesX86 = ${env:ProgramFiles(x86)}
- if (-not $programFilesX86) { $programFilesX86 = "C:\Program Files (x86)" }
-
- $vstestCandidates = @(
- # BuildTools
- "$programFilesX86\Microsoft Visual Studio\2022\BuildTools\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe",
- "C:\BuildTools\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe",
- # TestAgent (sometimes installed separately)
- "$programFilesX86\Microsoft Visual Studio\2022\TestAgent\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe",
- # Full VS installations
- "${env:ProgramFiles}\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe",
- "${env:ProgramFiles}\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe",
- "${env:ProgramFiles}\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe"
- )
-
- foreach ($candidate in $vstestCandidates) {
- if (Test-Path $candidate) {
- return $candidate
- }
- }
-
- return $null
+ <#
+ .SYNOPSIS
+ Finds vstest.console.exe in PATH or known locations.
+ .DESCRIPTION
+ First checks PATH, then falls back to known VS installation paths.
+ #>
+
+ # Try PATH first (setup scripts add vstest to PATH)
+ $vstestFromPath = Get-Command "vstest.console.exe" -ErrorAction SilentlyContinue
+ if ($vstestFromPath) {
+ return $vstestFromPath.Source
+ }
+
+ $toolchain = Get-VsToolchainInfo -Requires @('Microsoft.Component.MSBuild')
+ if ($toolchain -and $toolchain.VSTestPath) {
+ return $toolchain.VSTestPath
+ }
+
+ return $null
}
# =============================================================================
@@ -283,9 +565,14 @@ function Get-VSTestPath {
# =============================================================================
Export-ModuleMember -Function @(
- 'Initialize-VsDevEnvironment',
+ 'Get-VsWherePath',
+ 'Get-VsInstallationInfo',
+ 'Get-VsToolchainInfo',
+ 'Get-VsDevEnvironmentVariables',
+ 'Test-VsDevEnvironmentActive',
+ 'Initialize-VsDevEnvironment',
'Test-CvtresCompatibility',
- 'Get-MSBuildPath',
- 'Invoke-MSBuild',
- 'Get-VSTestPath'
+ 'Get-MSBuildPath',
+ 'Invoke-MSBuild',
+ 'Get-VSTestPath'
)
diff --git a/Build/Agent/Run-VsTests.ps1 b/Build/Agent/Run-VsTests.ps1
index 64ed1c1540..9de229e6b0 100644
--- a/Build/Agent/Run-VsTests.ps1
+++ b/Build/Agent/Run-VsTests.ps1
@@ -54,6 +54,7 @@ param(
)
$ErrorActionPreference = 'Continue' # Don't stop on stderr output from vstest
+Import-Module (Join-Path $PSScriptRoot 'FwBuildEnvironment.psm1') -Force
# Find repo root (where FieldWorks.sln is)
$repoRoot = $PSScriptRoot
@@ -71,12 +72,7 @@ if (-not $OutputDir) {
}
$runSettings = Join-Path $repoRoot "Test.runsettings"
-$vsTestPath = "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe"
-
-if (-not (Test-Path $vsTestPath)) {
- # Try BuildTools path
- $vsTestPath = "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe"
-}
+$vsTestPath = Get-VSTestPath
if (-not (Test-Path $vsTestPath)) {
Write-Error "vstest.console.exe not found. Install Visual Studio 2022 or Build Tools."
diff --git a/Build/Agent/Setup-FwBuildEnv.ps1 b/Build/Agent/Setup-FwBuildEnv.ps1
index a95fe4c6f5..f6f4784d3a 100644
--- a/Build/Agent/Setup-FwBuildEnv.ps1
+++ b/Build/Agent/Setup-FwBuildEnv.ps1
@@ -35,6 +35,8 @@ param(
)
$ErrorActionPreference = 'Stop'
+$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+Import-Module (Join-Path $scriptDir 'FwBuildEnvironment.psm1') -Force
function Write-Status {
param([string]$Message, [string]$Status = "INFO", [string]$Color = "White")
@@ -97,7 +99,6 @@ Write-Host "OutputGitHubEnv: $OutputGitHubEnv"
Write-Host "Verify: $Verify"
Write-Host ""
-$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$repoRoot = Resolve-Path "$scriptDir\..\.."
# Set FW_ROOT_CODE_DIR and FW_ROOT_DATA_DIR for DirectoryFinder fallback
@@ -109,6 +110,7 @@ Set-EnvVar -Name "FW_ROOT_DATA_DIR" -Value $distFiles
$results = @{
VSPath = $null
MSBuildPath = $null
+ VSTestPath = $null
Errors = @()
}
@@ -117,31 +119,38 @@ $results = @{
# ----------------------------------------------------------------------------
Write-Host "--- Locating Visual Studio ---" -ForegroundColor Cyan
-$vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
-if (Test-Path $vsWhere) {
- $vsPath = & $vsWhere -latest -requires Microsoft.Component.MSBuild -products * -property installationPath
- if ($vsPath) {
- Write-Status "Visual Studio: $vsPath" -Status "OK"
- $results.VSPath = $vsPath
-
- # Set VS environment variables
- Set-EnvVar -Name "VSINSTALLDIR" -Value "$vsPath\"
- Set-EnvVar -Name "VCINSTALLDIR" -Value "$vsPath\VC\"
-
- # VCTargetsPath for C++ builds
- $vcTargets = Join-Path $vsPath 'MSBuild\Microsoft\VC\v170'
- if (Test-Path $vcTargets) {
- Set-EnvVar -Name "VCTargetsPath" -Value $vcTargets
- }
+$toolchain = Get-VsToolchainInfo -Requires @('Microsoft.Component.MSBuild', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64')
+if ($toolchain) {
+ $results.VSPath = $toolchain.InstallationPath
+ $results.MSBuildPath = $toolchain.MSBuildPath
+ $results.VSTestPath = $toolchain.VSTestPath
+
+ if ([string]::IsNullOrWhiteSpace($toolchain.DisplayVersion)) {
+ Write-Status "Visual Studio: $($toolchain.InstallationPath)" -Status "OK"
}
else {
- Write-Status "Visual Studio not found via vswhere" -Status "FAIL"
- $results.Errors += "Visual Studio not found"
+ Write-Status "Visual Studio $($toolchain.DisplayVersion): $($toolchain.InstallationPath)" -Status "OK"
+ }
+
+ # Export installation hints only; build/test scripts still self-initialize via VsDevCmd.
+ Set-EnvVar -Name "VSINSTALLDIR" -Value ($toolchain.InstallationPath.TrimEnd('\') + '\')
+ if ($toolchain.VcInstallDir) {
+ Set-EnvVar -Name "VCINSTALLDIR" -Value ($toolchain.VcInstallDir.TrimEnd('\') + '\')
+ }
+ if ($toolchain.VCTargetsPath) {
+ Set-EnvVar -Name "VCTargetsPath" -Value $toolchain.VCTargetsPath
}
}
else {
- Write-Status "vswhere.exe not found at: $vsWhere" -Status "FAIL"
- $results.Errors += "vswhere.exe not found"
+ $vsWhere = Get-VsWherePath
+ if ($vsWhere) {
+ Write-Status "Visual Studio with MSBuild and C++ tools not found" -Status "FAIL"
+ $results.Errors += "Visual Studio with MSBuild and C++ tools not found"
+ }
+ else {
+ Write-Status "vswhere.exe not found" -Status "FAIL"
+ $results.Errors += "vswhere.exe not found"
+ }
}
# ----------------------------------------------------------------------------
@@ -150,25 +159,11 @@ else {
Write-Host ""
Write-Host "--- Locating MSBuild ---" -ForegroundColor Cyan
-$msbuildCandidates = @()
-if ($results.VSPath) {
- $msbuildCandidates += Join-Path $results.VSPath 'MSBuild\Current\Bin\MSBuild.exe'
- $msbuildCandidates += Join-Path $results.VSPath 'MSBuild\Current\Bin\amd64\MSBuild.exe'
-}
-$msbuildCandidates += "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\MSBuild.exe"
-$msbuildCandidates += "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2022\BuildTools\MSBuild\Current\Bin\MSBuild.exe"
-$msbuildCandidates += "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\MSBuild.exe"
-$msbuildCandidates += "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\MSBuild.exe"
-
-foreach ($candidate in $msbuildCandidates) {
- if (Test-Path $candidate) {
- $results.MSBuildPath = $candidate
- Write-Status "MSBuild: $candidate" -Status "OK"
- break
- }
+if ($results.MSBuildPath) {
+ Write-Status "MSBuild: $($results.MSBuildPath)" -Status "OK"
+ Add-ToPath -Path (Split-Path -Parent $results.MSBuildPath) | Out-Null
}
-
-if (-not $results.MSBuildPath) {
+else {
Write-Status "MSBuild not found" -Status "FAIL"
$results.Errors += "MSBuild not found"
}
@@ -203,37 +198,12 @@ if (-not $foundNetfx) {
Write-Host ""
Write-Host "--- Locating VSTest ---" -ForegroundColor Cyan
-$vstestPath = $null
-$vstestCandidates = @()
-
-# Check VS installation paths first
-if ($results.VSPath) {
- $vstestCandidates += Join-Path $results.VSPath 'Common7\IDE\CommonExtensions\Microsoft\TestWindow'
-}
-
-# Add known installation paths (BuildTools, TestAgent, etc.)
-$vstestCandidates += @(
- 'C:\BuildTools\Common7\IDE\CommonExtensions\Microsoft\TestWindow',
- "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2022\BuildTools\Common7\IDE\CommonExtensions\Microsoft\TestWindow",
- "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2022\TestAgent\Common7\IDE\CommonExtensions\Microsoft\TestWindow",
- "${env:ProgramFiles}\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TestWindow",
- "${env:ProgramFiles}\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\TestWindow",
- "${env:ProgramFiles}\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\TestWindow"
-)
-
-foreach ($candidate in $vstestCandidates) {
- if ($candidate -and (Test-Path (Join-Path $candidate 'vstest.console.exe'))) {
- $vstestPath = $candidate
- Add-ToPath -Path $vstestPath | Out-Null
- break
- }
-}
-
-if (-not $vstestPath) {
- Write-Status "vstest.console.exe not found" -Status "WARN"
+if ($results.VSTestPath) {
+ Add-ToPath -Path (Split-Path -Parent $results.VSTestPath) | Out-Null
+ Write-Status "VSTest: $($results.VSTestPath)" -Status "OK"
}
else {
- Write-Status "VSTest: $vstestPath" -Status "OK"
+ Write-Status "vstest.console.exe not found" -Status "WARN"
}
# ----------------------------------------------------------------------------
@@ -246,6 +216,7 @@ Write-Host "=== Setup Complete ===" -ForegroundColor Cyan
if ($OutputGitHubEnv -and $env:GITHUB_OUTPUT) {
"msbuild-path=$($results.MSBuildPath)" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
"vs-install-path=$($results.VSPath)" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
+ "vstest-path=$($results.VSTestPath)" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
}
# Return results object for programmatic use
diff --git a/Build/Agent/Setup-InstallerBuild.ps1 b/Build/Agent/Setup-InstallerBuild.ps1
index 32f6e4ae92..5d076a60b3 100644
--- a/Build/Agent/Setup-InstallerBuild.ps1
+++ b/Build/Agent/Setup-InstallerBuild.ps1
@@ -47,6 +47,43 @@ param(
$ErrorActionPreference = 'Stop'
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$repoRoot = Split-Path -Parent (Split-Path -Parent $scriptDir)
+Import-Module (Join-Path $scriptDir 'FwBuildEnvironment.psm1') -Force
+
+function Get-InstallerBuildCommand {
+ param(
+ [Parameter(Mandatory)]
+ [ValidateSet('RestorePackages', 'BuildInstaller', 'BuildPatchInstaller')]
+ [string]$Target
+ )
+
+ $arguments = @(
+ 'msbuild Build/InstallerBuild.proj',
+ "/t:$Target",
+ '/p:Configuration=Release',
+ '/p:Platform=x64'
+ )
+
+ if ($Target -ne 'RestorePackages') {
+ $arguments += @('/m', '/v:n')
+ }
+
+ return $arguments -join ' '
+}
+
+function Get-WrappedInstallerBuildCommand {
+ param(
+ [Parameter(Mandatory)]
+ [string]$VsDevCmdPath,
+ [Parameter(Mandatory)]
+ [string]$Command
+ )
+
+ return 'cmd /c "call ""{0}"" -arch=amd64 >nul && {1}"' -f $VsDevCmdPath, $Command
+}
+
+$restoreCommand = Get-InstallerBuildCommand -Target 'RestorePackages'
+$buildCommand = Get-InstallerBuildCommand -Target 'BuildInstaller'
+$patchCommand = Get-InstallerBuildCommand -Target 'BuildPatchInstaller'
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " FieldWorks Installer Build Setup" -ForegroundColor Cyan
@@ -55,6 +92,10 @@ Write-Host ""
$issues = @()
$warnings = @()
+$vsDevEnvActive = $false
+$restoreWrappedCommand = $null
+$buildWrappedCommand = $null
+$patchWrappedCommand = $null
#region WiX Toolset Validation
@@ -90,57 +131,41 @@ if (Test-Path $heatFromRepoPackages) {
Write-Host "`n--- Checking Visual Studio / MSBuild ---" -ForegroundColor Yellow
-$vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
-$vsInstall = $null
-$vsDevEnvActive = $false
+$toolchain = Get-VsToolchainInfo -Requires @('Microsoft.Component.MSBuild', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64')
+$vsDevEnvActive = Test-VsDevEnvironmentActive
-if (Test-Path $vsWhere) {
- $vsInstall = & $vsWhere -latest -property installationPath 2>$null
- if ($vsInstall) {
- $vsVersion = & $vsWhere -latest -property catalog_productDisplayVersion 2>$null
+if ($toolchain) {
+ $vsVersion = if ([string]::IsNullOrWhiteSpace($toolchain.DisplayVersion)) { 'unknown version' } else { $toolchain.DisplayVersion }
Write-Host "[OK] Visual Studio 2022: $vsVersion" -ForegroundColor Green
- # Check for MSBuild
- $msbuildPath = Join-Path $vsInstall "MSBuild\Current\Bin\MSBuild.exe"
- if (Test-Path $msbuildPath) {
- Write-Host "[OK] MSBuild found: $msbuildPath" -ForegroundColor Green
+ if ($toolchain.MSBuildPath) {
+ Write-Host "[OK] MSBuild found: $($toolchain.MSBuildPath)" -ForegroundColor Green
} else {
$issues += "MSBuild not found in VS installation"
}
- # Check for VsDevCmd
- $vsDevCmd = Join-Path $vsInstall "Common7\Tools\VsDevCmd.bat"
- $launchVsDevShell = Join-Path $vsInstall "Common7\Tools\Launch-VsDevShell.ps1"
- if ((Test-Path $vsDevCmd) -or (Test-Path $launchVsDevShell)) {
+ if ($toolchain.VsDevCmdPath) {
Write-Host "[OK] VS Developer environment scripts available" -ForegroundColor Green
+ $restoreWrappedCommand = Get-WrappedInstallerBuildCommand -VsDevCmdPath $toolchain.VsDevCmdPath -Command $restoreCommand
+ $buildWrappedCommand = Get-WrappedInstallerBuildCommand -VsDevCmdPath $toolchain.VsDevCmdPath -Command $buildCommand
+ $patchWrappedCommand = Get-WrappedInstallerBuildCommand -VsDevCmdPath $toolchain.VsDevCmdPath -Command $patchCommand
+ } else {
+ $issues += "VsDevCmd.bat not found in VS installation"
}
- # Check if VS Developer environment is active (nmake in PATH)
- $nmake = Get-Command nmake.exe -ErrorAction SilentlyContinue
- if ($nmake) {
- Write-Host "[OK] VS Developer environment active (nmake in PATH)" -ForegroundColor Green
- $vsDevEnvActive = $true
+ if ($vsDevEnvActive) {
+ Write-Host "[OK] VS Developer environment active" -ForegroundColor Green
} else {
- # Check if nmake exists in VS installation
- $nmakePath = Join-Path $vsInstall "VC\Tools\MSVC\*\bin\Hostx64\x64\nmake.exe"
- $nmakeExists = Get-ChildItem -Path $nmakePath -ErrorAction SilentlyContinue | Select-Object -First 1
- if ($nmakeExists) {
Write-Host "[WARN] VS Developer environment NOT active" -ForegroundColor Yellow
- Write-Host " nmake.exe exists but is not in PATH" -ForegroundColor Yellow
- Write-Host " Run builds from VS Developer Command Prompt or use:" -ForegroundColor Yellow
- Write-Host " cmd /c `"call `"$vsDevCmd`" -arch=amd64 && msbuild ...`"" -ForegroundColor Cyan
- $warnings += "VS Developer environment not active (nmake not in PATH)"
- } else {
- Write-Host "[MISSING] C++ build tools (nmake.exe) not found" -ForegroundColor Red
- Write-Host " Install 'Desktop development with C++' workload in VS Installer" -ForegroundColor Red
- $issues += "C++ build tools not installed (nmake.exe missing)"
- }
- }
- } else {
- $issues += "Visual Studio 2022 not installed"
+ Write-Host " Run builds from VS Developer Command Prompt or use the detected VsDevCmd wrapper commands below" -ForegroundColor Yellow
+ $warnings += "VS Developer environment not active"
}
} else {
+ if (Get-VsWherePath) {
+ $issues += "Visual Studio 2022 with MSBuild and C++ tools not installed"
+ } else {
$issues += "Visual Studio Installer not found"
+ }
}
#endregion
@@ -327,15 +352,15 @@ if ($issues.Count -eq 0) {
# VS Developer environment is active, show simple commands
Write-Host ""
Write-Host " # Restore packages" -ForegroundColor Gray
- Write-Host " msbuild Build/InstallerBuild.proj /t:RestorePackages /p:Configuration=Release /p:Platform=x64" -ForegroundColor Cyan
+ Write-Host " $restoreCommand" -ForegroundColor Cyan
Write-Host ""
Write-Host " # Build base installer" -ForegroundColor Gray
- Write-Host " msbuild Build/InstallerBuild.proj /t:BuildInstaller /p:Configuration=Release /p:Platform=x64 /p:config=release /m /v:n" -ForegroundColor Cyan
+ Write-Host " $buildCommand" -ForegroundColor Cyan
Write-Host ""
if ($SetupPatch) {
Write-Host " # Build patch installer" -ForegroundColor Gray
- Write-Host " msbuild Build/InstallerBuild.proj /t:BuildPatchInstaller /p:Configuration=Release /p:Platform=x64 /p:config=release /m /v:n" -ForegroundColor Cyan
+ Write-Host " $patchCommand" -ForegroundColor Cyan
Write-Host ""
}
} else {
@@ -344,17 +369,21 @@ if ($issues.Count -eq 0) {
Write-Host " # Option 1: Open VS Developer Command Prompt and run commands there" -ForegroundColor Gray
Write-Host " # Option 2: Use these one-liner commands from any PowerShell:" -ForegroundColor Gray
Write-Host ""
- Write-Host " # Restore packages" -ForegroundColor Gray
- Write-Host ' cmd /c "call ""C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat"" -arch=amd64 >nul && msbuild Build/InstallerBuild.proj /t:RestorePackages /p:Configuration=Release /p:Platform=x64"' -ForegroundColor Cyan
- Write-Host ""
- Write-Host " # Build base installer" -ForegroundColor Gray
- Write-Host ' cmd /c "call ""C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat"" -arch=amd64 >nul && msbuild Build/InstallerBuild.proj /t:BuildInstaller /p:Configuration=Release /p:Platform=x64 /p:config=release /m /v:n"' -ForegroundColor Cyan
- Write-Host ""
-
- if ($SetupPatch) {
- Write-Host " # Build patch installer" -ForegroundColor Gray
- Write-Host ' cmd /c "call ""C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat"" -arch=amd64 >nul && msbuild Build/InstallerBuild.proj /t:BuildPatchInstaller /p:Configuration=Release /p:Platform=x64 /p:config=release /m /v:n"' -ForegroundColor Cyan
+ if ($restoreWrappedCommand -and $buildWrappedCommand) {
+ Write-Host " # Restore packages" -ForegroundColor Gray
+ Write-Host " $restoreWrappedCommand" -ForegroundColor Cyan
+ Write-Host ""
+ Write-Host " # Build base installer" -ForegroundColor Gray
+ Write-Host " $buildWrappedCommand" -ForegroundColor Cyan
Write-Host ""
+
+ if ($SetupPatch -and $patchWrappedCommand) {
+ Write-Host " # Build patch installer" -ForegroundColor Gray
+ Write-Host " $patchWrappedCommand" -ForegroundColor Cyan
+ Write-Host ""
+ }
+ } else {
+ Write-Host " Unable to derive a VsDevCmd wrapper command for this installation." -ForegroundColor Yellow
}
}
diff --git a/Build/Agent/Verify-FwDependencies.ps1 b/Build/Agent/Verify-FwDependencies.ps1
index 10c943dc16..60250ad7a4 100644
--- a/Build/Agent/Verify-FwDependencies.ps1
+++ b/Build/Agent/Verify-FwDependencies.ps1
@@ -5,6 +5,8 @@
.DESCRIPTION
Checks for required tools and SDKs needed to build FieldWorks.
Can be run locally for testing or called from GitHub Actions workflows.
+ By default, the script writes host output only and does not emit result objects.
+ Use -PassThru when a caller needs structured results returned on the pipeline.
Expected dependencies (typically pre-installed on windows-latest):
- Visual Studio 2022 with Desktop & C++ workloads
@@ -24,7 +26,8 @@
If specified, prints the full per-dependency section headers and success details instead of the compact summary-only output.
.PARAMETER PassThru
- If specified, returns the dependency result objects for scripting callers instead of writing them implicitly.
+ If specified, returns the dependency result objects for scripting callers.
+ Without -PassThru, the script is quiet-by-default and writes host output only.
.EXAMPLE
# Quick check
@@ -45,6 +48,9 @@
.EXAMPLE
# Capture structured results for automation
$results = .\Build\Agent\Verify-FwDependencies.ps1 -IncludeOptional -PassThru
+
+.NOTES
+ Behavioral change: this script no longer emits dependency result objects unless -PassThru is specified.
#>
[CmdletBinding()]
@@ -56,6 +62,7 @@ param(
)
$ErrorActionPreference = 'Stop'
+Import-Module (Join-Path $PSScriptRoot 'FwBuildEnvironment.psm1') -Force
function Test-Dependency {
param(
@@ -158,12 +165,14 @@ $results += Test-Dependency -Name "Windows SDK" -Check {
# Visual Studio / MSBuild
$results += Test-Dependency -Name "Visual Studio 2022" -Check {
- $vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
- if (-not (Test-Path $vsWhere)) { throw "vswhere.exe not found" }
- $vsPath = & $vsWhere -latest -requires Microsoft.Component.MSBuild -products * -property installationPath
- if (-not $vsPath) { throw "No VS installation with MSBuild found" }
- $version = & $vsWhere -latest -property catalog_productDisplayVersion
- return "Version $version at $vsPath"
+ $vsInfo = Get-VsInstallationInfo -Requires @('Microsoft.Component.MSBuild', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64')
+ if (-not $vsInfo) {
+ $vsWhere = Get-VsWherePath
+ if (-not $vsWhere) { throw "vswhere.exe not found" }
+ throw "No VS installation with MSBuild and C++ tools found"
+ }
+
+ return "Version $($vsInfo.DisplayVersion) at $($vsInfo.InstallationPath)"
}
# MSBuild
@@ -173,11 +182,9 @@ $results += Test-Dependency -Name "MSBuild" -Check {
$version = (& msbuild.exe -version -nologo 2>$null | Select-Object -Last 1)
return "Version $version"
}
- # Try via vswhere
- $vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
- $vsPath = & $vsWhere -latest -requires Microsoft.Component.MSBuild -products * -property installationPath 2>$null
- if ($vsPath) {
- $msbuildPath = Join-Path $vsPath 'MSBuild\Current\Bin\MSBuild.exe'
+ $vsInfo = Get-VsInstallationInfo -Requires @('Microsoft.Component.MSBuild')
+ if ($vsInfo) {
+ $msbuildPath = Join-Path $vsInfo.InstallationPath 'MSBuild\Current\Bin\MSBuild.exe'
if (Test-Path $msbuildPath) {
return "Found at $msbuildPath (not in PATH)"
}
@@ -217,7 +224,7 @@ $results += Test-Dependency -Name "WiX Toolset (v6 via NuGet)" -Required "Option
throw "Installer project not found: $wixProj"
}
- [xml]$wixProjXml = Get-Content -LiteralPath $wixProj
+ [xml]$wixProjXml = Get-Content -LiteralPath $wixProj -Raw
$projectNode = $wixProjXml.Project
$hasWixSdk = $false
diff --git a/Build/Agent/fix-whitespace.ps1 b/Build/Agent/fix-whitespace.ps1
index 324a254a2f..1933489889 100644
--- a/Build/Agent/fix-whitespace.ps1
+++ b/Build/Agent/fix-whitespace.ps1
@@ -78,7 +78,7 @@ if (Test-Path -LiteralPath 'check-results.log') {
if (-not $fixFiles -or $fixFiles.Count -eq 0) {
$base = Get-BaseRef
Write-Host "Fixing whitespace for files changed since $base..HEAD"
- $fixFiles = git diff --name-only "$base"..HEAD
+ $fixFiles = git diff --name-only "$base..HEAD"
}
$files = $fixFiles | Where-Object { $_ -and (Test-Path $_) }
diff --git a/Build/FieldWorks.Toolchain.props b/Build/FieldWorks.Toolchain.props
new file mode 100644
index 0000000000..e1b0a2e65e
--- /dev/null
+++ b/Build/FieldWorks.Toolchain.props
@@ -0,0 +1,13 @@
+
+
+
+ 17
+ [17.0,18.0)
+ v170
+ v143
+ 17.0
+
+
diff --git a/Build/Src/FwBuildTasks/BuildUtils.cs b/Build/Src/FwBuildTasks/BuildUtils.cs
index 0484dd09d2..cf69ecd8b5 100644
--- a/Build/Src/FwBuildTasks/BuildUtils.cs
+++ b/Build/Src/FwBuildTasks/BuildUtils.cs
@@ -11,6 +11,7 @@
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Xml.Xsl;
+using System.Xml.Linq;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
@@ -24,6 +25,7 @@ public static class BuildUtils
{
public static bool IsUnix => Environment.OSVersion.Platform == PlatformID.Unix;
private const string NetFxLegacyVersionFolder = "v4.0.30319";
+ private const string ToolchainPolicyRelativePath = "Build\\FieldWorks.Toolchain.props";
private static readonly string[] NetFxFrameworkFolders = { "Framework64", "Framework" };
///
@@ -267,19 +269,92 @@ public static string ResolveDotNetFrameworkAssemblyPath(string assemblyFileName)
$"Probed: {string.Join("; ", probeLog.Distinct())}");
}
- private static IEnumerable GetToolLocationHelperCandidates(string toolName, ICollection probeLog)
+ private static string FindToolchainPolicyFile()
{
- var candidates = new List();
+ var repoRoot = Environment.GetEnvironmentVariable("FW_ROOT_CODE_DIR");
+ if (!String.IsNullOrWhiteSpace(repoRoot))
+ {
+ var repoCandidate = Path.Combine(repoRoot, ToolchainPolicyRelativePath);
+ if (File.Exists(repoCandidate))
+ return repoCandidate;
+ }
+
+ for (var directory = new DirectoryInfo(GetAssemblyFolder()); directory != null; directory = directory.Parent)
+ {
+ var candidate = Path.Combine(directory.FullName, ToolchainPolicyRelativePath);
+ if (File.Exists(candidate))
+ return candidate;
+ }
+
+ return null;
+ }
+
+ private static string GetToolchainPolicyProperty(string propertyName)
+ {
+ var policyFile = FindToolchainPolicyFile();
+ if (String.IsNullOrEmpty(policyFile))
+ return null;
+
try
{
- candidates.Add(ToolLocationHelper.GetPathToDotNetFrameworkSdkFile(
- toolName,
- TargetDotNetFrameworkVersion.Version48,
- VisualStudioVersion.Version170,
- DotNetFrameworkArchitecture.Bitness64));
+ var policyDocument = XDocument.Load(policyFile);
+ if (policyDocument.Root == null)
+ return null;
+
+ return policyDocument.Root
+ .Elements("PropertyGroup")
+ .Elements(propertyName)
+ .Select(element => element.Value == null ? null : element.Value.Trim())
+ .FirstOrDefault(value => !String.IsNullOrEmpty(value));
}
catch
{
+ return null;
+ }
+ }
+
+ private static VisualStudioVersion? GetConfiguredDotNetFrameworkSdkVisualStudioVersion()
+ {
+ switch (GetToolchainPolicyProperty("FwDotNetFrameworkSdkVisualStudioVersion"))
+ {
+ case "10.0":
+ return VisualStudioVersion.Version100;
+ case "11.0":
+ return VisualStudioVersion.Version110;
+ case "12.0":
+ return VisualStudioVersion.Version120;
+ case "14.0":
+ return VisualStudioVersion.Version140;
+ case "15.0":
+ return VisualStudioVersion.Version150;
+ case "16.0":
+ return VisualStudioVersion.Version160;
+ case "17.0":
+ return VisualStudioVersion.Version170;
+ case "18.0":
+ return VisualStudioVersion.Version180;
+ default:
+ return null;
+ }
+ }
+
+ private static IEnumerable GetToolLocationHelperCandidates(string toolName, ICollection probeLog)
+ {
+ var candidates = new List();
+ var configuredVisualStudioVersion = GetConfiguredDotNetFrameworkSdkVisualStudioVersion();
+ if (configuredVisualStudioVersion.HasValue)
+ {
+ try
+ {
+ candidates.Add(ToolLocationHelper.GetPathToDotNetFrameworkSdkFile(
+ toolName,
+ TargetDotNetFrameworkVersion.Version48,
+ configuredVisualStudioVersion.Value,
+ DotNetFrameworkArchitecture.Bitness64));
+ }
+ catch
+ {
+ }
}
try
diff --git a/Build/Src/FwBuildTasks/Make.cs b/Build/Src/FwBuildTasks/Make.cs
index 55458e919d..4a91985688 100644
--- a/Build/Src/FwBuildTasks/Make.cs
+++ b/Build/Src/FwBuildTasks/Make.cs
@@ -111,9 +111,21 @@ protected override string ToolName
}
}
+ private static string FindToolInDirectory(string directory, string toolName)
+ {
+ if (String.IsNullOrEmpty(directory) || !Directory.Exists(directory))
+ return null;
+
+ if (File.Exists(Path.Combine(directory, toolName)))
+ return directory;
+
+ return null;
+ }
+
private void CheckToolPath()
{
string path = Environment.GetEnvironmentVariable("PATH");
+ string vcToolsInstallDir = Environment.GetEnvironmentVariable("VCToolsInstallDir");
string vcInstallDir = Environment.GetEnvironmentVariable("VCINSTALLDIR");
//Console.WriteLine("DEBUG Make Task: PATH='{0}'", path);
string makePath = ToolPath == null ? String.Empty : ToolPath.Trim();
@@ -128,7 +140,7 @@ private void CheckToolPath()
if (File.Exists(Path.Combine(ToolPath, ToolName)))
return;
}
- string[] splitPath = path.Split(new char[] { Path.PathSeparator });
+ string[] splitPath = String.IsNullOrEmpty(path) ? new string[0] : path.Split(new[] { Path.PathSeparator });
foreach (var dir in splitPath)
{
if (File.Exists(Path.Combine(dir, ToolName)))
@@ -137,10 +149,27 @@ private void CheckToolPath()
return;
}
}
- // Fall Back to the install directory (if VCINSTALLDIR is set)
+ if (!String.IsNullOrEmpty(vcToolsInstallDir))
+ {
+ string activeToolPath = FindToolInDirectory(Path.Combine(vcToolsInstallDir, "bin", "Hostx64", "x64"), ToolName);
+ if (!String.IsNullOrEmpty(activeToolPath))
+ {
+ ToolPath = activeToolPath;
+ return;
+ }
+ }
+
+ // Fall back to the legacy VC install directory (if VCINSTALLDIR is set)
if (!String.IsNullOrEmpty(vcInstallDir))
{
- ToolPath = Path.Combine(vcInstallDir, "bin");
+ string legacyToolPath = FindToolInDirectory(Path.Combine(vcInstallDir, "bin"), ToolName);
+ if (!String.IsNullOrEmpty(legacyToolPath))
+ {
+ ToolPath = legacyToolPath;
+ return;
+ }
+
+ ToolPath = String.Empty;
}
else
{
diff --git a/Directory.Build.props b/Directory.Build.props
index 7495546d05..58dd34ad0e 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,4 +1,8 @@
+
+
+
true
diff --git a/Lib/src/unit++/VS/unit++.vcxproj b/Lib/src/unit++/VS/unit++.vcxproj
index 29bfc46673..f82f49fc28 100644
--- a/Lib/src/unit++/VS/unit++.vcxproj
+++ b/Lib/src/unit++/VS/unit++.vcxproj
@@ -19,12 +19,12 @@
StaticLibrary
MultiByte
- v143
+ $(FwPlatformToolset)
StaticLibrary
MultiByte
- v143
+ $(FwPlatformToolset)
@@ -96,4 +96,4 @@
-
\ No newline at end of file
+
diff --git a/Setup-Developer-Machine.ps1 b/Setup-Developer-Machine.ps1
index e2526a7520..05d96cee49 100644
--- a/Setup-Developer-Machine.ps1
+++ b/Setup-Developer-Machine.ps1
@@ -26,6 +26,8 @@ param(
$ErrorActionPreference = 'Stop'
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+Import-Module (Join-Path $scriptDir 'Build\Agent\FwBuildEnvironment.psm1') -Force
+$vsToolchain = $null
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " FieldWorks Developer Machine Setup" -ForegroundColor Cyan
@@ -57,22 +59,16 @@ if ($git) {
# Check Visual Studio 2022
if (-not $SkipVSCheck) {
- $vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
- if (Test-Path $vsWhere) {
- $vsInstall = & $vsWhere -latest -property installationPath 2>$null
- if ($vsInstall) {
- $vsVersion = & $vsWhere -latest -property catalog_productDisplayVersion 2>$null
- Write-Host "[OK] Visual Studio 2022: $vsVersion" -ForegroundColor Green
-
- # Check required workloads
- $workloads = & $vsWhere -latest -property catalog_productLineVersion 2>$null
- Write-Host " Location: $vsInstall" -ForegroundColor Gray
- } else {
- Write-Host "[MISSING] Visual Studio 2022 - Please install with:" -ForegroundColor Red
- Write-Host " - .NET desktop development workload" -ForegroundColor Red
- Write-Host " - Desktop development with C++ workload" -ForegroundColor Red
- exit 1
- }
+ $vsToolchain = Get-VsToolchainInfo -Requires @('Microsoft.Component.MSBuild', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64')
+ if ($vsToolchain) {
+ $vsVersion = if ([string]::IsNullOrWhiteSpace($vsToolchain.DisplayVersion)) { 'unknown version' } else { $vsToolchain.DisplayVersion }
+ Write-Host "[OK] Visual Studio 2022: $vsVersion" -ForegroundColor Green
+ Write-Host " Location: $($vsToolchain.InstallationPath)" -ForegroundColor Gray
+ } elseif (Get-VsWherePath) {
+ Write-Host "[MISSING] Visual Studio 2022 - Please install with:" -ForegroundColor Red
+ Write-Host " - .NET desktop development workload" -ForegroundColor Red
+ Write-Host " - Desktop development with C++ workload" -ForegroundColor Red
+ exit 1
} else {
Write-Host "[MISSING] Visual Studio 2022 - Please install from https://visualstudio.microsoft.com/" -ForegroundColor Red
exit 1
@@ -245,15 +241,12 @@ Write-Host "`n--- Configuring PATH ---" -ForegroundColor Yellow
$pathsToAdd = @()
# VSTest (Visual Studio 2022)
-$vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
-if (Test-Path $vsWhere) {
- $vsInstall = & $vsWhere -latest -property installationPath 2>$null
- if ($vsInstall) {
- $vstestPath = Join-Path $vsInstall 'Common7\IDE\CommonExtensions\Microsoft\TestWindow'
- if (Test-Path (Join-Path $vstestPath 'vstest.console.exe')) {
- $pathsToAdd += $vstestPath
- }
- }
+if (-not $vsToolchain -and -not $SkipVSCheck) {
+ $vsToolchain = Get-VsToolchainInfo -Requires @('Microsoft.Component.MSBuild', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64')
+}
+
+if ($vsToolchain -and $vsToolchain.VSTestPath) {
+ $pathsToAdd += (Split-Path -Parent $vsToolchain.VSTestPath)
}
# Update PATH
diff --git a/Src/DebugProcs/DebugProcs.vcxproj b/Src/DebugProcs/DebugProcs.vcxproj
index ddb0c867e2..a2debafda4 100644
--- a/Src/DebugProcs/DebugProcs.vcxproj
+++ b/Src/DebugProcs/DebugProcs.vcxproj
@@ -23,11 +23,11 @@
Makefile
- v143
+ $(FwPlatformToolset)
Makefile
- v143
+ $(FwPlatformToolset)
@@ -84,4 +84,4 @@
-
\ No newline at end of file
+
diff --git a/Src/Generic/Generic.vcxproj b/Src/Generic/Generic.vcxproj
index 6685a478b5..dc847d87c2 100644
--- a/Src/Generic/Generic.vcxproj
+++ b/Src/Generic/Generic.vcxproj
@@ -30,15 +30,15 @@
Makefile
- v143
+ $(FwPlatformToolset)
Makefile
- v143
+ $(FwPlatformToolset)
Makefile
- v143
+ $(FwPlatformToolset)
diff --git a/Src/Generic/Test/TestGeneric.vcxproj b/Src/Generic/Test/TestGeneric.vcxproj
index 895df81cbe..17eb8439d6 100644
--- a/Src/Generic/Test/TestGeneric.vcxproj
+++ b/Src/Generic/Test/TestGeneric.vcxproj
@@ -43,13 +43,13 @@
Application
- v143
+ $(FwPlatformToolset)
NotSet
true
Application
- v143
+ $(FwPlatformToolset)
NotSet
false
true
diff --git a/Src/Kernel/Kernel.vcxproj b/Src/Kernel/Kernel.vcxproj
index 438e89476f..1e5e3c0a62 100644
--- a/Src/Kernel/Kernel.vcxproj
+++ b/Src/Kernel/Kernel.vcxproj
@@ -26,11 +26,11 @@
Makefile
- v143
+ $(FwPlatformToolset)
Makefile
- v143
+ $(FwPlatformToolset)
@@ -84,4 +84,3 @@
-
diff --git a/Src/LexText/ParserCore/XAmpleCOMWrapper/XAmpleCOMWrapper.vcxproj b/Src/LexText/ParserCore/XAmpleCOMWrapper/XAmpleCOMWrapper.vcxproj
index 67bc3bdd13..4378e22621 100644
--- a/Src/LexText/ParserCore/XAmpleCOMWrapper/XAmpleCOMWrapper.vcxproj
+++ b/Src/LexText/ParserCore/XAmpleCOMWrapper/XAmpleCOMWrapper.vcxproj
@@ -24,19 +24,19 @@
DynamicLibrary
Static
MultiByte
- v143
+ $(FwPlatformToolset)
DynamicLibrary
Static
MultiByte
- v143
+ $(FwPlatformToolset)
DynamicLibrary
Static
MultiByte
- v143
+ $(FwPlatformToolset)
@@ -224,4 +224,4 @@
-
\ No newline at end of file
+
diff --git a/Src/Utilities/pcpatrflex/DisambiguateInFLExDB/DisambiguateInFLExDBTests/ToneParsInvokerTests.cs b/Src/Utilities/pcpatrflex/DisambiguateInFLExDB/DisambiguateInFLExDBTests/ToneParsInvokerTests.cs
index 898a185dee..a41d47ef96 100644
--- a/Src/Utilities/pcpatrflex/DisambiguateInFLExDB/DisambiguateInFLExDBTests/ToneParsInvokerTests.cs
+++ b/Src/Utilities/pcpatrflex/DisambiguateInFLExDB/DisambiguateInFLExDBTests/ToneParsInvokerTests.cs
@@ -192,18 +192,25 @@ private string NormalizeContent(string input)
private static string NormalizeViaIndex(string input, string match, string change)
{
- // I tried to use regular expressions but never got them to match...
- int iAppData = input.IndexOf(match);
- if (iAppData != -1)
+ int searchStart = 0;
+ while (searchStart < input.Length)
{
- int iColon = input.IndexOf(":");
- if (iColon != -1)
+ int matchIndex = input.IndexOf(match, searchStart, StringComparison.OrdinalIgnoreCase);
+ if (matchIndex == -1)
+ return input;
+
+ int colonIndex = input.LastIndexOf(':', matchIndex);
+ if (colonIndex > 0)
{
- iColon--; // skip the drive letter, too
- string appdataPath = input.Substring(iColon, iAppData - iColon);
- input = input.Replace(appdataPath, change);
+ int pathStart = colonIndex - 1;
+ input = input.Remove(pathStart, matchIndex - pathStart).Insert(pathStart, change);
+ searchStart = pathStart + change.Length + match.Length;
+ continue;
}
+
+ searchStart = matchIndex + match.Length;
}
+
return input;
}
diff --git a/Src/views/Test/TestViews.vcxproj b/Src/views/Test/TestViews.vcxproj
index 033270aa47..16b1166024 100644
--- a/Src/views/Test/TestViews.vcxproj
+++ b/Src/views/Test/TestViews.vcxproj
@@ -51,13 +51,13 @@
Application
- v143
+ $(FwPlatformToolset)
NotSet
true
Application
- v143
+ $(FwPlatformToolset)
NotSet
false
true
diff --git a/Src/views/views.vcxproj b/Src/views/views.vcxproj
index bc15e8bf27..1b846d0c43 100644
--- a/Src/views/views.vcxproj
+++ b/Src/views/views.vcxproj
@@ -30,17 +30,17 @@
Makefile
- v143
+ $(FwPlatformToolset)
false
Makefile
- v143
+ $(FwPlatformToolset)
false
Makefile
- v143
+ $(FwPlatformToolset)
false
@@ -217,4 +217,3 @@
-