Merge branch 'distutils'.

pull/358/head
Jussi Pakkanen 9 years ago
commit a5528249ad
  1. 5
      .gitignore
  2. 15
      MANIFEST.in
  3. 5
      create_release.sh
  4. 120
      install_meson.py
  5. 22
      meson
  6. 0
      mesonbuild/__init__.py
  7. 23
      mesonbuild/backends.py
  8. 10
      mesonbuild/build.py
  9. 8
      mesonbuild/compilers.py
  10. 2
      mesonbuild/coredata.py
  11. 6
      mesonbuild/dependencies.py
  12. 8
      mesonbuild/environment.py
  13. 33
      mesonbuild/interpreter.py
  14. 30
      mesonbuild/mconf.py
  15. 15
      mesonbuild/mesonlib.py
  16. 86
      mesonbuild/mesonmain.py
  17. 0
      mesonbuild/mesonmain.ui
  18. 0
      mesonbuild/mesonrunner.ui
  19. 0
      mesonbuild/mesonstart.ui
  20. 26
      mesonbuild/mgui.py
  21. 16
      mesonbuild/mintro.py
  22. 0
      mesonbuild/mlog.py
  23. 0
      mesonbuild/modules/__init__.py
  24. 18
      mesonbuild/modules/gnome.py
  25. 0
      mesonbuild/modules/modtest.py
  26. 4
      mesonbuild/modules/pkgconfig.py
  27. 6
      mesonbuild/modules/qt4.py
  28. 6
      mesonbuild/modules/qt5.py
  29. 9
      mesonbuild/modules/rpm.py
  30. 4
      mesonbuild/modules/windows.py
  31. 2
      mesonbuild/mparser.py
  32. 46
      mesonbuild/ninjabackend.py
  33. 4
      mesonbuild/optinterpreter.py
  34. 0
      mesonbuild/scripts/__init__.py
  35. 22
      mesonbuild/scripts/commandrunner.py
  36. 37
      mesonbuild/scripts/delwithsuffix.py
  37. 15
      mesonbuild/scripts/depfixer.py
  38. 12
      mesonbuild/scripts/dirchanger.py
  39. 10
      mesonbuild/scripts/gtkdochelper.py
  40. 2
      mesonbuild/scripts/meson_benchmark.py
  41. 28
      mesonbuild/scripts/meson_install.py
  42. 11
      mesonbuild/scripts/meson_test.py
  43. 9
      mesonbuild/scripts/regen_checker.py
  44. 14
      mesonbuild/scripts/symbolextractor.py
  45. 11
      mesonbuild/scripts/vcstagger.py
  46. 8
      mesonbuild/vs2010backend.py
  47. 0
      mesonbuild/wrap/__init__.py
  48. 40
      mesonbuild/wrap/wrap.py
  49. 67
      mesonbuild/wrap/wraptool.py
  50. 6
      mesonbuild/xcodebackend.py
  51. 20
      mesonconf
  52. 20
      mesongui
  53. 20
      mesonintrospect
  54. 13
      readme.txt
  55. 4
      run_cross_test.py
  56. 17
      run_tests.py
  57. 60
      setup.py
  58. 20
      wraptool

5
.gitignore vendored

@ -11,3 +11,8 @@ __pycache__
.DS_Store .DS_Store
*~ *~
packagecache packagecache
/MANIFEST
/build
/dist
/meson.egg-info

@ -0,0 +1,15 @@
graft test?cases
graft manual?tests
graft cross
graft data
graft graphics
graft man
graft tools
include run_tests.py
include run_cross_test.py
include readme.txt
include authors.txt
include contributing.txt
include COPYING
include run_cross_test.py
include run_tests.py

@ -1,5 +0,0 @@
#!/bin/sh
version=`./meson.py -v`
git archive --prefix meson-${version}/ HEAD | gzip > meson_${version}.tar.gz

@ -1,120 +0,0 @@
#!/usr/bin/env python3
# Copyright 2013-2014 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.
# This script installs Meson. We can't use Meson to install itself
# because of the bootstrap problem. We can't use any other build system
# either becaust that would be just silly.
import os, sys, glob, shutil, gzip
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--prefix', default='/usr/local', dest='prefix',
help='the installation prefix (default: %(default)s)')
parser.add_argument('--destdir', default='', dest='destdir',
help='the destdir (default: %(default)s)')
options = parser.parse_args()
if options.prefix[0] != '/':
print('Error, prefix must be an absolute path.')
sys.exit(1)
if options.destdir == '':
install_root = options.prefix
else:
install_root = os.path.join(options.destdir, options.prefix[1:])
script_dir = os.path.join(install_root, 'share/meson')
module_dir = os.path.join(script_dir, 'modules')
bin_dir = os.path.join(install_root, 'bin')
bin_script = os.path.join(script_dir, 'meson.py')
gui_script = os.path.join(script_dir, 'mesongui.py')
conf_script = os.path.join(script_dir, 'mesonconf.py')
intro_script = os.path.join(script_dir, 'mesonintrospect.py')
wraptool_script = os.path.join(script_dir, 'wraptool.py')
bin_name = os.path.join(bin_dir, 'meson')
gui_name = os.path.join(bin_dir, 'mesongui')
conf_name = os.path.join(bin_dir, 'mesonconf')
intro_name = os.path.join(bin_dir, 'mesonintrospect')
wraptool_name = os.path.join(bin_dir, 'wraptool')
man_dir = os.path.join(install_root, 'share/man/man1')
in_manfile = 'man/meson.1'
out_manfile = os.path.join(man_dir, 'meson.1.gz')
in_guimanfile = 'man/mesongui.1'
out_guimanfile = os.path.join(man_dir, 'mesongui.1.gz')
in_confmanfile = 'man/mesonconf.1'
out_confmanfile = os.path.join(man_dir, 'mesonconf.1.gz')
in_intromanfile = 'man/mesonintrospect.1'
out_intromanfile = os.path.join(man_dir, 'mesonintrospect.1.gz')
in_wrapmanfile = 'man/wraptool.1'
out_wrapmanfile = os.path.join(man_dir, 'wraptool.1.gz')
rpmmacros_dir = os.path.join(install_root, 'lib/rpm/macros.d')
symlink_value = os.path.relpath(bin_script, os.path.dirname(bin_name))
guisymlink_value = os.path.relpath(gui_script, os.path.dirname(gui_name))
confsymlink_value = os.path.relpath(conf_script, os.path.dirname(conf_name))
introsymlink_value = os.path.relpath(intro_script, os.path.dirname(intro_name))
wrapsymlink_value = os.path.relpath(wraptool_script, os.path.dirname(wraptool_name))
files = glob.glob('*.py')
files += glob.glob('*.ui')
noinstall = ['compile_meson.py', 'install_meson.py', 'run_tests.py', 'run_cross_test.py']
files = [x for x in files if x not in noinstall]
os.makedirs(script_dir, exist_ok=True)
os.makedirs(bin_dir, exist_ok=True)
os.makedirs(man_dir, exist_ok=True)
for f in files:
print('Installing %s to %s.' %(f, script_dir))
outfilename = os.path.join(script_dir, f)
shutil.copyfile(f, outfilename)
shutil.copystat(f, outfilename)
print('Creating symlinks.')
for i in [bin_name, gui_name, conf_name, intro_name, wraptool_name]:
try:
os.unlink(i)
except FileNotFoundError:
pass
os.symlink(symlink_value, bin_name)
os.symlink(guisymlink_value, gui_name)
os.symlink(confsymlink_value, conf_name)
os.symlink(introsymlink_value, intro_name)
os.symlink(wrapsymlink_value, wraptool_name)
print('Installing manfiles to %s.' % man_dir)
open(out_manfile, 'wb').write(gzip.compress(open(in_manfile, 'rb').read()))
open(out_confmanfile, 'wb').write(gzip.compress(open(in_confmanfile, 'rb').read()))
open(out_guimanfile, 'wb').write(gzip.compress(open(in_guimanfile, 'rb').read()))
open(out_intromanfile, 'wb').write(gzip.compress(open(in_intromanfile, 'rb').read()))
open(out_wrapmanfile, 'wb').write(gzip.compress(open(in_wrapmanfile, 'rb').read()))
print('Installing modules to %s.' % module_dir)
if os.path.exists('modules/__pycache__'):
shutil.rmtree('modules/__pycache__')
if os.path.exists(module_dir):
shutil.rmtree(module_dir)
shutil.copytree('modules', module_dir)
if os.path.exists('/usr/bin/rpm'):
print('Installing RPM macros to %s.' % rpmmacros_dir)
outfilename = os.path.join(rpmmacros_dir, 'macros.meson')
os.makedirs(rpmmacros_dir, exist_ok=True)
shutil.copyfile('data/macros.meson', outfilename)
shutil.copystat('data/macros.meson', outfilename)

@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Copyright 2013 The Meson development team # Copyright 2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -14,19 +14,11 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import os, sys from mesonbuild import mesonmain
import sys, os
if len(sys.argv) != 3: thisfile = __file__
print('%s <root of subdir to process> <suffix to delete>' % sys.argv[0]) if not os.path.isabs(thisfile):
sys.exit(1) thisfile = os.path.normpath(os.path.join(os.getcwd(), thisfile))
topdir = sys.argv[1] sys.exit(mesonmain.run(thisfile, sys.argv[1:]))
suffix = sys.argv[2]
if suffix[0] != '.':
suffix = '.' + suffix
for (root, dirs, files) in os.walk(topdir):
for f in files:
if f.endswith(suffix):
fullname = os.path.join(root, f)
os.unlink(fullname)

@ -13,11 +13,26 @@
# limitations under the License. # limitations under the License.
import os, pickle, re import os, pickle, re
import build from . import build
import dependencies from . import dependencies
import mesonlib from . import mesonlib
import json import json
from coredata import MesonException from .coredata import MesonException
class InstallData():
def __init__(self, source_dir, build_dir, prefix, depfixer):
self.source_dir = source_dir
self.build_dir= build_dir
self.prefix = prefix
self.targets = []
self.depfixer = depfixer
self.headers = []
self.man = []
self.data = []
self.po_package_name = ''
self.po = []
self.install_scripts = []
self.install_subdirs = []
class TestSerialisation: class TestSerialisation:
def __init__(self, name, suite, fname, is_cross, exe_wrapper, is_parallel, cmd_args, env, def __init__(self, name, suite, fname, is_cross, exe_wrapper, is_parallel, cmd_args, env,

@ -12,12 +12,12 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import coredata from . import coredata
import environment from . import environment
import dependencies from . import dependencies
import mlog from . import mlog
import copy, os import copy, os
from mesonlib import File, flatten from .mesonlib import File, flatten
known_basic_kwargs = {'install' : True, known_basic_kwargs = {'install' : True,
'c_pch' : True, 'c_pch' : True,

@ -14,10 +14,10 @@
import subprocess, os.path import subprocess, os.path
import tempfile import tempfile
import mesonlib from .import mesonlib
import mlog from . import mlog
from coredata import MesonException from .coredata import MesonException
import coredata from . import coredata
"""This file contains the data files of all compilers Meson knows """This file contains the data files of all compilers Meson knows
about. To support a new compiler, add its information below. about. To support a new compiler, add its information below.

@ -14,7 +14,7 @@
import pickle, os, uuid import pickle, os, uuid
version = '0.29.0-research' version = '0.29.0.dev2'
build_types = ['plain', 'debug', 'debugoptimized', 'release'] build_types = ['plain', 'debug', 'debugoptimized', 'release']
layouts = ['mirror', 'flat'] layouts = ['mirror', 'flat']

@ -21,9 +21,9 @@
import re import re
import os, stat, glob, subprocess, shutil import os, stat, glob, subprocess, shutil
from coredata import MesonException from . coredata import MesonException
import mlog from . import mlog
import mesonlib from . import mesonlib
class DependencyException(MesonException): class DependencyException(MesonException):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):

@ -1,4 +1,4 @@
# Copyright 2012-2014 The Meson development team # Copyright 2012-2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -13,8 +13,8 @@
# limitations under the License. # limitations under the License.
import os, re, subprocess import os, re, subprocess
import coredata, mesonlib from . import coredata, mesonlib
from compilers import * from .compilers import *
import configparser import configparser
build_filename = 'meson.build' build_filename = 'meson.build'
@ -125,7 +125,7 @@ class Environment():
coredata.save(self.coredata, cdf) coredata.save(self.coredata, cdf)
def get_script_dir(self): def get_script_dir(self):
return os.path.dirname(self.meson_script_file) return os.path.join(os.path.dirname(self.meson_script_file), '../scripts')
def get_log_dir(self): def get_log_dir(self):
return self.log_dir return self.log_dir

@ -12,15 +12,16 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import mparser from . import mparser
import environment from . import environment
import coredata from . import coredata
import dependencies from . import dependencies
import mlog from . import mlog
import build from . import build
import optinterpreter from . import optinterpreter
import wrap from .wrap import wrap
import mesonlib from . import mesonlib
import os, sys, platform, subprocess, shutil, uuid, re import os, sys, platform, subprocess, shutil, uuid, re
from functools import wraps from functools import wraps
@ -1093,7 +1094,7 @@ class Interpreter():
raise InvalidCode('Import takes one argument.') raise InvalidCode('Import takes one argument.')
modname = args[0] modname = args[0]
if not modname in self.environment.coredata.modules: if not modname in self.environment.coredata.modules:
module = importlib.import_module('modules.' + modname).initialize() module = importlib.import_module('mesonbuild.modules.' + modname).initialize()
self.environment.coredata.modules[modname] = module self.environment.coredata.modules[modname] = module
return ModuleHolder(modname, self.environment.coredata.modules[modname], self) return ModuleHolder(modname, self.environment.coredata.modules[modname], self)
@ -1609,9 +1610,17 @@ class Interpreter():
regex_selector = vcs['rev_regex'] regex_selector = vcs['rev_regex']
else: else:
vcs_cmd = [' '] # executing this cmd will fail in vcstagger.py and force to use the fallback string vcs_cmd = [' '] # executing this cmd will fail in vcstagger.py and force to use the fallback string
scriptfile = os.path.join(self.environment.get_script_dir(), 'vcstagger.py')
# vcstagger.py parameters: infile, outfile, fallback, source_dir, replace_string, regex_selector, command... # vcstagger.py parameters: infile, outfile, fallback, source_dir, replace_string, regex_selector, command...
kwargs['command'] = [sys.executable, scriptfile, '@INPUT0@', '@OUTPUT0@', fallback, source_dir, replace_string, regex_selector] + vcs_cmd kwargs['command'] = [sys.executable,
self.environment.get_build_command(),
'--internal',
'vcstagger',
'@INPUT0@',
'@OUTPUT0@',
fallback,
source_dir,
replace_string,
regex_selector] + vcs_cmd
kwargs.setdefault('build_always', True) kwargs.setdefault('build_always', True)
return self.func_custom_target(node, [kwargs['output']], kwargs) return self.func_custom_target(node, [kwargs['output']], kwargs)

@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Copyright 2014-2015 The Meson development team # Copyright 2014-2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -17,8 +17,8 @@
import sys, os import sys, os
import pickle import pickle
import argparse import argparse
import coredata, mesonlib from . import coredata, mesonlib
from coredata import build_types, layouts, warning_levels, libtypelist from .coredata import build_types, warning_levels, libtypelist
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
@ -59,13 +59,13 @@ class Conf:
longest_value = len(titles[2]) longest_value = len(titles[2])
longest_possible_value = len(titles[3]) longest_possible_value = len(titles[3])
for x in arr: for x in arr:
longest_name = max(longest_name, len(x[0])) longest_name = max(longest_name, len(x[0]))
longest_descr = max(longest_descr, len(x[1])) longest_descr = max(longest_descr, len(x[1]))
longest_value = max(longest_value, len(str(x[2]))) longest_value = max(longest_value, len(str(x[2])))
longest_possible_value = max(longest_possible_value, len(x[3])) longest_possible_value = max(longest_possible_value, len(x[3]))
if longest_possible_value > 0: if longest_possible_value > 0:
titles[3] = 'Possible Values' titles[3] = 'Possible Values'
print(' %s%s %s%s %s%s %s' % (titles[0], ' '*(longest_name - len(titles[0])), titles[1], ' '*(longest_descr - len(titles[1])), titles[2], ' '*(longest_value - len(titles[2])), titles[3])) print(' %s%s %s%s %s%s %s' % (titles[0], ' '*(longest_name - len(titles[0])), titles[1], ' '*(longest_descr - len(titles[1])), titles[2], ' '*(longest_value - len(titles[2])), titles[3]))
print(' %s%s %s%s %s%s %s' % ('-'*len(titles[0]), ' '*(longest_name - len(titles[0])), '-'*len(titles[1]), ' '*(longest_descr - len(titles[1])), '-'*len(titles[2]), ' '*(longest_value - len(titles[2])), '-'*len(titles[3]))) print(' %s%s %s%s %s%s %s' % ('-'*len(titles[0]), ' '*(longest_name - len(titles[0])), '-'*len(titles[1]), ' '*(longest_descr - len(titles[1])), '-'*len(titles[2]), ' '*(longest_value - len(titles[2])), '-'*len(titles[3])))
for i in arr: for i in arr:
@ -179,15 +179,15 @@ class Conf:
optarr.append([key, opt.description, opt.value, choices]) optarr.append([key, opt.description, opt.value, choices])
self.print_aligned(optarr) self.print_aligned(optarr)
if __name__ == '__main__': def run(args):
args = mesonlib.expand_arguments(sys.argv[:]) args = mesonlib.expand_arguments(args)
if not args: if not args:
sys.exit(1) sys.exit(1)
options = parser.parse_args(args[1:]) options = parser.parse_args(args)
if len(options.directory) > 1: if len(options.directory) > 1:
print('%s <build directory>' % sys.argv[0]) print('%s <build directory>' % args[0])
print('If you omit the build directory, the current directory is substituted.') print('If you omit the build directory, the current directory is substituted.')
sys.exit(1) return 1
if len(options.directory) == 0: if len(options.directory) == 0:
builddir = os.getcwd() builddir = os.getcwd()
else: else:
@ -202,4 +202,8 @@ if __name__ == '__main__':
except ConfException as e: except ConfException as e:
print('Meson configurator encountered an error:\n') print('Meson configurator encountered an error:\n')
print(e) print(e)
return(1)
return 0
if __name__ == '__main__':
sys.exit(run(sys.argv[1:]))

@ -18,7 +18,7 @@ import platform, subprocess, operator, os, shutil, re, sys
from glob import glob from glob import glob
from coredata import MesonException from .coredata import MesonException
class File: class File:
def __init__(self, is_built, subdir, fname): def __init__(self, is_built, subdir, fname):
@ -116,6 +116,15 @@ def detect_vcs(source_dir):
return vcs return vcs
return None return None
def grab_leading_numbers(vstr):
result = []
for x in vstr.split('.'):
try:
result.append(int(x))
except ValueError:
break
return result
numpart = re.compile('[0-9.]+') numpart = re.compile('[0-9.]+')
def version_compare(vstr1, vstr2): def version_compare(vstr1, vstr2):
@ -146,8 +155,8 @@ def version_compare(vstr1, vstr2):
vstr2 = vstr2[1:] vstr2 = vstr2[1:]
else: else:
cmpop = operator.eq cmpop = operator.eq
varr1 = [int(x) for x in vstr1.split('.')] varr1 = grab_leading_numbers(vstr1)
varr2 = [int(x) for x in vstr2.split('.')] varr2 = grab_leading_numbers(vstr2)
return cmpop(varr1, varr2) return cmpop(varr1, varr2)
def default_libdir(): def default_libdir():

@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Copyright 2012-2015 The Meson development team # Copyright 2012-2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -17,12 +17,12 @@
import sys, stat, traceback, pickle, argparse import sys, stat, traceback, pickle, argparse
import datetime import datetime
import os.path import os.path
import environment, interpreter, mesonlib from . import environment, interpreter, mesonlib
import build from . import build
import platform import platform
import mlog, coredata from . import mlog, coredata
from coredata import MesonException, build_types, layouts, warning_levels, libtypelist from .coredata import MesonException, build_types, layouts, warning_levels, libtypelist
backendlist = ['ninja', 'vs2010', 'xcode'] backendlist = ['ninja', 'vs2010', 'xcode']
@ -138,13 +138,13 @@ itself as required.'''
mlog.log('Build type:', mlog.bold('native build')) mlog.log('Build type:', mlog.bold('native build'))
b = build.Build(env) b = build.Build(env)
if self.options.backend == 'ninja': if self.options.backend == 'ninja':
import ninjabackend from . import ninjabackend
g = ninjabackend.NinjaBackend(b) g = ninjabackend.NinjaBackend(b)
elif self.options.backend == 'vs2010': elif self.options.backend == 'vs2010':
import vs2010backend from . import vs2010backend
g = vs2010backend.Vs2010Backend(b) g = vs2010backend.Vs2010Backend(b)
elif self.options.backend == 'xcode': elif self.options.backend == 'xcode':
import xcodebackend from . import xcodebackend
g = xcodebackend.XCodeBackend(b) g = xcodebackend.XCodeBackend(b)
else: else:
raise RuntimeError('Unknown backend "%s".' % self.options.backend) raise RuntimeError('Unknown backend "%s".' % self.options.backend)
@ -163,44 +163,83 @@ itself as required.'''
dumpfile = os.path.join(env.get_scratch_dir(), 'build.dat') dumpfile = os.path.join(env.get_scratch_dir(), 'build.dat')
pickle.dump(b, open(dumpfile, 'wb')) pickle.dump(b, open(dumpfile, 'wb'))
def run(args): def run_script_command(args):
cmdname = args[0]
cmdargs = args[1:]
if cmdname == 'test':
import mesonbuild.scripts.meson_test as abc
cmdfunc = abc.run
elif cmdname == 'benchmark':
import mesonbuild.scripts.meson_benchmark as abc
cmdfunc = abc.run
elif cmdname == 'install':
import mesonbuild.scripts.meson_install as abc
cmdfunc = abc.run
elif cmdname == 'commandrunner':
import mesonbuild.scripts.commandrunner as abc
cmdfunc = abc.run
elif cmdname == 'delsuffix':
import mesonbuild.scripts.delwithsuffix as abc
cmdfunc = abc.run
elif cmdname == 'depfixer':
import mesonbuild.scripts.depfixer as abc
cmdfunc = abc.run
elif cmdname == 'dirchanger':
import mesonbuild.scripts.dirchanger as abc
cmdfunc = abc.run
elif cmdname == 'gtkdoc':
import mesonbuild.scripts.gtkdochelper as abc
cmdfunc = abc.run
elif cmdname == 'regencheck':
import mesonbuild.scripts.regen_checker as abc
cmdfunc = abc.run
elif cmdname == 'symbolextractor':
import mesonbuild.scripts.symbolextractor as abc
cmdfunc = abc.run
elif cmdname == 'vcstagger':
import mesonbuild.scripts.vcstagger as abc
cmdfunc = abc.run
else:
raise MesonException('Unknown internal command {}.'.format(cmdname))
return cmdfunc(cmdargs)
def run(mainfile, args):
if sys.version_info < (3, 3): if sys.version_info < (3, 3):
print('Meson works correctly only with python 3.3+.') print('Meson works correctly only with python 3.3+.')
print('You have python %s.' % sys.version) print('You have python %s.' % sys.version)
print('Please update your environment') print('Please update your environment')
return 1 return 1
if args[-1] == 'secret-handshake': if len(args) >= 2 and args[0] == '--internal':
args = args[:-1] if args[1] != 'regenerate':
sys.exit(run_script_command(args[1:]))
args = args[2:]
handshake = True handshake = True
else: else:
handshake = False handshake = False
args = mesonlib.expand_arguments(args) args = mesonlib.expand_arguments(args)
if not args: options = parser.parse_args(args)
return 1
options = parser.parse_args(args[1:])
if options.print_version: if options.print_version:
print(coredata.version) print(coredata.version)
return 0 return 0
args = options.directories args = options.directories
if len(args) == 0 or len(args) > 2: if len(args) == 0 or len(args) > 2:
print('%s <source directory> <build directory>' % sys.argv[0]) print('{} <source directory> <build directory>'.format(sys.argv[0]))
print('If you omit either directory, the current directory is substituted.') print('If you omit either directory, the current directory is substituted.')
print('Run {} --help for more information.'.format(sys.argv[0]))
return 1 return 1
dir1 = args[0] dir1 = args[0]
if len(args) > 1: if len(args) > 1:
dir2 = args[1] dir2 = args[1]
else: else:
dir2 = '.' dir2 = '.'
this_file = os.path.abspath(__file__) while os.path.islink(mainfile):
while os.path.islink(this_file): resolved = os.readlink(mainfile)
resolved = os.readlink(this_file)
if resolved[0] != '/': if resolved[0] != '/':
this_file = os.path.join(os.path.dirname(this_file), resolved) mainfile = os.path.join(os.path.dirname(mainfile), resolved)
else: else:
this_file = resolved mainfile = resolved
try: try:
app = MesonApp(dir1, dir2, this_file, handshake, options) app = MesonApp(dir1, dir2, mainfile, handshake, options)
except Exception as e: except Exception as e:
# Log directory does not exist, so just print # Log directory does not exist, so just print
# to stdout. # to stdout.
@ -220,6 +259,3 @@ def run(args):
traceback.print_exc() traceback.print_exc()
return 1 return 1
return 0 return 0
if __name__ == '__main__':
sys.exit(run(sys.argv[:]))

@ -15,7 +15,7 @@
# limitations under the License. # limitations under the License.
import sys, os, pickle, time, shutil import sys, os, pickle, time, shutil
import build, coredata, environment, mesonlib from . import build, coredata, environment, mesonlib
from PyQt5 import uic from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QMainWindow, QHeaderView from PyQt5.QtWidgets import QApplication, QMainWindow, QHeaderView
from PyQt5.QtWidgets import QComboBox, QCheckBox from PyQt5.QtWidgets import QComboBox, QCheckBox
@ -242,23 +242,23 @@ class OptionForm:
combo.addItem('debug') combo.addItem('debug')
combo.addItem('debugoptimized') combo.addItem('debugoptimized')
combo.addItem('release') combo.addItem('release')
combo.setCurrentText(self.coredata.buildtype) combo.setCurrentText(self.coredata.get_builtin_option('buildtype'))
combo.currentTextChanged.connect(self.build_type_changed) combo.currentTextChanged.connect(self.build_type_changed)
self.form.addRow('Build type', combo) self.form.addRow('Build type', combo)
strip = QCheckBox("") strip = QCheckBox("")
strip.setChecked(self.coredata.strip) strip.setChecked(self.coredata.get_builtin_option('strip'))
strip.stateChanged.connect(self.strip_changed) strip.stateChanged.connect(self.strip_changed)
self.form.addRow('Strip on install', strip) self.form.addRow('Strip on install', strip)
coverage = QCheckBox("") coverage = QCheckBox("")
coverage.setChecked(self.coredata.coverage) coverage.setChecked(self.coredata.get_builtin_option('coverage'))
coverage.stateChanged.connect(self.coverage_changed) coverage.stateChanged.connect(self.coverage_changed)
self.form.addRow('Enable coverage', coverage) self.form.addRow('Enable coverage', coverage)
pch = QCheckBox("") pch = QCheckBox("")
pch.setChecked(self.coredata.use_pch) pch.setChecked(self.coredata.get_builtin_option('use_pch'))
pch.stateChanged.connect(self.pch_changed) pch.stateChanged.connect(self.pch_changed)
self.form.addRow('Enable pch', pch) self.form.addRow('Enable pch', pch)
unity = QCheckBox("") unity = QCheckBox("")
unity.setChecked(self.coredata.unity) unity.setChecked(self.coredata.get_builtin_option('unity'))
unity.stateChanged.connect(self.unity_changed) unity.stateChanged.connect(self.unity_changed)
self.form.addRow('Unity build', unity) self.form.addRow('Unity build', unity)
form.addRow(PyQt5.QtWidgets.QLabel("Project options")) form.addRow(PyQt5.QtWidgets.QLabel("Project options"))
@ -545,17 +545,21 @@ class MesonGuiRespawner():
self.gui.resize(s) self.gui.resize(s)
# Garbage collection takes care of the old gui widget # Garbage collection takes care of the old gui widget
if __name__ == '__main__':
def run(args): # SPECIAL, Qt wants all args, including command name.
app = QApplication(sys.argv) app = QApplication(sys.argv)
if len(sys.argv) == 1: if len(args) == 1:
arg = "" arg = ""
elif len(sys.argv) == 2: elif len(args) == 2:
arg = sys.argv[1] arg = sys.argv[1]
else: else:
print(sys.argv[0], "<build or source dir>") print(sys.argv[0], "<build or source dir>")
sys.exit(1) return 1
if os.path.exists(os.path.join(arg, 'meson-private/coredata.dat')): if os.path.exists(os.path.join(arg, 'meson-private/coredata.dat')):
guirespawner = MesonGuiRespawner(arg) guirespawner = MesonGuiRespawner(arg)
else: else:
runner = Starter(arg) runner = Starter(arg)
sys.exit(app.exec_()) return app.exec_()
if __name__ == '__main__':
sys.exit(run(sys.argv))

@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Copyright 2014-2015 The Meson development team # Copyright 2014-2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -22,7 +22,7 @@ Currently only works for the Ninja backend. Others use generated
project files and don't need this info.""" project files and don't need this info."""
import json, pickle import json, pickle
import coredata, build, mesonlib from . import coredata, build, mesonlib
import argparse import argparse
import sys, os import sys, os
@ -172,11 +172,11 @@ def list_tests(testdata):
result.append(to) result.append(to)
print(json.dumps(result)) print(json.dumps(result))
if __name__ == '__main__': def run(args):
options = parser.parse_args() options = parser.parse_args(args)
if len(options.args) > 1: if len(options.args) > 1:
print('Too many arguments') print('Too many arguments')
sys.exit(1) return 1
elif len(options.args) == 1: elif len(options.args) == 1:
bdir = options.args[0] bdir = options.args[0]
else: else:
@ -205,4 +205,8 @@ if __name__ == '__main__':
list_deps(coredata) list_deps(coredata)
else: else:
print('No command specified') print('No command specified')
sys.exit(1) return 1
return 0
if __name__ == '__main__':
sys.exit(run(sys.argv[1:]))

@ -1,4 +1,4 @@
# Copyright 2015 The Meson development team # Copyright 2015-2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -15,13 +15,13 @@
'''This module provides helper functions for Gnome/GLib related '''This module provides helper functions for Gnome/GLib related
functionality such as gobject-introspection and gresources.''' functionality such as gobject-introspection and gresources.'''
import build from .. import build
import os, sys import os, sys
import subprocess import subprocess
from coredata import MesonException from ..coredata import MesonException
import mlog from .. import mlog
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from mesonlib import File from ..mesonlib import File
girwarning_printed = False girwarning_printed = False
@ -260,11 +260,11 @@ class GnomeModule:
main_file = main_xml main_file = main_xml
src_dir = kwargs['src_dir'] src_dir = kwargs['src_dir']
targetname = modulename + '-doc' targetname = modulename + '-doc'
command = os.path.normpath(os.path.join(os.path.split(__file__)[0], "../gtkdochelper.py")) command = [state.environment.get_build_command(), '--internal', 'gtkdoc']
if hasattr(src_dir, 'held_object'): if hasattr(src_dir, 'held_object'):
src_dir= src_dir.held_object src_dir= src_dir.held_object
if not isinstance(src_dir, build.IncludeDirs): if not isinstance(src_dir, build.IncludeDirs):
raise MesonException('Invalidt keyword argument for src_dir.') raise MesonException('Invalid keyword argument for src_dir.')
incdirs = src_dir.get_incdirs() incdirs = src_dir.get_incdirs()
if len(incdirs) != 1: if len(incdirs) != 1:
raise MesonException('Argument src_dir has more than one directory specified.') raise MesonException('Argument src_dir has more than one directory specified.')
@ -279,9 +279,9 @@ class GnomeModule:
'--modulename=' + modulename] '--modulename=' + modulename]
args += self.unpack_args('--htmlargs=', 'html_args', kwargs) args += self.unpack_args('--htmlargs=', 'html_args', kwargs)
args += self.unpack_args('--scanargs=', 'scan_args', kwargs) args += self.unpack_args('--scanargs=', 'scan_args', kwargs)
res = [build.RunTarget(targetname, command, args, state.subdir)] res = [build.RunTarget(targetname, command[0], command[1:] + args, state.subdir)]
if kwargs.get('install', True): if kwargs.get('install', True):
res.append(build.InstallScript([command] + args)) res.append(build.InstallScript(command + args))
return res return res
def unpack_args(self, arg, kwarg_name, kwargs): def unpack_args(self, arg, kwarg_name, kwargs):

@ -12,8 +12,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import coredata, build from .. import coredata, build
import mesonlib from .. import mesonlib
import os import os
class PkgConfigModule: class PkgConfigModule:

@ -12,10 +12,10 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import dependencies, mlog from .. import dependencies, mlog
import os, subprocess import os, subprocess
import build from .. import build
from coredata import MesonException from ..coredata import MesonException
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
class Qt4Module(): class Qt4Module():

@ -12,10 +12,10 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import dependencies, mlog from .. import dependencies, mlog
import os, subprocess import os, subprocess
import build from .. import build
from coredata import MesonException from ..coredata import MesonException
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
class Qt5Module(): class Qt5Module():

@ -15,11 +15,12 @@
'''This module provides helper functions for RPM related '''This module provides helper functions for RPM related
functionality such as generating template RPM spec file.''' functionality such as generating template RPM spec file.'''
import build from .. import build
import compilers from .. import compilers
import datetime import datetime
import mlog from .. import mlog
import modules.gnome from ..modules import gnome
import os import os
class RPMModule: class RPMModule:

@ -12,8 +12,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import mesonlib, dependencies, build from .. import mesonlib, dependencies, build
from coredata import MesonException from ..coredata import MesonException
import os import os
class WindowsModule: class WindowsModule:

@ -13,7 +13,7 @@
# limitations under the License. # limitations under the License.
import re import re
from coredata import MesonException from .coredata import MesonException
class ParseException(MesonException): class ParseException(MesonException):
def __init__(self, text, lineno, colno): def __init__(self, text, lineno, colno):

@ -1,4 +1,4 @@
# Copyright 2012-2014 The Meson development team # Copyright 2012-2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -12,15 +12,15 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import backends from . import backends
import environment, mesonlib from . import environment, mesonlib
import build from . import build
import mlog from . import mlog
import dependencies from . import dependencies
from mesonlib import File from .mesonlib import File
from meson_install import InstallData from .backends import InstallData
from build import InvalidArguments from .build import InvalidArguments
from coredata import MesonException from .coredata import MesonException
import os, sys, pickle, re import os, sys, pickle, re
import subprocess, shutil import subprocess, shutil
@ -365,7 +365,7 @@ int dummy;
self.processed_targets[target.name + target.type_suffix()] = True self.processed_targets[target.name + target.type_suffix()] = True
def generate_run_target(self, target, outfile): def generate_run_target(self, target, outfile):
runnerscript = os.path.join(self.environment.get_script_dir(), 'commandrunner.py') runnerscript = [sys.executable, self.environment.get_build_command(), '--internal', 'commandrunner']
deps = [] deps = []
arg_strings = [] arg_strings = []
for i in target.args: for i in target.args:
@ -379,7 +379,7 @@ int dummy;
mlog.debug(str(i)) mlog.debug(str(i))
raise MesonException('Unreachable code in generate_run_target.') raise MesonException('Unreachable code in generate_run_target.')
elem = NinjaBuildElement(target.name, 'CUSTOM_COMMAND', deps) elem = NinjaBuildElement(target.name, 'CUSTOM_COMMAND', deps)
cmd = [sys.executable, runnerscript, self.environment.get_source_dir(), self.environment.get_build_dir(), target.subdir] cmd = runnerscript + [self.environment.get_source_dir(), self.environment.get_build_dir(), target.subdir]
texe = target.command texe = target.command
try: try:
texe = texe.held_object texe = texe.held_object
@ -460,14 +460,14 @@ int dummy;
script_root = self.environment.get_script_dir() script_root = self.environment.get_script_dir()
install_script = os.path.join(script_root, 'meson_install.py') install_script = os.path.join(script_root, 'meson_install.py')
install_data_file = os.path.join(self.environment.get_scratch_dir(), 'install.dat') install_data_file = os.path.join(self.environment.get_scratch_dir(), 'install.dat')
depfixer = os.path.join(script_root, 'depfixer.py') depfixer = [sys.executable, self.environment.get_build_command(), '--internal', 'depfixer']
d = InstallData(self.environment.get_source_dir(), d = InstallData(self.environment.get_source_dir(),
self.environment.get_build_dir(), self.environment.get_build_dir(),
self.environment.get_prefix(), depfixer) self.environment.get_prefix(), depfixer)
elem = NinjaBuildElement('install', 'CUSTOM_COMMAND', 'PHONY') elem = NinjaBuildElement('install', 'CUSTOM_COMMAND', 'PHONY')
elem.add_dep('all') elem.add_dep('all')
elem.add_item('DESC', 'Installing files.') elem.add_item('DESC', 'Installing files.')
elem.add_item('COMMAND', [sys.executable, install_script, install_data_file]) elem.add_item('COMMAND', [sys.executable, self.environment.get_build_command(), '--internal', 'install', install_data_file])
elem.add_item('pool', 'console') elem.add_item('pool', 'console')
self.generate_depmf_install(d) self.generate_depmf_install(d)
self.generate_target_install(d) self.generate_target_install(d)
@ -585,9 +585,8 @@ int dummy;
self.serialise_tests() self.serialise_tests()
valgrind = environment.find_valgrind() valgrind = environment.find_valgrind()
script_root = self.environment.get_script_dir() script_root = self.environment.get_script_dir()
test_script = os.path.join(script_root, 'meson_test.py')
test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat') test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat')
cmd = [sys.executable, test_script, test_data] cmd = [sys.executable, self.environment.get_build_command(), '--internal', 'test', test_data]
elem = NinjaBuildElement('test', 'CUSTOM_COMMAND', ['all', 'PHONY']) elem = NinjaBuildElement('test', 'CUSTOM_COMMAND', ['all', 'PHONY'])
elem.add_item('COMMAND', cmd) elem.add_item('COMMAND', cmd)
elem.add_item('DESC', 'Running all tests.') elem.add_item('DESC', 'Running all tests.')
@ -607,7 +606,7 @@ int dummy;
# And then benchmarks. # And then benchmarks.
benchmark_script = os.path.join(script_root, 'meson_benchmark.py') benchmark_script = os.path.join(script_root, 'meson_benchmark.py')
benchmark_data = os.path.join(self.environment.get_scratch_dir(), 'meson_benchmark_setup.dat') benchmark_data = os.path.join(self.environment.get_scratch_dir(), 'meson_benchmark_setup.dat')
cmd = [sys.executable, benchmark_script, benchmark_data] cmd = [sys.executable, self.environment.get_build_command(), '--internal', 'benchmark', benchmark_data]
elem = NinjaBuildElement('benchmark', 'CUSTOM_COMMAND', ['all', 'PHONY']) elem = NinjaBuildElement('benchmark', 'CUSTOM_COMMAND', ['all', 'PHONY'])
elem.add_item('COMMAND', cmd) elem.add_item('COMMAND', cmd)
elem.add_item('DESC', 'Running benchmark suite.') elem.add_item('DESC', 'Running benchmark suite.')
@ -631,9 +630,11 @@ int dummy;
outfile.write('rule REGENERATE_BUILD\n') outfile.write('rule REGENERATE_BUILD\n')
c = (quote_char + ninja_quote(sys.executable) + quote_char, c = (quote_char + ninja_quote(sys.executable) + quote_char,
quote_char + ninja_quote(self.environment.get_build_command()) + quote_char, quote_char + ninja_quote(self.environment.get_build_command()) + quote_char,
'--internal',
'regenerate',
quote_char + ninja_quote(self.environment.get_source_dir()) + quote_char, quote_char + ninja_quote(self.environment.get_source_dir()) + quote_char,
quote_char + ninja_quote(self.environment.get_build_dir()) + quote_char) quote_char + ninja_quote(self.environment.get_build_dir()) + quote_char)
outfile.write(" command = %s %s %s %s --backend ninja secret-handshake\n" % c) outfile.write(" command = %s %s %s %s %s %s --backend ninja\n" % c)
outfile.write(' description = Regenerating build files\n') outfile.write(' description = Regenerating build files\n')
outfile.write(' generator = 1\n\n') outfile.write(' generator = 1\n\n')
if len(self.build.pot) > 0: if len(self.build.pot) > 0:
@ -1096,9 +1097,12 @@ int dummy;
scriptdir = self.environment.get_script_dir() scriptdir = self.environment.get_script_dir()
outfile.write('\n') outfile.write('\n')
symrule = 'rule SHSYM\n' symrule = 'rule SHSYM\n'
symcmd = ' command = "%s" "%s" %s %s $CROSS\n' % (ninja_quote(sys.executable), symcmd = ' command = "%s" "%s" %s %s %s %s $CROSS\n' % (ninja_quote(sys.executable),
ninja_quote(os.path.join(scriptdir, 'symbolextractor.py')), self.environment.get_build_command(),
'$in', '$out') '--internal',
'symbolextractor',
'$in',
'$out')
synstat = ' restat = 1\n' synstat = ' restat = 1\n'
syndesc = ' description = Generating symbol file $out.\n' syndesc = ' description = Generating symbol file $out.\n'
outfile.write(symrule) outfile.write(symrule)

@ -12,8 +12,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import mparser from . import mparser
import coredata, mesonlib from . import coredata, mesonlib
import os, re import os, re
forbidden_option_names = coredata.builtin_options forbidden_option_names = coredata.builtin_options

@ -42,14 +42,18 @@ def run_command(source_dir, build_dir, subdir, command, arguments):
print('Could not execute command "%s".' % command) print('Could not execute command "%s".' % command)
sys.exit(1) sys.exit(1)
if __name__ == '__main__': def run(args):
if len(sys.argv) < 5: if len(args) < 4:
print(sys.argv[0], '<source dir> <build dir> <subdir> <command> [arguments]') print('commandrunner.py <source dir> <build dir> <subdir> <command> [arguments]')
src_dir = sys.argv[1] return 1
build_dir = sys.argv[2] src_dir = args[0]
subdir = sys.argv[3] build_dir = args[1]
command = sys.argv[4] subdir = args[2]
arguments = sys.argv[5:] command = args[3]
arguments = args[4:]
pc = run_command(src_dir, build_dir, subdir, command, arguments) pc = run_command(src_dir, build_dir, subdir, command, arguments)
pc.wait() pc.wait()
sys.exit(pc.returncode) return pc.returncode
if __name__ == '__main__':
sys.exit(run(sys.argv[1:]))

@ -0,0 +1,37 @@
#!/usr/bin/env python3
# Copyright 2013 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.
import os, sys
def run(args):
if len(sys.argv) != 2:
print('delwithsuffix.py <root of subdir to process> <suffix to delete>')
sys.exit(1)
topdir = sys.argv[1]
suffix = sys.argv[2]
if suffix[0] != '.':
suffix = '.' + suffix
for (root, _, files) in os.walk(topdir):
for f in files:
if f.endswith(suffix):
fullname = os.path.join(root, f)
os.unlink(fullname)
return 0
if __name__ == '__main__':
run(sys.argv[1:])

@ -284,16 +284,19 @@ class Elf(DataSizes):
entry.write(self.bf) entry.write(self.bf)
return None return None
if __name__ == '__main__': def run(args):
if len(sys.argv) < 2 or len(sys.argv) > 3: if len(args) < 1 or len(args) > 2:
print('This application resets target rpath.') print('This application resets target rpath.')
print('Don\'t run this unless you know what you are doing.') print('Don\'t run this unless you know what you are doing.')
print('%s: <binary file> <prefix>' % sys.argv[0]) print('%s: <binary file> <prefix>' % sys.argv[0])
exit(1) exit(1)
e = Elf(sys.argv[1]) e = Elf(args[0])
if len(sys.argv) == 2: if len(args) == 1:
e.print_rpath() e.print_rpath()
else: else:
new_rpath = sys.argv[2] new_rpath = args[1]
e.fix_rpath(new_rpath.encode('utf8')) e.fix_rpath(new_rpath.encode('utf8'))
#e.fix_deps(prefix.encode()) return 0
if __name__ == '__main__':
run(sys.argv[1:])

@ -19,8 +19,12 @@ the command given in the rest of the arguments.'''
import os, subprocess, sys import os, subprocess, sys
dirname = sys.argv[1] def run(args):
command = sys.argv[2:] dirname = args[0]
command = args[1:]
os.chdir(dirname) os.chdir(dirname)
sys.exit(subprocess.call(command)) return subprocess.call(command)
if __name__ == '__main__':
sys.exit(run(sys.argv[1:]))

@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Copyright 2015 The Meson development team # Copyright 2015-2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -87,8 +87,8 @@ def install_gtkdoc(build_root, doc_subdir, install_prefix, datadir, module):
shutil.rmtree(final_destination, ignore_errors=True) shutil.rmtree(final_destination, ignore_errors=True)
shutil.copytree(source, final_destination) shutil.copytree(source, final_destination)
if __name__ == '__main__': def run(args):
options = parser.parse_args(sys.argv[1:]) options = parser.parse_args(args)
if len(options.htmlargs) > 0: if len(options.htmlargs) > 0:
htmlargs = options.htmlargs.split('@@') htmlargs = options.htmlargs.split('@@')
else: else:
@ -116,3 +116,7 @@ if __name__ == '__main__':
installdir, installdir,
'share/gtk-doc/html', 'share/gtk-doc/html',
options.modulename) options.modulename)
return 0
if __name__ == '__main__':
sys.exit(run(sys.argv[1:]))

@ -16,7 +16,7 @@
import subprocess, sys, os, argparse import subprocess, sys, os, argparse
import pickle, statistics, json import pickle, statistics, json
import meson_test from . import meson_test
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--wd', default=None, dest='wd', parser.add_argument('--wd', default=None, dest='wd',

@ -17,21 +17,6 @@
import sys, pickle, os, shutil, subprocess, gzip, platform import sys, pickle, os, shutil, subprocess, gzip, platform
from glob import glob from glob import glob
class InstallData():
def __init__(self, source_dir, build_dir, prefix, depfixer):
self.source_dir = source_dir
self.build_dir= build_dir
self.prefix = prefix
self.targets = []
self.depfixer = depfixer
self.headers = []
self.man = []
self.data = []
self.po_package_name = ''
self.po = []
self.install_scripts = []
self.install_subdirs = []
def do_install(datafilename): def do_install(datafilename):
ifile = open(datafilename, 'rb') ifile = open(datafilename, 'rb')
d = pickle.load(ifile) d = pickle.load(ifile)
@ -208,7 +193,7 @@ def install_targets(d):
print("Symlink creation does not work on this platform.") print("Symlink creation does not work on this platform.")
printed_symlink_error = True printed_symlink_error = True
if is_elf_platform(): if is_elf_platform():
p = subprocess.Popen([d.depfixer, outname, install_rpath], p = subprocess.Popen(d.depfixer + [outname, install_rpath],
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE) stderr=subprocess.PIPE)
(stdo, stde) = p.communicate() (stdo, stde) = p.communicate()
@ -218,10 +203,13 @@ def install_targets(d):
print('Stderr:\n%s\n' % stde.decode()) print('Stderr:\n%s\n' % stde.decode())
sys.exit(1) sys.exit(1)
if __name__ == '__main__': def run(args):
if len(sys.argv) != 2: if len(args) != 1:
print('Installer script for Meson. Do not run on your own, mmm\'kay?') print('Installer script for Meson. Do not run on your own, mmm\'kay?')
print('%s [install info file]' % sys.argv[0]) print('meson_install.py [install info file]')
datafilename = sys.argv[1] datafilename = args[0]
do_install(datafilename) do_install(datafilename)
return 0
if __name__ == '__main__':
sys.exit(run(sys.argv[1:]))

@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Copyright 2013-2015 The Meson development team # Copyright 2013-2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -14,10 +14,15 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import mesonbuild
import sys, os, subprocess, time, datetime, pickle, multiprocessing, json import sys, os, subprocess, time, datetime, pickle, multiprocessing, json
import concurrent.futures as conc import concurrent.futures as conc
import argparse import argparse
import mesonlib import platform
def is_windows():
platname = platform.system().lower()
return platname == 'windows' or 'mingw' in platname
tests_failed = [] tests_failed = []
@ -70,7 +75,7 @@ def write_json_log(jsonlogfile, test_name, result):
jsonlogfile.write(json.dumps(result) + '\n') jsonlogfile.write(json.dumps(result) + '\n')
def run_with_mono(fname): def run_with_mono(fname):
if fname.endswith('.exe') and not mesonlib.is_windows(): if fname.endswith('.exe') and not is_windows():
return True return True
return False return False

@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Copyright 2015 The Meson development team # Copyright 2015-2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -35,8 +35,11 @@ def regen(regeninfo):
'--backend=vs2010', 'secret-handshake'] '--backend=vs2010', 'secret-handshake']
subprocess.check_call(cmd) subprocess.check_call(cmd)
if __name__ == '__main__': def run(args):
regeninfo = pickle.load(open(os.path.join(sys.argv[1], 'regeninfo.dump'), 'rb')) regeninfo = pickle.load(open(os.path.join(args[0], 'regeninfo.dump'), 'rb'))
if need_regen(regeninfo): if need_regen(regeninfo):
regen(regeninfo) regen(regeninfo)
sys.exit(0) sys.exit(0)
if __name__ == '__main__':
run(sys.argv[1:])

@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Copyright 2013-2015 The Meson development team # Copyright 2013-2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -23,7 +23,7 @@
# http://cgit.freedesktop.org/libreoffice/core/commit/?id=3213cd54b76bc80a6f0516aac75a48ff3b2ad67c # http://cgit.freedesktop.org/libreoffice/core/commit/?id=3213cd54b76bc80a6f0516aac75a48ff3b2ad67c
import sys, subprocess import sys, subprocess
import mesonlib from mesonbuild import mesonlib
import argparse import argparse
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
@ -92,11 +92,15 @@ def gen_symbols(libfilename, outfilename, cross_host):
else: else:
dummy_syms(outfilename) dummy_syms(outfilename)
if __name__ == '__main__': def run(args):
options = parser.parse_args() options = parser.parse_args(args)
if len(options.args) != 2: if len(options.args) != 2:
print(sys.argv[0], '<shared library file> <output file>') print('symbolextractor.py <shared library file> <output file>')
sys.exit(1) sys.exit(1)
libfile = options.args[0] libfile = options.args[0]
outfile = options.args[1] outfile = options.args[1]
gen_symbols(libfile, outfile, options.cross_host) gen_symbols(libfile, outfile, options.cross_host)
return 0
if __name__ == '__main__':
sys.exit(run(sys.argv[1:]))

@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Copyright 2015 The Meson development team # Copyright 2015-2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -27,7 +27,10 @@ def config_vcs_tag(infile, outfile, fallback, source_dir, replace_string, regex_
if (not os.path.exists(outfile)) or (open(outfile).read() != new_data): if (not os.path.exists(outfile)) or (open(outfile).read() != new_data):
open(outfile, 'w').write(new_data) open(outfile, 'w').write(new_data)
if __name__ == '__main__': def run(args):
infile, outfile, fallback, source_dir, replace_string, regex_selector = sys.argv[1:7] infile, outfile, fallback, source_dir, replace_string, regex_selector = args[0:6]
command = sys.argv[7:] command = args[6:]
config_vcs_tag(infile, outfile, fallback, source_dir, replace_string, regex_selector, command) config_vcs_tag(infile, outfile, fallback, source_dir, replace_string, regex_selector, command)
if __name__ == '__main__':
sys.exit(run(sys.argv[1:]))

@ -14,12 +14,12 @@
import os, sys import os, sys
import pickle import pickle
import backends, build from . import backends, build
import dependencies from . import dependencies
import mlog from . import mlog
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
import xml.dom.minidom import xml.dom.minidom
from coredata import MesonException from .coredata import MesonException
class RegenInfo(): class RegenInfo():
def __init__(self, source_dir, build_dir, depfiles, solutionfile): def __init__(self, source_dir, build_dir, depfiles, solutionfile):

@ -12,12 +12,46 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import mlog from .. import mlog
import urllib.request, os, hashlib, shutil import urllib.request, os, hashlib, shutil
import subprocess import subprocess
import sys import sys
import wraptool try:
import ssl
has_ssl = True
API_ROOT = 'https://wrapdb.mesonbuild.com/v1/'
except ImportError:
has_ssl = False
API_ROOT = 'http://wrapdb.mesonbuild.com/v1/'
def build_ssl_context():
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
ctx.options |= ssl.OP_NO_SSLv2
ctx.options |= ssl.OP_NO_SSLv3
ctx.verify_mode = ssl.CERT_REQUIRED
ctx.load_default_certs()
return ctx
def open_wrapdburl(urlstring):
global ssl_warning_printed
if has_ssl:
try:
return urllib.request.urlopen(urlstring)#, context=build_ssl_context())
except urllib.error.URLError:
if not ssl_warning_printed:
print('SSL connection failed. Falling back to unencrypted connections.')
ssl_warning_printed = True
if not ssl_warning_printed:
print('Warning: SSL not available, traffic not authenticated.',
file=sys.stderr)
ssl_warning_printed = True
# Trying to open SSL connection to wrapdb fails because the
# certificate is not known.
if urlstring.startswith('https'):
urlstring = 'http' + urlstring[5:]
return urllib.request.urlopen(urlstring)
class PackageDefinition: class PackageDefinition:
def __init__(self, fname): def __init__(self, fname):
@ -94,7 +128,7 @@ class Resolver:
def get_data(self, url): def get_data(self, url):
blocksize = 10*1024 blocksize = 10*1024
if url.startswith('https://wrapdb.mesonbuild.com'): if url.startswith('https://wrapdb.mesonbuild.com'):
resp = wraptool.open_wrapdburl(url) resp = open_wrapdburl(url)
else: else:
resp = urllib.request.urlopen(url) resp = urllib.request.urlopen(url)
dlsize = int(resp.info()['Content-Length']) dlsize = int(resp.info()['Content-Length'])

@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Copyright 2015 The Meson development team # Copyright 2015-2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -14,24 +14,15 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import urllib.request, json import json
import sys, os import sys, os
import configparser import configparser
import shutil import shutil
import platform
try:
import ssl
has_ssl = True
API_ROOT = 'https://wrapdb.mesonbuild.com/v1/'
except ImportError:
has_ssl = False
API_ROOT = 'http://wrapdb.mesonbuild.com/v1/'
ssl_warning_printed = False
from glob import glob from glob import glob
from .wrap import API_ROOT, open_wrapdburl
help_templ = '''This program allows you to manage your Wrap dependencies help_templ = '''This program allows you to manage your Wrap dependencies
using the online wrap database http://wrapdb.mesonbuild.com. using the online wrap database http://wrapdb.mesonbuild.com.
@ -56,33 +47,6 @@ Commands:
def print_help(): def print_help():
print(help_templ % sys.argv[0]) print(help_templ % sys.argv[0])
def build_ssl_context():
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
ctx.options |= ssl.OP_NO_SSLv2
ctx.options |= ssl.OP_NO_SSLv3
ctx.verify_mode = ssl.CERT_REQUIRED
ctx.load_default_certs()
return ctx
def open_wrapdburl(urlstring):
global ssl_warning_printed
if has_ssl:
try:
return urllib.request.urlopen(urlstring)#, context=build_ssl_context())
except urllib.error.URLError:
if not ssl_warning_printed:
print('SSL connection failed. Falling back to unencrypted connections.')
ssl_warning_printed = True
if not ssl_warning_printed:
print('Warning: SSL not available, traffic not authenticated.',
file=sys.stderr)
ssl_warning_printed = True
# Trying to open SSL connection to wrapdb fails because the
# certificate is not known.
if urlstring.startswith('https'):
urlstring = 'http' + urlstring[5:]
return urllib.request.urlopen(urlstring)
def get_result(urlstring): def get_result(urlstring):
u = open_wrapdburl(urlstring) u = open_wrapdburl(urlstring)
data = u.read().decode('utf-8') data = u.read().decode('utf-8')
@ -197,37 +161,40 @@ def status():
else: else:
print('', name, 'not up to date. Have %s %d, but %s %d is available.' % (current_branch, current_revision, latest_branch, latest_revision)) print('', name, 'not up to date. Have %s %d, but %s %d is available.' % (current_branch, current_revision, latest_branch, latest_revision))
if __name__ == '__main__': def run(args):
if len(sys.argv) < 2 or sys.argv[1] == '-h' or sys.argv[1] == '--help': if len(args) == 0 or args[0] == '-h' or args[0] == '--help':
print_help() print_help()
sys.exit(0) return 0
command = sys.argv[1] command = args[0]
args = sys.argv[2:] args = args[1:]
if command == 'list': if command == 'list':
list_projects() list_projects()
elif command == 'search': elif command == 'search':
if len(args) != 1: if len(args) != 1:
print('Search requires exactly one argument.') print('Search requires exactly one argument.')
sys.exit(1) return 1
search(args[0]) search(args[0])
elif command == 'install': elif command == 'install':
if len(args) != 1: if len(args) != 1:
print('Install requires exactly one argument.') print('Install requires exactly one argument.')
sys.exit(1) return 1
install(args[0]) install(args[0])
elif command == 'update': elif command == 'update':
if len(args) != 1: if len(args) != 1:
print('update requires exactly one argument.') print('update requires exactly one argument.')
sys.exit(1) return 1
update(args[0]) update(args[0])
elif command == 'info': elif command == 'info':
if len(args) != 1: if len(args) != 1:
print('info requires exactly one argument.') print('info requires exactly one argument.')
sys.exit(1) return 1
info(args[0]) info(args[0])
elif command == 'status': elif command == 'status':
status() status()
else: else:
print('Unknown command', command) print('Unknown command', command)
sys.exit(1) return 1
return 0
if __name__ == '__main__':
sys.exit(run(sys.argv[1:]))

@ -12,11 +12,11 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import backends, build from . import backends, build
import mesonlib from . import mesonlib
import uuid, os, sys import uuid, os, sys
from coredata import MesonException from .coredata import MesonException
class XCodeBackend(backends.Backend): class XCodeBackend(backends.Backend):
def __init__(self, build): def __init__(self, build):

@ -0,0 +1,20 @@
#!/usr/bin/env python3
# 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.
from mesonbuild import mconf
import sys
sys.exit(mconf.run(sys.argv[1:]))

@ -0,0 +1,20 @@
#!/usr/bin/env python3
# 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.
from mesonbuild import mgui
import sys
sys.exit(mgui.run(sys.argv))

@ -0,0 +1,20 @@
#!/usr/bin/env python3
# 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.
from mesonbuild import mintro
import sys
sys.exit(mintro.run(sys.argv[1:]))

@ -4,22 +4,15 @@ build system.
Dependencies Dependencies
Python http://python.org (version 3.3 or newer) Python http://python.org (version 3.4 or newer)
Ninja http://martine.github.com/ninja/ Ninja http://martine.github.com/ninja/
Installing from source Installing from source
You can run Meson directly from a revision control checkout or an You can run Meson directly from a revision control checkout or an
extracted tarball. Installing it system-wide is simple. extracted tarball. Meson is also available from PyPi, so it can
be installed with 'pip install meson'.
Configure step: None
Compile step: None
Unit test step: ./run_tests.py
Install step: [sudo] ./install_meson.py --prefix /your/prefix --destdir /destdir/path
The default value of prefix is /usr/local. The default value of destdir
is empty.
Running Running

@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Copyright 2013-2014 The Meson development team # Copyright 2013-2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -23,7 +23,7 @@ Not part of the main test suite because of two reasons:
Eventually migrate to something fancier.''' Eventually migrate to something fancier.'''
import os, subprocess, shutil, sys import os, subprocess, shutil, sys
import environment import mesonbuild.environment as environment
from run_tests import gather_tests from run_tests import gather_tests

@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Copyright 2012-2015 The Meson development team # Copyright 2012-2016 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -18,15 +18,16 @@ from glob import glob
import os, subprocess, shutil, sys, signal import os, subprocess, shutil, sys, signal
from io import StringIO from io import StringIO
import sys import sys
import environment from mesonbuild import environment
import mesonlib from mesonbuild import mesonlib
import mlog from mesonbuild import mlog
import meson, meson_test, meson_benchmark from mesonbuild import mesonmain
from mesonbuild.scripts import meson_test, meson_benchmark
import argparse import argparse
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
import time import time
from meson import backendlist from mesonbuild.mesonmain import backendlist
class TestResult: class TestResult:
def __init__(self, msg, stdo, stde, conftime=0, buildtime=0, testtime=0): def __init__(self, msg, stdo, stde, conftime=0, buildtime=0, testtime=0):
@ -44,7 +45,7 @@ print_debug = 'MESON_PRINT_TEST_OUTPUT' in os.environ
test_build_dir = 'work area' test_build_dir = 'work area'
install_dir = os.path.join(os.path.split(os.path.abspath(__file__))[0], 'install dir') install_dir = os.path.join(os.path.split(os.path.abspath(__file__))[0], 'install dir')
meson_command = './meson.py' meson_command = os.path.join(os.getcwd(), 'meson')
class StopException(Exception): class StopException(Exception):
def __init__(self): def __init__(self):
@ -154,7 +155,7 @@ def run_configure_inprocess(commandlist):
old_stderr = sys.stderr old_stderr = sys.stderr
sys.stderr = mystderr = StringIO() sys.stderr = mystderr = StringIO()
try: try:
returncode = meson.run(commandlist) returncode = mesonmain.run(commandlist[0], commandlist[1:])
finally: finally:
sys.stdout = old_stdout sys.stdout = old_stdout
sys.stderr = old_stderr sys.stderr = old_stderr

@ -0,0 +1,60 @@
#!/usr/bin/env python3
# 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.
# We need to support Python installations that have nothing but the basic
# Python installation. Use setuptools when possible and fall back to
# plain distutils when setuptools is not available.
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
from mesonbuild.coredata import version
setup(name='meson',
version=version,
description='A high performance build system',
author='Jussi Pakkanen',
author_email='jpakkane@gmail.com',
url='http://mesonbuild.com',
license=' Apache License, Version 2.0',
packages=['mesonbuild',
'mesonbuild.modules',
'mesonbuild.scripts',
'mesonbuild.wrap'],
package_data={'mesonbuild': ['*.ui']},
scripts=['meson', 'mesonconf', 'mesongui', 'mesonintrospect', 'wraptool'],
data_files=[('share/man/man1', ['man/meson.1',
'man/mesonconf.1',
'man/mesongui.1',
'man/mesonintrospect.1',
'man/wraptool.1'])],
classifiers=['Development Status :: 5 - Production/Stable',
'Environment :: Console',
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License',
'Natural Language :: English',
'Operating System :: MacOS :: MacOS X',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX :: BSD',
'Operating System :: POSIX :: Linux',
'Programming Language :: Python :: 3 :: Only',
'Topic :: Software Development :: Build Tools',
],
long_description='''Meson is a cross-platform build system designed to be both as
fast and as user friendly as possible. It supports many languages and compilers, including
GCC, Clang and Visual Studio. Its build definitions are written in a simple non-turing
complete DSL.''')

@ -0,0 +1,20 @@
#!/usr/bin/env python3
# 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.
from mesonbuild.wrap import wraptool
import sys
sys.exit(wraptool.run(sys.argv[1:]))
Loading…
Cancel
Save