|
8 | 8 | # ------------------------------ |
9 | 9 | from __future__ import annotations |
10 | 10 |
|
| 11 | +import distutils.ccompiler |
11 | 12 | import os |
12 | 13 | import re |
13 | 14 | import shutil |
14 | 15 | import struct |
15 | 16 | import subprocess |
16 | 17 | import sys |
| 18 | +import tempfile |
17 | 19 | import warnings |
18 | 20 | from collections.abc import Iterator |
19 | 21 | from typing import Any |
@@ -292,6 +294,47 @@ def _pkg_config(name: str) -> tuple[list[str], list[str]] | None: |
292 | 294 | return None |
293 | 295 |
|
294 | 296 |
|
| 297 | +def _try_compile(compiler: distutils.ccompiler.CCompiler, code: str) -> bool: |
| 298 | + try: |
| 299 | + with tempfile.TemporaryDirectory() as d: |
| 300 | + fn = os.path.join(d, "test.c") |
| 301 | + with open(fn, "w") as f: |
| 302 | + f.write(code) |
| 303 | + compiler.compile([fn], output_dir=d, extra_preargs=["-Werror"]) |
| 304 | + return True |
| 305 | + except distutils.ccompiler.CompileError: |
| 306 | + return False |
| 307 | + |
| 308 | + |
| 309 | +def _try_compile_attr(compiler: distutils.ccompiler.CCompiler, attr: str) -> bool: |
| 310 | + code = f""" |
| 311 | + #pragma GCC diagnostic error "-Wattributes" |
| 312 | + #pragma clang diagnostic error "-Wattributes" |
| 313 | +
|
| 314 | + int {attr} foo; |
| 315 | + int main() {{ |
| 316 | + return 0; |
| 317 | + }} |
| 318 | + """ |
| 319 | + |
| 320 | + return _try_compile(compiler, code) |
| 321 | + |
| 322 | + |
| 323 | +def _try_compile_tls_define_macro( |
| 324 | + compiler: distutils.ccompiler.CCompiler, |
| 325 | +) -> tuple[str, str | None] | None: |
| 326 | + if _try_compile_attr(compiler, "thread_local"): # C23 |
| 327 | + return ("HAVE_THREAD_LOCAL", None) |
| 328 | + elif _try_compile_attr(compiler, "_Thread_local"): # C11/C17 |
| 329 | + return ("HAVE__THREAD_LOCAL", None) |
| 330 | + elif _try_compile_attr(compiler, "__thread"): # GCC/clang |
| 331 | + return ("HAVE___THREAD", None) |
| 332 | + elif _try_compile_attr(compiler, "__declspec(thread)"): # MSVC |
| 333 | + return ("HAVE___DECLSPEC_THREAD_", None) |
| 334 | + else: |
| 335 | + return None |
| 336 | + |
| 337 | + |
295 | 338 | class pil_build_ext(build_ext): |
296 | 339 | class ext_feature: |
297 | 340 | features = [ |
@@ -888,6 +931,10 @@ def build_extensions(self) -> None: |
888 | 931 | if struct.unpack("h", b"\0\1")[0] == 1: |
889 | 932 | defs.append(("WORDS_BIGENDIAN", None)) |
890 | 933 |
|
| 934 | + tls_define_macro = _try_compile_tls_define_macro(self.compiler) |
| 935 | + if tls_define_macro is not None: |
| 936 | + defs.append(tls_define_macro) |
| 937 | + |
891 | 938 | defs.append(("PILLOW_VERSION", f'"{PILLOW_VERSION}"')) |
892 | 939 |
|
893 | 940 | self._update_extension("PIL._imaging", libs, defs) |
@@ -1008,18 +1055,32 @@ def debug_build() -> bool: |
1008 | 1055 |
|
1009 | 1056 |
|
1010 | 1057 | files: list[str | os.PathLike[str]] = ["src/_imaging.c"] |
| 1058 | +define_macros: list[tuple[str, str | None]] = [] |
| 1059 | + |
| 1060 | +tls_define_macro = _try_compile_tls_define_macro(distutils.ccompiler.new_compiler()) |
| 1061 | +if tls_define_macro is not None: |
| 1062 | + define_macros.append(tls_define_macro) |
| 1063 | + |
1011 | 1064 | for src_file in _IMAGING: |
1012 | 1065 | files.append("src/" + src_file + ".c") |
1013 | 1066 | for src_file in _LIB_IMAGING: |
1014 | 1067 | files.append(os.path.join("src/libImaging", src_file + ".c")) |
1015 | 1068 | ext_modules = [ |
1016 | | - Extension("PIL._imaging", files), |
1017 | | - Extension("PIL._imagingft", ["src/_imagingft.c"]), |
1018 | | - Extension("PIL._imagingcms", ["src/_imagingcms.c"]), |
1019 | | - Extension("PIL._webp", ["src/_webp.c"]), |
1020 | | - Extension("PIL._imagingtk", ["src/_imagingtk.c", "src/Tk/tkImaging.c"]), |
1021 | | - Extension("PIL._imagingmath", ["src/_imagingmath.c"]), |
1022 | | - Extension("PIL._imagingmorph", ["src/_imagingmorph.c"]), |
| 1069 | + Extension("PIL._imaging", files, define_macros=define_macros), |
| 1070 | + Extension("PIL._imagingft", ["src/_imagingft.c"], define_macros=define_macros[:]), |
| 1071 | + Extension("PIL._imagingcms", ["src/_imagingcms.c"], define_macros=define_macros[:]), |
| 1072 | + Extension("PIL._webp", ["src/_webp.c"], define_macros=define_macros[:]), |
| 1073 | + Extension( |
| 1074 | + "PIL._imagingtk", |
| 1075 | + ["src/_imagingtk.c", "src/Tk/tkImaging.c"], |
| 1076 | + define_macros=define_macros[:], |
| 1077 | + ), |
| 1078 | + Extension( |
| 1079 | + "PIL._imagingmath", ["src/_imagingmath.c"], define_macros=define_macros[:] |
| 1080 | + ), |
| 1081 | + Extension( |
| 1082 | + "PIL._imagingmorph", ["src/_imagingmorph.c"], define_macros=define_macros[:] |
| 1083 | + ), |
1023 | 1084 | ] |
1024 | 1085 |
|
1025 | 1086 |
|
|
0 commit comments