Skip to content

Clang doesn't add builtins directory (LLVM-292) #83

Closed
@aykevl

Description

@aykevl

Clang has multiple flags for controlling the include path. From the documentation:

-nostdinc
Do not search the standard system directories or compiler builtin directories for include files.

-nostdlibinc
Do not search the standard system directories for include files, but do search compiler builtin include directories.

-nobuiltininc
Do not search clang’s builtin directory for include files.

So in effect, -nostdinc implies -nostdlibinc and -nobuiltininc. But to control the standard system include dir and the builtins include dir separately, we have -nostdlibinc and -nobuiltininc to control those two kinds of include dirs separately.

You can see the logic here for the RISCV toolchain:

void RISCVToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
                                               ArgStringList &CC1Args) const {
  if (DriverArgs.hasArg(options::OPT_nostdinc))
    return;

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

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

For BareMetal it's similar, with the addition of multilib:

void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
                                          ArgStringList &CC1Args) const {
  if (DriverArgs.hasArg(options::OPT_nostdinc))
    return;

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

  if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) {
    const SmallString<128> SysRoot(computeSysRoot());
    if (!SysRoot.empty()) {
      for (const Multilib &M : getOrderedMultilibs()) {
        SmallString<128> Dir(SysRoot);
        llvm::sys::path::append(Dir, M.includeSuffix());
        llvm::sys::path::append(Dir, "include");
        addSystemInclude(DriverArgs, CC1Args, Dir.str());
      }
    }
  }
}

Unfortunately, it seems that Xtensa ignores the builtins include directory unless a GCC installation has been found. In fact, if the -nostdlibinc flag is passed, it exits early without adding the builtins directory at all!

void XtensaToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
                                                ArgStringList &CC1Args) const {
  if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc) ||
      DriverArgs.hasArg(options::OPT_nostdlibinc))
    return;

  if (!getDriver().SysRoot.empty()) {
    SmallString<128> Dir(getDriver().SysRoot);
    llvm::sys::path::append(Dir, "include");
    addSystemInclude(DriverArgs, CC1Args, Dir.str());
  } else if (GCCInstallation.isValid()) {
    SmallString<128> Path1(getDriver().ResourceDir);
    llvm::sys::path::append(Path1, "include");
    SmallString<128> Path2(GCCToolchainDir);
    llvm::sys::path::append(Path2, GCCToolchainName, "sys-include");
    SmallString<128> Path3(GCCToolchainDir);
    llvm::sys::path::append(Path3, GCCToolchainName, "include");

    const StringRef Paths[] = {Path1, Path2, Path3};
    addSystemIncludes(DriverArgs, CC1Args, Paths);
  } else {
    SmallString<128> Dir(computeSysRoot());
    llvm::sys::path::append(Dir, "include");
    addSystemInclude(DriverArgs, CC1Args, Dir.str());
  }
}

This makes no sense to me, since the resources directory is specific to Clang. On Linux, it's the /usr/lib/clang/<version>/include/ directory.

In TinyGo, we're not using a GCC installation. We use picolibc as the libc, and otherwise use LLVM native tools. Therefore, there is no GCC installation. To better control this, we pass -nostdlibinc to ignore the system libc, with the expectation that the builtins directory is still added. Xtensa is the only platform where this is not the case.

Somehow this still works when using Clang as-is (hence why I don't have an easy reproducer) because Clang seems to add this directory again somewhere else, but when I use it with libclang and specify the resource directory manually, the builtins directory doesn't get added.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions