releasing/cbrtools/perl/CheckBc
changeset 607 378360dbbdba
parent 602 3145852acc89
equal deleted inserted replaced
591:22486c9c7b15 607:378360dbbdba
       
     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