[Powershell script]
Referenced: >[#1 - Powershelling with ninja]<
Calling script (build.ps1)
$ProjectName = "hello_world"
$ProjectType = "exe"
$hello_world = @{
ProjectName = $ProjectName
ProjectSrcFiles = "$ProjectName/src"
ProjectIncludeFiles = "$ProjectName/include"
ProjectType = $ProjectType
}
$ProjectName = "static_lib"
$ProjectType = "lib"
$static_lib = @{
ProjectName = $ProjectName
ProjectSrcFiles = "$ProjectName/src"
ProjectIncludeFiles = "$ProjectName/include"
ProjectType = $ProjectType
}
$ProjectName = "dynamic_lib"
$ProjectType = "dll"
$dynamic_lib = @{
ProjectName = $ProjectName
ProjectSrcFiles = "$ProjectName/src"
ProjectIncludeFiles = "$ProjectName/include"
ProjectType = $ProjectType
}
# Run the deployment script
.\.build/per_project.ps1 @hello_world
.\.build/per_project.ps1 @static_lib
.\.build/per_project.ps1 @dynamic_lib
Receiving script (per_project.ps1)
Param(
[Parameter(Mandatory=$true)]
[string]$ProjectName,
[string]$ProjectSrcFiles,
[string]$ProjectIncludeFiles,
[string]$ProjectType
)
Write-Host "--- Attempting to build $ProjectName --- " -ForegroundColor DarkGreen
# PowerShell settings
$ErrorActionPreference = "Stop" # This will stop executing the script immediately
# Global
$CurrentDirectory = (Get-Location).ToString().Replace('\', '/')
$Out = ".out"
$ProjectSubFolder = "projects"
$ProjectFolder = "$Out/$ProjectName"
$ProjectSource = "../../$ProjectSubFolder/$ProjectSrcFiles"
$ProjectInclude = "../../$ProjectSubFolder/$ProjectIncludeFiles"
$NinjaFile = "$ProjectFolder/build.ninja"
# Support old legacy PowerShell
$RunningOnWindows = $env:OS -match "Windows" -or $IsWindows
if ($RunningOnWindows) {
# On Windows - Run this ps in dedicated PowerShell for VS so that compiler/linker can find everything it needs
# Check if compiler path exists
if (!(Get-Command cl.exe -ErrorAction SilentlyContinue)) {
Write-Host "Error: cl.exe not found. Please run this in a Developer PowerShell." -ForegroundColor Red
exit 1
}
# Check if link path exists
if (!(Get-Command link.exe -ErrorAction SilentlyContinue)) {
Write-Host "Error: link.exe not found. Please run this in a Developer PowerShell." -ForegroundColor Red
exit 1
}
#We are on Windows!
Write-Host "Detected Windows - Using MSVC" -ForegroundColor Cyan
#Define ninja variables here
$NinjaCompilerCommands = "/showIncludes /c"
$NinjaDebugOut = "Debug"
$NinjaReleaseOut = "Release"
$NinjaDebugBin = "$NinjaDebugOut/bin"
$NinjaReleaseBin = "$NinjaReleaseOut/bin"
$NinjaDebugLib = "$NinjaDebugOut/lib"
$NinjaReleaseLib = "$NinjaReleaseOut/lib"
$NinjaDebugObj = "$NinjaDebugOut/obj"
$NinjaReleaseObj = "$NinjaReleaseOut/obj"
$NinjaDeps = "msvc"
#Executable name
$ExecutableName = "$ProjectName.exe"
$LibName = "$ProjectName.lib"
$DllName = "$ProjectName.dll"
#Compiler
$Compiler = "cl.exe"
# Use /FS as the compiler will be writing to the same .pdb simulatenously (Thanks Ninja!)
# Use /Fa to generate assembly files
# Use /EHsc - From Microsoft manual = When you use /EHs or /EHsc, the compiler assumes that exceptions can only occur at a throw statement or at a function call. This assumption allows the compiler to eliminate code for tracking the lifetime of many unwindable objects
$DebugCompilerFlags = "/nologo /MDd /Zi /Ob0 /Od /RTC1 /W4 /EHsc /FS "
$ReleaseCompilerFlags = "/nologo /MD /Zi /O2 /Ob2 /Zo /FAs /DNDEBUG /EHsc /FS "
# Separate include directories as those will need to be bundled in the future
$DebugCompilerFlags += "/I$ProjectInclude"
$ReleaseCompilerFlags += "/I$ProjectInclude"
$CompilerObjectOut = "/Fo"
#Linker
$Linker = "link.exe"
$DebugLinkerFlags = "/NOLOGO /DEBUG:FULL /OPT:REF /OPT:ICF /INCREMENTAL:NO"
$ReleaseLinkerFlags = "/NOLOGO /DEBUG:FULL /OPT:REF /OPT:ICF /INCREMENTAL:NO"
$LinkerObjectOut = "/OUT:"
if ($ProjectType -eq "dll"){
$DebugCompilerFlags = "$DebugCompilerFlags /LD /D_USRDLL /D_WINDLL"
$ReleaseCompilerFlags += "$ReleaseCompilerFlags /LD /D_USRDLL /D_WINDLL"
$DebugLinkerFlags = "$DebugLinkerFlags /DLL /OPT:NOICF"
$ReleaseLinkerFlags = "$ReleaseLinkerFlags /DLL /OPT:NOICF"
}
#Librarian
$Archiver = "lib.exe"
$ArchiverFlags = "/NOLOGO"
$ArchiverObjectOut = "/OUT:"
}
else {
# Linux / MacOS is currently not supported
Write-Host "--- Cannot run on Non-Windows platform ---" -ForegroundColor Red
exit 1
}
# Attempt to remove the file
Remove-Item -Path $NinjaFile -Force -ErrorAction SilentlyContinue
# If the .out doesn't exist, create it
if (!(Test-Path $ProjectFolder)) {
New-Item -ItemType Directory -Path $ProjectFolder
}
# So it begins...
Write-Host "--- Starting Build ---" -ForegroundColor DarkGreen
$NinjaContent = @"
rule $("$ProjectName")_debug_cc
command = $($Compiler) $($NinjaCompilerCommands) $($CompilerObjectOut)`$out $($DebugCompilerFlags) `$in
description = Compiling `$in
deps = $($NinjaDeps)
rule $("$ProjectName")_release_cc
command = $($Compiler) $($NinjaCompilerCommands) $($CompilerObjectOut)`$out $($ReleaseCompilerFlags) `$in
description = Compiling `$in
deps = $($NinjaDeps)
rule $("$ProjectName")_debug_lk
command = $($Linker) $($LinkerObjectOut)`$out $($DebugLinkerFlags) `$in
description = Linking `$out
rule $("$ProjectName")_release_lk
command = $($Linker) $($LinkerObjectOut)`$out $($ReleaseLinkerFlags) `$in
description = Linking `$out
rule $("$ProjectName")_lib
command = $($Archiver) $($ArchiverObjectOut)`$out $($ArchiverFlags) `$in
rule $("$ProjectName")_debug_dll
command = $($Linker) $($LinkerObjectOut)`$out $($DebugLinkerFlags) `$in
description = Linking `$out
rule $("$ProjectName")_release_dll
command = $($Linker) $($LinkerObjectOut)`$out $($ReleaseLinkerFlags) `$in
description = Linking `$out
"@
# Get list of source files first. This gets all files without .cpp extension
$ListOfSourceFiles = (Get-ChildItem -Path "$ProjectSubFolder/$ProjectSrcFiles" -File).BaseName
$ListOfDebugObj = ""
$ListOfReleaseObj = ""
foreach ($File in $ListOfSourceFiles) {
#Now we need to build object files
$NinjaContent += "`n"
$NinjaContent += "`nbuild $($NinjaDebugObj)/$($File).obj: $("$ProjectName")_debug_cc $($ProjectSource)/$($File).cpp"
$NinjaContent += "`nbuild $($NinjaReleaseObj)/$($File).obj: $("$ProjectName")_release_cc $($ProjectSource)/$($File).cpp"
# Add this to the growing list for the final piece
$ListOfDebugObj += "$($NinjaDebugObj)/$($File).obj "
$ListOfReleaseObj += "$($NinjaReleaseObj)/$($File).obj "
}
$NinjaContent += "`n"
if ($ProjectType -eq "exe") {
$NinjaContent += "`nbuild $($NinjaDebugBin)/$($ExecutableName): $("$ProjectName")_debug_lk $($ListOfDebugObj)"
$NinjaContent += "`nbuild $($NinjaReleaseBin)/$($ExecutableName): $("$ProjectName")_release_lk $($ListOfReleaseObj)"
}
elseif ($ProjectType -eq "lib") {
$NinjaContent += "`nbuild $($NinjaDebugLib)/$($LibName): $("$ProjectName")_lib $($ListOfDebugObj)"
$NinjaContent += "`nbuild $($NinjaReleaseLib)/$($LibName): $("$ProjectName")_lib $($ListOfReleaseObj)"
}
elseif ($ProjectType -eq "dll") {
$NinjaContent += "`nbuild $($NinjaDebugLib)/$($DllName) | $($NinjaDebugLib)/$($LibName): $("$ProjectName")_debug_dll $($ListOfDebugObj)"
$NinjaContent += "`nbuild $($NinjaReleaseLib)/$($DllName) | $($NinjaReleaseLib)/$($LibName): $("$ProjectName")_release_dll $($ListOfReleaseObj)"
}
# Save the file
$NinjaContent | Out-File -FilePath $NinjaFile -Encoding ascii
# Call Ninja
# @args forwards things like: .\build.ps1 -t clean
ninja -C "$CurrentDirectory/$ProjectFolder"
# Post-Build
# This only runs if Ninja exits successfully (Exit Code 0)
if ($LASTEXITCODE -eq 0) {
Write-Host "--- Build Complete! ---" -ForegroundColor DarkGreen
}