I'm replacing my Visual Studio project files with FASTBuild makefiles because it builds in a fraction of the time. Right now FASTBuild isn't well known. The official documentation is sorely lacking, and I can't find anyone else talking about it online.
I've spent quite a bit of time programming-by-error-message to figure out how FASTBuild really works, and I've come up with a functional makefile. It still lacks some features essential to IDE development work, but otherwise it's solid.
The downside is that it's long, verbose, repetitive, ugly, and it's going to be unpleasant to roll this one test project out to the other 95 project files in my solution.
If anyone out there knows FASTBuild, I need suggestions on how to make this less redundant and generally less awful.
; FASTBUILD makefile
;_______________
; Variables to customize this library build
;_______________
.LibraryName = 'LibraryName'
.InputFiles = { 'file1.cpp' 'file2.cpp' 'etc.cpp' }
.InputFilesManaged = { 'fileM1.cpp' 'fileM2.cpp' 'etcM.cpp' }
.PathToSolutionBase = '..\..'
;From <AdditionalIncludeDirectories>
.HeaderIncludePaths = '..\Lib1;..\Lib1\Src;..\Lib2;..\Lib3;'
.Includes = ' /I"..\Lib1"'
+ ' /I"..\Lib1\Src"'
+ ' /I"..\Lib2"'
+ ' /I"..\Lib3"'
.PCHFile = 'stdafx.cpp'
.PCHHeader = 'StdAfx.h'
.ObjPath = 'obj'
.OutputPath = '$PathToSolutionBase$\bin'
.ForceUsingCommon = ' /FU"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Core.dll"'
+ ' /FU"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.dll"'
+ ' /FU"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Drawing.dll"'
+ ' /FU"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Windows.Forms.dll"'
; Source: grep "<ProjectReference" *.vcxproj | sed -e 's/.*=.//g' | sed -e 's/..$//g'
.ForceUsing_Debug_x86 = ' /FU"$OutputPath$\Debug-win32\DLL1.dll"'
+ ' /FU"$OutputPath$\Debug-win32\DLL2.dll"'
+ ' /FU"$OutputPath$\Debug-win32\DLL3.dll"'
+ ' /FU"$OutputPath$\Debug-win32\DLL4.dll"'
+ ' /FU"$OutputPath$\Debug-win32\DLL6.dll"'
+ ' /FU"$OutputPath$\Debug-win32\DLL7.dll"'
.ForceUsing_Release_x86 = ' /FU"$OutputPath$\Release-win32\DLL1.dll"'
+ ' /FU"$OutputPath$\Release-win32\DLL2.dll"'
+ ' /FU"$OutputPath$\Release-win32\DLL3.dll"'
+ ' /FU"$OutputPath$\Release-win32\DLL4.dll"'
+ ' /FU"$OutputPath$\Release-win32\DLL5.dll"'
+ ' /FU"$OutputPath$\Release-win32\DLL7.dll"'
.ForceUsing_Debug_x64 = ' /FU"$OutputPath$\Debug-x64\DLL1.dll"'
+ ' /FU"$OutputPath$\Debug-x64\DLL2.dll"'
+ ' /FU"$OutputPath$\Debug-x64\DLL3.dll"'
+ ' /FU"$OutputPath$\Debug-x64\DLL4.dll"'
+ ' /FU"$OutputPath$\Debug-x64\DLL5.dll"'
+ ' /FU"$OutputPath$\Debug-x64\DLL7.dll"'
.ForceUsing_Release_x64 = ' /FU"$OutputPath$\Release-x64\DLL1.dll"'
+ ' /FU"$OutputPath$\Release-x64\DLL2.dll"'
+ ' /FU"$OutputPath$\Release-x64\DLL3.dll"'
+ ' /FU"$OutputPath$\Release-x64\DLL4.dll"'
+ ' /FU"$OutputPath$\Release-x64\DLL5.dll"'
+ ' /FU"$OutputPath$\Release-x64\DLL7.dll"'
;_______________
; Generic boilerplate which will eventually be an #include
;_______________
; Common defines
.VSBasePath = 'C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin'
.CompilerSettingsC = '/Z7 /nologo /W4 /WX /MP /EHa /GS /Gy /Gd /wd"4945" /fp:precise /Zc:wchar_t /Zc:forScope /errorReport:queue'
.CompilerSettingsNativeC = '/c /Gm-'
.DefinesC = ' /D_UNICODE'
+ ' /DUNICODE'
+ ' /D_AFXDLL'
+ ' /D_WINDOWS'
// Architecture
.ArchX86 =
[
.Compiler = '$VSBasePath$\cl.exe'
.Librarian = '$VSBasePath$\lib.exe'
.Linker = '$VSBasePath$\link.exe'
.LibrarianOptions = '/OUT:%2 %1 /MACHINE:X86'
.LinkerOptions = '/OUT:%2 %1 /MACHINE:X86'
.ArchName = 'win32'
.CompilerSettingsA = ''
.DefinesA = '/DWIN32'
]
.ArchX64 =
[
.Compiler = '$VSBasePath$\x86_amd64\cl.exe'
.Librarian = '$VSBasePath$\x86_amd64\lib.exe'
.Linker = '$VSBasePath$\x86_amd64\link.exe'
.LibrarianOptions = '/OUT:%2 %1 /MACHINE:X64'
.LinkerOptions = '/OUT:%2 %1 /MACHINE:X64'
.ArchName = 'x64'
.CompilerSettingsA = ''
.DefinesA = '/DWIN64'
]
// Build type
.BuildDebug =
[
.CompilerSettingsB = '/Od /MDd'
.CompilerSettingsBNative = '/RTC1 /analyze-'
.DefinesB = '/D_DEBUG'
.BuildName = 'Debug'
]
.BuildRelease =
[
.CompilerSettingsB = '/O2 /Ob2 /Oi /Oy /GF /MD'
.CompilerSettingsBNative = ''
.DefinesB = '/DNDEBUG'
.BuildName = 'Release'
]
// Complete build target
.Target_Debug_x86 =
[
Using( .ArchX86 )
Using( .BuildDebug )
.CompilerSettingsT = '/Oy-'
.DefinesT = '/D "_CRTDBG_MAP_ALLOC"'
.ForceUsing = '$ForceUsingCommon$ $ForceUsing_Debug_x86$'
]
.Target_Release_x86 =
[
Using( .ArchX86 )
Using( .BuildRelease )
.CompilerSettingsT = ''
.DefinesT = ''
.ForceUsing = '$ForceUsingCommon$ $ForceUsing_Release_x86$'
]
.Target_Debug_x64 =
[
Using( .ArchX64 )
Using( .BuildDebug )
.CompilerSettingsT = ''
.DefinesT = ''
.ForceUsing = '$ForceUsingCommon$ $ForceUsing_Debug_x64$'
]
.Target_Release_x64 =
[
Using( .ArchX64 )
Using( .BuildRelease )
.CompilerSettingsT = ''
.DefinesT = ''
.ForceUsing = '$ForceUsingCommon$ $ForceUsing_Release_x64$'
]
.Targets = { .Target_Debug_x86, .Target_Release_x86, .Target_Debug_x64, .Target_Release_x64 }
ForEach( .Target in .Targets )
{
Using( .Target ) // Copy all variables from Target
.TargetName = '$BuildName$_$ArchName$'
.FullOutputPath = '$OutputPath$\$ArchName$\$BuildName$'
.FullObjPath = '$ObjPath$\$ArchName$\$BuildName$\'
Unity("Lib_Unity_$TargetName$")
{
.UnityInputFiles = .InputFiles
.UnityInputIsolateWritableFiles = true
.UnityOutputPath = .FullObjPath
.UnityOutputPattern = 'Unity-native*.cpp'
.UnityPCH = .PCHHeader
}
Unity("Lib_Unity_managed_$TargetName$")
{
.UnityInputFiles = .InputFilesManaged
.UnityInputIsolateWritableFiles = true
.UnityOutputPath = .FullObjPath
.UnityOutputPattern = 'Unity-managed*.cpp'
}
ObjectList("Lib_managed_$TargetName$")
{
.CompilerInputUnity = 'Lib_Unity_managed_$TargetName$'
.CompilerOptions = '"%1" /c /clr /Fo"%2" $ForceUsing$ $CompilerSettingsC$ $CompilerSettingsB$ $CompilerSettingsA$ $CompilerSettingsT$ $DefinesC$ $DefinesB$ $DefinesA$ $DefinesT$ $Includes$'
.CompilerOutputPath = .FullObjPath
}
Library("Lib_$TargetName$")
{
.CompilerInputUnity = 'Lib_Unity_$TargetName$'
.PCHInputFile = .PCHFile
.PCHOutputFile = "$FullObjPath$\$LibraryName$.pch"
.LibrarianOutput = '$FullOutputPath$\$LibraryName$.lib'
.LibrarianAdditionalInputs = 'Lib_managed_$TargetName$'
.CommonCompileOptions = '"%1" /Fp"$PCHOutputFile$" $CompilerSettingsBNative$ $CompilerSettingsNativeC$ $CompilerSettingsC$ $CompilerSettingsB$ $CompilerSettingsA$ $CompilerSettingsT$ $DefinesC$ $DefinesB$ $DefinesA$ $DefinesT$ $Includes$'
.CompilerOptions = '$CommonCompileOptions$ /Yu"$PCHHeader$" /Fo"%2" /Fd"$FullOutputPath$\$LibraryName$.pdb"'
.CompilerOutputPath = .FullObjPath
.PCHOptions = '$CommonCompileOptions$ /Yc"$PCHHeader$" /Fo"%3"'
}
}
VCXProject("Project")
{
.ProjectOutput = '$LibraryName$.vcxproj'
.ProjectInputPaths = {'.'}
.ProjectAllowedFileExtensions = { '.h' '.cpp' '.c' '.rc' '.cs' }
.ProjectInputPathsExclude = {'obj'}
.ProjectBasePath = '.'
.ProjectBuildCommand = '$PathToSolutionBase$\Build\fbuild -vs Lib_^$(Configuration)_^$(Platform)'
.ProjectRebuildCommand = '$ProjectBuildCommand$ -clean'
.IncludeSearchPath = .HeaderIncludePaths
}
Alias( 'all' )
{
.Targets = { 'Lib_Debug_win32', 'Lib_Release_win32', 'Lib_Debug_x64', 'Lib_Release_x64' }
}