Skip to content

Commit aea9e64

Browse files
committed
Improved Linux LLVM/libclang detection
The previous path detection logic of pybind11_mkdoc uses mismatched LLVM and libclang paths e.g. when LLVM 9 & 11 is installed but the libc++ version is stuck at v9. This commit causes the two to be consistent and generally simplifies the code that has grown somewhat organically. The ability to override paths is retained.
1 parent c4822b8 commit aea9e64

File tree

1 file changed

+50
-54
lines changed

1 file changed

+50
-54
lines changed

pybind11_mkdoc/mkdoc_lib.py

Lines changed: 50 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -287,76 +287,72 @@ def read_args(args):
287287
if library_file is not None:
288288
cindex.Config.set_library_file(library_file)
289289
elif platform.system() == 'Linux':
290-
# cython.util.find_library does not find `libclang` for all clang
291-
# versions and distributions. LLVM switched to a monolithical setup
292-
# that includes everything under /usr/lib/llvm{version_number}/
293-
# We therefore glob for the library and select the highest version
294-
if 'LIBCLANG_PATH' in os.environ:
295-
cindex.Config.set_library_file(os.environ['LIBCLANG_PATH'])
296-
else:
297-
library_file_dirs = glob("/usr/lib/llvm-*/lib/libclang.so.1")
298-
if len(library_file_dirs) > 0:
299-
library_file = sorted(library_file_dirs, reverse=True)[0]
300-
cindex.Config.set_library_file(library_file)
301-
else:
302-
raise FileNotFoundError("Failed to find libclang.so shared object file! "
303-
"Set the LIBCLANG_PATH environment variable to provide a path to it.")
304-
305-
# clang doesn't find its own base includes by default on Linux,
306-
# but different distros install them in different paths.
307-
# Try to autodetect, preferring the highest numbered version.
290+
# LLVM switched to a monolithical setup that includes everything under
291+
# /usr/lib/llvm{version_number}/. We glob for the library and select
292+
# the highest version
308293
def folder_version(d):
309294
return [int(ver) for ver in re.findall(r'(?<!lib)(?<!\d)\d+', d)]
310295

311-
# capability to specify path to LLVM dir manually
312-
# useful when installing LLVM to non standard directories
296+
llvm_dir = max((
297+
path
298+
for libdir in ['lib64', 'lib', 'lib32']
299+
for path in glob('/usr/%s/llvm-*' % libdir)
300+
if os.path.exists(os.path.join(path, 'lib', 'libclang.so.1'))
301+
), default=None, key=folder_version)
302+
303+
# Ability to override LLVM/libclang paths
313304
if 'LLVM_DIR_PATH' in os.environ:
314305
llvm_dir = os.environ['LLVM_DIR_PATH']
306+
elif llvm_dir is None:
307+
raise FileNotFoundError(
308+
"Failed to find a LLVM installation providing the file "
309+
"/usr/lib{32,64}/llvm-{VER}/lib/libclang.so.1. Make sure that "
310+
"you have installed the packages libclang1-{VER} and "
311+
"libc++-{VER}-dev, where {VER} refers to the desired "
312+
"Clang/LLVM version (e.g. 11). You may alternatively override "
313+
"the automatic search by specifying the LIBLLVM_DIR_PATH "
314+
"(for the LLVM base directory) and/or LIBCLANG_PATH (if "
315+
"libclang is located at a nonstandard location) environment "
316+
"variables.")
317+
318+
if 'LIBCLANG_PATH' in os.environ:
319+
libclang_dir = os.environ['LIBCLANG_PATH']
315320
else:
316-
llvm_dir = max((
317-
path
318-
for libdir in ['lib64', 'lib', 'lib32']
319-
for path in glob('/usr/%s/llvm-*' % libdir)
320-
if os.path.isdir(path)
321-
), default=None, key=folder_version)
321+
libclang_dir = os.path.join(llvm_dir, 'lib', 'libclang.so.1')
322322

323+
cindex.Config.set_library_file(libclang_dir)
324+
cpp_dirs = [ ]
323325

324-
if llvm_dir:
325-
if '-stdlib=libc++' in args:
326-
parameters.extend(['-isystem', os.path.join(llvm_dir, 'include', 'c++', 'v1')])
326+
if '-stdlib=libc++' not in args:
327+
cpp_dirs.append(max(
328+
glob('/usr/include/c++/*'
329+
), default=None, key=folder_version))
327330

328-
if 'CLANG_INCLUDE_DIR' in os.environ:
329-
clang_include_dir = os.environ['CLANG_INCLUDE_DIR']
330-
else:
331-
clang_include_dir = max(
332-
glob(os.path.join(llvm_dir, 'lib', 'clang', '*')
333-
), default=None, key=folder_version)
331+
cpp_dirs.append(max(
332+
glob('/usr/include/%s-linux-gnu/c++/*' % platform.machine()
333+
), default=None, key=folder_version))
334+
else:
335+
cpp_dirs.append(os.path.join(llvm_dir, 'include', 'c++', 'v1'))
334336

335-
if clang_include_dir is not None:
336-
parameters.extend(['-isystem', clang_include_dir])
337+
if 'CLANG_INCLUDE_DIR' in os.environ:
338+
cpp_dirs.append(os.environ['CLANG_INCLUDE_DIR'])
339+
else:
340+
cpp_dirs.append(max(
341+
glob(os.path.join(llvm_dir, 'lib', 'clang', '*', 'include')
342+
), default=None, key=folder_version))
337343

338-
# Add additional C++ include directories
339-
cpp_dirs = []
344+
cpp_dirs.append('/usr/include/%s-linux-gnu' % platform.machine())
345+
cpp_dirs.append('/usr/include')
340346

341-
# capability to specify more cpp include dirs manually
347+
# Capability to specify additional include directories manually
342348
if 'CPP_INCLUDE_DIRS' in os.environ:
343349
cpp_dirs.extend([cpp_dir for cpp_dir in os.environ['CPP_INCLUDE_DIRS'].split()
344350
if os.path.exists(cpp_dir)])
345351

346-
cpp_dirs.append(max(
347-
glob('/usr/include/c++/*'
348-
), default=None, key=folder_version))
349-
350-
cpp_dirs.append(max(
351-
glob('/usr/include/%s-linux-gnu/c++/*' % platform.machine()
352-
), default=None, key=folder_version))
353-
354-
for cpp_dir in cpp_dirs :
355-
if cpp_dir is not None :
356-
parameters.extend(['-isystem', cpp_dir])
357-
358-
parameters.extend(['-isystem', '/usr/include/%s-linux-gnu' % platform.machine(),
359-
'-isystem', '/usr/include'])
352+
for cpp_dir in cpp_dirs:
353+
if cpp_dir is None:
354+
continue
355+
parameters.extend(['-isystem', cpp_dir])
360356

361357
for item in args:
362358
if item.startswith('-'):

0 commit comments

Comments
 (0)