2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008 Colin Walters
4 # Copyright (C) 2008 Johan Dahlin
6 # This library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2 of the License, or (at your option) any later version.
11 # This library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this library; if not, write to the
18 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 # Boston, MA 02111-1307, USA.
26 from .glibtransformer import IntrospectionBinary
28 # bugzilla.gnome.org/558436
29 # Compile a binary program which is then linked to a library
30 # we want to introspect, in order to call its get_type functions.
32 _PROGRAM_TEMPLATE = '''/* This file is generated, do not edit */
34 #include <girepository.h>
37 static GOptionEntry entries[] =
43 main(int argc, char **argv)
45 GOptionContext *context;
51 context = g_option_context_new ("");
52 g_option_context_add_main_entries (context, entries, "girepository-1.0");
53 g_option_context_add_group (context, g_irepository_get_option_group ());
54 if (!g_option_context_parse (context, &argc, &argv, &error))
56 g_printerr ("introspect failed (%d,%d): %s\\n",
57 error->domain, error->code,
66 class CompilerError(Exception):
70 class LinkerError(Exception):
74 class DumpCompiler(object):
76 def __init__(self, options):
77 self._options = options
78 self._tmpdir = tempfile.mkdtemp('', 'tmp-introspect')
80 self._compiler_cmd = os.environ.get('CC', 'gcc')
81 self._linker_cmd = os.environ.get('LD', self._compiler_cmd)
82 self._pkgconfig_cmd = os.environ.get('PKG_CONFIG', 'pkg-config')
84 self._uninst_srcdir = os.environ.get(
85 'UNINSTALLED_INTROSPECTION_SRCDIR')
86 self._packages = ['gio-2.0 gthread-2.0']
87 if not self._uninst_srcdir:
88 self._packages.append('gobject-introspection-1.0')
93 c_path = self._generate_tempfile('.c')
95 f.write(_PROGRAM_TEMPLATE)
98 o_path = self._generate_tempfile('.o')
99 bin_path = self._generate_tempfile()
102 self._compile(o_path, c_path)
103 except CompilerError, e:
104 raise SystemExit('ERROR: ' + str(e))
107 self._link(bin_path, o_path)
108 except LinkerError, e:
109 raise SystemExit('ERROR: ' + str(e))
113 return IntrospectionBinary([bin_path], self._tmpdir)
117 def _generate_tempfile(self, suffix=''):
118 tmpl = '%s-%s%s' % (self._options.namespace_name,
119 self._options.namespace_version, suffix)
120 return os.path.join(self._tmpdir, tmpl)
122 def _run_pkgconfig(self, flag):
123 proc = subprocess.Popen(
124 [self._pkgconfig_cmd, flag] + self._packages,
125 stdout=subprocess.PIPE)
126 return proc.communicate()[0].split()
128 def _use_libtool_infection(self):
129 libtool_infection = not self._options.nolibtool
130 if not libtool_infection:
133 if self._options.libtool_path:
134 # Automake by default sets:
135 # LIBTOOL = $(SHELL) $(top_builddir)/libtool
136 # To be strictly correct we would have to parse shell. For now
138 return self._options.libtool_path.split()
141 subprocess.check_call(['libtool', '--version'])
142 except subprocess.CalledProcessError, e:
143 # If libtool's not installed, assume we don't need it
148 def _compile(self, output, *sources):
149 args = [self._compiler_cmd]
150 if self._compiler_cmd == 'gcc':
152 pkgconfig_flags = self._run_pkgconfig('--cflags')
153 if self._uninst_srcdir:
154 args.append('-I' + os.path.join(self._uninst_srcdir,
156 args.extend(pkgconfig_flags)
157 for include in self._options.cpp_includes:
158 args.append('-I' + include)
159 args.extend(['-c', '-o', output])
160 for source in sources:
161 if not os.path.exists(source):
163 "Could not find c source file: %s" % (source, ))
164 args.extend(list(sources))
165 subprocess.check_call(args)
167 def _link(self, output, *sources):
169 libtool = self._use_libtool_infection()
172 args.append('--mode=link')
173 args.append('--tag=CC')
175 args.extend([self._linker_cmd, '-o', output])
177 # Make sure to list the library to be introspected first since it's
178 # likely to be uninstalled yet and we want the uninstalled RPATHs have
179 # priority (or we might run with installed library that is older)
181 # Search the current directory first
184 uninst_builddir = os.environ.get('UNINSTALLED_INTROSPECTION_BUILDDIR')
185 # hack for building GIRepository.gir, skip -lgirepository-1.0 since
186 # libgirepository-1.0.la is not in current directory and we refer to it
187 # explicitly below anyway
188 if (not uninst_builddir or
189 self._options.libraries[0] != 'girepository-1.0'):
190 # We only use the first library; assume others are "custom"
191 # libraries like from gir-repository. Right now those don't define
192 # new GTypes, so we don't need to introspect them.
193 args.append('-l' + self._options.libraries[0])
195 # hack for building gobject-introspection itself
197 path = os.path.join(uninst_builddir, 'girepository',
198 'libgirepository-1.0.la')
201 args.extend(self._run_pkgconfig('--libs'))
202 for source in sources:
203 if not os.path.exists(source):
205 "Could not find object file: %s" % (source, ))
206 args.extend(list(sources))
208 subprocess.check_call(args)
211 def compile_introspection_binary(options):
212 dc = DumpCompiler(options)