Accumulated uncommitted work: GHOST Web backend, WebGL/GPU web layer, web workflow engine and protocol, tooling, docs and task records. Large generated evidence, user-testing archives, build snapshots and imported test assets remain untracked. Co-Authored-By: Claude Code <noreply@anthropic.com>
75 lines
5.8 KiB
Python
75 lines
5.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Build pinned native image codecs and OpenImageIO for Blender WASM."""
|
|
import hashlib, re, subprocess, sys, tarfile, urllib.request
|
|
from pathlib import Path
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
BASE = ROOT / 'build_web_oiio'
|
|
PREFIX = BASE / 'install'
|
|
VERSIONS = (ROOT / 'blender-5.2.0/build_files/build_environment/cmake/versions.cmake').read_text()
|
|
def value(key):
|
|
return re.search(r'set\(' + key + r' ([^)]+)\)', VERSIONS)[1]
|
|
def source(name):
|
|
version = value(name + '_VERSION')
|
|
filename = value(name + '_FILE').replace('${' + name + '_VERSION}', version)
|
|
url = value(name + '_URI').replace('${' + name + '_VERSION}', version).replace('http:', 'https:')
|
|
expected, algorithm = value(name+'_HASH'), value(name+'_HASH_TYPE').lower()
|
|
if name == 'PNG' and version == '1.6.58':
|
|
filename = 'libpng-3061454d980de7d53608f594194cfac722721d2a.tar.gz'
|
|
url = 'https://codeload.github.com/pnggroup/libpng/tar.gz/3061454d980de7d53608f594194cfac722721d2a'
|
|
expected, algorithm = 'a2569b7553971e36e86c8f75b9d1b5abbe92c436e05169afe3f0072e937f3536', 'sha256'
|
|
archive = BASE / filename
|
|
if not archive.exists():
|
|
try:
|
|
with urllib.request.urlopen(url, timeout=60) as response: data = response.read()
|
|
except OSError:
|
|
with urllib.request.urlopen('https://download.blender.org/dependencies/' + filename, timeout=60) as response: data = response.read()
|
|
if hashlib.new(algorithm, data).hexdigest() != expected:
|
|
raise SystemExit(name + ' download differs from Blender pinned hash')
|
|
archive.write_bytes(data)
|
|
if hashlib.new(algorithm, archive.read_bytes()).hexdigest() != expected: raise SystemExit(name + ' archive hash mismatch')
|
|
with tarfile.open(archive) as package:
|
|
directory = BASE / package.getmembers()[0].name.split('/')[0]
|
|
if not (directory / 'CMakeLists.txt').exists(): package.extractall(BASE, filter='data')
|
|
return directory
|
|
def build(name, directory, options):
|
|
if len(sys.argv)>1 and name not in sys.argv[1:]: return
|
|
toolchain = ROOT / '.emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake'
|
|
prefixes = ';'.join(str(p) for p in (PREFIX, ROOT/'build_web_openexr/install', ROOT/'build_web_ocio/install'))
|
|
subprocess.run(['cmake', '-S', str(directory), '-B', str(BASE/name), '-G', 'Ninja',
|
|
'-DCMAKE_TOOLCHAIN_FILE='+str(toolchain), '-DCMAKE_BUILD_TYPE=Release',
|
|
'-DCMAKE_INSTALL_PREFIX='+str(PREFIX), '-DCMAKE_INSTALL_LIBDIR='+str(PREFIX/'lib'),
|
|
'-DCMAKE_PREFIX_PATH='+prefixes, '-DCMAKE_FIND_ROOT_PATH='+prefixes,
|
|
'-DCMAKE_CXX_FLAGS=-fexceptions', '-DBUILD_SHARED_LIBS=OFF', '-DBUILD_TESTING=OFF',
|
|
'-DZLIB_LIBRARY='+str(ROOT/'build_web_blender6/lib/libzstatic.a'),
|
|
'-DZLIB_INCLUDE_DIR='+str(ROOT/'blender-5.2.0/extern/zlib'), *options], cwd=ROOT, check=True)
|
|
subprocess.run(['cmake','--build',str(BASE/name),'--target','install','--parallel','8'],cwd=ROOT,check=True)
|
|
def main():
|
|
BASE.mkdir(exist_ok=True)
|
|
build('jpeg',source('JPEG'),['-DENABLE_SHARED=OFF','-DENABLE_STATIC=ON','-DWITH_SIMD=OFF','-DENABLE_TESTING=OFF'])
|
|
build('png',source('PNG'),['-DPNG_SHARED=OFF','-DPNG_TESTS=OFF','-DPNG_TOOLS=OFF','-DPNG_EXECUTABLES=OFF'])
|
|
build('tiff',source('TIFF'),['-Dtiff-tools=OFF','-Dtiff-tests=OFF','-Dtiff-contrib=OFF','-Dtiff-docs=OFF','-Dtiff-deprecated=OFF','-Dlibdeflate=OFF','-Dlzma=OFF','-Dzstd=OFF','-Dwebp=OFF','-Djbig=OFF'])
|
|
robin = source('ROBINMAP')
|
|
fmt = BASE/'fmt'; fmt.mkdir(exist_ok=True)
|
|
(fmt/'fmtConfigVersion.cmake').write_text('set(PACKAGE_VERSION "10.1.0")\nset(PACKAGE_VERSION_COMPATIBLE TRUE)\n')
|
|
(fmt/'fmtConfig.cmake').write_text('add_library(fmt::fmt-header-only INTERFACE IMPORTED)\nset_target_properties(fmt::fmt-header-only PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "'+str(ROOT/'blender-5.2.0/extern/fmt/include')+'" INTERFACE_COMPILE_DEFINITIONS "FMT_HEADER_ONLY;FMT_CONSTEVAL=;FMT_USE_CONSTEXPR=0;FMT_USE_NONTYPE_TEMPLATE_ARGS=0")\n')
|
|
oiio=source('OPENIMAGEIO')
|
|
platform=oiio/'src/libutil/sysutil.cpp'; text=platform.read_text()
|
|
text=text.replace('#include <thread>', '#include <thread>\n#ifdef __EMSCRIPTEN__\n# include <unistd.h>\n#endif',1) if '#ifdef __EMSCRIPTEN__' not in text else text
|
|
text=text.replace('#elif defined(__GNU__) || defined(__OpenBSD__) || defined(_WIN32)', '#elif defined(__GNU__) || defined(__OpenBSD__) || defined(_WIN32) || defined(__EMSCRIPTEN__)')
|
|
text=text.replace('# include <unistd.h>', '# include <unistd.h>\n# include <emscripten/heap.h>',1) if '<emscripten/heap.h>' not in text else text
|
|
text=text.replace('Sysutil::physical_memory()\n{\n#if defined(__linux__)', 'Sysutil::physical_memory()\n{\n#if defined(__EMSCRIPTEN__)\n return emscripten_get_heap_max();\n#elif defined(__linux__)')
|
|
platform.write_text(text)
|
|
strings=oiio/'src/libutil/strutil.cpp'; text=strings.read_text()
|
|
text=text.replace('|| defined(__GLIBC__)\n', '|| defined(__GLIBC__) || defined(__EMSCRIPTEN__)\n')
|
|
strings.write_text(text.replace('|| defined(__GLIBC__) || defined(__NetBSD__)\n', '|| defined(__GLIBC__) || defined(__NetBSD__) || defined(__EMSCRIPTEN__)\n'))
|
|
build('oiio',oiio,[
|
|
'-DCMAKE_PROJECT_INCLUDE='+str(ROOT/'tools/web/oiio-wasm-dependencies.cmake'),
|
|
'-Dfmt_DIR='+str(fmt), '-DROBINMAP_INCLUDE_DIR='+str(robin/'include'),
|
|
'-DOIIO_BUILD_TOOLS=OFF','-DOIIO_BUILD_TESTS=OFF','-DUSE_PYTHON=OFF','-DINSTALL_DOCS=OFF','-DEMBEDPLUGINS=ON',
|
|
'-DOpenImageIO_BUILD_MISSING_DEPS=none','-DUSE_SIMD=0','-DUSE_TBB=OFF','-DUSE_OPENCOLORIO=ON',
|
|
'-DUSE_FFMPEG=OFF','-DUSE_OPENVDB=OFF','-DUSE_FREETYPE=OFF','-DUSE_OPENCV=OFF','-DUSE_OPENJPEG=OFF','-DUSE_WEBP=OFF',
|
|
'-DUSE_JXL=OFF','-DUSE_LIBHEIF=OFF','-DUSE_LIBRAW=OFF','-DUSE_LIBUHDR=OFF','-DUSE_PTEX=OFF','-DUSE_DCMTK=OFF'])
|
|
|
|
if __name__ == '__main__':
|
|
main()
|