Skip to content

Conversation

@simpal01
Copy link
Contributor

@simpal01 simpal01 commented Jul 2, 2025

This patch extends the Multilib Yaml format to allow specifying an IncludeDirs for the header path/s per multilib variant. The goal is to enable fine-grained control over header search paths for each multilib variant. This feature is especially useful in setups where header paths deviate from the default bare-metal assumptions. For example, when headers are shared across target triples, it becomes necessary to organize them under target-triple-specific directories to ensure correct resolution.

In the Clang driver, GCCSuffix, OSSuffix and IncludeSuffix are path suffixes that help the compiler locate the correct set of headers and libraries for the selected target. Clang’s multilib infrastructure uses the Multilib class to encapsulate these suffixes. Currently, in the bare-metal Clang driver, all of these suffixes — GCCSuffix, OSSuffix, and IncludeSuffix — are effectively mapped to the Dir field specified in the multilib.yaml configuration.

This patch allows it to be configured independently of Dir, enabling finer-grained control over header search directories for each multilib variant.

Key Changes:

  • New Field: IncludeDirs in multilib.yaml (header directory or list of header directories, strings, optional).

  • When present, this path is passed to the Multilib constructor and appended to the sysroot during header path resolution. If omitted, behaviour defaults to preserving current behaviour.

For example,

Dir: aarch64-none-elf/aarch64a_exn_rtti_unaligned
Flags:
--target=aarch64-unknown-none-elf
IncludeDirs:
include
include-libunwind
aarch64-none-elf/include
aarch64-none-elf/aarch64a_exn_rtti_unaligned/include

Implementation Notes:

  1. Extend the YAML parser to read the IncludeDirs key.
  2. Update the Multilib constructor to store the content from this field.
  3. Ensure the driver logic reads and applies IncludeDirs correctly.

This patch extends the Multilib Yaml format to allow
specifying an IncludePath for the header path/s per
multilib variant. The goal is to enable fine-grained
control over header search paths for each multilib variant.
This feature is especially useful in setups where header
paths deviate from the default bare-metal assumptions.
For example, when headers are shared across target triples,
it becomes necessary to organize them under target-triple-specific
directories to ensure correct resolution.

In the Clang driver, GCCSuffix, OSSuffix and IncludeSuffix
are path suffixes that help the compiler locate the correct
set of headers and libraries for the selected target.
Clang’s multilib infrastructure uses the Multilib class to
encapsulate these suffixes. Currently, in the bare-metal
Clang driver, all of these suffixes — GCCSuffix, OSSuffix, and
IncludeSuffix — are effectively mapped to the Dir field specified
in the multilib.yaml configuration.

This patch allows it to be configured independently of Dir,
enabling finer-grained control over header search paths for each multilib variant.

Key Changes:
New Field: IncludePath in multilib.yaml (header path or list of header
paths, strings, optional). When present, this path is passed to the
Multilib constructor and appended to the sysroot during header path resolution.
If omitted, behaviour defaults to preserving current behaviour.

For example,
- Dir: aarch64-none-elf/aarch64a_exn_rtti_unaligned
  Flags:
  - --target=aarch64-unknown-none-elf
  IncludePath:
  - include
  - include-libunwind
  - aarch64-none-elf/include
  - aarch64-none-elf/aarch64a_exn_rtti_unaligned/include

Implementation Notes:
1. Extend the YAML parser to read the IncludePath key.
2. Update the Multilib constructor to store the content from this field.
3. Ensure the driver logic reads and applies IncludePath correctly.
@simpal01 simpal01 marked this pull request as draft July 2, 2025 08:36
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' labels Jul 2, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 2, 2025

@llvm/pr-subscribers-clang-driver

@llvm/pr-subscribers-clang

Author: Simi Pallipurath (simpal01)

Changes

This patch extends the Multilib Yaml format to allow specifying an IncludePath for the header path/s per multilib variant. The goal is to enable fine-grained control over header search paths for each multilib variant. This feature is especially useful in setups where header paths deviate from the default bare-metal assumptions. For example, when headers are shared across target triples, it becomes necessary to organize them under target-triple-specific directories to ensure correct resolution.

In the Clang driver, GCCSuffix, OSSuffix and IncludeSuffix are path suffixes that help the compiler locate the correct set of headers and libraries for the selected target. Clang’s multilib infrastructure uses the Multilib class to encapsulate these suffixes. Currently, in the bare-metal Clang driver, all of these suffixes — GCCSuffix, OSSuffix, and IncludeSuffix — are effectively mapped to the Dir field specified in the multilib.yaml configuration.

This patch allows it to be configured independently of Dir, enabling finer-grained control over header search paths for each multilib variant.

Key Changes:

  • New Field: IncludePath in multilib.yaml (header path or list of header paths, strings, optional).

  • When present, this path is passed to the Multilib constructor and appended to the sysroot during header path resolution. If omitted, behaviour defaults to preserving current behaviour.

For example,

  • Dir: aarch64-none-elf/aarch64a_exn_rtti_unaligned Flags:
    • --target=aarch64-unknown-none-elf IncludePath:
    • include
    • include-libunwind
    • aarch64-none-elf/include
    • aarch64-none-elf/aarch64a_exn_rtti_unaligned/include

Implementation Notes:

  1. Extend the YAML parser to read the IncludePath key.
  2. Update the Multilib constructor to store the content from this field.
  3. Ensure the driver logic reads and applies IncludePath correctly.

Full diff: https://github.com/llvm/llvm-project/pull/146651.diff

3 Files Affected:

  • (modified) clang/include/clang/Driver/Multilib.h (+7)
  • (modified) clang/lib/Driver/Multilib.cpp (+12-3)
  • (modified) clang/lib/Driver/ToolChains/BareMetal.cpp (+29-8)
diff --git a/clang/include/clang/Driver/Multilib.h b/clang/include/clang/Driver/Multilib.h
index fc071ef48ca0f..1f1372508c480 100644
--- a/clang/include/clang/Driver/Multilib.h
+++ b/clang/include/clang/Driver/Multilib.h
@@ -35,12 +35,14 @@ class Driver;
 class Multilib {
 public:
   using flags_list = std::vector<std::string>;
+  using includepath_list = std::vector<std::string>;
 
 private:
   std::string GCCSuffix;
   std::string OSSuffix;
   std::string IncludeSuffix;
   flags_list Flags;
+  includepath_list IncludePath;
 
   // Optionally, a multilib can be assigned a string tag indicating that it's
   // part of a group of mutually exclusive possibilities. If two or more
@@ -62,6 +64,7 @@ class Multilib {
   /// This is enforced with an assert in the constructor.
   Multilib(StringRef GCCSuffix = {}, StringRef OSSuffix = {},
            StringRef IncludeSuffix = {}, const flags_list &Flags = flags_list(),
+           const includepath_list &IncludePath = includepath_list(),
            StringRef ExclusiveGroup = {},
            std::optional<StringRef> Error = std::nullopt);
 
@@ -81,6 +84,10 @@ class Multilib {
   /// All elements begin with either '-' or '!'
   const flags_list &flags() const { return Flags; }
 
+  /// Get the include paths specified in multilib.yaml under the 'IncludePath'
+  /// field
+  const includepath_list &includePath() const { return IncludePath; }
+
   /// Get the exclusive group label.
   const std::string &exclusiveGroup() const { return ExclusiveGroup; }
 
diff --git a/clang/lib/Driver/Multilib.cpp b/clang/lib/Driver/Multilib.cpp
index 87fa1af54a8ea..2cbb47dd7acdb 100644
--- a/clang/lib/Driver/Multilib.cpp
+++ b/clang/lib/Driver/Multilib.cpp
@@ -29,9 +29,11 @@ using namespace llvm::sys;
 
 Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix,
                    StringRef IncludeSuffix, const flags_list &Flags,
+                   const includepath_list &IncludePath,
                    StringRef ExclusiveGroup, std::optional<StringRef> Error)
     : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix),
-      Flags(Flags), ExclusiveGroup(ExclusiveGroup), Error(Error) {
+      Flags(Flags), IncludePath(IncludePath), ExclusiveGroup(ExclusiveGroup),
+      Error(Error) {
   assert(GCCSuffix.empty() ||
          (StringRef(GCCSuffix).front() == '/' && GCCSuffix.size() > 1));
   assert(OSSuffix.empty() ||
@@ -299,6 +301,7 @@ struct MultilibSerialization {
   std::string Dir;        // if this record successfully selects a library dir
   std::string Error;      // if this record reports a fatal error message
   std::vector<std::string> Flags;
+  std::vector<std::string> IncludePath;
   std::string Group;
 };
 
@@ -350,6 +353,7 @@ template <> struct llvm::yaml::MappingTraits<MultilibSerialization> {
     io.mapOptional("Dir", V.Dir);
     io.mapOptional("Error", V.Error);
     io.mapRequired("Flags", V.Flags);
+    io.mapOptional("IncludePath", V.IncludePath);
     io.mapOptional("Group", V.Group);
   }
   static std::string validate(IO &io, MultilibSerialization &V) {
@@ -359,6 +363,10 @@ template <> struct llvm::yaml::MappingTraits<MultilibSerialization> {
       return "the 'Dir' and 'Error' keys may not both be specified";
     if (StringRef(V.Dir).starts_with("/"))
       return "paths must be relative but \"" + V.Dir + "\" starts with \"/\"";
+    for (const auto &Path : V.IncludePath) {
+      if (StringRef(Path).starts_with("/"))
+        return "paths must be relative but \"" + Path + "\" starts with \"/\"";
+    }
     return std::string{};
   }
 };
@@ -489,7 +497,8 @@ MultilibSet::parseYaml(llvm::MemoryBufferRef Input,
   Multilibs.reserve(MS.Multilibs.size());
   for (const auto &M : MS.Multilibs) {
     if (!M.Error.empty()) {
-      Multilibs.emplace_back("", "", "", M.Flags, M.Group, M.Error);
+      Multilibs.emplace_back("", "", "", M.Flags, M.IncludePath, M.Group,
+                             M.Error);
     } else {
       std::string Dir;
       if (M.Dir != ".")
@@ -498,7 +507,7 @@ MultilibSet::parseYaml(llvm::MemoryBufferRef Input,
       // Multilib constructor. If we later support more than one type of group,
       // we'll have to look up the group name in MS.Groups, check its type, and
       // decide what to do here.
-      Multilibs.emplace_back(Dir, Dir, Dir, M.Flags, M.Group);
+      Multilibs.emplace_back(Dir, Dir, Dir, M.Flags, M.IncludePath, M.Group);
     }
   }
 
diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp
index 981395deb9dbc..dfa801ce887c7 100644
--- a/clang/lib/Driver/ToolChains/BareMetal.cpp
+++ b/clang/lib/Driver/ToolChains/BareMetal.cpp
@@ -417,10 +417,20 @@ void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
   const SmallString<128> SysRootDir(computeSysRoot());
   if (!SysRootDir.empty()) {
     for (const Multilib &M : getOrderedMultilibs()) {
-      SmallString<128> Dir(SysRootDir);
-      llvm::sys::path::append(Dir, M.includeSuffix());
-      llvm::sys::path::append(Dir, "include");
-      addSystemInclude(DriverArgs, CC1Args, Dir.str());
+      // Add include paths specified in multilib.yaml under the 'IncludePath'
+      // field
+      if (!M.includePath().empty()) {
+        for (const std::string &Path : M.includePath()) {
+          SmallString<128> Dir(SysRoot);
+          llvm::sys::path::append(Dir, Path);
+          addSystemInclude(DriverArgs, CC1Args, Dir.str());
+        }
+      } else {
+        SmallString<128> Dir(SysRootDir);
+        llvm::sys::path::append(Dir, M.includeSuffix());
+        llvm::sys::path::append(Dir, "include");
+        addSystemInclude(DriverArgs, CC1Args, Dir.str());
+      }
     }
   }
 }
@@ -501,10 +511,21 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
         addSystemInclude(DriverArgs, CC1Args, TargetDir.str());
         break;
       }
-      // Add generic path if nothing else succeeded so far.
-      llvm::sys::path::append(Dir, "include", "c++", "v1");
-      addSystemInclude(DriverArgs, CC1Args, Dir.str());
-      break;
+      if (!M.includePath().empty()) {
+        // Add include paths specified in multilib.yaml under the 'IncludePath'
+        // field
+        for (const std::string &Path : M.includePath()) {
+          Dir = SysRoot;
+          llvm::sys::path::append(Dir, Path, "c++", "v1");
+          addSystemInclude(DriverArgs, CC1Args, Dir.str());
+        }
+        break;
+      } else {
+        // Add generic path if nothing else succeeded so far.
+        llvm::sys::path::append(Dir, "include", "c++", "v1");
+        addSystemInclude(DriverArgs, CC1Args, Dir.str());
+        break;
+      }
     }
     case ToolChain::CST_Libstdcxx: {
       llvm::sys::path::append(Dir, "include", "c++");

@simpal01 simpal01 marked this pull request as ready for review July 10, 2025 14:34
@simpal01
Copy link
Contributor Author

simpal01 commented Jul 10, 2025

This pull request implements the feature proposed in the corresponding RFC https://discourse.llvm.org/t/rfc-support-target-triple-specific-include-paths-derived-from-sysroot-via-multilib-yaml-or-driver-logic/86925

It is being now changed to an open implementation to help explore the design further and gather feedback.
Kindly review .

# (/include) to IncludePath triggers the expected
# error.

# # RUN: %clang --target=aarch64-none-elf --multi-lib-config=%s %s -### -o /dev/null 2>&1 \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit surprised that this double # doesn't stop the run from happening!

Also slightly surprised that you didn't need a not on the command line. Does the clang driver not return a failure status when it finds an error in multilib.yaml?

Copy link
Contributor Author

@simpal01 simpal01 Jul 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. It did not give me any failure

-- Testing: 1 tests, 1 workers --
PASS: Clang :: Driver/baremetal-multilib-includepath-error.yaml (1 of 1)
Exit Code: 0

Command Output (stderr):
--
/data_nvme1n1/LLVM-PROJECT/build-driver/bin/clang --target=aarch64-none-elf --multi-lib-config=/data_nvme1n1/LLVM-PROJECT/llvm-project-fork/clang/test/Driver/baremetal-multilib-includepath-error.yaml /data_nvme1n1/LLVM-PROJECT/llvm-project-fork/clang/test/Driver/baremetal-multilib-includepath-error.yaml -### -o /dev/null 2>&1  | /data_nvme1n1/LLVM-PROJECT/build-driver/bin/FileCheck /data_nvme1n1/LLVM-PROJECT/llvm-project-fork/clang/test/Driver/baremetal-multilib-includepath-error.yaml --check-prefix=CHECK-ERROR # RUN: at line 15
+ /data_nvme1n1/LLVM-PROJECT/build-driver/bin/clang --target=aarch64-none-elf --multi-lib-config=/data_nvme1n1/LLVM-PROJECT/llvm-project-fork/clang/test/Driver/baremetal-multilib-includepath-error.yaml /data_nvme1n1/LLVM-PROJECT/llvm-project-fork/clang/test/Driver/baremetal-multilib-includepath-error.yaml -### -o /dev/null
+ /data_nvme1n1/LLVM-PROJECT/build-driver/bin/FileCheck /data_nvme1n1/LLVM-PROJECT/llvm-project-fork/clang/test/Driver/baremetal-multilib-includepath-error.yaml --check-prefix=CHECK-ERROR

--

********************

Testing Time: 0.07s

Total Discovered Tests: 1
  Passed: 1 (100.00%)

When running the command manually:

$ /data_nvme1n1/LLVM-PROJECT/build-driver/bin/clang --target=aarch64-none-elf --multi-lib-config=/data_nvme1n1/LLVM-PROJECT/llvm-project-fork/clang/test/Driver/baremetal-multilib-includepath-error.yaml /data_nvme1n1/LLVM-PROJECT/llvm-project-fork/clang/test/Driver/baremetal-multilib-includepath-error.yaml -### -o /dev/null 2>&1

/data_nvme1n1/LLVM-PROJECT/llvm-project-fork/clang/test/Driver/baremetal-multilib-includepath-error.yaml:22:3: error: paths must be relative but "/include" starts with "/"
- Dir: aarch64-none-elf/aarch64a_exn_rtti_unaligned
  ^
clang version 21.0.0git ([email protected]:simpal01/llvm-project-fork.git fe8fcbffbfc7c8a16285d3100f089b6528fb1329)
Target: aarch64-unknown-none-elf
Thread model: posix
InstalledDir: /data_nvme1n1/LLVM-PROJECT/build-driver/bin

ah! This might be because I unintentionally included -###, which only prints the driver’s command sequence without actually performing compilation.

After removing -###, it became necessary to include not to ensure the llvm-lit test passed.

Good catch Simon!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i will update the test accordingly

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see! Well found.

The `-###` flag was unintentionally included,
causing the compiler to only print the driver
command sequence without performing compilation.
This masked the need for the `not` command in the llvm-lit test.
After removing `-###`, the missing `not` was added to correctly
expect a failing compile, ensuring the test behaves as intended.
simpal01 added a commit to simpal01/arm-toolchain that referenced this pull request Jul 14, 2025
The current ATFE package  redundantly duplicates identical
C and C++ headers across more than 100 ibrary variants,
despite the fact that these headers do not vary within a
given target triple aside from few. As a result, each variant
currently maintains its own include/ and include/c++/v1/ directories,
leading to unnecessary duplication.

This patch is to refactor the multilib layout to use a single
shared header directory per target triple, eliminating redundant
copies of identical headers across library variants, while keeping
variant-specific headers within each variant’s own include/ directory.

Changing the layout of the package structure will require corresponding
updates to the ATFE build system, as it currently assumes a variant specific
directory hierarchy for headers and libraries during installation and packaging.

A new Python script has been introduced that runs after the runtime
subproject has been executed for each variant and the non-optimised
multilib directories have been generated. This script identifies and
extracts common headers from the non-optimised multilibs and creates
an optimized multilib directory. In this optimised directory, only the
common headers are centralised, while the remaining contents are preserved
as-is from the non-optimised layout.

A CMake flag has been added to disable this multilib optimisation phase.
When this flag is set, the optimised multilib directory will not be generated.
Additionally, the optimisation step is skipped automatically if there are fewer
than two multilib variants to build.

To support this new layout with a centralised include directory, a new
field called IncludePath has been added to multilib.yaml.This field specifies
 a base path for locating header files wich gets added to the header
search path sequence by clang.

Corresponding changes in Clang:
llvm/llvm-project#146651
simpal01 added a commit to simpal01/arm-toolchain that referenced this pull request Jul 15, 2025
The current ATFE package  redundantly duplicates identical
C and C++ headers across more than 100 ibrary variants,
despite the fact that these headers do not vary within a
given target triple aside from few. As a result, each variant
currently maintains its own include/ and include/c++/v1/ directories,
leading to unnecessary duplication.

This patch is to refactor the multilib layout to use a single
shared header directory per target triple, eliminating redundant
copies of identical headers across library variants, while keeping
variant-specific headers within each variant’s own include/ directory.

Changing the layout of the package structure will require corresponding
updates to the ATFE build system, as it currently assumes a variant specific
directory hierarchy for headers and libraries during installation and packaging.

A new Python script has been introduced that runs after the runtime
subproject has been executed for each variant and the non-optimised
multilib directories have been generated. This script identifies and
extracts common headers from the non-optimised multilibs and creates
an optimised multilib directory. In this optimised directory, only the
common headers are centralised, while the remaining contents are preserved
as-is from the non-optimised layout.

A CMake flag has been added to disable this multilib optimisation phase.
When this flag is set, the optimised multilib directory will not be generated.
Additionally, the optimisation step is skipped automatically if there are fewer
than two multilib variants to build.

To support this new layout with a centralised include directory, a new
field called IncludePath has been added to multilib.yaml.This field specifies
 a base path for locating header files wich gets added to the header
search path sequence by clang.

Corresponding changes in Clang:
llvm/llvm-project#146651
simpal01 added a commit to simpal01/arm-toolchain that referenced this pull request Jul 23, 2025
The current ATFE package  redundantly duplicates identical
C and C++ headers across more than 100 ibrary variants,
despite the fact that these headers do not vary within a
given target triple aside from few. As a result, each variant
currently maintains its own include/ and include/c++/v1/ directories,
leading to unnecessary duplication.

This patch is to refactor the multilib layout to use a single
shared header directory per target triple, eliminating redundant
copies of identical headers across library variants, while keeping
variant-specific headers within each variant’s own include/ directory.

Changing the layout of the package structure will require corresponding
updates to the ATFE build system, as it currently assumes a variant specific
directory hierarchy for headers and libraries during installation and packaging.

A new Python script has been introduced that runs after the runtime
subproject has been executed for each variant and the non-optimised
multilib directories have been generated. This script identifies and
extracts common headers from the non-optimised multilibs and creates
an optimised multilib directory. In this optimised directory, only the
common headers are centralised, while the remaining contents are preserved
as-is from the non-optimised layout.

A CMake flag has been added to disable this multilib optimisation phase.
When this flag is set, the optimised multilib directory will not be generated.
Additionally, the optimisation step is skipped automatically if there are fewer
than two multilib variants to build.

To support this new layout with a centralised include directory, a new
field called IncludePath has been added to multilib.yaml.This field specifies
 a base path for locating header files wich gets added to the header
search path sequence by clang.

Corresponding changes in Clang:
llvm/llvm-project#146651
@github-actions
Copy link

github-actions bot commented Jul 28, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@simpal01 simpal01 changed the title [Multilib] Extend the Multilib system to support an IncludepPath field. [Multilib] Extend the Multilib system to support an IncludeDirs field. Jul 28, 2025
simpal01 added a commit to simpal01/arm-toolchain that referenced this pull request Jul 29, 2025
… downstream patching.

The corresponding llvm patch is currently under upstream
review: llvm/llvm-project#146651
simpal01 added a commit to arm/arm-toolchain that referenced this pull request Jul 29, 2025
…n IncludeDirs field. (#447)

Downstream issue:#446.

This patch extends the Multilib yaml format to allow specifying an
IncludeDirs for the header path/s per multilib variant. The goal is to
enable fine-grained control over header search paths for each multilib
variant. This feature is especially useful in setups where header paths
deviate from the default bare-metal assumptions. For example, when
headers are shared across target triples, it becomes necessary to
organise them under target-triple-specific directories to ensure correct
resolution.

This is already in upstream review
llvm/llvm-project#146651.
Since the review is pending, a downstream patch is made to enable
IncludeDirs support in multilib.yaml
simpal01 added a commit to arm/arm-toolchain that referenced this pull request Jul 29, 2025
…423)

The current ATFE package redundantly duplicates identical C and C++
headers across more than 100 ibrary variants, despite the fact that
these headers do not vary within a given target triple aside from few.
As a result, each variant currently maintains its own include/ and
include/c++/v1/ directories, leading to unnecessary duplication.

This patch is to refactor the multilib layout to use a single shared
header directory per target triple, eliminating redundant copies of
identical headers across library variants, while keeping
variant-specific headers within each variant’s own include/ directory.

Changing the layout of the package structure will require corresponding
updates to the ATFE build system, as it currently assumes a variant
specific directory hierarchy for headers and libraries during
installation and packaging.

A new Python script has been introduced that runs after the runtime
subproject has been executed for each variant and the non-optimised
multilib directories have been generated. This script identifies and
extracts common headers from the non-optimised multilibs and creates an
optimized multilib directory. In this optimised directory, only the
common headers are centralised, while the remaining contents are
preserved as-is from the non-optimised layout.

A CMake flag called ENABLE_MULTILIB_HEADER_OPTIMISATION has been added
to disable this multilib optimisation phase. When this flag is not set,
the optimised multilib directory will not be generated. Additionally,
the optimisation step is skipped automatically if there are fewer than
two multilib variants to build.

To support this new layout with a centralised include directory, a new
field called IncludeDirs has been added to multilib.yaml. This field
specifies a base directory for locating header files which gets added to
the header search path sequence by clang.

Corresponding changes in Clang:
llvm/llvm-project#146651
simpal01 added a commit to simpal01/arm-toolchain that referenced this pull request Jul 31, 2025
…n IncludeDirs field. (arm#447)

Downstream issue:arm#446.

This patch extends the Multilib yaml format to allow specifying an
IncludeDirs for the header path/s per multilib variant. The goal is to
enable fine-grained control over header search paths for each multilib
variant. This feature is especially useful in setups where header paths
deviate from the default bare-metal assumptions. For example, when
headers are shared across target triples, it becomes necessary to
organise them under target-triple-specific directories to ensure correct
resolution.

This is already in upstream review
llvm/llvm-project#146651.
Since the review is pending, a downstream patch is made to enable
IncludeDirs support in multilib.yaml

[ATFE] Package common multilib headers into target triple directory. (arm#423)

The current ATFE package redundantly duplicates identical C and C++
headers across more than 100 ibrary variants, despite the fact that
these headers do not vary within a given target triple aside from few.
As a result, each variant currently maintains its own include/ and
include/c++/v1/ directories, leading to unnecessary duplication.

This patch is to refactor the multilib layout to use a single shared
header directory per target triple, eliminating redundant copies of
identical headers across library variants, while keeping
variant-specific headers within each variant’s own include/ directory.

Changing the layout of the package structure will require corresponding
updates to the ATFE build system, as it currently assumes a variant
specific directory hierarchy for headers and libraries during
installation and packaging.

A new Python script has been introduced that runs after the runtime
subproject has been executed for each variant and the non-optimised
multilib directories have been generated. This script identifies and
extracts common headers from the non-optimised multilibs and creates an
optimized multilib directory. In this optimised directory, only the
common headers are centralised, while the remaining contents are
preserved as-is from the non-optimised layout.

A CMake flag called ENABLE_MULTILIB_HEADER_OPTIMISATION has been added
to disable this multilib optimisation phase. When this flag is not set,
the optimised multilib directory will not be generated. Additionally,
the optimisation step is skipped automatically if there are fewer than
two multilib variants to build.

To support this new layout with a centralised include directory, a new
field called IncludeDirs has been added to multilib.yaml. This field
specifies a base directory for locating header files which gets added to
the header search path sequence by clang.

Corresponding changes in Clang:
llvm/llvm-project#146651

[ATFE] Prioritize multilib-specific headers over target-level headers. (arm#451)

Adjust the header search order so that variant-specific directories (e.g
armv6m_soft_nofp_size/include/) are searched before the common
target-level directories (e.g include/) in the -internal-isystem list.

This ensures that headers tailored for a specific multilib variant take
precedence over the generic headers, allowing correct header resolution
in the presence of overrides.

Previously, the common target-level directory could shadow
multilib-specific headers if the same file existed in both paths.
simpal01 added a commit to simpal01/arm-toolchain that referenced this pull request Jul 31, 2025
…n IncludeDirs field. (arm#447)

Downstream issue:arm#446.

This patch extends the Multilib yaml format to allow specifying an
IncludeDirs for the header path/s per multilib variant. The goal is to
enable fine-grained control over header search paths for each multilib
variant. This feature is especially useful in setups where header paths
deviate from the default bare-metal assumptions. For example, when
headers are shared across target triples, it becomes necessary to
organise them under target-triple-specific directories to ensure correct
resolution.

This is already in upstream review
llvm/llvm-project#146651.
Since the review is pending, a downstream patch is made to enable
IncludeDirs support in multilib.yaml
simpal01 added a commit to simpal01/arm-toolchain that referenced this pull request Jul 31, 2025
…rm#423)

The current ATFE package redundantly duplicates identical C and C++
headers across more than 100 ibrary variants, despite the fact that
these headers do not vary within a given target triple aside from few.
As a result, each variant currently maintains its own include/ and
include/c++/v1/ directories, leading to unnecessary duplication.

This patch is to refactor the multilib layout to use a single shared
header directory per target triple, eliminating redundant copies of
identical headers across library variants, while keeping
variant-specific headers within each variant’s own include/ directory.

Changing the layout of the package structure will require corresponding
updates to the ATFE build system, as it currently assumes a variant
specific directory hierarchy for headers and libraries during
installation and packaging.

A new Python script has been introduced that runs after the runtime
subproject has been executed for each variant and the non-optimised
multilib directories have been generated. This script identifies and
extracts common headers from the non-optimised multilibs and creates an
optimized multilib directory. In this optimised directory, only the
common headers are centralised, while the remaining contents are
preserved as-is from the non-optimised layout.

A CMake flag called ENABLE_MULTILIB_HEADER_OPTIMISATION has been added
to disable this multilib optimisation phase. When this flag is not set,
the optimised multilib directory will not be generated. Additionally,
the optimisation step is skipped automatically if there are fewer than
two multilib variants to build.

To support this new layout with a centralised include directory, a new
field called IncludeDirs has been added to multilib.yaml. This field
specifies a base directory for locating header files which gets added to
the header search path sequence by clang.

Corresponding changes in Clang:
llvm/llvm-project#146651
simpal01 added a commit to simpal01/arm-toolchain that referenced this pull request Jul 31, 2025
…n IncludeDirs field. (arm#447)

Downstream issue:arm#446.

This patch extends the Multilib yaml format to allow specifying an
IncludeDirs for the header path/s per multilib variant. The goal is to
enable fine-grained control over header search paths for each multilib
variant. This feature is especially useful in setups where header paths
deviate from the default bare-metal assumptions. For example, when
headers are shared across target triples, it becomes necessary to
organise them under target-triple-specific directories to ensure correct
resolution.

This is already in upstream review
llvm/llvm-project#146651.
Since the review is pending, a downstream patch is made to enable
IncludeDirs support in multilib.yaml
simpal01 added a commit to simpal01/arm-toolchain that referenced this pull request Jul 31, 2025
…rm#423)

The current ATFE package redundantly duplicates identical C and C++
headers across more than 100 ibrary variants, despite the fact that
these headers do not vary within a given target triple aside from few.
As a result, each variant currently maintains its own include/ and
include/c++/v1/ directories, leading to unnecessary duplication.

This patch is to refactor the multilib layout to use a single shared
header directory per target triple, eliminating redundant copies of
identical headers across library variants, while keeping
variant-specific headers within each variant’s own include/ directory.

Changing the layout of the package structure will require corresponding
updates to the ATFE build system, as it currently assumes a variant
specific directory hierarchy for headers and libraries during
installation and packaging.

A new Python script has been introduced that runs after the runtime
subproject has been executed for each variant and the non-optimised
multilib directories have been generated. This script identifies and
extracts common headers from the non-optimised multilibs and creates an
optimized multilib directory. In this optimised directory, only the
common headers are centralised, while the remaining contents are
preserved as-is from the non-optimised layout.

A CMake flag called ENABLE_MULTILIB_HEADER_OPTIMISATION has been added
to disable this multilib optimisation phase. When this flag is not set,
the optimised multilib directory will not be generated. Additionally,
the optimisation step is skipped automatically if there are fewer than
two multilib variants to build.

To support this new layout with a centralised include directory, a new
field called IncludeDirs has been added to multilib.yaml. This field
specifies a base directory for locating header files which gets added to
the header search path sequence by clang.

Corresponding changes in Clang:
llvm/llvm-project#146651
simpal01 added a commit to arm/arm-toolchain that referenced this pull request Aug 1, 2025
…n IncludeDirs field. (#447)

Downstream issue:#446.

This patch extends the Multilib yaml format to allow specifying an
IncludeDirs for the header path/s per multilib variant. The goal is to
enable fine-grained control over header search paths for each multilib
variant. This feature is especially useful in setups where header paths
deviate from the default bare-metal assumptions. For example, when
headers are shared across target triples, it becomes necessary to
organise them under target-triple-specific directories to ensure correct
resolution.

This is already in upstream review
llvm/llvm-project#146651.
Since the review is pending, a downstream patch is made to enable
IncludeDirs support in multilib.yaml
simpal01 added a commit to arm/arm-toolchain that referenced this pull request Aug 1, 2025
…423)

The current ATFE package redundantly duplicates identical C and C++
headers across more than 100 ibrary variants, despite the fact that
these headers do not vary within a given target triple aside from few.
As a result, each variant currently maintains its own include/ and
include/c++/v1/ directories, leading to unnecessary duplication.

This patch is to refactor the multilib layout to use a single shared
header directory per target triple, eliminating redundant copies of
identical headers across library variants, while keeping
variant-specific headers within each variant’s own include/ directory.

Changing the layout of the package structure will require corresponding
updates to the ATFE build system, as it currently assumes a variant
specific directory hierarchy for headers and libraries during
installation and packaging.

A new Python script has been introduced that runs after the runtime
subproject has been executed for each variant and the non-optimised
multilib directories have been generated. This script identifies and
extracts common headers from the non-optimised multilibs and creates an
optimized multilib directory. In this optimised directory, only the
common headers are centralised, while the remaining contents are
preserved as-is from the non-optimised layout.

A CMake flag called ENABLE_MULTILIB_HEADER_OPTIMISATION has been added
to disable this multilib optimisation phase. When this flag is not set,
the optimised multilib directory will not be generated. Additionally,
the optimisation step is skipped automatically if there are fewer than
two multilib variants to build.

To support this new layout with a centralised include directory, a new
field called IncludeDirs has been added to multilib.yaml. This field
specifies a base directory for locating header files which gets added to
the header search path sequence by clang.

Corresponding changes in Clang:
llvm/llvm-project#146651
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants