source: pkg/raul/main/gobject-introspection/trunk/debian/dh_girepository @ 7351

Revision 7351, 10.9 KB checked in by alanbach-guest, 3 years ago (diff)
  • Sync'd with Debian 0.10.2-1
Line 
1#! /usr/bin/perl -w
2
3=head1 NAME
4
5dh_girepository - compute dependencies for GObject introspection packages
6
7=cut
8
9use strict;
10use File::Find;
11use Debian::Debhelper::Dh_Lib;
12
13=head1 SYNOPSIS
14
15B<dh_girepository> [I<debhelper options>] [-lI<directory>] [-pI<directory>] [-XI<item>] [I<private [...]>]
16
17=head1 DESCRIPTION
18
19dh_girepository is a debhelper program to compute dependencies for packages
20shipping GObject introspection data.
21
22The dependencies are generated in the ${gir:Depends} substitution variable.
23
24=head1 OPTIONS
25
26=over 4
27
28=item B<-l>I<directory>
29
30Specify a directory (or a colon-separated list of directories) where to look
31for the .gir XML files that were used to generate the .typelib files that
32are scanned. This option is only necessary if those files are not shipped in
33another, architecture-dependent package.
34
35=item B<-p>I<directory>
36
37Specify a directory (or a colon-separated list of directories) where to look
38for the dependencies. This is useful when a dependency ships the .typelib
39in a private directory.
40
41=item B<-X>I<item>
42
43Exclude files that contain I<item> anywhere in their filename from being
44analyzed.
45
46=item I<private [...]>
47List of directories where to look for typelibs and the corresponding .gir
48files. Useful when the package installs its typelibs in a private
49directory, such as /usr/lib/<package>. Library dependencies are also looked
50there, in case your typelib depends on a library that you ship on a private
51directory.
52
53=back
54
55=head1 CONFORMS TO
56
57GObject introspection mini policy as of 2010-12-07.
58
59=cut
60
61# Initialisation code
62init(options => {
63    "l=s", => \$dh{L_PARAMS},
64    "p=s", => \$dh{P_PARAMS},
65});
66my @paths_first = ();
67my @privdirs = ();
68if ($dh{L_PARAMS}) {
69    push @paths_first, split /:/, $dh{L_PARAMS};
70}
71if ($dh{P_PARAMS}) {
72    push @privdirs, split /:/, $dh{P_PARAMS};
73}
74isnative($dh{MAINPACKAGE}); # Necessary to have $dh{VERSION}
75my $bin_version = $dh{VERSION};
76my @archpackages = getpackages("arch");
77
78my $typelib_path = "/usr/lib/girepository-1.0";
79my @typelibdirs = (@ARGV, $typelib_path);
80my $gir_path = "/usr/share/gir-1.0";
81my @girdirs = (@ARGV, $gir_path);
82my $arch_triplet = `dpkg-architecture -qDEB_BUILD_GNU_TYPE`;
83chomp $arch_triplet;
84my @privlibdirs = (@ARGV);
85my @libdirs = ("/lib/$arch_triplet", "/lib", "/usr/lib/$arch_triplet", "/usr/lib", @privlibdirs);
86my $format;
87
88# Get Build-Depends in an array
89my @bdeps;
90my $cur = 0;
91open (my $control, "<", "debian/control") or error ("Cannot open debian/control");
92while (<$control>) {
93    chomp;
94    s/\s+$//;
95    if ($cur) {
96        if (/^\s+(.*)$/) {
97            push @bdeps, split ",",$1;
98            if ($1 !~ /,$/) {
99                $cur = 0;
100            }
101        } else {
102            $cur = 0;
103        }
104    }
105    if (/^Build-Depends:\s*(.*)$/) {
106        push @bdeps, split ",",$1;
107        if ($1 =~ /,$/) {
108            $cur = 1;
109        } else {
110            $cur = 0;
111        }
112    }
113}
114close $control;
115
116
117# We can’t parse .typelib files, so we need the corresponding .gir
118# somewhere in the same source package (or with -l).
119
120sub find_gir {
121    my $req = shift;
122    $req =~ s/\.typelib$//;
123    my $f;
124    foreach my $path (@paths_first) {
125        $f = "$path/$req.gir";
126        if (-f $f) {
127            verbose_print ("Found $req.gir in $path");
128            return $f;
129        }
130    }
131    foreach my $otherpkg (@archpackages) {
132        foreach my $girdir (@girdirs) {
133            $f = tmpdir($otherpkg)."$girdir/$req.gir";
134            if (-f $f) {
135                verbose_print ("Found $req.gir in $otherpkg package");
136                return $f;
137            }
138        }
139    }
140    error("Could not find gir file for $req.typelib");
141}
142
143
144# Function used for dependencies on other .typelib files
145
146sub require_typelib {
147    my $req = shift;
148    my $package = shift;
149    my $fullpath = "$typelib_path/$req";
150
151    verbose_print ("Dependency: $req");
152    foreach my $girdir (@girdirs) {
153        if (-f tmpdir($package)."$girdir/$req") {
154            verbose_print("  found in the same package");
155            return;
156        }
157    }
158    foreach my $otherpkg (@archpackages) {
159        if (-f tmpdir($otherpkg)."$fullpath") {
160            verbose_print ("  found in $otherpkg");
161            error("Dependency on $otherpkg with a different format than $format") unless $otherpkg =~ /^gir$format/;
162            addsubstvar ($package, "gir:Depends", $otherpkg, "= $bin_version");
163            return;
164        }
165    }
166    foreach my $privpath (@privdirs) {
167        if (-f "$privpath/$req") {
168            verbose_print ("  found in $privpath");
169            $fullpath = "$privpath/$req";
170            last;
171        }
172    }
173    error("Could not find $req dependency") unless -f "$fullpath";
174    my @output = (split ':', `dpkg -S $fullpath 2>/dev/null`);
175    error("$fullpath does not belong to any package") unless @output;
176    my $deppkg = $output[0];
177    error("Dependency on $deppkg with a different format than $format") unless $deppkg =~ /^gir$format/;
178    # Look for version information in build-dependencies
179    my $found = 0;
180    foreach my $bdep (@bdeps) {
181        if ($bdep =~ /^\s*([a-z0-9\._\-\+]+)\s*\((.*)\)/) {
182            if ($1 eq $deppkg) {
183                addsubstvar ($package, "gir:Depends", $1, $2);
184                $found = 1;
185            }
186        }
187    }
188    if (! $found) {
189        addsubstvar ($package, "gir:Depends", $deppkg);
190    }
191}
192
193
194sub find_library_in_package {
195    my $req = shift;
196    my $package = shift;
197    my $tmp = "";
198    if ($package) {
199        $tmp = tmpdir ($package);
200    }
201    my @loclibdirs = grep -d, map "$tmp$_", @libdirs;
202    foreach my $libdir (@loclibdirs) {
203        if (-f "$libdir/$req" or -l "$libdir/$req") {
204            return "$libdir/$req";
205        }
206    }
207}
208
209sub find_library {
210    my $req = shift;
211    my $package = shift;
212
213    my $file = find_library_in_package ($req, $package);
214    if ($file) {
215        verbose_print ("    found in the same package");
216    } else {
217        foreach my $otherpkg (@archpackages) {
218            $file = find_library_in_package ($req, $otherpkg);
219            if ($file) {
220                verbose_print ("    found in $otherpkg");
221                last;
222            }
223        }
224    }
225    if (!$file) {
226        $file = find_library_in_package ($req);
227        if ($file) {
228            verbose_print ("    found on filesystem");
229        } else {
230            error ("Could not find library $req");
231        }
232    }
233
234    if (-l $file and not -f $file) {
235        # We have a symbolic link that points to another package
236        verbose_print ("    ... it's a symlink ...");
237        return find_library (readlink ($file), $package);
238    }
239    return $file;
240}
241
242foreach my $package (@{$dh{DOPACKAGES}}) {
243    my $tmp = tmpdir($package);
244    my $ext = pkgext($package);
245    my @bin_files = ();
246    my @c_files = ();
247    my @typelib_deps = ();
248    foreach my $dir (@typelibdirs) {
249        my $typelibdir = "$tmp$dir";
250        next unless -d $typelibdir;
251        opendir(DIRHANDLE, $typelibdir);
252        while (my $typelib = readdir(DIRHANDLE)) {
253            next unless $typelib =~ /\.typelib$/;
254            next if excludefile ($typelib);
255            my $girfile = find_gir ($typelib);
256            error("Unable to open $girfile") unless open (my $f, "<", $girfile);
257            verbose_print ("$girfile...");
258            my @libraries = ();
259            my @symbols = ();
260            my $infunction = 0;
261            while (<$f>) {
262                # "Parse" the XML file
263                chomp;
264                if (/<repository.+version="(.*?)"/) {
265                    # gir format version
266                    $format="$1";
267                } elsif (/<include\s+name="(.*?)"\s+version="(.*?)"\/>/) {
268                    # Dependency on another typelib file
269                    my $deptypelib="$1-$2.typelib";
270                    verbose_print ("  Dependency: $deptypelib");
271                    if (! grep { $_ eq $deptypelib } @typelib_deps) {
272                        push @typelib_deps, $deptypelib;
273                    }
274                } elsif (/shared-library="(.*?)"/) {
275                    # Dependency on a shared library
276                    foreach my $shlibname (split ",", $1) {
277                        if ($shlibname !~ /\.so/) {
278                            $shlibname = "lib$shlibname.so"
279                        }
280                        verbose_print ("  Library: $shlibname");
281                        push @libraries, find_library ($shlibname, $package);
282                    }
283                } elsif (/<(method|constructor|function)\s.*c:identifier="(.*?)"/) {
284                    push @symbols, $2;
285                } elsif (/<(method|constructor|function)/) {
286                    $infunction = 1;
287                } elsif ($infunction and /c:identifier="(.*?)"/) {
288                    push @symbols, $1;
289                }
290                if (/>$/) {
291                    $infunction = 0;
292                }
293            }
294            close $f;
295            error("Unable to determine gir format") unless $format;
296            error("Package name $package doesn't match gir format $format")
297                unless $package =~ /^gir$format/
298                or not $typelibdir =~ /usr\/lib\/girepository/;
299            verbose_print(sprintf("  %d symbols found", $#symbols+1));
300            if (@libraries or @symbols) {
301                my $c_file = "$typelibdir/$typelib.c";
302                my $bin_file = "$typelibdir/$typelib.so";
303                verbose_print ("  writing $c_file");
304                if (!$dh{NO_ACT}){
305                    error("Unable to open $girfile") unless open (F, ">", $c_file);
306                    print F "void gir_dummy_function () {\n";
307                    foreach my $symbol (@symbols) {
308                        print F "$symbol ();\n";
309                    }
310                    print F "}";
311                    close F;
312                }
313                push @c_files, $c_file;
314
315                # Build a dummy binary using all referenced symbols and libraries
316                # We use -shared so that gcc doesn’t try to resolve references
317                verbose_print ("  building $bin_file");
318                doit (("gcc", "-shared", "-fPIC", "-o", $bin_file, $c_file, @libraries));
319                push @bin_files, $bin_file;
320            }
321        }
322    }
323    if (@bin_files) {
324        # dpkg-shlibdeps expects this directory to exist
325        if (! -d "$tmp/DEBIAN") {
326            doit("install","-o",0,"-g",0,"-d","$tmp/DEBIAN");
327        }
328
329        # Let dpkg-shlibdeps generate the corresponding dependencies
330        # It must run first since otherwise it overwrites the variable
331        complex_doit ("LD_LIBRARY_PATH=" . join (':', @privlibdirs) . " dpkg-shlibdeps -pgir -Tdebian/${ext}substvars -xlibc6 -xlibc0 @bin_files");
332    }
333    doit (("rm", "-f", @c_files, @bin_files));
334
335    # Generate dependencies on other .typelib files
336    foreach my $dep (@typelib_deps) {
337        require_typelib ($dep, $package);
338    }
339}
340
341=head1 SEE ALSO
342
343L<debhelper(7)>
344
345This program is a part of gobject-introspection but is made to work with
346debhelper.
347
348=head1 AUTHOR
349
350Josselin Mouette <joss@debian.org>
351
352=cut
Note: See TracBrowser for help on using the repository browser.