[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