waf

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

glib2.py (15771B)


      1 #! /usr/bin/env python
      2 # encoding: utf-8
      3 # Thomas Nagy, 2006-2018 (ita)
      4 
      5 """
      6 Support for GLib2 tools:
      7 
      8 * marshal
      9 * enums
     10 * gsettings
     11 * gresource
     12 """
     13 
     14 import os
     15 import functools
     16 from waflib import Context, Task, Utils, Options, Errors, Logs
     17 from waflib.TaskGen import taskgen_method, before_method, feature, extension
     18 from waflib.Configure import conf
     19 
     20 ################## marshal files
     21 
     22 @taskgen_method
     23 def add_marshal_file(self, filename, prefix):
     24 	"""
     25 	Adds a file to the list of marshal files to process. Store them in the attribute *marshal_list*.
     26 
     27 	:param filename: xml file to compile
     28 	:type filename: string
     29 	:param prefix: marshal prefix (--prefix=prefix)
     30 	:type prefix: string
     31 	"""
     32 	if not hasattr(self, 'marshal_list'):
     33 		self.marshal_list = []
     34 	self.meths.append('process_marshal')
     35 	self.marshal_list.append((filename, prefix))
     36 
     37 @before_method('process_source')
     38 def process_marshal(self):
     39 	"""
     40 	Processes the marshal files stored in the attribute *marshal_list* to create :py:class:`waflib.Tools.glib2.glib_genmarshal` instances.
     41 	Adds the c file created to the list of source to process.
     42 	"""
     43 	for f, prefix in getattr(self, 'marshal_list', []):
     44 		node = self.path.find_resource(f)
     45 
     46 		if not node:
     47 			raise Errors.WafError('file not found %r' % f)
     48 
     49 		h_node = node.change_ext('.h')
     50 		c_node = node.change_ext('.c')
     51 
     52 		task = self.create_task('glib_genmarshal', node, [h_node, c_node])
     53 		task.env.GLIB_GENMARSHAL_PREFIX = prefix
     54 	self.source = self.to_nodes(getattr(self, 'source', []))
     55 	self.source.append(c_node)
     56 
     57 class glib_genmarshal(Task.Task):
     58 	vars    = ['GLIB_GENMARSHAL_PREFIX', 'GLIB_GENMARSHAL']
     59 	color   = 'BLUE'
     60 	ext_out = ['.h']
     61 	def run(self):
     62 		bld = self.generator.bld
     63 
     64 		get = self.env.get_flat
     65 		cmd1 = "%s %s --prefix=%s --header > %s" % (
     66 			get('GLIB_GENMARSHAL'),
     67 			self.inputs[0].srcpath(),
     68 			get('GLIB_GENMARSHAL_PREFIX'),
     69 			self.outputs[0].abspath()
     70 		)
     71 
     72 		ret = bld.exec_command(cmd1)
     73 		if ret:
     74 			return ret
     75 
     76 		#print self.outputs[1].abspath()
     77 		c = '''#include "%s"\n''' % self.outputs[0].name
     78 		self.outputs[1].write(c)
     79 
     80 		cmd2 = "%s %s --prefix=%s --body >> %s" % (
     81 			get('GLIB_GENMARSHAL'),
     82 			self.inputs[0].srcpath(),
     83 			get('GLIB_GENMARSHAL_PREFIX'),
     84 			self.outputs[1].abspath()
     85 		)
     86 		return bld.exec_command(cmd2)
     87 
     88 ########################## glib-mkenums
     89 
     90 @taskgen_method
     91 def add_enums_from_template(self, source='', target='', template='', comments=''):
     92 	"""
     93 	Adds a file to the list of enum files to process. Stores them in the attribute *enums_list*.
     94 
     95 	:param source: enum file to process
     96 	:type source: string
     97 	:param target: target file
     98 	:type target: string
     99 	:param template: template file
    100 	:type template: string
    101 	:param comments: comments
    102 	:type comments: string
    103 	"""
    104 	if not hasattr(self, 'enums_list'):
    105 		self.enums_list = []
    106 	self.meths.append('process_enums')
    107 	self.enums_list.append({'source': source,
    108 	                        'target': target,
    109 	                        'template': template,
    110 	                        'file-head': '',
    111 	                        'file-prod': '',
    112 	                        'file-tail': '',
    113 	                        'enum-prod': '',
    114 	                        'value-head': '',
    115 	                        'value-prod': '',
    116 	                        'value-tail': '',
    117 	                        'comments': comments})
    118 
    119 @taskgen_method
    120 def add_enums(self, source='', target='',
    121               file_head='', file_prod='', file_tail='', enum_prod='',
    122               value_head='', value_prod='', value_tail='', comments=''):
    123 	"""
    124 	Adds a file to the list of enum files to process. Stores them in the attribute *enums_list*.
    125 
    126 	:param source: enum file to process
    127 	:type source: string
    128 	:param target: target file
    129 	:type target: string
    130 	:param file_head: unused
    131 	:param file_prod: unused
    132 	:param file_tail: unused
    133 	:param enum_prod: unused
    134 	:param value_head: unused
    135 	:param value_prod: unused
    136 	:param value_tail: unused
    137 	:param comments: comments
    138 	:type comments: string
    139 	"""
    140 	if not hasattr(self, 'enums_list'):
    141 		self.enums_list = []
    142 	self.meths.append('process_enums')
    143 	self.enums_list.append({'source': source,
    144 	                        'template': '',
    145 	                        'target': target,
    146 	                        'file-head': file_head,
    147 	                        'file-prod': file_prod,
    148 	                        'file-tail': file_tail,
    149 	                        'enum-prod': enum_prod,
    150 	                        'value-head': value_head,
    151 	                        'value-prod': value_prod,
    152 	                        'value-tail': value_tail,
    153 	                        'comments': comments})
    154 
    155 @before_method('process_source')
    156 def process_enums(self):
    157 	"""
    158 	Processes the enum files stored in the attribute *enum_list* to create :py:class:`waflib.Tools.glib2.glib_mkenums` instances.
    159 	"""
    160 	for enum in getattr(self, 'enums_list', []):
    161 		task = self.create_task('glib_mkenums')
    162 		env = task.env
    163 
    164 		inputs = []
    165 
    166 		# process the source
    167 		source_list = self.to_list(enum['source'])
    168 		if not source_list:
    169 			raise Errors.WafError('missing source ' + str(enum))
    170 		source_list = [self.path.find_resource(k) for k in source_list]
    171 		inputs += source_list
    172 		env.GLIB_MKENUMS_SOURCE = [k.abspath() for k in source_list]
    173 
    174 		# find the target
    175 		if not enum['target']:
    176 			raise Errors.WafError('missing target ' + str(enum))
    177 		tgt_node = self.path.find_or_declare(enum['target'])
    178 		if tgt_node.name.endswith('.c'):
    179 			self.source.append(tgt_node)
    180 		env.GLIB_MKENUMS_TARGET = tgt_node.abspath()
    181 
    182 
    183 		options = []
    184 
    185 		if enum['template']: # template, if provided
    186 			template_node = self.path.find_resource(enum['template'])
    187 			options.append('--template %s' % (template_node.abspath()))
    188 			inputs.append(template_node)
    189 		params = {'file-head' : '--fhead',
    190 		           'file-prod' : '--fprod',
    191 		           'file-tail' : '--ftail',
    192 		           'enum-prod' : '--eprod',
    193 		           'value-head' : '--vhead',
    194 		           'value-prod' : '--vprod',
    195 		           'value-tail' : '--vtail',
    196 		           'comments': '--comments'}
    197 		for param, option in params.items():
    198 			if enum[param]:
    199 				options.append('%s %r' % (option, enum[param]))
    200 
    201 		env.GLIB_MKENUMS_OPTIONS = ' '.join(options)
    202 
    203 		# update the task instance
    204 		task.set_inputs(inputs)
    205 		task.set_outputs(tgt_node)
    206 
    207 class glib_mkenums(Task.Task):
    208 	"""
    209 	Processes enum files
    210 	"""
    211 	run_str = '${GLIB_MKENUMS} ${GLIB_MKENUMS_OPTIONS} ${GLIB_MKENUMS_SOURCE} > ${GLIB_MKENUMS_TARGET}'
    212 	color   = 'PINK'
    213 	ext_out = ['.h']
    214 
    215 ######################################### gsettings
    216 
    217 @taskgen_method
    218 def add_settings_schemas(self, filename_list):
    219 	"""
    220 	Adds settings files to process to *settings_schema_files*
    221 
    222 	:param filename_list: files
    223 	:type filename_list: list of string
    224 	"""
    225 	if not hasattr(self, 'settings_schema_files'):
    226 		self.settings_schema_files = []
    227 
    228 	if not isinstance(filename_list, list):
    229 		filename_list = [filename_list]
    230 
    231 	self.settings_schema_files.extend(filename_list)
    232 
    233 @taskgen_method
    234 def add_settings_enums(self, namespace, filename_list):
    235 	"""
    236 	Called only once by task generator to set the enums namespace.
    237 
    238 	:param namespace: namespace
    239 	:type namespace: string
    240 	:param filename_list: enum files to process
    241 	:type filename_list: file list
    242 	"""
    243 	if hasattr(self, 'settings_enum_namespace'):
    244 		raise Errors.WafError("Tried to add gsettings enums to %r more than once" % self.name)
    245 	self.settings_enum_namespace = namespace
    246 
    247 	if not isinstance(filename_list, list):
    248 		filename_list = [filename_list]
    249 	self.settings_enum_files = filename_list
    250 
    251 @feature('glib2')
    252 def process_settings(self):
    253 	"""
    254 	Processes the schema files in *settings_schema_files* to create :py:class:`waflib.Tools.glib2.glib_mkenums` instances. The
    255 	same files are validated through :py:class:`waflib.Tools.glib2.glib_validate_schema` tasks.
    256 
    257 	"""
    258 	enums_tgt_node = []
    259 	install_files = []
    260 
    261 	settings_schema_files = getattr(self, 'settings_schema_files', [])
    262 	if settings_schema_files and not self.env.GLIB_COMPILE_SCHEMAS:
    263 		raise Errors.WafError ("Unable to process GSettings schemas - glib-compile-schemas was not found during configure")
    264 
    265 	# 1. process gsettings_enum_files (generate .enums.xml)
    266 	#
    267 	if hasattr(self, 'settings_enum_files'):
    268 		enums_task = self.create_task('glib_mkenums')
    269 
    270 		source_list = self.settings_enum_files
    271 		source_list = [self.path.find_resource(k) for k in source_list]
    272 		enums_task.set_inputs(source_list)
    273 		enums_task.env.GLIB_MKENUMS_SOURCE = [k.abspath() for k in source_list]
    274 
    275 		target = self.settings_enum_namespace + '.enums.xml'
    276 		tgt_node = self.path.find_or_declare(target)
    277 		enums_task.set_outputs(tgt_node)
    278 		enums_task.env.GLIB_MKENUMS_TARGET = tgt_node.abspath()
    279 		enums_tgt_node = [tgt_node]
    280 
    281 		install_files.append(tgt_node)
    282 
    283 		options = '--comments "<!-- @comment@ -->" --fhead "<schemalist>" --vhead "  <@type@ id=\\"%s.@EnumName@\\">" --vprod "    <value nick=\\"@valuenick@\\" value=\\"@valuenum@\\"/>" --vtail "  </@type@>" --ftail "</schemalist>" ' % (self.settings_enum_namespace)
    284 		enums_task.env.GLIB_MKENUMS_OPTIONS = options
    285 
    286 	# 2. process gsettings_schema_files (validate .gschema.xml files)
    287 	#
    288 	for schema in settings_schema_files:
    289 		schema_task = self.create_task ('glib_validate_schema')
    290 
    291 		schema_node = self.path.find_resource(schema)
    292 		if not schema_node:
    293 			raise Errors.WafError("Cannot find the schema file %r" % schema)
    294 		install_files.append(schema_node)
    295 		source_list = enums_tgt_node + [schema_node]
    296 
    297 		schema_task.set_inputs (source_list)
    298 		schema_task.env.GLIB_COMPILE_SCHEMAS_OPTIONS = [("--schema-file=" + k.abspath()) for k in source_list]
    299 
    300 		target_node = schema_node.change_ext('.xml.valid')
    301 		schema_task.set_outputs (target_node)
    302 		schema_task.env.GLIB_VALIDATE_SCHEMA_OUTPUT = target_node.abspath()
    303 
    304 	# 3. schemas install task
    305 	def compile_schemas_callback(bld):
    306 		if not bld.is_install:
    307 			return
    308 		compile_schemas = Utils.to_list(bld.env.GLIB_COMPILE_SCHEMAS)
    309 		destdir = Options.options.destdir
    310 		paths = bld._compile_schemas_registered
    311 		if destdir:
    312 			paths = (os.path.join(destdir, path.lstrip(os.sep)) for path in paths)
    313 		for path in paths:
    314 			Logs.pprint('YELLOW', 'Updating GSettings schema cache %r' % path)
    315 			if self.bld.exec_command(compile_schemas + [path]):
    316 				Logs.warn('Could not update GSettings schema cache %r' % path)
    317 
    318 	if self.bld.is_install:
    319 		schemadir = self.env.GSETTINGSSCHEMADIR
    320 		if not schemadir:
    321 			raise Errors.WafError ('GSETTINGSSCHEMADIR not defined (should have been set up automatically during configure)')
    322 
    323 		if install_files:
    324 			self.add_install_files(install_to=schemadir, install_from=install_files)
    325 			registered_schemas = getattr(self.bld, '_compile_schemas_registered', None)
    326 			if not registered_schemas:
    327 				registered_schemas = self.bld._compile_schemas_registered = set()
    328 				self.bld.add_post_fun(compile_schemas_callback)
    329 			registered_schemas.add(schemadir)
    330 
    331 class glib_validate_schema(Task.Task):
    332 	"""
    333 	Validates schema files
    334 	"""
    335 	run_str = 'rm -f ${GLIB_VALIDATE_SCHEMA_OUTPUT} && ${GLIB_COMPILE_SCHEMAS} --dry-run ${GLIB_COMPILE_SCHEMAS_OPTIONS} && touch ${GLIB_VALIDATE_SCHEMA_OUTPUT}'
    336 	color   = 'PINK'
    337 
    338 ################## gresource
    339 
    340 @extension('.gresource.xml')
    341 def process_gresource_source(self, node):
    342 	"""
    343 	Creates tasks that turn ``.gresource.xml`` files to C code
    344 	"""
    345 	if not self.env.GLIB_COMPILE_RESOURCES:
    346 		raise Errors.WafError ("Unable to process GResource file - glib-compile-resources was not found during configure")
    347 
    348 	if 'gresource' in self.features:
    349 		return
    350 
    351 	h_node = node.change_ext('_xml.h')
    352 	c_node = node.change_ext('_xml.c')
    353 	self.create_task('glib_gresource_source', node, [h_node, c_node])
    354 	self.source.append(c_node)
    355 
    356 @feature('gresource')
    357 def process_gresource_bundle(self):
    358 	"""
    359 	Creates tasks to turn ``.gresource`` files from ``.gresource.xml`` files::
    360 
    361 		def build(bld):
    362 			bld(
    363 				features='gresource',
    364 				source=['resources1.gresource.xml', 'resources2.gresource.xml'],
    365 				install_path='${LIBDIR}/${PACKAGE}'
    366 			)
    367 
    368 	:param source: XML files to process
    369 	:type source: list of string
    370 	:param install_path: installation path
    371 	:type install_path: string
    372 	"""
    373 	for i in self.to_list(self.source):
    374 		node = self.path.find_resource(i)
    375 
    376 		task = self.create_task('glib_gresource_bundle', node, node.change_ext(''))
    377 		inst_to = getattr(self, 'install_path', None)
    378 		if inst_to:
    379 			self.add_install_files(install_to=inst_to, install_from=task.outputs)
    380 
    381 class glib_gresource_base(Task.Task):
    382 	"""
    383 	Base class for gresource based tasks
    384 	"""
    385 	color    = 'BLUE'
    386 	base_cmd = '${GLIB_COMPILE_RESOURCES} --sourcedir=${SRC[0].parent.srcpath()} --sourcedir=${SRC[0].bld_dir()}'
    387 
    388 	def scan(self):
    389 		"""
    390 		Scans gresource dependencies through ``glib-compile-resources --generate-dependencies command``
    391 		"""
    392 		bld = self.generator.bld
    393 		kw = {}
    394 		kw['cwd'] = self.get_cwd()
    395 		kw['quiet'] = Context.BOTH
    396 
    397 		cmd = Utils.subst_vars('${GLIB_COMPILE_RESOURCES} --sourcedir=%s --sourcedir=%s --generate-dependencies %s' % (
    398 			self.inputs[0].parent.srcpath(),
    399 			self.inputs[0].bld_dir(),
    400 			self.inputs[0].bldpath()
    401 		), self.env)
    402 
    403 		output = bld.cmd_and_log(cmd, **kw)
    404 
    405 		nodes = []
    406 		names = []
    407 		for dep in output.splitlines():
    408 			if dep:
    409 				node = bld.bldnode.find_node(dep)
    410 				if node:
    411 					nodes.append(node)
    412 				else:
    413 					names.append(dep)
    414 
    415 		return (nodes, names)
    416 
    417 class glib_gresource_source(glib_gresource_base):
    418 	"""
    419 	Task to generate C source code (.h and .c files) from a gresource.xml file
    420 	"""
    421 	vars    = ['GLIB_COMPILE_RESOURCES']
    422 	fun_h   = Task.compile_fun_shell(glib_gresource_base.base_cmd + ' --target=${TGT[0].abspath()} --generate-header ${SRC}')
    423 	fun_c   = Task.compile_fun_shell(glib_gresource_base.base_cmd + ' --target=${TGT[1].abspath()} --generate-source ${SRC}')
    424 	ext_out = ['.h']
    425 
    426 	def run(self):
    427 		return self.fun_h[0](self) or self.fun_c[0](self)
    428 
    429 class glib_gresource_bundle(glib_gresource_base):
    430 	"""
    431 	Task to generate a .gresource binary file from a gresource.xml file
    432 	"""
    433 	run_str = glib_gresource_base.base_cmd + ' --target=${TGT} ${SRC}'
    434 	shell   = True # temporary workaround for #795
    435 
    436 @conf
    437 def find_glib_genmarshal(conf):
    438 	conf.find_program('glib-genmarshal', var='GLIB_GENMARSHAL')
    439 
    440 @conf
    441 def find_glib_mkenums(conf):
    442 	if not conf.env.PERL:
    443 		conf.find_program('perl', var='PERL')
    444 	conf.find_program('glib-mkenums', interpreter='PERL', var='GLIB_MKENUMS')
    445 
    446 @conf
    447 def find_glib_compile_schemas(conf):
    448 	# when cross-compiling, gsettings.m4 locates the program with the following:
    449 	#   pkg-config --variable glib_compile_schemas gio-2.0
    450 	conf.find_program('glib-compile-schemas', var='GLIB_COMPILE_SCHEMAS')
    451 
    452 	def getstr(varname):
    453 		return getattr(Options.options, varname, getattr(conf.env,varname, ''))
    454 
    455 	gsettingsschemadir = getstr('GSETTINGSSCHEMADIR')
    456 	if not gsettingsschemadir:
    457 		datadir = getstr('DATADIR')
    458 		if not datadir:
    459 			prefix = conf.env.PREFIX
    460 			datadir = os.path.join(prefix, 'share')
    461 		gsettingsschemadir = os.path.join(datadir, 'glib-2.0', 'schemas')
    462 
    463 	conf.env.GSETTINGSSCHEMADIR = gsettingsschemadir
    464 
    465 @conf
    466 def find_glib_compile_resources(conf):
    467 	conf.find_program('glib-compile-resources', var='GLIB_COMPILE_RESOURCES')
    468 
    469 def configure(conf):
    470 	"""
    471 	Finds the following programs:
    472 
    473 	* *glib-genmarshal* and set *GLIB_GENMARSHAL*
    474 	* *glib-mkenums* and set *GLIB_MKENUMS*
    475 	* *glib-compile-schemas* and set *GLIB_COMPILE_SCHEMAS* (not mandatory)
    476 	* *glib-compile-resources* and set *GLIB_COMPILE_RESOURCES* (not mandatory)
    477 	"""
    478 	conf.find_glib_genmarshal()
    479 	conf.find_glib_mkenums()
    480 	conf.find_glib_compile_schemas(mandatory=False)
    481 	conf.find_glib_compile_resources(mandatory=False)
    482 
    483 def options(opt):
    484 	"""
    485 	Adds the ``--gsettingsschemadir`` command-line option
    486 	"""
    487 	gr = opt.add_option_group('Installation directories')
    488 	gr.add_option('--gsettingsschemadir', help='GSettings schema location [DATADIR/glib-2.0/schemas]', default='', dest='GSETTINGSSCHEMADIR')
    489