Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/giscanner/scannermain.py
diff options
context:
space:
mode:
Diffstat (limited to 'giscanner/scannermain.py')
-rw-r--r--giscanner/scannermain.py342
1 files changed, 342 insertions, 0 deletions
diff --git a/giscanner/scannermain.py b/giscanner/scannermain.py
new file mode 100644
index 0000000..f7ac884
--- /dev/null
+++ b/giscanner/scannermain.py
@@ -0,0 +1,342 @@
+#!/usr/bin/env python
+# -*- Mode: Python -*-
+# GObject-Introspection - a framework for introspecting GObject libraries
+# Copyright (C) 2008 Johan Dahlin
+# Copyright (C) 2009 Red Hat, Inc.
+#
+# 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
+
+from giscanner.annotationparser import AnnotationParser, InvalidAnnotationError
+from giscanner.ast import Include
+from giscanner.cachestore import CacheStore
+from giscanner.dumper import compile_introspection_binary
+from giscanner.glibtransformer import GLibTransformer, IntrospectionBinary
+from giscanner.minixpath import myxpath, xpath_assert
+from giscanner.sourcescanner import SourceScanner
+from giscanner.transformer import Transformer
+
+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("", "--add-include-path",
+ action="append", dest="include_paths", default=[],
+ help="include paths for other GIR files")
+ parser.add_option("", "--program",
+ action="store", dest="program", default=None,
+ help="program to execute")
+ parser.add_option("", "--program-arg",
+ action="append", dest="program_args", default=[],
+ help="extra arguments to program")
+ parser.add_option("", "--libtool",
+ action="store", dest="libtool_path", default=None,
+ help="full path to libtool")
+ parser.add_option("", "--no-libtool",
+ action="store_true", dest="nolibtool", default=False,
+ help="use libtool")
+ 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, also "
+ "used as --strip-prefix default"))
+ parser.add_option("", "--nsversion",
+ action="store", dest="namespace_version",
+ help="version of namespace for this unit")
+ parser.add_option("", "--strip-prefix",
+ action="store", dest="strip_prefix", default=None,
+ help="remove this prefix from objects and functions")
+ 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("", "--inject",
+ action="store_true", dest="inject",
+ help="Inject additional components into GIR XML")
+ parser.add_option("", "--xpath-assertions",
+ action="store", dest="xpath_assertions",
+ help="Use given file to create assertions on GIR content")
+ parser.add_option("", "--c-include",
+ action="append", dest="c_includes", default=[],
+ help="headers which should be included in C programs")
+
+ 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 GIRParser
+ from giscanner.girwriter import GIRWriter
+ from giscanner.girparser import C_NS
+ from xml.etree.cElementTree import parse
+
+ c_ns_key = '{%s}' % (C_NS, )
+
+ tree = parse(path)
+ root = tree.getroot()
+ for node in root.getiterator():
+ for attrib in list(node.attrib):
+ if attrib.startswith(c_ns_key):
+ del node.attrib[attrib]
+ parser = GIRParser()
+ parser.parse_tree(tree)
+
+ writer = GIRWriter(parser.get_namespace(),
+ parser.get_shared_libraries(),
+ parser.get_includes())
+ sys.stdout.write(writer.get_xml())
+ return 0
+
+def inject(path, additions, outpath):
+ from giscanner.girparser import GIRParser
+ from giscanner.girwriter import GIRWriter
+ from xml.etree.cElementTree import parse
+
+ tree = parse(path)
+ root = tree.getroot()
+ injectDoc = parse(open(additions))
+ for node in injectDoc.getroot():
+ injectPath = node.attrib['path']
+ target = myxpath(root, injectPath)
+ if not target:
+ raise ValueError("Couldn't find path %r" % (injectPath, ))
+ for child in node:
+ target.append(child)
+
+ parser = GIRParser()
+ parser.parse_tree(tree)
+ writer = GIRWriter(parser.get_namespace(),
+ parser.get_shared_libraries(),
+ parser.get_includes())
+ outf = open(outpath, 'w')
+ outf.write(writer.get_xml())
+ outf.close()
+ 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()
+ for assertion in assertions_list:
+ assertion = assertion.strip()
+ xpath_assert(root, assertion)
+ f.close()
+ return 0
+
+def process_options(output, allowed_flags):
+ for option in output.split():
+ for flag in allowed_flags:
+ if not option.startswith(flag):
+ continue
+ yield option
+ break
+
+def process_packages(parser, options, packages):
+ args = ['pkg-config', '--cflags']
+ args.extend(packages)
+ output = subprocess.Popen(args,
+ stdout=subprocess.PIPE).communicate()[0]
+ if output is None:
+ # the error output should have already appeared on our stderr,
+ # so we just exit
+ sys.exit(1)
+ # 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']
+ filtered_output = list(process_options(output, options_whitelist))
+ 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)
+
+ args = ['pkg-config', '--libs-only-L']
+ args.extend(packages)
+ output = subprocess.Popen(args,
+ stdout=subprocess.PIPE).communicate()[0]
+ if output is None:
+ sys.exit(1)
+ filtered_output = list(process_options(output, options_whitelist))
+ pkg_options, unused = parser.parse_args(filtered_output)
+ options.library_paths.extend(pkg_options.library_paths)
+
+def scanner_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.inject:
+ if len(args) != 4:
+ _error('Need three filenames; e.g. g-ir-scanner '
+ '--inject Source.gir Additions.xml SourceOut.gir')
+ return inject(*args[1:4])
+
+ 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 or options.program):
+ _error("Must specify --program or --library")
+ libraries = options.libraries
+
+ # FIXME: using LPATH is definitely not portable enough. Using Python's
+ # find_library for finding our shared libraries is not a portable enough
+ # anyway as it behaves differently depending on the OS
+ lpath = os.environ.get('LPATH')
+ library_path = ':'.join(options.library_paths)
+
+ ld_library_path = os.environ.get('LD_LIBRARY_PATH')
+ if ld_library_path:
+ library_path = ':'.join([ld_library_path, library_path])
+
+ if lpath:
+ os.environ['LPATH'] = ':'.join([lpath, library_path])
+ else:
+ os.environ['LPATH'] = library_path
+ 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, ))
+ # Make absolute, because we do comparisons inside scannerparser.c
+ # against the absolute path that cpp will give us
+ filenames.append(os.path.abspath(arg))
+
+ cachestore = CacheStore()
+ transformer = Transformer(cachestore,
+ options.namespace_name,
+ options.namespace_version)
+ if options.strip_prefix:
+ transformer.set_strip_prefix(options.strip_prefix)
+ else:
+ transformer.set_strip_prefix(options.namespace_name)
+ transformer.set_include_paths(options.include_paths)
+ shown_include_warning = False
+ for include in options.includes:
+ if os.sep in include:
+ raise ValueError("Invalid include path %r" % (include, ))
+ include_obj = Include.from_string(include)
+ transformer.register_include(include_obj)
+
+ packages = set(options.packages)
+ packages.update(transformer.get_pkgconfig_packages())
+ process_packages(parser, options, packages)
+
+ # 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(filenames)
+
+ # Transform the C symbols into AST nodes
+ transformer.set_source_ast(ss)
+
+ # Transform the C AST nodes into higher level
+ # GLib/GObject nodes
+ glibtransformer = GLibTransformer(transformer,
+ noclosure=options.noclosure)
+
+ # Do enough parsing that we have the get_type() functions to reference
+ # when creating the introspection binary
+ glibtransformer.init_parse()
+
+ if options.program:
+ args=[options.program]
+ args.extend(options.program_args)
+ binary = IntrospectionBinary(args)
+ else:
+ binary = compile_introspection_binary(options,
+ glibtransformer.get_get_type_functions())
+
+ glibtransformer.set_introspection_binary(binary)
+
+ namespace = glibtransformer.parse()
+
+ ap = AnnotationParser(namespace, ss, transformer)
+ try:
+ ap.parse()
+ except InvalidAnnotationError, e:
+ raise SystemExit("ERROR in annotation: %s" % (str(e), ))
+
+ # Write out AST
+ writer = Writer(namespace, libraries, transformer.get_includes(),
+ options.packages, options.c_includes)
+ data = writer.get_xml()
+ if options.output:
+ fd = open(options.output, "w")
+ fd.write(data)
+ else:
+ print data
+
+ return 0