| 1 | Author: Danny Milosavljevic <[email protected]>
|
| 2 | Date: 2025-10-20
|
| 3 | Subject: Make clang importer heed CPLUS_INCLUDE_PATH
|
| 4 |
|
| 5 | |
| 6 | |
| 7 | @@ -787,6 +787,9 @@
|
| 8 | SmallVector<std::pair<std::string, std::string>, 1> overridenFiles;
|
| 9 |
|
| 10 | bool requiresBuiltinHeadersInSystemModules;
|
| 11 | +
|
| 12 | + /// Extra arguments to pass to the Clang invocation (e.g., -isystem paths).
|
| 13 | + std::vector<std::string> extraArgs;
|
| 14 | };
|
| 15 |
|
| 16 | /// On Linux, some platform libraries (glibc, libstdc++) are not modularized.
|
| 17 | |
| 18 | |
| 19 | @@ -1326,6 +1326,12 @@
|
| 20 | importer->requiresBuiltinHeadersInSystemModules =
|
| 21 | fileMapping.requiresBuiltinHeadersInSystemModules;
|
| 22 |
|
| 23 | + // Add extra arguments from file mapping (e.g., C++ stdlib include paths).
|
| 24 | + ctx.ClangImporterOpts.ExtraArgs.insert(
|
| 25 | + ctx.ClangImporterOpts.ExtraArgs.end(),
|
| 26 | + fileMapping.extraArgs.begin(),
|
| 27 | + fileMapping.extraArgs.end());
|
| 28 | +
|
| 29 | // Create a new Clang compiler invocation.
|
| 30 | {
|
| 31 | if (auto ClangArgs = importer->getClangCC1Arguments(ctx, VFS))
|
| 32 | |
| 33 | |
| 34 | @@ -21,6 +21,7 @@
|
| 35 | #include "clang/Driver/ToolChain.h"
|
| 36 | #include "clang/Frontend/CompilerInstance.h"
|
| 37 | #include "llvm/WindowsDriver/MSVCPaths.h"
|
| 38 | +#include <cstdlib>
|
| 39 |
|
| 40 | using namespace swift;
|
| 41 |
|
| 42 | @@ -306,9 +307,71 @@
|
| 43 | {"cstdlib", "string", "vector"}, vfs)) {
|
| 44 | cxxStdlibDir = dir.value();
|
| 45 | } else {
|
| 46 | - if (!suppressDiagnostic)
|
| 47 | - ctx.Diags.diagnose(SourceLoc(), diag::libstdcxx_not_found, triple.str());
|
| 48 | - return;
|
| 49 | + // FALLBACK: Try reading CPLUS_INCLUDE_PATH from environment.
|
| 50 | + // This is needed because Swift doesn't go through the full clang driver
|
| 51 | + // command construction that processes environment variables into -cxx-isystem
|
| 52 | + // arguments. When AddClangCXXStdlibIncludeArgs fails to find GCC (e.g., due
|
| 53 | + // to --gcc-toolchain pointing to wrong location or GCC detection failing),
|
| 54 | + // parsedStdlibArgs will be empty and findFirstIncludeDir returns nullopt.
|
| 55 | + // In Guix, CPLUS_INCLUDE_PATH is set by the build environment.
|
| 56 | + const char *cplusIncludePath = std::getenv("CPLUS_INCLUDE_PATH");
|
| 57 | + if (cplusIncludePath) {
|
| 58 | + llvm::SmallVector<llvm::StringRef, 8> envPaths;
|
| 59 | + llvm::StringRef(cplusIncludePath).split(envPaths, ':', -1, false);
|
| 60 | +
|
| 61 | + for (const auto &envPath : envPaths) {
|
| 62 | + Path dir(envPath.str());
|
| 63 | + // Check if this directory contains C++ stdlib headers
|
| 64 | + Path testFile(dir);
|
| 65 | + llvm::sys::path::append(testFile, "cstdlib");
|
| 66 | + if (vfs->exists(testFile)) {
|
| 67 | + llvm::sys::path::remove_dots(dir, /*remove_dot_dot=*/true);
|
| 68 | + cxxStdlibDir = dir;
|
| 69 | + break;
|
| 70 | + }
|
| 71 | + }
|
| 72 | + }
|
| 73 | +
|
| 74 | + if (cxxStdlibDir.empty()) {
|
| 75 | + if (!suppressDiagnostic)
|
| 76 | + ctx.Diags.diagnose(SourceLoc(), diag::libstdcxx_not_found, triple.str());
|
| 77 | + return;
|
| 78 | + }
|
| 79 | + }
|
| 80 | +
|
| 81 | + // ADD INCLUDE PATHS FOR ARCH-SPECIFIC HEADERS:
|
| 82 | + // GCC's libstdc++ has architecture-specific headers in subdirectories.
|
| 83 | + // Standard clang driver adds THREE separate -internal-isystem include paths:
|
| 84 | + // 1. /path/to/gcc/include/c++ (base: cstdlib, string, vector, etc.)
|
| 85 | + // 2. /path/to/gcc/include/c++/TRIPLE (arch: bits/c++config.h, ext/*, etc.)
|
| 86 | + // 3. /path/to/gcc/include/c++/backward (backward compatibility headers)
|
| 87 | + // This allows clang to find both generic headers (cstddef) and arch-specific
|
| 88 | + // headers (bits/c++config.h) in their respective directories.
|
| 89 | + //
|
| 90 | + // We add these three paths as -isystem arguments via fileMapping.extraArgs.
|
| 91 | + // This is equivalent to what clang's AddClangCXXStdlibIncludeArgs does when
|
| 92 | + // it calls addSystemInclude three times in Gnu.cpp:addLibStdCXXIncludePaths.
|
| 93 | + // Using -isystem instead of VFS redirects ensures error messages reference
|
| 94 | + // real filesystem paths that users can verify exist.
|
| 95 | +
|
| 96 | + // 1. Base directory (already found above in cxxStdlibDir)
|
| 97 | + fileMapping.extraArgs.push_back("-isystem");
|
| 98 | + fileMapping.extraArgs.push_back(std::string(cxxStdlibDir));
|
| 99 | +
|
| 100 | + // 2. Architecture-specific subdirectory (e.g., x86_64-unknown-linux-gnu)
|
| 101 | + Path archSpecificDir(cxxStdlibDir);
|
| 102 | + llvm::sys::path::append(archSpecificDir, triple.str());
|
| 103 | + if (vfs->exists(archSpecificDir)) {
|
| 104 | + fileMapping.extraArgs.push_back("-isystem");
|
| 105 | + fileMapping.extraArgs.push_back(std::string(archSpecificDir));
|
| 106 | + }
|
| 107 | +
|
| 108 | + // 3. Backward compatibility directory
|
| 109 | + Path backwardDir(cxxStdlibDir);
|
| 110 | + llvm::sys::path::append(backwardDir, "backward");
|
| 111 | + if (vfs->exists(backwardDir)) {
|
| 112 | + fileMapping.extraArgs.push_back("-isystem");
|
| 113 | + fileMapping.extraArgs.push_back(std::string(backwardDir));
|
| 114 | }
|
| 115 |
|
| 116 | Path actualModuleMapPath;
|