drm-scripts-gentree.pl revision 1.1 1 1.1 mrg #!/usr/bin/perl
2 1.1 mrg #
3 1.1 mrg # Original version were part of Gerd Knorr's v4l scripts.
4 1.1 mrg #
5 1.1 mrg # Several improvements by (c) 2005-2007 Mauro Carvalho Chehab
6 1.1 mrg #
7 1.1 mrg # Largely re-written (C) 2007 Trent Piepho <xyzzy (at] speakeasy.org>
8 1.1 mrg # Stolen for DRM usage by airlied
9 1.1 mrg #
10 1.1 mrg # Theory of Operation
11 1.1 mrg #
12 1.1 mrg # This acts as a sort of mini version of cpp, which will process
13 1.1 mrg # #if/#elif/#ifdef/etc directives to strip out code used to support
14 1.1 mrg # multiple kernel versions or otherwise not wanted to be sent upstream to
15 1.1 mrg # git.
16 1.1 mrg #
17 1.1 mrg # Conditional compilation directives fall into two catagories,
18 1.1 mrg # "processed" and "other". The "other" directives are ignored and simply
19 1.1 mrg # output as they come in without changes (see 'keep' exception). The
20 1.1 mrg # "processed" variaty are evaluated and only the lines in the 'true' part
21 1.1 mrg # are kept, like cpp would do.
22 1.1 mrg #
23 1.1 mrg # If gentree knows the result of an expression, that directive will be
24 1.1 mrg # "processed", otherwise it will be an "other". gentree knows the value
25 1.1 mrg # of LINUX_VERSION_CODE, BTTV_VERSION_CODE, the KERNEL_VERSION(x,y,z)
26 1.1 mrg # macro, numeric constants like 0 and 1, and a few defines like MM_KERNEL
27 1.1 mrg # and STV0297_CS2.
28 1.1 mrg #
29 1.1 mrg # An exception is if the comment "/*KEEP*/" appears after the expression,
30 1.1 mrg # in which case that directive will be considered an "other" and not
31 1.1 mrg # processed, other than to remove the keep comment.
32 1.1 mrg #
33 1.1 mrg # Known bugs:
34 1.1 mrg # don't specify the root directory e.g. '/' or even '////'
35 1.1 mrg # directives continued with a back-slash will always be ignored
36 1.1 mrg # you can't modify a source tree in-place, i.e. source dir == dest dir
37 1.1 mrg
38 1.1 mrg use strict;
39 1.1 mrg use File::Find;
40 1.1 mrg use Fcntl ':mode';
41 1.1 mrg
42 1.1 mrg my $VERSION = shift;
43 1.1 mrg my $SRC = shift;
44 1.1 mrg my $DESTDIR = shift;
45 1.1 mrg
46 1.1 mrg if (!defined($DESTDIR)) {
47 1.1 mrg print "Usage:\ngentree.pl\t<version> <source dir> <dest dir>\n\n";
48 1.1 mrg exit;
49 1.1 mrg }
50 1.1 mrg
51 1.1 mrg my $BTTVCODE = KERNEL_VERSION(0,9,17);
52 1.1 mrg my ($LINUXCODE, $extra) = kernel_version($VERSION);
53 1.1 mrg my $DEBUG = 0;
54 1.1 mrg
55 1.1 mrg my %defs = (
56 1.1 mrg 'LINUX_VERSION_CODE' => $LINUXCODE,
57 1.1 mrg 'MM_KERNEL' => ($extra =~ /-mm/)?1:0,
58 1.1 mrg 'DRM_ODD_MM_COMPAT' => 0,
59 1.1 mrg 'I915_HAVE_FENCE' => 1,
60 1.1 mrg 'I915_HAVE_BUFFER' => 1,
61 1.1 mrg 'VIA_HAVE_DMABLIT' => 1,
62 1.1 mrg 'VIA_HAVE_CORE_MM' => 1,
63 1.1 mrg 'VIA_HAVE_FENCE' => 1,
64 1.1 mrg 'VIA_HAVE_BUFFER' => 1,
65 1.1 mrg 'SIS_HAVE_CORE_MM' => 1,
66 1.1 mrg 'DRM_FULL_MM_COMPAT' => 1,
67 1.1 mrg '__linux__' => 1,
68 1.1 mrg );
69 1.1 mrg
70 1.1 mrg #################################################################
71 1.1 mrg # helpers
72 1.1 mrg
73 1.1 mrg sub kernel_version($) {
74 1.1 mrg $_[0] =~ m/(\d+)\.(\d+)\.(\d+)(.*)/;
75 1.1 mrg return ($1*65536 + $2*256 + $3, $4);
76 1.1 mrg }
77 1.1 mrg
78 1.1 mrg # used in eval()
79 1.1 mrg sub KERNEL_VERSION($$$) { return $_[0]*65536 + $_[1]*256 + $_[2]; }
80 1.1 mrg
81 1.1 mrg sub evalexp($) {
82 1.1 mrg local $_ = shift;
83 1.1 mrg s|/\*.*?\*/||go; # delete /* */ comments
84 1.1 mrg s|//.*$||o; # delete // comments
85 1.1 mrg s/\bdefined\s*\(/(/go; # defined(foo) to (foo)
86 1.1 mrg while (/\b([_A-Za-z]\w*)\b/go) {
87 1.1 mrg if (exists $defs{$1}) {
88 1.1 mrg my $id = $1; my $pos = $-[0];
89 1.1 mrg s/$id/$defs{$id}/;
90 1.1 mrg pos = $-[0];
91 1.1 mrg } elsif ($1 ne 'KERNEL_VERSION') {
92 1.1 mrg return(undef);
93 1.1 mrg }
94 1.1 mrg }
95 1.1 mrg return(eval($_) ? 1 : 0);
96 1.1 mrg }
97 1.1 mrg
98 1.1 mrg #################################################################
99 1.1 mrg # filter out version-specific code
100 1.1 mrg
101 1.1 mrg sub filter_source ($$) {
102 1.1 mrg my ($in,$out) = @_;
103 1.1 mrg my $line;
104 1.1 mrg my $level=0;
105 1.1 mrg my %if = ();
106 1.1 mrg my %state = ();
107 1.1 mrg
108 1.1 mrg my @dbgargs = \($level, %state, %if, $line);
109 1.1 mrg sub dbgline($\@) {
110 1.1 mrg my $level = ${$_[1][0]};
111 1.1 mrg printf STDERR ("/* BP %4d $_[0] state=$_[1][1]->{$level} if=$_[1][2]->{$level} level=$level (${$_[1][3]}) */\n", $.) if $DEBUG;
112 1.1 mrg }
113 1.1 mrg
114 1.1 mrg open IN, '<', $in or die "Error opening $in: $!\n";
115 1.1 mrg open OUT, '>', $out or die "Error opening $out: $!\n";
116 1.1 mrg
117 1.1 mrg print STDERR "File: $in, for kernel $VERSION($LINUXCODE)/\n" if $DEBUG;
118 1.1 mrg
119 1.1 mrg while ($line = <IN>) {
120 1.1 mrg chomp $line;
121 1.1 mrg next if ($line =~ m/^#include \"compat.h\"/o);
122 1.1 mrg # next if ($line =~ m/[\$]Id:/);
123 1.1 mrg
124 1.1 mrg # For "#if 0 /*KEEP*/;" the ; should be dropped too
125 1.1 mrg if ($line =~ m@^\s*#\s*if(n?def)?\s.*?(\s*/\*\s*(?i)keep\s*\*/;?)@) {
126 1.1 mrg $state{$level} = "ifother";
127 1.1 mrg $if{$level} = 1;
128 1.1 mrg dbgline "#if$1 (keep)", @dbgargs;
129 1.1 mrg $line =~ s/\Q$2\E//;
130 1.1 mrg $level++;
131 1.1 mrg }
132 1.1 mrg # handle all ifdef/ifndef lines
133 1.1 mrg elsif ($line =~ /^\s*#\s*if(n?)def\s*(\w+)/o) {
134 1.1 mrg if (exists $defs{$2}) {
135 1.1 mrg $state{$level} = 'if';
136 1.1 mrg $if{$level} = ($1 eq 'n') ? !$defs{$2} : $defs{$2};
137 1.1 mrg dbgline "#if$1def $2", @dbgargs;
138 1.1 mrg $level++;
139 1.1 mrg next;
140 1.1 mrg }
141 1.1 mrg $state{$level} = "ifother";
142 1.1 mrg $if{$level} = 1;
143 1.1 mrg dbgline "#if$1def (other)", @dbgargs;
144 1.1 mrg $level++;
145 1.1 mrg }
146 1.1 mrg # handle all ifs
147 1.1 mrg elsif ($line =~ /^\s*#\s*if\s+(.*)$/o) {
148 1.1 mrg my $res = evalexp($1);
149 1.1 mrg if (defined $res) {
150 1.1 mrg $state{$level} = 'if';
151 1.1 mrg $if{$level} = $res;
152 1.1 mrg dbgline '#if '.($res?'(yes)':'(no)'), @dbgargs;
153 1.1 mrg $level++;
154 1.1 mrg next;
155 1.1 mrg } else {
156 1.1 mrg $state{$level} = 'ifother';
157 1.1 mrg $if{$level} = 1;
158 1.1 mrg dbgline '#if (other)', @dbgargs;
159 1.1 mrg $level++;
160 1.1 mrg }
161 1.1 mrg }
162 1.1 mrg # handle all elifs
163 1.1 mrg elsif ($line =~ /^\s*#\s*elif\s+(.*)$/o) {
164 1.1 mrg my $exp = $1;
165 1.1 mrg $level--;
166 1.1 mrg $level < 0 and die "more elifs than ifs";
167 1.1 mrg $state{$level} =~ /if/ or die "unmatched elif";
168 1.1 mrg
169 1.1 mrg if ($state{$level} eq 'if' && !$if{$level}) {
170 1.1 mrg my $res = evalexp($exp);
171 1.1 mrg defined $res or die 'moving from if to ifother';
172 1.1 mrg $state{$level} = 'if';
173 1.1 mrg $if{$level} = $res;
174 1.1 mrg dbgline '#elif1 '.($res?'(yes)':'(no)'), @dbgargs;
175 1.1 mrg $level++;
176 1.1 mrg next;
177 1.1 mrg } elsif ($state{$level} ne 'ifother') {
178 1.1 mrg $if{$level} = 0;
179 1.1 mrg $state{$level} = 'elif';
180 1.1 mrg dbgline '#elif0', @dbgargs;
181 1.1 mrg $level++;
182 1.1 mrg next;
183 1.1 mrg }
184 1.1 mrg $level++;
185 1.1 mrg }
186 1.1 mrg elsif ($line =~ /^\s*#\s*else/o) {
187 1.1 mrg $level--;
188 1.1 mrg $level < 0 and die "more elses than ifs";
189 1.1 mrg $state{$level} =~ /if/ or die "unmatched else";
190 1.1 mrg $if{$level} = !$if{$level} if ($state{$level} eq 'if');
191 1.1 mrg $state{$level} =~ s/^if/else/o; # if -> else, ifother -> elseother, elif -> elif
192 1.1 mrg dbgline '#else', @dbgargs;
193 1.1 mrg $level++;
194 1.1 mrg next if $state{$level-1} !~ /other$/o;
195 1.1 mrg }
196 1.1 mrg elsif ($line =~ /^\s*#\s*endif/o) {
197 1.1 mrg $level--;
198 1.1 mrg $level < 0 and die "more endifs than ifs";
199 1.1 mrg dbgline '#endif', @dbgargs;
200 1.1 mrg next if $state{$level} !~ /other$/o;
201 1.1 mrg }
202 1.1 mrg
203 1.1 mrg my $print = 1;
204 1.1 mrg for (my $i=0;$i<$level;$i++) {
205 1.1 mrg next if $state{$i} =~ /other$/o; # keep code in ifother/elseother blocks
206 1.1 mrg if (!$if{$i}) {
207 1.1 mrg $print = 0;
208 1.1 mrg dbgline 'DEL', @{[\$i, \%state, \%if, \$line]};
209 1.1 mrg last;
210 1.1 mrg }
211 1.1 mrg }
212 1.1 mrg print OUT "$line\n" if $print;
213 1.1 mrg }
214 1.1 mrg close IN;
215 1.1 mrg close OUT;
216 1.1 mrg }
217 1.1 mrg
218 1.1 mrg #################################################################
219 1.1 mrg
220 1.1 mrg sub parse_dir {
221 1.1 mrg my $file = $File::Find::name;
222 1.1 mrg
223 1.1 mrg return if ($file =~ /CVS/);
224 1.1 mrg return if ($file =~ /~$/);
225 1.1 mrg
226 1.1 mrg my $f2 = $file;
227 1.1 mrg $f2 =~ s/^\Q$SRC\E/$DESTDIR/;
228 1.1 mrg
229 1.1 mrg my $mode = (stat($file))[2];
230 1.1 mrg if ($mode & S_IFDIR) {
231 1.1 mrg print("mkdir -p '$f2'\n");
232 1.1 mrg system("mkdir -p '$f2'"); # should check for error
233 1.1 mrg return;
234 1.1 mrg }
235 1.1 mrg print "from $file to $f2\n";
236 1.1 mrg
237 1.1 mrg if ($file =~ m/.*\.[ch]$/) {
238 1.1 mrg filter_source($file, $f2);
239 1.1 mrg } else {
240 1.1 mrg system("cp $file $f2");
241 1.1 mrg }
242 1.1 mrg }
243 1.1 mrg
244 1.1 mrg
245 1.1 mrg # main
246 1.1 mrg
247 1.1 mrg printf "kernel is %s (0x%x)\n",$VERSION,$LINUXCODE;
248 1.1 mrg
249 1.1 mrg # remove any trailing slashes from dir names. don't pass in just '/'
250 1.1 mrg $SRC =~ s|/*$||; $DESTDIR =~ s|/*$||;
251 1.1 mrg
252 1.1 mrg print "finding files at $SRC\n";
253 1.1 mrg
254 1.1 mrg find({wanted => \&parse_dir, no_chdir => 1}, $SRC);
255