chore: checkpoint web Blender migration source, tools and docs
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>
This commit is contained in:
81
tools/web/build-native-desktop-adapters.py
Normal file
81
tools/web/build-native-desktop-adapters.py
Normal file
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build WM/RNA objects and link an isolated candidate from existing native libraries."""
|
||||
import datetime
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shlex
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
root=Path(__file__).resolve().parents[2]
|
||||
if '--configured' not in sys.argv:
|
||||
result=subprocess.run(['bash','-c','source tools/web/native-build-env.sh && exec "$1" "$2" --configured',
|
||||
'_',sys.executable,str(Path(__file__).resolve())],cwd=root)
|
||||
sys.exit(result.returncode)
|
||||
build=root/'build_blender_native'
|
||||
candidate=build/'desktop-adapter'
|
||||
directory=root/'tests/golden/WBV2-P1424-001/native-desktop-adapter-build'/datetime.datetime.now(datetime.timezone.utc).strftime('%Y%m%dT%H%M%SZ')
|
||||
directory.mkdir(parents=True)
|
||||
for name in ('objects','lib','bin','generated'):(candidate/name).mkdir(parents=True,exist_ok=True)
|
||||
report={'schemaVersion':1,'status':'BUILDING','validation':'NOT_RUN','steps':[],'strategy':'REUSE_EXISTING_LIBRARIES_NO_DNA_LAYOUT_CHANGE'}
|
||||
|
||||
def run(name,command,cwd=build):
|
||||
with (directory/(name+'.log')).open('w') as log:
|
||||
result=subprocess.run(command,cwd=cwd,env=dict(os.environ,WBV2_SKIP_TYPECHECK='1'),stdout=log,stderr=subprocess.STDOUT)
|
||||
report['steps'].append({'name':name,'exitCode':result.returncode})
|
||||
if result.returncode:raise RuntimeError(name+' artifact build failed')
|
||||
|
||||
def digest(file):
|
||||
sha=hashlib.sha256()
|
||||
with file.open('rb') as stream:
|
||||
for data in iter(lambda:stream.read(1024*1024),b''):sha.update(data)
|
||||
return {'sha256':sha.hexdigest(),'bytes':file.stat().st_size}
|
||||
|
||||
def link_command(target):
|
||||
output=subprocess.check_output(['ninja','-t','commands',target],cwd=build,text=True)
|
||||
tokens=shlex.split(output.strip().splitlines()[-1])
|
||||
if tokens[:2]==[':','&&']:tokens=tokens[2:]
|
||||
if '&&' in tokens:tokens=tokens[:tokens.index('&&')]
|
||||
if not tokens or 'g++' not in Path(tokens[0]).name or '-o' not in tokens:raise RuntimeError('NATIVE_LINK_RULE_UNSUPPORTED')
|
||||
return tokens
|
||||
|
||||
try:
|
||||
rules=['CXX_COMPILER__makesrna_unscanned_Release','CXX_COMPILER__bf_rna_unscanned_Release','CXX_COMPILER__bf_windowmanager_unscanned_Release']
|
||||
commands=json.loads(subprocess.check_output(['ninja','-t','compdb',*rules],cwd=build,text=True))
|
||||
def compile_object(suffix,name,source=None):
|
||||
entry=next(item for item in commands if item['file'].endswith(suffix))
|
||||
args=shlex.split(entry['command']);destination=candidate/'objects'/name
|
||||
for flag in ('-o','-MT','-MF'):
|
||||
if flag in args:args[args.index(flag)+1]=str(destination)+('.d' if flag=='-MF' else '')
|
||||
if source:args[args.index('-c')+1]=str(source)
|
||||
args.insert(1,'-I'+str(candidate/'generated'))
|
||||
run(name,args)
|
||||
return destination,entry['output']
|
||||
generator_object,old_generator_object=compile_object('/rna_wm_api.cc','rna_wm_api.cc.o')
|
||||
args=link_command('bin/makesrna');args=[str(generator_object) if value==old_generator_object else value for value in args]
|
||||
generator=candidate/'bin/makesrna';args[args.index('-o')+1]=str(generator);run('link-makesrna',args)
|
||||
run('generate-rna',[str(generator),str(root/'blender-5.2.0/source/blender/makesdna')+'/',str(candidate/'generated')+'/',str(candidate/'generated')+'/'])
|
||||
wm_object,_=compile_object('/wm_window.cc','wm_window.cc.o')
|
||||
rna_object,_=compile_object('/rna_wm_gen.cc','rna_wm_gen.cc.o',candidate/'generated/rna_wm_gen.cc')
|
||||
replacements={};report['reusedArchives']={}
|
||||
for name,object_file in [('libbf_windowmanager.a',wm_object),('libbf_rna.a',rna_object)]:
|
||||
archive=build/'lib'/name;report['reusedArchives'][name]=digest(archive)
|
||||
target=candidate/'lib'/name;shutil.copyfile(archive,target)
|
||||
run('archive-'+name,['ar','rcs',str(target),str(object_file)])
|
||||
replacements['lib/'+name]=str(target)
|
||||
args=link_command('bin/blender');args=[replacements.get(value,value) for value in args]
|
||||
pending=candidate/'bin/blender.pending';args[args.index('-o')+1]=str(pending)
|
||||
run('link-blender',args)
|
||||
runtime=candidate/'bin/5.2'
|
||||
if not runtime.exists():runtime.symlink_to(build/'bin/5.2',target_is_directory=True)
|
||||
pending.replace(candidate/'bin/blender')
|
||||
run('web',['node','tools/web/incremental-web-build.mjs'],root)
|
||||
report.update(status='BUILT_UNVERIFIED',nativeBinary=digest(candidate/'bin/blender'),binary=str(candidate/'bin/blender'))
|
||||
except BaseException as error:
|
||||
report.update(status='BUILD_INCOMPLETE',error=str(error));raise
|
||||
finally:
|
||||
(directory/'build.json').write_text(json.dumps(report,indent=2)+'\n')
|
||||
print(json.dumps({'directory':str(directory),**report}),flush=True)
|
||||
Reference in New Issue
Block a user