Repository navigation
Expand file tree
/
Copy pathsetup.py
More file actions
371 lines (316 loc) · 14.1 KB
/
Copy pathsetup.py
File metadata and controls
371 lines (316 loc) · 14.1 KB
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
#!/usr/bin/env python3
"""
Cross-platform setup script for Tiny Thermal Camera Python bindings
Supports Windows, Linux (x86, ARM, MIPS), and cross-compilation
"""
from setuptools import setup, Extension, find_packages
from pybind11.setup_helpers import Pybind11Extension, build_ext
import pybind11
import subprocess
import platform
import sys
import os
import shutil
from pathlib import Path
def get_platform_info():
"""Detect platform and architecture"""
system = platform.system().lower()
machine = platform.machine().lower()
# Check for cross-compilation environment variables
cross_compile = os.environ.get('CROSS_COMPILE', '')
target_arch = os.environ.get('TARGET_ARCH', '')
if cross_compile:
return 'linux', target_arch or cross_compile.split('-')[0]
return system, machine
def get_linux_lib_path(arch, cross_compile=''):
"""Determine the correct Linux library path based on architecture"""
lib_base = "./libs/linux/"
# Map architectures to library directories
arch_map = {
# x86 architectures
'x86_64': 'x86-linux_libs',
'x86': 'x86-linux_libs',
'i686': 'x86-linux_libs',
'i386': 'x86-linux_libs',
# ARM 64-bit architectures
'aarch64': 'aarch64-linux-gnu_libs',
'arm64': 'aarch64-linux-gnu_libs',
# ARM 32-bit architectures
'armv7l': 'arm-linux-gnueabihf_libs',
'armv7': 'arm-linux-gnueabihf_libs',
'armv6l': 'arm-linux-gnueabi_libs',
'arm': 'arm-linux-gnueabi_libs',
# MIPS architectures
'mips': 'mips-linux-gnu_libs',
'mipsel': 'mips-linux-gnu_libs',
}
# Special cross-compilation targets
cross_compile_map = {
'aarch64-linux-gnu': 'aarch64-linux-gnu_libs',
'aarch64-none-linux-gnu': 'aarch64-none-linux-gnu_libs',
'aarch64-v01c01-linux-musl': 'aarch64-v01c01-linux-musl_libs',
'arm-buildroot-linux-uclibcgnueabihf': 'arm-buildroot-linux-uclibcgnueabihf_libs',
'arm-himix100-linux': 'arm-himix100-linux_libs',
'arm-himix200-linux': 'arm-himix200-linux_libs',
'arm-hisiv300-linux-uclibcgnueabi': 'arm-hisiv300-linux-uclibcgnueabi_libs',
'arm-hisiv500-linux-uclibcgnueabi': 'arm-hisiv500-linux-uclibcgnueabi_libs',
'arm-linux-gnueabi': 'arm-linux-gnueabi_libs',
'arm-linux-gnueabihf': 'arm-linux-gnueabihf_libs',
'mips-linux-gnu': 'mips-linux-gnu_libs',
}
# Check for specific cross-compilation target
if cross_compile and cross_compile in cross_compile_map:
return lib_base + cross_compile_map[cross_compile]
# Fallback to architecture mapping
lib_dir = arch_map.get(arch, 'x86-linux_libs')
lib_path = lib_base + lib_dir
# Verify the path exists
if not os.path.exists(lib_path):
print(f"Warning: Library path {lib_path} not found, defaulting to x86-linux_libs")
lib_path = lib_base + "x86-linux_libs"
return lib_path
def get_opencv_flags(system):
"""Get OpenCV compiler and linker flags for the platform"""
# First check if local OpenCV headers exist
local_opencv = "./libir_sample"
if os.path.exists(local_opencv):
print(f"Using local OpenCV headers from {local_opencv}")
# Just return the include path, no libraries needed for basic functionality
return [local_opencv], []
if system == 'windows':
# Windows OpenCV paths (adjust as needed)
opencv_include = os.environ.get('OPENCV_INCLUDE', './libir_sample')
opencv_lib = os.environ.get('OPENCV_LIB', '')
# Check if OpenCV library is specified and exists
if opencv_lib:
opencv_lib_file = os.path.join(opencv_lib, 'opencv_world.lib')
if os.path.exists(opencv_lib_file):
return [opencv_include], [opencv_lib_file]
# Just use headers without linking to OpenCV libs
print(f"Using OpenCV headers only from {opencv_include}")
return [opencv_include], []
else:
# Linux/Unix - use pkg-config
try:
cflags = subprocess.check_output(['pkg-config', 'opencv4', '--cflags']).decode('utf-8').strip().split()
libs = subprocess.check_output(['pkg-config', 'opencv4', '--libs']).decode('utf-8').strip().split()
return cflags, libs
except:
# Fallback to local headers
print(f"Warning: OpenCV not found via pkg-config, using local headers from {local_opencv}")
return [local_opencv], []
def create_extension(system, arch):
"""Create platform-specific extension configuration"""
opencv_cflags, opencv_libs = get_opencv_flags(system)
cross_compile = os.environ.get('CROSS_COMPILE', '')
# Base configuration
include_dirs = [
pybind11.get_include(),
"./include",
"./libs/include", # Additional include path
".",
]
libraries = []
extra_objects = []
extra_compile_args = []
extra_link_args = []
define_macros = [("IMAGE_AND_TEMP_OUTPUT", None)]
if system == 'windows':
# Windows configuration - detect architecture
import platform
is_64bit = platform.machine().endswith('64')
if is_64bit:
# Use x64 DLLs from FalconApplication
lib_path = os.path.abspath("./libs/win/x64/dll")
# Check if we have the x64 DLLs and import libraries
if os.path.exists(lib_path):
# Use import libraries for linking
lib_files = ["libiruvc.lib", "libirtemp.lib", "libirprocess.lib", "libirparse.lib"]
for lib_file in lib_files:
lib_file_path = os.path.join(lib_path, lib_file)
if os.path.exists(lib_file_path):
extra_objects.append(lib_file_path)
else:
print(f"Warning: {lib_file} not found")
print(f"Using 64-bit DLLs and import libraries from {lib_path}")
else:
print("Warning: x64 DLLs not found, build may fail")
else:
# Use Win32 libraries for 32-bit Python
lib_base_path = "./libs/win/Win32/"
use_dll = os.environ.get('USE_DLL', '1') == '1'
if use_dll:
lib_path = os.path.abspath(lib_base_path + "dll")
extra_objects.extend([
os.path.join(lib_path, "libiruvc.lib"),
os.path.join(lib_path, "libirtemp.lib"),
os.path.join(lib_path, "libirprocess.lib"),
os.path.join(lib_path, "libirparse.lib"),
])
else:
lib_path = os.path.abspath(lib_base_path + "lib")
extra_objects.extend([
os.path.join(lib_path, "libiruvc.lib"),
os.path.join(lib_path, "libirtemp.lib"),
os.path.join(lib_path, "libirprocess.lib"),
os.path.join(lib_path, "libirparse.lib"),
])
# Windows system libraries
libraries.extend(['ws2_32', 'winusb', 'setupapi'])
define_macros.append(("WIN32", None))
define_macros.append(("_WINDOWS", None))
# MSVC compiler flags
extra_compile_args.extend(['/O2', '/MD'])
else: # Linux/Unix
lib_path = get_linux_lib_path(arch, cross_compile)
# Check if we should use shared or static libraries
use_shared = os.environ.get('USE_SHARED', '0') == '1'
if use_shared:
# Use shared libraries
libraries.extend(['iruvc', 'irtemp', 'irprocess', 'irparse'])
extra_link_args.extend([f'-L{os.path.abspath(lib_path)}', f'-Wl,-rpath,$ORIGIN/{lib_path}'])
else:
# Use static libraries (default)
lib_files = ['libiruvc', 'libirtemp', 'libirprocess', 'libirparse']
# Check for MIPS (limited libraries)
if 'mips' in lib_path:
lib_files = ['libirtemp', 'libirprocess', 'libirparse'] # No libiruvc for MIPS
for lib in lib_files:
lib_file = f"{lib_path}/{lib}.a"
if os.path.exists(lib_file):
extra_objects.append(lib_file)
else:
print(f"Warning: {lib_file} not found")
# Linux system libraries
libraries.extend(['usb-1.0', 'pthread', 'm'])
define_macros.append(("linux", None))
# GCC compiler flags
extra_compile_args.extend(['-O3', '-Wall', '-fPIC'])
# Add cross-compilation flags if needed
if cross_compile:
extra_compile_args.append(f'--target={cross_compile}')
extra_link_args.append(f'--target={cross_compile}')
# Add OpenCV flags
if system == 'windows':
# For Windows, opencv_cflags is just a list with the include path
include_dirs.extend(opencv_cflags)
# opencv_libs contains the .lib file path
extra_objects.extend(opencv_libs)
else:
# For Linux, parse the flags properly
include_dirs.extend([flag[2:] for flag in opencv_cflags if flag.startswith('-I')])
extra_compile_args.extend([flag for flag in opencv_cflags if not flag.startswith('-I')])
extra_link_args.extend(opencv_libs)
# Create extension
return Pybind11Extension(
"tiny_thermal_camera",
sources=["python_bindings_tiny.cpp"],
include_dirs=include_dirs,
libraries=libraries,
extra_objects=extra_objects,
language='c++',
cxx_std=11,
define_macros=define_macros,
extra_compile_args=extra_compile_args,
extra_link_args=extra_link_args,
)
def prepare_dll_package():
"""Prepare DLL package for Windows"""
if platform.system().lower() != 'windows':
return []
# Check if DLL directory already exists (development setup already done)
package_dir = Path("src/tiny_thermal_camera")
dlls_dir = package_dir / "dlls"
if dlls_dir.exists() and list(dlls_dir.glob("*.dll")):
print("DLL package already prepared (using existing dlls/)")
return ["tiny_thermal_camera"]
print("Preparing DLL package for Windows...")
# Run the DLL collection script
try:
import subprocess
result = subprocess.run([sys.executable, 'scripts/setup_dll_collection.py'],
capture_output=True, text=True)
if result.returncode != 0:
print(f"Warning: DLL collection failed: {result.stderr}")
return []
except Exception as e:
print(f"Warning: Could not run DLL collection: {e}")
return []
# Check if src/tiny_thermal_camera package was updated
if package_dir.exists():
print("DLL package prepared successfully")
return ["tiny_thermal_camera"]
else:
print("Warning: DLL package not found")
return []
def main():
"""Main setup function"""
# Detect platform
system, arch = get_platform_info()
cross_compile = os.environ.get('CROSS_COMPILE', '')
print(f"Building for: {system} / {arch}")
if cross_compile:
print(f"Cross-compiling for: {cross_compile}")
# Prepare DLL package for Windows (if needed)
prepare_dll_package()
# Find packages in src directory
packages = find_packages(where="src")
package_dir = {"": "src"}
# Create extension module
ext_modules = [create_extension(system, arch)]
# Package data for DLL inclusion
package_data = {}
if packages and "tiny_thermal_camera" in packages:
package_data["tiny_thermal_camera"] = ["dlls/*.dll", "libs/*.lib"]
# Run setup
setup(
name="tiny-thermal-camera",
version="1.0.0",
author="Thermal Camera Python Bindings",
author_email="mail@matbee.com",
description="Cross-platform Python bindings for P2/Tiny1C thermal camera SDK",
long_description="""
Cross-platform Python bindings for the AC010_256 thermal camera SDK.
Supports P2/Tiny1C thermal cameras on Windows, Linux (x86, ARM, MIPS).
Features:
- Cross-platform support (Windows, Linux)
- Multiple architecture support (x86, ARM, MIPS)
- Camera control (open/close, start/stop streaming)
- Raw frame acquisition and temperature processing
- NumPy array integration
- Automatic DLL management on Windows
""",
packages=packages,
package_dir=package_dir,
package_data=package_data,
include_package_data=True,
ext_modules=ext_modules,
cmdclass={"build_ext": build_ext},
zip_safe=False,
python_requires=">=3.6",
install_requires=[
"numpy>=1.15.0",
"pybind11>=2.6.0",
],
extras_require={
"test": ["pytest>=6.0"],
"visualization": ["opencv-python>=4.0.0", "matplotlib>=3.0.0"],
},
classifiers=[
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
"Topic :: Scientific/Engineering",
"Topic :: Software Development :: Libraries :: Python Modules",
],
)
if __name__ == "__main__":
main()