|
5 | 5 |
|
6 | 6 | from __future__ import annotations |
7 | 7 |
|
| 8 | +import os |
| 9 | +import shlex |
8 | 10 | import sys |
9 | 11 | from pathlib import Path |
10 | 12 |
|
11 | 13 | from setuptools import Extension, setup |
12 | 14 | from setuptools.command.build_ext import build_ext |
13 | 15 |
|
| 16 | + |
14 | 17 | ROOT_DIR = Path(__file__).resolve().parent |
15 | 18 | if str(ROOT_DIR) not in sys.path: |
16 | 19 | sys.path.insert(0, str(ROOT_DIR)) |
17 | 20 |
|
18 | | -from setup_utils import MODULE_SOURCES, collect_build_config |
| 21 | +import setup_utils |
| 22 | +from setup_utils import ( |
| 23 | + augment_compile_flags, |
| 24 | + discover_include_dirs, |
| 25 | + discover_library_dirs, |
| 26 | + extend_env_paths, |
| 27 | + extend_unique, |
| 28 | + find_library_with_brew, |
| 29 | + find_library_with_ldconfig, |
| 30 | + find_library_with_pkg_config, |
| 31 | + has_header, |
| 32 | + has_library, |
| 33 | + is_truthy_env, |
| 34 | + is_windows_platform, |
| 35 | + locate_library_file, |
| 36 | + prepare_pcre2_source, |
| 37 | + run_pkg_config, |
| 38 | +) |
| 39 | + |
| 40 | + |
| 41 | +MODULE_SOURCES = [ |
| 42 | + "pcre_ext/pcre2.c", |
| 43 | + "pcre_ext/error.c", |
| 44 | + "pcre_ext/cache.c", |
| 45 | + "pcre_ext/flag.c", |
| 46 | + "pcre_ext/util.c", |
| 47 | + "pcre_ext/memory.c", |
| 48 | +] |
| 49 | + |
| 50 | +PCRE_EXT_DIR = ROOT_DIR / "pcre_ext" |
| 51 | +PCRE2_REPO_URL = "https://github.com/PCRE2Project/pcre2.git" |
| 52 | +PCRE2_TAG = "pcre2-10.46" |
| 53 | + |
| 54 | +LIB_EXTENSIONS = [ |
| 55 | + ".so", |
| 56 | + ".so.0", |
| 57 | + ".so.1", |
| 58 | + ".a", |
| 59 | + ".dylib", |
| 60 | + ".sl", |
| 61 | +] |
| 62 | + |
| 63 | +LIBRARY_BASENAME = "libpcre2-8" |
| 64 | + |
| 65 | +LIBRARY_SEARCH_PATTERNS = [ |
| 66 | + f"**/{LIBRARY_BASENAME}.lib", |
| 67 | + f"**/{LIBRARY_BASENAME}.a", |
| 68 | + f"**/{LIBRARY_BASENAME}.so", |
| 69 | + f"**/{LIBRARY_BASENAME}.so.*", |
| 70 | + f"**/{LIBRARY_BASENAME}.dylib", |
| 71 | + "**/pcre2-8.lib", |
| 72 | + "**/pcre2-8.dll", |
| 73 | + "**/pcre2-8-static.lib", |
| 74 | + "**/pcre2-8-static.dll", |
| 75 | +] |
| 76 | + |
| 77 | +RUNTIME_LIBRARY_FILES: list[str] = [] |
| 78 | + |
| 79 | +setup_utils.configure_environment( |
| 80 | + pcre_ext_dir=PCRE_EXT_DIR, |
| 81 | + repo_url=PCRE2_REPO_URL, |
| 82 | + repo_tag=PCRE2_TAG, |
| 83 | + lib_extensions=LIB_EXTENSIONS, |
| 84 | + library_basename=LIBRARY_BASENAME, |
| 85 | + library_search_patterns=LIBRARY_SEARCH_PATTERNS, |
| 86 | +) |
| 87 | + |
| 88 | + |
| 89 | +def collect_build_config() -> dict[str, list[str] | list[tuple[str, str | None]]]: |
| 90 | + include_dirs: list[str] = [] |
| 91 | + library_dirs: list[str] = [] |
| 92 | + libraries: list[str] = [] |
| 93 | + extra_compile_args: list[str] = [] |
| 94 | + extra_link_args: list[str] = [] |
| 95 | + define_macros: list[tuple[str, str | None]] = [] |
| 96 | + library_files: list[str] = [] |
| 97 | + |
| 98 | + source_include_dirs, source_library_dirs, source_library_files = prepare_pcre2_source() |
| 99 | + for directory in source_include_dirs: |
| 100 | + extend_unique(include_dirs, directory) |
| 101 | + for directory in source_library_dirs: |
| 102 | + extend_unique(library_dirs, directory) |
| 103 | + for path in source_library_files: |
| 104 | + extend_unique(library_files, path) |
| 105 | + |
| 106 | + cflags = run_pkg_config("--cflags") |
| 107 | + libs = run_pkg_config("--libs") |
| 108 | + |
| 109 | + for flag in cflags: |
| 110 | + if flag.startswith("-I") and len(flag) > 2: |
| 111 | + extend_unique(include_dirs, flag[2:]) |
| 112 | + elif flag.startswith("-D") and len(flag) > 2: |
| 113 | + name_value = flag[2:].split("=", 1) |
| 114 | + define_macros.append((name_value[0], name_value[1] if len(name_value) > 1 else None)) |
| 115 | + else: |
| 116 | + extra_compile_args.append(flag) |
| 117 | + |
| 118 | + for flag in libs: |
| 119 | + if flag.startswith("-L") and len(flag) > 2: |
| 120 | + extend_unique(library_dirs, flag[2:]) |
| 121 | + elif flag.startswith("-l") and len(flag) > 2: |
| 122 | + extend_unique(libraries, flag[2:]) |
| 123 | + else: |
| 124 | + extra_link_args.append(flag) |
| 125 | + |
| 126 | + extend_env_paths(include_dirs, "PCRE2_INCLUDE_DIR") |
| 127 | + extend_env_paths(library_dirs, "PCRE2_LIBRARY_DIR") |
| 128 | + |
| 129 | + env_lib_path = os.environ.get("PCRE2_LIBRARY_PATH") |
| 130 | + if env_lib_path: |
| 131 | + for raw_path in env_lib_path.split(os.pathsep): |
| 132 | + candidate = raw_path.strip() |
| 133 | + if not candidate: |
| 134 | + continue |
| 135 | + path = Path(candidate) |
| 136 | + if path.is_file() or any(candidate.endswith(ext) for ext in LIB_EXTENSIONS): |
| 137 | + extend_unique(library_files, str(path)) |
| 138 | + parent = str(path.parent) |
| 139 | + if parent: |
| 140 | + extend_unique(library_dirs, parent) |
| 141 | + else: |
| 142 | + extend_unique(library_dirs, candidate) |
| 143 | + |
| 144 | + extend_env_paths(libraries, "PCRE2_LIBRARIES") |
| 145 | + |
| 146 | + if not library_files: |
| 147 | + for path in find_library_with_pkg_config(): |
| 148 | + extend_unique(library_files, path) |
| 149 | + |
| 150 | + if not library_files: |
| 151 | + directory_candidates = [Path(p) for p in library_dirs] |
| 152 | + directory_candidates.extend(Path(p) for p in discover_library_dirs()) |
| 153 | + for directory in directory_candidates: |
| 154 | + located = locate_library_file(directory) |
| 155 | + if located is not None: |
| 156 | + extend_unique(library_files, str(located)) |
| 157 | + break |
| 158 | + |
| 159 | + if not library_files: |
| 160 | + for path in find_library_with_ldconfig(): |
| 161 | + extend_unique(library_files, path) |
| 162 | + |
| 163 | + if not library_files: |
| 164 | + for path in find_library_with_brew(): |
| 165 | + extend_unique(library_files, path) |
| 166 | + |
| 167 | + env_cflags = os.environ.get("PCRE2_CFLAGS") |
| 168 | + if env_cflags: |
| 169 | + extra_compile_args.extend(shlex.split(env_cflags)) |
| 170 | + |
| 171 | + env_ldflags = os.environ.get("PCRE2_LDFLAGS") |
| 172 | + if env_ldflags: |
| 173 | + extra_link_args.extend(shlex.split(env_ldflags)) |
| 174 | + |
| 175 | + if not is_windows_platform() and not any(flag.startswith("-std=") for flag in extra_compile_args): |
| 176 | + extra_compile_args.append("-std=c99") |
| 177 | + |
| 178 | + if not has_header(include_dirs): |
| 179 | + include_dirs.extend(discover_include_dirs()) |
| 180 | + |
| 181 | + if not has_library(library_dirs): |
| 182 | + library_dirs.extend(discover_library_dirs()) |
| 183 | + |
| 184 | + runtime_libraries: list[str] = [] |
| 185 | + |
| 186 | + if library_files: |
| 187 | + for runtime_path in library_files: |
| 188 | + lower_name = runtime_path.lower() |
| 189 | + if lower_name.endswith(".dll") or lower_name.endswith(".dylib") or ".so" in Path(runtime_path).name: |
| 190 | + extend_unique(runtime_libraries, runtime_path) |
| 191 | + |
| 192 | + linkable_files: list[str] = [] |
| 193 | + for path in library_files: |
| 194 | + suffix = Path(path).suffix.lower() |
| 195 | + if suffix == ".dll": |
| 196 | + continue |
| 197 | + linkable_files.append(path) |
| 198 | + |
| 199 | + if linkable_files: |
| 200 | + libraries = [lib for lib in libraries if lib != "pcre2-8"] |
| 201 | + for path in linkable_files: |
| 202 | + extend_unique(extra_link_args, path) |
| 203 | + parent = str(Path(path).parent) |
| 204 | + if parent: |
| 205 | + extend_unique(library_dirs, parent) |
| 206 | + elif "pcre2-8" not in libraries: |
| 207 | + libraries.append("pcre2-8") |
| 208 | + elif "pcre2-8" not in libraries: |
| 209 | + libraries.append("pcre2-8") |
| 210 | + |
| 211 | + if sys.platform.startswith("linux") and "dl" not in libraries: |
| 212 | + libraries.append("dl") |
| 213 | + |
| 214 | + if is_windows_platform(): |
| 215 | + has_runtime_dll = any(path.lower().endswith(".dll") for path in runtime_libraries) |
| 216 | + force_static_env = is_truthy_env("PCRE2_FORCE_STATIC") |
| 217 | + if (force_static_env or (library_files and not has_runtime_dll)) and not any( |
| 218 | + macro[0] == "PCRE2_STATIC" for macro in define_macros |
| 219 | + ): |
| 220 | + define_macros.append(("PCRE2_STATIC", "1")) |
| 221 | + |
| 222 | + augment_compile_flags(extra_compile_args) |
| 223 | + |
| 224 | + RUNTIME_LIBRARY_FILES.clear() |
| 225 | + RUNTIME_LIBRARY_FILES.extend(runtime_libraries) |
| 226 | + |
| 227 | + return { |
| 228 | + "include_dirs": include_dirs, |
| 229 | + "library_dirs": library_dirs, |
| 230 | + "libraries": libraries, |
| 231 | + "extra_compile_args": extra_compile_args, |
| 232 | + "extra_link_args": extra_link_args, |
| 233 | + "define_macros": define_macros, |
| 234 | + } |
19 | 235 |
|
20 | 236 |
|
21 | 237 | EXTENSION = Extension( |
|
0 commit comments