|
74 | 74 | excinfo_t, |
75 | 75 | CPUCallConv, |
76 | 76 | ) |
77 | | -from functools import cached_property |
| 77 | +from functools import cached_property, lru_cache |
78 | 78 | from numba.core.datamodel.registry import register_default as model_register |
79 | 79 | from numba.core.datamodel.registry import default_manager as model_manager |
80 | 80 | from numba.core.datamodel.models import OpaqueModel |
|
113 | 113 |
|
114 | 114 |
|
115 | 115 | def link_shared_library(obj_path, out_path): |
| 116 | + # Generate trampolines for numba/NRT symbols. We use trampolines to link the |
| 117 | + # absolute symbol addresses from numba to the self-contained shared library |
| 118 | + # for the OpenMP target CPU module. |
| 119 | + # TODO: ask numba upstream to provide a static library with these symbols. |
| 120 | + @lru_cache |
| 121 | + def generate_trampolines(): |
| 122 | + from numba import _helperlib |
| 123 | + from numba.core.runtime import _nrt_python as _nrt |
| 124 | + |
| 125 | + # Signature mapping for numba/NRT functions. Add more as needed. |
| 126 | + SIGNATURES = { |
| 127 | + # GIL management |
| 128 | + "numba_gil_ensure": ("void", []), |
| 129 | + "numba_gil_release": ("void", []), |
| 130 | + # Memory allocation |
| 131 | + "NRT_MemInfo_alloc": ("void*", ["size_t"]), |
| 132 | + "NRT_MemInfo_alloc_safe": ("void*", ["size_t"]), |
| 133 | + "NRT_MemInfo_alloc_aligned": ("void*", ["size_t", "size_t"]), |
| 134 | + "NRT_MemInfo_alloc_safe_aligned": ("void*", ["size_t", "size_t"]), |
| 135 | + "NRT_MemInfo_free": ("void", ["void*"]), |
| 136 | + } |
| 137 | + |
| 138 | + trampoline_c = """#include <stddef.h>""" |
| 139 | + |
| 140 | + symbols = [] |
| 141 | + # Process _helperlib symbols |
| 142 | + for py_name in _helperlib.c_helpers: |
| 143 | + c_name = "numba_" + py_name |
| 144 | + c_address = _helperlib.c_helpers[py_name] |
| 145 | + |
| 146 | + if c_name in SIGNATURES: |
| 147 | + ret_type, params = SIGNATURES[c_name] |
| 148 | + symbols.append((c_name, c_address, ret_type, params)) |
| 149 | + |
| 150 | + # Process _nrt symbols |
| 151 | + for py_name in _nrt.c_helpers: |
| 152 | + if py_name.startswith("_"): |
| 153 | + c_name = py_name |
| 154 | + else: |
| 155 | + c_name = "NRT_" + py_name |
| 156 | + c_address = _nrt.c_helpers[py_name] |
| 157 | + |
| 158 | + if c_name in SIGNATURES: |
| 159 | + ret_type, params = SIGNATURES[c_name] |
| 160 | + symbols.append((c_name, c_address, ret_type, params)) |
| 161 | + |
| 162 | + # Generate trampolines |
| 163 | + for c_name, c_address, ret_type, params in sorted(symbols): |
| 164 | + # Build parameter list |
| 165 | + if not params: |
| 166 | + param_list = "void" |
| 167 | + arg_list = "" |
| 168 | + else: |
| 169 | + param_list = ", ".join( |
| 170 | + f"{ptype} arg{i}" for i, ptype in enumerate(params) |
| 171 | + ) |
| 172 | + arg_list = ", ".join(f"arg{i}" for i in range(len(params))) |
| 173 | + |
| 174 | + # Build function pointer type |
| 175 | + func_ptr_type = f"{ret_type} (*)({', '.join(params) if params else 'void'})" |
| 176 | + |
| 177 | + # Generate the trampoline |
| 178 | + trampoline_c += f""" |
| 179 | + __attribute__((visibility("default"))) |
| 180 | + {ret_type} {c_name}({param_list}) {{ |
| 181 | + {"" if ret_type == "void" else "return "}(({func_ptr_type})0x{c_address:x})({arg_list}); |
| 182 | + }} |
| 183 | + """ |
| 184 | + |
| 185 | + return trampoline_c |
| 186 | + |
116 | 187 | """ |
117 | 188 | Produce a shared library from a single object file and link numba C symbols. |
118 | 189 | Uses distutils' compiler. |
119 | 190 | """ |
120 | 191 | obj_path = str(Path(obj_path)) |
121 | 192 | out_path = str(Path(out_path)) |
122 | 193 |
|
123 | | - from numba import _helperlib |
124 | | - from numba.core.runtime import _nrt_python as _nrt |
125 | | - |
126 | | - # Prepare list of Numba C symbols to link against. |
127 | | - symbols = [] |
128 | | - for py_name in _helperlib.c_helpers: |
129 | | - c_name = "numba_" + py_name |
130 | | - c_address = _helperlib.c_helpers[py_name] |
131 | | - symbols.append(f"-Wl,--defsym={c_name}=0x{c_address:x}") |
132 | | - |
133 | | - for py_name in _nrt.c_helpers: |
134 | | - if py_name.startswith("_"): |
135 | | - # internal API |
136 | | - c_name = py_name |
137 | | - else: |
138 | | - c_name = "NRT_" + py_name |
139 | | - c_address = _nrt.c_helpers[py_name] |
140 | | - symbols.append(f"-Wl,--defsym={c_name}=0x{c_address:x}") |
| 194 | + trampoline_code = generate_trampolines() |
| 195 | + fd, trampoline_c = tempfile.mkstemp(".c") |
| 196 | + os.close(fd) |
| 197 | + with open(trampoline_c, "w") as f: |
| 198 | + f.write(trampoline_code) |
141 | 199 |
|
142 | 200 | cc = ccompiler.new_compiler() |
143 | 201 | sysconfig.customize_compiler(cc) |
144 | | - |
145 | 202 | extra_pre = [] |
146 | 203 | extra_post = [] |
147 | 204 |
|
148 | | - if sys.platform.startswith("linux") or sys.platform.startswith("freebsd"): |
149 | | - # Add numba symbols to the link. |
150 | | - extra_post += symbols |
151 | | - elif sys.platform == "darwin": |
152 | | - raise NotImplementedError("link_shared_library not implemented on Windows") |
153 | | - elif os.name == "nt": |
154 | | - raise NotImplementedError("link_shared_library not implemented on Windows") |
155 | | - else: |
156 | | - raise RuntimeError(f"Unsupported platform: {sys.platform}") |
| 205 | + try: |
| 206 | + trampoline_o = cc.compile([trampoline_c]) |
| 207 | + except Exception as e: |
| 208 | + raise RuntimeError( |
| 209 | + f"Compilation failed for trampolines in {trampoline_c}" |
| 210 | + ) from e |
| 211 | + finally: |
| 212 | + os.remove(trampoline_c) |
157 | 213 |
|
| 214 | + objs = [obj_path] + trampoline_o |
158 | 215 | try: |
159 | 216 | cc.link_shared_object( |
160 | | - objects=[obj_path], |
| 217 | + objects=objs, |
161 | 218 | output_filename=out_path, |
162 | 219 | extra_preargs=extra_pre, |
163 | 220 | extra_postargs=extra_post, |
164 | 221 | ) |
165 | 222 | except Exception as e: |
166 | 223 | raise RuntimeError(f"Link failed for {out_path}") from e |
| 224 | + finally: |
| 225 | + for file_o in trampoline_o: |
| 226 | + os.remove(file_o) |
167 | 227 |
|
168 | 228 |
|
169 | 229 | ### |
|
0 commit comments