Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lldb][ClangExpressionParser] Set BuiltinHeadersInSystemModules depending on SDK version #102309

Merged

Conversation

Michael137
Copy link
Member

This patch changes the way we initialize BuiltinHeadersInSystemModules which is one of the flags controlling Clang's behaviour when the Darwin module is split into more fine-grained modules. The ClangExpressionParser currently unconditionally sets -fbuiltin-headers-in-system-modules when evaluating expressions with the target.import-std-module setting. This flag should, however, be set depending on the SDK version (which is what the Clang Darwin toolchain does).

Unfortunately, the compiler instance that we create with ClangExpressionParser never consults the Clang driver, and thus doesn't correctly infer BuiltinHeadersInSystemModules. Note, this isn't an issue with the CompilerInstance that the ClangModulesDeclVendor creates because it uses the createInovcation API, which calls into Darwin::addClangTargetOptions.

This patch mimicks how sdkSupportsBuiltinModules is used in Darwin::addClangTargetOptions.

This ensures that the import-std-module API tests run cleanly regardless of SDK version.

The plan is to eventually make the CompilerInstance construction in ClangExpressionParser go through the driver, so we can avoid duplicating the logic in LLDB. But we aren't there yet.

Implementation

  • We look for the SDKSettings.json in the sysroot directory that we found in DWARF (via DW_AT_LLVM_sysroot)
  • Then parse this file and extract the SDK version number out of it
  • Then mimick sdkSupportsBuiltinModules from Toolchains/Darwin.cpp and set BuiltinHeadersInSystemModules based on it

rdar://116490281

@llvmbot
Copy link
Member

llvmbot commented Aug 7, 2024

@llvm/pr-subscribers-lldb

Author: Michael Buch (Michael137)

Changes

This patch changes the way we initialize BuiltinHeadersInSystemModules which is one of the flags controlling Clang's behaviour when the Darwin module is split into more fine-grained modules. The ClangExpressionParser currently unconditionally sets -fbuiltin-headers-in-system-modules when evaluating expressions with the target.import-std-module setting. This flag should, however, be set depending on the SDK version (which is what the Clang Darwin toolchain does).

Unfortunately, the compiler instance that we create with ClangExpressionParser never consults the Clang driver, and thus doesn't correctly infer BuiltinHeadersInSystemModules. Note, this isn't an issue with the CompilerInstance that the ClangModulesDeclVendor creates because it uses the createInovcation API, which calls into Darwin::addClangTargetOptions.

This patch mimicks how sdkSupportsBuiltinModules is used in Darwin::addClangTargetOptions.

This ensures that the import-std-module API tests run cleanly regardless of SDK version.

The plan is to eventually make the CompilerInstance construction in ClangExpressionParser go through the driver, so we can avoid duplicating the logic in LLDB. But we aren't there yet.

Implementation

  • We look for the SDKSettings.json in the sysroot directory that we found in DWARF (via DW_AT_LLVM_sysroot)
  • Then parse this file and extract the SDK version number out of it
  • Then mimick sdkSupportsBuiltinModules from Toolchains/Darwin.cpp and set BuiltinHeadersInSystemModules based on it

rdar://116490281


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

3 Files Affected:

  • (modified) lldb/include/lldb/Utility/XcodeSDK.h (+14)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp (+49-3)
  • (modified) lldb/source/Utility/XcodeSDK.cpp (+21)
diff --git a/lldb/include/lldb/Utility/XcodeSDK.h b/lldb/include/lldb/Utility/XcodeSDK.h
index 673ea578ffce85..69c7e23d3d0f63 100644
--- a/lldb/include/lldb/Utility/XcodeSDK.h
+++ b/lldb/include/lldb/Utility/XcodeSDK.h
@@ -85,6 +85,20 @@ class XcodeSDK {
   /// Whether LLDB feels confident importing Clang modules from this SDK.
   static bool SDKSupportsModules(Type type, llvm::VersionTuple version);
   static bool SDKSupportsModules(Type desired_type, const FileSpec &sdk_path);
+
+  /// Returns true if the SDK for the specified triple supports
+  /// builtin modules in system headers.
+  ///
+  /// NOTE: should be kept in sync with sdkSupportsBuiltinModules in
+  /// Toolchains/Darwin.cpp
+  ///
+  /// FIXME: this function will be removed once LLDB's ClangExpressionParser
+  /// constructs the compiler instance through the driver/toolchain. See \ref
+  /// SetupImportStdModuleLangOpts
+  ///
+  static bool SDKSupportsBuiltinModules(const llvm::Triple &triple,
+                                        llvm::VersionTuple sdk_version);
+
   /// Return the canonical SDK name, such as "macosx" for the macOS SDK.
   static std::string GetCanonicalName(Info info);
   /// Return the best-matching SDK type for a specific triple.
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index f41323d32ac863..3b67d28203c3de 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -39,6 +39,7 @@
 #include "llvm/ExecutionEngine/ExecutionEngine.h"
 #include "llvm/Support/CrashRecoveryContext.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/TargetSelect.h"
 
@@ -91,6 +92,8 @@
 #include "lldb/Utility/StringList.h"
 
 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+#include "Plugins/Platform/MacOSX/PlatformDarwin.h"
+#include "lldb/Utility/XcodeSDK.h"
 
 #include <cctype>
 #include <memory>
@@ -279,6 +282,48 @@ class ClangDiagnosticManagerAdapter : public clang::DiagnosticConsumer {
   std::string m_output;
 };
 
+/// Returns true if the SDK for the specified triple supports
+/// builtin modules in system headers. This is used to decide
+/// whether to pass -fbuiltin-headers-in-system-modules to
+/// the compiler instance when compiling the `std` module.
+///
+/// \param[in] target The target triple.
+///
+static llvm::Expected<bool>
+sdkSupportsBuiltinModules(lldb_private::Target &target) {
+  auto arch_spec = target.GetArchitecture();
+  auto const &triple = arch_spec.GetTriple();
+  auto module_sp = target.GetExecutableModule();
+  if (!module_sp)
+    return llvm::createStringError("Executable module not found.");
+
+  // Get SDK path that the target was compiled against.
+  auto sdk_or_err = PlatformDarwin::GetSDKPathFromDebugInfo(*module_sp);
+  if (!sdk_or_err)
+    return sdk_or_err.takeError();
+
+  // Use the SDK path from debug-info to find a local matching SDK directory.
+  auto sdk_path_or_err =
+      HostInfo::GetSDKRoot(HostInfo::SDKOptions{std::move(sdk_or_err->first)});
+  if (!sdk_path_or_err)
+    return sdk_path_or_err.takeError();
+
+  auto VFS = FileSystem::Instance().GetVirtualFileSystem();
+  if (!VFS)
+    return llvm::createStringError("No virtual filesystem available.");
+
+  // Extract SDK version from the /path/to/some.sdk/SDKSettings.json
+  auto parsed_or_err = clang::parseDarwinSDKInfo(*VFS, *sdk_path_or_err);
+  if (!parsed_or_err)
+    return parsed_or_err.takeError();
+
+  auto maybe_sdk = *parsed_or_err;
+  if (!maybe_sdk)
+    return llvm::createStringError("Couldn't find Darwin SDK info.");
+
+  return XcodeSDK::SDKSupportsBuiltinModules(triple, maybe_sdk->getVersion());
+}
+
 static void SetupModuleHeaderPaths(CompilerInstance *compiler,
                                    std::vector<std::string> include_directories,
                                    lldb::TargetSP target_sp) {
@@ -561,7 +606,8 @@ static void SetupLangOpts(CompilerInstance &compiler,
   lang_opts.NoBuiltin = true;
 }
 
-static void SetupImportStdModuleLangOpts(CompilerInstance &compiler) {
+static void SetupImportStdModuleLangOpts(CompilerInstance &compiler,
+                                         lldb_private::Target &target) {
   LangOptions &lang_opts = compiler.getLangOpts();
   lang_opts.Modules = true;
   // We want to implicitly build modules.
@@ -578,7 +624,7 @@ static void SetupImportStdModuleLangOpts(CompilerInstance &compiler) {
   lang_opts.GNUMode = true;
   lang_opts.GNUKeywords = true;
   lang_opts.CPlusPlus11 = true;
-  lang_opts.BuiltinHeadersInSystemModules = true;
+  lang_opts.BuiltinHeadersInSystemModules = !sdkSupportsBuiltinModules(target);
 
   // The Darwin libc expects this macro to be set.
   lang_opts.GNUCVersion = 40201;
@@ -659,7 +705,7 @@ ClangExpressionParser::ClangExpressionParser(
   if (auto *clang_expr = dyn_cast<ClangUserExpression>(&m_expr);
       clang_expr && clang_expr->DidImportCxxModules()) {
     LLDB_LOG(log, "Adding lang options for importing C++ modules");
-    SetupImportStdModuleLangOpts(*m_compiler);
+    SetupImportStdModuleLangOpts(*m_compiler, *target_sp);
     SetupModuleHeaderPaths(m_compiler.get(), m_include_directories, target_sp);
   }
 
diff --git a/lldb/source/Utility/XcodeSDK.cpp b/lldb/source/Utility/XcodeSDK.cpp
index 712d611db28f83..64e0672a963ca9 100644
--- a/lldb/source/Utility/XcodeSDK.cpp
+++ b/lldb/source/Utility/XcodeSDK.cpp
@@ -259,6 +259,27 @@ bool XcodeSDK::SupportsSwift() const {
   }
 }
 
+bool XcodeSDK::SDKSupportsBuiltinModules(const llvm::Triple &triple,
+                                         llvm::VersionTuple sdk_version) {
+  using namespace llvm;
+
+  switch (triple.getOS()) {
+  case Triple::OSType::MacOSX:
+    return sdk_version >= VersionTuple(15U);
+  case Triple::OSType::IOS:
+    return sdk_version >= VersionTuple(18U);
+  case Triple::OSType::TvOS:
+    return sdk_version >= VersionTuple(18U);
+  case Triple::OSType::WatchOS:
+    return sdk_version >= VersionTuple(11U);
+  case Triple::OSType::XROS:
+    return sdk_version >= VersionTuple(2U);
+  default:
+    // New SDKs support builtin modules from the start.
+    return true;
+  }
+}
+
 bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type,
                                   const FileSpec &sdk_path) {
   ConstString last_path_component = sdk_path.GetFilename();

@Michael137 Michael137 force-pushed the lldb/import-std-module-using-local-sdk branch from acc9323 to 3dfbfc7 Compare August 7, 2024 13:05
Copy link
Collaborator

@adrian-prantl adrian-prantl left a comment

Choose a reason for hiding this comment

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

Thanks, this LGTM, next step should be to replace the use of include_directories with DW_AT_APPLE_sdk.

@ian-twilightcoder
Copy link
Contributor

This really isn't the right approach. BuiltinHeadersInSystemModules isn't the only important default that the driver sets up. Can we change the invocation setup to use clang::createInvocation or clang::CompilerInvocation::CreateFromArgs or clang::BuildCompilation? Or is that planned for another change?

@@ -259,6 +259,27 @@ bool XcodeSDK::SupportsSwift() const {
}
}

bool XcodeSDK::SDKSupportsBuiltinModules(const llvm::Triple &target_triple,
Copy link
Contributor

Choose a reason for hiding this comment

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

This function got changed in #102239

Copy link
Member Author

Choose a reason for hiding this comment

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

I already accounted for the version check changes

Copy link
Contributor

Choose a reason for hiding this comment

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

But you didn't pick up the environment check

Copy link
Member Author

@Michael137 Michael137 Aug 7, 2024

Choose a reason for hiding this comment

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

Don't think we really want to support this in/care about non-native environments tbh

@Michael137
Copy link
Member Author

This really isn't the right approach. BuiltinHeadersInSystemModules isn't the only important default that the driver sets up. Can we change the invocation setup to use clang::createInvocation or clang::CompilerInvocation::CreateFromArgs or clang::BuildCompilation? Or is that planned for another change?

Yes I 100% agree that we should use the driver. This has been a FIXME for many years now. But to unblock the current test failures I think this should be fine to land. And when we switch to using the driver properly we'll remove this.

@Michael137 Michael137 merged commit 1cbcf74 into llvm:main Aug 7, 2024
6 checks passed
@Michael137 Michael137 deleted the lldb/import-std-module-using-local-sdk branch August 7, 2024 23:00
jasonmolenda added a commit that referenced this pull request Aug 8, 2024
…es depending on SDK version (#102309)"

This reverts commit 1cbcf74.

unittests do not build because liblldbPluginExpressionParserClang.a now
depends on liblldbPluginPlatformMacOSX.a when built on macOS, reverting
until we can straighten out the dependency.
Michael137 added a commit to Michael137/llvm-project that referenced this pull request Aug 8, 2024
…rmDarwin into Platform

This will soon be needed for
llvm#102309, where we
plan on calling these APIs from generic ExpressionParser code.
Michael137 added a commit to Michael137/llvm-project that referenced this pull request Aug 8, 2024
…rmDarwin into Platform

This will soon be needed for
llvm#102309, where we
plan on calling these APIs from generic ExpressionParser code.
Michael137 added a commit to Michael137/llvm-project that referenced this pull request Aug 8, 2024
…es depending on SDK version (llvm#102309)"

Depends on llvm#102488

This reverts commit cf56e26.

The original change was reverted because it was causing linker failures
in the unit-tests:
```
Undefined symbols for architecture arm64:
  "lldb_private::PlatformDarwin::GetSDKPathFromDebugInfo(lldb_private::Module&)",
referenced from:
      lldb_private::ClangExpressionParser::ClangExpressionParser(lldb_private::ExecutionContextScope*,
lldb_private::Expression&, bool,
std::__1::vector<std::__1::basic_string<char,
std::__1::char_traits<char>, std::__1::allocator<char>>,
std::__1::allocator<std::__1::basic_string<char,
std::__1::char_traits<char>, std::__1::allocator<char>>>>,
std::__1::basic_string<char, std::__1::char_traits<char>,
std::__1::allocator<char>>) in
liblldbPluginExpressionParserClang.a[11](ClangExpressionParser.cpp.o)
ld: symbol(s) not found for architecture arm64
c++: error: linker command failed with exit code 1 (use -v to see
invocation)
```

The relanded version differs only in the fact that we now use the
generic `Platform` abstraction to get to `GetSDKPathFromDebugInfo`.
Michael137 added a commit that referenced this pull request Aug 9, 2024
…es depending on SDK version (#102309)" (#102497)

Depends on #102488

This reverts commit
cf56e26.

The original change was reverted because it was causing linker failures
in the unit-tests:
```
Undefined symbols for architecture arm64:
  "lldb_private::PlatformDarwin::GetSDKPathFromDebugInfo(lldb_private::Module&)",
referenced from:
      lldb_private::ClangExpressionParser::ClangExpressionParser(lldb_private::ExecutionContextScope*,
lldb_private::Expression&, bool,
std::__1::vector<std::__1::basic_string<char,
std::__1::char_traits<char>, std::__1::allocator<char>>,
std::__1::allocator<std::__1::basic_string<char,
std::__1::char_traits<char>, std::__1::allocator<char>>>>,
std::__1::basic_string<char, std::__1::char_traits<char>,
std::__1::allocator<char>>) in
liblldbPluginExpressionParserClang.a[11](ClangExpressionParser.cpp.o)
ld: symbol(s) not found for architecture arm64
c++: error: linker command failed with exit code 1 (use -v to see
invocation)
```

The relanded version differs only in the fact that we now use the
generic `Platform` abstraction to get to `GetSDKPathFromDebugInfo`.
adrian-prantl pushed a commit to adrian-prantl/llvm-project that referenced this pull request Oct 11, 2024
…ding on SDK version (llvm#102309)

This patch changes the way we initialize `BuiltinHeadersInSystemModules`
which is one of the flags controlling Clang's behaviour when the Darwin
module is split into more fine-grained modules. The
ClangExpressionParser currently unconditionally sets
`-fbuiltin-headers-in-system-modules` when evaluating expressions with
the `target.import-std-module` setting. This flag should, however, be
set depending on the SDK version (which is what the Clang Darwin
toolchain does).

Unfortunately, the compiler instance that we create with
`ClangExpressionParser` never consults the Clang driver, and thus
doesn't correctly infer `BuiltinHeadersInSystemModules`. Note, this
isn't an issue with the `CompilerInstance` that the
`ClangModulesDeclVendor` creates because it uses the `createInovcation`
API, which calls into `Darwin::addClangTargetOptions`.

This patch mimicks how `sdkSupportsBuiltinModules` is used in
`Darwin::addClangTargetOptions`.

This ensures that the `import-std-module` API tests run cleanly
regardless of SDK version.

The plan is to eventually make the `CompilerInstance` construction in
`ClangExpressionParser` go through the driver, so we can avoid
duplicating the logic in LLDB. But we aren't there yet.

**Implementation**
* We look for the `SDKSettings.json` in the sysroot directory that we
found in DWARF (via `DW_AT_LLVM_sysroot`)
* Then parse this file and extract the SDK version number out of it
* Then mimick `sdkSupportsBuiltinModules` from `Toolchains/Darwin.cpp`
and set `BuiltinHeadersInSystemModules` based on it

rdar://116490281
(cherry picked from commit 1cbcf74)
adrian-prantl pushed a commit to adrian-prantl/llvm-project that referenced this pull request Oct 11, 2024
…es depending on SDK version (llvm#102309)"

This reverts commit 1cbcf74.

unittests do not build because liblldbPluginExpressionParserClang.a now
depends on liblldbPluginPlatformMacOSX.a when built on macOS, reverting
until we can straighten out the dependency.

(cherry picked from commit cf56e26)
adrian-prantl pushed a commit to adrian-prantl/llvm-project that referenced this pull request Oct 11, 2024
…es depending on SDK version (llvm#102309)" (llvm#102497)

Depends on llvm#102488

This reverts commit
llvm@cf56e26.

The original change was reverted because it was causing linker failures
in the unit-tests:
```
Undefined symbols for architecture arm64:
  "lldb_private::PlatformDarwin::GetSDKPathFromDebugInfo(lldb_private::Module&)",
referenced from:
      lldb_private::ClangExpressionParser::ClangExpressionParser(lldb_private::ExecutionContextScope*,
lldb_private::Expression&, bool,
std::__1::vector<std::__1::basic_string<char,
std::__1::char_traits<char>, std::__1::allocator<char>>,
std::__1::allocator<std::__1::basic_string<char,
std::__1::char_traits<char>, std::__1::allocator<char>>>>,
std::__1::basic_string<char, std::__1::char_traits<char>,
std::__1::allocator<char>>) in
liblldbPluginExpressionParserClang.a[11](ClangExpressionParser.cpp.o)
ld: symbol(s) not found for architecture arm64
c++: error: linker command failed with exit code 1 (use -v to see
invocation)
```

The relanded version differs only in the fact that we now use the
generic `Platform` abstraction to get to `GetSDKPathFromDebugInfo`.

(cherry picked from commit 3fffa6d)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants