aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Claessens <xavier.claessens@collabora.com>2022-06-03 10:34:55 -0400
committerXavier Claessens <xclaesse@gmail.com>2022-06-17 11:53:38 -0400
commit57909b53d6d2099e45873688b659ce071f6039ef (patch)
treee97b29cad444268cdef507abf83205bff3367ef7
parentb1649899a2d392bd0a4c3a629614d29aafd73bb9 (diff)
downloadmeson-57909b53d6d2099e45873688b659ce071f6039ef.zip
meson-57909b53d6d2099e45873688b659ce071f6039ef.tar.gz
meson-57909b53d6d2099e45873688b659ce071f6039ef.tar.bz2
Improve WINEPATH reduction
- Remove duplicated code in mdevenv.py - Change the limit to 1024 instead of 2048 which is what has been tested. - Skip shortening if it is already short enough. - Skip shortening with wine >= 6.4 which does not seems to have that limitation any more. - Downgrade exception to warning in the case WINEPATH cannot be shortened under 1024 chars, it is possible that it will still work.
-rw-r--r--mesonbuild/mdevenv.py44
-rw-r--r--mesonbuild/mesonlib/universal.py91
-rw-r--r--mesonbuild/mtest.py3
-rw-r--r--mesonbuild/scripts/meson_exe.py3
4 files changed, 69 insertions, 72 deletions
diff --git a/mesonbuild/mdevenv.py b/mesonbuild/mdevenv.py
index 46b301c..d0e84ff 100644
--- a/mesonbuild/mdevenv.py
+++ b/mesonbuild/mdevenv.py
@@ -6,7 +6,7 @@ import itertools
from pathlib import Path
from . import build, minstall, dependencies
-from .mesonlib import MesonException, RealPathAction, is_windows, setup_vsenv, OptionKey, quote_arg
+from .mesonlib import MesonException, RealPathAction, is_windows, setup_vsenv, OptionKey, quote_arg, get_wine_shortpath
from . import mlog
import typing as T
@@ -28,43 +28,6 @@ def get_windows_shell() -> str:
result = subprocess.check_output(command)
return result.decode().strip()
-def get_wine_shortpath(build_dir: str, winecmd: str, wine_paths: T.List[str]) -> T.List[str]:
- '''
- WINEPATH size is limited to 1024 bytes which can easily be exceeded when
- adding the path to every dll inside build directory. See
- https://bugs.winehq.org/show_bug.cgi?id=45810.
-
- To shorthen it as much as possible we use path relative to builddir
- where possible and convert absolute paths to Windows shortpath (e.g.
- "/usr/x86_64-w64-mingw32/lib" to "Z:\\usr\\X86_~FWL\\lib").
- '''
- rel_paths = []
- abs_paths = []
- builddir = Path(build_dir)
- for p in wine_paths:
- try:
- rel = Path(p).relative_to(builddir)
- rel_paths.append(str(rel))
- except ValueError:
- abs_paths.append(p)
- if not abs_paths:
- return rel_paths
- with tempfile.NamedTemporaryFile('w', suffix='.bat', encoding='utf-8', delete=False) as bat_file:
- bat_file.write('''
- @ECHO OFF
- for %%x in (%*) do (
- echo|set /p=;%~sx
- )
- ''')
- try:
- stdout = subprocess.check_output([winecmd, 'cmd', '/C', bat_file.name] + abs_paths,
- encoding='utf-8', stderr=subprocess.DEVNULL)
- return rel_paths + [p for p in set(stdout.split(';')) if p]
- except subprocess.CalledProcessError:
- return rel_paths + abs_paths
- finally:
- os.unlink(bat_file.name)
-
def reduce_winepath(build_dir: str, env: T.Dict[str, str]) -> None:
winepath = env.get('WINEPATH')
if not winepath:
@@ -72,10 +35,7 @@ def reduce_winepath(build_dir: str, env: T.Dict[str, str]) -> None:
winecmd = shutil.which('wine64') or shutil.which('wine')
if not winecmd:
return
- winepath = ';'.join(get_wine_shortpath(build_dir, winecmd, winepath.split(';')))
- if len(winepath) > 1024:
- mlog.warning(f'WINEPATH exceeds 1024 characters which could cause issues:\n{winepath}')
- env['WINEPATH'] = winepath
+ env['WINEPATH'] = get_wine_shortpath([winecmd], winepath.split(';'), build_dir)
mlog.log('Meson detected wine and has set WINEPATH accordingly')
def get_env(b: build.Build, build_dir: str) -> T.Tuple[T.Dict[str, str], T.Set[str]]:
diff --git a/mesonbuild/mesonlib/universal.py b/mesonbuild/mesonlib/universal.py
index 71f206a..ebcd9f4 100644
--- a/mesonbuild/mesonlib/universal.py
+++ b/mesonbuild/mesonlib/universal.py
@@ -26,9 +26,8 @@ import platform, subprocess, operator, os, shlex, shutil, re
import collections
from functools import lru_cache, wraps, total_ordering
from itertools import tee, filterfalse
-from tempfile import TemporaryDirectory
+from tempfile import TemporaryDirectory, NamedTemporaryFile
import typing as T
-import uuid
import textwrap
import copy
import pickle
@@ -1888,35 +1887,71 @@ class RealPathAction(argparse.Action):
setattr(namespace, self.dest, os.path.abspath(os.path.realpath(values)))
-def get_wine_shortpath(winecmd: T.List[str], wine_paths: T.Sequence[str]) -> str:
- """Get A short version of @wine_paths to avoid reaching WINEPATH number
- of char limit.
- """
+def get_wine_shortpath(winecmd: T.List[str], wine_paths: T.Sequence[str],
+ workdir: T.Optional[str] = None) -> str:
+ '''
+ WINEPATH size is limited to 1024 bytes which can easily be exceeded when
+ adding the path to every dll inside build directory. See
+ https://bugs.winehq.org/show_bug.cgi?id=45810.
- wine_paths = list(OrderedSet(wine_paths))
+ To shorten it as much as possible we use path relative to `workdir`
+ where possible and convert absolute paths to Windows shortpath (e.g.
+ "/usr/x86_64-w64-mingw32/lib" to "Z:\\usr\\X86_~FWL\\lib").
- getShortPathScript = '%s.bat' % str(uuid.uuid4()).lower()[:5]
- with open(getShortPathScript, mode='w', encoding='utf-8') as f:
- f.write("@ECHO OFF\nfor %%x in (%*) do (\n echo|set /p=;%~sx\n)\n")
- f.flush()
- try:
- with open(os.devnull, 'w', encoding='utf-8') as stderr:
- wine_path = subprocess.check_output(
- winecmd +
- ['cmd', '/C', getShortPathScript] + wine_paths,
- stderr=stderr).decode('utf-8')
- except subprocess.CalledProcessError as e:
- print("Could not get short paths: %s" % e)
- wine_path = ';'.join(wine_paths)
- finally:
- os.remove(getShortPathScript)
- if len(wine_path) > 2048:
- raise MesonException(
- 'WINEPATH size {} > 2048'
- ' this will cause random failure.'.format(
- len(wine_path)))
+ This limitation reportedly has been fixed with wine >= 6.4
+ '''
- return wine_path.strip(';')
+ # Remove duplicates
+ wine_paths = list(OrderedSet(wine_paths))
+
+ # Check if it's already short enough
+ wine_path = ';'.join(wine_paths)
+ if len(wine_path) <= 1024:
+ return wine_path
+
+ # Check if we have wine >= 6.4
+ from ..programs import ExternalProgram
+ wine = ExternalProgram('wine', winecmd, silent=True)
+ if version_compare(wine.get_version(), '>=6.4'):
+ return wine_path
+
+ # Check paths that can be reduced by making them relative to workdir.
+ rel_paths = []
+ if workdir:
+ abs_paths = []
+ for p in wine_paths:
+ try:
+ rel = Path(p).relative_to(workdir)
+ rel_paths.append(str(rel))
+ except ValueError:
+ abs_paths.append(p)
+ wine_paths = abs_paths
+
+ if wine_paths:
+ # BAT script that takes a list of paths in argv and prints semi-colon separated shortpaths
+ with NamedTemporaryFile('w', suffix='.bat', encoding='utf-8', delete=False) as bat_file:
+ bat_file.write('''
+ @ECHO OFF
+ for %%x in (%*) do (
+ echo|set /p=;%~sx
+ )
+ ''')
+ try:
+ stdout = subprocess.check_output(winecmd + ['cmd', '/C', bat_file.name] + wine_paths,
+ encoding='utf-8', stderr=subprocess.DEVNULL)
+ stdout = stdout.strip(';')
+ if stdout:
+ wine_paths = stdout.split(';')
+ else:
+ mlog.warning('Could not shorten WINEPATH: empty stdout')
+ except subprocess.CalledProcessError as e:
+ mlog.warning(f'Could not shorten WINEPATH: {str(e)}')
+ finally:
+ os.unlink(bat_file.name)
+ wine_path = ';'.join(rel_paths + wine_paths)
+ if len(wine_path) > 1024:
+ mlog.warning('WINEPATH exceeds 1024 characters which could cause issues')
+ return wine_path
def run_once(func: T.Callable[..., _T]) -> T.Callable[..., _T]:
diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py
index ea5b2da..d733ce8 100644
--- a/mesonbuild/mtest.py
+++ b/mesonbuild/mtest.py
@@ -1338,7 +1338,8 @@ class SingleTestRunner:
if os.path.basename(c).startswith('wine'):
env['WINEPATH'] = get_wine_shortpath(
winecmd,
- ['Z:' + p for p in self.test.extra_paths] + env.get('WINEPATH', '').split(';')
+ ['Z:' + p for p in self.test.extra_paths] + env.get('WINEPATH', '').split(';'),
+ self.test.workdir
)
break
diff --git a/mesonbuild/scripts/meson_exe.py b/mesonbuild/scripts/meson_exe.py
index 486c101..c8f2f3b 100644
--- a/mesonbuild/scripts/meson_exe.py
+++ b/mesonbuild/scripts/meson_exe.py
@@ -51,7 +51,8 @@ def run_exe(exe: ExecutableSerialisation, extra_env: T.Optional[T.Dict[str, str]
if exe.exe_wrapper and mesonlib.substring_is_in_list('wine', exe.exe_wrapper.get_command()):
child_env['WINEPATH'] = mesonlib.get_wine_shortpath(
exe.exe_wrapper.get_command(),
- ['Z:' + p for p in exe.extra_paths] + child_env.get('WINEPATH', '').split(';')
+ ['Z:' + p for p in exe.extra_paths] + child_env.get('WINEPATH', '').split(';'),
+ exe.workdir
)
stdin = None