So, CMake seems incapable of passing through /pdbaltpath:%_PDB% when given in a CMakeLists.txt (first learning). It somehow ends up as %%%%_PDB%%%% which then will evaluate — assuming a foobar.exe — to %%%foobar.pdb%%% in the PE file. Using generator expressions ($<1:...>) didn’t help either.
So obviously one would start using a workaround like this dumped into a Directory.Build.targets (because the corresponding .props ends up too early in the MSBuild sequencing, so we need to delay things a bit):
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="OverrideLinkerSwitches" AfterTargets="ComputeLinkSwitches" BeforeTargets="Link">
<ItemGroup>
<Link>
<AdditionalOptions>%(Link.AdditionalOptions) /pdbaltpath:%_PDB%</AdditionalOptions>
</Link>
</ItemGroup>
</Target>
</Project>
For those not “in the know” this manipulates the <ItemGroup /> named Link after it has been defined in the project file, if we assume a vanilla .vcxproj in order to append the linker switch to the end.
Well done, nothing to see here, move on.
Nope, not so! This is what trips up CompilerIdCXX.vcxproj (Modules/CMakeDetermineCXXCompiler.cmake ⇒ Modules/CMakeFindBinUtils.cmake) with:
error MSB4096: The item “Debug\CMakeCXXCompilerId.obj” in item list “Link” does not define a value for metadata “AdditionalOptions”. In order to use this metadata, either qualify it by specifying %(Link.AdditionalOptions), or ensure that all items in this list define a value for this metadata.
Hmm, very interesting. Why would Link items not have this metadata which gets set by every vanilla C/C++ .vcxproj file?! And why did I even ask?
Of course wasted a massive amount of time on this, because the CMake generator step for VS does considerably more than is conventional in this ecosystem and generates throwaway projects with paths hardcoded to the system and the CMake version and other goodness. It’s the Unix ./configure bolted onto default VS builds for no particular reason.
At a minimum I would have expected that the underhanded detection mechanisms inhibit Directory.Build.* and friends (like with ImportDirectoryBuildProps=false and friends), so the developer can see the failure in the generated projects which then do include them, but the detection with “out-of-tree” inside subdirectory (build dir underneath source dir) doesn’t accidentally catch ambient MSBuild stuff during its “ssssshhhhh”-phase.
Instead I have to work around CMake’s hacks now with this:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemDefinitionGroup>
<Link><!-- Bolt the metadata onto the Link items now, using whatever may have been set before -->
<AdditionalOptions>%(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<Target Name="OverrideLinkerSwitches" AfterTargets="ComputeLinkSwitches" BeforeTargets="Link">
<ItemGroup>
<Link>
<AdditionalOptions>%(Link.AdditionalOptions) /pdbaltpath:%_PDB%</AdditionalOptions>
</Link>
</ItemGroup>
</Target>
</Project>
If you can tell I am no big fan of CMake, that’s no coincidence. But at least this way others will know how to work around it.
At least I got to drive -Wdev --debug-find --debug-output --log-level=DEBUG again.
[imagine a hide the pain Harold GIF here]
PS: it doesn’t find either, so this thread is equally valid for CMAKE_CXX_COMPILER.