|
1 #!perl |
|
2 # Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 # All rights reserved. |
|
4 # This component and the accompanying materials are made available |
|
5 # under the terms of the License "Eclipse Public License v1.0" |
|
6 # which accompanies this distribution, and is available |
|
7 # at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 # |
|
9 # Initial Contributors: |
|
10 # Nokia Corporation - initial contribution. |
|
11 # |
|
12 # Contributors: |
|
13 # |
|
14 # Description: |
|
15 # |
|
16 # |
|
17 |
|
18 require 5.006_001; |
|
19 use strict; |
|
20 use FindBin; |
|
21 use Pod::Usage; |
|
22 use lib "$FindBin::Bin"; |
|
23 use Getopt::Long; |
|
24 use CheckBc; |
|
25 |
|
26 $|++; |
|
27 |
|
28 # |
|
29 # Main. |
|
30 # |
|
31 |
|
32 ProcessCommandLine(); |
|
33 |
|
34 |
|
35 # |
|
36 # Subs. |
|
37 # |
|
38 |
|
39 sub ProcessCommandLine { |
|
40 Getopt::Long::Configure ("bundling"); |
|
41 my $help; |
|
42 my $verbose; |
|
43 my @additionalHeaders; |
|
44 my @additionalIncludePaths; |
|
45 my @ignoreClasses; |
|
46 my $ignoreR3Unused = 0; |
|
47 my $whichChecks = { noClassSize => 0, noDef => 0, noVtable => 0 }; |
|
48 GetOptions('h' => \$help, 'v+' => \$verbose, 'c' => \$whichChecks->{noClassSize}, 'd' => \$whichChecks->{noDef}, 't' => \$whichChecks->{noVtable}, 'header=s' => \@additionalHeaders, 'include=s' => \@additionalIncludePaths, 'ignore=s' => \@ignoreClasses, 'ignoreR3UNUSED+' => \$ignoreR3Unused); |
|
49 |
|
50 if ($help) { |
|
51 Usage($verbose); |
|
52 } |
|
53 |
|
54 my $allNo = 1; |
|
55 foreach my $thisCheck (keys %{$whichChecks}) { |
|
56 unless ($whichChecks->{$thisCheck}) { |
|
57 $allNo = 0; |
|
58 last; |
|
59 } |
|
60 } |
|
61 if ($allNo) { |
|
62 print "\nError: Specified options have disabled all the checks\n\n"; |
|
63 Usage(); |
|
64 } |
|
65 |
|
66 if (scalar(@ARGV) == 1) { |
|
67 my $descriptionFile = shift @ARGV; |
|
68 HandleDescriptionFile($descriptionFile, $ignoreR3Unused, $whichChecks, $verbose); |
|
69 } |
|
70 elsif (scalar(@ARGV) == 2) { |
|
71 my $bldInfDir1 = shift @ARGV; |
|
72 my $bldInfDir2 = shift @ARGV; |
|
73 HandleBldInfPair($bldInfDir1, $bldInfDir2, \@additionalHeaders, \@additionalIncludePaths, \@ignoreClasses, $ignoreR3Unused, $whichChecks, $verbose); |
|
74 } |
|
75 else { |
|
76 print "Error: Invalid arguments\n"; |
|
77 Usage(); |
|
78 } |
|
79 } |
|
80 |
|
81 sub Usage { |
|
82 my $verbose = shift; |
|
83 if ($verbose) { |
|
84 system("perldoc $0"); |
|
85 } |
|
86 else { |
|
87 pod2usage(-verbose => 1); |
|
88 } |
|
89 die ("\n"); |
|
90 } |
|
91 |
|
92 sub HandleBldInfPair { |
|
93 my $bldInfDir1 = shift; |
|
94 my $bldInfDir2 = shift; |
|
95 my $additionalHeaders = shift; |
|
96 my $additionalIncludePaths = shift; |
|
97 my $ignoreClasses = shift; |
|
98 my $ignoreR3Unused = shift; |
|
99 my $whichChecks = shift; |
|
100 my $verbose = shift; |
|
101 my $checkBc = CheckBc->New($bldInfDir1, $bldInfDir2, $verbose, undef, $additionalHeaders, $additionalIncludePaths, $ignoreClasses, $ignoreR3Unused); |
|
102 if (DoCheck($checkBc, $whichChecks)) { |
|
103 print "Check passed\n"; |
|
104 } |
|
105 else { |
|
106 print "Check failed\n"; |
|
107 } |
|
108 } |
|
109 |
|
110 sub HandleDescriptionFile { |
|
111 my $descriptionFile = shift; |
|
112 my $ignoreR3Unused = shift; |
|
113 my $whichChecks = shift; |
|
114 my $verbose = shift; |
|
115 open (DESC, $descriptionFile) or die "Error: Couldn't open \"$descriptionFile\": $!\n"; |
|
116 my $lineNum = 0; |
|
117 while (my $thisLine = <DESC>) { |
|
118 ++$lineNum; |
|
119 chomp $thisLine; |
|
120 $thisLine =~ s/^\s*$//; |
|
121 $thisLine =~ s/#.*//; |
|
122 next if ($thisLine eq ''); |
|
123 $thisLine =~ s/^\s+//; |
|
124 @ARGV = split (/\s+/, $thisLine); |
|
125 my @additionalHeaders; |
|
126 my @additionalIncludePaths; |
|
127 my @ignoreClasses; |
|
128 GetOptions('header=s' => \@additionalHeaders, 'include=s' => \@additionalIncludePaths, 'ignore=s' => \@ignoreClasses); |
|
129 my $component = shift @ARGV; |
|
130 my $bldInfDir1 = shift @ARGV; |
|
131 my $bldInfDir2 = shift @ARGV; |
|
132 unless ($component and $bldInfDir1 and $bldInfDir2) { |
|
133 die "Error: Invalid line in $descriptionFile($lineNum)\n"; |
|
134 } |
|
135 print "=== $component\n"; |
|
136 eval { |
|
137 my $checkBc = CheckBc->New($bldInfDir1, $bldInfDir2, $verbose, $component, \@additionalHeaders, \@additionalIncludePaths, \@ignoreClasses, $ignoreR3Unused); |
|
138 if (DoCheck($checkBc, $whichChecks)) { |
|
139 print "=== $component passed ===\n"; |
|
140 } |
|
141 else { |
|
142 print "=== $component failed ===\n"; |
|
143 } |
|
144 }; |
|
145 if ($@) { |
|
146 print $@; |
|
147 print "===\n"; |
|
148 } |
|
149 } |
|
150 close (DESC); |
|
151 } |
|
152 |
|
153 sub DoCheck { |
|
154 my $checkBc = shift; |
|
155 my $whichChecks = shift; |
|
156 my $passed = 1; |
|
157 unless ($whichChecks->{noDef}) { |
|
158 unless ($checkBc->CheckDefFiles() and $passed) { |
|
159 $passed = 0; |
|
160 } |
|
161 } |
|
162 unless ($whichChecks->{noClassSize}) { |
|
163 unless ($checkBc->CheckClassSizes() and $passed) { |
|
164 $passed = 0; |
|
165 } |
|
166 } |
|
167 unless ($whichChecks->{noVtable}) { |
|
168 unless ($checkBc->CheckVTables() and $passed) { |
|
169 $passed = 0; |
|
170 } |
|
171 } |
|
172 return $passed; |
|
173 } |
|
174 |
|
175 __END__ |
|
176 |
|
177 =head1 NAME |
|
178 |
|
179 CheckBc - Runs some simple tests to see if one component source tree is backwards compatible another. |
|
180 |
|
181 =head1 SYNOPSIS |
|
182 |
|
183 checkbc [options] (<bld_inf_dir_1> <bld_inf_dir_2>) | <description_file> |
|
184 |
|
185 Options: |
|
186 |
|
187 -h help |
|
188 -c don't check class sizes |
|
189 -d don't check def files |
|
190 -t don't check vtables |
|
191 -v verbose output (-vv very verbose) |
|
192 |
|
193 Additional options for use on a per component basis: |
|
194 |
|
195 --ignoreR3UNUSED |
|
196 --ignore <class_to_ignore> |
|
197 --header <additional_header_file> |
|
198 --include <additional_include_path> |
|
199 |
|
200 =head1 DESCRIPTION |
|
201 |
|
202 C<CheckBc> is a tool that attempts to discover if one release of a component has broken backwards compatibility with another. It is currently able to perform the following checks: |
|
203 |
|
204 =over 4 |
|
205 |
|
206 =item 1 |
|
207 |
|
208 Compares the ARM F<.def> files to ensure that only new lines have been added to the end of the file. |
|
209 |
|
210 =item 2 |
|
211 |
|
212 Compares the sizes of any classes that have an exported C++ constructor. This is done by compiling some generated C++ code that uses the C<sizeof> operator to print the relevant class sizes to C<STDOUT>. |
|
213 |
|
214 =item 3 |
|
215 |
|
216 Compares the v-table layouts of any classes that have an exported C++ constructor. This is done by compiling each source code set to ARM4 assembler listings, comparing the v-table sections. |
|
217 |
|
218 =back |
|
219 |
|
220 There are two ways of envoking C<CheckBc>: |
|
221 |
|
222 =over 4 |
|
223 |
|
224 =item 1 By specifying a pair of F<bld.inf> directories |
|
225 |
|
226 Given the location of two F<bld.inf> files (say, C<bld_inf_1> and C<bld_inf_2>), C<CheckBc> attempts to discover if the source code referred by by C<bld_inf_2> is backwards compatible with C<bld_inf_1>. |
|
227 |
|
228 =item 2 By specifying a list of F<bld.inf> directory pairs in a text file |
|
229 |
|
230 The text file must have the following line format: |
|
231 |
|
232 <component_name> <bld_inf_dir_1> <bld_inf_dir_2> [options] |
|
233 |
|
234 Any text following a 'C<#>' character will be ignored. |
|
235 |
|
236 =back |
|
237 |
|
238 Using either invokation method, the following options can be specified as many times as required: |
|
239 |
|
240 =over 4 |
|
241 |
|
242 =item * --ignoreR3UNUSED |
|
243 |
|
244 Indicates that differences between F<.def> files relating to the R3UNUSED export stub optimisation should be ignored. |
|
245 |
|
246 =item * --header <additional_header> |
|
247 |
|
248 Specifies an additional #include statement to be included in the generated C++. This option can be used to get headers that don't include all the headers they need to compile. Common headers are automatically included (e32std.h, e32def.h and e32base.h), but occasionally others are also required. |
|
249 |
|
250 =item * --include <additional_include_path> |
|
251 |
|
252 Specifies an additional path that the pre-processor should use to find header files. |
|
253 |
|
254 =item * --ignore <class_to_ignore> |
|
255 |
|
256 Specifies the name of a class that should be ignored from a class size point of view. This option can be useful if components release librarys that are intended for debugging purposes only and so are not required to maintain backwards compatibility. |
|
257 |
|
258 =back |
|
259 |
|
260 =head1 LIMITATIONS |
|
261 |
|
262 =over 4 |
|
263 |
|
264 =item 1 |
|
265 |
|
266 The component's headers must compile using Microsoft's Visual C++ compiler. |
|
267 |
|
268 =item 2 |
|
269 |
|
270 The component's exported headers must compile when they are all #include'd into a single F<.cpp> file. If this isn't the case, then the C<--header> option can be used to add additional headers. |
|
271 |
|
272 =item 3 |
|
273 |
|
274 Declarations of the component's exported C++ constructors must be found in one of the exported headers. |
|
275 |
|
276 =item 4 |
|
277 |
|
278 F<.def> file lines are expected to be identical. This can lead to checks failing falsely because, for example, the name of a function may be changed without breaking BC provided the F<.def> file is carefully edited. |
|
279 |
|
280 =item 5 |
|
281 |
|
282 The components must compile as ARM4. This is likely to mean that each set of source code needs to be accompanied with a suitable F<\epoc32> tree that allows it to be built. The simplest way to acheive this is to prepare a pair of subst'd drives. |
|
283 |
|
284 =back |
|
285 |
|
286 =head1 KNOWN BUGS |
|
287 |
|
288 F<bld.inf>, F<.mmp> and F<.def> file parsing is probably not as industrial strength as it should be. |
|
289 |
|
290 =head1 COPYRIGHT |
|
291 |
|
292 Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
293 All rights reserved. |
|
294 This component and the accompanying materials are made available |
|
295 under the terms of the License "Eclipse Public License v1.0" |
|
296 which accompanies this distribution, and is available |
|
297 at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
298 |
|
299 Initial Contributors: |
|
300 Nokia Corporation - initial contribution. |
|
301 |
|
302 Contributors: |
|
303 |
|
304 Description: |
|
305 |
|
306 |
|
307 =cut |