Repository: mesonbuild/meson

Issue:
[0.60.2] import('cmake') cannot handle cmake not being on path. 
Meson just says it cannot find cmake although it has been passed via a native/cross file as: 
```
[binaries]
...
cmake = 'E:/vcpkg_cache/downloads/tools/cmake-3.21.1-windows/cmake-3.21.1-windows-i386/bin/cmake.exe'
....
```

CI run (https://dev.azure.com/vcpkg/public/_build/results?buildId=64620&view=logs&jobId=7922e5c4-0103-5f8f-ad17-45ce9bb98e80&j=878666d5-db33-5b27-9e7d-b0c7ee352005)

The fact that meson assumes stuff to be on path although full paths are passed seems to be a consistent error...... (same goes for ninja)



Discussion:
I am unable to reproduce this. My setup: In `test cases/cmake/1 basic`; `meson build --native-file native.ini` with:

```ini
[binaries]

cmake = '/home/daniel/prefix/builds/cmake/bin/cmake'
```

I made sure to uninstall my system CMake and I have no other CMake installation in my `PATH`.

```
he Meson build system
Version: 0.60.2
Source dir: /home/daniel/projects/meson/test cases/cmake/1 basic
Build dir: /home/daniel/projects/meson/test cases/cmake/1 basic/build
Build type: native build
Project name: cmakeSubTest
Project version: undefined
C compiler for the host machine: cc (gcc 11.1.0 "cc (GCC) 11.1.0")
C linker for the host machine: cc ld.bfd 2.36.1
C++ compiler for the host machine: c++ (gcc 11.1.0 "c++ (GCC) 11.1.0")
C++ linker for the host machine: c++ ld.bfd 2.36.1
Host machine cpu family: x86_64
Host machine cpu: x86_64

Executing subproject cmMod method cmake

cmMod| Found CMake: /home/daniel/prefix/builds/cmake/bin/cmake (3.21.20210708)

| Configuring the build directory with CMake version 3.21.20210708
| Running CMake with: -G Ninja -DCMAKE_INSTALL_PREFIX=/usr/local
|   - build directory:          /home/daniel/projects/meson/test cases/cmake/1 basic/build/subprojects/cmMod/__CMake_build
|   - source directory:         /home/daniel/projects/meson/test cases/cmake/1 basic/subprojects/cmMod
|   - toolchain file:           /home/daniel/projects/meson/test cases/cmake/1 basic/build/subprojects/cmMod/__CMake_build/CMakeMesonToolchainFile.cmake
|   - preload file:             /home/daniel/projects/meson/test cases/cmake/1 basic/build/meson-private/data/preload.cmake
|   - trace args:               --trace-expand --trace-format=json-v1 --no-warn-unused-cli --trace-redirect=cmake_trace.txt
|   - disabled policy warnings: [CMP0025, CMP0047, CMP0056, CMP0060, CMP0065, CMP0066, CMP0067, CMP0082, CMP0089, CMP0102]
```

Do you have a minimal test case, or can you at least provide a log file with only the meson failure? The link you provided is not really helpful since I have to dig through 10k lines of output.
Just download the artifacts. Those contain the failing port. Alternativley, try building toml++ with meson. I will provide the exact error msg as soon as i get on a pc.
[config-x64-linux-dbg-out.log](https://github.com/mesonbuild/meson/files/7729524/config-x64-linux-dbg-out.log)
[meson-native-x64-linux.log](https://github.com/mesonbuild/meson/files/7729526/meson-native-x64-linux.log)
[meson-native-x64-linux-debug.log](https://github.com/mesonbuild/meson/files/7729528/meson-native-x64-linux-debug.log)


Should be fixed with #9737.

Resolving patch:
diff --git a/mesonbuild/modules/cmake.py b/mesonbuild/modules/cmake.py
--- a/mesonbuild/modules/cmake.py
+++ b/mesonbuild/modules/cmake.py
@@ -34,7 +34,6 @@
     InvalidArguments,
     InterpreterException,
 )
-from ..programs import ExternalProgram
 
 
 COMPATIBILITIES = ['AnyNewerVersion', 'SameMajorVersion', 'SameMinorVersion', 'ExactVersion']
@@ -233,11 +232,11 @@ def detect_voidp_size(self, env):
 
         return compiler.sizeof('void *', '', env)
 
-    def detect_cmake(self):
+    def detect_cmake(self, state):
         if self.cmake_detected:
             return True
 
-        cmakebin = ExternalProgram('cmake', silent=False)
+        cmakebin = state.find_program('cmake', silent=False)
         if not cmakebin.found():
             return False
 
@@ -272,7 +271,7 @@ def write_basic_package_version_file(self, state, _args, kwargs):
         if compatibility not in COMPATIBILITIES:
             raise mesonlib.MesonException('compatibility must be either AnyNewerVersion, SameMajorVersion or ExactVersion.')
 
-        if not self.detect_cmake():
+        if not self.detect_cmake(state):
             raise mesonlib.MesonException('Unable to find cmake')
 
         pkgroot = pkgroot_name = kwargs.get('install_dir', None)
diff --git a/mesonbuild/modules/dlang.py b/mesonbuild/modules/dlang.py
--- a/mesonbuild/modules/dlang.py
+++ b/mesonbuild/modules/dlang.py
@@ -22,7 +22,6 @@
 from .. import dependencies
 from .. import mlog
 from ..mesonlib import Popen_safe, MesonException
-from ..programs import ExternalProgram
 
 class DlangModule(ExtensionModule):
     class_dubbin = None
@@ -34,7 +33,7 @@ def __init__(self, interpreter):
             'generate_dub_file': self.generate_dub_file,
         })
 
-    def _init_dub(self):
+    def _init_dub(self, state):
         if DlangModule.class_dubbin is None:
             self.dubbin = dependencies.DubDependency.class_dubbin
             DlangModule.class_dubbin = self.dubbin
@@ -42,7 +41,7 @@ def _init_dub(self):
             self.dubbin = DlangModule.class_dubbin
 
         if DlangModule.class_dubbin is None:
-            self.dubbin = self.check_dub()
+            self.dubbin = self.check_dub(state)
             DlangModule.class_dubbin = self.dubbin
         else:
             self.dubbin = DlangModule.class_dubbin
@@ -53,7 +52,7 @@ def _init_dub(self):
 
     def generate_dub_file(self, state, args, kwargs):
         if not DlangModule.init_dub:
-            self._init_dub()
+            self._init_dub(state)
 
         if len(args) < 2:
             raise MesonException('Missing arguments')
@@ -109,8 +108,8 @@ def _call_dubbin(self, args, env=None):
         p, out = Popen_safe(self.dubbin.get_command() + args, env=env)[0:2]
         return p.returncode, out.strip()
 
-    def check_dub(self):
-        dubbin = ExternalProgram('dub', silent=True)
+    def check_dub(self, state):
+        dubbin = state.find_program('dub', silent=True)
         if dubbin.found():
             try:
                 p, out = Popen_safe(dubbin.get_command() + ['--version'])[0:2]


Test patch: