File indexing completed on 2024-12-15 05:11:24
0001 #!/usr/bin/perl -w 0002 # vim:sw=2:et 0003 # tries to reduce the number of includes in KDE source files 0004 # (c) 2001-2007 Dirk Mueller <mueller@kde.org> 0005 0006 use File::Basename; 0007 use Cwd; 0008 0009 # declaration of useful subroutines 0010 sub find_src_includes($); 0011 sub find_fixable_sources ($); 0012 sub find_fixable_headers($); 0013 sub find_removable_includes ($); 0014 sub warn_before_modifying ($); 0015 sub remove_include ($$$); 0016 sub replace_include ($$$); 0017 sub replace_include_type ($$); 0018 sub fix_duplicates($); 0019 sub fix_compat_includes($); 0020 sub fix_unnecessary($); 0021 sub fix_include_type($); 0022 sub copy_file($$); 0023 sub process_source_file($); 0024 sub extract_gcc_error($); 0025 0026 # some global variables 0027 $verbose = 0; # turns on debugging 0028 $modify = 0; # if 1 it should try to fix the files as well 0029 $experimental = 0; # try&error if an include is obsolete (slow!!) 0030 @explicitfiles = (); # filled in if passing files on the command line 0031 0032 # statistic variables 0033 $exp_success = 0; 0034 $exp_failure = 0; 0035 0036 while (defined ($ARGV[0])) 0037 { 0038 $_ = shift; 0039 if (/^--help$|^-h$/) { 0040 print "Usage: fixkdeincludes [--verbose | -v] [--experimental | -e ] [--modify | -m ]\n"; 0041 exit 0; 0042 } 0043 elsif (/^--verbose$|^-v$/) { 0044 $verbose = 1; # Oh is there a problem...? 0045 } 0046 elsif (/^--modify$|^-m$/) { 0047 $modify = 1; 0048 } 0049 elsif (/^--experimental$|^-e$/) { 0050 $modify = 1; 0051 $experimental = 1; 0052 } 0053 elsif (!/^-/) { 0054 push @explicitfiles, $_; 0055 } 0056 } 0057 0058 $cppExt = "(cpp|cc|cxx|C|c\\+\\+)"; 0059 $hExt = "(h|H|hh|hxx|hpp|h\\+\\+)"; 0060 0061 # list of compat headers. scroll down ... much of boring stuff here.. 0062 %compatmap = ( 0063 'qapp.h' => "qapplication.h", 0064 'qarray.h' => "qmemarray.h", 0065 'qbitarry.h' => "qbitarray.h", 0066 'qbttngrp.h' => "qbuttongroup.h", 0067 'qchkbox.h' => "qcheckbox.h", 0068 'qclipbrd.h' => "qclipboard.h", 0069 'qcollect.h' => "qptrcollection.h", 0070 'qcollection.h' => "qptrcollection.h", 0071 'qcombo.h' => "qcombobox.h", 0072 'qconnect.h' => "qconnection.h", 0073 'qdatetm.h' => "qdatetime.h", 0074 'qdrawutl.h' => "qdrawutil.h", 0075 'qdstream.h' => "qdatastream.h", 0076 'qfiledef.h' => "private/qfiledefs_p.h", 0077 'qfiledlg.h' => "qfiledialog.h", 0078 'qfileinf.h' => "qfileinfo.h", 0079 'qfontdta.h' => "qfontdata.h", 0080 'qfontinf.h' => "qfontinfo.h", 0081 'qfontmet.h' => "qfontmetrics.h", 0082 'qgrpbox.h' => "qgroupbox.h", 0083 'qintcach.h' => "qintcache.h", 0084 'qiodev.h' => "qiodevice.h", 0085 'qlcdnum.h' => "qlcdnumber.h", 0086 'qlined.h' => "qlineedit.h", 0087 'qmenudta.h' => "qmenudata.h", 0088 'qmetaobj.h' => "qmetaobject.h", 0089 'qmlined.h' => "qtmultilineedit.h", 0090 'qmsgbox.h' => "qmessagebox.h", 0091 'qmultilinedit.h' => "qmultilineedit.h", 0092 'qobjcoll.h' => "qobjectlist.h>\n\#include <qobjectdict.h", 0093 'qobjdefs.h' => "qobjectdefs.h", 0094 'qpaintd.h' => "qpaintdevice.h", 0095 'qpaintdc.h' => "qpaintdevicedefs.h", 0096 'qpdevmet.h' => "qpaintdevicemetrics.h", 0097 'qpmcache.h' => "qpixmapcache.h", 0098 'qpntarry.h' => "qpointarray.h", 0099 'qpopmenu.h' => "qpopupmenu.h", 0100 'qprndlg.h' => "qprintdialog.h", 0101 'qprogbar.h' => "qprogressbar.h", 0102 'qprogdlg.h' => "qprogressdialog.h", 0103 'qpsprn.h' => "private/qpsprinter_p.h", 0104 'qpushbt.h' => "qpushbutton.h", 0105 'qqueue.h' => "qptrqueue.h", 0106 'qradiobt.h' => "qradiobutton.h", 0107 'qrangect.h' => "qrangecontrol.h", 0108 'qscrbar.h' => "qscrollbar.h", 0109 'qsocknot.h' => "qsocketnotifier.h", 0110 'qstack.h' => "qptrstack.h", 0111 'qtabdlg.h' => "qtabdialog.h", 0112 'qtstream.h' => "qtextstream.h", 0113 'qwidcoll.h' => "qwidgetlist.h>\n\#include <qwidgetintdict.h", 0114 'qwindefs.h' => "qwindowdefs.h", 0115 0116 # and now the KDE specific compat includes 0117 'kapp.h' => "kapplication.h", 0118 'kstddirs.h' => "kstandarddirs.h", 0119 'kuniqueapp.h' => "kuniqueapplication.h", 0120 'ktmainwindow.h'=> "kmainwindow.h", 0121 'kcolorbtn.h' => "kcolorbutton.h", 0122 'kcolordlg.h' => "kcolordialog.h", 0123 'kxmlgui.h' => "kxmlguifactory.h", 0124 'kdebugclasses.h' => "kdebug.h", 0125 0126 # Qt5/KF5 list 0127 'QtTest/QtTest' => "QtTest/QTest", # oops, don't include the full module, which includes all of QtCore 0128 ); 0129 0130 0131 # now it starts to get interesting again 0132 0133 # Look for source files in the given directory ($dir, first parameter) 0134 sub find_fixable_sources ($) 0135 { 0136 # for now I grep the directory (requires srcdir==builddir) 0137 # ideally it should read the CMakeLists.txt to find out the sources actually used 0138 0139 my ( $dir ) = @_; 0140 0141 opendir (DIR, "$dir") || die "Couldn't read '$dir'\n"; 0142 my @sources = grep { /^.*\.$cppExt$/o } readdir(DIR); 0143 closedir(DIR); 0144 0145 push @sources, "CMakeLists.txt" if ( -f "CMakeLists.txt" ); 0146 0147 print "found sources: [ " . join(' ', @sources) . " ] in $dir\n" if ($verbose); 0148 0149 # prefix them with $dir 0150 my @retsources = (); 0151 foreach $source(@sources) { 0152 # skip platform-specific sources. We assume unix, so we skip win and mac 0153 next if ($source =~ /_mac.cpp/ || $source =~ /_win.cpp/); 0154 push @retsources, "$dir/$source"; 0155 } 0156 0157 return @retsources; 0158 } 0159 0160 # Look for header files in the given directory ($dir, first parameter) 0161 sub find_fixable_headers ($) 0162 { 0163 # for now I grep the directory (requires srcdir==builddir) 0164 # actually it should read the Makefile and 0165 # find the _HEADERS tags that are put there by 0166 0167 my ( $dir ) = @_; 0168 0169 opendir (DIR, "$dir") || die "Couldn't read '$dir'\n"; 0170 my @headers = grep { /^.*\.$hExt$/o } readdir(DIR); 0171 closedir(DIR); 0172 0173 print "found headers: [ " . join(' ', @headers) . " ] in $dir\n" if ($verbose); 0174 0175 # prefix them with $dir 0176 my @retheaders = (); 0177 foreach $source(@headers) { 0178 push @retheaders, "$dir/$source"; 0179 } 0180 0181 return @retheaders; 0182 } 0183 0184 sub find_removable_includes ($) 0185 { 0186 my $srcfile = shift @_; 0187 open(SRC, "< $srcfile") || die "find_removable_includes: couldn't open '$srcfile'\n"; 0188 0189 my @includes = (); 0190 0191 # we skip all includes that are somehow ifdefed 0192 0193 my $cpplevel = 0; 0194 $cpplevel = -1 if ($srcfile=~m/^.*\.$hExt$/); # plan for header-protection #ifndef/#define/#endif 0195 while (<SRC>) { 0196 # support for removing libs from CMakeLists.txt 0197 if ($srcfile =~ /CMakeLists.txt/ && !/add_library/) { 0198 while (s/(KF5::\w+)//) { 0199 push @includes, $1; 0200 } 0201 next; 0202 } 0203 if ($_ =~ m/^\#if/) { 0204 $cpplevel = $cpplevel + 1; 0205 next; 0206 } 0207 if ($_ =~ m/^\#endif/) { 0208 $cpplevel = $cpplevel - 1; 0209 next; 0210 } 0211 if ($cpplevel == 0 && $_ =~ m/^\#include\s*[\"<](.*)[\">]\S*/) { 0212 # We only look for foo.h and q* and k* 0213 #if ($cpplevel == 0 && (($_ =~ m/^\#include\s*\"(\S+\.h)\"\S*/) || ($_ =~ m/^\#include\s*\<([qk]\S+)\>\S*/))) { 0214 push @includes, $1; 0215 next; 0216 } 0217 } 0218 close SRC; 0219 0220 print "No fixable includes found in $srcfile\n" if ($verbose and not @includes); 0221 print "found includes: [ " . join(' ', @includes) . " ]\n" if ($verbose and @includes); 0222 0223 return @includes; 0224 } 0225 0226 sub find_installed_headers($) 0227 { 0228 my $sdir = shift @_; 0229 my @includes = (); 0230 0231 open(I, "<$sdir/CMakeLists.txt") || die "couldn't open $sdir/CMakeLists.txt $!"; 0232 0233 my $data = join('', <I>); 0234 $data =~ s/\s*\n/ /g; 0235 0236 # now search for not installed headers 0237 while($data =~ /install\s*\(\s*FILES\s*([^()]*)\)/ig) { 0238 my $list = $1; 0239 foreach my $i (split (' ', $list)) { 0240 next if ($i !~ m/\.h$/); 0241 push @includes, $i; 0242 } 0243 } 0244 close(I); 0245 return @includes; 0246 } 0247 0248 # first parameter: srcfile 0249 # second parameter: include to remove 0250 # third parameter is the duplicate level: this include is removed $level times 0251 sub remove_include ($$$) 0252 { 0253 my $srcfile = shift @_; 0254 my $include = quotemeta(shift @_); 0255 my $level = shift @_; 0256 0257 die "$srcfile is not read/writeable!\n" if( ! -r $srcfile || ! -w $srcfile); 0258 open(I, "< $srcfile") or die "remove_include: couldn't open '$srcfile'\n"; 0259 my @contents = <I>; 0260 close(I); 0261 0262 # ok, CPU time doesn't count so we do it the lazy way 0263 # we should remove the last occurence of the include in the 0264 # file because in case it is a duplicate removing the first 0265 # one could make a difference. 0266 my @revcontents = reverse @contents; 0267 @contents = (); 0268 0269 # we skip all includes that are somehow ifdefed 0270 # note the logic is reversed because it operates 0271 # on reversed lines :) 0272 my $cpplevel = 0; 0273 $cpplevel = -1 if ($srcfile=~m/^.*\.$hExt$/); # plan for header-protection #ifndef/#define/#endif 0274 foreach $line (@revcontents) { 0275 if ($line =~ m/^\#if/) { 0276 $cpplevel = $cpplevel - 1; 0277 push @contents, $line; 0278 next; 0279 } 0280 0281 if ($line =~ m/^\#endif/) { 0282 $cpplevel = $cpplevel + 1; 0283 push @contents, $line; 0284 next; 0285 } 0286 0287 if ($srcfile =~ /CMakeLists.txt/ && $line !~ /add_library/) { 0288 # Remove library, keep the rest of the line 0289 $line =~ s/ $include//; 0290 } elsif ($level && $cpplevel == 0 && 0291 (($line =~ m/^\#include\s*\"$include\"\S*/) || ($line =~ m/^\#include\s*\<$include\>\S*/))) { 0292 $level = $level - 1; 0293 # skipping the line.. 0294 next; 0295 } 0296 0297 push @contents, $line; 0298 } 0299 0300 # now we have the fixed contents in @contents, although in wrong order 0301 open(O, "> $srcfile") || die "remove_include: couldn't open '$srcfile' for writing\n"; 0302 print O reverse @contents; 0303 close (O); 0304 } 0305 0306 # first parameter: srcfile 0307 # second parameter: include to replace 0308 # third parameter the include file to replace it with 0309 sub replace_include ($$$) 0310 { 0311 my $srcfile = shift @_; 0312 my $include = quotemeta(shift @_); 0313 my $destinclude = shift @_; 0314 0315 die "$srcfile is not read/writeable!\n" if( ! -r $srcfile || ! -w $srcfile); 0316 open(I, "< $srcfile") or die "replace_include: couldn't open '$srcfile'\n"; 0317 my @contents = <I>; 0318 close(I); 0319 0320 # ok, CPU time doesn't count so we do it the lazy way 0321 my @revcontents = reverse @contents; 0322 @contents = (); 0323 0324 # we skip all includes that are somehow ifdefed 0325 # note the logic is reversed because it operates 0326 # on reversed lines :) 0327 my $cpplevel = 0; 0328 $cpplevel = -1 if ($srcfile=~m/^.*\.$hExt$/); # plan for header-protection #ifndef/#define/#endif 0329 foreach $line (@revcontents) { 0330 if ($line =~ m/^\#if/) { 0331 $cpplevel = $cpplevel - 1; 0332 push @contents, $line; 0333 next; 0334 } 0335 0336 if ($line =~ m/^\#endif/) { 0337 $cpplevel = $cpplevel + 1; 0338 push @contents, $line; 0339 next; 0340 } 0341 0342 if ($cpplevel == 0 && 0343 (($line =~ m/^\#include\s*\"$include\"\S*/) || ($line =~ m/^\#include\s*\<$include\>\S*/))) 0344 { 0345 print "HAH! found $include to replace in $srcfile!\n" if($verbose); 0346 $line =~ s/(\#include\s*[\"<])$include([\">]\S*)/$1$destinclude$2/; 0347 } 0348 0349 push @contents, $line; 0350 } 0351 0352 # now we have the fixed contents in @contents 0353 open(O, "> $srcfile") || die "replace_include: couldn't open '$srcfile' for writing\n"; 0354 print O reverse @contents; 0355 close (O); 0356 } 0357 0358 # fixes #include <foo.h> -> #include "foo.h" 0359 sub replace_include_type ($$) 0360 { 0361 my ($srcfile, $include) = @_; 0362 0363 die "$srcfile is not read/writeable!\n" if( ! -r $srcfile || ! -w $srcfile); 0364 open(I, "< $srcfile") or die "replace_include: couldn't open '$srcfile'\n"; 0365 my @contents = <I>; 0366 close(I); 0367 0368 grep(s/^(\#include)\s*<$include>(.*)$/$1 \"$include\"$2/, @contents); 0369 0370 # now we have the fixed contents in @contents 0371 open(O, "> $srcfile") || die "replace_include: couldn't open '$srcfile' for writing\n"; 0372 print O @contents; 0373 close (O); 0374 } 0375 0376 sub fix_duplicates($) 0377 { 0378 my $srcfile = shift @_; 0379 0380 return if ($srcfile =~ /CMakeLists.txt/); 0381 0382 my @includes = &find_removable_includes($srcfile); 0383 0384 my %inclMap = (); 0385 0386 # initialize 0387 foreach $include (@includes) { 0388 $inclMap{$include} = 0; 0389 } 0390 0391 # count number of occurences 0392 foreach $include (@includes) { 0393 $inclMap{$include} = $inclMap{$include} + 1; 0394 } 0395 0396 # check for duplicates 0397 foreach $include (keys %inclMap) { 0398 next if $inclMap{$include} <= 1; 0399 0400 print "$srcfile: duplicate level ". $inclMap{$include} .": ". $include ."\n"; 0401 0402 &remove_include($srcfile, $include, $inclMap{$include} - 1) if($modify); 0403 } 0404 } 0405 0406 sub extract_gcc_error($) 0407 { 0408 my $out = shift; 0409 0410 # print "out: $out\n"; 0411 0412 while ($out =~ m/^(.*?):([0-9]+):(.*)$/mg) # filename:lineno:message 0413 { 0414 my $field1 = $1 || ""; 0415 my $field2 = $2 || ""; 0416 my $field3 = $3 || ""; 0417 0418 # print "f1: $field1, f2: $field2, f3: $field3\n"; 0419 0420 next if ($field3 =~ m/\s+warning:.*/); 0421 next if ($field3 =~ m/^\s*$/); 0422 return basename($field1); 0423 } 0424 return "BUG!"; 0425 } 0426 0427 sub fix_compat_includes($) 0428 { 0429 my $srcfile = shift @_; 0430 0431 my @includes = &find_removable_includes($srcfile); 0432 0433 my %inclMap = (); 0434 0435 # initialize 0436 foreach $include (@includes) { 0437 $inclMap{$include} = 0; 0438 } 0439 0440 # count number of occurences 0441 foreach $include (@includes) { 0442 $inclMap{$include} = $inclMap{$include} + 1; 0443 } 0444 0445 # check for compat headers 0446 foreach $include (keys %inclMap) { 0447 if( defined $compatmap{$include}) { 0448 print "$srcfile: compat header: $include, to be replaced by ". $compatmap{$include} ."\n"; 0449 &replace_include($srcfile, $include, $compatmap{$include}) if($modify); 0450 } 0451 } 0452 } 0453 0454 sub fix_include_type($) 0455 { 0456 my $srcfile = shift @_; 0457 my $srcdir = dirname($srcfile); 0458 0459 open(I, "<$srcfile") || die "couldn't open $srcfile in _fix_include_type"; 0460 my @bracketincs = grep s/^\s*\#include\s*<([^>]+)>\s*$/$1/, <I>; 0461 close(I); 0462 0463 foreach my $include (@bracketincs) { 0464 next if (!(-r "$srcdir/$include")); 0465 next if (grep (/^$include$/, @instheaders)); 0466 next if ($include eq "config.h"); # oh don't get me started on that 0467 0468 print "$srcfile: #include <$include> should use #include \"...\"\n"; 0469 &replace_include_type($srcfile, $include) if($modify); 0470 } 0471 } 0472 0473 # copies a file from src to dest, overwrites destination if exists 0474 sub copy_file($$) 0475 { 0476 my $src = shift(@_); 0477 my $dst = shift(@_); 0478 0479 open(I, "< $src") or die "copy_file: can't open $src for input\n"; 0480 my @fcontents = <I>; 0481 close(I); 0482 open(O, "> $dst") or die "copy_file: can't open $dst for output\n"; 0483 print O @fcontents; 0484 close(O); 0485 } 0486 0487 # interrupt handler for fix_unnecessary 0488 sub sighandler_fix_unnecessary() 0489 { 0490 my($sig) = @_; 0491 print "Caught a SIG$sig--shutting down after restoring $srcfile\n"; 0492 chdir($srcdir); 0493 unlink $srcfile || warn "couldn't unlink $srcfile"; 0494 rename $localbackup, $srcfile || warn "couldn't rename $localbackup to $srcfile"; 0495 system("touch $srcfile") if ($srcfile =~ /CMakeLists.txt/); 0496 exit(1); 0497 } 0498 0499 sub fix_unnecessary($) 0500 { 0501 local $srcfile = shift @_; 0502 local $srcdir = dirname($srcfile); 0503 0504 # find canonical path for srcdir 0505 my $origdir = cwd; 0506 chdir($srcdir); 0507 $srcdir = cwd; 0508 print "srcdir=$srcdir\n" if($verbose); 0509 0510 my $builddir = $srcdir; 0511 my $makecmd = "make"; 0512 if (defined $ENV{"OBJ_REPLACEMENT"}) 0513 { 0514 # we have to use sed here, because perl can't do s#a#b# 0515 $builddir = `echo $srcdir | sed -e "\$OBJ_REPLACEMENT"`; 0516 chomp $builddir; 0517 $makecmd = "makeobj"; 0518 } 0519 print "builddir=$builddir\n" if($verbose); 0520 0521 my $tot = $exp_success + $exp_failure; 0522 print "=============== $srcfile (successes: $exp_success; total: $tot)\n"; 0523 0524 $srcfile = basename($srcfile); 0525 0526 # first figure out some details 0527 my @includes = &find_removable_includes($srcfile); 0528 0529 my $blanksrc = $srcfile; 0530 $blanksrc =~ s/(.*)\.[^\.]+/$1/; 0531 0532 print "Checking for initial compilation: "; 0533 chdir($builddir); 0534 my $objextension = "BUG"; 0535 my $lastcommand = ""; 0536 if($srcfile =~ /\.$hExt$/o || $srcfile =~ /CMakeLists.txt/) { 0537 $lastcommand = "$makecmd all"; 0538 $output = `$lastcommand 2>&1`; 0539 $objextension = "all" if ( 0 == ($? >> 8)); 0540 } 0541 else { 0542 unlink "$blanksrc.o"; 0543 $lastcommand = "$makecmd $blanksrc.o"; 0544 $output = `$lastcommand 2>&1`; 0545 $objextension = ".o" if ( 0 == ($? >> 8)); 0546 } 0547 if($objextension eq "BUG") { 0548 warn "can't figure out right compile command for $srcfile :-(\n" . 0549 "??? unused, or didn't compile in the first place?\n" . 0550 "Tried: $lastcommand, and got:\n" . 0551 "$output"; 0552 chdir($origdir); 0553 warn "Aborting!\n"; 0554 exit 1; 0555 } 0556 0557 print "worked with $objextension\n"; 0558 0559 my $initialwarnings = grep(/warning:/, $output); 0560 print "got warnings: $initialwarnings\n" if ($verbose); 0561 0562 # now try to drop some includes 0563 foreach $include (@includes) { 0564 # kdatastream is special because 0565 # it will break the application if removed even 0566 # if it continues to compile 0567 next if( $include eq "kdatastream.h"); 0568 # I also like to have kdebug.h still in 0569 # so that it's easy to add kDebug calls 0570 next if( $include eq "kdebug.h"); 0571 # avoid this one as it might cause 0572 # certain code parts to be disabled from compilation 0573 next if( $include eq "qmodules.h"); 0574 # don't remove this one either. causes conditional 0575 # code to be compiled incorrectly 0576 next if( $include eq "kdeversion.h"); 0577 # don't remove the config.h include 0578 # conditional code may depend on this file 0579 next if( $include eq "config.h"); 0580 # check if it is its own header file 0581 my $blankhdr = $include; 0582 $blankhdr =~ s/(.*)\.[^\.]+/$1/; 0583 next if ($blankhdr eq $blanksrc); 0584 0585 chdir($srcdir); 0586 0587 local $localbackup = $srcfile . "#fixkdeincludes"; 0588 0589 # preserve timestamp if possible for CVS 0590 unlink $localbackup; 0591 rename $srcfile, $localbackup; 0592 copy_file($localbackup, $srcfile); 0593 0594 # revert to backup in case of interrupt (Ctrl+C) 0595 $SIG{'INT'} = \&sighandler_fix_unnecessary; 0596 0597 # check if it still compiles 0598 if($verbose) { 0599 chdir($builddir); 0600 # testing headers? need to compile everything 0601 if($objextension eq "all") { 0602 # wait a second for makefile timestamp comparisons 0603 sleep 1; 0604 `$makecmd all 2>&1`; 0605 } 0606 else { 0607 unlink "$blanksrc$objextension"; 0608 `$makecmd $blanksrc$objextension 2>&1`; 0609 } 0610 die "unexpected error $output\nexitcode=" . ($? >> 8) if($? >> 8); 0611 chdir($srcdir); 0612 } 0613 0614 # duplicates have to be nuked here , so it will be dropped maximum once 0615 print "trying without $include: "; 0616 &remove_include($srcfile, $include, 1); 0617 0618 chdir($builddir); 0619 0620 # try if it compiles 0621 if($objextension eq "all") { 0622 sleep 1; 0623 $output=`$makecmd $objextension 2>&1`; 0624 } 0625 else { 0626 unlink "$builddir/$blanksrc$objextension"; 0627 $output=`$makecmd $blanksrc$objextension 2>&1`; 0628 } 0629 my $retcode = ($? >> 8); 0630 #print "retcode=$retcode\n$output" if ($verbose); 0631 0632 my $warnings = grep(/warning:/, $output); 0633 print "got warnings: $warnings\n" if ($verbose); 0634 0635 chdir($srcdir); 0636 if($retcode == 0 and $warnings == $initialwarnings) { 0637 # wow, it worked, lets continue! 0638 print "SUCCESS!\n"; 0639 $SIG{'INT'} = 'DEFAULT'; 0640 unlink $localbackup; 0641 $exp_success = $exp_success + 1; 0642 } 0643 else { 0644 # is this a fixable error? 0645 if($objextension eq "all" and 0646 &extract_gcc_error($output) ne $srcfile) { 0647 print "failed (error in " . &extract_gcc_error($output) . ")\n"; 0648 # FIXME: implement fixup of the compilation error 0649 # so that we can be much more agressive in removing 0650 # unneeded includes from headers 0651 } 0652 else 0653 { 0654 # better luck next time 0655 if ($retcode == 0 and $warnings != $initialwarnings) { 0656 print "FAILED, introduces " . ($warnings - $initialwarnings) . " new warnings\n"; 0657 } else { 0658 print "FATALLY failed\n"; 0659 } 0660 } 0661 unlink $srcfile; 0662 rename $localbackup, $srcfile; 0663 system("touch $srcfile") if ($srcfile =~ /CMakeLists.txt/); 0664 $SIG{'INT'} = 'DEFAULT'; 0665 0666 $exp_failure = $exp_failure + 1; 0667 } 0668 } 0669 0670 print "\n"; 0671 0672 chdir($origdir); 0673 } 0674 0675 sub process_source_file($) 0676 { 0677 local $file = shift @_; 0678 my $pure = basename($file); 0679 print "Checking: $file\n" if($verbose); 0680 #&fix_include_type($file); 0681 &fix_compat_includes($file); 0682 &fix_duplicates($file); 0683 &fix_unnecessary($file) if ($experimental && !grep (/^$pure$/, @instheaders)); 0684 print "\n" if ($verbose); 0685 } 0686 0687 sub check_for_cmake_srcdir($) 0688 { 0689 my $dir = shift; 0690 0691 return 0 if !( -r "$dir/CMakeLists.txt"); 0692 return 1 if !( -r "$dir/CMakeFiles"); 0693 0694 # ok, now it is either srcdir with srcdir==builddir, or it is builddir, 0695 # which we don't want. 0696 0697 open(I, "<$dir/Makefile") || die "couldn't read $dir/Makefile"; 0698 while(<I>) { 0699 if(/^srcdir\s*=\s*(\S+)/) { 0700 close(I); 0701 0702 if($1 ne ".") { 0703 print "Skipping build dir: $dir\n" if($verbose); 0704 return 0; 0705 } 0706 return 1; 0707 } 0708 } 0709 0710 close(I); 0711 # ok, this makefile isn't generated by cmake, we don't want that 0712 return 0; 0713 } 0714 0715 sub init_compat_includelist() 0716 { 0717 # We identify identical headers by their md5sum 0718 open(L, "md5sum /usr/include/Qt{3Support,Core,DBus,Gui,Network," . 0719 "OpenGL,Script,Sql,Svg,Test,Xml}/* | sort |") || return; 0720 0721 my $oldsum = "<invalid>"; 0722 my $oldname; 0723 0724 while(<L>) { 0725 m/^(\S+)\s+(\S+)/; 0726 0727 my ($sum, $fname) = ($1, $2); 0728 0729 $fname = $1 if ($fname =~ /\/(Qt.*)/); # remove /usr/include/, keep only QtFoo/Bar 0730 0731 if ($oldsum eq $sum) { 0732 $compatmap{$fname} = $oldname; 0733 if ($fname =~ /\/(.*)/) { 0734 $compatmap{$1} = $oldname; 0735 } 0736 next; 0737 } 0738 0739 $oldname = $fname; 0740 $oldsum = $sum; 0741 } 0742 close(L); 0743 } 0744 0745 ############################################################################# 0746 # here is the main logic 0747 # 0748 0749 &init_compat_includelist(); 0750 0751 # warn about modified files - TODO port to git diff --quiet, but the exit code seems broken 0752 #if($modify) { 0753 #`cvscheck | grep '^[MmC]'`; 0754 #print "WARNING: you have pending local changes. You might commit them by accident!\n\n" if($? >> 8 == 0); 0755 #} 0756 0757 if($experimental) { 0758 print "WARNING: The experimental mode is indeed experimental.\n"; 0759 print "It tries to reduce includes by testing if it would compile\n"; 0760 print "without a particular include. It might introduce subtle bugs\n"; 0761 print "or break compilation for make check or make final.\n\n"; 0762 print "This operation mode is known to be unsafe. You've been warned.\n"; 0763 } 0764 0765 # process files from the command line, if any 0766 if ( $#explicitfiles >= 0 ) { 0767 foreach $file( @explicitfiles ) { 0768 &process_source_file( $file ); 0769 } 0770 exit 0; 0771 } 0772 0773 # first generate a list of subdirectories 0774 @dirlist = (); 0775 push @dirlist, "." if (&check_for_cmake_srcdir(".")); 0776 die "current directory isn't srcdir!" if (!scalar @dirlist); 0777 foreach $dir ( @dirlist ) { 0778 opendir (DIR, "$dir") || warn "Couldn't read '$dir'"; 0779 my $subdir = ""; 0780 while( $subdir = readdir(DIR)) { 0781 next if ($subdir =~ /^\./); 0782 next if !( -d "$dir/$subdir"); 0783 next if (! &check_for_cmake_srcdir("$dir/$subdir")); 0784 0785 push @dirlist, "$dir/$subdir"; 0786 } 0787 closedir(DIR); 0788 } 0789 0790 # now iterate over all subdirs 0791 foreach $dir(@dirlist) { 0792 0793 # check if this directory wants not to be fixed 0794 if(open(M, "$dir/CMakeLists.txt")) { 0795 my @mcontents = grep /(\-UQT_NO_COMPAT|\-UKDE_NO_COMPAT)/, <M>; 0796 close(M); 0797 if ( @mcontents ) { 0798 print "Skipping directory: $dir\n"; 0799 next; 0800 } 0801 } 0802 0803 @headers = &find_fixable_headers($dir); 0804 @instheaders = &find_installed_headers($dir); 0805 foreach $file(@headers) { 0806 &process_source_file($file); 0807 } 0808 @sources = &find_fixable_sources($dir); 0809 foreach $file(@sources) { 0810 &process_source_file($file); 0811 } 0812 }