From a8120eb5195ed0e7b44662f107baa23dbbda73a9 Mon Sep 17 00:00:00 2001
From: Jussi Pakkanen <jpakkane@gmail.com>
Date: Fri, 12 Feb 2016 21:12:18 +0200
Subject: [PATCH 1/9] Added plain Python sample project.

---
 run_tests.py                                  |  1 +
 test cases/python3/1 basic/gluon/__init__.py  |  0
 test cases/python3/1 basic/gluon/gluonator.py |  2 ++
 test cases/python3/1 basic/meson.build        |  9 +++++++++
 test cases/python3/1 basic/prog.py            |  9 +++++++++
 test cases/python3/1 basic/subdir/meson.build |  5 +++++
 test cases/python3/1 basic/subdir/subprog.py  | 12 ++++++++++++
 7 files changed, 38 insertions(+)
 create mode 100644 test cases/python3/1 basic/gluon/__init__.py
 create mode 100644 test cases/python3/1 basic/gluon/gluonator.py
 create mode 100644 test cases/python3/1 basic/meson.build
 create mode 100755 test cases/python3/1 basic/prog.py
 create mode 100644 test cases/python3/1 basic/subdir/meson.build
 create mode 100755 test cases/python3/1 basic/subdir/subprog.py

diff --git a/run_tests.py b/run_tests.py
index 221194993..331af7ec9 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -260,6 +260,7 @@ def detect_tests_to_run():
     all_tests.append(('objective c', gather_tests('test cases/objc'), False if not mesonlib.is_windows() else True))
     all_tests.append(('fortran', gather_tests('test cases/fortran'), False if shutil.which('gfortran') else True))
     all_tests.append(('swift', gather_tests('test cases/swift'), False if shutil.which('swiftc') else True))
+    all_tests.append(('python3', gather_tests('test cases/python3'), False if shutil.which('python3') else True))
     return all_tests
 
 def run_tests(extra_args):
diff --git a/test cases/python3/1 basic/gluon/__init__.py b/test cases/python3/1 basic/gluon/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/test cases/python3/1 basic/gluon/gluonator.py b/test cases/python3/1 basic/gluon/gluonator.py
new file mode 100644
index 000000000..b53d6ded3
--- /dev/null
+++ b/test cases/python3/1 basic/gluon/gluonator.py	
@@ -0,0 +1,2 @@
+def gluoninate():
+    return 42
diff --git a/test cases/python3/1 basic/meson.build b/test cases/python3/1 basic/meson.build
new file mode 100644
index 000000000..badd3e58c
--- /dev/null
+++ b/test cases/python3/1 basic/meson.build	
@@ -0,0 +1,9 @@
+project('python sample', 'c')
+
+py3 = find_program('python3')
+
+main = files('prog.py')
+
+test('toplevel', py3, args : main)
+
+subdir('subdir')
diff --git a/test cases/python3/1 basic/prog.py b/test cases/python3/1 basic/prog.py
new file mode 100755
index 000000000..9d95aea27
--- /dev/null
+++ b/test cases/python3/1 basic/prog.py	
@@ -0,0 +1,9 @@
+#!/usr/bin/env python3
+
+from gluon import gluonator
+import sys
+
+print('Running mainprog from root dir.')
+
+if gluonator.gluoninate() != 42:
+    sys.exit(1)
diff --git a/test cases/python3/1 basic/subdir/meson.build b/test cases/python3/1 basic/subdir/meson.build
new file mode 100644
index 000000000..3f275ad1b
--- /dev/null
+++ b/test cases/python3/1 basic/subdir/meson.build	
@@ -0,0 +1,5 @@
+submain = find_program('subprog.py')
+
+test('subdir',
+  submain,
+  env : 'PYTHONPATH=' + meson.source_root())
diff --git a/test cases/python3/1 basic/subdir/subprog.py b/test cases/python3/1 basic/subdir/subprog.py
new file mode 100755
index 000000000..08652f084
--- /dev/null
+++ b/test cases/python3/1 basic/subdir/subprog.py	
@@ -0,0 +1,12 @@
+#!/usr/bin/env python3
+
+# In order to run this program, PYTHONPATH must be set to
+# point to source root.
+
+from gluon import gluonator
+import sys
+
+print('Running mainprog from subdir.')
+
+if gluonator.gluoninate() != 42:
+    sys.exit(1)

From 98d00386b141771a62668198f36bd38b1a9e6112 Mon Sep 17 00:00:00 2001
From: Jussi Pakkanen <jpakkane@gmail.com>
Date: Fri, 12 Feb 2016 21:57:31 +0200
Subject: [PATCH 2/9] Can build a Python extension module.

---
 mesonbuild/build.py                           | 18 +++++--
 test cases/python3/2 extmodule/blaster.py     | 14 ++++++
 .../python3/2 extmodule/ext/meson.build       |  6 +++
 .../python3/2 extmodule/ext/tachyon_module.c  | 49 +++++++++++++++++++
 test cases/python3/2 extmodule/meson.build    |  9 ++++
 5 files changed, 92 insertions(+), 4 deletions(-)
 create mode 100755 test cases/python3/2 extmodule/blaster.py
 create mode 100644 test cases/python3/2 extmodule/ext/meson.build
 create mode 100644 test cases/python3/2 extmodule/ext/tachyon_module.c
 create mode 100644 test cases/python3/2 extmodule/meson.build

diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index f9e628de6..7b4f3c9ab 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -44,7 +44,9 @@ known_basic_kwargs = {'install' : True,
 
 known_shlib_kwargs = known_basic_kwargs.copy()
 known_shlib_kwargs.update({'version' : True,
-                           'soversion' : True})
+                           'soversion' : True,
+                           'name_prefix' : True,
+                           })
 
 backslash_explanation = \
 '''Compiler arguments have a backslash "\\" character. This is unfortunately not
@@ -411,6 +413,11 @@ class BuildTarget():
             if not os.path.isfile(trial):
                 raise InvalidArguments('Tried to add non-existing resource %s.' % r)
         self.resources = resources
+        if 'name_prefix' in kwargs:
+            name_prefix = kwargs['name_prefix']
+            if not isinstance(name_prefix, str):
+                raise InvalidArguments('Name prefix must be a string.')
+            self.prefix = name_prefix
 
     def get_subdir(self):
         return self.subdir
@@ -654,7 +661,8 @@ class StaticLibrary(BuildTarget):
         super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
         if len(self.sources) > 0 and self.sources[0].endswith('.cs'):
             raise InvalidArguments('Static libraries not supported for C#.')
-        self.prefix = environment.get_static_lib_prefix()
+        if not hasattr(self, 'prefix'):
+            self.prefix = environment.get_static_lib_prefix()
         self.suffix = environment.get_static_lib_suffix()
         if len(self.sources) > 0 and self.sources[0].endswith('.rs'):
             self.suffix = 'rlib'
@@ -675,11 +683,13 @@ class SharedLibrary(BuildTarget):
         self.soversion = None
         super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs);
         if len(self.sources) > 0 and self.sources[0].endswith('.cs'):
+            prefix = 'lib'
             self.suffix = 'dll'
-            self.prefix = 'lib'
         else:
-            self.prefix = environment.get_shared_lib_prefix()
+            prefix = environment.get_shared_lib_prefix()
             self.suffix = environment.get_shared_lib_suffix()
+        if not hasattr(self, 'prefix'):
+            self.prefix = prefix
         if len(self.sources) > 0 and self.sources[0].endswith('.rs'):
             self.suffix = 'rlib'
         self.importsuffix = environment.get_import_lib_suffix()
diff --git a/test cases/python3/2 extmodule/blaster.py b/test cases/python3/2 extmodule/blaster.py
new file mode 100755
index 000000000..7e1eae63a
--- /dev/null
+++ b/test cases/python3/2 extmodule/blaster.py	
@@ -0,0 +1,14 @@
+#!/usr/bin/env python3
+
+import tachyon
+import sys
+
+result = tachyon.phaserize('shoot')
+
+if not isinstance(result, int):
+    print('Returned result not an integer.')
+    sys.exit(1)
+
+if result != 1:
+    print('Returned result {} is not 1.'.format(result))
+    sys.exit(1)
diff --git a/test cases/python3/2 extmodule/ext/meson.build b/test cases/python3/2 extmodule/ext/meson.build
new file mode 100644
index 000000000..1184835d8
--- /dev/null
+++ b/test cases/python3/2 extmodule/ext/meson.build	
@@ -0,0 +1,6 @@
+pylib = shared_library('tachyon',
+  'tachyon_module.c',
+  dependencies : py3_dep,
+  name_prefix : '')
+
+pypathdir = meson.current_build_dir()
diff --git a/test cases/python3/2 extmodule/ext/tachyon_module.c b/test cases/python3/2 extmodule/ext/tachyon_module.c
new file mode 100644
index 000000000..b2592e482
--- /dev/null
+++ b/test cases/python3/2 extmodule/ext/tachyon_module.c	
@@ -0,0 +1,49 @@
+/*
+  Copyright 2016 The Meson development team
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+*/
+
+/* A very simple Python extension module. */
+
+#include <Python.h>
+#include <string.h>
+
+static PyObject* phaserize(PyObject *self, PyObject *args) {
+    const char *message;
+    int result;
+
+    if(!PyArg_ParseTuple(args, "s", &message))
+        return NULL;
+
+    result = strcmp(message, "shoot") ? 0 : 1;
+    return PyLong_FromLong(result);
+}
+
+static PyMethodDef TachyonMethods[] = {
+    {"phaserize",  phaserize, METH_VARARGS,
+     "Shoot tachyon cannons."},
+    {NULL, NULL, 0, NULL}
+};
+
+static struct PyModuleDef tachyonmodule = {
+   PyModuleDef_HEAD_INIT,
+   "tachyon",
+   NULL,
+   -1,
+   TachyonMethods
+};
+
+PyMODINIT_FUNC PyInit_tachyon(void) {
+    return PyModule_Create(&tachyonmodule);
+}
diff --git a/test cases/python3/2 extmodule/meson.build b/test cases/python3/2 extmodule/meson.build
new file mode 100644
index 000000000..a86a1222c
--- /dev/null
+++ b/test cases/python3/2 extmodule/meson.build	
@@ -0,0 +1,9 @@
+project('Python extension module', 'c')
+
+py3_dep = dependency('python3')
+
+subdir('ext')
+
+test('extmod',
+  find_program('blaster.py'),
+  env : ['PYTHONPATH=' + pypathdir])

From 738f7f860c08f1322d09c72a3db44308f4a16404 Mon Sep 17 00:00:00 2001
From: Jussi Pakkanen <jpakkane@gmail.com>
Date: Fri, 12 Feb 2016 22:57:38 +0200
Subject: [PATCH 3/9] Added Cython sample project.

---
 test cases/python3/3 cython/cytest.py         | 23 ++++++++++++++++++
 .../python3/3 cython/libdir/cstorer.pxd       |  9 +++++++
 .../python3/3 cython/libdir/meson.build       | 18 ++++++++++++++
 test cases/python3/3 cython/libdir/storer.c   | 24 +++++++++++++++++++
 test cases/python3/3 cython/libdir/storer.h   |  8 +++++++
 test cases/python3/3 cython/libdir/storer.pyx | 16 +++++++++++++
 test cases/python3/3 cython/meson.build       | 12 ++++++++++
 7 files changed, 110 insertions(+)
 create mode 100755 test cases/python3/3 cython/cytest.py
 create mode 100644 test cases/python3/3 cython/libdir/cstorer.pxd
 create mode 100644 test cases/python3/3 cython/libdir/meson.build
 create mode 100644 test cases/python3/3 cython/libdir/storer.c
 create mode 100644 test cases/python3/3 cython/libdir/storer.h
 create mode 100644 test cases/python3/3 cython/libdir/storer.pyx
 create mode 100644 test cases/python3/3 cython/meson.build

diff --git a/test cases/python3/3 cython/cytest.py b/test cases/python3/3 cython/cytest.py
new file mode 100755
index 000000000..43443dc66
--- /dev/null
+++ b/test cases/python3/3 cython/cytest.py	
@@ -0,0 +1,23 @@
+#!/usr/bin/env python3
+
+from storer import Storer
+import sys
+
+s = Storer()
+
+if s.get_value() != 0:
+    print('Initial value incorrect.')
+    sys.exit(1)
+
+s.set_value(42)
+
+if s.get_value() != 42:
+    print('Setting value failed.')
+    sys.exit(1)
+
+try:
+    s.set_value('not a number')
+    print('Using wrong argument type did not fail.')
+    sys.exit(1)
+except TypeError:
+    pass
diff --git a/test cases/python3/3 cython/libdir/cstorer.pxd b/test cases/python3/3 cython/libdir/cstorer.pxd
new file mode 100644
index 000000000..7b730fc75
--- /dev/null
+++ b/test cases/python3/3 cython/libdir/cstorer.pxd	
@@ -0,0 +1,9 @@
+
+cdef extern from "storer.h":
+    ctypedef struct Storer:
+        pass
+
+    Storer* storer_new();
+    void storer_destroy(Storer *s);
+    int storer_get_value(Storer *s);
+    void storer_set_value(Storer *s, int v);
diff --git a/test cases/python3/3 cython/libdir/meson.build b/test cases/python3/3 cython/libdir/meson.build
new file mode 100644
index 000000000..e5cfc8604
--- /dev/null
+++ b/test cases/python3/3 cython/libdir/meson.build	
@@ -0,0 +1,18 @@
+pxd_c = custom_target('cstorer_pxd',
+  output : 'cstorer_pxd.c',
+  input : 'cstorer.pxd',
+  command : [cython, '@INPUT@', '-o', '@OUTPUT@'],
+)
+
+pyx_c = custom_target('storer_pyx',
+  output : 'storer_pyx.c',
+  input : 'storer.pyx',
+  command : [cython, '@INPUT@', '-o', '@OUTPUT@'],
+)
+
+slib = shared_library('storer',
+  'storer.c', pxd_c, pyx_c,
+  name_prefix : '',
+  dependencies : py3_dep)
+
+pydir = meson.current_build_dir()
diff --git a/test cases/python3/3 cython/libdir/storer.c b/test cases/python3/3 cython/libdir/storer.c
new file mode 100644
index 000000000..0199bb850
--- /dev/null
+++ b/test cases/python3/3 cython/libdir/storer.c	
@@ -0,0 +1,24 @@
+#include"storer.h"
+#include<stdlib.h>
+
+struct _Storer {
+    int value;
+};
+
+Storer* storer_new() {
+    Storer *s = malloc(sizeof(struct _Storer));
+    s->value = 0;
+    return s;
+}
+
+void storer_destroy(Storer *s) {
+    free(s);
+}
+
+int storer_get_value(Storer *s) {
+    return s->value;
+}
+
+void storer_set_value(Storer *s, int v) {
+    s->value = v;
+}
diff --git a/test cases/python3/3 cython/libdir/storer.h b/test cases/python3/3 cython/libdir/storer.h
new file mode 100644
index 000000000..4f7191711
--- /dev/null
+++ b/test cases/python3/3 cython/libdir/storer.h	
@@ -0,0 +1,8 @@
+#pragma once
+
+typedef struct _Storer Storer;
+
+Storer* storer_new();
+void storer_destroy(Storer *s);
+int storer_get_value(Storer *s);
+void storer_set_value(Storer *s, int v);
diff --git a/test cases/python3/3 cython/libdir/storer.pyx b/test cases/python3/3 cython/libdir/storer.pyx
new file mode 100644
index 000000000..6ad6830e3
--- /dev/null
+++ b/test cases/python3/3 cython/libdir/storer.pyx	
@@ -0,0 +1,16 @@
+cimport cstorer
+
+cdef class Storer:
+    cdef cstorer.Storer* _c_storer
+
+    def __cinit__(self):
+        self._c_storer = cstorer.storer_new()
+
+    def __dealloc__(self):
+        cstorer.storer_destroy(self._c_storer)
+
+    cpdef int get_value(self):
+        return cstorer.storer_get_value(self._c_storer)
+
+    cpdef void set_value(self, int value):
+        cstorer.storer_set_value(self._c_storer, value)
diff --git a/test cases/python3/3 cython/meson.build b/test cases/python3/3 cython/meson.build
new file mode 100644
index 000000000..2d5948e26
--- /dev/null
+++ b/test cases/python3/3 cython/meson.build	
@@ -0,0 +1,12 @@
+project('cython', 'c',
+  default_options : ['warning_level=3'])
+
+cython = find_program('cython3')
+py3_dep = dependency('python3')
+
+subdir('libdir')
+
+test('cython tester',
+  find_program('cytest.py'),
+  env : ['PYTHONPATH=' + pydir]
+)

From 16b9a522352560f44d418053af9e795c61efd691 Mon Sep 17 00:00:00 2001
From: Jussi Pakkanen <jpakkane@gmail.com>
Date: Sun, 14 Feb 2016 18:32:58 +0200
Subject: [PATCH 4/9] Fix cython to work on platforms other than latest Ubuntu.

---
 test cases/python3/3 cython/libdir/meson.build | 8 +-------
 test cases/python3/3 cython/libdir/storer.pyx  | 2 +-
 2 files changed, 2 insertions(+), 8 deletions(-)

diff --git a/test cases/python3/3 cython/libdir/meson.build b/test cases/python3/3 cython/libdir/meson.build
index e5cfc8604..baa4c1dbf 100644
--- a/test cases/python3/3 cython/libdir/meson.build	
+++ b/test cases/python3/3 cython/libdir/meson.build	
@@ -1,9 +1,3 @@
-pxd_c = custom_target('cstorer_pxd',
-  output : 'cstorer_pxd.c',
-  input : 'cstorer.pxd',
-  command : [cython, '@INPUT@', '-o', '@OUTPUT@'],
-)
-
 pyx_c = custom_target('storer_pyx',
   output : 'storer_pyx.c',
   input : 'storer.pyx',
@@ -11,7 +5,7 @@ pyx_c = custom_target('storer_pyx',
 )
 
 slib = shared_library('storer',
-  'storer.c', pxd_c, pyx_c,
+  'storer.c', pyx_c,
   name_prefix : '',
   dependencies : py3_dep)
 
diff --git a/test cases/python3/3 cython/libdir/storer.pyx b/test cases/python3/3 cython/libdir/storer.pyx
index 6ad6830e3..ed551dc5f 100644
--- a/test cases/python3/3 cython/libdir/storer.pyx	
+++ b/test cases/python3/3 cython/libdir/storer.pyx	
@@ -12,5 +12,5 @@ cdef class Storer:
     cpdef int get_value(self):
         return cstorer.storer_get_value(self._c_storer)
 
-    cpdef void set_value(self, int value):
+    cpdef set_value(self, int value):
         cstorer.storer_set_value(self._c_storer, value)

From 98d3fb53725cf961b554a4f44e64975be896eeeb Mon Sep 17 00:00:00 2001
From: Jussi Pakkanen <jpakkane@gmail.com>
Date: Sun, 21 Feb 2016 14:51:36 +0200
Subject: [PATCH 5/9] Extract python3 dependency information from the current
 process if it is not available in pkg-config.

---
 .gitignore                 |  2 ++
 mesonbuild/dependencies.py | 39 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+)

diff --git a/.gitignore b/.gitignore
index 1e42da4ea..1a49bc18a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,7 @@
 /.project
 /.pydevproject
+/.settings
+/.cproject
 
 __pycache__
 /install dir
diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py
index b89bc11b0..6171c41ed 100644
--- a/mesonbuild/dependencies.py
+++ b/mesonbuild/dependencies.py
@@ -21,6 +21,7 @@
 
 import re
 import os, stat, glob, subprocess, shutil
+import sysconfig
 from . coredata import MesonException
 from . import mlog
 from . import mesonlib
@@ -1073,6 +1074,43 @@ class ThreadDependency(Dependency):
     def need_threads(self):
         return True
 
+class Python3Dependency(Dependency):
+    def __init__(self, environment, kwargs):
+        super().__init__()
+        self.is_found = False
+        try:
+            pkgdep = PkgConfigDependency('python3', environment, kwargs)
+            if pkgdep.found():
+                self.cargs = pkgdep.cargs
+                self.libs = pkgdep.libs
+                self.is_found = True
+                return
+        except Exception:
+            pass
+        if not self.is_found:
+            if mesonlib.is_windows():
+                inc = sysconfig.get_path('include')
+                platinc = sysconfig.get_path('platinclude')
+                self.cargs = ['-I' + inc]
+                if inc != platinc:
+                    self.cargs.append('-I' + platinc)
+                # Nothing exposes this directly that I coulf find
+                basedir = sysconfig.get_config_var('base')
+                vernum = sysconfig.get_config_var('py_version_nodot')
+                self.libs = ['-L{}/libs'.format(basedir),
+                             '-lpython{}'.format(vernum)]
+                self.is_found = True
+        if self.is_found:
+            mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'))
+        else:
+            mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.red('NO'))
+
+    def get_compile_args(self):
+        return self.cargs
+
+    def get_link_args(self):
+        return self.libs
+
 def get_dep_identifier(name, kwargs):
     elements = [name]
     modlist = kwargs.get('modules', [])
@@ -1123,4 +1161,5 @@ packages = {'boost': BoostDependency,
             'sdl2' : SDL2Dependency,
             'gl' : GLDependency,
             'threads' : ThreadDependency,
+            'python3' : Python3Dependency,
            }

From a04c33e12527d3ed7a07dce0380afabb46cf4f3d Mon Sep 17 00:00:00 2001
From: Jussi Pakkanen <jpakkane@gmail.com>
Date: Sun, 21 Feb 2016 17:12:09 +0200
Subject: [PATCH 6/9] Can build Python extension on OSX.

---
 mesonbuild/build.py                           | 25 +++++++++++++++----
 mesonbuild/dependencies.py                    |  9 +++++++
 .../python3/2 extmodule/ext/meson.build       | 10 +++++++-
 3 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 7b4f3c9ab..31f12b142 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -46,6 +46,7 @@ known_shlib_kwargs = known_basic_kwargs.copy()
 known_shlib_kwargs.update({'version' : True,
                            'soversion' : True,
                            'name_prefix' : True,
+                           'name_suffix' : True,
                            })
 
 backslash_explanation = \
@@ -415,9 +416,20 @@ class BuildTarget():
         self.resources = resources
         if 'name_prefix' in kwargs:
             name_prefix = kwargs['name_prefix']
-            if not isinstance(name_prefix, str):
+            if isinstance(name_prefix, list):
+                if len(name_prefix) != 0:
+                    raise InvalidArguments('Array must be empty to signify null.')
+            elif not isinstance(name_prefix, str):
                 raise InvalidArguments('Name prefix must be a string.')
             self.prefix = name_prefix
+        if 'name_suffix' in kwargs:
+            name_suffix = kwargs['name_suffix']
+            if isinstance(name_suffix, list):
+                if len(name_suffix) != 0:
+                    raise InvalidArguments('Array must be empty to signify null.')
+            elif not isinstance(name_suffix, str):
+                raise InvalidArguments('Name suffix must be a string.')
+            self.suffix = name_suffix
 
     def get_subdir(self):
         return self.subdir
@@ -684,14 +696,17 @@ class SharedLibrary(BuildTarget):
         super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs);
         if len(self.sources) > 0 and self.sources[0].endswith('.cs'):
             prefix = 'lib'
-            self.suffix = 'dll'
+            suffix = 'dll'
         else:
             prefix = environment.get_shared_lib_prefix()
-            self.suffix = environment.get_shared_lib_suffix()
+            suffix = environment.get_shared_lib_suffix()
         if not hasattr(self, 'prefix'):
             self.prefix = prefix
-        if len(self.sources) > 0 and self.sources[0].endswith('.rs'):
-            self.suffix = 'rlib'
+        if not hasattr(self, 'suffix'):
+            if len(self.sources) > 0 and self.sources[0].endswith('.rs'):
+                self.suffix = 'rlib'
+            else:
+                self.suffix = suffix
         self.importsuffix = environment.get_import_lib_suffix()
         self.filename = self.prefix + self.name + '.' + self.suffix
 
diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py
index 6171c41ed..ca5fa8984 100644
--- a/mesonbuild/dependencies.py
+++ b/mesonbuild/dependencies.py
@@ -1077,6 +1077,7 @@ class ThreadDependency(Dependency):
 class Python3Dependency(Dependency):
     def __init__(self, environment, kwargs):
         super().__init__()
+        self.name = 'python3'
         self.is_found = False
         try:
             pkgdep = PkgConfigDependency('python3', environment, kwargs)
@@ -1100,6 +1101,14 @@ class Python3Dependency(Dependency):
                 self.libs = ['-L{}/libs'.format(basedir),
                              '-lpython{}'.format(vernum)]
                 self.is_found = True
+            elif mesonlib.is_osx():
+                # In OSX the Python 3 framework does not have a version
+                # number in its name.
+                fw = ExtraFrameworkDependency('python', False)
+                if fw.found():
+                    self.cargs = fw.get_compile_args()
+                    self.libs = fw.get_link_args()
+                    self.is_found = True
         if self.is_found:
             mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'))
         else:
diff --git a/test cases/python3/2 extmodule/ext/meson.build b/test cases/python3/2 extmodule/ext/meson.build
index 1184835d8..04c0592c2 100644
--- a/test cases/python3/2 extmodule/ext/meson.build	
+++ b/test cases/python3/2 extmodule/ext/meson.build	
@@ -1,6 +1,14 @@
+if host_machine.system() == 'darwin'
+  # Default suffix is 'dylib' but Python does not use for extensions.
+  suffix = 'so'
+else
+  suffix = []
+endif
+
 pylib = shared_library('tachyon',
   'tachyon_module.c',
   dependencies : py3_dep,
-  name_prefix : '')
+  name_prefix : '',
+  name_suffix : suffix)
 
 pypathdir = meson.current_build_dir()

From 40d70e1b15f785a31cfbfcd4f4bb959c0ee3adb6 Mon Sep 17 00:00:00 2001
From: Jussi Pakkanen <jpakkane@gmail.com>
Date: Sun, 21 Feb 2016 17:14:10 +0200
Subject: [PATCH 7/9] Skip cython test if it does not exist.

---
 test cases/python3/3 cython/meson.build | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/test cases/python3/3 cython/meson.build b/test cases/python3/3 cython/meson.build
index 2d5948e26..cd245c71c 100644
--- a/test cases/python3/3 cython/meson.build	
+++ b/test cases/python3/3 cython/meson.build	
@@ -1,12 +1,17 @@
 project('cython', 'c',
   default_options : ['warning_level=3'])
 
-cython = find_program('cython3')
-py3_dep = dependency('python3')
+cython = find_program('cython3', required : false)
 
-subdir('libdir')
+if cython.found()
+  py3_dep = dependency('python3')
 
-test('cython tester',
-  find_program('cytest.py'),
-  env : ['PYTHONPATH=' + pydir]
-)
+  subdir('libdir')
+
+  test('cython tester',
+    find_program('cytest.py'),
+    env : ['PYTHONPATH=' + pydir]
+  )
+else
+  message('Cython not found, skipping test.')
+endif

From 836b121a9cebce2c5bde2cf07df147a382363348 Mon Sep 17 00:00:00 2001
From: Jussi Pakkanen <jpakkane@gmail.com>
Date: Mon, 22 Feb 2016 00:09:06 +0200
Subject: [PATCH 8/9] Refix Linux.

---
 mesonbuild/build.py | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 31f12b142..e2dd7ca03 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -427,9 +427,10 @@ class BuildTarget():
             if isinstance(name_suffix, list):
                 if len(name_suffix) != 0:
                     raise InvalidArguments('Array must be empty to signify null.')
-            elif not isinstance(name_suffix, str):
-                raise InvalidArguments('Name suffix must be a string.')
-            self.suffix = name_suffix
+            else:
+                if not isinstance(name_suffix, str):
+                    raise InvalidArguments('Name suffix must be a string.')
+                self.suffix = name_suffix
 
     def get_subdir(self):
         return self.subdir

From efceac497fa2702124398b2712761015d9a1c78a Mon Sep 17 00:00:00 2001
From: Jussi Pakkanen <jpakkane@gmail.com>
Date: Fri, 26 Feb 2016 21:04:11 +0200
Subject: [PATCH 9/9] Python extension module finally works on Windows.

---
 test cases/python3/2 extmodule/ext/meson.build |  3 +++
 test cases/python3/2 extmodule/meson.build     |  5 ++++-
 test cases/python3/3 cython/libdir/meson.build | 11 +++++++++++
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/test cases/python3/2 extmodule/ext/meson.build b/test cases/python3/2 extmodule/ext/meson.build
index 04c0592c2..7d67953cb 100644
--- a/test cases/python3/2 extmodule/ext/meson.build	
+++ b/test cases/python3/2 extmodule/ext/meson.build	
@@ -1,6 +1,9 @@
 if host_machine.system() == 'darwin'
   # Default suffix is 'dylib' but Python does not use for extensions.
   suffix = 'so'
+elif host_machine.system() == 'windows'
+  # On Windows the extension is pyd for some unexplainable reason.
+  suffix = 'pyd'
 else
   suffix = []
 endif
diff --git a/test cases/python3/2 extmodule/meson.build b/test cases/python3/2 extmodule/meson.build
index a86a1222c..858bbea9f 100644
--- a/test cases/python3/2 extmodule/meson.build	
+++ b/test cases/python3/2 extmodule/meson.build	
@@ -1,4 +1,7 @@
-project('Python extension module', 'c')
+project('Python extension module', 'c',
+  default_options : ['buildtype=release'])
+# Because Windows Python ships only with optimized libs,
+# we must build this project the same way.
 
 py3_dep = dependency('python3')
 
diff --git a/test cases/python3/3 cython/libdir/meson.build b/test cases/python3/3 cython/libdir/meson.build
index baa4c1dbf..5c0352e88 100644
--- a/test cases/python3/3 cython/libdir/meson.build	
+++ b/test cases/python3/3 cython/libdir/meson.build	
@@ -1,3 +1,13 @@
+if host_machine.system() == 'darwin'
+  # Default suffix is 'dylib' but Python does not use for extensions.
+  suffix = 'so'
+elif host_machine.system() == 'windows'
+  # On Windows the extension is pyd for some unexplainable reason.
+  suffix = 'pyd'
+else
+  suffix = []
+endif
+
 pyx_c = custom_target('storer_pyx',
   output : 'storer_pyx.c',
   input : 'storer.pyx',
@@ -7,6 +17,7 @@ pyx_c = custom_target('storer_pyx',
 slib = shared_library('storer',
   'storer.c', pyx_c,
   name_prefix : '',
+  name_suffix : suffix,
   dependencies : py3_dep)
 
 pydir = meson.current_build_dir()