# This file is part of the open-lmake distribution (git@github.com:cesar-douady/open-lmake.git)
# Copyright (c) 2023-2025 Doliam
# This program is free software: you can redistribute/modify under the terms of the GPL-v3 (https://www.gnu.org/licenses/gpl-3.0.html).
# This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
import shutil
import lmake
if __name__!='__main__' :
from lmake.rules import Rule,PyRule
lmake.manifest = ('Lmakefile.py',)
lmake.config.network_delay = 10 # WineInit is still alive after job end for ~1s but may last more than 5s
lmake.config.trace.n_jobs = 10000 # ensure we keep all traces
xvfb = shutil.which('xvfb-run')
class Base(Rule) :
stems = { 'Method' : r'\w+' }
class WineRule(Rule) :
tmp_view = '/tmp' # ensure pid namespace is used to ensure reliable job termination
side_targets = {
'WINE' : (r'.wine/{*:.*}' ,'incremental') # wine writes in dir, even after init
, 'CACHE' : (r'.cache/{*:.*}','incremental') # .
, 'LOCAL' : (r'.local/{*:.*}','incremental') # .
, 'DBUS' : (r'.dbus/{*:.*}' ,'incremental') # .
}
side_deps = {
'TOP_DIR' : ('.' ,'readdir_ok') # wine seems to sometimes readdir that
, 'LOCAL_DIR' : ('.local' ,'readdir_ok') # .
, 'CONFIG_DIR' : ('.config' ,'readdir_ok') # .
, 'MENUS_DIR' : ('.config/menus','readdir_ok') # .
}
environ = { 'WINEDEBUG' : '-all' }
if xvfb : environ_resources = { 'SMALL_ID' : '$SMALL_ID' } # display is provided by xvfb-run
else : environ_resources = { 'DISPLAY' : lmake.user_environ['DISPLAY'] } # use current display
class WineInit(WineRule) :
target = 'wine_init'
targets = { 'WINE' : (r'.wine/{*:.*}','incremental') } # for init wine env is not incremental
side_targets = { 'WINE' : None }
timeout = 120 # actual time is ~10s but seems to sometimes block under heavy load
stderr_ok = True
readdir_ok = True
if xvfb : cmd = f'D=$(($SMALL_ID+50)) ; {xvfb} -n $D wine64 cmd && sleep 1' # do nothing, init support files (in targets) wait for wineserver to die (3s by default)
else : cmd = ' wine64 cmd && sleep 1' # .
for ext in ('','64') :
class Dut(Base,WineRule) :
name = f'Dut{ext}'
target = f'dut{ext}.{{Method}}'
deps = { 'WINE_INIT' : 'wine_init' }
timeout = 40 # actual time is ~2s
autodep = '{Method}'
# wine sends err messages, that do occur, to stdout !
if xvfb : cmd = f'set -o pipefail ; D=$(($SMALL_ID+50)) ; {xvfb} -n $D wine{ext} hostname | head -1 && sleep 2' # wine exits before hostname has finished !
else : cmd = f'set -o pipefail ; wine{ext} hostname | head -1 && sleep 2' # .
class Chk(Base,PyRule) :
target = r'test{Ext:64|}.{Method}'
dep = 'dut{Ext}.{Method}'
def cmd() :
import socket
import sys
ref = socket.gethostname().lower()
dut = sys.stdin.read().strip().lower()
assert dut==ref,f'{dut} != {ref}'
else :
import os
import os.path as osp
import subprocess as sp
import sys
import ut
wine64 = shutil.which('wine64')
if not wine64 :
print('wine64 not available',file=open('skipped','w'))
exit()
# try to adapt to various installations
wine64 = osp.realpath(wine64)
if wine64.startswith('/usr/bin/') : prefix_exe = '/usr/lib/x86_64-linux-gnu/wine/x86_64-windows'
else : prefix_exe = osp.dirname(osp.dirname(wine64))+'/lib64/wine/x86_64-windows'
cmd_exe = f'{prefix_exe}/cmd.exe'
if not osp.exists(cmd_exe) :
print(f'{cmd_exe} not found',file=open('skipped','w'))
exit()
hostname_exe = f'{prefix_exe}/hostname.exe'
if not osp.exists(hostname_exe) :
print(f'{hostname_exe} not found',file=open('skipped','w'))
exit()
ut.lmake( *(f'test64.{m}' for m in lmake.autodeps) , done=1+2*len(lmake.autodeps) , new=0 , rc=0 )
ut.lmake( *(f'test64.{m}' for m in lmake.autodeps) ) # ensure nothing needs to be remade
if os.environ['HAS_32'] and shutil.which('wine') :
methods_32 = [m for m in lmake.autodeps if m!='ptrace']
ut.lmake( *(f'test.{m}' for m in methods_32) , done=2*len(methods_32) , new=0 , rc=0 ) # ptrace is not supported in 32 bits
ut.lmake( *(f'test.{m}' for m in methods_32) ) # ensure nothing needs to be remade