123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- #!/usr/bin/env python
- # encoding: utf-8
- # Ali Sabil, 2007
- # Radosław Szkodziński, 2010
- """
- At this point, vala is still unstable, so do not expect
- this tool to be too stable either (apis, etc)
- """
- import re
- from waflib import Build, Context, Errors, Logs, Node, Options, Task, Utils
- from waflib.TaskGen import extension, taskgen_method
- from waflib.Configure import conf
- class valac(Task.Task):
- """
- Compiles vala files
- """
- #run_str = "${VALAC} ${VALAFLAGS}" # ideally
- #vars = ['VALAC_VERSION']
- vars = ["VALAC", "VALAC_VERSION", "VALAFLAGS"]
- ext_out = ['.h']
- def run(self):
- cmd = self.env.VALAC + self.env.VALAFLAGS
- resources = getattr(self, 'vala_exclude', [])
- cmd.extend([a.abspath() for a in self.inputs if a not in resources])
- ret = self.exec_command(cmd, cwd=self.vala_dir_node.abspath())
- if ret:
- return ret
- if self.generator.dump_deps_node:
- self.generator.dump_deps_node.write('\n'.join(self.generator.packages))
- return ret
- @taskgen_method
- def init_vala_task(self):
- """
- Initializes the vala task with the relevant data (acts as a constructor)
- """
- self.profile = getattr(self, 'profile', 'gobject')
- self.packages = packages = Utils.to_list(getattr(self, 'packages', []))
- self.use = Utils.to_list(getattr(self, 'use', []))
- if packages and not self.use:
- self.use = packages[:] # copy
- if self.profile == 'gobject':
- if not 'GOBJECT' in self.use:
- self.use.append('GOBJECT')
- def addflags(flags):
- self.env.append_value('VALAFLAGS', flags)
- if self.profile:
- addflags('--profile=%s' % self.profile)
- valatask = self.valatask
- # output directory
- if hasattr(self, 'vala_dir'):
- if isinstance(self.vala_dir, str):
- valatask.vala_dir_node = self.path.get_bld().make_node(self.vala_dir)
- try:
- valatask.vala_dir_node.mkdir()
- except OSError:
- raise self.bld.fatal('Cannot create the vala dir %r' % valatask.vala_dir_node)
- else:
- valatask.vala_dir_node = self.vala_dir
- else:
- valatask.vala_dir_node = self.path.get_bld()
- addflags('--directory=%s' % valatask.vala_dir_node.abspath())
- if hasattr(self, 'thread'):
- if self.profile == 'gobject':
- if not 'GTHREAD' in self.use:
- self.use.append('GTHREAD')
- else:
- #Vala doesn't have threading support for dova nor posix
- Logs.warn('Profile %s means no threading support', self.profile)
- self.thread = False
- if self.thread:
- addflags('--thread')
- self.is_lib = 'cprogram' not in self.features
- if self.is_lib:
- addflags('--library=%s' % self.target)
- h_node = valatask.vala_dir_node.find_or_declare('%s.h' % self.target)
- valatask.outputs.append(h_node)
- addflags('--header=%s' % h_node.name)
- valatask.outputs.append(valatask.vala_dir_node.find_or_declare('%s.vapi' % self.target))
- if getattr(self, 'gir', None):
- gir_node = valatask.vala_dir_node.find_or_declare('%s.gir' % self.gir)
- addflags('--gir=%s' % gir_node.name)
- valatask.outputs.append(gir_node)
- self.vala_target_glib = getattr(self, 'vala_target_glib', getattr(Options.options, 'vala_target_glib', None))
- if self.vala_target_glib:
- addflags('--target-glib=%s' % self.vala_target_glib)
- addflags(['--define=%s' % x for x in Utils.to_list(getattr(self, 'vala_defines', []))])
- packages_private = Utils.to_list(getattr(self, 'packages_private', []))
- addflags(['--pkg=%s' % x for x in packages_private])
- def _get_api_version():
- api_version = '1.0'
- if hasattr(Context.g_module, 'API_VERSION'):
- version = Context.g_module.API_VERSION.split(".")
- if version[0] == "0":
- api_version = "0." + version[1]
- else:
- api_version = version[0] + ".0"
- return api_version
- self.includes = Utils.to_list(getattr(self, 'includes', []))
- valatask.install_path = getattr(self, 'install_path', '')
- valatask.vapi_path = getattr(self, 'vapi_path', '${DATAROOTDIR}/vala/vapi')
- valatask.pkg_name = getattr(self, 'pkg_name', self.env.PACKAGE)
- valatask.header_path = getattr(self, 'header_path', '${INCLUDEDIR}/%s-%s' % (valatask.pkg_name, _get_api_version()))
- valatask.install_binding = getattr(self, 'install_binding', True)
- self.vapi_dirs = vapi_dirs = Utils.to_list(getattr(self, 'vapi_dirs', []))
- #includes = []
- if hasattr(self, 'use'):
- local_packages = Utils.to_list(self.use)[:] # make sure to have a copy
- seen = []
- while len(local_packages) > 0:
- package = local_packages.pop()
- if package in seen:
- continue
- seen.append(package)
- # check if the package exists
- try:
- package_obj = self.bld.get_tgen_by_name(package)
- except Errors.WafError:
- continue
- # in practice the other task is already processed
- # but this makes it explicit
- package_obj.post()
- package_name = package_obj.target
- task = getattr(package_obj, 'valatask', None)
- if task:
- for output in task.outputs:
- if output.name == package_name + ".vapi":
- valatask.set_run_after(task)
- if package_name not in packages:
- packages.append(package_name)
- if output.parent not in vapi_dirs:
- vapi_dirs.append(output.parent)
- if output.parent not in self.includes:
- self.includes.append(output.parent)
- if hasattr(package_obj, 'use'):
- lst = self.to_list(package_obj.use)
- lst.reverse()
- local_packages = [pkg for pkg in lst if pkg not in seen] + local_packages
- addflags(['--pkg=%s' % p for p in packages])
- for vapi_dir in vapi_dirs:
- if isinstance(vapi_dir, Node.Node):
- v_node = vapi_dir
- else:
- v_node = self.path.find_dir(vapi_dir)
- if not v_node:
- Logs.warn('Unable to locate Vala API directory: %r', vapi_dir)
- else:
- addflags('--vapidir=%s' % v_node.abspath())
- self.dump_deps_node = None
- if self.is_lib and self.packages:
- self.dump_deps_node = valatask.vala_dir_node.find_or_declare('%s.deps' % self.target)
- valatask.outputs.append(self.dump_deps_node)
- if self.is_lib and valatask.install_binding:
- headers_list = [o for o in valatask.outputs if o.suffix() == ".h"]
- if headers_list:
- self.install_vheader = self.add_install_files(install_to=valatask.header_path, install_from=headers_list)
- vapi_list = [o for o in valatask.outputs if (o.suffix() in (".vapi", ".deps"))]
- if vapi_list:
- self.install_vapi = self.add_install_files(install_to=valatask.vapi_path, install_from=vapi_list)
- gir_list = [o for o in valatask.outputs if o.suffix() == '.gir']
- if gir_list:
- self.install_gir = self.add_install_files(
- install_to=getattr(self, 'gir_path', '${DATAROOTDIR}/gir-1.0'), install_from=gir_list)
- if hasattr(self, 'vala_resources'):
- nodes = self.to_nodes(self.vala_resources)
- valatask.vala_exclude = getattr(valatask, 'vala_exclude', []) + nodes
- valatask.inputs.extend(nodes)
- for x in nodes:
- addflags(['--gresources', x.abspath()])
- @extension('.vala', '.gs')
- def vala_file(self, node):
- """
- Compile a vala file and bind the task to *self.valatask*. If an existing vala task is already set, add the node
- to its inputs. The typical example is::
- def build(bld):
- bld.program(
- packages = 'gtk+-2.0',
- target = 'vala-gtk-example',
- use = 'GTK GLIB',
- source = 'vala-gtk-example.vala foo.vala',
- vala_defines = ['DEBUG'] # adds --define=<xyz> values to the command-line
- # the following arguments are for libraries
- #gir = 'hello-1.0',
- #gir_path = '/tmp',
- #vapi_path = '/tmp',
- #pkg_name = 'hello'
- # disable installing of gir, vapi and header
- #install_binding = False
- # profile = 'xyz' # adds --profile=<xyz> to enable profiling
- # thread = True, # adds --thread, except if profile is on or not on 'gobject'
- # vala_target_glib = 'xyz' # adds --target-glib=<xyz>, can be given through the command-line option --vala-target-glib=<xyz>
- )
- :param node: vala file
- :type node: :py:class:`waflib.Node.Node`
- """
- try:
- valatask = self.valatask
- except AttributeError:
- valatask = self.valatask = self.create_task('valac')
- self.init_vala_task()
- valatask.inputs.append(node)
- name = node.name[:node.name.rfind('.')] + '.c'
- c_node = valatask.vala_dir_node.find_or_declare(name)
- valatask.outputs.append(c_node)
- self.source.append(c_node)
- @extension('.vapi')
- def vapi_file(self, node):
- try:
- valatask = self.valatask
- except AttributeError:
- valatask = self.valatask = self.create_task('valac')
- self.init_vala_task()
- valatask.inputs.append(node)
- @conf
- def find_valac(self, valac_name, min_version):
- """
- Find the valac program, and execute it to store the version
- number in *conf.env.VALAC_VERSION*
- :param valac_name: program name
- :type valac_name: string or list of string
- :param min_version: minimum version acceptable
- :type min_version: tuple of int
- """
- valac = self.find_program(valac_name, var='VALAC')
- try:
- output = self.cmd_and_log(valac + ['--version'])
- except Errors.WafError:
- valac_version = None
- else:
- ver = re.search(r'\d+.\d+.\d+', output).group().split('.')
- valac_version = tuple([int(x) for x in ver])
- self.msg('Checking for %s version >= %r' % (valac_name, min_version),
- valac_version, valac_version and valac_version >= min_version)
- if valac and valac_version < min_version:
- self.fatal("%s version %r is too old, need >= %r" % (valac_name, valac_version, min_version))
- self.env.VALAC_VERSION = valac_version
- return valac
- @conf
- def check_vala(self, min_version=(0,8,0), branch=None):
- """
- Check if vala compiler from a given branch exists of at least a given
- version.
- :param min_version: minimum version acceptable (0.8.0)
- :type min_version: tuple
- :param branch: first part of the version number, in case a snapshot is used (0, 8)
- :type branch: tuple of int
- """
- if self.env.VALA_MINVER:
- min_version = self.env.VALA_MINVER
- if self.env.VALA_MINVER_BRANCH:
- branch = self.env.VALA_MINVER_BRANCH
- if not branch:
- branch = min_version[:2]
- try:
- find_valac(self, 'valac-%d.%d' % (branch[0], branch[1]), min_version)
- except self.errors.ConfigurationError:
- find_valac(self, 'valac', min_version)
- @conf
- def check_vala_deps(self):
- """
- Load the gobject and gthread packages if they are missing.
- """
- if not self.env.HAVE_GOBJECT:
- pkg_args = {'package': 'gobject-2.0',
- 'uselib_store': 'GOBJECT',
- 'args': '--cflags --libs'}
- if getattr(Options.options, 'vala_target_glib', None):
- pkg_args['atleast_version'] = Options.options.vala_target_glib
- self.check_cfg(**pkg_args)
- if not self.env.HAVE_GTHREAD:
- pkg_args = {'package': 'gthread-2.0',
- 'uselib_store': 'GTHREAD',
- 'args': '--cflags --libs'}
- if getattr(Options.options, 'vala_target_glib', None):
- pkg_args['atleast_version'] = Options.options.vala_target_glib
- self.check_cfg(**pkg_args)
- def configure(self):
- """
- Use the following to enforce minimum vala version::
- def configure(conf):
- conf.env.VALA_MINVER = (0, 10, 0)
- conf.load('vala')
- """
- self.load('gnu_dirs')
- self.check_vala_deps()
- self.check_vala()
- self.add_os_flags('VALAFLAGS')
- self.env.append_unique('VALAFLAGS', ['-C'])
- def options(opt):
- """
- Load the :py:mod:`waflib.Tools.gnu_dirs` tool and add the ``--vala-target-glib`` command-line option
- """
- opt.load('gnu_dirs')
- valaopts = opt.add_option_group('Vala Compiler Options')
- valaopts.add_option('--vala-target-glib', default=None,
- dest='vala_target_glib', metavar='MAJOR.MINOR',
- help='Target version of glib for Vala GObject code generation')
|