Repository: mesonbuild/meson

Issue:
gtkdoc-scangobj fails to find the shared library it scans (W32)
For example:
`Error in gtkdoc helper script:`
`'mingw\\bin\\python.EXE' failed with status 3221225781`
`WARNING:root:Running scanner failed: -1073741515, command: ./gtk4-scan.exe`
This is because the shared library being scanned is not in library search path. On *nix that is handled by adjusting `LD_LIBRARY_PATH`, but on W32 the variable that needs adjustment is `PATH`, and meson doesn't change it.

Here's a patch to fix that.
[0001-gtk-doc-Use-LD_LIBRARY_PATH-to-modify-PATH-on-W32.patch.txt](https://github.com/mesonbuild/meson/files/1843401/0001-gtk-doc-Use-LD_LIBRARY_PATH-to-modify-PATH-on-W32.patch.txt)


Discussion:
lazka: CI fails due to SSL problems with https://nirbheek.in/

(I host CI related binaries on a [dummy git tag](https://github.com/quodlibet/quodlibet/releases/tag/ci) in another project, maybe something to consider)
lazka: @LRN does this look OK to you?

Patch:
diff --git a/__main__.py b/__main__.py
index c412e3718..27cd4c05a 100644
--- a/__main__.py
+++ b/__main__.py
@@ -14,7 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import meson
+from mesonbuild import mesonmain
 import sys
 
-sys.exit(meson.main())
+sys.exit(mesonmain.main())
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index df4d05b66..099e5b975 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -345,13 +345,11 @@ class Environment:
         # static libraries, and executables.
         # Versioning is added to these names in the backends as-needed.
         cross = self.is_cross_build()
-        if (not cross and mesonlib.is_windows()) \
-                or (cross and self.cross_info.has_host() and self.cross_info.config['host_machine']['system'] == 'windows'):
+        if mesonlib.for_windows(cross, self):
             self.exe_suffix = 'exe'
             self.object_suffix = 'obj'
             self.win_libdir_layout = True
-        elif (not cross and mesonlib.is_cygwin()) \
-                or (cross and self.cross_info.has_host() and self.cross_info.config['host_machine']['system'] == 'cygwin'):
+        elif mesonlib.for_cygwin(cross, self):
             self.exe_suffix = 'exe'
             self.object_suffix = 'o'
             self.win_libdir_layout = True
@@ -1039,6 +1037,12 @@ class CrossBuildInfo:
     def get_stdlib(self, language):
         return self.config['properties'][language + '_stdlib']
 
+    def get_host_system(self):
+        "Name of host system like 'linux', or None"
+        if self.has_host():
+            return self.config['host_machine']['system']
+        return None
+
     def get_properties(self):
         return self.config['properties']
 
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index af21a9cb0..87f50d710 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -299,9 +299,7 @@ def for_windows(is_cross, env):
     """
     if not is_cross:
         return is_windows()
-    elif env.cross_info.has_host():
-        return env.cross_info.config['host_machine']['system'] == 'windows'
-    return False
+    return env.cross_info.get_host_system() == 'windows'
 
 def for_cygwin(is_cross, env):
     """
@@ -311,9 +309,7 @@ def for_cygwin(is_cross, env):
     """
     if not is_cross:
         return is_cygwin()
-    elif env.cross_info.has_host():
-        return env.cross_info.config['host_machine']['system'] == 'cygwin'
-    return False
+    return env.cross_info.get_host_system() == 'cygwin'
 
 def for_linux(is_cross, env):
     """
@@ -323,9 +319,7 @@ def for_linux(is_cross, env):
     """
     if not is_cross:
         return is_linux()
-    elif env.cross_info.has_host():
-        return env.cross_info.config['host_machine']['system'] == 'linux'
-    return False
+    return env.cross_info.get_host_system() == 'linux'
 
 def for_darwin(is_cross, env):
     """
@@ -335,9 +329,7 @@ def for_darwin(is_cross, env):
     """
     if not is_cross:
         return is_osx()
-    elif env.cross_info.has_host():
-        return env.cross_info.config['host_machine']['system'] in ('darwin', 'ios')
-    return False
+    return env.cross_info.get_host_system() in ('darwin', 'ios')
 
 def for_android(is_cross, env):
     """
@@ -347,9 +339,7 @@ def for_android(is_cross, env):
     """
     if not is_cross:
         return is_android()
-    elif env.cross_info.has_host():
-        return env.cross_info.config['host_machine']['system'] == 'android'
-    return False
+    return env.cross_info.get_host_system() == 'android'
 
 def for_haiku(is_cross, env):
     """
@@ -359,9 +349,7 @@ def for_haiku(is_cross, env):
     """
     if not is_cross:
         return is_haiku()
-    elif env.cross_info.has_host():
-        return env.cross_info.config['host_machine']['system'] == 'haiku'
-    return False
+    return env.cross_info.get_host_system() == 'haiku'
 
 def for_openbsd(is_cross, env):
     """
diff --git a/mesonbuild/scripts/gtkdochelper.py b/mesonbuild/scripts/gtkdochelper.py
index 371d95d6e..bf3d9f6af 100644
--- a/mesonbuild/scripts/gtkdochelper.py
+++ b/mesonbuild/scripts/gtkdochelper.py
@@ -17,7 +17,7 @@ import subprocess
 import shlex
 import shutil
 import argparse
-from ..mesonlib import MesonException, Popen_safe
+from ..mesonlib import MesonException, Popen_safe, is_windows
 from . import destdir_join
 
 parser = argparse.ArgumentParser()
@@ -47,10 +47,20 @@ parser.add_argument('--mode', dest='mode', default='')
 parser.add_argument('--installdir', dest='install_dir')
 parser.add_argument('--run', dest='run', default='')
 
-def gtkdoc_run_check(cmd, cwd, library_path=None):
+def gtkdoc_run_check(cmd, cwd, library_paths=None):
+    if library_paths is None:
+        library_paths = []
+
     env = dict(os.environ)
-    if library_path:
-        env['LD_LIBRARY_PATH'] = library_path
+    if is_windows():
+        if 'PATH' in env:
+            library_paths.extend(env['PATH'].split(os.pathsep))
+        env['PATH'] = os.pathsep.join(library_paths)
+    else:
+        if 'LD_LIBRARY_PATH' in env:
+            library_paths.extend(env['LD_LIBRARY_PATH'].split(os.pathsep))
+        env['LD_LIBRARY_PATH'] = os.pathsep.join(library_paths)
+
     # Put stderr into stdout since we want to print it out anyway.
     # This preserves the order of messages.
     p, out = Popen_safe(cmd, cwd=cwd, env=env, stderr=subprocess.STDOUT)[0:2]
@@ -137,11 +147,8 @@ def build_gtkdoc(source_root, build_root, doc_subdir, src_subdirs,
         for ldflag in shlex.split(ldflags):
             if ldflag.startswith('-Wl,-rpath,'):
                 library_paths.append(ldflag[11:])
-        if 'LD_LIBRARY_PATH' in os.environ:
-            library_paths.append(os.environ['LD_LIBRARY_PATH'])
-        library_path = ':'.join(library_paths)
 
-        gtkdoc_run_check(scanobjs_cmd, build_root, library_path)
+        gtkdoc_run_check(scanobjs_cmd, build_root, library_paths)
 
     # Make docbook files
     if mode == 'auto':


Test patch:
diff --git a/run_meson_command_tests.py b/run_meson_command_tests.py
index 6efd911b5..cd220de5c 100755
--- a/run_meson_command_tests.py
+++ b/run_meson_command_tests.py
@@ -18,6 +18,7 @@ import os
 import tempfile
 import unittest
 import subprocess
+import zipapp
 from pathlib import Path
 
 from mesonbuild.mesonlib import windows_proof_rmtree, python_command, is_windows
@@ -182,5 +183,13 @@ class CommandTests(unittest.TestCase):
     def test_meson_exe_windows(self):
         raise unittest.SkipTest('NOT IMPLEMENTED')
 
+    def test_meson_zipapp(self):
+        if is_windows():
+            raise unittest.SkipTest('NOT IMPLEMENTED')
+        source = Path(__file__).resolve().parent.as_posix()
+        target = self.tmpdir / 'meson.pyz'
+        zipapp.create_archive(source=source, target=target, interpreter=python_command[0], main=None)
+        self._run([target.as_posix(), '--help'])
+
 if __name__ == '__main__':
     unittest.main(buffer=True)