aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/mesonlib
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 /mesonbuild/mesonlib
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.
Diffstat (limited to 'mesonbuild/mesonlib')
-rw-r--r--mesonbuild/mesonlib/universal.py91
1 files changed, 63 insertions, 28 deletions
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]: