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=$ + LIBCLANG_LIBRARY_PATH=$ "${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 de07a7bdeef40..0001d71e6744c 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 6838e926f4c9d..e8dc5fd0683aa 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -170,6 +170,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|? ==============================