[Lldb-commits] [lldb] [lldb] Get init scripts from user config directories (PR #236789)

via lldb-commits lldb-commits at lists.llvm.org
Mon Nov 2 01:42:57 PST 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Nerixyz (Nerixyz)

<details>
<summary>Changes</summary>

#<!-- -->71426 is the [most 👍'd open issue on llvm/llvm-project](https://github.com/llvm/llvm-project/issues?q=is%3Aissue+state%3Aopen+sort%3Areactions-%2B1-desc), so let's fix it.

This PR adds an additional directory for lookups of configs from the user's home directory, but keeps the original ones. The lookup order will be as follows (copy-pasted from the updated manpage):

1. ``~/.lldbinit-{program}`` - the program specific init file. This would be
   ``~/.lldbinit-lldb`` for the command line :program:`lldb` and 
   ``~/.lldbinit-Xcode`` for Xcode.
2. ``{config-dir}/lldb/init-{program}`` - the program specific init file in the
   user's config directory. On Linux, ``config-dir`` is resolved through
   ``XDG_CONFIG_HOME`` (or ``~/.config`` if unset). On macOS, it's
   ``~/Library/Preferences/``. On Windows, it's ``%USERPROFILE%\AppData\Local``.
3. ``~/.lldbinit``
4. ``{config-dir}/lldb/init``

The user's config directory comes after the user's home to maintain the current order. And lldb expects an `lldb/` directory inside the config directory to group all lldb-related files. Most other programs that have more than one config do this too (at least on my system). It's also consistent with clangd which loads from `{config-dir}/clangd/config.yml`. For the init files, I removed the `.lldb` prefix as the directory already contains `lldb`.

Fixes #<!-- -->71426.

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


5 Files Affected:

- (modified) lldb/docs/man/lldb.rst (+23-15) 
- (modified) lldb/include/lldb/Host/HostInfoBase.h (+5) 
- (modified) lldb/source/Host/common/HostInfoBase.cpp (+24) 
- (modified) lldb/source/Interpreter/CommandInterpreter.cpp (+15-4) 
- (added) lldb/test/Shell/Driver/LLDBInitConfigDir.test (+56) 


``````````diff
diff --git a/lldb/docs/man/lldb.rst b/lldb/docs/man/lldb.rst
index 0a2a2093f8c6bb..77751d098db99f 100644
--- a/lldb/docs/man/lldb.rst
+++ b/lldb/docs/man/lldb.rst
@@ -307,32 +307,40 @@ CONFIGURATION FILES
 -------------------
 
 :program:`lldb` reads things like settings, aliases and commands from the
-.lldbinit file.
+``.lldbinit`` / ``init`` file.
+
+The lookup order is as follows:
+
+1. ``~/.lldbinit-{program}`` - the program specific init file. This would be
+   ``~/.lldbinit-lldb`` for the command line :program:`lldb` and 
+   ``~/.lldbinit-Xcode`` for Xcode.
+2. ``{config-dir}/lldb/init-{program}`` - the program specific init file in the
+   user's config directory. On Linux, ``config-dir`` is resolved through
+   ``XDG_CONFIG_HOME`` (or ``~/.config`` if unset). On macOS, it's
+   ``~/Library/Preferences/``. On Windows, it's ``%USERPROFILE%\AppData\Local``.
+3. ``~/.lldbinit``
+4. ``{config-dir}/lldb/init``
 
-First, :program:`lldb` will try to read the application specific init file
-whose name is ~/.lldbinit followed by a "-" and the name of the current
-program. This would be ~/.lldbinit-lldb for the command line :program:`lldb`
-and ~/.lldbinit-Xcode for Xcode. If there is no application specific init
-file, :program:`lldb` will look for an init file in the home directory.
 If launched with a `REPL`_ option, it will first look for a REPL configuration
 file, specific to the REPL language. The init file should be named as follow:
-``.lldbinit-<language>-repl`` (i.e. ``.lldbinit-swift-repl``). If this file doesn't
-exist, or :program:`lldb` wasn't launch with `REPL`_, meaning there is neither
+``.lldbinit-<language>-repl`` (i.e. ``.lldbinit-swift-repl`` or 
+``init-swift-repl`` in the config directory). If this file doesn't
+exist, or :program:`lldb` wasn't launched with `REPL`_, meaning there is neither
 a REPL init file nor an application specific init file, ``lldb`` will fallback to
-the global ~/.lldbinit.
+the global ``~/.lldbinit``.
 
-Secondly, it will look for an .lldbinit file in the current working directory.
+Secondly, it will look for an ``.lldbinit`` file in the current working directory.
 For security reasons, :program:`lldb` will print a warning and not source this
 file by default. This behavior can be changed by changing the
-target.load-cwd-lldbinit setting.
+``target.load-cwd-lldbinit`` setting.
 
-To always load the .lldbinit file in the current working directory, add the
-following command to ~/.lldbinit:
+To always load the ``.lldbinit`` file in the current working directory, add the
+following command to ``~/.lldbinit``:
 
   settings set target.load-cwd-lldbinit true
 
-To never load the .lldbinit file in the current working directory and silence
-the warning, add the following command to ~/.lldbinit:
+To never load the ``.lldbinit`` file in the current working directory and silence
+the warning, add the following command to ``~/.lldbinit``:
 
   settings set target.load-cwd-lldbinit false
 
diff --git a/lldb/include/lldb/Host/HostInfoBase.h b/lldb/include/lldb/Host/HostInfoBase.h
index ba31b60f76bfe8..6ba217b90fc75b 100644
--- a/lldb/include/lldb/Host/HostInfoBase.h
+++ b/lldb/include/lldb/Host/HostInfoBase.h
@@ -150,6 +150,10 @@ class HostInfoBase {
   /// directory member of the FileSpec is filled in.
   static FileSpec GetUserHomeDir();
 
+  /// Returns the directory containing the users configs (e.g. `~/.config`).
+  /// Only the directory member of the FileSpec is filled in.
+  static FileSpec GetUserConfigDir();
+
   /// Returns the directory containing the users lldb home (e.g. `~/.lldb/`).
   /// Only the directory member of the FileSpec is filled in.
   static FileSpec GetUserLLDBDir();
@@ -278,6 +282,7 @@ class HostInfoBase {
   static bool ComputeHeaderDirectory(FileSpec &file_spec);
   static bool ComputeSystemPluginsDirectory(FileSpec &file_spec);
   static bool ComputeUserHomeDirectory(FileSpec &file_spec);
+  static bool ComputeUserConfigDirectory(FileSpec &file_spec);
   static bool ComputeUserLLDBHomeDirectory(FileSpec &file_spec);
   static bool ComputeUserPluginsDirectory(FileSpec &file_spec);
 
diff --git a/lldb/source/Host/common/HostInfoBase.cpp b/lldb/source/Host/common/HostInfoBase.cpp
index fed7aa5cfde386..78303908039829 100644
--- a/lldb/source/Host/common/HostInfoBase.cpp
+++ b/lldb/source/Host/common/HostInfoBase.cpp
@@ -17,6 +17,7 @@
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/StreamString.h"
 
+#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/ScopedPrinter.h"
@@ -70,6 +71,8 @@ struct HostInfoBaseFields {
   FileSpec m_lldb_system_plugin_dir;
   llvm::once_flag m_lldb_user_home_dir_once;
   FileSpec m_lldb_user_home_dir;
+  llvm::once_flag m_lldb_user_config_dir_once;
+  FileSpec m_lldb_user_config_dir;
   llvm::once_flag m_lldb_user_lldb_dir_once;
   FileSpec m_lldb_user_lldb_dir;
   llvm::once_flag m_lldb_user_plugin_dir_once;
@@ -183,6 +186,16 @@ FileSpec HostInfoBase::GetUserHomeDir() {
   return g_fields->m_lldb_user_home_dir;
 }
 
+FileSpec HostInfoBase::GetUserConfigDir() {
+  llvm::call_once(g_fields->m_lldb_user_config_dir_once, []() {
+    if (!HostInfo::ComputeUserConfigDirectory(g_fields->m_lldb_user_config_dir))
+      g_fields->m_lldb_user_config_dir = FileSpec();
+    LLDB_LOG(GetLog(LLDBLog::Host), "user config dir -> `{0}`",
+             g_fields->m_lldb_user_config_dir);
+  });
+  return g_fields->m_lldb_user_config_dir;
+}
+
 FileSpec HostInfoBase::GetUserLLDBDir() {
   llvm::call_once(g_fields->m_lldb_user_lldb_dir_once, []() {
     if (!HostInfo::ComputeUserLLDBHomeDirectory(g_fields->m_lldb_user_lldb_dir))
@@ -366,6 +379,17 @@ bool HostInfoBase::ComputeUserHomeDirectory(FileSpec &file_spec) {
   return true;
 }
 
+bool HostInfoBase::ComputeUserConfigDirectory(FileSpec &file_spec) {
+  llvm::SmallString<256> str;
+  if (!llvm::sys::path::user_config_directory(str))
+    return false;
+  llvm::sys::path::append(str, "lldb");
+  FileSpec temp_file(str);
+  FileSystem::Instance().Resolve(temp_file);
+  file_spec.SetDirectory(temp_file.GetPath());
+  return true;
+}
+
 bool HostInfoBase::ComputeUserLLDBHomeDirectory(FileSpec &file_spec) {
   FileSpec home_dir_spec = GetUserHomeDir();
   home_dir_spec.AppendPathComponent(".lldb");
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index 6d361470039fda..087bce961a4447 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -2614,6 +2614,19 @@ int CommandInterpreter::GetOptionArgumentPosition(const char *in_string) {
   return position;
 }
 
+static void GetHomeOrConfigFile(FileSpec &file, llvm::StringRef name) {
+  FileSpec home_file =
+      HostInfo::GetUserHomeDir().CopyByAppendingPathComponent(name);
+  FileSpec config_dir = HostInfo::GetUserConfigDir();
+  if (FileSystem::Instance().Exists(home_file) || !config_dir) {
+    file = std::move(home_file);
+    return;
+  }
+  bool ok = name.consume_front(".lldb");
+  assert(ok);
+  file = config_dir.CopyByAppendingPathComponent(name);
+}
+
 static void GetHomeInitFile(FileSpec &init_file, llvm::StringRef suffix = {}) {
   std::string init_file_name = ".lldbinit";
   if (!suffix.empty()) {
@@ -2621,8 +2634,7 @@ static void GetHomeInitFile(FileSpec &init_file, llvm::StringRef suffix = {}) {
     init_file_name.append(suffix.str());
   }
 
-  init_file =
-      HostInfo::GetUserHomeDir().CopyByAppendingPathComponent(init_file_name);
+  GetHomeOrConfigFile(init_file, init_file_name);
 }
 
 static void GetHomeREPLInitFile(FileSpec &init_file, LanguageType language) {
@@ -2640,8 +2652,7 @@ static void GetHomeREPLInitFile(FileSpec &init_file, LanguageType language) {
        llvm::Twine("-repl"))
           .str();
 
-  init_file =
-      HostInfo::GetUserHomeDir().CopyByAppendingPathComponent(init_file_name);
+  GetHomeOrConfigFile(init_file, init_file_name);
 }
 
 static void GetCwdInitFile(llvm::SmallVectorImpl<char> &init_file) {
diff --git a/lldb/test/Shell/Driver/LLDBInitConfigDir.test b/lldb/test/Shell/Driver/LLDBInitConfigDir.test
new file mode 100644
index 00000000000000..b3082e41c1feca
--- /dev/null
+++ b/lldb/test/Shell/Driver/LLDBInitConfigDir.test
@@ -0,0 +1,56 @@
+# REQUIRES: python && system-linux
+
+# RUN: rm -rf %t.config
+# RUN: rm -rf %t.home
+# RUN: rm -rf %t.root
+
+# RUN: mkdir -p %t.config/lldb
+# RUN: mkdir -p %t.home/lldb
+# RUN: mkdir -p %t.root/lldb
+
+# RUN: echo 'script -- print("CFG: .config/.lldbinit#")' > %t.config/.lldbinit
+# RUN: echo 'script -- print("CFG: .config/lldb/.lldbinit#")' > %t.config/lldb/.lldbinit
+# RUN: echo 'script -- print("CFG: .config/lldb/init#")' > %t.config/lldb/init
+# RUN: echo 'script -- print("CFG: .config/lldb/init-lldb#")' > %t.config/lldb/init-lldb
+
+# RUN: echo 'script -- print("CFG: .home/lldb/init#")' > %t.home/lldb/init
+# RUN: echo 'script -- print("CFG: .home/.lldbinit#")' > %t.home/.lldbinit
+# RUN: echo 'script -- print("CFG: .home/.lldbinit-lldb#")' > %t.home/.lldbinit-lldb
+
+# RUN: echo 'script -- print("CFG: .root/lldb/init#")' > %t.root/lldb/init
+# RUN: echo 'script -- print("CFG: .root/.lldbinit#")' > %t.root/.lldbinit
+
+# RUN: cd %t.root
+
+# RUN: env HOME=%t.home XDG_CONFIG_HOME=%t.config %lldb-init 2>&1 | FileCheck %s -check-prefix=HOME-LLDB,CHECK
+# RUN: env HOME=%t.home XDG_CONFIG_HOME=%t.config %lldb-init -local-lldbinit 2>&1 | FileCheck %s -check-prefix=LOCAL,HOME-LLDB,CHECK
+
+# RUN: rm %t.home/.lldbinit-lldb
+
+# RUN: env HOME=%t.home XDG_CONFIG_HOME=%t.config %lldb-init 2>&1 | FileCheck %s -check-prefix=XDG-LLDB,CHECK
+# RUN: env HOME=%t.home XDG_CONFIG_HOME=%t.config %lldb-init -local-lldbinit 2>&1 | FileCheck %s -check-prefix=LOCAL,XDG-LLDB,CHECK
+
+# RUN: rm %t.config/lldb/init-lldb
+
+# RUN: env HOME=%t.home XDG_CONFIG_HOME=%t.config %lldb-init 2>&1 | FileCheck %s -check-prefix=HOME,CHECK
+# RUN: env HOME=%t.home XDG_CONFIG_HOME=%t.config %lldb-init -local-lldbinit 2>&1 | FileCheck %s -check-prefix=LOCAL,HOME,CHECK
+
+# RUN: rm %t.home/.lldbinit
+
+# RUN: env HOME=%t.home XDG_CONFIG_HOME=%t.config %lldb-init 2>&1 | FileCheck %s -check-prefix=XDG,CHECK
+# RUN: env HOME=%t.home XDG_CONFIG_HOME=%t.config %lldb-init -local-lldbinit 2>&1 | FileCheck %s -check-prefix=LOCAL,XDG,CHECK
+
+# HOME-LLDB: CFG: .home/.lldbinit-lldb#
+# CHECK-NOT: CFG:
+
+# HOME: CFG: .home/.lldbinit#
+# CHECK-NOT: CFG:
+
+# XDG: CFG: .config/lldb/init#
+# CHECK-NOT: CFG:
+
+# XDG-LLDB: CFG: .config/lldb/init-lldb#
+# CHECK-NOT: CFG:
+
+# LOCAL: CFG: .root/.lldbinit#
+# CHECK-NOT: CFG:

``````````

</details>


https://github.com/llvm/llvm-project/pull/236789


More information about the lldb-commits mailing list