source: websoy/genie.py @ 45:0ae8e270840e

Revision 45:0ae8e270840e, 10.6 KB checked in by Arc Riley <arcriley@…>, 7 years ago (diff)

Upgrading waf genie tool

Line 
1#!/usr/bin/env python
2# encoding: utf-8
3# Ali Sabil, 2007
4# Radosław Szkodziński, 2010
5# Arc Riley, 2010, 2011, 2012
6
7"""
8At this point, vala is still unstable, so do not expect
9this tool to be too stable either (apis, etc)
10"""
11
12import os.path, shutil, re
13from waflib import Context, Task, Runner, Utils, Logs, Build, Node, Options, Errors
14from waflib.TaskGen import extension, after_method, before_method
15from waflib.Configure import conf
16
17class valac(Task.Task):
18        """
19        Task to compile vala files.
20        """
21        vars = ["VALAC", "VALAC_VERSION", "VALAFLAGS"]
22        ext_out = ['.h']
23
24        def run(self):
25                env = self.env
26
27                cmd = [env['VALAC'], '-C', '--quiet']
28                cmd.extend(Utils.to_list(env['VALAFLAGS']))
29
30                if self.threading:
31                        cmd.append('--thread')
32
33                if self.profile:
34                        cmd.append('--profile=%s' % self.profile)
35
36                if self.target_glib:
37                        cmd.append('--target-glib=%s' % self.target_glib)
38
39                if self.is_lib:
40                        output_dir = self.outputs[0].bld_dir()
41                        cmd.append('--library=' + self.target)
42                        for x in self.outputs:
43                                if x.name.endswith('.h'):
44                                        cmd.append('--header=' + x.name)
45                        if self.gir:
46                                cmd.append('--gir=%s.gir' % self.gir)
47
48                for vapi_dir in self.vapi_dirs:
49                        cmd.append('--vapidir=%s' % vapi_dir)
50
51                for package in self.packages:
52                        cmd.append('--pkg=%s' % package)
53
54                for package in self.packages_private:
55                        cmd.append('--pkg=%s' % package)
56
57                for define in self.vala_defines:
58                        cmd.append('--define=%s' % define)
59
60                cmd.extend([a.abspath() for a in self.inputs])
61                ret = self.exec_command(cmd, cwd=self.outputs[0].parent.abspath())
62
63                if ret:
64                        return ret
65
66                for x in self.outputs:
67                        if id(x.parent) != id(self.outputs[0].parent):
68                                shutil.move(self.outputs[0].parent.abspath() + os.sep + x.name, x.abspath())
69
70                if self.packages and getattr(self, 'deps_node', None):
71                        self.deps_node.write('\n'.join(self.packages))
72
73                return ret
74
75@extension('.vala', '.gs')
76def vala_file(self, node):
77        """
78        Compile a vala file and bind the task to *self.valatask*. If an existing vala task is already set, add the node
79        to its inputs. The typical example is::
80
81                def build(bld):
82                        bld.program(
83                                packages      = 'gtk+-2.0',
84                                target        = 'vala-gtk-example',
85                                uselib        = 'GTK GLIB',
86                                source        = 'vala-gtk-example.vala foo.vala',
87                                vala_defines  = ['DEBUG']
88                                # the following arguments are for libraries
89                                #gir          = 'hello-1.0',
90                                #gir_path     = '/tmp',
91                                #vapi_path = '/tmp',
92                                #pkg_name = 'hello'
93                        )
94
95
96        :param node: vala file
97        :type node: :py:class:`waflib.Node.Node`
98        """
99        # TODO: the vala task should use self.generator.attribute instead of copying attributes from self to the task
100        valatask = getattr(self, "valatask", None)
101        # there is only one vala task and it compiles all vala files .. :-/
102        if not valatask:
103                def _get_api_version():
104                        api_version = getattr (Context.g_module, 'API_VERSION', None)
105                        if api_version == None:
106                                version = Context.g_module.VERSION.split(".")
107                                if version[0] == "0":
108                                        api_version = "0." + version[1]
109                                else:
110                                        api_version = version[0]
111                        return api_version
112
113                valatask = self.create_task('valac')
114                self.valatask = valatask # this assumes one vala task by task generator
115                self.includes = Utils.to_list(getattr(self, 'includes', []))
116                self.uselib = self.to_list(getattr(self, 'uselib', []))
117                valatask.packages = []
118                valatask.packages_private = Utils.to_list(getattr(self, 'packages_private', []))
119                valatask.vapi_dirs = []
120                valatask.target = self.target
121                valatask.threading = False
122                valatask.install_path = getattr(self, 'install_path', '')
123                valatask.profile = getattr(self, 'profile', 'gobject')
124                valatask.vala_defines = getattr(self, 'vala_defines', [])
125                valatask.target_glib = None
126                valatask.gir = getattr(self, 'gir', None)
127                valatask.gir_path = getattr(self, 'gir_path', '${DATAROOTDIR}/gir-1.0')
128                valatask.vapi_path = getattr(self, 'vapi_path', '${DATAROOTDIR}/vala/vapi')
129                valatask.pkg_name = getattr(self, 'pkg_name', self.env['PACKAGE'])
130                valatask.header_path = getattr(self, 'header_path', '${INCLUDEDIR}/%s-%s' % (valatask.pkg_name, _get_api_version()))
131
132                valatask.is_lib = False
133                if not 'cprogram' in self.features:
134                        valatask.is_lib = True
135
136                packages = Utils.to_list(getattr(self, 'packages', []))
137                vapi_dirs = Utils.to_list(getattr(self, 'vapi_dirs', []))
138                includes =  []
139
140                if hasattr(self, 'use'):
141                        local_packages = Utils.to_list(self.use)[:] # make sure to have a copy
142                        seen = []
143                        while len(local_packages) > 0:
144                                package = local_packages.pop()
145                                if package in seen:
146                                        continue
147                                seen.append(package)
148
149                                # check if the package exists
150                                try:
151                                        package_obj = self.bld.get_tgen_by_name(package)
152                                except Errors.WafError:
153                                        continue
154                                package_name = package_obj.target
155                                package_node = package_obj.path
156                                package_dir = package_node.path_from(self.path)
157
158                                for task in package_obj.tasks:
159                                        for output in task.outputs:
160                                                if output.name == package_name + ".vapi":
161                                                        valatask.set_run_after(task)
162                                                        if package_name not in packages:
163                                                                packages.append(package_name)
164                                                        if package_dir not in vapi_dirs:
165                                                                vapi_dirs.append(package_dir)
166                                                        if package_dir not in includes:
167                                                                includes.append(package_dir)
168
169                                if hasattr(package_obj, 'use'):
170                                        lst = self.to_list(package_obj.use)
171                                        lst.reverse()
172                                        local_packages = [pkg for pkg in lst if pkg not in seen] + local_packages
173
174                valatask.packages = packages
175                for vapi_dir in vapi_dirs:
176                        try:
177                                valatask.vapi_dirs.append(self.path.find_dir(vapi_dir).abspath())
178                                valatask.vapi_dirs.append(self.path.find_dir(vapi_dir).get_bld().abspath())
179                        except AttributeError:
180                                Logs.warn("Unable to locate Vala API directory: '%s'" % vapi_dir)
181
182                self.includes.append(self.bld.srcnode.abspath())
183                self.includes.append(self.bld.bldnode.abspath())
184                for include in includes:
185                        try:
186                                self.includes.append(self.path.find_dir(include).abspath())
187                                self.includes.append(self.path.find_dir(include).get_bld().abspath())
188                        except AttributeError:
189                                Logs.warn("Unable to locate include directory: '%s'" % include)
190
191
192                if valatask.profile == 'gobject':
193                        if hasattr(self, 'target_glib'):
194                                Logs.warn('target_glib on vala tasks is not supported --vala-target-glib=MAJOR.MINOR from the vala tool options')
195
196                        if getattr(Options.options, 'vala_target_glib', None):
197                                valatask.target_glib = Options.options.vala_target_glib
198
199                        if not 'GOBJECT' in self.uselib:
200                                self.uselib.append('GOBJECT')
201
202                if hasattr(self, 'threading'):
203                        if valatask.profile == 'gobject':
204                                valatask.threading = self.threading
205                                if not 'GTHREAD' in self.uselib:
206                                        self.uselib.append('GTHREAD')
207                        else:
208                                #Vala doesn't have threading support for dova nor posix
209                                Logs.warn("Profile %s does not have threading support" % valatask.profile)
210
211                if valatask.is_lib:
212                        valatask.outputs.append(self.path.find_or_declare('%s.h' % self.name))
213                        valatask.outputs.append(self.path.find_or_declare('%s.vapi' % self.target))
214
215                        if valatask.gir:
216                                valatask.outputs.append(self.path.find_or_declare('%s.gir' % self.gir))
217
218                        if valatask.packages:
219                                d = self.path.find_or_declare('%s.deps' % self.target)
220                                valatask.outputs.append(d)
221                                valatask.deps_node = d
222
223        valatask.inputs.append(node)
224        c_node = node.change_ext('.c')
225
226        valatask.outputs.append(c_node)
227        self.source.append(c_node)
228
229        if valatask.is_lib:
230                headers_list = [o for o in valatask.outputs if o.suffix() == ".h"]
231                try:
232                        self.install_vheader.source = headers_list
233                except AttributeError:
234                        self.install_vheader = self.bld.install_files(valatask.header_path, headers_list, self.env)
235
236                vapi_list = [o for o in valatask.outputs if (o.suffix() in (".vapi", ".deps"))]
237                try:
238                        self.install_vapi.source = vapi_list
239                except AttributeError:
240                        self.install_vapi = self.bld.install_files(valatask.vapi_path, vapi_list, self.env)
241
242                gir_list = [o for o in valatask.outputs if o.suffix() == ".gir"]
243                try:
244                        self.install_gir.source = gir_list
245                except AttributeError:
246                        self.install_gir = self.bld.install_files(valatask.gir_path, gir_list, self.env)
247
248valac = Task.update_outputs(valac) # no decorators for python2 classes
249
250@conf
251def check_vala(self, min_version=(0,11,7), branches=('0.18', '0.16', '0.14', '0.12')):
252    """
253    Check if vala compiler from a given branch exists of at least a given
254    version.
255
256    :param min_version: minimum version acceptable (0.11.7)
257    :type min_version: tuple
258    :param branches: branches of valac able to compile the program
259    :type branches: tuple of string
260"""
261    valac = None
262    for branch in branches:
263        try:
264            valac_name = 'valac-'+branch
265            valac = self.find_program(valac_name, var='VALAC')
266        except:
267            continue
268        break
269
270    # No acceptable branches found, try valac by itself, fail if not found
271    if not valac:
272        valac_name = 'valac'
273        valac = self.find_program(valac_name, var='VALAC')
274       
275    output = self.cmd_and_log(valac + ' --version')
276    if output == "UNKNOWN" :
277        output = branch+'.0' # best guess
278    ver = re.search(r'\d+.\d+.\d+', output).group(0).split('.')
279    valac_version = tuple([int(x) for x in ver])
280    self.msg('Checking for %s version >= %r' % (valac_name, min_version),
281             valac_version, valac_version and valac_version >= min_version)
282    if valac_version < min_version:
283        self.fatal("%s version %r is too old, need >= %r" % (valac_name, valac_version, min_version))
284    self.env['VALAC_VERSION'] = valac_version
285
286
287@conf
288def check_vala_deps(self):
289        """
290        Load the gobject and gthread packages if they are missing.
291        """
292        if not self.env['HAVE_GOBJECT']:
293                pkg_args = {'package':      'gobject-2.0',
294                            'uselib_store': 'GOBJECT',
295                            'args':         '--cflags --libs'}
296                if getattr(Options.options, 'vala_target_glib', None):
297                        pkg_args['atleast_version'] = Options.options.vala_target_glib
298                self.check_cfg(**pkg_args)
299
300        if not self.env['HAVE_GTHREAD']:
301                pkg_args = {'package':      'gthread-2.0',
302                            'uselib_store': 'GTHREAD',
303                            'args':         '--cflags --libs'}
304                if getattr(Options.options, 'vala_target_glib', None):
305                        pkg_args['atleast_version'] = Options.options.vala_target_glib
306                self.check_cfg(**pkg_args)
307
308def configure(self):
309        """
310        Use the following to enforce minimum vala version::
311
312                def configure(conf):
313                        conf.load('vala', funs='')
314                        conf.check_vala(min_version=(0,10,0))
315        """
316        self.load('gnu_dirs')
317        self.check_vala_deps()
318        self.check_vala()
319
320def options(opt):
321        """
322        Load the :py:mod:`waflib.Tools.gnu_dirs` tool and add the ``--vala-target-glib`` command-line option
323        """
324        opt.load('gnu_dirs')
325        valaopts = opt.add_option_group('Vala Compiler Options')
326        valaopts.add_option ('--vala-target-glib', default=None,
327                dest='vala_target_glib', metavar='MAJOR.MINOR',
328                help='Target version of glib for Vala GObject code generation')
329
Note: See TracBrowser for help on using the repository browser.