diff --git a/clang/include/clang/Driver/Distro.h b/clang/include/clang/Driver/Distro.h --- a/clang/include/clang/Driver/Distro.h +++ b/clang/include/clang/Driver/Distro.h @@ -23,6 +23,8 @@ class Distro { public: enum DistroType { + // Special value means that no detection was performed yet. + UninitializedDistro = -1, // NB: Releases of a particular Linux distro should be kept together // in this enum, because some tests are done by integer comparison against // the first and last known member in the family, e.g. IsRedHat(). diff --git a/clang/lib/Driver/Distro.cpp b/clang/lib/Driver/Distro.cpp --- a/clang/lib/Driver/Distro.cpp +++ b/clang/lib/Driver/Distro.cpp @@ -21,20 +21,10 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS, const llvm::Triple &TargetOrHost) { - // If we don't target Linux, no need to check the distro. This saves a few - // OS calls. - if (!TargetOrHost.isOSLinux()) - return Distro::UnknownDistro; - - // If the host is not running Linux, and we're backed by a real file system, - // no need to check the distro. This is the case where someone is - // cross-compiling from BSD or Windows to Linux, and it would be meaningless - // to try to figure out the "distro" of the non-Linux host. - IntrusiveRefCntPtr RealFS = - llvm::vfs::getRealFileSystem(); - llvm::Triple HostTriple(llvm::sys::getProcessTriple()); - if (!HostTriple.isOSLinux() && &VFS == RealFS.get()) - return Distro::UnknownDistro; + // We're definitely on Linux, so start looking for the filesystem artifacts. + // TODO: adjust this to match modern freedesktop.org's compilant system + // with /etc/os-release and/or /usr/lib/os-release. For the details, + // see https://www.freedesktop.org/software/systemd/man/os-release.html. llvm::ErrorOr> File = VFS.getBufferForFile("/etc/lsb-release"); @@ -168,5 +158,36 @@ return Distro::UnknownDistro; } +static Distro::DistroType GetDistro(llvm::vfs::FileSystem &VFS, + const llvm::Triple &TargetOrHost) { + static Distro::DistroType Type = Distro::UninitializedDistro; + + // If we don't target Linux, no need to check the distro. This saves a few + // OS calls. + if (!TargetOrHost.isOSLinux()) + return Distro::UnknownDistro; + + // If we perform the detection already, return the result. This saves a few + // more OS calls assuming there was no underlying on-the fly distro change. + if (Type != Distro::UninitializedDistro) + return Type; + + // If the host is not running Linux, and we're backed by a real file system, + // no need to check the distro. This is the case where someone is + // cross-compiling from BSD or Windows to Linux, and it would be meaningless + // to try to figure out the "distro" of the non-Linux host. + IntrusiveRefCntPtr RealFS = + llvm::vfs::getRealFileSystem(); + llvm::Triple HostTriple(llvm::sys::getProcessTriple()); + + if (!HostTriple.isOSLinux() && &VFS == RealFS.get()) + Type = Distro::UnknownDistro; + else + // Perform the detection and save the result. + Type = DetectDistro(VFS, TargetOrHost); + + return Type; +} + Distro::Distro(llvm::vfs::FileSystem &VFS, const llvm::Triple &TargetOrHost) - : DistroVal(DetectDistro(VFS, TargetOrHost)) {} + : DistroVal(GetDistro(VFS, TargetOrHost)) {}