From dff020e679bf8f8de4b401d38de6a5e9f43ea847 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 5 Dec 2025 15:07:31 -0500 Subject: [PATCH 1/2] FASTBuild: Add internal helper for intermediate directory creation --- Source/cmFastbuildNormalTargetGenerator.cxx | 6 ++++++ Source/cmFastbuildNormalTargetGenerator.h | 1 + 2 files changed, 7 insertions(+) diff --git a/Source/cmFastbuildNormalTargetGenerator.cxx b/Source/cmFastbuildNormalTargetGenerator.cxx index efeabaeb60..fab5d931a2 100644 --- a/Source/cmFastbuildNormalTargetGenerator.cxx +++ b/Source/cmFastbuildNormalTargetGenerator.cxx @@ -523,6 +523,12 @@ void cmFastbuildNormalTargetGenerator::EnsureDirectoryExists( } } +void cmFastbuildNormalTargetGenerator::EnsureParentDirectoryExists( + std::string const& path) const +{ + this->EnsureDirectoryExists(cmSystemTools::GetParentDirectory(path)); +} + std::vector cmFastbuildNormalTargetGenerator::GetManifestsAsFastbuildPath() const { diff --git a/Source/cmFastbuildNormalTargetGenerator.h b/Source/cmFastbuildNormalTargetGenerator.h index 5512b19a41..8a01f776cd 100644 --- a/Source/cmFastbuildNormalTargetGenerator.h +++ b/Source/cmFastbuildNormalTargetGenerator.h @@ -157,4 +157,5 @@ private: std::vector GetManifestsAsFastbuildPath() const; void EnsureDirectoryExists(std::string const& path) const; + void EnsureParentDirectoryExists(std::string const& path) const; }; From 6f1fe8853ddce3c6f0937e82db3ff8dbe5725586 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 5 Dec 2025 15:09:08 -0500 Subject: [PATCH 2/2] FASTBuild: Fix default MSVC compiler PDB paths When we pass a PDB output directory to the compiler in a path that requires quoting, the trailing backslash must be escaped to be parsed correctly by the compiler, e.g., `cl /Fd"path\with space\\"`. However, `fbuild` does not parse this correctly when extracting `/Fd`. Work around that bug by using a trailing forward slash in quotes instead. --- Source/cmFastbuildNormalTargetGenerator.cxx | 47 +++++++++++++-------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/Source/cmFastbuildNormalTargetGenerator.cxx b/Source/cmFastbuildNormalTargetGenerator.cxx index fab5d931a2..45b172e31c 100644 --- a/Source/cmFastbuildNormalTargetGenerator.cxx +++ b/Source/cmFastbuildNormalTargetGenerator.cxx @@ -68,6 +68,12 @@ std::string const UNITY_BUILD_BATCH_SIZE("UNITY_BUILD_BATCH_SIZE"); std::string const SKIP_UNITY_BUILD_INCLUSION("SKIP_UNITY_BUILD_INCLUSION"); std::string const UNITY_GROUP("UNITY_GROUP"); +#ifdef _WIN32 +char const kPATH_SLASH = '\\'; +#else +char const kPATH_SLASH = '/'; +#endif + } // anonymous namespace cmFastbuildNormalTargetGenerator::cmFastbuildNormalTargetGenerator( @@ -810,24 +816,31 @@ void cmFastbuildNormalTargetGenerator::ComputePaths( this->ConvertToFastbuildPath(linkerPDB)); } } - if (GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY) { - std::string const pdbDir = GeneratorTarget->GetCompilePDBDirectory(Config); - LogMessage("GetCompilePDBDirectory: " + pdbDir); - EnsureDirectoryExists(pdbDir); - std::string pdbName = this->GeneratorTarget->GetCompilePDBName(Config); - LogMessage("GetCompilePDBName: " + pdbDir); - // If we don't have Compiler's PDB, we must add a trailing slash to satisfy - // MSVC. - bool needTrailingSlash = false; - if (pdbName.empty()) { - needTrailingSlash = true; - } - std::string const compilerPDB = cmStrCat(pdbDir, '\\', pdbName); - if (!compilerPDB.empty()) { - target.Variables["CompilerPDB"] = cmSystemTools::ConvertToOutputPath( - this->ConvertToFastbuildPath(compilerPDB) + - (needTrailingSlash ? "\\ " : "")); + std::string const compilerPDB = this->ComputeTargetCompilePDB(this->Config); + if (!compilerPDB.empty()) { + LogMessage("ComputeTargetCompilePDB: " + compilerPDB); + std::string compilerPDBArg = cmSystemTools::ConvertToOutputPath( + this->ConvertToFastbuildPath(compilerPDB)); + if (cmHasSuffix(compilerPDB, '/')) { + // The compiler will choose the .pdb file name. + this->EnsureDirectoryExists(compilerPDB); + // ConvertToFastbuildPath dropped the trailing slash. Add it back. + // We do this after ConvertToOutputPath so that we can use a forward + // slash in the case that the argument is quoted. + if (cmHasSuffix(compilerPDBArg, '"')) { + // A quoted trailing backslash requires escaping, e.g., `/Fd"dir\\"`, + // but fbuild does not parse such arguments correctly as of 1.15. + // Always use a forward slash. + compilerPDBArg.insert(compilerPDBArg.size() - 1, 1, '/'); + } else { + // An unquoted trailing slash or backslash is fine. + compilerPDBArg.push_back(kPATH_SLASH); + } + } else { + // We have an explicit .pdb path with file name. + this->EnsureParentDirectoryExists(compilerPDB); } + target.Variables["CompilerPDB"] = std::move(compilerPDBArg); } std::string const impLibFullPath = GeneratorTarget->GetFullPath(Config, cmStateEnums::ImportLibraryArtifact);