Skip to content

Commit

Permalink
[Driver] move FreeBSD header search path management to the driver
Browse files Browse the repository at this point in the history
This matches OpenBSD, and it supports Swift's use of clang for its C interop
functionality.  Recent changes to Swift use AddClangSystemIncludeArgs() to
inspect the cc1 args; this doesn't work for platforms where cc1 adds standard
include paths implicitly.  See:

<apple/swift@cf33542>

Also clean up InitHeaderSearch, making it clearer which targets manage header
search paths in the driver.

Differential Revision: https://reviews.llvm.org/D138183
  • Loading branch information
mhjacobson committed Nov 18, 2022
1 parent a35ad71 commit ba7a1d9
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 64 deletions.
35 changes: 35 additions & 0 deletions clang/lib/Driver/ToolChains/FreeBSD.cpp
Expand Up @@ -11,6 +11,7 @@
#include "Arch/Mips.h"
#include "Arch/Sparc.h"
#include "CommonArgs.h"
#include "clang/Config/config.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
Expand Down Expand Up @@ -408,6 +409,40 @@ unsigned FreeBSD::GetDefaultDwarfVersion() const {
return 4;
}

void FreeBSD::AddClangSystemIncludeArgs(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
const Driver &D = getDriver();

if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
return;

if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
SmallString<128> Dir(D.ResourceDir);
llvm::sys::path::append(Dir, "include");
addSystemInclude(DriverArgs, CC1Args, Dir.str());
}

if (DriverArgs.hasArg(options::OPT_nostdlibinc))
return;

// Check for configure-time C include directories.
StringRef CIncludeDirs(C_INCLUDE_DIRS);
if (CIncludeDirs != "") {
SmallVector<StringRef, 5> dirs;
CIncludeDirs.split(dirs, ":");
for (StringRef dir : dirs) {
StringRef Prefix =
llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : "";
addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
}
return;
}

addExternCSystemInclude(DriverArgs, CC1Args,
concat(D.SysRoot, "/usr/include"));
}

void FreeBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
addSystemInclude(DriverArgs, CC1Args,
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/FreeBSD.h
Expand Up @@ -58,6 +58,9 @@ class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF {
bool IsMathErrnoDefault() const override { return false; }
bool IsObjCNonFragileABIDefault() const override { return true; }

void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
CXXStdlibType GetDefaultCXXStdlibType() const override;
void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
Expand Down
119 changes: 55 additions & 64 deletions clang/lib/Lex/InitHeaderSearch.cpp
Expand Up @@ -42,9 +42,9 @@ struct DirectoryLookupInfo {
: Group(Group), Lookup(Lookup), UserEntryIdx(UserEntryIdx) {}
};

/// InitHeaderSearch - This class makes it easier to set the search paths of
/// a HeaderSearch object. InitHeaderSearch stores several search path lists
/// internally, which can be sent to a HeaderSearch object in one swoop.
/// This class makes it easier to set the search paths of a HeaderSearch object.
/// InitHeaderSearch stores several search path lists internally, which can be
/// sent to a HeaderSearch object in one swoop.
class InitHeaderSearch {
std::vector<DirectoryLookupInfo> IncludePath;
std::vector<std::pair<std::string, bool> > SystemHeaderPrefixes;
Expand All @@ -58,56 +58,54 @@ class InitHeaderSearch {
: Headers(HS), Verbose(verbose), IncludeSysroot(std::string(sysroot)),
HasSysroot(!(sysroot.empty() || sysroot == "/")) {}

/// AddPath - Add the specified path to the specified group list, prefixing
/// the sysroot if used.
/// Add the specified path to the specified group list, prefixing the sysroot
/// if used.
/// Returns true if the path exists, false if it was ignored.
bool AddPath(const Twine &Path, IncludeDirGroup Group, bool isFramework,
Optional<unsigned> UserEntryIdx = None);

/// AddUnmappedPath - Add the specified path to the specified group list,
/// without performing any sysroot remapping.
/// Add the specified path to the specified group list, without performing any
/// sysroot remapping.
/// Returns true if the path exists, false if it was ignored.
bool AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,
bool isFramework,
Optional<unsigned> UserEntryIdx = None);

/// AddSystemHeaderPrefix - Add the specified prefix to the system header
/// prefix list.
/// Add the specified prefix to the system header prefix list.
void AddSystemHeaderPrefix(StringRef Prefix, bool IsSystemHeader) {
SystemHeaderPrefixes.emplace_back(std::string(Prefix), IsSystemHeader);
}

/// AddGnuCPlusPlusIncludePaths - Add the necessary paths to support a gnu
/// libstdc++.
/// Add the necessary paths to support a gnu libstdc++.
/// Returns true if the \p Base path was found, false if it does not exist.
bool AddGnuCPlusPlusIncludePaths(StringRef Base, StringRef ArchDir,
StringRef Dir32, StringRef Dir64,
const llvm::Triple &triple);

/// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to support a MinGW
/// libstdc++.
/// Add the necessary paths to support a MinGW libstdc++.
void AddMinGWCPlusPlusIncludePaths(StringRef Base,
StringRef Arch,
StringRef Version);

// AddDefaultCIncludePaths - Add paths that should always be searched.
/// Add paths that should always be searched.
void AddDefaultCIncludePaths(const llvm::Triple &triple,
const HeaderSearchOptions &HSOpts);

// AddDefaultCPlusPlusIncludePaths - Add paths that should be searched when
// compiling c++.
/// Add paths that should be searched when compiling c++.
void AddDefaultCPlusPlusIncludePaths(const LangOptions &LangOpts,
const llvm::Triple &triple,
const HeaderSearchOptions &HSOpts);

/// AddDefaultSystemIncludePaths - Adds the default system include paths so
/// that e.g. stdio.h is found.
/// Returns true iff AddDefaultIncludePaths should do anything. If this
/// returns false, include paths should instead be handled in the driver.
bool ShouldAddDefaultIncludePaths(const llvm::Triple &triple);

/// Adds the default system include paths so that e.g. stdio.h is found.
void AddDefaultIncludePaths(const LangOptions &Lang,
const llvm::Triple &triple,
const HeaderSearchOptions &HSOpts);

/// Realize - Merges all search path lists into one list and send it to
/// HeaderSearch.
/// Merges all search path lists into one list and send it to HeaderSearch.
void Realize(const LangOptions &Lang);
};

Expand Down Expand Up @@ -225,18 +223,15 @@ void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(StringRef Base,

void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
const HeaderSearchOptions &HSOpts) {
llvm::Triple::OSType os = triple.getOS();

if (triple.isOSDarwin()) {
if (!ShouldAddDefaultIncludePaths(triple))
llvm_unreachable("Include management is handled in the driver.");
}

llvm::Triple::OSType os = triple.getOS();

if (HSOpts.UseStandardSystemIncludes) {
switch (os) {
case llvm::Triple::CloudABI:
case llvm::Triple::FreeBSD:
case llvm::Triple::NetBSD:
case llvm::Triple::OpenBSD:
case llvm::Triple::NaCl:
case llvm::Triple::PS4:
case llvm::Triple::PS5:
Expand Down Expand Up @@ -280,12 +275,6 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
}

switch (os) {
case llvm::Triple::Linux:
case llvm::Triple::Hurd:
case llvm::Triple::Solaris:
case llvm::Triple::OpenBSD:
llvm_unreachable("Include management is handled in the driver.");

case llvm::Triple::CloudABI: {
// <sysroot>/<triple>/include
SmallString<128> P = StringRef(HSOpts.ResourceDir);
Expand Down Expand Up @@ -386,20 +375,12 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(
const LangOptions &LangOpts, const llvm::Triple &triple,
const HeaderSearchOptions &HSOpts) {
llvm::Triple::OSType os = triple.getOS();
// FIXME: temporary hack: hard-coded paths.

if (triple.isOSDarwin()) {
if (!ShouldAddDefaultIncludePaths(triple))
llvm_unreachable("Include management is handled in the driver.");
}

// FIXME: temporary hack: hard-coded paths.
llvm::Triple::OSType os = triple.getOS();
switch (os) {
case llvm::Triple::Linux:
case llvm::Triple::Hurd:
case llvm::Triple::Solaris:
case llvm::Triple::AIX:
llvm_unreachable("Include management is handled in the driver.");
break;
case llvm::Triple::Win32:
switch (triple.getEnvironment()) {
default: llvm_unreachable("Include management is handled in the driver.");
Expand All @@ -425,46 +406,56 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(
}
}

void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
const llvm::Triple &triple,
const HeaderSearchOptions &HSOpts) {
// NB: This code path is going away. All of the logic is moving into the
// driver which has the information necessary to do target-specific
// selections of default include paths. Each target which moves there will be
// exempted from this logic here until we can delete the entire pile of code.
bool InitHeaderSearch::ShouldAddDefaultIncludePaths(
const llvm::Triple &triple) {
switch (triple.getOS()) {
default:
break; // Everything else continues to use this routine's logic.

case llvm::Triple::AIX:
case llvm::Triple::Emscripten:
case llvm::Triple::Linux:
case llvm::Triple::FreeBSD:
case llvm::Triple::Hurd:
case llvm::Triple::Linux:
case llvm::Triple::OpenBSD:
case llvm::Triple::Solaris:
case llvm::Triple::WASI:
case llvm::Triple::AIX:
return;
return false;

case llvm::Triple::Win32:
if (triple.getEnvironment() != llvm::Triple::Cygnus ||
triple.isOSBinFormatMachO())
return;
return false;
break;

case llvm::Triple::UnknownOS:
if (triple.isWasm())
return;
return false;
break;

default:
break;
}

// All header search logic is handled in the Driver for Darwin.
return true; // Everything else uses AddDefaultIncludePaths().
}

void InitHeaderSearch::AddDefaultIncludePaths(
const LangOptions &Lang, const llvm::Triple &triple,
const HeaderSearchOptions &HSOpts) {
// NB: This code path is going away. All of the logic is moving into the
// driver which has the information necessary to do target-specific
// selections of default include paths. Each target which moves there will be
// exempted from this logic in ShouldAddDefaultIncludePaths() until we can
// delete the entire pile of code.
if (!ShouldAddDefaultIncludePaths(triple))
return;

// NOTE: some additional header search logic is handled in the driver for
// Darwin.
if (triple.isOSDarwin()) {
if (HSOpts.UseStandardSystemIncludes) {
// Add the default framework include paths on Darwin.
if (triple.isDriverKit()) {
AddPath("/System/DriverKit/System/Library/Frameworks", System, true);
}
else {
} else {
AddPath("/System/Library/Frameworks", System, true);
AddPath("/Library/Frameworks", System, true);
}
Expand All @@ -484,9 +475,9 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
AddDefaultCIncludePaths(triple, HSOpts);
}

/// RemoveDuplicates - If there are duplicate directory entries in the specified
/// search list, remove the later (dead) ones. Returns the number of non-system
/// headers removed, which is used to update NumAngled.
/// If there are duplicate directory entries in the specified search list,
/// remove the later (dead) ones. Returns the number of non-system headers
/// removed, which is used to update NumAngled.
static unsigned RemoveDuplicates(std::vector<DirectoryLookupInfo> &SearchList,
unsigned First, bool Verbose) {
llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenDirs;
Expand Down
7 changes: 7 additions & 0 deletions clang/test/Driver/freebsd.c
Expand Up @@ -213,3 +213,10 @@
// RELOCATABLE-NOT: "-dynamic-linker"
// RELOCATABLE-NOT: "-l
// RELOCATABLE-NOT: crt{{[^./]+}}.o

// Check that the driver passes include paths to cc1 on FreeBSD.
// RUN: %clang -### %s --target=x86_64-unknown-freebsd13.1 -r 2>&1 \
// RUN: | FileCheck %s --check-prefix=DRIVER-PASS-INCLUDES
// DRIVER-PASS-INCLUDES: "-cc1" {{.*}}"-resource-dir" "[[RESOURCE:[^"]+]]"
// DRIVER-PASS-INCLUDES-SAME: {{^}} "-internal-isystem" "[[RESOURCE]]{{/|\\\\}}include"
// DRIVER-PASS-INCLUDES-SAME: {{^}} "-internal-externc-isystem" "/usr/include"
8 changes: 8 additions & 0 deletions clang/test/Driver/freebsd.cpp
Expand Up @@ -40,3 +40,11 @@
// CHECK-LIBCXX-SYSROOT-SLASH: "-cc1"
// CHECK-LIBCXX-SYSROOT-SLASH-SAME: "-isysroot" "[[SYSROOT:[^"]+/]]"
// CHECK-LIBCXX-SYSROOT-SLASH-SAME: "-internal-isystem" "[[SYSROOT]]usr/include/c++/v1"

// Check that the driver passes include paths to cc1 on FreeBSD.
// RUN: %clang -### %s --target=x86_64-unknown-freebsd13.1 -r 2>&1 \
// RUN: | FileCheck %s --check-prefix=DRIVER-PASS-INCLUDES
// DRIVER-PASS-INCLUDES: "-cc1" {{.*}}"-resource-dir" "[[RESOURCE:[^"]+]]"
// DRIVER-PASS-INCLUDES-SAME: {{^}} "-internal-isystem" "/usr/include/c++/v1"
// DRIVER-PASS-INCLUDES-SAME: {{^}} "-internal-isystem" "[[RESOURCE]]{{/|\\\\}}include"
// DRIVER-PASS-INCLUDES-SAME: {{^}} "-internal-externc-isystem" "/usr/include"

0 comments on commit ba7a1d9

Please sign in to comment.