aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Claessens <xavier.claessens@collabora.com>2022-04-20 15:17:51 -0400
committerJussi Pakkanen <jpakkane@gmail.com>2022-05-06 23:04:11 +0300
commitf9200ca8f7429d614dcb8c4144269461c6a7d9d9 (patch)
tree192030b5e3d301e3a5be272ecfd2e4ca2ab1b267
parent1e4d4fce2250ab415964ad89c1d8b2c649b0b00d (diff)
downloadmeson-f9200ca8f7429d614dcb8c4144269461c6a7d9d9.zip
meson-f9200ca8f7429d614dcb8c4144269461c6a7d9d9.tar.gz
meson-f9200ca8f7429d614dcb8c4144269461c6a7d9d9.tar.bz2
devenv: Set WINEPATH when cross compiling for Windows
-rw-r--r--docs/markdown/Commands.md6
-rw-r--r--docs/markdown/snippets/devenv_winepath.md4
-rw-r--r--mesonbuild/backend/backends.py18
-rw-r--r--mesonbuild/mdevenv.py52
4 files changed, 74 insertions, 6 deletions
diff --git a/docs/markdown/Commands.md b/docs/markdown/Commands.md
index b137166..762cd2f 100644
--- a/docs/markdown/Commands.md
+++ b/docs/markdown/Commands.md
@@ -351,4 +351,10 @@ top build directory, that file is loaded by gdb automatically. In the case of
python scripts that needs to load other python modules, `PYTHONPATH` may need
to be modified using `meson.add_devenv()`.
+Since *Since 0.63.0* when cross compiling for Windows `WINEPATH` is used instead
+of `PATH` which allows running Windows executables using wine. Note that since
+`WINEPATH` size is currently limited to 1024 characters, paths relative to the
+root of build directory are used. That means current workdir must be the root of
+build directory when running wine.
+
{{ devenv_arguments.inc }}
diff --git a/docs/markdown/snippets/devenv_winepath.md b/docs/markdown/snippets/devenv_winepath.md
new file mode 100644
index 0000000..b9e24a0
--- /dev/null
+++ b/docs/markdown/snippets/devenv_winepath.md
@@ -0,0 +1,4 @@
+## Running Windows executables with Wine in `meson devenv`
+
+When cross compiling for Windows, `meson devenv` now sets `WINEPATH` pointing to
+all directories containing needed DLLs and executables.
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index b5b8171..26402b7 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -1801,9 +1801,12 @@ class Backend:
env = build.EnvironmentVariables()
extra_paths = set()
library_paths = set()
+ host_machine = self.environment.machines[MachineChoice.HOST]
+ need_exe_wrapper = self.environment.need_exe_wrapper()
+ need_wine = need_exe_wrapper and host_machine.is_windows()
for t in self.build.get_targets().values():
cross_built = not self.environment.machines.matches_build_machine(t.for_machine)
- can_run = not cross_built or not self.environment.need_exe_wrapper()
+ can_run = not cross_built or not need_exe_wrapper or need_wine
in_default_dir = t.should_install() and not t.get_install_dir()[2]
if not can_run or not in_default_dir:
continue
@@ -1813,22 +1816,25 @@ class Backend:
# so they get used by default instead of searching on system when
# in developer environment.
extra_paths.add(tdir)
- if mesonlib.is_windows() or mesonlib.is_cygwin():
+ if host_machine.is_windows() or host_machine.is_cygwin():
# On windows we cannot rely on rpath to run executables from build
# directory. We have to add in PATH the location of every DLL needed.
- extra_paths.update(self.determine_windows_extra_paths(t, []))
+ library_paths.update(self.determine_windows_extra_paths(t, []))
elif isinstance(t, build.SharedLibrary):
# Add libraries that are going to be installed in libdir into
# LD_LIBRARY_PATH. This allows running system applications using
# that library.
library_paths.add(tdir)
if library_paths:
- if mesonlib.is_windows() or mesonlib.is_cygwin():
+ if host_machine.is_windows() or host_machine.is_cygwin():
extra_paths.update(library_paths)
- elif mesonlib.is_osx():
+ elif host_machine.is_darwin():
env.prepend('DYLD_LIBRARY_PATH', list(library_paths))
else:
env.prepend('LD_LIBRARY_PATH', list(library_paths))
if extra_paths:
- env.prepend('PATH', list(extra_paths))
+ if need_wine:
+ env.prepend('WINEPATH', list(extra_paths), separator=';')
+ else:
+ env.prepend('PATH', list(extra_paths))
return env
diff --git a/mesonbuild/mdevenv.py b/mesonbuild/mdevenv.py
index 27533e3..f5dcf30 100644
--- a/mesonbuild/mdevenv.py
+++ b/mesonbuild/mdevenv.py
@@ -28,6 +28,56 @@ 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 as e:
+ 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:
+ return
+ 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
+ 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]]:
extra_env = build.EnvironmentVariables()
extra_env.set('MESON_DEVENV', ['1'])
@@ -39,6 +89,8 @@ def get_env(b: build.Build, build_dir: str) -> T.Tuple[T.Dict[str, str], T.Set[s
env = i.get_env(env)
varnames |= i.get_names()
+ reduce_winepath(build_dir, env)
+
return env, varnames
def bash_completion_files(b: build.Build, install_data: 'InstallData') -> T.List[str]: