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
27 from .utils import get_libtool_command
29 # bugzilla.gnome.org/558436
30 # Compile a binary program which is then linked to a library
31 # we want to introspect, in order to call its get_type functions.
33 _PROGRAM_TEMPLATE = """/* This file is generated, do not edit */
35 #include <girepository.h>
38 static GOptionEntry entries[] =
44 main(int argc, char **argv)
46 GOptionContext *context;
49 if (!g_thread_supported ()) g_thread_init (NULL);
54 context = g_option_context_new ("");
55 g_option_context_add_main_entries (context, entries, "girepository-1.0");
56 g_option_context_add_group (context, g_irepository_get_option_group ());
57 if (!g_option_context_parse (context, &argc, &argv, &error))
59 g_printerr ("introspect failed (%%d,%%d): %%s\\n",
60 error->domain, error->code,
69 class CompilerError(Exception):
73 class LinkerError(Exception):
77 class DumpCompiler(object):
79 def __init__(self, options, get_type_functions):
80 self._options = options
81 self._get_type_functions = get_type_functions
82 # We have to use the current directory to work around Unix
83 # sysadmins who mount /tmp noexec
84 self._tmpdir = tempfile.mkdtemp('', 'tmp-introspect', dir=os.getcwd())
86 self._compiler_cmd = os.environ.get('CC', 'gcc')
87 self._linker_cmd = os.environ.get('CC', self._compiler_cmd)
88 self._pkgconfig_cmd = os.environ.get('PKG_CONFIG', 'pkg-config')
90 self._uninst_srcdir = os.environ.get(
91 'UNINSTALLED_INTROSPECTION_SRCDIR')
92 self._packages = ['gio-2.0 gthread-2.0']
93 if not self._uninst_srcdir:
94 self._packages.append('gobject-introspection-1.0')
100 tpl_args['init_sections'] = "\n".join(self._options.init_sections)
102 c_path = self._generate_tempfile('.c')
103 f = open(c_path, 'w')
104 f.write(_PROGRAM_TEMPLATE % tpl_args)
106 # We need to reference our get_type functions to make sure they are
107 # pulled in at the linking stage if the library is a static library
108 # rather than a shared library.
109 if len(self._get_type_functions) > 0:
110 for func in self._get_type_functions:
111 f.write("extern GType " + func + "(void);\n")
112 f.write("GType (*GI_GET_TYPE_FUNCS_[])(void) = {\n")
114 for func in self._get_type_functions:
123 o_path = self._generate_tempfile('.o')
124 bin_path = self._generate_tempfile()
127 self._compile(o_path, c_path)
128 except CompilerError, e:
129 raise SystemExit('ERROR: ' + str(e))
132 self._link(bin_path, o_path)
133 except LinkerError, e:
134 raise SystemExit('ERROR: ' + str(e))
136 return IntrospectionBinary([bin_path], self._tmpdir)
140 def _generate_tempfile(self, suffix=''):
141 tmpl = '%s-%s%s' % (self._options.namespace_name,
142 self._options.namespace_version, suffix)
143 return os.path.join(self._tmpdir, tmpl)
145 def _run_pkgconfig(self, flag):
146 proc = subprocess.Popen(
147 [self._pkgconfig_cmd, flag] + self._packages,
148 stdout=subprocess.PIPE)
149 return proc.communicate()[0].split()
151 def _compile(self, output, *sources):
152 # Not strictly speaking correct, but easier than parsing shell
153 args = self._compiler_cmd.split()
154 # Do not add -Wall when using init code as we do not include any
155 # header of the library being introspected
156 if self._compiler_cmd == 'gcc' and not self._options.init_sections:
158 pkgconfig_flags = self._run_pkgconfig('--cflags')
159 if self._uninst_srcdir:
160 args.append('-I' + os.path.join(self._uninst_srcdir,
162 args.extend(pkgconfig_flags)
163 cflags = os.environ.get('CFLAGS')
165 for iflag in cflags.split():
167 for include in self._options.cpp_includes:
168 args.append('-I' + include)
169 args.extend(['-c', '-o', output])
170 for source in sources:
171 if not os.path.exists(source):
173 "Could not find c source file: %s" % (source, ))
174 args.extend(list(sources))
175 subprocess.check_call(args)
177 def _link(self, output, *sources):
179 libtool = get_libtool_command(self._options)
182 args.append('--mode=link')
183 args.append('--tag=CC')
184 args.append('--silent')
186 args.extend([self._linker_cmd, '-o', output])
188 cflags = os.environ.get('CFLAGS')
190 for iflag in cflags.split():
193 # Make sure to list the library to be introspected first since it's
194 # likely to be uninstalled yet and we want the uninstalled RPATHs have
195 # priority (or we might run with installed library that is older)
197 # Search the current directory first
200 uninst_builddir = os.environ.get('UNINSTALLED_INTROSPECTION_BUILDDIR')
201 # hack for building GIRepository.gir, skip -lgirepository-1.0 since
202 # libgirepository-1.0.la is not in current directory and we refer to it
203 # explicitly below anyway
204 for library in self._options.libraries:
205 if (uninst_builddir and
206 self._options.libraries[0] == 'girepository-1.0'):
208 if library.endswith(".la"): # explicitly specified libtool library
211 args.append('-l' + library)
213 # hack for building gobject-introspection itself
215 path = os.path.join(uninst_builddir, 'girepository',
216 'libgirepository-1.0.la')
219 args.extend(self._run_pkgconfig('--libs'))
220 for source in sources:
221 if not os.path.exists(source):
223 "Could not find object file: %s" % (source, ))
224 args.extend(list(sources))
226 subprocess.check_call(args)
229 def compile_introspection_binary(options, get_type_functions):
230 dc = DumpCompiler(options, get_type_functions)