| #!/usr/bin/env pswd | |
| ############################################################################ | |
| # tools/testbuild.ps1 | |
| # PowerShell script for CI on Windows Native | |
| # | |
| # SPDX-License-Identifier: Apache-2.0 | |
| # | |
| # Licensed to the Apache Software Foundation (ASF) under one or more | |
| # contributor license agreements. See the NOTICE file distributed with | |
| # this work for additional information regarding copyright ownership. The | |
| # ASF licenses this file to you under the Apache License, Version 2.0 (the | |
| # "License"); you may not use this file except in compliance with the | |
| # License. You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
| # License for the specific language governing permissions and limitations | |
| # under the License. | |
| # | |
| ############################################################################ | |
| # Set-PSDebug -Trace 0 | |
| $progname = $($MyInvocation.MyCommand.Name) | |
| $WD = Resolve-Path("Get-Location\..\..\..\..") | |
| $nuttx = "$WD\nuttx" | |
| $global:fail = 0 | |
| $APPSDIR = "$WD\apps" | |
| if ($null -eq $ARTIFACTDIR) { | |
| $ARTIFACTDIR = "$WD\buildartifacts" | |
| } | |
| $PRINTLISTONLY = 0 | |
| $GITCLEAN = 0 | |
| $SAVEARTIFACTS = 0 | |
| $CHECKCLEAN = 1 | |
| $CODECHECKER = 0 | |
| $NINJACMAKE = 0 | |
| $RUN = 0 | |
| $MSVC = 0 | |
| function showusage { | |
| Write-Host "" | |
| Write-Host "USAGE: $progname -h [-n] [-A] [-G] [-N]" | |
| Write-Host "Where:" | |
| Write-Host " -h will show this help test and terminate" | |
| Write-Host " -n selects Windows native" | |
| Write-Host " -p only print the list of configs without running any builds" | |
| Write-Host " -A store the build executable artifact in ARTIFACTDIR (defaults to ../buildartifacts" | |
| Write-Host " -C Skip tree cleanness check." | |
| Write-Host " -G Use `"git clean -xfdq`" instead of `"make distclean`" to clean the tree." | |
| Write-Host " -N Use CMake with Ninja as the backend." | |
| Write-Host " <testlist-file> selects the list of configurations to test. No default" | |
| Write-Host "" | |
| exit 1 | |
| } | |
| # Define a function to search for Visual Studio 2022 installation | |
| function Find-VisualStudio { | |
| # Check common installation paths | |
| $commonPaths = @( | |
| "C:\Program Files\Microsoft Visual Studio\2022\Community", | |
| "C:\Program Files\Microsoft Visual Studio\2022\Professional", | |
| "C:\Program Files\Microsoft Visual Studio\2022\Enterprise" | |
| ) | |
| foreach ($path in $commonPaths) { | |
| if (Test-Path $path) { | |
| $MSVC = 1 | |
| } | |
| } | |
| if ($MSVC -eq 1) { | |
| Write-Host "Found Visual Studio 2022 installations" | |
| return $MSVC = 1 | |
| } | |
| else { | |
| Write-Host "Visual Studio 2022 is not installed on this system." | |
| return $MSVC = 0 | |
| } | |
| } | |
| $MSVC = Find-VisualStudio | |
| if (!$args[0]) { | |
| showusage | |
| } | |
| for ( $i = 0; $i -lt $args.count; $i++ ) { | |
| switch -regex -casesensitive ($($args[$i])) { | |
| '-h' { | |
| showusage | |
| } | |
| '-p' { | |
| $PRINTLISTONLY = 1 | |
| } | |
| '-G' { | |
| $GITCLEAN = 1 | |
| } | |
| '-A' { | |
| $SAVEARTIFACTS = 1 | |
| } | |
| '-C' { | |
| $CHECKCLEAN = 0 | |
| } | |
| '-N' { | |
| $NINJACMAKE = 1 | |
| } | |
| default { | |
| Write-Host "File $($args[$i])" -ForegroundColor Green | |
| $testfile = $($args[$i]) | |
| } | |
| } | |
| } | |
| # Check if testfile file exists | |
| if (-not (Test-Path -Path "$testfile")) { | |
| Write-Host "ERROR: Missing test list file" -ForegroundColor Red | |
| showusage | |
| } | |
| # Check if nuttx directory exists | |
| if (-Not (Test-Path -Path $nuttx)) { | |
| Write-Host "ERROR: Expected to find nuttx/ at $nuttx" -ForegroundColor Red | |
| showusage | |
| } | |
| # Check if apps directory exists | |
| if (-Not (Test-Path -Path $APPSDIR)) { | |
| Write-Host "ERROR: No directory found at $APPSDIR" -ForegroundColor Red | |
| exit 1 | |
| } | |
| $patternallitem = '^(-|\\)|^[C|c][M|m][A|a][K|k][E|e]' | |
| $patterntestlist = '^\\' | |
| $patternblacklist = '^-' | |
| if ($NINJACMAKE -eq 1) { | |
| $patterncmakelist = '^[C|c][M|m][A|a][K|k][E|e][,]' | |
| } | |
| $content = Get-Content .\$testfile | |
| $content = $content -replace '/', '\' | |
| Set-Location "$nuttx" | |
| $listfull = $content | Select-String $patternallitem -AllMatches | |
| $testlist = $listfull | Select-String $patterntestlist -AllMatches | |
| $blacklist = $listfull | Select-String $patternblacklist -AllMatches | |
| if ($NINJACMAKE -eq 1) { | |
| $cmakelist = $listfull | Select-String $patterncmakelist -AllMatches | |
| } | |
| # Clean up after the last build | |
| function distclean { | |
| Write-Host " Cleaning..." | |
| if ((Test-Path ".config") -or (Test-Path "build\.config")) { | |
| if (($GITCLEAN -eq 1) -or ($cmake)) { | |
| git -C $nuttx clean -xfdq | |
| git -C $APPSDIR clean -xfdq | |
| } | |
| else { | |
| # Remove .version manually because this file is shipped with | |
| # the release package and then distclean has to keep it. | |
| if ($CHECKCLEAN -ne 0) { | |
| if ((Test-Path -Path "$nuttx\.git") -or (Test-Path -Path "$APPSDIR\.git")) { | |
| try { | |
| if (git -C $nuttx status --ignored -s 2>$null) { | |
| git -C $nuttx status --ignored -s | |
| $global:fail = 1 | |
| } | |
| if (git -C $APPSDIR status --ignored -s 2>$null) { | |
| git -C $APPSDIR status --ignored -s | |
| $global:fail = 1 | |
| } | |
| } | |
| catch { | |
| Write-Host "Git is not installed. Please install Git to use this script." -ForegroundColor Red | |
| $global:fail = 1 | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| function run_command ($command) { | |
| invoke-expression "$command" *>$null | |
| Write-Host "run_command $_" | |
| return $_ | |
| } | |
| function configure_cmake { | |
| # Run CMake with specified configurations | |
| try { | |
| $tmpconfig = $config -replace '\\', ':' | |
| # cmake -B vs2022 -DBOARD_CONFIG=sim/windows -G"Visual Studio 17 2022" -A Win32 | |
| # cmake --build vs2022 | |
| if (($tmpconfig -match "windows") -and ($MSVC -eq 1)) { | |
| if (cmake -B build -DBOARD_CONFIG="$tmpconfig" -G"Visual Studio 17 2022" -A Win32 1>$null) { | |
| cmake -B build -DBOARD_CONFIG="$tmpconfig" -G"Visual Studio 17 2022" -A Win32 | |
| $global:fail = 1 | |
| } | |
| } | |
| else { | |
| if (cmake -B build -DBOARD_CONFIG="$tmpconfig" -GNinja 1>$null) { | |
| cmake -B build -DBOARD_CONFIG="$tmpconfig" -GNinja | |
| Write-Host "cmake -B build -DBOARD_CONFIG=$tmpconfig -GNinja" | |
| $global:fail = 1 | |
| } | |
| } | |
| Write-Host " CMake configuration completed successfully." | |
| } | |
| catch { | |
| Write-Host " CMake configuration failed: $_" | |
| $global:fail = 1 | |
| } | |
| if ($toolchain) { | |
| $patternallitem = '_TOOLCHAIN_' | |
| $contentconfig = Get-Content "$nuttx\build\.config" | |
| $listtoolchain = $contentconfig | Select-String $patternallitem -AllMatches | |
| $listtoolchain = $listtoolchain | Select-String 'CONFIG_TOOLCHAIN_WINDOWS', 'CONFIG_ARCH_TOOLCHAIN_*' -NotMatch | Select-String '=y' -AllMatches | |
| $toolchainarr = $listtoolchain -split '=' | |
| $original_toolchain = $($toolchainarr[0]) | |
| if ($original_toolchain) { | |
| Write-Host " Disabling $original_toolchain" | |
| kconfig-tweak.ps1 --file "$nuttx\build\.config" -d $original_toolchain | |
| } | |
| Write-Host " Enabling $toolchain" | |
| kconfig-tweak.ps1 --file "$nuttx\build\.config" -e $toolchain | |
| } | |
| } | |
| function configure { | |
| Write-Host " Configuring..." | |
| if ($cmake) { | |
| configure_cmake | |
| } | |
| else { | |
| # configure_default to-do | |
| Write-Host " configure_default" -ForegroundColor Green | |
| } | |
| } | |
| # Perform the next build | |
| function build_default { | |
| # make build_default to-do | |
| } | |
| function build_cmake { | |
| # Build the project | |
| try { | |
| $errorcmakelist = @() | |
| # $ErrorActionPreference = 'Stop' | |
| $ErrorActionPreference = "Continue" | |
| $errorcmakelist = (cmake --build build 2>$null) | |
| if ($lastExitCode -ne 0) { | |
| foreach ($errorline in $errorcmakelist) { | |
| Write-Host "$errorline" | |
| } | |
| } | |
| else { | |
| Write-Host " Build completed successfully." | |
| } | |
| } | |
| catch { | |
| Write-Error "Build failed: $_" | |
| $global:fail = 1 | |
| } | |
| if ($SAVEARTIFACTS -eq 1) { | |
| $artifactconfigdir = "$ARTIFACTDIR\$config" | |
| # Write-Host "Copy in artifactconfigdir: $artifactconfigdir" | |
| New-Item -Force -ItemType directory -Path $artifactconfigdir > $null | |
| try { | |
| $contentmanifest = $null | |
| $contentmanifest = Get-Content "$nuttx\build\nuttx.manifest" | |
| $tmpconfig = $config -replace '\\', ':' | |
| if (($tmpconfig -match "windows") -and ($MSVC -eq 1)) { | |
| Copy-Item -Path "$nuttx\build\Debug\nuttx.exe" -Destination $artifactconfigdir -Force -ErrorAction Stop | |
| Copy-Item -Path "$nuttx\build\Debug\nuttx.pdb" -Destination $artifactconfigdir -Force -ErrorAction Stop | |
| } | |
| else { | |
| foreach ($ma in $contentmanifest) { | |
| Copy-Item -Path "$nuttx\build\$ma" -Destination $artifactconfigdir -Force -ErrorAction Stop | |
| } | |
| } | |
| } | |
| catch { | |
| Write-Host " An error occurred while copying files: $_" -ForegroundColor Red | |
| $global:fail = 1 | |
| } | |
| } | |
| } | |
| function build { | |
| Write-Host " Building NuttX..." | |
| if ($cmake) { | |
| # Write-Host " build_cmake" -ForegroundColor Green | |
| build_cmake | |
| } | |
| else { | |
| # make build_default to-do | |
| Write-Host " build_default to-do" -ForegroundColor Green | |
| } | |
| } | |
| function refresh_default { | |
| # make refresh_default to-do | |
| } | |
| function refresh_cmake { | |
| # Ensure defconfig in the canonical form | |
| if ($toolchain) { | |
| if ($original_toolchain) { | |
| kconfig-tweak.ps1 --file "$nuttx\build\.config" -e $original_toolchain | |
| } | |
| kconfig-tweak.ps1 --file "$nuttx\build\.config" -d $toolchain | |
| } | |
| try { | |
| if (cmake --build build -t refreshsilent 1>$null) { | |
| cmake --build build -t refreshsilent | |
| $global:fail = 1 | |
| } | |
| Write-Host " Refresh completed successfully." | |
| } | |
| catch { | |
| Write-Error "Refresh failed: $_" | |
| $global:fail = 1 | |
| } | |
| try { | |
| Remove-Item build -Recurse -Force | |
| } | |
| catch { | |
| Write-Error "Remove-Item failed: $_" | |
| } | |
| # Ensure nuttx and apps directory in clean state | |
| if ($CHECKCLEAN -ne 0) { | |
| if ((Test-Path -Path "$nuttx\.git") -or (Test-Path -Path "$APPSDIR\.git")) { | |
| try { | |
| if (git -C $nuttx status -s 2>$null) { | |
| Write-Host "Git $nuttx status " -ForegroundColor Yellow | |
| git -C $nuttx status -s | |
| $global:fail = 1 | |
| } | |
| if (git -C $APPSDIR status -s 2>$null) { | |
| Write-Host "Git $APPSDIR status " -ForegroundColor Yellow | |
| git -C $APPSDIR status -s | |
| $global:fail = 1 | |
| } | |
| } | |
| catch { | |
| Write-Host "Git is not installed. Please install Git to use this script." -ForegroundColor Red | |
| $global:fail = 1 | |
| } | |
| } | |
| } | |
| # Use -f option twice to remove git sub-repository | |
| git -C $nuttx clean -f -xfdq | |
| git -C $APPSDIR clean -f -xfdq | |
| } | |
| function refresh { | |
| if ($cmake) { | |
| refresh_cmake | |
| } | |
| else { | |
| # make refresh_default to-do | |
| } | |
| } | |
| function run { | |
| # run to-do | |
| } | |
| # Coordinate the steps for the next build test | |
| function dotest { | |
| param ( | |
| [string]$configfull | |
| ) | |
| Write-Host "====================================================================================" | |
| $configarr = $configfull -split ',' | |
| $config = $($configarr[0]) | |
| $check = "Windows," + $config -replace '\\', ':' | |
| $skip = 0 | |
| foreach ($re in $blacklist) { | |
| if ("-$check" -eq "$re") { | |
| $skip = 1 | |
| } | |
| } | |
| $cmake = $null | |
| if ($NINJACMAKE -eq 1) { | |
| foreach ($l in $cmakelist) { | |
| if ("Cmake," + $config -replace '\\', ':' -eq "$l") { | |
| $cmake = 1 | |
| } | |
| } | |
| } | |
| Write-Host "Configuration/Tool: $configfull" -ForegroundColor Yellow | |
| if ($PRINTLISTONLY -eq 1) { | |
| return | |
| } | |
| $tmparr = $config -split '\\' | |
| $configdir = $($tmparr[1]) | |
| $boarddir = $($tmparr[0]).Trim() | |
| if (($boarddir -eq "sim") -and ($MSVC -ne 1)) { | |
| $skip = 1 | |
| } | |
| $path = "$nuttx\boards\*\*\$boarddir\configs\$configdir" | |
| if (-Not (Test-Path -Path $path)) { | |
| Write-Host "ERROR: no configuration found at $path" -ForegroundColor Red | |
| showusage | |
| } | |
| $toolchain = $null | |
| $original_toolchain = $null | |
| if ($config -ne $configfull) { | |
| $toolchain = $($configarr[1]) | |
| } | |
| Write-Host (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") -ForegroundColor Yellow | |
| Write-Host "------------------------------------------------------------------------------------" | |
| distclean | |
| if ($skip -ne 1 ) { | |
| configure | |
| build | |
| refresh | |
| } | |
| else { | |
| Write-Host " Skipping: $config" -ForegroundColor Green | |
| } | |
| } | |
| foreach ($line in $testlist) { | |
| $firstch = [string[]]$line | ForEach-Object { $_[0] } | |
| $arr = $line -split ',' | |
| if ($firstch -eq '\') { | |
| $dir = $arr | |
| if (!$dir[1]) { | |
| $cnftoolchain = "" | |
| } | |
| else { | |
| $cnftoolchain = "," + $dir[1] | |
| } | |
| $filePath = Get-ChildItem -Path "boards$($dir[0])" -Recurse -ErrorAction SilentlyContinue | Where-Object { $_.Name -eq "defconfig" } | |
| if ($filePath) { | |
| foreach ($i in $filePath) { | |
| $arrpath = $($i.FullName) -split '\\' | |
| $list = "$($arrpath[$arrpath.count - 4])\$($arrpath[$arrpath.count - 2])" | |
| dotest "$list$cnftoolchain" | |
| } | |
| } | |
| else { | |
| Write-Host "File '$FileName' not found in '$list'." -ForegroundColor Yellow | |
| } | |
| } | |
| else { | |
| dotest "$line" | |
| } | |
| } | |
| Write-Host "------------------------------------------------------------------------------------" | |
| $timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") | |
| Write-Host "End: $timestamp" -ForegroundColor Yellow | |
| Write-Host "====================================================================================" | |
| exit $global:fail |