-
Notifications
You must be signed in to change notification settings - Fork 5
/
build.py
170 lines (135 loc) · 4.58 KB
/
build.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
import os
from pathlib import Path
import shutil
from struct import unpack
import subprocess
from typing import List, Any
PACKAGE_DIR = Path(__file__).parent / "openjpeg"
LIB_DIR = Path(__file__).parent / "lib"
BUILD_TOOLS = Path(__file__).parent / "build_tools"
OPENJPEG_SRC = LIB_DIR / "openjpeg" / "src" / "lib" / "openjp2"
INTERFACE_SRC = LIB_DIR / "interface"
BUILD_DIR = LIB_DIR / "openjpeg" / "build"
BACKUP_DIR = BUILD_TOOLS / "backup"
def build(setup_kwargs: Any) -> Any:
from setuptools import Extension
from setuptools.dist import Distribution
import Cython.Compiler.Options
from Cython.Build import build_ext, cythonize
import numpy
setup_oj()
# Determine if system is big endian or not
macros = [("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")]
if unpack("h", b"\x00\x01")[0] == 1:
macros.append(("PYOJ_BIG_ENDIAN", None))
ext = Extension(
"_openjpeg",
[os.fspath(p) for p in get_source_files()],
language="c",
include_dirs=[
os.fspath(OPENJPEG_SRC),
os.fspath(INTERFACE_SRC),
numpy.get_include(),
],
extra_compile_args=[],
extra_link_args=[],
define_macros=macros,
)
ext_modules = cythonize(
[ext],
include_path=ext.include_dirs,
language_level=3,
)
dist = Distribution({"ext_modules": ext_modules})
cmd = build_ext(dist)
cmd.ensure_finalized()
cmd.run()
for output in cmd.get_outputs():
output = Path(output)
relative_ext = output.relative_to(cmd.build_lib)
shutil.copyfile(output, relative_ext)
reset_oj()
return setup_kwargs
def get_source_files() -> List[Path]:
"""Return a list of paths to the source files to be compiled."""
source_files = [
INTERFACE_SRC / "decode.c",
INTERFACE_SRC / "encode.c",
INTERFACE_SRC / "color.c",
INTERFACE_SRC / "utils.c",
]
for fname in OPENJPEG_SRC.glob("*"):
if fname.parts[-1].startswith("test"):
continue
if fname.parts[-1].startswith("bench"):
continue
if fname.suffix == ".c":
source_files.append(fname)
source_files = [p.relative_to(Path(__file__).parent) for p in source_files]
source_files.insert(0, PACKAGE_DIR / "_openjpeg.pyx")
return source_files
def setup_oj() -> None:
"""Run custom cmake."""
base_dir = LIB_DIR / "openjpeg"
p_openjpeg = base_dir / "src" / "lib" / "openjp2" / "openjpeg.c"
# Backup original CMakeLists.txt and openjpeg.c files
if os.path.exists(BACKUP_DIR):
shutil.rmtree(BACKUP_DIR)
BACKUP_DIR.mkdir(exist_ok=True, parents=True)
shutil.copy(
LIB_DIR / "openjpeg" / "CMakeLists.txt",
BACKUP_DIR / "CMakeLists.txt.backup",
)
shutil.copy(
OPENJPEG_SRC / "openjpeg.c",
BACKUP_DIR / "openjpeg.c.backup",
)
# Copy custom CMakeLists.txt file to openjpeg base dir
shutil.copy(
BUILD_TOOLS / "cmake" / "CMakeLists.txt",
LIB_DIR / "openjpeg" / "CMakeLists.txt",
)
# Edit openjpeg.c to remove the OPJ_API declaration
with p_openjpeg.open("r") as f:
data = f.readlines()
data = [
line.replace("OPJ_API ", "")
if line.startswith("OPJ_API ") else line for line in data
]
with p_openjpeg.open("w") as f:
f.write("".join(data))
if os.path.exists(BUILD_DIR):
shutil.rmtree(BUILD_DIR)
try:
os.remove(INTERFACE_SRC / "opj_config.h")
os.remove(INTERFACE_SRC / "opj_config_private.h")
except:
pass
os.mkdir(BUILD_DIR)
cur_dir = os.getcwd()
os.chdir(BUILD_DIR)
subprocess.call(['cmake', os.fspath((LIB_DIR / "openjpeg").resolve(strict=True))])
os.chdir(cur_dir)
# Turn off JPIP
if os.path.exists(INTERFACE_SRC / "opj_config.h"):
with open(INTERFACE_SRC / "opj_config.h", "a") as f:
f.write("\n")
f.write("#define USE_JPIP 0")
def reset_oj() -> None:
# Restore submodule to original state
# Restore CMakeLists.txt and openjpeg.c files
if (BACKUP_DIR / "CMakeLists.txt.backup").exists():
shutil.copy(
BACKUP_DIR / "CMakeLists.txt.backup",
LIB_DIR / "openjpeg" / "CMakeLists.txt",
)
if (BACKUP_DIR / "openjpeg.c.backup").exists():
shutil.copy(
BACKUP_DIR / "openjpeg.c.backup",
OPENJPEG_SRC / "openjpeg.c",
)
# Cleanup added directories
if os.path.exists(BUILD_DIR):
shutil.rmtree(BUILD_DIR)
if os.path.exists(BACKUP_DIR):
shutil.rmtree(BACKUP_DIR)