226 lines
8.2 KiB
PowerShell
226 lines
8.2 KiB
PowerShell
|
|
<#
|
|
.SYNOPSIS
|
|
Generate std-like headers which you can use just like standard c++'s ones.
|
|
For example include <thread>.
|
|
.PARAMETER GccPath
|
|
Path to GCC. Will try to use the default one from $env:Path if not
|
|
specified.
|
|
.PARAMETER MinGWStdThreadsPath
|
|
Path to mingw-std-threads folder. Will try to use $PSScriptRoot/.. if not
|
|
specified.
|
|
.PARAMETER DestinationFolder
|
|
Destination folder where generated headers will be saved to
|
|
.PARAMETER GenerateCompilerWrapperWithFileName
|
|
If specified, will be generated a wrapper batch script for g++ which automatically
|
|
adds $DestinationFolder as an include path
|
|
.PARAMETER Interactive
|
|
Use this switch if you want to pass parameters interactively
|
|
#>
|
|
[CmdletBinding(PositionalBinding = $false)]
|
|
param (
|
|
# Path of GCC
|
|
[Parameter(Mandatory = $false,
|
|
ValueFromPipelineByPropertyName = $true,
|
|
ParameterSetName = "NonInteractive",
|
|
HelpMessage = "Pathtof GCC. Will try to use the default one from `$env:Path if not specified.")]
|
|
[string]
|
|
$GccPath,
|
|
|
|
# Path of mingw-std-threads
|
|
[Parameter(Mandatory = $false,
|
|
ValueFromPipelineByPropertyName = $true,
|
|
ParameterSetName = "NonInteractive",
|
|
HelpMessage = "Path to mingw-std-threads folder. Will try to use `$PSScriptRoot/.. if not specified.")]
|
|
[string]
|
|
$MinGWStdThreadsPath,
|
|
|
|
# Destination folder path
|
|
[Parameter(Mandatory = $true,
|
|
ValueFromPipelineByPropertyName = $true,
|
|
ParameterSetName = "NonInteractive",
|
|
HelpMessage = "Destination folder where generated headers will be saved to")]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$DestinationFolder,
|
|
|
|
# Compiler wrapper path
|
|
[Parameter(Mandatory = $false,
|
|
ValueFromPipelineByPropertyName = $true,
|
|
ParameterSetName = "NonInteractive",
|
|
HelpMessage = "If specified, will generate a wrapper batch script for g++ which automatically adds `$DestinationFolder as an include path")]
|
|
[string]
|
|
$GenerateCompilerWrapperWithFileName,
|
|
|
|
# Interactive Switch
|
|
[Parameter(ParameterSetName = "Interactive")]
|
|
[switch]
|
|
$Interactive = $false
|
|
)
|
|
|
|
# Stop execution when encountering any error (includeing Write-Error command)
|
|
$ErrorActionPreference = "Stop";
|
|
|
|
# headers to be generated
|
|
$headers = @("condition_variable", "future", "mutex", "shared_mutex", "thread")
|
|
|
|
# ask for user input in interactive mode
|
|
if ($Interactive) {
|
|
Write-Host "Generate std-like headers which you can use just like standard c++'s ones."
|
|
Write-Host "Something like `"include <thread>`"."
|
|
|
|
$DestinationFolder = Read-Host -Prompt "Destination folder into which headers will be generated"
|
|
$GccPath = Read-Host -Prompt "Path to GCC, optional. Press Enter to let it be retrieved from PATH"
|
|
$MinGWStdThreadsPath = Read-Host -Prompt "Path to mingw-std-threads folder, optional. Press Enter to use default value"
|
|
$GenerateCompilerWrapperWithFileName = Read-Host "Optional path to which a wrapper batch script for g++ will be created. It will automatically use $DestinationFolder as an include path. Press Enter to skip"
|
|
}
|
|
|
|
if (-not $GccPath) {
|
|
$GccPath = "gcc"
|
|
}
|
|
|
|
# set default value of $MinGWStdThreadsPath
|
|
if (-not $MinGWStdThreadsPath) {
|
|
$scriptFilePath = $null
|
|
if ($MyInvocation.MyCommand.CommandType -eq "ExternalScript") {
|
|
$scriptFilePath = $MyInvocation.MyCommand.Definition
|
|
}
|
|
else {
|
|
$scriptFilePath = [Environment]::GetCommandLineArgs()[0]
|
|
}
|
|
$MinGWStdThreadsPath = (Get-Item -LiteralPath $scriptFilePath).Directory.Parent.FullName
|
|
}
|
|
|
|
# Normalize paths
|
|
$GccPath = (Get-Command -Name $GccPath).Source
|
|
$MinGWStdThreadsPath = Resolve-Path -LiteralPath $MinGWStdThreadsPath
|
|
$DestinationFolder = New-Item -Path $DestinationFolder -ItemType "Directory" -Force
|
|
|
|
Write-Output "GccPath: $GccPath"
|
|
Write-Output "MinGWStdThreadsPath: $MinGWStdThreadsPath"
|
|
Write-Output "DestinationFolder: $DestinationFolder"
|
|
if ($GenerateCompilerWrapperWithFileName) {
|
|
Write-Output "GenerateCompilerWrapperWithFileName: $GenerateCompilerWrapperWithFileName"
|
|
}
|
|
|
|
# Find path of real headers
|
|
Write-Output "Retrieving system header search paths..."
|
|
|
|
$readingIncludePath = $false
|
|
# Empty array which will later store include paths
|
|
$includePaths = @()
|
|
|
|
# Launch GCC
|
|
$processStartInfo = New-Object -TypeName "System.Diagnostics.ProcessStartInfo"
|
|
$processStartInfo.FileName = $GccPath
|
|
$processStartInfo.Arguments = "-xc++ -E -v -"
|
|
$processStartInfo.RedirectStandardInput = $true
|
|
$processStartInfo.RedirectStandardOutput = $true
|
|
$processStartInfo.RedirectStandardError = $true
|
|
$processStartInfo.UseShellExecute = $false
|
|
|
|
$outputLines = @()
|
|
$gcc = New-Object -TypeName "System.Diagnostics.Process"
|
|
try {
|
|
$gcc.StartInfo = $processStartInfo
|
|
$gcc.Start() | Out-Null
|
|
$gcc.StandardInput.Close()
|
|
$gcc.WaitForExit()
|
|
$output = $gcc.StandardError.ReadToEnd()
|
|
$outputLines = $output -split "[\r\n]" |
|
|
ForEach-Object { return $_.Trim() } |
|
|
Where-Object { return $_.Length -gt 0 }
|
|
}
|
|
finally {
|
|
$gcc.StandardInput.Dispose()
|
|
$gcc.StandardOutput.Dispose()
|
|
$gcc.StandardError.Dispose()
|
|
$gcc.Dispose()
|
|
}
|
|
|
|
# Parse Output
|
|
foreach ($line in $outputLines) {
|
|
if (-not $readingIncludePath) {
|
|
if ($line -match "#include <...> search starts here:") {
|
|
$readingIncludePath = $true
|
|
}
|
|
continue
|
|
}
|
|
|
|
if ($line -match "End of search list.") {
|
|
break
|
|
}
|
|
|
|
Write-Output "Retrieved search path: $line"
|
|
$includePaths += $line
|
|
}
|
|
|
|
if ($includePaths.Count -eq 0) {
|
|
Write-Error "Error: didn't find any #inlcude <...> search paths"
|
|
}
|
|
|
|
# look for std header paths
|
|
Write-Output "Searching for standard headers..."
|
|
$stdHeaders = @()
|
|
# set a label called "nextHeader" to allow continue with outer loop
|
|
:nextHeader foreach ($header in $headers) {
|
|
# check if mingw-std-threads headers exist
|
|
$myHeader = "mingw.$header.h"
|
|
$myHeader = Join-Path -Path $MinGWStdThreadsPath -ChildPath $myHeader
|
|
if (-not (Test-Path -LiteralPath $myHeader -PathType "Leaf")) {
|
|
Write-Error "Error: mingw-std-threads header not found: $myHeader"
|
|
}
|
|
|
|
foreach ($inludePath in $includePaths) {
|
|
$fullPath = Join-Path -Path $inludePath -ChildPath $header
|
|
if (Test-Path -LiteralPath $fullPath -PathType "Leaf") {
|
|
$fullPath = (Get-Item -LiteralPath $fullPath).FullName
|
|
$stdHeaders += $fullPath
|
|
Write-Output "Found std header: $fullPath"
|
|
# if found matching header, continue with outer loop
|
|
continue nextHeader
|
|
}
|
|
}
|
|
|
|
Write-Error "Error: didn't find $header in any search paths"
|
|
}
|
|
|
|
# generate headers
|
|
Write-Output "Generating headers..."
|
|
foreach ($stdHeader in $stdHeaders) {
|
|
$headerFileName = (Get-Item -LiteralPath $stdHeader).Name
|
|
$myHeader = "mingw.$headerFileName.h"
|
|
$myHeader = Join-Path -Path $MinGWStdThreadsPath -ChildPath $myHeader
|
|
Write-Output "Generating <$headerFileName> from $myHeader and $stdHeader..."
|
|
|
|
# both two headers should already have include guards
|
|
# but we still add a #pragma once just to be safe
|
|
$content = "#pragma once`r`n"
|
|
$content += "#include `"$stdHeader`"`r`n"
|
|
$content += "#include `"$myHeader`"`r`n";
|
|
|
|
$outputFileName = Join-Path -Path $DestinationFolder -ChildPath $headerFileName
|
|
Write-Output "Writing file: $outputFileName"
|
|
|
|
# use .NET's method to output lines to avoid UTF-8 BOM
|
|
$noBomEncoding = New-Object -TypeName "System.Text.UTF8Encoding" -ArgumentList $false
|
|
[IO.File]::WriteAllText($outputFileName, $content, $noBomEncoding)
|
|
}
|
|
|
|
$message = "Successfully generated std-like headers. Use them by adding "
|
|
$message += "`"-I$DestinationFolder`" to your compiler command line parameters"
|
|
Write-Output $message
|
|
|
|
if ($GenerateCompilerWrapperWithFileName) {
|
|
$compilerFolder = Split-Path -LiteralPath $GccPath
|
|
$compiler = Join-Path -Path $compilerFolder -ChildPath "g++"
|
|
$command = "@echo off`r`n"
|
|
$command += "$compiler %* `"-I$DestinationFolder`""
|
|
$wrapper = New-Item -Path $GenerateCompilerWrapperWithFileName -ItemType "File" -Force
|
|
|
|
# use .NET's method to output lines to avoid UTF-8 BOM
|
|
$noBomEncoding = New-Object -TypeName "System.Text.UTF8Encoding" -ArgumentList $false
|
|
[IO.File]::WriteAllText($wrapper, $command, $noBomEncoding)
|
|
|
|
Write-Output "Wrapper batch script successfully generated to $wrapper"
|
|
} |