waf

FORK: waf with some random patches
git clone https://git.neptards.moe/neptards/waf.git
Log | Files | Refs | README

vala.py (11373B)


      1 #!/usr/bin/env python
      2 # encoding: utf-8
      3 # Ali Sabil, 2007
      4 # Radosław Szkodziński, 2010
      5 
      6 """
      7 At this point, vala is still unstable, so do not expect
      8 this tool to be too stable either (apis, etc)
      9 """
     10 
     11 import re
     12 from waflib import Build, Context, Errors, Logs, Node, Options, Task, Utils
     13 from waflib.TaskGen import extension, taskgen_method
     14 from waflib.Configure import conf
     15 
     16 class valac(Task.Task):
     17 	"""
     18 	Compiles vala files
     19 	"""
     20 	#run_str = "${VALAC} ${VALAFLAGS}" # ideally
     21 	#vars = ['VALAC_VERSION']
     22 	vars = ["VALAC", "VALAC_VERSION", "VALAFLAGS"]
     23 	ext_out = ['.h']
     24 
     25 	def run(self):
     26 		cmd = self.env.VALAC + self.env.VALAFLAGS
     27 		resources = getattr(self, 'vala_exclude', [])
     28 		cmd.extend([a.abspath() for a in self.inputs if a not in resources])
     29 		ret = self.exec_command(cmd, cwd=self.vala_dir_node.abspath())
     30 
     31 		if ret:
     32 			return ret
     33 
     34 		if self.generator.dump_deps_node:
     35 			self.generator.dump_deps_node.write('\n'.join(self.generator.packages))
     36 
     37 		return ret
     38 
     39 @taskgen_method
     40 def init_vala_task(self):
     41 	"""
     42 	Initializes the vala task with the relevant data (acts as a constructor)
     43 	"""
     44 	self.profile = getattr(self, 'profile', 'gobject')
     45 
     46 	self.packages = packages = Utils.to_list(getattr(self, 'packages', []))
     47 	self.use = Utils.to_list(getattr(self, 'use', []))
     48 	if packages and not self.use:
     49 		self.use = packages[:] # copy
     50 
     51 	if self.profile == 'gobject':
     52 		if not 'GOBJECT' in self.use:
     53 			self.use.append('GOBJECT')
     54 
     55 	def addflags(flags):
     56 		self.env.append_value('VALAFLAGS', flags)
     57 
     58 	if self.profile:
     59 		addflags('--profile=%s' % self.profile)
     60 
     61 	valatask = self.valatask
     62 
     63 	# output directory
     64 	if hasattr(self, 'vala_dir'):
     65 		if isinstance(self.vala_dir, str):
     66 			valatask.vala_dir_node = self.path.get_bld().make_node(self.vala_dir)
     67 			try:
     68 				valatask.vala_dir_node.mkdir()
     69 			except OSError:
     70 				raise self.bld.fatal('Cannot create the vala dir %r' % valatask.vala_dir_node)
     71 		else:
     72 			valatask.vala_dir_node = self.vala_dir
     73 	else:
     74 		valatask.vala_dir_node = self.path.get_bld()
     75 	addflags('--directory=%s' % valatask.vala_dir_node.abspath())
     76 
     77 	if hasattr(self, 'thread'):
     78 		if self.profile == 'gobject':
     79 			if not 'GTHREAD' in self.use:
     80 				self.use.append('GTHREAD')
     81 		else:
     82 			#Vala doesn't have threading support for dova nor posix
     83 			Logs.warn('Profile %s means no threading support', self.profile)
     84 			self.thread = False
     85 
     86 		if self.thread:
     87 			addflags('--thread')
     88 
     89 	self.is_lib = 'cprogram' not in self.features
     90 	if self.is_lib:
     91 		addflags('--library=%s' % self.target)
     92 
     93 		h_node = valatask.vala_dir_node.find_or_declare('%s.h' % self.target)
     94 		valatask.outputs.append(h_node)
     95 		addflags('--header=%s' % h_node.name)
     96 
     97 		valatask.outputs.append(valatask.vala_dir_node.find_or_declare('%s.vapi' % self.target))
     98 
     99 		if getattr(self, 'gir', None):
    100 			gir_node = valatask.vala_dir_node.find_or_declare('%s.gir' % self.gir)
    101 			addflags('--gir=%s' % gir_node.name)
    102 			valatask.outputs.append(gir_node)
    103 
    104 	self.vala_target_glib = getattr(self, 'vala_target_glib', getattr(Options.options, 'vala_target_glib', None))
    105 	if self.vala_target_glib:
    106 		addflags('--target-glib=%s' % self.vala_target_glib)
    107 
    108 	addflags(['--define=%s' % x for x in Utils.to_list(getattr(self, 'vala_defines', []))])
    109 
    110 	packages_private = Utils.to_list(getattr(self, 'packages_private', []))
    111 	addflags(['--pkg=%s' % x for x in packages_private])
    112 
    113 	def _get_api_version():
    114 		api_version = '1.0'
    115 		if hasattr(Context.g_module, 'API_VERSION'):
    116 			version = Context.g_module.API_VERSION.split(".")
    117 			if version[0] == "0":
    118 				api_version = "0." + version[1]
    119 			else:
    120 				api_version = version[0] + ".0"
    121 		return api_version
    122 
    123 	self.includes = Utils.to_list(getattr(self, 'includes', []))
    124 	valatask.install_path = getattr(self, 'install_path', '')
    125 
    126 	valatask.vapi_path = getattr(self, 'vapi_path', '${DATAROOTDIR}/vala/vapi')
    127 	valatask.pkg_name = getattr(self, 'pkg_name', self.env.PACKAGE)
    128 	valatask.header_path = getattr(self, 'header_path', '${INCLUDEDIR}/%s-%s' % (valatask.pkg_name, _get_api_version()))
    129 	valatask.install_binding = getattr(self, 'install_binding', True)
    130 
    131 	self.vapi_dirs = vapi_dirs = Utils.to_list(getattr(self, 'vapi_dirs', []))
    132 	#includes =  []
    133 
    134 	if hasattr(self, 'use'):
    135 		local_packages = Utils.to_list(self.use)[:] # make sure to have a copy
    136 		seen = []
    137 		while len(local_packages) > 0:
    138 			package = local_packages.pop()
    139 			if package in seen:
    140 				continue
    141 			seen.append(package)
    142 
    143 			# check if the package exists
    144 			try:
    145 				package_obj = self.bld.get_tgen_by_name(package)
    146 			except Errors.WafError:
    147 				continue
    148 
    149 			# in practice the other task is already processed
    150 			# but this makes it explicit
    151 			package_obj.post()
    152 			package_name = package_obj.target
    153 			task = getattr(package_obj, 'valatask', None)
    154 			if task:
    155 				for output in task.outputs:
    156 					if output.name == package_name + ".vapi":
    157 						valatask.set_run_after(task)
    158 						if package_name not in packages:
    159 							packages.append(package_name)
    160 						if output.parent not in vapi_dirs:
    161 							vapi_dirs.append(output.parent)
    162 						if output.parent not in self.includes:
    163 							self.includes.append(output.parent)
    164 
    165 			if hasattr(package_obj, 'use'):
    166 				lst = self.to_list(package_obj.use)
    167 				lst.reverse()
    168 				local_packages = [pkg for pkg in lst if pkg not in seen] + local_packages
    169 
    170 	addflags(['--pkg=%s' % p for p in packages])
    171 
    172 	for vapi_dir in vapi_dirs:
    173 		if isinstance(vapi_dir, Node.Node):
    174 			v_node = vapi_dir
    175 		else:
    176 			v_node = self.path.find_dir(vapi_dir)
    177 		if not v_node:
    178 			Logs.warn('Unable to locate Vala API directory: %r', vapi_dir)
    179 		else:
    180 			addflags('--vapidir=%s' % v_node.abspath())
    181 
    182 	self.dump_deps_node = None
    183 	if self.is_lib and self.packages:
    184 		self.dump_deps_node = valatask.vala_dir_node.find_or_declare('%s.deps' % self.target)
    185 		valatask.outputs.append(self.dump_deps_node)
    186 
    187 	if self.is_lib and valatask.install_binding:
    188 		headers_list = [o for o in valatask.outputs if o.suffix() == ".h"]
    189 		if headers_list:
    190 			self.install_vheader = self.add_install_files(install_to=valatask.header_path, install_from=headers_list)
    191 
    192 		vapi_list = [o for o in valatask.outputs if (o.suffix() in (".vapi", ".deps"))]
    193 		if vapi_list:
    194 			self.install_vapi = self.add_install_files(install_to=valatask.vapi_path, install_from=vapi_list)
    195 
    196 		gir_list = [o for o in valatask.outputs if o.suffix() == '.gir']
    197 		if gir_list:
    198 			self.install_gir = self.add_install_files(
    199 				install_to=getattr(self, 'gir_path', '${DATAROOTDIR}/gir-1.0'), install_from=gir_list)
    200 
    201 	if hasattr(self, 'vala_resources'):
    202 		nodes = self.to_nodes(self.vala_resources)
    203 		valatask.vala_exclude = getattr(valatask, 'vala_exclude', []) + nodes
    204 		valatask.inputs.extend(nodes)
    205 		for x in nodes:
    206 			addflags(['--gresources', x.abspath()])
    207 
    208 @extension('.vala', '.gs')
    209 def vala_file(self, node):
    210 	"""
    211 	Compile a vala file and bind the task to *self.valatask*. If an existing vala task is already set, add the node
    212 	to its inputs. The typical example is::
    213 
    214 		def build(bld):
    215 			bld.program(
    216 				packages      = 'gtk+-2.0',
    217 				target        = 'vala-gtk-example',
    218 				use           = 'GTK GLIB',
    219 				source        = 'vala-gtk-example.vala foo.vala',
    220 				vala_defines  = ['DEBUG'] # adds --define=<xyz> values to the command-line
    221 
    222 				# the following arguments are for libraries
    223 				#gir          = 'hello-1.0',
    224 				#gir_path     = '/tmp',
    225 				#vapi_path = '/tmp',
    226 				#pkg_name = 'hello'
    227 				# disable installing of gir, vapi and header
    228 				#install_binding = False
    229 
    230 				# profile     = 'xyz' # adds --profile=<xyz> to enable profiling
    231 				# thread      = True, # adds --thread, except if profile is on or not on 'gobject'
    232 				# vala_target_glib = 'xyz' # adds --target-glib=<xyz>, can be given through the command-line option --vala-target-glib=<xyz>
    233 			)
    234 
    235 
    236 	:param node: vala file
    237 	:type node: :py:class:`waflib.Node.Node`
    238 	"""
    239 
    240 	try:
    241 		valatask = self.valatask
    242 	except AttributeError:
    243 		valatask = self.valatask = self.create_task('valac')
    244 		self.init_vala_task()
    245 
    246 	valatask.inputs.append(node)
    247 	name = node.name[:node.name.rfind('.')] + '.c'
    248 	c_node = valatask.vala_dir_node.find_or_declare(name)
    249 	valatask.outputs.append(c_node)
    250 	self.source.append(c_node)
    251 
    252 @extension('.vapi')
    253 def vapi_file(self, node):
    254 	try:
    255 		valatask = self.valatask
    256 	except AttributeError:
    257 		valatask = self.valatask = self.create_task('valac')
    258 		self.init_vala_task()
    259 	valatask.inputs.append(node)
    260 
    261 @conf
    262 def find_valac(self, valac_name, min_version):
    263 	"""
    264 	Find the valac program, and execute it to store the version
    265 	number in *conf.env.VALAC_VERSION*
    266 
    267 	:param valac_name: program name
    268 	:type valac_name: string or list of string
    269 	:param min_version: minimum version acceptable
    270 	:type min_version: tuple of int
    271 	"""
    272 	valac = self.find_program(valac_name, var='VALAC')
    273 	try:
    274 		output = self.cmd_and_log(valac + ['--version'])
    275 	except Errors.WafError:
    276 		valac_version = None
    277 	else:
    278 		ver = re.search(r'\d+.\d+.\d+', output).group().split('.')
    279 		valac_version = tuple([int(x) for x in ver])
    280 
    281 	self.msg('Checking for %s version >= %r' % (valac_name, min_version),
    282 	         valac_version, valac_version and valac_version >= min_version)
    283 	if valac and valac_version < min_version:
    284 		self.fatal("%s version %r is too old, need >= %r" % (valac_name, valac_version, min_version))
    285 
    286 	self.env.VALAC_VERSION = valac_version
    287 	return valac
    288 
    289 @conf
    290 def check_vala(self, min_version=(0,8,0), branch=None):
    291 	"""
    292 	Check if vala compiler from a given branch exists of at least a given
    293 	version.
    294 
    295 	:param min_version: minimum version acceptable (0.8.0)
    296 	:type min_version: tuple
    297 	:param branch: first part of the version number, in case a snapshot is used (0, 8)
    298 	:type branch: tuple of int
    299 	"""
    300 	if self.env.VALA_MINVER:
    301 		min_version = self.env.VALA_MINVER
    302 	if self.env.VALA_MINVER_BRANCH:
    303 		branch = self.env.VALA_MINVER_BRANCH
    304 	if not branch:
    305 		branch = min_version[:2]
    306 	try:
    307 		find_valac(self, 'valac-%d.%d' % (branch[0], branch[1]), min_version)
    308 	except self.errors.ConfigurationError:
    309 		find_valac(self, 'valac', min_version)
    310 
    311 @conf
    312 def check_vala_deps(self):
    313 	"""
    314 	Load the gobject and gthread packages if they are missing.
    315 	"""
    316 	if not self.env.HAVE_GOBJECT:
    317 		pkg_args = {'package':      'gobject-2.0',
    318 		            'uselib_store': 'GOBJECT',
    319 		            'args':         '--cflags --libs'}
    320 		if getattr(Options.options, 'vala_target_glib', None):
    321 			pkg_args['atleast_version'] = Options.options.vala_target_glib
    322 		self.check_cfg(**pkg_args)
    323 
    324 	if not self.env.HAVE_GTHREAD:
    325 		pkg_args = {'package':      'gthread-2.0',
    326 		            'uselib_store': 'GTHREAD',
    327 		            'args':         '--cflags --libs'}
    328 		if getattr(Options.options, 'vala_target_glib', None):
    329 			pkg_args['atleast_version'] = Options.options.vala_target_glib
    330 		self.check_cfg(**pkg_args)
    331 
    332 def configure(self):
    333 	"""
    334 	Use the following to enforce minimum vala version::
    335 
    336 		def configure(conf):
    337 			conf.env.VALA_MINVER = (0, 10, 0)
    338 			conf.load('vala')
    339 	"""
    340 	self.load('gnu_dirs')
    341 	self.check_vala_deps()
    342 	self.check_vala()
    343 	self.add_os_flags('VALAFLAGS')
    344 	self.env.append_unique('VALAFLAGS', ['-C'])
    345 
    346 def options(opt):
    347 	"""
    348 	Load the :py:mod:`waflib.Tools.gnu_dirs` tool and add the ``--vala-target-glib`` command-line option
    349 	"""
    350 	opt.load('gnu_dirs')
    351 	valaopts = opt.add_option_group('Vala Compiler Options')
    352 	valaopts.add_option('--vala-target-glib', default=None,
    353 		dest='vala_target_glib', metavar='MAJOR.MINOR',
    354 		help='Target version of glib for Vala GObject code generation')
    355