Looking through the source code from TextTransformation.exe (with ILSpy) I don't think this is possible without modifying the template (but I do have a solution).
Ultimately what we care about here is the step during the template parsing where Microsoft.VisualStudio.TextTemplating.Engine.ResolveAssemblyReferences() is called. This delegates to ITextTemplatingEngineHost.ResolveAssemblyReference() (though it does expand environment variables first)
When the template is run from the command line, the implementation being used is that provided by the CommandLineHost, and its implementation simply looks for the file as supplied in reference paths and the GAC. Given the file name will at this point still have the $(SolutionPath) bit in, it's never going to succeed.
You could implement your own version of TextTransform.exe, but you'd have to start largely from scratch (or use reflection), since CommandLineHost is internal :-( Or you could potentially leverage the Mono port https://mcmap.net/q/35651/-t4-without-visual-studio
I can't say I'm happy about this, because I find myself in the same boat...
Edit: However... since ultimately all you need to do is change the template, I put together a PowerShell script to copy the templates to the temp directory, manually expanding the $(SolutionDir) macro in the process, and execute them from there. That seems to work just fine.
Drop this into the offending project (you might want to change the file extension) and you should be good to go:
<#
.Synopsis
Executes all the T4 templates within designated areas of the containing project
.Description
Unfortunately the Visual Studio 2010 'Transform All Templates' function doesn't appear
to work in SSDT projects, so have to resort to hackery like this to bulk-execute templates
#>
param(
)
$ErrorActionPreference = 'stop';
$scriptDir = Split-Path $MyInvocation.MyCommand.Path
$commonProgramFiles32 = $env:CommmonProgramFiles
if (Test-Path environment::"CommonProgramFiles(x86)") { $commonProgramFiles32 = (gi "Env:CommonProgramFiles(x86)").Value };
$t4 = Resolve-Path "$commonProgramFiles32\Microsoft Shared\TextTemplating\10.0\texttransform.exe";
$solutionDir = Resolve-Path "$scriptDir\..\"
$templates = @(dir "$scriptDir\Database Objects\load\*.tt")
# Cloning to temp dir originally caused issues, because I use the file name in the template (doh!)
# Now I copy to temp dir under the same name
pushd $scriptDir;
try{
foreach($template in $templates){
$templateTemp = Join-Path ([IO.Path]::GetTempPath()) $template.Name;
$targetfile = [IO.Path]::ChangeExtension($template.FullName, '.sql');
Write-Host "Running $($template.Name)"
Write-Host "...output to $targetFile";
# When run from outside VisualStudio you can't use $(SolutionDir)
# ...so have to modify the template to get this to work...
# ...do this by cloning to a temp file, and running this instead
Get-Content $template.FullName | % {
$_.Replace('$(SolutionDir)',"$solutionDir")
} | Out-File -FilePath:$templateTemp
try{
& $t4 $templateTemp -out $targetfile -I $template.DirectoryName;
}finally{
if(Test-Path $templateTemp){ Remove-Item $templateTemp; }
}
}
}finally{
popd;
}
set SolutionDir=%cd%
to set the variable to the current directory? – Idleman