Repository: mesonbuild/meson

Issue:
Cross-compiling broken
Yesterday it worked, now fails:

```
Compiler: linux-gcc
Platform: 64 bit
Buildtype: debug

The Meson build system
Version: 0.38.0.dev1
Source dir: F:\avian\hello-c
Build dir: F:\avian\hello-c\build\linux-gcc-64-debug
Build type: cross build
Project name: hello
Native c compiler: gcc (gcc 5.4.0)
Cross c compiler: c:\cygwin-cross\bin\x86_64-pc-linux-gnu-gcc (gcc 4.8.2)
Host machine cpu family: x86_64
Host machine cpu: x86_64
Target machine cpu family: x86_64
Target machine cpu: x86_64
Build machine cpu family: x86_64
Build machine cpu: x86_64

Meson encountered an error in file meson.build, line 10, column 2:
Pkg-config not found.
```

meson.build:
```
project('hello', ['c'], license: 'Apache',
default_options: [
  'warning_level=2',
  'default_library=static',
])

if meson.get_compiler('c').get_id() == 'msvc'
  zlib = subproject('zlib').get_variable('zlib_dep')
else
  zlib = dependency('zlib')
endif

bin2c = subproject('bin2c').get_variable('bin2c')

if target_machine.system() == 'windows'
  link_args = ['-static']
else
  link_args = []
endif

exe = executable('hello',
  sources: [
    'hello.c',
    bin2c.process('../../hello.zip', extra_args: ['-n', 'zip_file'])
  ],
  link_args: link_args,
  dependencies: zlib)

```
crossfile:
```
[host_machine]
system     = 'linux'
cpu_family = 'x86_64'
cpu        = 'x86_64'
endian     = 'little'

[binaries]
c          = 'c:\\cygwin-cross\\bin\\x86_64-pc-linux-gnu-gcc'
cpp        = 'c:\\cygwin-cross\\bin\\x86_64-pc-linux-gnu-g++'
ar         = 'c:\\cygwin-cross\\bin\\x86_64-pc-linux-gnu-ar'
strip      = 'c:\\cygwin-cross\\bin\\x86_64-pc-linux-gnu-strip'
pkgconfig  = 'c:\\cygwin-cross\\bin\\x86_64-pc-linux-gnu-pkg-config'

[properties]
root       = 'c:\\cygwin-cross\\usr\\x86_64-pc-linux-gnu\\sys-root'
```



Discussion:
git revert 8e9f0c9
fixes this
Can you verify that the pkg-config executable specified exists on your machine and is runnable?
Yes, it exists and runnable:
```
>c:\cygwin-cross\bin\x86_64-pc-linux-gnu-pkg-config --version
0.28
```

But `shutil.which` does not find it without `.exe` extension:
```
>>> print(shutil.which('c:\\cygwin-cross\\bin\\x86_64-pc-linux-gnu-pkg-config'))    
None                                                                                
>>> print(shutil.which('c:\\cygwin-cross\\bin\\x86_64-pc-linux-gnu-pkg-config.exe'))
c:\cygwin-cross\bin\x86_64-pc-linux-gnu-pkg-config.exe                              
```

I think the only reliable way to check for existence is `popen` and catch not found exception.
Or better - do not check here at all, postpone when it will really needed.

> But shutil.which does not find it without .exe extension:

We already handle this in the `ExternalProgram`, so we should probably use that everywhere we might get an absolute path instead of `shutil.which`:

```
# On Windows, if name is an absolute path, we need the extension too
for ext in self.windows_exts:                                       
    fullpath = '{}.{}'.format(name, ext)
    if os.path.exists(fullpath):                                    
        return [fullpath]                                           
```

Resolving patch:
diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py
--- a/mesonbuild/dependencies.py
+++ b/mesonbuild/dependencies.py
@@ -119,10 +119,15 @@ def __init__(self, name, environment, kwargs):
                 if self.required:
                     raise DependencyException('Pkg-config binary missing from cross file')
             else:
-                potential_pkgbin = environment.cross_info.config['binaries'].get('pkgconfig', 'non_existing_binary')
-                if shutil.which(potential_pkgbin):
-                    self.pkgbin = potential_pkgbin
+                potential_pkgbin = ExternalProgram(environment.cross_info.config['binaries'].get('pkgconfig', 'non_existing_binary'),
+                                                   silent=True)
+                if potential_pkgbin.found():
+                    # FIXME, we should store all pkg-configs in ExternalPrograms.
+                    # However that is too destabilizing a change to do just before release.
+                    self.pkgbin = potential_pkgbin.get_command()[0]
                     PkgConfigDependency.class_pkgbin = self.pkgbin
+                else:
+                    mlog.debug('Cross pkg-config %s not found.' % potential_pkgbin.name)
         # Only search for the native pkg-config the first time and
         # store the result in the class definition
         elif PkgConfigDependency.class_pkgbin is None:


Test patch: