summaryrefslogtreecommitdiff
path: root/giscanner/scannermain.py
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2009-03-09 15:08:50 -0400
committerColin Walters <walters@verbum.org>2009-03-16 13:29:50 -0400
commit90526643ceb248c56e40f5b6755c3cbb91c3857c (patch)
treef1fcdc171a4e9014941867316351f9629c4f37c8 /giscanner/scannermain.py
parent2bd97368f6ced0d23977ce980ac159453cc18d8c (diff)
downloadgobject-introspection-90526643ceb248c56e40f5b6755c3cbb91c3857c.tar.gz
Bug 574501 - Install giscanner Python module to private directory
We don't want to pollute the global namespace with our private libraries. Also, this sidesteps all the craziness that is happening with OS vendors changing how Python installs modules.
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 00000000..f7ac884a
--- /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