aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--mesonbuild/backend/backends.py3
-rw-r--r--mesonbuild/backend/vs2010backend.py82
-rw-r--r--mesonbuild/build.py42
-rw-r--r--mesonbuild/dependencies.py48
-rw-r--r--mesonbuild/environment.py2
-rw-r--r--mesonbuild/mesonmain.py25
-rw-r--r--mesonbuild/scripts/regen_checker.py18
-rwxr-xr-xrun_tests.py1
-rw-r--r--test cases/common/106 subproject subdir/meson.build6
-rw-r--r--test cases/common/106 subproject subdir/prog.c5
-rw-r--r--test cases/common/106 subproject subdir/subprojects/sub/lib/meson.build2
-rw-r--r--test cases/common/106 subproject subdir/subprojects/sub/lib/sub.c5
-rw-r--r--test cases/common/106 subproject subdir/subprojects/sub/lib/sub.h6
-rw-r--r--test cases/common/106 subproject subdir/subprojects/sub/meson.build2
-rwxr-xr-xtest cases/common/59 object generator/obj_generator.py2
-rw-r--r--test cases/python3/1 basic/gluon/__init__.py0
-rw-r--r--test cases/python3/1 basic/gluon/gluonator.py2
-rw-r--r--test cases/python3/1 basic/meson.build9
-rwxr-xr-xtest cases/python3/1 basic/prog.py9
-rw-r--r--test cases/python3/1 basic/subdir/meson.build5
-rwxr-xr-xtest cases/python3/1 basic/subdir/subprog.py12
-rwxr-xr-xtest cases/python3/2 extmodule/blaster.py14
-rw-r--r--test cases/python3/2 extmodule/ext/meson.build17
-rw-r--r--test cases/python3/2 extmodule/ext/tachyon_module.c49
-rw-r--r--test cases/python3/2 extmodule/meson.build12
-rwxr-xr-xtest cases/python3/3 cython/cytest.py23
-rw-r--r--test cases/python3/3 cython/libdir/cstorer.pxd9
-rw-r--r--test cases/python3/3 cython/libdir/meson.build23
-rw-r--r--test cases/python3/3 cython/libdir/storer.c24
-rw-r--r--test cases/python3/3 cython/libdir/storer.h8
-rw-r--r--test cases/python3/3 cython/libdir/storer.pyx16
-rw-r--r--test cases/python3/3 cython/meson.build17
33 files changed, 446 insertions, 54 deletions
diff --git a/.gitignore b/.gitignore
index 1e42da4..1a49bc1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,7 @@
/.project
/.pydevproject
+/.settings
+/.cproject
__pycache__
/install dir
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index a354d6e..d2176c7 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -125,6 +125,9 @@ class Backend():
outfileabs = os.path.join(self.environment.get_build_dir(), outfilename)
outfileabs_tmp = outfileabs + '.tmp'
abs_files.append(outfileabs)
+ outfileabs_tmp_dir = os.path.dirname(outfileabs_tmp)
+ if not os.path.exists(outfileabs_tmp_dir):
+ os.makedirs(outfileabs_tmp_dir)
outfile = open(outfileabs_tmp, 'w')
langlist[language] = outfile
result.append(outfilename)
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index c9fe09f..58a7bd3 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -21,13 +21,13 @@ from .. import mlog
import xml.etree.ElementTree as ET
import xml.dom.minidom
from ..coredata import MesonException
+from ..environment import Environment
class RegenInfo():
- def __init__(self, source_dir, build_dir, depfiles, solutionfile):
+ def __init__(self, source_dir, build_dir, depfiles):
self.source_dir = source_dir
self.build_dir = build_dir
self.depfiles = depfiles
- self.solutionfile = solutionfile
class Vs2010Backend(backends.Backend):
def __init__(self, build):
@@ -37,8 +37,10 @@ class Vs2010Backend(backends.Backend):
self.source_suffix_in_obj = False
def generate_custom_generator_commands(self, target, parent_node):
- idgroup = ET.SubElement(parent_node, 'ItemDefinitionGroup')
all_output_files = []
+ commands = []
+ inputs = []
+ outputs = []
for genlist in target.get_generated_sources():
if isinstance(genlist, build.CustomTarget):
all_output_files += [os.path.join(self.get_target_dir(genlist), i) for i in genlist.output]
@@ -50,7 +52,7 @@ class Vs2010Backend(backends.Backend):
if isinstance(exe, build.BuildTarget):
exe_file = os.path.join(self.environment.get_build_dir(), self.get_target_filename(exe))
else:
- exe_file = exe.get_command()
+ exe_file = exe.get_command()[0]
base_args = generator.get_arglist()
for i in range(len(infilelist)):
if len(infilelist) == len(outfilelist):
@@ -67,13 +69,18 @@ class Vs2010Backend(backends.Backend):
args = [x.replace("@SOURCE_DIR@", self.environment.get_source_dir()).replace("@BUILD_DIR@", self.get_target_private_dir(target))
for x in args]
fullcmd = [exe_file] + args
- cbs = ET.SubElement(idgroup, 'CustomBuildStep')
- ET.SubElement(cbs, 'Command').text = ' '.join(self.special_quote(fullcmd))
- ET.SubElement(cbs, 'Inputs').text = infilename
- ET.SubElement(cbs, 'Outputs').text = ';'.join(outfiles)
- ET.SubElement(cbs, 'Message').text = 'Generating sources from %s.' % infilename
- pg = ET.SubElement(parent_node, 'PropertyGroup')
- ET.SubElement(pg, 'CustomBuildBeforeTargets').text = 'ClCompile'
+ commands.append(' '.join(self.special_quote(fullcmd)))
+ inputs.append(infilename)
+ outputs.extend(outfiles)
+ if len(commands) > 0:
+ idgroup = ET.SubElement(parent_node, 'ItemDefinitionGroup')
+ cbs = ET.SubElement(idgroup, 'CustomBuildStep')
+ ET.SubElement(cbs, 'Command').text = '\r\n'.join(commands)
+ ET.SubElement(cbs, 'Inputs').text = ";".join(inputs)
+ ET.SubElement(cbs, 'Outputs').text = ';'.join(outputs)
+ ET.SubElement(cbs, 'Message').text = 'Generating custom sources.'
+ pg = ET.SubElement(parent_node, 'PropertyGroup')
+ ET.SubElement(pg, 'CustomBuildBeforeTargets').text = 'ClCompile'
return all_output_files
def generate(self, interp):
@@ -85,18 +92,22 @@ class Vs2010Backend(backends.Backend):
self.gen_testproj('RUN_TESTS', os.path.join(self.environment.get_build_dir(), 'RUN_TESTS.vcxproj'))
self.gen_regenproj('REGEN', os.path.join(self.environment.get_build_dir(), 'REGEN.vcxproj'))
self.generate_solution(sln_filename, projlist)
- self.generate_regen_info(sln_filename)
- open(os.path.join(self.environment.get_scratch_dir(), 'regen.stamp'), 'wb')
- rulefile = os.path.join(self.environment.get_scratch_dir(), 'regen.rule')
- if not os.path.exists(rulefile):
- open(rulefile, 'w').write("# For some reason this needs to be here.")
+ self.generate_regen_info()
+ Vs2010Backend.touch_regen_timestamp(self.environment.get_build_dir())
+
+ @staticmethod
+ def get_regen_stampfile(build_dir):
+ return os.path.join(os.path.join(build_dir, Environment.private_dir), 'regen.stamp')
+
+ @staticmethod
+ def touch_regen_timestamp(build_dir):
+ open(Vs2010Backend.get_regen_stampfile(build_dir), 'w').close()
- def generate_regen_info(self, sln_filename):
+ def generate_regen_info(self):
deps = self.get_regen_filelist()
regeninfo = RegenInfo(self.environment.get_source_dir(),
self.environment.get_build_dir(),
- deps,
- sln_filename)
+ deps)
pickle.dump(regeninfo, open(os.path.join(self.environment.get_scratch_dir(), 'regeninfo.dump'), 'wb'))
def get_obj_target_deps(self, obj_list):
@@ -206,21 +217,22 @@ class Vs2010Backend(backends.Backend):
def split_sources(self, srclist):
sources = []
headers = []
+ objects = []
for i in srclist:
if self.environment.is_header(i):
headers.append(i)
+ elif self.environment.is_object(i):
+ objects.append(i)
else:
sources.append(i)
- return (sources, headers)
+ return (sources, headers, objects)
def target_to_build_root(self, target):
if target.subdir == '':
return ''
- directories = os.path.split(target.subdir)
- directories = list(filter(bool,directories)) #Filter out empty strings
-
- return '/'.join(['..']*len(directories))
+ directories = os.path.normpath(target.subdir).split(os.sep)
+ return os.sep.join(['..']*len(directories))
def special_quote(self, arr):
return ['"%s"' % i for i in arr]
@@ -323,7 +335,7 @@ class Vs2010Backend(backends.Backend):
down = self.target_to_build_root(target)
proj_to_src_root = os.path.join(down, self.build_to_src)
proj_to_src_dir = os.path.join(proj_to_src_root, target.subdir)
- (sources, headers) = self.split_sources(target.sources)
+ (sources, headers, objects) = self.split_sources(target.sources)
buildtype = self.buildtype
project_name = target.name
target_name = target.name
@@ -356,7 +368,7 @@ class Vs2010Backend(backends.Backend):
ET.SubElement(type_config, 'UseDebugLibraries').text = 'true'
ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.props')
generated_files = self.generate_custom_generator_commands(target, root)
- (gen_src, gen_hdrs) = self.split_sources(generated_files)
+ (gen_src, gen_hdrs, gen_objs) = self.split_sources(generated_files)
direlem = ET.SubElement(root, 'PropertyGroup')
fver = ET.SubElement(direlem, '_ProjectFileVersion')
fver.text = self.project_file_version
@@ -483,6 +495,13 @@ class Vs2010Backend(backends.Backend):
for s in gen_src:
relpath = self.relpath(s, target.subdir)
ET.SubElement(inc_src, 'CLCompile', Include=relpath)
+ if len(objects) > 0:
+ # Do not add gen_objs to project file. Those are automatically used by MSBuild, because they are part of
+ # the CustomBuildStep Outputs.
+ inc_objs = ET.SubElement(root, 'ItemGroup')
+ for s in objects:
+ relpath = s.rel_to_builddir(proj_to_src_root)
+ ET.SubElement(inc_objs, 'Object', Include=relpath)
ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
# Reference the regen target.
ig = ET.SubElement(root, 'ItemGroup')
@@ -558,15 +577,18 @@ exit /b %%1
:cmDone
if %%errorlevel%% neq 0 goto :VCEnd'''
igroup = ET.SubElement(root, 'ItemGroup')
- custombuild = ET.SubElement(igroup, 'CustomBuild', Include='meson-private/regen.rule')
+ rulefile = os.path.join(self.environment.get_scratch_dir(), 'regen.rule')
+ if not os.path.exists(rulefile):
+ with open(rulefile, 'w') as f:
+ f.write("# Meson regen file.")
+ custombuild = ET.SubElement(igroup, 'CustomBuild', Include=rulefile)
message = ET.SubElement(custombuild, 'Message')
message.text = 'Checking whether solution needs to be regenerated.'
ET.SubElement(custombuild, 'Command').text = cmd_templ % \
('" "'.join(regen_command), private_dir)
- ET.SubElement(custombuild, 'Outputs').text = os.path.join(self.environment.get_scratch_dir(), 'regen.stamp')
+ ET.SubElement(custombuild, 'Outputs').text = Vs2010Backend.get_regen_stampfile(self.environment.get_build_dir())
deps = self.get_regen_filelist()
- depstr = ';'.join([os.path.join(self.environment.get_source_dir(), d) for d in deps])
- ET.SubElement(custombuild, 'AdditionalInputs').text = depstr
+ ET.SubElement(custombuild, 'AdditionalInputs').text = ';'.join(deps)
ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
ET.SubElement(root, 'ImportGroup', Label='ExtensionTargets')
tree = ET.ElementTree(root)
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index f9e628d..e2dd7ca 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -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
diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py
index b89bc11..ca5fa89 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,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,
}
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 369ca20..1586248 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -126,7 +126,7 @@ class Environment():
def is_cross_build(self):
return self.cross_info is not None
- def generating_finished(self):
+ def dump_coredata(self):
cdf = os.path.join(self.get_build_dir(), Environment.coredata_file)
coredata.save(self.coredata, cdf)
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index 0317651..543a31f 100644
--- a/mesonbuild/mesonmain.py
+++ b/mesonbuild/mesonmain.py
@@ -166,8 +166,8 @@ itself as required.'''
mlog.log('Build machine cpu family:', mlog.bold(intr.builtin['build_machine'].cpu_family_method([], {})))
mlog.log('Build machine cpu:', mlog.bold(intr.builtin['build_machine'].cpu_method([], {})))
intr.run()
+ env.dump_coredata()
g.generate(intr)
- env.generating_finished()
dumpfile = os.path.join(env.get_scratch_dir(), 'build.dat')
pickle.dump(b, open(dumpfile, 'wb'))
@@ -231,15 +231,22 @@ def run(mainfile, args):
return 0
args = options.directories
if len(args) == 0 or len(args) > 2:
- print('{} <source directory> <build directory>'.format(sys.argv[0]))
- print('If you omit either directory, the current directory is substituted.')
- print('Run {} --help for more information.'.format(sys.argv[0]))
- return 1
- dir1 = args[0]
- if len(args) > 1:
- dir2 = args[1]
+ # if there's a meson.build in the dir above, and not in the current
+ # directory, assume we're in the build directory
+ if len(args) == 0 and not os.path.exists('meson.build') and os.path.exists('../meson.build'):
+ dir1 = '..'
+ dir2 = '.'
+ else:
+ print('{} <source directory> <build directory>'.format(sys.argv[0]))
+ print('If you omit either directory, the current directory is substituted.')
+ print('Run {} --help for more information.'.format(sys.argv[0]))
+ return 1
else:
- dir2 = '.'
+ dir1 = args[0]
+ if len(args) > 1:
+ dir2 = args[1]
+ else:
+ dir2 = '.'
while os.path.islink(mainfile):
resolved = os.readlink(mainfile)
if resolved[0] != '/':
diff --git a/mesonbuild/scripts/regen_checker.py b/mesonbuild/scripts/regen_checker.py
index a5e5fab..2e974d8 100644
--- a/mesonbuild/scripts/regen_checker.py
+++ b/mesonbuild/scripts/regen_checker.py
@@ -19,13 +19,18 @@ import pickle, subprocess
# This could also be used for XCode.
-def need_regen(regeninfo):
- sln_time = os.stat(os.path.join(regeninfo.build_dir, regeninfo.solutionfile)).st_mtime
+def need_regen(regeninfo, regen_timestamp):
for i in regeninfo.depfiles:
curfile = os.path.join(regeninfo.build_dir, i)
curtime = os.stat(curfile).st_mtime
- if curtime > sln_time:
+ if curtime > regen_timestamp:
return True
+ # The timestamp file gets automatically deleted by MSBuild during a 'Clean' build.
+ # We must make sure to recreate it, even if we do not regenerate the solution.
+ # Otherwise, Visual Studio will always consider the REGEN project out of date.
+ print("Everything is up-to-date, regeneration of build files is not needed.")
+ from mesonbuild.backend.vs2010backend import Vs2010Backend
+ Vs2010Backend.touch_regen_timestamp(regeninfo.build_dir)
return False
def regen(regeninfo):
@@ -41,8 +46,11 @@ def regen(regeninfo):
subprocess.check_call(cmd)
def run(args):
- regeninfo = pickle.load(open(os.path.join(args[0], 'regeninfo.dump'), 'rb'))
- if need_regen(regeninfo):
+ private_dir = args[0]
+ dumpfile = os.path.join(private_dir, 'regeninfo.dump')
+ regeninfo = pickle.load(open(dumpfile, 'rb'))
+ regen_timestamp = os.stat(dumpfile).st_mtime
+ if need_regen(regeninfo, regen_timestamp):
regen(regeninfo)
sys.exit(0)
diff --git a/run_tests.py b/run_tests.py
index d4c6ff2..e85a6d6 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/common/106 subproject subdir/meson.build b/test cases/common/106 subproject subdir/meson.build
new file mode 100644
index 0000000..ec9fad1
--- /dev/null
+++ b/test cases/common/106 subproject subdir/meson.build
@@ -0,0 +1,6 @@
+project('proj', 'c')
+subproject('sub')
+libSub = dependency('sub', fallback: ['sub', 'libSub'])
+
+exe = executable('prog', 'prog.c', dependencies: libSub)
+test('subproject subdir', exe)
diff --git a/test cases/common/106 subproject subdir/prog.c b/test cases/common/106 subproject subdir/prog.c
new file mode 100644
index 0000000..02ae337
--- /dev/null
+++ b/test cases/common/106 subproject subdir/prog.c
@@ -0,0 +1,5 @@
+#include <sub.h>
+
+int main() {
+ return sub();
+}
diff --git a/test cases/common/106 subproject subdir/subprojects/sub/lib/meson.build b/test cases/common/106 subproject subdir/subprojects/sub/lib/meson.build
new file mode 100644
index 0000000..731d22b
--- /dev/null
+++ b/test cases/common/106 subproject subdir/subprojects/sub/lib/meson.build
@@ -0,0 +1,2 @@
+lib = static_library('sub', 'sub.c')
+libSub = declare_dependency(include_directories: include_directories('.'), link_with: lib)
diff --git a/test cases/common/106 subproject subdir/subprojects/sub/lib/sub.c b/test cases/common/106 subproject subdir/subprojects/sub/lib/sub.c
new file mode 100644
index 0000000..3291e3c
--- /dev/null
+++ b/test cases/common/106 subproject subdir/subprojects/sub/lib/sub.c
@@ -0,0 +1,5 @@
+#include "sub.h"
+
+int sub() {
+ return 0;
+}
diff --git a/test cases/common/106 subproject subdir/subprojects/sub/lib/sub.h b/test cases/common/106 subproject subdir/subprojects/sub/lib/sub.h
new file mode 100644
index 0000000..f1ab0e1
--- /dev/null
+++ b/test cases/common/106 subproject subdir/subprojects/sub/lib/sub.h
@@ -0,0 +1,6 @@
+#ifndef SUB_H
+#define SUB_H
+
+int sub();
+
+#endif
diff --git a/test cases/common/106 subproject subdir/subprojects/sub/meson.build b/test cases/common/106 subproject subdir/subprojects/sub/meson.build
new file mode 100644
index 0000000..bf69c25
--- /dev/null
+++ b/test cases/common/106 subproject subdir/subprojects/sub/meson.build
@@ -0,0 +1,2 @@
+project('sub', 'c')
+subdir('lib')
diff --git a/test cases/common/59 object generator/obj_generator.py b/test cases/common/59 object generator/obj_generator.py
index 6960059..204f1eb 100755
--- a/test cases/common/59 object generator/obj_generator.py
+++ b/test cases/common/59 object generator/obj_generator.py
@@ -12,7 +12,7 @@ if __name__ == '__main__':
ifile = sys.argv[2]
ofile = sys.argv[3]
if compiler.endswith('cl'):
- cmd = [compiler, '/nologo', '/Fo'+ofile, '/c', ifile]
+ cmd = [compiler, '/nologo', '/MDd', '/Fo'+ofile, '/c', ifile]
else:
cmd = [compiler, '-c', ifile, '-o', ofile]
sys.exit(subprocess.call(cmd))
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 0000000..e69de29
--- /dev/null
+++ b/test cases/python3/1 basic/gluon/__init__.py
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 0000000..b53d6de
--- /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 0000000..badd3e5
--- /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 0000000..9d95aea
--- /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 0000000..3f275ad
--- /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 0000000..08652f0
--- /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)
diff --git a/test cases/python3/2 extmodule/blaster.py b/test cases/python3/2 extmodule/blaster.py
new file mode 100755
index 0000000..7e1eae6
--- /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 0000000..7d67953
--- /dev/null
+++ b/test cases/python3/2 extmodule/ext/meson.build
@@ -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()
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 0000000..b2592e4
--- /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 0000000..858bbea
--- /dev/null
+++ b/test cases/python3/2 extmodule/meson.build
@@ -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])
diff --git a/test cases/python3/3 cython/cytest.py b/test cases/python3/3 cython/cytest.py
new file mode 100755
index 0000000..43443dc
--- /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 0000000..7b730fc
--- /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 0000000..5c0352e
--- /dev/null
+++ b/test cases/python3/3 cython/libdir/meson.build
@@ -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()
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 0000000..0199bb8
--- /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 0000000..4f71917
--- /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 0000000..ed551dc
--- /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 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 0000000..cd245c7
--- /dev/null
+++ b/test cases/python3/3 cython/meson.build
@@ -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