bioforge 2.3.0__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bioforge-2.3.0.data/purelib/bioforge/__init__.py +74 -0
- bioforge-2.3.0.data/purelib/bioforge/aligner.py +953 -0
- bioforge-2.3.0.data/purelib/bioforge/analyze.py +385 -0
- bioforge-2.3.0.data/purelib/bioforge/bgzf.py +119 -0
- bioforge-2.3.0.data/purelib/bioforge/biocore.py +2092 -0
- bioforge-2.3.0.data/purelib/bioforge/engine/__init__.py +1 -0
- bioforge-2.3.0.data/purelib/bioforge/engine/_loader.py +543 -0
- bioforge-2.3.0.data/purelib/bioforge/engine/build.py +231 -0
- bioforge-2.3.0.data/purelib/bioforge/engine/engine.c +1538 -0
- bioforge-2.3.0.data/purelib/bioforge/engine/engine.dll +0 -0
- bioforge-2.3.0.data/purelib/bioforge/qcreport.py +298 -0
- bioforge-2.3.0.data/purelib/bioforge/smart_translator.py +601 -0
- bioforge-2.3.0.dist-info/METADATA +736 -0
- bioforge-2.3.0.dist-info/RECORD +18 -0
- bioforge-2.3.0.dist-info/WHEEL +5 -0
- bioforge-2.3.0.dist-info/entry_points.txt +4 -0
- bioforge-2.3.0.dist-info/licenses/LICENSE +280 -0
- bioforge-2.3.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"""
|
|
2
|
+
engine/build.py — Compila el motor C a DLL/SO (Windows / Linux / macOS).
|
|
3
|
+
|
|
4
|
+
Uso:
|
|
5
|
+
python engine/build.py
|
|
6
|
+
|
|
7
|
+
Detecta el compilador automáticamente (GCC, incluida la ubicación típica de
|
|
8
|
+
MSYS2 en Windows; clang en macOS) e intenta enlazar zlib (.gz) y libdeflate
|
|
9
|
+
(.gz ~2× más rápido). Cada dependencia degrada con gracia si no está.
|
|
10
|
+
|
|
11
|
+
Variables de entorno
|
|
12
|
+
────────────────────
|
|
13
|
+
BIOFORGE_PORTABLE=1 Compila para CPU genérica (sin `-march=native`).
|
|
14
|
+
OBLIGATORIO al construir wheels distribuidos.
|
|
15
|
+
BIOFORGE_STATIC=1 Enlace AUTOCONTENIDO para wheels: en Linux/macOS enlaza
|
|
16
|
+
OpenMP (libgomp/libomp) de forma estática para que el
|
|
17
|
+
.so no dependa de librerías fuera de la lista blanca de
|
|
18
|
+
manylinux. Así el paso "repair" (auditwheel/delocate)
|
|
19
|
+
sobra y se puede saltar. zlib se deja dinámico (está en
|
|
20
|
+
la lista blanca / es del sistema en macOS).
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import os
|
|
24
|
+
import shutil
|
|
25
|
+
import subprocess
|
|
26
|
+
import sys
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
|
|
29
|
+
ENGINE_DIR = Path(__file__).parent
|
|
30
|
+
SRC = ENGINE_DIR / "engine.c"
|
|
31
|
+
|
|
32
|
+
# Ubicaciones habituales de GCC en Windows (MSYS2) si no está en el PATH.
|
|
33
|
+
_WIN_GCC_CANDIDATES = [
|
|
34
|
+
r"C:\msys64\mingw64\bin\gcc.exe",
|
|
35
|
+
r"C:\msys64\ucrt64\bin\gcc.exe",
|
|
36
|
+
r"C:\mingw64\bin\gcc.exe",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _flag(name: str) -> bool:
|
|
41
|
+
return os.environ.get(name, "") not in ("", "0", "false")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _find_compiler() -> str | None:
|
|
45
|
+
"""GCC en Windows/Linux; clang (o gcc) en macOS."""
|
|
46
|
+
if sys.platform == "darwin":
|
|
47
|
+
return shutil.which("clang") or shutil.which("gcc")
|
|
48
|
+
found = shutil.which("gcc")
|
|
49
|
+
if found:
|
|
50
|
+
return found
|
|
51
|
+
if sys.platform == "win32":
|
|
52
|
+
for cand in _WIN_GCC_CANDIDATES:
|
|
53
|
+
if Path(cand).exists():
|
|
54
|
+
return cand
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _brew_prefix(pkg: str) -> str | None:
|
|
59
|
+
"""Prefijo de instalación de un paquete Homebrew (macOS), o None."""
|
|
60
|
+
try:
|
|
61
|
+
res = subprocess.run(["brew", "--prefix", pkg],
|
|
62
|
+
capture_output=True, text=True)
|
|
63
|
+
if res.returncode == 0:
|
|
64
|
+
p = res.stdout.strip()
|
|
65
|
+
return p if p and Path(p).exists() else None
|
|
66
|
+
except FileNotFoundError:
|
|
67
|
+
pass
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _run(cmd: list[str]) -> subprocess.CompletedProcess:
|
|
72
|
+
env = os.environ.copy()
|
|
73
|
+
cc = cmd[0]
|
|
74
|
+
if sys.platform == "win32" and cc.lower().endswith("gcc.exe"):
|
|
75
|
+
env["PATH"] = str(Path(cc).parent) + os.pathsep + env.get("PATH", "")
|
|
76
|
+
return subprocess.run(cmd, capture_output=True, text=True, env=env)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _arch() -> list[str]:
|
|
80
|
+
# Nativa para uso local (máxima velocidad), genérica para wheels.
|
|
81
|
+
return ["-O3"] if _flag("BIOFORGE_PORTABLE") else ["-O3", "-march=native"]
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
85
|
+
# Ruta AUTOCONTENIDA para wheels (Linux/macOS): compilar + enlazar en dos pasos,
|
|
86
|
+
# con OpenMP estático. Devuelve True si produjo engine.so.
|
|
87
|
+
# ──────────────────────────────────────────────────────────────────────────────
|
|
88
|
+
def _build_static_unix(cc: str) -> bool:
|
|
89
|
+
out = ENGINE_DIR / "engine.so"
|
|
90
|
+
obj = ENGINE_DIR / "engine.o"
|
|
91
|
+
is_mac = sys.platform == "darwin"
|
|
92
|
+
arch = _arch()
|
|
93
|
+
|
|
94
|
+
# ── Paso 1: compilar a objeto (pragmas OpenMP activos) ──────────────────────
|
|
95
|
+
cflags = [cc, "-c", *arch, "-fPIC", "-DBIO_USE_ZLIB"]
|
|
96
|
+
libomp = None
|
|
97
|
+
if is_mac:
|
|
98
|
+
libomp = _brew_prefix("libomp")
|
|
99
|
+
if libomp:
|
|
100
|
+
cflags += ["-Xpreprocessor", "-fopenmp", f"-I{libomp}/include"]
|
|
101
|
+
else:
|
|
102
|
+
print("[aviso] libomp no encontrado; motor sin parseo paralelo.")
|
|
103
|
+
else:
|
|
104
|
+
cflags += ["-fopenmp"]
|
|
105
|
+
cflags += ["-o", str(obj), str(SRC)]
|
|
106
|
+
|
|
107
|
+
print("Compilando engine.c -> engine.o (objeto) ...")
|
|
108
|
+
res = _run(cflags)
|
|
109
|
+
if res.returncode != 0:
|
|
110
|
+
# Reintentar sin zlib (p.ej. faltan cabeceras de zlib).
|
|
111
|
+
cflags = [c for c in cflags if c != "-DBIO_USE_ZLIB"]
|
|
112
|
+
res = _run(cflags)
|
|
113
|
+
if res.returncode != 0:
|
|
114
|
+
print("[ERROR] No se pudo compilar el objeto:")
|
|
115
|
+
print(res.stderr)
|
|
116
|
+
return False
|
|
117
|
+
zlib_on = False
|
|
118
|
+
else:
|
|
119
|
+
zlib_on = True
|
|
120
|
+
|
|
121
|
+
# ── Paso 2: enlazar a .so autocontenido (OpenMP estático) ───────────────────
|
|
122
|
+
link = [cc, "-shared", "-o", str(out), str(obj)]
|
|
123
|
+
if is_mac:
|
|
124
|
+
if libomp:
|
|
125
|
+
link += [f"{libomp}/lib/libomp.a"] # OpenMP estático (full path)
|
|
126
|
+
if zlib_on:
|
|
127
|
+
link += ["-lz"] # zlib del sistema (dinámico)
|
|
128
|
+
else:
|
|
129
|
+
link += ["-static-libgcc"]
|
|
130
|
+
# libgomp ESTÁTICO (no está en la lista blanca de manylinux);
|
|
131
|
+
# zlib y pthread DINÁMICOS (sí están en la lista blanca).
|
|
132
|
+
link += ["-Wl,--whole-archive", "-l:libgomp.a", "-Wl,--no-whole-archive"]
|
|
133
|
+
if zlib_on:
|
|
134
|
+
link += ["-lz"]
|
|
135
|
+
link += ["-lpthread", "-lm", "-ldl"]
|
|
136
|
+
|
|
137
|
+
print("Enlazando engine.o -> engine.so (OpenMP estático) ...")
|
|
138
|
+
res = _run(link)
|
|
139
|
+
if res.returncode != 0 and not is_mac:
|
|
140
|
+
# Fallback: libgomp dinámico (wheel funcionará donde haya libgomp.so.1).
|
|
141
|
+
print("[aviso] Enlace estático de OpenMP falló; probando dinámico.")
|
|
142
|
+
link = [cc, "-shared", "-o", str(out), str(obj), "-fopenmp"]
|
|
143
|
+
if zlib_on:
|
|
144
|
+
link += ["-lz"]
|
|
145
|
+
res = _run(link)
|
|
146
|
+
|
|
147
|
+
try:
|
|
148
|
+
obj.unlink()
|
|
149
|
+
except OSError:
|
|
150
|
+
pass
|
|
151
|
+
|
|
152
|
+
if res.returncode == 0 and out.exists():
|
|
153
|
+
size_kb = out.stat().st_size // 1024
|
|
154
|
+
omp = "con" if (is_mac and libomp) or not is_mac else "sin"
|
|
155
|
+
gz = "con" if zlib_on else "sin"
|
|
156
|
+
print(f"[OK] Motor autocontenido: {out} ({size_kb} KB) "
|
|
157
|
+
f"[{omp} OpenMP · {gz} .gz]")
|
|
158
|
+
return True
|
|
159
|
+
|
|
160
|
+
print("[ERROR] Error de enlace:")
|
|
161
|
+
print(res.stderr)
|
|
162
|
+
return False
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def build() -> bool:
|
|
166
|
+
cc = _find_compiler()
|
|
167
|
+
if not cc:
|
|
168
|
+
print("[ERROR] No se encontró compilador. Instala MinGW-w64 (Windows), "
|
|
169
|
+
"gcc (Linux) o Xcode/clang (macOS) y vuelve a intentarlo.")
|
|
170
|
+
return False
|
|
171
|
+
|
|
172
|
+
# Wheels distribuidos en Linux/macOS → ruta autocontenida (OpenMP estático).
|
|
173
|
+
if _flag("BIOFORGE_STATIC") and sys.platform != "win32":
|
|
174
|
+
return _build_static_unix(cc)
|
|
175
|
+
|
|
176
|
+
arch = _arch()
|
|
177
|
+
omp = ["-fopenmp"]
|
|
178
|
+
|
|
179
|
+
if sys.platform == "win32":
|
|
180
|
+
out = ENGINE_DIR / "engine.dll"
|
|
181
|
+
# -static enlaza libgomp, libgcc y winpthread DENTRO del DLL.
|
|
182
|
+
base = [cc, *arch, *omp, "-shared", "-static"]
|
|
183
|
+
zlib_link = ["-l:libz.a"]
|
|
184
|
+
deflate_link = ["-l:libdeflate.a"]
|
|
185
|
+
elif sys.platform == "darwin":
|
|
186
|
+
out = ENGINE_DIR / "engine.so"
|
|
187
|
+
libomp = _brew_prefix("libomp")
|
|
188
|
+
extra_inc: list[str] = []
|
|
189
|
+
extra_lib: list[str] = []
|
|
190
|
+
if libomp:
|
|
191
|
+
omp = ["-Xpreprocessor", "-fopenmp"]
|
|
192
|
+
extra_inc += [f"-I{libomp}/include"]
|
|
193
|
+
extra_lib += [f"-L{libomp}/lib", "-lomp"]
|
|
194
|
+
else:
|
|
195
|
+
omp = []
|
|
196
|
+
base = [cc, *arch, *omp, "-shared", "-fPIC", *extra_inc, *extra_lib]
|
|
197
|
+
zlib_link = ["-lz"]
|
|
198
|
+
deflate_link = ["-ldeflate"]
|
|
199
|
+
else: # Linux (uso local, no-wheel)
|
|
200
|
+
out = ENGINE_DIR / "engine.so"
|
|
201
|
+
base = [cc, *arch, *omp, "-shared", "-fPIC"]
|
|
202
|
+
zlib_link = ["-lz"]
|
|
203
|
+
deflate_link = ["-ldeflate"]
|
|
204
|
+
|
|
205
|
+
common = base + ["-o", str(out), str(SRC)]
|
|
206
|
+
attempts = [
|
|
207
|
+
("CON .gz + libdeflate (rápido)",
|
|
208
|
+
["-DBIO_USE_ZLIB", "-DBIO_USE_LIBDEFLATE"] + zlib_link + deflate_link),
|
|
209
|
+
("CON .gz (zlib)", ["-DBIO_USE_ZLIB"] + zlib_link),
|
|
210
|
+
("SIN soporte .gz", []),
|
|
211
|
+
]
|
|
212
|
+
|
|
213
|
+
mode = "portátil/genérica" if _flag("BIOFORGE_PORTABLE") else "nativa (-march=native)"
|
|
214
|
+
print(f"Compilando {SRC.name} -> {out.name} [arquitectura {mode}] ...")
|
|
215
|
+
last = None
|
|
216
|
+
for label, link in attempts:
|
|
217
|
+
res = _run(common + link)
|
|
218
|
+
last = res
|
|
219
|
+
if res.returncode == 0:
|
|
220
|
+
size_kb = out.stat().st_size // 1024
|
|
221
|
+
print(f"[OK] Motor compilado [{label}]: {out} ({size_kb} KB)")
|
|
222
|
+
return True
|
|
223
|
+
print(f"[aviso] No se pudo compilar [{label}]; probando alternativa.")
|
|
224
|
+
|
|
225
|
+
print("[ERROR] Error de compilacion:")
|
|
226
|
+
print(last.stderr if last else "(sin salida)")
|
|
227
|
+
return False
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
if __name__ == "__main__":
|
|
231
|
+
sys.exit(0 if build() else 1)
|