753ee8d94e283aa36cbf71d70f72aaebad532630
[sfrench/samba-autobuild/.git] / buildtools / wafadmin / Tools / vala.py
1 #!/usr/bin/env python
2 # encoding: utf-8
3 # Ali Sabil, 2007
4
5 import os.path, shutil
6 import Task, Runner, Utils, Logs, Build, Node, Options
7 from TaskGen import extension, after, before
8
9 EXT_VALA = ['.vala', '.gs']
10
11 class valac_task(Task.Task):
12
13         vars = ("VALAC", "VALAC_VERSION", "VALAFLAGS")
14         before = ("cc", "cxx")
15
16         def run(self):
17                 env = self.env
18                 inputs = [a.srcpath(env) for a in self.inputs]
19                 valac = env['VALAC']
20                 vala_flags = env.get_flat('VALAFLAGS')
21                 top_src = self.generator.bld.srcnode.abspath()
22                 top_bld = self.generator.bld.srcnode.abspath(env)
23
24                 if env['VALAC_VERSION'] > (0, 1, 6):
25                         cmd = [valac, '-C', '--quiet', vala_flags]
26                 else:
27                         cmd = [valac, '-C', vala_flags]
28
29                 if self.threading:
30                         cmd.append('--thread')
31
32                 if self.profile:
33                         cmd.append('--profile=%s' % self.profile)
34
35                 if self.target_glib:
36                         cmd.append('--target-glib=%s' % self.target_glib)
37
38                 features = self.generator.features
39
40                 if 'cshlib' in features or 'cstaticlib' in features:
41                         output_dir = self.outputs[0].bld_dir(env)
42                         cmd.append('--library ' + self.target)
43                         if env['VALAC_VERSION'] >= (0, 7, 0):
44                                 for x in self.outputs:
45                                         if x.name.endswith('.h'):
46                                                 cmd.append('--header ' + x.bldpath(self.env))
47                         cmd.append('--basedir ' + top_src)
48                         cmd.append('-d ' + top_bld)
49                         if env['VALAC_VERSION'] > (0, 7, 2) and hasattr(self, 'gir'):
50                                 cmd.append('--gir=%s.gir' % self.gir)
51
52                 else:
53                         output_dir = self.outputs[0].bld_dir(env)
54                         cmd.append('-d %s' % output_dir)
55
56                 for vapi_dir in self.vapi_dirs:
57                         cmd.append('--vapidir=%s' % vapi_dir)
58
59                 for package in self.packages:
60                         cmd.append('--pkg %s' % package)
61
62                 for package in self.packages_private:
63                         cmd.append('--pkg %s' % package)
64
65                 cmd.append(" ".join(inputs))
66                 result = self.generator.bld.exec_command(" ".join(cmd))
67
68                 if not 'cprogram' in features:
69                         # generate the .deps file
70                         if self.packages:
71                                 filename = os.path.join(self.generator.path.abspath(env), "%s.deps" % self.target)
72                                 deps = open(filename, 'w')
73                                 for package in self.packages:
74                                         deps.write(package + '\n')
75                                 deps.close()
76
77                         # handle vala 0.1.6 who doesn't honor --directory for the generated .vapi
78                         self._fix_output("../%s.vapi" % self.target)
79                         # handle vala >= 0.1.7 who has a weid definition for --directory
80                         self._fix_output("%s.vapi" % self.target)
81                         # handle vala >= 0.2.0 who doesn't honor --directory for the generated .gidl
82                         self._fix_output("%s.gidl" % self.target)
83                         # handle vala >= 0.3.6 who doesn't honor --directory for the generated .gir
84                         self._fix_output("%s.gir" % self.target)
85                         if hasattr(self, 'gir'):
86                                 self._fix_output("%s.gir" % self.gir)
87
88                 first = None
89                 for node in self.outputs:
90                         if not first:
91                                 first = node
92                         else:
93                                 if first.parent.id != node.parent.id:
94                                         # issue #483
95                                         if env['VALAC_VERSION'] < (0, 7, 0):
96                                                 shutil.move(first.parent.abspath(self.env) + os.sep + node.name, node.abspath(self.env))
97                 return result
98
99         def install(self):
100                 bld = self.generator.bld
101                 features = self.generator.features
102
103                 if self.attr("install_path") and ("cshlib" in features or "cstaticlib" in features):
104                         headers_list = [o for o in self.outputs if o.suffix() == ".h"]
105                         vapi_list = [o for o in self.outputs if (o.suffix() in (".vapi", ".deps"))]
106                         gir_list = [o for o in self.outputs if o.suffix() == ".gir"]
107
108                         for header in headers_list:
109                                 top_src = self.generator.bld.srcnode
110                                 package = self.env['PACKAGE']
111                                 try:
112                                         api_version = Utils.g_module.API_VERSION
113                                 except AttributeError:
114                                         version = Utils.g_module.VERSION.split(".")
115                                         if version[0] == "0":
116                                                 api_version = "0." + version[1]
117                                         else:
118                                                 api_version = version[0] + ".0"
119                                 install_path = '${INCLUDEDIR}/%s-%s/%s' % (package, api_version, header.relpath_gen(top_src))
120                                 bld.install_as(install_path, header, self.env)
121                         bld.install_files('${DATAROOTDIR}/vala/vapi', vapi_list, self.env)
122                         bld.install_files('${DATAROOTDIR}/gir-1.0', gir_list, self.env)
123
124         def _fix_output(self, output):
125                 top_bld = self.generator.bld.srcnode.abspath(self.env)
126                 try:
127                         src = os.path.join(top_bld, output)
128                         dst = self.generator.path.abspath (self.env)
129                         shutil.move(src, dst)
130                 except:
131                         pass
132
133 @extension(EXT_VALA)
134 def vala_file(self, node):
135         valatask = getattr(self, "valatask", None)
136         # there is only one vala task and it compiles all vala files .. :-/
137         if not valatask:
138                 valatask = self.create_task('valac')
139                 self.valatask = valatask
140                 self.includes = Utils.to_list(getattr(self, 'includes', []))
141                 self.uselib = self.to_list(self.uselib)
142                 valatask.packages = []
143                 valatask.packages_private = Utils.to_list(getattr(self, 'packages_private', []))
144                 valatask.vapi_dirs = []
145                 valatask.target = self.target
146                 valatask.threading = False
147                 valatask.install_path = self.install_path
148                 valatask.profile = getattr (self, 'profile', 'gobject')
149                 valatask.target_glib = None #Deprecated
150
151                 packages = Utils.to_list(getattr(self, 'packages', []))
152                 vapi_dirs = Utils.to_list(getattr(self, 'vapi_dirs', []))
153                 includes =  []
154
155                 if hasattr(self, 'uselib_local'):
156                         local_packages = Utils.to_list(self.uselib_local)
157                         seen = []
158                         while len(local_packages) > 0:
159                                 package = local_packages.pop()
160                                 if package in seen:
161                                         continue
162                                 seen.append(package)
163
164                                 # check if the package exists
165                                 package_obj = self.name_to_obj(package)
166                                 if not package_obj:
167                                         raise Utils.WafError("object '%s' was not found in uselib_local (required by '%s')" % (package, self.name))
168
169                                 package_name = package_obj.target
170                                 package_node = package_obj.path
171                                 package_dir = package_node.relpath_gen(self.path)
172
173                                 for task in package_obj.tasks:
174                                         for output in task.outputs:
175                                                 if output.name == package_name + ".vapi":
176                                                         valatask.set_run_after(task)
177                                                         if package_name not in packages:
178                                                                 packages.append(package_name)
179                                                         if package_dir not in vapi_dirs:
180                                                                 vapi_dirs.append(package_dir)
181                                                         if package_dir not in includes:
182                                                                 includes.append(package_dir)
183
184                                 if hasattr(package_obj, 'uselib_local'):
185                                         lst = self.to_list(package_obj.uselib_local)
186                                         lst.reverse()
187                                         local_packages = [pkg for pkg in lst if pkg not in seen] + local_packages
188
189                 valatask.packages = packages
190                 for vapi_dir in vapi_dirs:
191                         try:
192                                 valatask.vapi_dirs.append(self.path.find_dir(vapi_dir).abspath())
193                                 valatask.vapi_dirs.append(self.path.find_dir(vapi_dir).abspath(self.env))
194                         except AttributeError:
195                                 Logs.warn("Unable to locate Vala API directory: '%s'" % vapi_dir)
196
197                 self.includes.append(node.bld.srcnode.abspath())
198                 self.includes.append(node.bld.srcnode.abspath(self.env))
199                 for include in includes:
200                         try:
201                                 self.includes.append(self.path.find_dir(include).abspath())
202                                 self.includes.append(self.path.find_dir(include).abspath(self.env))
203                         except AttributeError:
204                                 Logs.warn("Unable to locate include directory: '%s'" % include)
205
206                 if valatask.profile == 'gobject':
207                         if hasattr(self, 'target_glib'):
208                                 Logs.warn ('target_glib on vala tasks is deprecated --vala-target-glib=MAJOR.MINOR from the vala tool options')
209
210                         if getattr(Options.options, 'vala_target_glib', None):
211                                 valatask.target_glib = Options.options.vala_target_glib
212
213                         if not 'GOBJECT' in self.uselib:
214                                 self.uselib.append('GOBJECT')
215
216                 if hasattr(self, 'threading'):
217                         if valatask.profile == 'gobject':
218                                 valatask.threading = self.threading
219                                 if not 'GTHREAD' in self.uselib:
220                                         self.uselib.append('GTHREAD')
221                         else:
222                                 #Vala doesn't have threading support for dova nor posix
223                                 Logs.warn("Profile %s does not have threading support" % valatask.profile)
224
225                 if hasattr(self, 'gir'):
226                         valatask.gir = self.gir
227
228         env = valatask.env
229
230         output_nodes = []
231
232         c_node = node.change_ext('.c')
233         output_nodes.append(c_node)
234         self.allnodes.append(c_node)
235
236         if env['VALAC_VERSION'] < (0, 7, 0):
237                 output_nodes.append(node.change_ext('.h'))
238         else:
239                 if not 'cprogram' in self.features:
240                         output_nodes.append(self.path.find_or_declare('%s.h' % self.target))
241
242         if not 'cprogram' in self.features:
243                 output_nodes.append(self.path.find_or_declare('%s.vapi' % self.target))
244                 if env['VALAC_VERSION'] > (0, 7, 2):
245                         if hasattr(self, 'gir'):
246                                 output_nodes.append(self.path.find_or_declare('%s.gir' % self.gir))
247                 elif env['VALAC_VERSION'] > (0, 3, 5):
248                         output_nodes.append(self.path.find_or_declare('%s.gir' % self.target))
249                 elif env['VALAC_VERSION'] > (0, 1, 7):
250                         output_nodes.append(self.path.find_or_declare('%s.gidl' % self.target))
251                 if valatask.packages:
252                         output_nodes.append(self.path.find_or_declare('%s.deps' % self.target))
253
254         valatask.inputs.append(node)
255         valatask.outputs.extend(output_nodes)
256
257 def detect(conf):
258         min_version = (0, 1, 6)
259         min_version_str = "%d.%d.%d" % min_version
260
261         valac = conf.find_program('valac', var='VALAC', mandatory=True)
262
263         if not conf.env["HAVE_GOBJECT"]:
264                 pkg_args = {'package':      'gobject-2.0',
265                             'uselib_store': 'GOBJECT',
266                             'args':         '--cflags --libs'}
267                 if getattr(Options.options, 'vala_target_glib', None):
268                         pkg_args['atleast_version'] = Options.options.vala_target_glib
269
270                 conf.check_cfg(**pkg_args)
271
272         if not conf.env["HAVE_GTHREAD"]:
273                 pkg_args = {'package':      'gthread-2.0',
274                             'uselib_store': 'GTHREAD',
275                             'args':         '--cflags --libs'}
276                 if getattr(Options.options, 'vala_target_glib', None):
277                         pkg_args['atleast_version'] = Options.options.vala_target_glib
278
279                 conf.check_cfg(**pkg_args)
280
281         try:
282                 output = Utils.cmd_output(valac + " --version", silent=True)
283                 version = output.split(' ', 1)[-1].strip().split(".")[0:3]
284                 version = [int(x) for x in version]
285                 valac_version = tuple(version)
286         except Exception:
287                 valac_version = (0, 0, 0)
288
289         conf.check_message('program version',
290                         'valac >= ' + min_version_str,
291                         valac_version >= min_version,
292                         "%d.%d.%d" % valac_version)
293
294         conf.check_tool('gnu_dirs')
295
296         if valac_version < min_version:
297                 conf.fatal("valac version too old to be used with this tool")
298                 return
299
300         conf.env['VALAC_VERSION'] = valac_version
301         conf.env['VALAFLAGS'] = ''
302
303 def set_options (opt):
304         valaopts = opt.add_option_group('Vala Compiler Options')
305         valaopts.add_option ('--vala-target-glib', default=None,
306                              dest='vala_target_glib', metavar='MAJOR.MINOR',
307                              help='Target version of glib for Vala GObject code generation')
308