Repository: mesonbuild/meson

Issue:
meson crash: mesonbuild.mesonlib is not a package.
The command ` meson configure . -Doptimization=0` crashes with a python stack trace:
```
Traceback (most recent call last):
  File "/Users/john/.local/share/virtualenvs/etc-vauAPygS/lib/python3.10/site-packages/mesonbuild/mesonmain.py", line 194, in run
    return options.run_func(options)
  File "/Users/john/.local/share/virtualenvs/etc-vauAPygS/lib/python3.10/site-packages/mesonbuild/mconf.py", line 300, in run
    c = Conf(builddir)
  File "/Users/john/.local/share/virtualenvs/etc-vauAPygS/lib/python3.10/site-packages/mesonbuild/mconf.py", line 72, in __init__
    self.build = build.load(self.build_dir)
  File "/Users/john/.local/share/virtualenvs/etc-vauAPygS/lib/python3.10/site-packages/mesonbuild/build.py", line 2907, in load
    obj = pickle.load(f)
ModuleNotFoundError: No module named 'mesonbuild.mesonlib.universal'; 'mesonbuild.mesonlib' is not a package

ERROR: Unhandled python exception

    This is a Meson bug and should be reported!
```

Source is [cairo](https://gitlab.freedesktop.org/cairo/cairo/) at [commit 6dc5df6](https://gitlab.freedesktop.org/cairo/cairo/-/commit/c6dc5df61264be1bec2e622355b97c6c45d236fc).

Native compilation on macOS 13.1beta with Xcode 14.1's toolchain. Python is a locally-compiled 3.10 in a pyenv-controlled virtenv, and meson-0.64.0 was just pulled from pypi with pip3.


Discussion:
your system sounds broken
@tristan957 OK, but that's not very helpful. What is broken about it?
Usually when I have seen this error it is because Meson was installed with a different version of Python than what it is being executed with.
But this happened in meson configure, when configuring an existing build directory.

The actual problem is that Meson requires you to re-setup when you update to a new major version.

Usually you'd get an "error: you configured with meson 0.63 which is an older version, pls redo everything, kthxbai", more or less.

In this case it failed before the error message could be generated so you got a stacktrace instead. This is a UX bug, I know why it happened and I will PR the fix shortly.
Hmm. It turns out that @tristan957 was almost right: There are in fact two python builds accessible to meson though they're both v3.10.0. Meson was installed in the virtenv, but $PYTHON pointed to another instance of python3.10 and that python's sys.path doesn't include meson's modules.

However, it's also correct that once I did `rm -rf * && meson ../../src/cairo` with the new meson version `meson configure . -Doptimization=0` no longer crashes.

Glad a PR could come out of it and your problem fixed :).

Resolving patch:
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -36,7 +36,7 @@
     extract_as_list, typeslistify, stringlistify, classify_unity_sources,
     get_filenames_templates_dict, substitute_values, has_path_sep,
     OptionKey, PerMachineDefaultable, OptionOverrideProxy,
-    MesonBugException, EnvironmentVariables
+    MesonBugException, EnvironmentVariables, pickle_load,
 )
 from .compilers import (
     is_object, clink_langs, sort_clink, all_languages,
@@ -2900,24 +2900,11 @@ def get_sources_string_names(sources, backend):
 
 def load(build_dir: str) -> Build:
     filename = os.path.join(build_dir, 'meson-private', 'build.dat')
-    load_fail_msg = f'Build data file {filename!r} is corrupted. Try with a fresh build tree.'
-    nonexisting_fail_msg = f'No such build data file as "{filename!r}".'
     try:
-        with open(filename, 'rb') as f:
-            obj = pickle.load(f)
+        return pickle_load(filename, 'Build data', Build)
     except FileNotFoundError:
-        raise MesonException(nonexisting_fail_msg)
-    except (pickle.UnpicklingError, EOFError):
-        raise MesonException(load_fail_msg)
-    except AttributeError:
-        raise MesonException(
-            f"Build data file {filename!r} references functions or classes that don't "
-            "exist. This probably means that it was generated with an old "
-            "version of meson. Try running from the source directory "
-            f"meson setup {build_dir} --wipe")
-    if not isinstance(obj, Build):
-        raise MesonException(load_fail_msg)
-    return obj
+        raise MesonException(f'No such build data file as {filename!r}.')
+
 
 def save(obj: Build, filename: str) -> None:
     with open(filename, 'wb') as f:
diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py
--- a/mesonbuild/utils/universal.py
+++ b/mesonbuild/utils/universal.py
@@ -2289,16 +2289,21 @@ def pickle_load(filename: str, object_name: str, object_type: T.Type) -> T.Any:
     except (pickle.UnpicklingError, EOFError):
         raise MesonException(load_fail_msg)
     except (TypeError, ModuleNotFoundError, AttributeError):
+        build_dir = os.path.dirname(os.path.dirname(filename))
         raise MesonException(
             f"{object_name} file {filename!r} references functions or classes that don't "
             "exist. This probably means that it was generated with an old "
-            "version of meson.")
+            "version of meson. Try running from the source directory "
+            f'meson setup {build_dir} --wipe')
     if not isinstance(obj, object_type):
         raise MesonException(load_fail_msg)
     from ..coredata import version as coredata_version
     from ..coredata import major_versions_differ, MesonVersionMismatchException
-    if major_versions_differ(obj.version, coredata_version):
-        raise MesonVersionMismatchException(obj.version, coredata_version)
+    version = getattr(obj, 'version', None)
+    if version is None:
+        version = obj.environment.coredata.version
+    if major_versions_differ(version, coredata_version):
+        raise MesonVersionMismatchException(version, coredata_version)
     return obj
 
 


Test patch: