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>
82 lines
4.6 KiB
Python
82 lines
4.6 KiB
Python
#!/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)
|