rpm/{arch-symbols,mkspec}: Add support for ARM
[opensuse:kernel-source.git] / rpm / mkspec
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 use File::Copy;
7 use Getopt::Long;
8
9 my $dir = ".";
10 my $rpmrelease;
11 my $patches="";
12
13 GetOptions(
14         "patches=s" => \$patches,
15         "release=s" => \$rpmrelease
16 ) or die "Usage: $0 [--release <release>] [--patches <dir>]\n";
17
18 # flavor -> [supported archs]
19 my %flavor_archs = parse_config_conf();
20 # subset to include in kernel-syms
21 my %syms_flavor_archs = parse_config_conf("syms");
22
23 # template name -> template body
24 my %templates = read_spec_templates();
25
26 # config.sh variables
27 my %vars = parse_config_sh();
28 my ($srcversion, $variant, $vanilla_only) =
29         ($vars{'SRCVERSION'}, $vars{'VARIANT'}, $vars{'VANILLA_ONLY'});
30 $vanilla_only ||= "0";
31
32 # package name -> [summary, description]
33 my %binary_descriptions = parse_descriptions();
34
35 $patches="--patches $patches" if $patches;
36 my $patchversion = `$dir/compute-PATCHVERSION.sh $patches`;
37 chomp $patchversion;
38 my $rpmversion = $patchversion;
39 # stuff the -rcX tag into the rpm version if possible;
40 $rpmversion =~ s/\.0-rc/.rc/;
41 $rpmversion =~ s/-rc\d+//;
42 $rpmversion =~ s/-/./g;
43
44 if (defined($rpmrelease)) {
45         # convince abuild that we really want this release number
46         xopen(my $fh, '>', "$dir/get_release_number.sh");
47         print $fh "#!/bin/sh\n";
48         print $fh "echo \"$rpmrelease.0\"\n";
49         close($fh);
50         chmod(0755, "$dir/get_release_number.sh");
51 } else {
52         $rpmrelease = "0";
53 }
54 $rpmrelease =~ s/-/./g;
55
56 my $sources = join("", $templates{source} =~ /\nSource\d+:[^\n]*/mg);
57 # Find all SourceN: foo.tar.bz2 lines and generate the NoSource:
58 # lines and the %setup line
59 my @tarballs = ($sources =~ /\nSource(\d+):[^\n]*\.tar\.bz2/mg);
60 my $nosource = join("\n", map { "NoSource:       $_" } @tarballs);
61 # Source0 (the linux tarball) is unpacked manually
62 @tarballs = grep { $_ > 0 } @tarballs;
63 my $unpack_patches = join(" ", map { "-a $_" } @tarballs);
64 # List of scripts to automatically chmod +x before build
65 my $scripts = join(",", grep { is_script($_) }
66                         ($sources =~ /\nSource\d+:\s*([^\s]*)/mg));
67
68 my %macros = (
69         VARIANT => $variant,
70         VANILLA_ONLY => $vanilla_only,
71         SRCVERSION => $srcversion,
72         PATCHVERSION => $patchversion,
73         RPMVERSION => $rpmversion,
74         RELEASE => $rpmrelease,
75         SOURCES => $sources,
76         NOSOURCE => $nosource,
77         UNPACK_PATCHES => $unpack_patches,
78         SCRIPTS => $scripts,
79         YEAR => (localtime time)[5] + 1900,
80 );
81
82 # binary spec files
83 for my $flavor (sort keys(%flavor_archs)) {
84         my ($summary, $description);
85         if (!exists($binary_descriptions{"kernel-$flavor"})) {
86                 print STDERR "warning: no description for kernel-$flavor found\n";
87                 $summary = "The Linux Kernel";
88                 $description = "The Linux Kernel.";
89         } else {
90                 $summary = $binary_descriptions{"kernel-$flavor"}->[0];
91                 $description = $binary_descriptions{"kernel-$flavor"}->[1];
92         }
93
94         do_spec('binary', "kernel-$flavor.spec", %macros,
95                 FLAVOR => $flavor,
96                 SUMMARY => $summary,
97                 DESCRIPTION => $description,
98                 ARCHS => join(" ", arch2rpm(@{$flavor_archs{$flavor}})),
99                 PROVIDES_OBSOLETES => provides_obsoletes($flavor, @{$flavor_archs{$flavor}}),
100         );
101 }
102 # kernel-source.spec
103 do_spec('source', "kernel-source$variant.spec", %macros);
104
105 # kernel-docs.spec
106 do_spec('docs', "kernel-docs$variant.spec", %macros);
107
108 # kernel-syms.spec
109 {
110         my $requires = "";
111         my %all_archs;
112         for my $flavor (sort keys(%syms_flavor_archs)) {
113                 next if $flavor eq "vanilla";
114                 my @archs = arch2rpm(@{$syms_flavor_archs{$flavor}});
115                 $all_archs{$_} = 1 for @archs;
116                 $requires .= "%ifarch @archs\n";
117                 $requires .= "Requires:       kernel-$flavor-devel = \%version-\%source_rel\n";
118                 $requires .= "%endif\n";
119         }
120         chomp $requires;
121         if (keys(%all_archs)) {
122                 do_spec('syms', "kernel-syms$variant.spec", %macros,
123                         REQUIRES => $requires,
124                         ARCHS => join(" ", sort(keys(%all_archs))));
125         }
126 }
127
128 exit 0;
129
130
131
132 sub parse_config_conf {
133         my @symbols = @_;
134         my $symbols = join(' ', @symbols);
135         my %res;
136
137         for my $arch (split(/\s+/, `$dir/arch-symbols --list`)) {
138                 my @flavors = `$dir/guards $arch $symbols < $dir/config.conf`;
139                 next if @flavors == 0;
140                 chomp @flavors;
141                 @flavors = map { s/.*\///; $_ } @flavors;
142                 for my $flavor (@flavors) {
143                         $res{$flavor} ||= [];
144                         push(@{$res{$flavor}}, $arch);
145                 }
146         }
147         for my $flavor (keys(%res)) {
148                 $res{$flavor} = [sort @{$res{$flavor}}];
149         }
150         return %res;
151 }
152
153 sub read_spec_templates {
154         my %res;
155
156         for my $template (qw(binary source syms docs)) {
157                 xopen(my $fh, '<', "$dir/kernel-$template.spec.in");
158                 local $/ = undef;
159                 $res{$template} = <$fh>;
160                 close($fh);
161         }
162         return %res;
163 }
164
165 # return a hash of config.sh variables
166 sub parse_config_sh {
167         my %res;
168
169         xopen(my $fh, '<', "$dir/config.sh");
170         while (<$fh>) {
171                 chomp;
172                 if (/^\s*([A-Z_]+)=(.*)/) {
173                         $res{$1} = $2;
174                 }
175         }
176         close($fh);
177         return %res;
178 }
179
180 sub parse_descriptions {
181         my %res;
182         my $current;
183         my $blank = "";
184         # 0 - expect summary, 1 - eating blank lines, 2 - reading description
185         my $state = 0;
186
187         xopen(my $fh, '<', "$dir/package-descriptions");
188         while (<$fh>) {
189                 next if /^\s*#/;
190
191                 if (/^==+\s+([^\s]+)\s+==+\s*$/) {
192                         my $package = $1;
193                         if ($current) {
194                                 chomp $current->[1];
195                         }
196                         $current = ["", ""];
197                         $res{$package} = $current;
198                         $state = 0;
199                         next;
200                 }
201                 if (/^$/) {
202                         if ($state == 2) {
203                                 $blank .= $_;
204                         }
205                         next;
206                 }
207                 # non-blank line and not === package ===
208                 if ($state == 0) {
209                         chomp;
210                         $current->[0] = $_;
211                         $state = 1;
212                 } elsif ($state == 1) {
213                         $current->[1] = $_;
214                         $blank = "";
215                         $state = 2;
216                 } else {
217                         $current->[1] .= $blank;
218                         $blank = "";
219                         $current->[1] .= $_;
220                 }
221         }
222         if ($current) {
223                 chomp $current->[1];
224         }
225         close($fh);
226         return %res;
227 }
228
229 sub is_script {
230         my $script = shift;
231
232         return undef if $script =~ /\.(tar\.(gz|bz2)|in|conf)$/;
233         return undef if $script =~ /^README/;
234         return 1 if $script =~ /\.pl$/;
235         open(my $fh, '<', $script) or return undef;
236         sysread($fh, my $shebang, 2);
237         close($fh);
238         return 1 if $shebang eq "#!";
239         return undef;
240 }
241
242 sub arch2rpm {
243         if (wantarray) {
244                 return map { _arch2rpm($_) } @_;
245         }
246         return _arch2rpm($_[0]);
247 }
248 sub _arch2rpm {
249         my $arch = shift;
250         return "\%ix86" if $arch eq "i386";
251         return "\%arm" if $arch eq "arm";
252         return $arch;
253 }
254
255 sub provides_obsoletes {
256         my $flavor = shift;
257         my @archs = @_;
258         my $res = "";
259
260         for my $arch (@archs) {
261                 my @packs = `$dir/guards $arch $flavor <$dir/old-packages.conf`;
262                 chomp @packs;
263                 next if (!@packs);
264                 my $rpmarch = arch2rpm($arch);
265                 chomp $rpmarch;
266                 $res .= "\%ifarch $rpmarch\n";
267                 $res .= "Provides:       @packs\n";
268                 $res .= "Obsoletes:      @packs\n";
269                 $res .= "\%endif\n";
270         }
271         chomp $res;
272         return $res;
273 }
274
275 sub do_spec {
276         my $template = shift;
277         my $specfile = shift;
278         my %macros = @_;
279
280         my $text = $templates{$template};
281         for my $m (keys %macros) {
282                 $text =~ s/\@$m\@/$macros{$m}/g;
283         }
284         print "$specfile\n";
285         xopen(my $fh, '>', "$dir/$specfile");
286         print $fh $text;
287         close($fh);
288
289         return if $specfile eq "kernel-source$variant.spec";
290         my $changesfile = $specfile;
291         $changesfile =~ s/\.spec$//;
292         $changesfile .= ".changes";
293         copy("$dir/kernel-source$variant.changes", $changesfile);
294 }
295
296 sub xopen {
297         open($_[0], $_[1], $_[2]) or die "$_[2]: $!\n";
298 }
299