Author: Thomas Applencourt
Date: 2025-12-16T22:15:11+09:00
New Revision: a0622a66c7f8655e6646283ab8e3a3f069571f2e

URL: 
https://github.com/llvm/llvm-project/commit/a0622a66c7f8655e6646283ab8e3a3f069571f2e
DIFF: 
https://github.com/llvm/llvm-project/commit/a0622a66c7f8655e6646283ab8e3a3f069571f2e.diff

LOG: [libclang/python] Add LIBCLANG_LIBRARY_PATH and LIBCLANG_LIBRARY_FILE 
(#170201)

Close #167421 

This PR adds the environment variables ``LIBCLANG_LIBRARY_PATH`` and
``LIBCLANG_LIBRARY_FILE``, which allow users to specify the directory
path and the exact library file that should be used to locate libclang.

---------

Co-authored-by: Jannick Kremer <[email protected]>
Co-authored-by: Vlad Serebrennikov <[email protected]>

Added: 
    clang/bindings/python/tests/cindex/test_environment_variable.py

Modified: 
    clang/bindings/python/README.txt
    clang/bindings/python/clang/cindex.py
    clang/bindings/python/tests/CMakeLists.txt
    clang/bindings/python/tests/cindex/test_access_specifiers.py
    clang/bindings/python/tests/cindex/test_cdb.py
    clang/bindings/python/tests/cindex/test_code_completion.py
    clang/bindings/python/tests/cindex/test_comment.py
    clang/bindings/python/tests/cindex/test_cursor.py
    clang/bindings/python/tests/cindex/test_cursor_kind.py
    clang/bindings/python/tests/cindex/test_cursor_language.py
    clang/bindings/python/tests/cindex/test_diagnostics.py
    clang/bindings/python/tests/cindex/test_exception_specification_kind.py
    clang/bindings/python/tests/cindex/test_file.py
    clang/bindings/python/tests/cindex/test_index.py
    clang/bindings/python/tests/cindex/test_lib.py
    clang/bindings/python/tests/cindex/test_linkage.py
    clang/bindings/python/tests/cindex/test_location.py
    clang/bindings/python/tests/cindex/test_source_range.py
    clang/bindings/python/tests/cindex/test_tls_kind.py
    clang/bindings/python/tests/cindex/test_token_kind.py
    clang/bindings/python/tests/cindex/test_tokens.py
    clang/bindings/python/tests/cindex/test_translation_unit.py
    clang/bindings/python/tests/cindex/test_type.py
    clang/docs/ReleaseNotes.rst

Removed: 
    


################################################################################
diff  --git a/clang/bindings/python/README.txt 
b/clang/bindings/python/README.txt
index 3e509662144fa..1898b4d303b45 100644
--- a/clang/bindings/python/README.txt
+++ b/clang/bindings/python/README.txt
@@ -4,12 +4,12 @@
 
 This directory implements Python bindings for Clang.
 
-You may need to set CLANG_LIBRARY_PATH so that the Clang library can be
+You may need to set LIBCLANG_LIBRARY_PATH so that the Clang library can be
 found. The unit tests are designed to be run with any standard test
 runner. For example:
 --
 $ env PYTHONPATH=$(echo ~/llvm/clang/bindings/python/) \
-      CLANG_LIBRARY_PATH=$(llvm-config --libdir) \
+      LIBCLANG_LIBRARY_PATH=$(llvm-config --libdir) \
   python3 -m unittest discover -v
 tests.cindex.test_index.test_create ... ok
 ...

diff  --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index d352373e85c60..5a5267f51d84e 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -4383,8 +4383,8 @@ def register(item: LibFunc) -> None:
 
 
 class Config:
-    library_path = None
-    library_file: str | None = None
+    library_path: str | None = os.environ.get("LIBCLANG_LIBRARY_PATH")
+    library_file: str | None = os.environ.get("LIBCLANG_LIBRARY_FILE")
     compatibility_check = True
     loaded = False
 
@@ -4468,10 +4468,11 @@ def get_cindex_library(self) -> CDLL:
         try:
             library = cdll.LoadLibrary(self.get_filename())
         except OSError as e:
-            msg = (
-                str(e) + ". To provide a path to libclang use "
-                "Config.set_library_path() or "
-                "Config.set_library_file()."
+            msg = str(e) + (
+                "To provide the path to the directory containing libclang, you 
can use the environment variable "
+                "LIBCLANG_LIBRARY_PATH or call Config.set_library_path(). "
+                "Alternatively, you can specify the path of the library file 
using "
+                "LIBCLANG_LIBRARY_FILE or Config.set_library_file()."
             )
             raise LibclangError(msg)
 

diff  --git a/clang/bindings/python/tests/CMakeLists.txt 
b/clang/bindings/python/tests/CMakeLists.txt
index d9a6bbf452bd6..21fe6fb79793f 100644
--- a/clang/bindings/python/tests/CMakeLists.txt
+++ b/clang/bindings/python/tests/CMakeLists.txt
@@ -5,7 +5,7 @@
 add_custom_target(check-clang-python
     COMMAND ${CMAKE_COMMAND} -E env
             CLANG_NO_DEFAULT_CONFIG=1
-            CLANG_LIBRARY_PATH=$<TARGET_FILE_DIR:libclang>
+            LIBCLANG_LIBRARY_PATH=$<TARGET_FILE_DIR:libclang>
             "${Python3_EXECUTABLE}" -m unittest discover
     DEPENDS libclang
     WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/..)

diff  --git a/clang/bindings/python/tests/cindex/test_access_specifiers.py 
b/clang/bindings/python/tests/cindex/test_access_specifiers.py
index ca2bbd3cc8611..7397daddc3ace 100644
--- a/clang/bindings/python/tests/cindex/test_access_specifiers.py
+++ b/clang/bindings/python/tests/cindex/test_access_specifiers.py
@@ -1,9 +1,5 @@
-import os
+from clang.cindex import AccessSpecifier
 
-from clang.cindex import AccessSpecifier, Config
-
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import unittest
 

diff  --git a/clang/bindings/python/tests/cindex/test_cdb.py 
b/clang/bindings/python/tests/cindex/test_cdb.py
index 5abe56f0d65f8..735daefe4c62d 100644
--- a/clang/bindings/python/tests/cindex/test_cdb.py
+++ b/clang/bindings/python/tests/cindex/test_cdb.py
@@ -1,9 +1,7 @@
 import os
 
-from clang.cindex import CompilationDatabase, CompilationDatabaseError, Config
+from clang.cindex import CompilationDatabase, CompilationDatabaseError
 
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import gc
 import unittest

diff  --git a/clang/bindings/python/tests/cindex/test_code_completion.py 
b/clang/bindings/python/tests/cindex/test_code_completion.py
index c7a86aa82a8eb..32b75eb1ae029 100644
--- a/clang/bindings/python/tests/cindex/test_code_completion.py
+++ b/clang/bindings/python/tests/cindex/test_code_completion.py
@@ -1,9 +1,5 @@
-import os
+from clang.cindex import TranslationUnit
 
-from clang.cindex import Config, TranslationUnit
-
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import unittest
 from pathlib import Path

diff  --git a/clang/bindings/python/tests/cindex/test_comment.py 
b/clang/bindings/python/tests/cindex/test_comment.py
index 1ecbb42c18ffc..382ca867dcebd 100644
--- a/clang/bindings/python/tests/cindex/test_comment.py
+++ b/clang/bindings/python/tests/cindex/test_comment.py
@@ -1,9 +1,5 @@
-import os
+from clang.cindex import TranslationUnit
 
-from clang.cindex import Config, TranslationUnit
-
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import unittest
 

diff  --git a/clang/bindings/python/tests/cindex/test_cursor.py 
b/clang/bindings/python/tests/cindex/test_cursor.py
index 7cb616a7ef148..76680e576b307 100644
--- a/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -1,9 +1,6 @@
-import os
-
 from clang.cindex import (
     AvailabilityKind,
     BinaryOperator,
-    Config,
     Cursor,
     CursorKind,
     PrintingPolicy,
@@ -15,8 +12,6 @@
     conf,
 )
 
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import gc
 import unittest

diff  --git a/clang/bindings/python/tests/cindex/test_cursor_kind.py 
b/clang/bindings/python/tests/cindex/test_cursor_kind.py
index 3b693ff45cfd4..25c1636de5f52 100644
--- a/clang/bindings/python/tests/cindex/test_cursor_kind.py
+++ b/clang/bindings/python/tests/cindex/test_cursor_kind.py
@@ -1,9 +1,5 @@
-import os
+from clang.cindex import CursorKind
 
-from clang.cindex import Config, CursorKind
-
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import unittest
 

diff  --git a/clang/bindings/python/tests/cindex/test_cursor_language.py 
b/clang/bindings/python/tests/cindex/test_cursor_language.py
index fa2a678f736a9..dc0ee57541f75 100644
--- a/clang/bindings/python/tests/cindex/test_cursor_language.py
+++ b/clang/bindings/python/tests/cindex/test_cursor_language.py
@@ -1,9 +1,5 @@
-import os
+from clang.cindex import LanguageKind
 
-from clang.cindex import Config, LanguageKind
-
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import unittest
 

diff  --git a/clang/bindings/python/tests/cindex/test_diagnostics.py 
b/clang/bindings/python/tests/cindex/test_diagnostics.py
index ee7d37c896d70..17c1a4e50a20c 100644
--- a/clang/bindings/python/tests/cindex/test_diagnostics.py
+++ b/clang/bindings/python/tests/cindex/test_diagnostics.py
@@ -1,9 +1,5 @@
-import os
+from clang.cindex import Diagnostic
 
-from clang.cindex import Config, Diagnostic
-
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import unittest
 

diff  --git a/clang/bindings/python/tests/cindex/test_environment_variable.py 
b/clang/bindings/python/tests/cindex/test_environment_variable.py
new file mode 100644
index 0000000000000..09ad81c9f3751
--- /dev/null
+++ b/clang/bindings/python/tests/cindex/test_environment_variable.py
@@ -0,0 +1,63 @@
+import unittest
+import unittest.mock
+import sys
+import os
+
+
+def reset_import_and_get_fresh_config():
+    # Reloads the clang.cindex module to reset any class-level state in Config.
+    sys.modules.pop("clang.cindex", None)
+    sys.modules.pop("clang", None)
+    from clang.cindex import Config
+
+    return Config()
+
+
+class TestEnvironementVariable(unittest.TestCase):
+    def test_working_libclang_library_file(self):
+        ref_libclang_library_file = 
reset_import_and_get_fresh_config().get_filename()
+        with unittest.mock.patch.dict(
+            os.environ, {"LIBCLANG_LIBRARY_FILE": ref_libclang_library_file}
+        ):
+            reset_import_and_get_fresh_config().lib
+
+    @unittest.mock.patch.dict("os.environ", {"LIBCLANG_LIBRARY_FILE": 
"/dev/null"})
+    def test_non_working_libclang_library_file(self):
+        config = reset_import_and_get_fresh_config()
+        import clang.cindex
+
+        with self.assertRaises(clang.cindex.LibclangError):
+            config.lib
+
+    def test_working_libclang_library_path(self):
+        # Get adequate libclang path
+        ref_libclang_library_file = 
reset_import_and_get_fresh_config().get_filename()
+        ref_libclang_library_path, filename = 
os.path.split(ref_libclang_library_file)
+        filename_root, filename_ext = os.path.splitext(filename)
+
+        # Config only recognizes the default libclang filename.
+        # If LIBCLANG_LIBRARY_FILE points to a non-standard name, skip this 
test.
+
+        if not (
+            filename_root == "libclang" and filename_ext in (".so", ".dll", 
".dylib")
+        ):
+            self.skipTest(f"Skipping because {filename} is not a default 
libclang name")
+
+        with unittest.mock.patch.dict(
+            os.environ, {"LIBCLANG_LIBRARY_PATH": ref_libclang_library_path}
+        ):
+            # Remove LIBCLANG_LIBRARY_FILE to avoid it taking precedence if 
set by the user
+            # Need to be in the mocked environement
+            os.environ.pop("LIBCLANG_LIBRARY_FILE", None)
+            reset_import_and_get_fresh_config().lib
+
+    @unittest.mock.patch.dict("os.environ", {"LIBCLANG_LIBRARY_PATH": 
"not_a_real_dir"})
+    def test_non_working_libclang_library_path(self):
+        # Remove LIBCLANG_LIBRARY_FILE to avoid it taking precedence if set by 
the user
+        os.environ.pop("LIBCLANG_LIBRARY_FILE", None)
+
+        config = reset_import_and_get_fresh_config()
+        import clang.cindex
+
+        with self.assertRaises(clang.cindex.LibclangError):
+            config.lib

diff  --git 
a/clang/bindings/python/tests/cindex/test_exception_specification_kind.py 
b/clang/bindings/python/tests/cindex/test_exception_specification_kind.py
index f7806ffad8012..26181c8143fb7 100644
--- a/clang/bindings/python/tests/cindex/test_exception_specification_kind.py
+++ b/clang/bindings/python/tests/cindex/test_exception_specification_kind.py
@@ -1,9 +1,5 @@
-import os
+from clang.cindex import CursorKind, ExceptionSpecificationKind
 
-from clang.cindex import Config, CursorKind, ExceptionSpecificationKind
-
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import unittest
 

diff  --git a/clang/bindings/python/tests/cindex/test_file.py 
b/clang/bindings/python/tests/cindex/test_file.py
index 2be9b9e332611..ab5c7ca543055 100644
--- a/clang/bindings/python/tests/cindex/test_file.py
+++ b/clang/bindings/python/tests/cindex/test_file.py
@@ -1,9 +1,7 @@
 import os
 
-from clang.cindex import Config, File, Index, TranslationUnit
+from clang.cindex import File, Index, TranslationUnit
 
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import unittest
 

diff  --git a/clang/bindings/python/tests/cindex/test_index.py 
b/clang/bindings/python/tests/cindex/test_index.py
index f3d3ac00e5f7b..8e169ac73d4a0 100644
--- a/clang/bindings/python/tests/cindex/test_index.py
+++ b/clang/bindings/python/tests/cindex/test_index.py
@@ -1,9 +1,7 @@
 import os
 
-from clang.cindex import Config, Index, TranslationUnit
+from clang.cindex import Index, TranslationUnit
 
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import unittest
 

diff  --git a/clang/bindings/python/tests/cindex/test_lib.py 
b/clang/bindings/python/tests/cindex/test_lib.py
index 5e88ebf9d8448..c1b1e8e1ab392 100644
--- a/clang/bindings/python/tests/cindex/test_lib.py
+++ b/clang/bindings/python/tests/cindex/test_lib.py
@@ -1,9 +1,5 @@
-import os
-
 import clang.cindex
 
-if "CLANG_LIBRARY_PATH" in os.environ:
-    clang.cindex.Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import unittest
 import ast

diff  --git a/clang/bindings/python/tests/cindex/test_linkage.py 
b/clang/bindings/python/tests/cindex/test_linkage.py
index 93bf43a042047..74c1982925f1d 100644
--- a/clang/bindings/python/tests/cindex/test_linkage.py
+++ b/clang/bindings/python/tests/cindex/test_linkage.py
@@ -1,9 +1,5 @@
-import os
+from clang.cindex import LinkageKind
 
-from clang.cindex import Config, LinkageKind
-
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import unittest
 

diff  --git a/clang/bindings/python/tests/cindex/test_location.py 
b/clang/bindings/python/tests/cindex/test_location.py
index 3c6b0357e2f83..8d43d5012321a 100644
--- a/clang/bindings/python/tests/cindex/test_location.py
+++ b/clang/bindings/python/tests/cindex/test_location.py
@@ -2,7 +2,6 @@
 from pathlib import Path
 
 from clang.cindex import (
-    Config,
     Cursor,
     File,
     SourceLocation,
@@ -10,8 +9,6 @@
     TranslationUnit,
 )
 
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import unittest
 

diff  --git a/clang/bindings/python/tests/cindex/test_source_range.py 
b/clang/bindings/python/tests/cindex/test_source_range.py
index ca3ebc4041955..f1f2694b5820c 100644
--- a/clang/bindings/python/tests/cindex/test_source_range.py
+++ b/clang/bindings/python/tests/cindex/test_source_range.py
@@ -1,10 +1,7 @@
-import os
 from pathlib import Path
 
-from clang.cindex import Config, SourceLocation, SourceRange, TranslationUnit
+from clang.cindex import SourceLocation, SourceRange, TranslationUnit
 
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import unittest
 

diff  --git a/clang/bindings/python/tests/cindex/test_tls_kind.py 
b/clang/bindings/python/tests/cindex/test_tls_kind.py
index f80a46f4d5680..16b8cdf6cbfb1 100644
--- a/clang/bindings/python/tests/cindex/test_tls_kind.py
+++ b/clang/bindings/python/tests/cindex/test_tls_kind.py
@@ -1,9 +1,5 @@
-import os
+from clang.cindex import TLSKind
 
-from clang.cindex import Config, TLSKind
-
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import unittest
 

diff  --git a/clang/bindings/python/tests/cindex/test_token_kind.py 
b/clang/bindings/python/tests/cindex/test_token_kind.py
index 594f30a448d84..59d4c43ec5607 100644
--- a/clang/bindings/python/tests/cindex/test_token_kind.py
+++ b/clang/bindings/python/tests/cindex/test_token_kind.py
@@ -1,9 +1,5 @@
-import os
+from clang.cindex import TokenKind
 
-from clang.cindex import Config, TokenKind
-
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import unittest
 

diff  --git a/clang/bindings/python/tests/cindex/test_tokens.py 
b/clang/bindings/python/tests/cindex/test_tokens.py
index 6658579c63835..049e4a5ae6382 100644
--- a/clang/bindings/python/tests/cindex/test_tokens.py
+++ b/clang/bindings/python/tests/cindex/test_tokens.py
@@ -1,9 +1,5 @@
-import os
+from clang.cindex import CursorKind, SourceLocation, SourceRange, TokenKind
 
-from clang.cindex import Config, CursorKind, SourceLocation, SourceRange, 
TokenKind
-
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import unittest
 

diff  --git a/clang/bindings/python/tests/cindex/test_translation_unit.py 
b/clang/bindings/python/tests/cindex/test_translation_unit.py
index 272cf05bed7b7..d43cebcef3310 100644
--- a/clang/bindings/python/tests/cindex/test_translation_unit.py
+++ b/clang/bindings/python/tests/cindex/test_translation_unit.py
@@ -1,7 +1,6 @@
 import os
 
 from clang.cindex import (
-    Config,
     Cursor,
     CursorKind,
     File,
@@ -13,8 +12,6 @@
     TranslationUnitSaveError,
 )
 
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import gc
 import tempfile

diff  --git a/clang/bindings/python/tests/cindex/test_type.py 
b/clang/bindings/python/tests/cindex/test_type.py
index cc101beca8cc5..562ac74e98b6e 100644
--- a/clang/bindings/python/tests/cindex/test_type.py
+++ b/clang/bindings/python/tests/cindex/test_type.py
@@ -1,7 +1,4 @@
-import os
-
 from clang.cindex import (
-    Config,
     CursorKind,
     PrintingPolicy,
     PrintingPolicyProperty,
@@ -10,8 +7,6 @@
     TypeKind,
 )
 
-if "CLANG_LIBRARY_PATH" in os.environ:
-    Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])
 
 import gc
 import unittest

diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 37100249058ef..c39fe6e98b176 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -176,6 +176,9 @@ Clang Python Bindings Potentially Breaking Changes
   ElaboratedTypes. The value becomes unused, and all the existing users should
   expect the former underlying type to be reported instead.
 - Remove ``AccessSpecifier.NONE`` kind. No libclang interfaces ever returned 
this kind.
+- Allow setting the path to the libclang library via environment variables: 
``LIBCLANG_LIBRARY_PATH``
+  to specifiy the path to the containing folder, or ``LIBCLANG_LIBRARY_FILE`` 
to specify the path to
+  the library file
 
 What's New in Clang |release|?
 ==============================


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to