jfb created this revision. jfb added reviewers: JDevlieghere, bruno. Herald added subscribers: cfe-commits, dexonsmith, jkorous. Herald added a project: clang.
The motivation for 'physical' mode in D58169 <https://reviews.llvm.org/D58169> was pretty sensible, but it has one unfortunate side-effect: working close to the maximum path size now causes failures when it used not to. We therefore want to be able to set the VFS mode for the driver. This requires moving where the driver's VFS is initialized because arguments aren't available in the Driver constructor. I was careful to put this initialization early enough that the VFS isn't used yet (it would segfault if it were, since it's not set). rdar://problem/54103540 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D65986 Files: clang/include/clang/Driver/Driver.h clang/include/clang/Driver/Options.td clang/lib/Driver/Driver.cpp clang/test/Driver/vfsmode.py
Index: clang/test/Driver/vfsmode.py =================================================================== --- /dev/null +++ clang/test/Driver/vfsmode.py @@ -0,0 +1,49 @@ +# Check that we can change the VFS mode between 'real' and 'physical', which +# affects the maximum path length that clang can deal with. + +# UNSUPPORTED: system-windows + +# RUN: rm -rf xxx* +# RUN: python %s > %t +# RUN: cat %t | xargs not %clang 2>&1 | FileCheck %s --check-prefix=PHYSICAL +# RUN: cat %t | xargs not %clang -ivfsmode=physical 2>&1 | FileCheck %s --check-prefix=PHYSICAL +# RUN: cat %t | xargs %clang -ivfsmode=real + +# PHYSICAL: error: no such file or directory: + +import os +import subprocess + +current = os.path.realpath(os.curdir) +name_max = int(subprocess.check_output("getconf NAME_MAX /", shell=True)) +path_max = int(subprocess.check_output("getconf PATH_MAX /", shell=True)) +assert name_max > 0 +assert path_max > 0 + +filename = 'o.c' +code = "int main() { return 0; }" + +relative = '' +absolute = current + +# Create directories which almost, but not quite, exhaust PATH_MAX. +target_len = path_max - 1 +while len(absolute) < target_len: + new_name_len = target_len - len(absolute) - 1 + new_name_len = new_name_len if new_name_len < name_max else name_max + absolute = os.path.join(absolute, 'x' * new_name_len) + relative = os.path.join(relative, 'x' * new_name_len) + os.mkdir(relative) + assert os.path.exists(absolute) + assert os.path.exists(relative) + +# Create a file whose relative path doesn't exceed PATH_MAX, but whose absolute +# path does. +file_relative_path = os.path.join(relative, filename) +with open(file_relative_path, 'w') as f: + f.write(code) + +assert os.path.exists(file_relative_path) + +# Print out the relative path so lit can pass to clang. +print file_relative_path Index: clang/lib/Driver/Driver.cpp =================================================================== --- clang/lib/Driver/Driver.cpp +++ clang/lib/Driver/Driver.cpp @@ -131,10 +131,6 @@ CCCGenericGCCName(""), Saver(Alloc), CheckInputsExist(true), GenReproducer(false), SuppressMissingInputWarning(false) { - // Provide a sane fallback if no VFS is specified. - if (!this->VFS) - this->VFS = llvm::vfs::createPhysicalFileSystem().release(); - Name = llvm::sys::path::filename(ClangExecutable); Dir = llvm::sys::path::parent_path(ClangExecutable); InstalledDir = Dir; // Provide a sensible default installed dir. @@ -150,6 +146,41 @@ ResourceDir = GetResourcesPath(ClangExecutable, CLANG_RESOURCE_DIR); } +void Driver::ParseVFSMode(ArrayRef<const char *> Args) { + const std::string OptionPrefix = + getOpts().getOption(options::OPT_ivfsmode).getPrefixedName(); + enum class VFSMode { Unknown, Real, Physical } Mode = VFSMode::Unknown; + for (const char *ArgPtr : Args) { + if (!ArgPtr) + continue; + const StringRef Arg = ArgPtr; + if (!Arg.startswith(OptionPrefix)) + continue; + const StringRef Value = Arg.drop_front(OptionPrefix.size()); + VFSMode M = llvm::StringSwitch<VFSMode>(Value) + .Case("real", VFSMode::Real) + .Case("physical", VFSMode::Physical) + .Default(VFSMode::Unknown); + if (M != VFSMode::Unknown) + Mode = M; + else + Diag(diag::err_drv_unsupported_option_argument) << OptionPrefix << Value; + } + + switch (Mode) { + case VFSMode::Unknown: + if (!this->VFS) { + LLVM_FALLTHROUGH; + case VFSMode::Physical: + this->VFS = llvm::vfs::createPhysicalFileSystem().release(); + } + break; + case VFSMode::Real: + this->VFS = llvm::vfs::getRealFileSystem().get(); + break; + } +} + void Driver::ParseDriverMode(StringRef ProgramName, ArrayRef<const char *> Args) { if (ClangNameParts.isEmpty()) @@ -946,6 +977,10 @@ } } + // We might try accessing the VFS fairly eatly, so make sure we have the + // right one. + ParseVFSMode(ArgList.slice(1)); + // We look for the driver mode option early, because the mode can affect // how other options are parsed. ParseDriverMode(ClangExecutable, ArgList.slice(1)); Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -2005,8 +2005,10 @@ HelpText<"Add directory to SYSTEM include search path, " "absolute paths are relative to -isysroot">, MetaVarName<"<directory>">, Flags<[CC1Option]>; -def ivfsoverlay : JoinedOrSeparate<["-"], "ivfsoverlay">, Group<clang_i_Group>, Flags<[CC1Option]>, - HelpText<"Overlay the virtual filesystem described by file over the real file system">; +def ivfsoverlay : JoinedOrSeparate<["-"], "ivfsoverlay">, Group<clang_i_Group>, Flags<[CC1Option]>, HelpText<"Overlay the virtual filesystem described by file over the real file system">; +def ivfsmode : Joined<["-"], "ivfsmode=">, Group<clang_i_Group>, Flags<[CC1Option, HelpHidden]>, + HelpText<"Use the virtual file system in 'real' mode, or 'physical' mode. In 'real' mode the working directory is linked to the process' working directory. In 'physical' mode it has its own working directory, independent of (but initially equal to) that of the process.">, + Values<"real,physical">; def imultilib : Separate<["-"], "imultilib">, Group<gfortran_Group>; def keep__private__externs : Flag<["-"], "keep_private_externs">; def l : JoinedOrSeparate<["-"], "l">, Flags<[LinkerInput, RenderJoined]>, Index: clang/include/clang/Driver/Driver.h =================================================================== --- clang/include/clang/Driver/Driver.h +++ clang/include/clang/Driver/Driver.h @@ -355,11 +355,13 @@ /// @name Driver Steps /// @{ - /// ParseDriverMode - Look for and handle the driver mode option in Args. + /// Look for and handle the VFS mode option in Args. + void ParseVFSMode(ArrayRef<const char *> Args); + + /// Look for and handle the driver mode option in Args. void ParseDriverMode(StringRef ProgramName, ArrayRef<const char *> Args); - /// ParseArgStrings - Parse the given list of strings into an - /// ArgList. + /// Parse the given list of strings into an ArgList. llvm::opt::InputArgList ParseArgStrings(ArrayRef<const char *> Args, bool IsClCompatMode, bool &ContainsError);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits