@@ -528,7 +528,13 @@ def _bool(value: Any, name: str) -> bool:
528
528
raise ConfigError (f'Configuration entry "{ name } " must be a boolean' )
529
529
return value
530
530
531
+ def _str (value : Any , name : str ) -> str :
532
+ if not isinstance (value , str ):
533
+ raise ConfigError (f'Configuration entry "{ name } " must be a string' )
534
+ return value
535
+
531
536
scheme = _table ({
537
+ 'cli' : _str ,
532
538
'limited-api' : _bool ,
533
539
'args' : _table ({
534
540
name : _strings for name in _MESON_ARGS_KEYS
@@ -607,7 +613,22 @@ def __init__( # noqa: C901
607
613
self ._meson_args : MesonArgs = collections .defaultdict (list )
608
614
self ._limited_api = False
609
615
610
- _check_meson_version ()
616
+ # load pyproject.toml
617
+ pyproject = tomllib .loads (self ._source_dir .joinpath ('pyproject.toml' ).read_text ())
618
+
619
+ # load meson args from pyproject.toml
620
+ pyproject_config = _validate_pyproject_config (pyproject )
621
+ for key , value in pyproject_config .get ('args' , {}).items ():
622
+ self ._meson_args [key ].extend (value )
623
+
624
+ # meson arguments from the command line take precedence over
625
+ # arguments from the configuration file thus are added later
626
+ if meson_args :
627
+ for key , value in meson_args .items ():
628
+ self ._meson_args [key ].extend (value )
629
+
630
+ # determine command to invoke meson
631
+ self ._meson = _get_meson_command (pyproject_config .get ('cli' ))
611
632
612
633
self ._ninja = _env_ninja_command ()
613
634
if self ._ninja is None :
@@ -645,20 +666,6 @@ def __init__( # noqa: C901
645
666
self ._meson_cross_file .write_text (cross_file_data )
646
667
self ._meson_args ['setup' ].extend (('--cross-file' , os .fspath (self ._meson_cross_file )))
647
668
648
- # load pyproject.toml
649
- pyproject = tomllib .loads (self ._source_dir .joinpath ('pyproject.toml' ).read_text ())
650
-
651
- # load meson args from pyproject.toml
652
- pyproject_config = _validate_pyproject_config (pyproject )
653
- for key , value in pyproject_config .get ('args' , {}).items ():
654
- self ._meson_args [key ].extend (value )
655
-
656
- # meson arguments from the command line take precedence over
657
- # arguments from the configuration file thus are added later
658
- if meson_args :
659
- for key , value in meson_args .items ():
660
- self ._meson_args [key ].extend (value )
661
-
662
669
# write the native file
663
670
native_file_data = textwrap .dedent (f'''
664
671
[binaries]
@@ -740,7 +747,7 @@ def _configure(self, reconfigure: bool = False) -> None:
740
747
]
741
748
if reconfigure :
742
749
setup_args .insert (0 , '--reconfigure' )
743
- self ._run ([ 'meson' , 'setup' , * setup_args ])
750
+ self ._run (self . _meson + [ 'setup' , * setup_args ])
744
751
745
752
@property
746
753
def _build_command (self ) -> List [str ]:
@@ -750,7 +757,7 @@ def _build_command(self) -> List[str]:
750
757
# environment. Using the --ninja-args option allows to
751
758
# provide the exact same semantics for the compile arguments
752
759
# provided by the users.
753
- cmd = [ 'meson' , 'compile' ]
760
+ cmd = self . _meson + [ 'compile' ]
754
761
args = list (self ._meson_args ['compile' ])
755
762
if args :
756
763
cmd .append (f'--ninja-args={ args !r} ' )
@@ -824,7 +831,7 @@ def version(self) -> str:
824
831
def sdist (self , directory : Path ) -> pathlib .Path :
825
832
"""Generates a sdist (source distribution) in the specified directory."""
826
833
# generate meson dist file
827
- self ._run ([ 'meson' , 'dist' , '--allow-dirty' , '--no-tests' , '--formats' , 'gztar' , * self ._meson_args ['dist' ]])
834
+ self ._run (self . _meson + [ 'dist' , '--allow-dirty' , '--no-tests' , '--formats' , 'gztar' , * self ._meson_args ['dist' ]])
828
835
829
836
# move meson dist file to output path
830
837
dist_name = f'{ self .name } -{ self .version } '
@@ -919,6 +926,34 @@ def _parse_version_string(string: str) -> Tuple[int, ...]:
919
926
return (0 , )
920
927
921
928
929
+ def _get_meson_command (
930
+ meson_tool : str | None = None , * , version : str = _MESON_REQUIRED_VERSION
931
+ ) -> List [str ]:
932
+ """Return the command to invoke meson.
933
+ Uses the MESON env var if set, else the `cli` entry in pyproject.toml if given,
934
+ else the standard `meson` executable.
935
+ """
936
+ _meson = os .environ .get ('MESON' )
937
+ if _meson is None :
938
+ if meson_tool is not None :
939
+ _meson = str (pathlib .Path (meson_tool ).resolve ())
940
+ else :
941
+ _meson = 'meson'
942
+
943
+ # If the specified Meson string ends in `.py`, we run it with the current
944
+ # Python executable. This avoids problems for users on Windows, where
945
+ # making a script executable isn't enough to get it to run when invoked
946
+ # directly. For packages that vendor a forked Meson, the `meson.py` in the
947
+ # root of the Meson repo can be used this way.
948
+ if _meson .endswith (".py" ):
949
+ meson_cli = [sys .executable , _meson ]
950
+ else :
951
+ meson_cli = [_meson ]
952
+
953
+ _check_meson_version (meson_cli , version = version )
954
+ return meson_cli
955
+
956
+
922
957
def _env_ninja_command (* , version : str = _NINJA_REQUIRED_VERSION ) -> Optional [str ]:
923
958
"""Returns the path to ninja, or None if no ninja found."""
924
959
required_version = _parse_version_string (version )
@@ -933,7 +968,7 @@ def _env_ninja_command(*, version: str = _NINJA_REQUIRED_VERSION) -> Optional[st
933
968
return None
934
969
935
970
936
- def _check_meson_version (* , version : str = _MESON_REQUIRED_VERSION ) -> None :
971
+ def _check_meson_version (meson_cli : List [ str ], / , * , version : str = _MESON_REQUIRED_VERSION ) -> None :
937
972
"""Check that the meson executable in the path has an appropriate version.
938
973
939
974
The meson Python package is a dependency of the meson-python
@@ -944,7 +979,7 @@ def _check_meson_version(*, version: str = _MESON_REQUIRED_VERSION) -> None:
944
979
945
980
"""
946
981
required_version = _parse_version_string (version )
947
- meson_version = subprocess .run ([ 'meson' , '--version' ], check = False , text = True , capture_output = True ).stdout
982
+ meson_version = subprocess .run (meson_cli + [ '--version' ], check = False , text = True , capture_output = True ).stdout
948
983
if _parse_version_string (meson_version ) < required_version :
949
984
raise ConfigError (f'Could not find meson version { version } or newer, found { meson_version } .' )
950
985
0 commit comments