Repository: mesonbuild/meson

Issue:
wxWidgets dependecy on Windows (MSYS2-MinGW) not detected
As mentioned in #27.

Currently it seems that wxWidgets's `wx-config` is not detected when wxWidgets is a dependency. This is running inside a MSYS2-MinGW64 shell which installed MSYS2-MinGW64-wxWidgets package. It ships with a `wx-config` utility.

```
$ meson.py build
The Meson build system
Version: 0.38.1
Source dir: C:/msys64/home/fzwoc/code/test
Build dir: C:/msys64/home/fzwoc/code/test/build
Build type: native build
Project name: Test
Native cpp compiler: c++ (gcc 6.3.0)
Build machine cpu family: x86_64
Build machine cpu: x86_64
Found wx-config: NO
Neither wx-config-3.0 nor wx-config found; can't detect dependency

Meson encountered an error in file meson.build, line 3, column 0:
Dependency "wxwidgets" not found
```

The utility is found from the same shell meson was run just fine.

```
$ which wx-config
/mingw64/bin/wx-config
$ wx-config --version
3.0.2
```

Perhaps MSYS2-MinGW64's python interpreter has a different search path than the real shell?



Discussion:
I can't reproduce this. It works fine for me:

```console
$ pacman -S mingw64/mingw-w64-x86_64-wxWidgets
$ ../..//../meson.py build
The Meson build system
Version: 0.38.1
Source dir: /c/Users/nirbheek/projects/meson.git/test cases/frameworks/9 wxwidgets
Build dir: /c/Users/nirbheek/projects/meson.git/test cases/frameworks/9 wxwidgets/build
Build type: native build
Project name: wxwidgets test
Native cpp compiler: c++ (gcc 6.3.0)
Build machine cpu family: x86_64
Build machine cpu: x86_64
Found wx-config: /mingw64/bin/wx-config (3.0.2)
Dependency wxwidgets found: YES
Build targets in project: 1
$ which python
/usr/bin/python
$ which wx-config
/mingw64/bin/wx-config
$ wx-config --version
3.0.2
```
Scratch that, I can reproduce it if I use the Windows-Native Python:

```console
$ /c/Python35/python.exe ../..//../meson.py build
The Meson build system
Version: 0.38.1
Source dir: C:\Users\nirbheek\projects\meson.git\test cases\frameworks\9 wxwidgets
Build dir: C:\Users\nirbheek\projects\meson.git\test cases\frameworks\9 wxwidgets\build
Build type: native build
Project name: wxwidgets test
Native cpp compiler: c++ (gcc 6.3.0)
Build machine cpu family: x86_64
Build machine cpu: x86_64
Found wx-config: NO
Neither wx-config-3.0 nor wx-config found; can't detect dependency
Build targets in project: 0
```

This is not a Meson bug, you will need to install the Python inside MSYS2-MinGW64 and use that otherwise it can't know about the MSYS2 "virtual" file paths. The values in `PATH` are correct, but they don't make sense to the native-windows Python:

```console
$ echo $PATH
/mingw64/bin:/usr/local/bin:/usr/bin:/bin:/c/Windows/System32:/c/Windows:/c/Windows/System32/Wbem:/c/Windows/System32/WindowsPowerShell/v1.0/:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl
```

Perhaps it's an MSYS2 bug since at least MSYS1 used to translate these paths to versions that native-windows applications could find. As it stands, it is very difficult for native-windows and MSYS2 binaries to work together.
Could indeed be an MSYS2 bug. However I'm using the MSYS2-MinGW python.

```
$ which python
/mingw64/bin/python
```

I tried to use the MSYS2 python instead of the MSYS2-MinGW64:
```
$ /usr/bin/python /mingw64/bin/meson.py build
Traceback (most recent call last):
  File "/mingw64/bin/meson.py", line 17, in <module>
    from mesonbuild import mlog, mesonmain, mesonlib
ImportError: No module named 'mesonbuild'
```

But I guess this is not how it works..
Yeah, looks like the MSYS2-MinGW64 python is totally broken:

```console
$ which wx-config
/mingw64/bin/wx-config
$ echo $PATH
/mingw64/bin:/usr/local/bin:/usr/bin:/bin:/c/Windows/System32:/c/Windows:/c/Windows/System32/Wbem:/c/Windows/System32/WindowsPowerShell/v1.0/:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl
$ which python3
/mingw64/bin/python3
$ python3
Python 3.5.2 (default, Nov  7 2016, 14:06:02)  [GCC 6.2.0 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess
>>> subprocess.check_call(['wx-config', '--version'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:/msys64/mingw64/lib/python3.5\subprocess.py", line 576, in check_call
    retcode = call(*popenargs, **kwargs)
  File "C:/msys64/mingw64/lib/python3.5\subprocess.py", line 557, in call
    with Popen(*popenargs, **kwargs) as p:
  File "C:/msys64/mingw64/lib/python3.5\subprocess.py", line 947, in __init__
    restore_signals, start_new_session)
  File "C:/msys64/mingw64/lib/python3.5\subprocess.py", line 1224, in _execute_child
    startupinfo)
FileNotFoundError: [WinError 2] The system cannot find the file specified
>>> exit()
Error in atexit._run_exitfuncs:
OSError: [Errno -1] Windows Error 0xffffffff
```

This is convincing me even more that no one should use MSYS2 since it is very poorly maintained. :)

I think your best bet is to clone the meson git repository, and directly run `meson.py` with the MSYS2 python. Don't run `setup.py`.

You won't be able to run the meson installed via MSYS2-MinGW64 because the library paths are incorrect.

... alternatively, ditch MSYS2, use windows-native wxWidgets, and do everything in `cmd.exe` or in powershell. I honestly don't know which is more painful. ;)
This is almost certainly an MSYS2 bug. 

```console
$ python3 -c 'import os; print(os.environ["PATH"])'
C:\msys64\mingw64\bin;C:\msys64\usr\local\bin;C:\msys64\usr\bin;[...]
$ python3 -c "import os; print(os.path.isfile('C:\\msys64\\mingw64\\bin\\wx-config'))"
False
$ python3 -c "import os; print(os.path.isfile('C:\\\\msys64\\\\mingw64\\bin\\\\wx-config'))"
False
$ python3 -c 'import os; print(os.sep)'
/
$ python3 -c "import os; print(os.path.isfile('C:/msys64/mingw64/bin/wx-config'))"
True
```

So either the value of `os.sep` built into Python is wrong, or the value of `PATH` set for python3 by the shell is wrong.
Ah crap. MSYS2 sounded like the most convenient cross compile / package manager approach to me. I will look into something else..

Closing this bug as there seems nothing wrong with mesonbuild.
In fact the problem has nothing to do with PATH. It's because subprocess.Popen() under Windows cannot execute POSIX shell script (wx-config) directly. A possible solution:

>mesonbuild/dependencies/ui.py
  
    # p, out = Popen_safe([wxc, '--version'])[0:2]
    p, out = Popen_safe(['sh', wxc, '--version'])[0:2]
    # ... and the same for --cflags and --libs
He's right, can this issue be reopened?

I've looked at the code (it isn't in `mesonbuild/dependencies/ui.py` anymore) and got it to work by letting the check test everything again with `sh` prefixed. I'm not sure if this has security concerns or might break something on other platforms though?
Meson has code for finding shell scripts, it's used by default when you use `find_program()` inside a build file. See: `mesonbuild/dependencies/base.py:ExternalProgram`

Resolving patch:
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -419,6 +419,14 @@ def find_config(self, versions=None):
 
         best_match = (None, None)
         for tool in tools:
+            if len(tool) == 1:
+                # In some situations the command can't be directly executed.
+                # For example Shell scripts need to be called through sh on
+                # Windows (see issue #1423).
+                potential_bin = ExternalProgram(tool[0], silent=True)
+                if not potential_bin.found():
+                    continue
+                tool = potential_bin.get_command()
             try:
                 p, out = Popen_safe(tool + ['--version'])[:2]
             except (FileNotFoundError, PermissionError):
@@ -459,7 +467,7 @@ def report_config(self, version, req_version):
             elif req_version:
                 found_msg.append('need {!r}'.format(req_version))
         else:
-            found_msg += [mlog.green('YES'), '({})'.format(shutil.which(self.config[0])), version]
+            found_msg += [mlog.green('YES'), '({})'.format(' '.join(self.config)), version]
 
         mlog.log(*found_msg)
 


Test patch: