Merge Python 3 module support.

pull/402/head
Jussi Pakkanen 9 years ago
commit ea60a22cd5
  1. 2
      .gitignore
  2. 42
      mesonbuild/build.py
  3. 48
      mesonbuild/dependencies.py
  4. 1
      run_tests.py
  5. 0
      test cases/python3/1 basic/gluon/__init__.py
  6. 2
      test cases/python3/1 basic/gluon/gluonator.py
  7. 9
      test cases/python3/1 basic/meson.build
  8. 9
      test cases/python3/1 basic/prog.py
  9. 5
      test cases/python3/1 basic/subdir/meson.build
  10. 12
      test cases/python3/1 basic/subdir/subprog.py
  11. 14
      test cases/python3/2 extmodule/blaster.py
  12. 17
      test cases/python3/2 extmodule/ext/meson.build
  13. 49
      test cases/python3/2 extmodule/ext/tachyon_module.c
  14. 12
      test cases/python3/2 extmodule/meson.build
  15. 23
      test cases/python3/3 cython/cytest.py
  16. 9
      test cases/python3/3 cython/libdir/cstorer.pxd
  17. 23
      test cases/python3/3 cython/libdir/meson.build
  18. 24
      test cases/python3/3 cython/libdir/storer.c
  19. 8
      test cases/python3/3 cython/libdir/storer.h
  20. 16
      test cases/python3/3 cython/libdir/storer.pyx
  21. 17
      test cases/python3/3 cython/meson.build

2
.gitignore vendored

@ -1,5 +1,7 @@
/.project
/.pydevproject
/.settings
/.cproject
__pycache__
/install dir

@ -44,7 +44,10 @@ 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,
'name_suffix' : True,
})
backslash_explanation = \
'''Compiler arguments have a backslash "\\" character. This is unfortunately not
@ -411,6 +414,23 @@ 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 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.')
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
@ -654,7 +674,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,13 +696,18 @@ 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'):
self.suffix = 'dll'
self.prefix = 'lib'
prefix = 'lib'
suffix = 'dll'
else:
self.prefix = environment.get_shared_lib_prefix()
self.suffix = environment.get_shared_lib_suffix()
if len(self.sources) > 0 and self.sources[0].endswith('.rs'):
self.suffix = 'rlib'
prefix = environment.get_shared_lib_prefix()
suffix = environment.get_shared_lib_suffix()
if not hasattr(self, 'prefix'):
self.prefix = prefix
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

@ -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,52 @@ class ThreadDependency(Dependency):
def need_threads(self):
return True
class Python3Dependency(Dependency):
def __init__(self, environment, kwargs):
super().__init__()
self.name = 'python3'
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
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:
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 +1170,5 @@ packages = {'boost': BoostDependency,
'sdl2' : SDL2Dependency,
'gl' : GLDependency,
'threads' : ThreadDependency,
'python3' : Python3Dependency,
}

@ -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):

@ -0,0 +1,2 @@
def gluoninate():
return 42

@ -0,0 +1,9 @@
project('python sample', 'c')
py3 = find_program('python3')
main = files('prog.py')
test('toplevel', py3, args : main)
subdir('subdir')

@ -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)

@ -0,0 +1,5 @@
submain = find_program('subprog.py')
test('subdir',
submain,
env : 'PYTHONPATH=' + meson.source_root())

@ -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)

@ -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)

@ -0,0 +1,17 @@
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
pylib = shared_library('tachyon',
'tachyon_module.c',
dependencies : py3_dep,
name_prefix : '',
name_suffix : suffix)
pypathdir = meson.current_build_dir()

@ -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);
}

@ -0,0 +1,12 @@
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')
subdir('ext')
test('extmod',
find_program('blaster.py'),
env : ['PYTHONPATH=' + pypathdir])

@ -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

@ -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);

@ -0,0 +1,23 @@
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',
command : [cython, '@INPUT@', '-o', '@OUTPUT@'],
)
slib = shared_library('storer',
'storer.c', pyx_c,
name_prefix : '',
name_suffix : suffix,
dependencies : py3_dep)
pydir = meson.current_build_dir()

@ -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;
}

@ -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);

@ -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 set_value(self, int value):
cstorer.storer_set_value(self._c_storer, value)

@ -0,0 +1,17 @@
project('cython', 'c',
default_options : ['warning_level=3'])
cython = find_program('cython3', required : false)
if cython.found()
py3_dep = dependency('python3')
subdir('libdir')
test('cython tester',
find_program('cytest.py'),
env : ['PYTHONPATH=' + pydir]
)
else
message('Cython not found, skipping test.')
endif
Loading…
Cancel
Save