#!/usr/bin/env python # -*- Mode: Python -*- # GObject-Introspection - a framework for introspecting GObject libraries # Copyright (C) 2008 Johan Dahlin # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # import subprocess import optparse import os import sys # This only works on unix systems currentdir = os.path.dirname(os.path.abspath(sys.argv[0])) basedir = os.path.abspath(os.path.join(currentdir, '..')) if (os.path.exists(os.path.join(basedir, '.svn')) or os.path.exists(os.path.join(basedir, '.git'))): path = basedir else: path = os.path.join(basedir, 'lib', 'python%d.%d' % sys.version_info[:2], 'site-packages') sys.path.insert(0, path) from giscanner.glibtransformer import GLibTransformer from giscanner.sourcescanner import SourceScanner from giscanner.transformer import Transformer from giscanner.minixpath import xpath_assert def _get_option_parser(): parser = optparse.OptionParser('%prog [options] sources') parser.add_option("", "--format", action="store", dest="format", default="gir", help="format to use, one of gidl, gir") parser.add_option("-i", "--include", action="append", dest="includes", default=[], help="include types for other gidls") parser.add_option("-l", "--library", action="append", dest="libraries", default=[], help="libraries of this unit") parser.add_option("-L", "--library-path", action="append", dest="library_paths", default=[], help="directories to search for libraries") parser.add_option("-n", "--namespace", action="store", dest="namespace_name", help="name of namespace for this unit") parser.add_option("", "--strip-prefix", action="store", dest="strip_prefix", default="", help="prefix to strip from functions, like g_") parser.add_option("-o", "--output", action="store", dest="output", help="output to writeout, defaults to stdout") parser.add_option("", "--pkg", action="append", dest="packages", default=[], help="pkg-config packages to get cflags from") parser.add_option("-v", "--verbose", action="store_true", dest="verbose", help="be verbose") parser.add_option("", "--noclosure", action="store_true", dest="noclosure", help="do not delete unknown types") parser.add_option("", "--typelib-xml", action="store_true", dest="typelib_xml", help="Just convert GIR to typelib XML") parser.add_option("", "--xpath-assertions", action="store", dest="xpath_assertions", help="Use given file to create assertions on GIR content") group = optparse.OptionGroup(parser, "Preprocessor options") group.add_option("-I", help="Pre-processor include file", action="append", dest="cpp_includes", default=[]) group.add_option("-D", help="Pre-processor define", action="append", dest="cpp_defines", default=[]) group.add_option("-U", help="Pre-processor undefine", action="append", dest="cpp_undefines", default=[]) group.add_option("-p", dest="", help="Ignored") parser.add_option_group(group) return parser def _error(msg): raise SystemExit('ERROR: %s' % (msg, )) def typelib_xml_strip(path): from giscanner.girparser import C_NS c_ns_key = '{%s}' % (C_NS, ) from xml.etree.cElementTree import parse doc = parse(open(path)) for node in doc.getiterator(): for attrib in list(node.attrib): if attrib.startswith(c_ns_key): del node.attrib[attrib] doc.write(sys.stdout) return 0 def validate(assertions, path): from xml.etree.cElementTree import parse doc = parse(open(path)) root = doc.getroot() f = open(assertions) assertions_list = f.readlines() print "=== CHECKING %s (%d assertions) ===" % (assertions, len(assertions_list)) for assertion in assertions_list: assertion = assertion.strip() xpath_assert(root, assertion) f.close() print "=== PASSED %s ===" % (assertions, ) return 0 def main(args): parser = _get_option_parser() (options, args) = parser.parse_args(args) if len(args) <= 1: _error('Need at least one filename') if options.typelib_xml: return typelib_xml_strip(args[1]) if options.xpath_assertions: return validate(options.xpath_assertions, args[1]) if not options.namespace_name: _error('Namespace name missing') if options.format == 'gir': from giscanner.girwriter import GIRWriter as Writer else: _error("Unknown format: %s" % (options.format, )) if not options.libraries: _error("Must specify --library for primary library") primary_library = options.libraries[0] for package in options.packages: output = subprocess.Popen(['pkg-config', '--cflags', package], stdout=subprocess.PIPE).communicate()[0] # Some pkg-config files on Windows have options we don't understand, # so we explicitly filter to only the ones we need. options_whitelist = ['-I', '-D', '-U', '-l', '-L'] def filter_option(opt): for optstart in options_whitelist: if opt.startswith(optstart): return True return False output = output.split() filtered_output = filter(filter_option, output) pkg_options, unused = parser.parse_args(filtered_output) options.cpp_includes.extend(pkg_options.cpp_includes) options.cpp_defines.extend(pkg_options.cpp_defines) options.cpp_undefines.extend(pkg_options.cpp_undefines) output = subprocess.Popen(['pkg-config', '--libs-only-L', package], stdout=subprocess.PIPE).communicate()[0] output = output.split() filtered_output = filter(filter_option, output) pkg_options, unused = parser.parse_args(filtered_output) options.library_paths.extend(pkg_options.library_paths) filenames = [] for arg in args: if (arg.endswith('.c') or arg.endswith('.h')): if not os.path.exists(arg): _error('%s: no such a file or directory' % (arg, )) filenames.append(arg) # Run the preprocessor, tokenize and construct simple # objects representing the raw C symbols ss = SourceScanner() ss.set_cpp_options(options.cpp_includes, options.cpp_defines, options.cpp_undefines) ss.parse_files(filenames) ss.parse_macros() # Transform the C symbols into AST nodes transformer = Transformer(ss, options.namespace_name) transformer.set_strip_prefix(options.strip_prefix) for include in options.includes: transformer.register_include(include) # Transform the C AST nodes into higher level # GLib/GObject nodes glibtransformer = GLibTransformer(transformer, noclosure=options.noclosure) if options.libraries: for library in options.libraries: glibtransformer.add_library(library) namespace = glibtransformer.parse() # Write out AST writer = Writer(namespace, primary_library, transformer.get_includes()) data = writer.get_xml() if options.output: fd = open(options.output, "w") fd.write(data) else: print data return 0 sys.exit(main(sys.argv))