Implemented module-local caching of module profiles.
[profile/ivi/qtbase.git] / bin / syncqt
1 #!/usr/bin/perl -w
2 ######################################################################
3 #
4 # Synchronizes Qt header files - internal development tool.
5 #
6 # Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 # Contact: Nokia Corporation (qt-info@nokia.com)
8 #
9 ######################################################################
10
11 # use packages -------------------------------------------------------
12 use File::Basename;
13 use File::Path;
14 use Cwd;
15 use Cwd 'abs_path';
16 use Config;
17 use strict;
18
19 # set output basedir to be where ever syncqt is run from
20 our $out_basedir = getcwd();
21 $out_basedir =~ s=\\=/=g;
22 our $basedir;
23 our $quoted_basedir;
24
25
26 # try to figure out where QtBase is located
27 # normally the script location should be enough, if not fall back to
28 # QTDIR environment variable. If that doesn't work, later ask the
29 # user to use the -qtdir option explicitly.
30 my $qtbasedir = $ENV{"QTDIR"};
31 $qtbasedir = dirname(dirname($0)) if (!$qtbasedir);
32 $qtbasedir =~ s=\\=/=g if (defined $qtbasedir);
33
34 # will be defined based on the modules sync.profile
35 our (%modules, %moduleheaders, %classnames, %mastercontent, %modulepris);
36
37 # global variables (modified by options)
38 my $isunix = 0;
39 my $module = 0;
40 my $showonly = 0;
41 my $quiet = 0;
42 my $remove_stale = 1;
43 my $force_win = 0;
44 my $force_relative = 0;
45 my $check_includes = 0;
46 my $copy_headers = 0;
47 my $create_uic_class_map = 0;
48 my $create_private_headers = 1;
49 my $module_fwd = "";
50 my $cache_module_fwd = 0;
51 my $developer_build = 0;
52 my $no_module_version_header = 0;
53 my @modules_to_sync ;
54 $force_relative = 1 if ( -d "/System/Library/Frameworks" );
55
56
57 # functions ----------------------------------------------------------
58
59 ######################################################################
60 # Syntax:  showUsage()
61 # Params:  -none-
62 #
63 # Purpose: Show the usage of the script.
64 # Returns: -none-
65 ######################################################################
66 sub showUsage
67 {
68     print "$0 usage:\n";
69     print "  <module directory>    Specifies which module to sync header files for (required for shadow builds!)\n\n";
70
71     print "  -copy                 Copy headers instead of include-fwd(default: " . ($copy_headers ? "yes" : "no") . ")\n";
72     print "  -remove-stale         Removes stale headers              (default: " . ($remove_stale ? "yes" : "no") . ")\n";
73     print "  -relative             Force relative symlinks            (default: " . ($force_relative ? "yes" : "no") . ")\n";
74     print "  -windows              Force platform to Windows          (default: " . ($force_win ? "yes" : "no") . ")\n";
75     print "  -showonly             Show action but not perform        (default: " . ($showonly ? "yes" : "no") . ")\n";
76     print "  -outdir <PATH>        Specify output directory for sync  (default: $out_basedir)\n";
77     print "  -qtdir <PATH>         Set the path to QtBase             (detected: " . (defined $qtbasedir ? $qtbasedir : "-none-") . ")\n";
78     print "  -quiet                Only report problems, not activity (default: " . ($quiet ? "yes" : "no") . ")\n";
79     print "  -separate-module <NAME>:<PROFILEDIR>:<HEADERDIR>\n";
80     print "                        Create headers for <NAME> with original headers in\n";
81     print "                        <HEADERDIR> relative to <PROFILEDIR> \n";
82     print "  -private              Force copy private headers         (default: " . ($create_private_headers ? "yes" : "no") . ")\n";
83     print "  -module-fwd <PATH>    Create fwd includes for module pri files in the given\n";
84     print "                        path (default: none)\n";
85     print "  -cache-module-fwd     Create a .qmake.cache file to cache the location of the\n";
86     print "                        fwd includes\n";
87     print "  -developer-build      Point libraries and binaries to a common directory for\n";
88     print "                        easy development\n";
89     print "  -no-module-version-header\n";
90     print "                        Don't create module version header file\n";
91     print "  -help                 This help\n";
92     exit 0;
93 }
94
95 ######################################################################
96 # Syntax:  checkUnix()
97 # Params:  -none-
98 #
99 # Purpose: Check if script runs on a Unix system or not. Cygwin
100 #          systems are _not_ detected as Unix systems.
101 # Returns: 1 if a unix system, else 0.
102 ######################################################################
103 sub checkUnix {
104     my ($r) = 0;
105     if ( $force_win != 0) {
106         return 0;
107     } elsif ( -f "/bin/uname" ) {
108         $r = 1;
109         (-f "\\bin\\uname") && ($r = 0);
110     } elsif ( -f "/usr/bin/uname" ) {
111         $r = 1;
112         (-f "\\usr\\bin\\uname") && ($r = 0);
113     }
114     if($r) {
115         $_ = $Config{'osname'};
116         $r = 0 if( /(ms)|(cyg)win/i );
117     }
118     return $r;
119 }
120
121 sub checkRelative {
122     my ($dir) = @_;
123     return 0 if($dir =~ /^\//);
124     return 0 if(!checkUnix() && $dir =~ /[a-zA-Z]:[\/\\]/);
125     return 1;
126 }
127
128 ######################################################################
129 # Syntax:  shouldMasterInclude(iheader)
130 # Params:  iheader, string, filename to verify inclusion
131 #
132 # Purpose: Determines if header should be in the master include file.
133 # Returns: 0 if file contains "#pragma qt_no_master_include" or not
134 #          able to open, else 1.
135 ######################################################################
136 sub shouldMasterInclude {
137     my ($iheader) = @_;
138     return 0 if(basename($iheader) =~ /_/);
139     return 0 if(basename($iheader) =~ /qconfig/);
140     if(open(F, "<$iheader")) {
141         while(<F>) {
142             chomp;
143             return 0 if(/^\#pragma qt_no_master_include$/);
144         }
145         close(F);
146     } else {
147         return 0;
148     }
149     return 1;
150 }
151
152 ######################################################################
153 # Syntax:  classNames(iheader)
154 # Params:  iheader, string, filename to parse for classname "symlinks"
155 #
156 # Purpose: Scans through iheader to find all classnames that should be
157 #          synced into library's include structure.
158 # Returns: List of all class names in a file.
159 ######################################################################
160 sub classNames {
161     my @ret;
162     my ($iheader) = @_;
163
164     my $classname = $classnames{basename($iheader)};
165     push @ret, $classname if ($classname);
166
167     my $parsable = "";
168     if(open(F, "<$iheader")) {
169         while(<F>) {
170             my $line = $_;
171             chomp $line;
172                         chop $line if ($line =~ /\r$/);
173             if($line =~ /^\#/) {
174                 if($line =~ /\\$/) {
175                     while($line = <F>) {
176                         chomp $line;
177                         last unless($line =~ /\\$/);
178                     }
179                 }
180                 return @ret if($line =~ m/^#pragma qt_sync_stop_processing/);
181                 push(@ret, $1) if($line =~ m/^#pragma qt_class\(([^)]*)\)[\r\n]*$/);
182                 $line = 0;
183             }
184             if($line) {
185                 $line =~ s,//.*$,,; #remove c++ comments
186                 $line .= ";" if($line =~ m/^Q_[A-Z_]*\(.*\)[\r\n]*$/); #qt macro
187                 $line .= ";" if($line =~ m/^QT_(BEGIN|END)_HEADER[\r\n]*$/); #qt macro
188                 $line .= ";" if($line =~ m/^QT_(BEGIN|END)_NAMESPACE[\r\n]*$/); #qt macro
189                 $line .= ";" if($line =~ m/^QT_MODULE\(.*\)[\r\n]*$/); # QT_MODULE macro
190                 $parsable .= " " . $line;
191             }
192         }
193         close(F);
194     }
195
196     my $last_definition = 0;
197     my @namespaces;
198     for(my $i = 0; $i < length($parsable); $i++) {
199         my $definition = 0;
200         my $character = substr($parsable, $i, 1);
201         if($character eq "/" && substr($parsable, $i+1, 1) eq "*") { #I parse like this for greedy reasons
202             for($i+=2; $i < length($parsable); $i++) {
203                 my $end = substr($parsable, $i, 2);
204                 if($end eq "*/") {
205                     $last_definition = $i+2;
206                     $i++;
207                     last;
208                 }
209             }
210         } elsif($character eq "{") {
211             my $brace_depth = 1;
212             my $block_start = $i + 1;
213           BLOCK: for($i+=1; $i < length($parsable); $i++) {
214               my $ignore = substr($parsable, $i, 1);
215               if($ignore eq "{") {
216                   $brace_depth++;
217               } elsif($ignore eq "}") {
218                   $brace_depth--;
219                   unless($brace_depth) {
220                       for(my $i2 = $i+1; $i2 < length($parsable); $i2++) {
221                           my $end = substr($parsable, $i2, 1);
222                           if($end eq ";" || $end ne " ") {
223                               $definition = substr($parsable, $last_definition, $block_start - $last_definition) . "}";
224                               $i = $i2 if($end eq ";");
225                               $last_definition = $i + 1;
226                               last BLOCK;
227                           }
228                       }
229                   }
230               }
231           }
232         } elsif($character eq ";") {
233             $definition = substr($parsable, $last_definition, $i - $last_definition + 1);
234             $last_definition = $i + 1;
235         } elsif($character eq "}") {
236             # a naked } must be a namespace ending
237             # if it's not a namespace, it's eaten by the loop above
238             pop @namespaces;
239             $last_definition = $i + 1;
240         }
241
242         if (substr($parsable, $last_definition, $i - $last_definition + 1) =~ m/ namespace ([^ ]*) /
243             && substr($parsable, $i+1, 1) eq "{") {
244             push @namespaces, $1;
245
246             # Eat the opening { so that the condensing loop above doesn't see it
247             $i++;
248             $last_definition = $i + 1;
249         }
250
251         if($definition) {
252             $definition =~ s=[\n\r]==g;
253             my @symbols;
254             if($definition =~ m/^ *typedef *.*\(\*([^\)]*)\)\(.*\);$/) {
255                 push @symbols, $1;
256             } elsif($definition =~ m/^ *typedef +(.*) +([^ ]*);$/) {
257                 push @symbols, $2;
258             } elsif($definition =~ m/^ *(template *<.*> *)?(class|struct) +([^ ]* +)?([^<\s]+) ?(<[^>]*> ?)?\s*((,|:)\s*(public|protected|private) *.*)? *\{\}$/) {
259                 push @symbols, $4;
260             } elsif($definition =~ m/^ *Q_DECLARE_.*ITERATOR\((.*)\);$/) {
261                 push @symbols, "Q" . $1 . "Iterator";
262                 push @symbols, "QMutable" . $1 . "Iterator";
263             }
264
265             foreach my $symbol (@symbols) {
266                 $symbol = (join("::", @namespaces) . "::" . $symbol) if (scalar @namespaces);
267                 push @ret, $symbol
268                     if ($symbol =~ /^Q[^:]*$/           # no-namespace, starting with Q
269                         || $symbol =~ /^Phonon::/);     # or in the Phonon namespace
270             }
271         }
272     }
273     return @ret;
274 }
275
276 ######################################################################
277 # Syntax:  syncHeader(header, iheader, copy, timestamp)
278 # Params:  header, string, filename to create "symlink" for
279 #          iheader, string, destination name of symlink
280 #          copy, forces header to be a copy of iheader
281 #          timestamp, the requested modification time if copying
282 #
283 # Purpose: Syncronizes header to iheader
284 # Returns: 1 if successful, else 0.
285 ######################################################################
286 sub syncHeader {
287     my ($header, $iheader, $copy, $ts) = @_;
288     $iheader =~ s=\\=/=g;
289     $header =~ s=\\=/=g;
290     return copyFile($iheader, $header) if($copy);
291
292     unless(-e $header) {
293         my $header_dir = dirname($header);
294         mkpath $header_dir, !$quiet;
295
296         #write it
297         my $iheader_out = fixPaths($iheader, $header_dir);
298         open HEADER, ">$header" || die "Could not open $header for writing!\n";
299         print HEADER "#include \"$iheader_out\"\n";
300         close HEADER;
301         if(defined($ts)) {
302             utime(time, $ts, $header) or die "$iheader, $header";
303         }
304         return 1;
305     }
306     return 0;
307 }
308
309 ######################################################################
310 # Syntax:  fixPaths(file, dir)
311 # Params:  file, string, filepath to be made relative to dir
312 #          dir, string, dirpath for point of origin
313 #
314 # Purpose: file is made relative (if possible) of dir.
315 # Returns: String with the above applied conversion.
316 ######################################################################
317 sub fixPaths {
318     my ($file, $dir) = @_;
319     $file =~ s=\\=/=g;
320     $dir =~ s=\\=/=g;
321
322     #setup
323     my $ret = $file;
324     $ret =~ s,/cygdrive/([a-zA-Z])/,$1:/,g;
325     my $file_dir = dirname($file);
326     if($file_dir eq ".") {
327         $file_dir = getcwd();
328         $file_dir =~ s=\\=/=g;
329     }
330     $file_dir =~ s,/cygdrive/([a-zA-Z])/,$1:/,g;
331     if($dir eq ".") {
332         $dir = getcwd();
333         $dir =~ s=\\=/=g;
334     }
335     $dir =~ s,/cygdrive/([a-zA-Z])/,$1:/,g;
336     return basename($file) if($file_dir eq $dir);
337
338     #guts
339     while ($file_dir =~ s,/[^/]+/\.\./,/,) {}
340     while ($dir =~ s,/[^/]+/\.\./,/,) {}
341     my $match_dir = 0;
342     for(my $i = 1; $i < length($file_dir); $i++) {
343         my $slash = index($file_dir, "/", $i);
344         last if($slash == -1);
345         my $tmp = substr($file_dir, 0, $slash);
346         last unless($dir =~ m,^\Q$tmp\E/,);
347         $match_dir = $tmp;
348         $i = $slash;
349     }
350     if($match_dir) {
351         my $after = substr($dir, length($match_dir));
352         my $count = ($after =~ tr,/,,);
353         my $dots = "";
354         for(my $i = 0; $i < $count; $i++) {
355             $dots .= "../";
356         }
357         $ret =~ s,^\Q$match_dir\E,$dots,;
358     }
359     $ret =~ s,/+,/,g;
360     return $ret;
361 }
362
363 ######################################################################
364 # Syntax:  fileContents(filename)
365 # Params:  filename, string, filename of file to return contents
366 #
367 # Purpose: Get the contents of a file.
368 # Returns: String with contents of the file, or empty string if file
369 #          doens't exist.
370 # Warning: Dies if it does exist but script cannot get read access.
371 ######################################################################
372 sub fileContents {
373     my ($filename) = @_;
374     my $filecontents = "";
375     if (-e $filename) {
376         open(I, "< $filename") || die "Could not open $filename for reading, read block?";
377         local $/;
378         binmode I;
379         $filecontents = <I>;
380         close I;
381     }
382     return $filecontents;
383 }
384
385 ######################################################################
386 # Syntax:  fileCompare(file1, file2)
387 # Params:  file1, string, filename of first file
388 #          file2, string, filename of second file
389 #
390 # Purpose: Determines if files are equal, and which one is newer.
391 # Returns: 0 if files are equal no matter the timestamp, -1 if file1
392 #          is newer, 1 if file2 is newer.
393 ######################################################################
394 sub fileCompare {
395     my ($file1, $file2) = @_;
396     my $file1contents = fileContents($file1);
397     my $file2contents = fileContents($file2);
398     if (! -e $file1) { return 1; }
399     if (! -e $file2) { return -1; }
400     return $file1contents ne $file2contents ? (stat($file2))[9] <=> (stat($file1))[9] : 0;
401 }
402
403 ######################################################################
404 # Syntax:  copyFile(file, ifile)
405 # Params:  file, string, filename to create duplicate for
406 #          ifile, string, destination name of duplicate
407 #
408 # Purpose: Keeps files in sync so changes in the newer file will be
409 #          written to the other.
410 # Returns: 1 if files were synced, else 0.
411 # Warning: Dies if script cannot get write access.
412 ######################################################################
413 sub copyFile
414 {
415     my ($file,$ifile, $copy,$knowdiff,$filecontents,$ifilecontents) = @_;
416     # Bi-directional synchronization
417     open( I, "< " . $file ) || die "Could not open $file for reading";
418     local $/;
419     binmode I;
420     $filecontents = <I>;
421     close I;
422     if ( open(I, "< " . $ifile) ) {
423         local $/;
424         binmode I;
425         $ifilecontents = <I>;
426         close I;
427         $copy = fileCompare($file, $ifile);
428         $knowdiff = 0,
429     } else {
430         $copy = -1;
431         $knowdiff = 1;
432     }
433
434     if ( $knowdiff || ($filecontents ne $ifilecontents) ) {
435         if ( $copy > 0 ) {
436             my $file_dir = dirname($file);
437             mkpath $file_dir, !$quiet unless(-e $file_dir);
438             open(O, "> " . $file) || die "Could not open $file for writing (no write permission?)";
439             local $/;
440             binmode O;
441             print O $ifilecontents;
442             close O;
443             utime time, (stat($ifile))[9], $file;
444             return 1;
445         } elsif ( $copy < 0 ) {
446             my $ifile_dir = dirname($ifile);
447             mkpath $ifile_dir, !$quiet unless(-e $ifile_dir);
448             open(O, "> " . $ifile) || die "Could not open $ifile for writing (no write permission?)";
449             local $/;
450             binmode O;
451             print O $filecontents;
452             close O;
453             utime time, (stat($file))[9], $ifile;
454             return 1;
455         }
456     }
457     return 0;
458 }
459
460 ######################################################################
461 # Syntax:  symlinkFile(file, ifile)
462 # Params:  file, string, filename to create "symlink" for
463 #          ifile, string, destination name of symlink
464 #
465 # Purpose: File is symlinked to ifile (or copied if filesystem doesn't
466 #          support symlink).
467 # Returns: 1 on success, else 0.
468 ######################################################################
469 sub symlinkFile
470 {
471     my ($file,$ifile) = @_;
472
473     if ($isunix) {
474         print "symlink created for $file " unless $quiet;
475         if ( $force_relative && ($ifile =~ /^$quoted_basedir/)) {
476             my $t = getcwd();
477             my $c = -1;
478             my $p = "../";
479             $t =~ s-^$quoted_basedir/--;
480             $p .= "../" while( ($c = index( $t, "/", $c + 1)) != -1 );
481             $file =~ s-^$quoted_basedir/-$p-;
482             print " ($file)\n" unless $quiet;
483         }
484         print "\n" unless $quiet;
485         return symlink($file, $ifile);
486     }
487     return copyFile($file, $ifile);
488 }
489
490 ######################################################################
491 # Syntax:  findFiles(dir, match, descend)
492 # Params:  dir, string, directory to search for name
493 #          match, string, regular expression to match in dir
494 #          descend, integer, 0 = non-recursive search
495 #                            1 = recurse search into subdirectories
496 #
497 # Purpose: Finds files matching a regular expression.
498 # Returns: List of matching files.
499 #
500 # Examples:
501 #   findFiles("/usr","\.cpp$",1)  - finds .cpp files in /usr and below
502 #   findFiles("/tmp","^#",0)      - finds #* files in /tmp
503 ######################################################################
504 sub findFiles {
505     my ($dir,$match,$descend) = @_;
506     my ($file,$p,@files);
507     local(*D);
508     $dir =~ s=\\=/=g;
509     ($dir eq "") && ($dir = ".");
510     if ( opendir(D,$dir) ) {
511         if ( $dir eq "." ) {
512             $dir = "";
513         } else {
514             ($dir =~ /\/$/) || ($dir .= "/");
515         }
516         foreach $file ( sort readdir(D) ) {
517             next if ( $file  =~ /^\.\.?$/ );
518             $p = $file;
519             ($file =~ /$match/) && (push @files, $p);
520             if ( $descend && -d $p && ! -l $p ) {
521                 push @files, &findFiles($p,$match,$descend);
522             }
523         }
524         closedir(D);
525     }
526     return @files;
527 }
528
529 ######################################################################
530 # Syntax:  loadSyncProfile()
531 #
532 # Purpose: Locates the sync.profile.
533 # Returns: Hashmap of module name -> directory.
534 ######################################################################
535 sub loadSyncProfile {
536     my ($srcbase, $outbase) = @_;
537     print("srcbase = $$srcbase \n");
538     print("outbase = $$outbase \n");
539
540     my $syncprofile = "$$srcbase/sync.profile";
541     my $result;
542     unless ($result = do "$syncprofile") {
543         die "syncqt couldn't parse $syncprofile: $@" if $@;
544         die "syncqt couldn't execute $syncprofile: $!" unless defined $result;
545     }
546     return $result;
547 }
548
549 sub locateSyncProfile
550 {
551     my ($directory) = @_;
552     my $syncprofile;
553     $directory = abs_path($directory);
554     while(!defined $syncprofile) {
555         local(*D);
556         if (opendir(D, $directory)) {
557             foreach my $file (sort readdir(D)) {
558                 next if ($file =~ /^\.\.?$/);
559                 $syncprofile = "$directory/$file" if ($file =~ /^sync\.profile$/);
560                 last if (defined $syncprofile);
561             }
562             closedir(D);
563         }
564         last if (defined $syncprofile || $directory eq "/" || $directory =~ /^?:[\/\\]$/);
565         $directory = dirname($directory);
566     }
567     return $syncprofile;
568 }
569
570 # check if this is an in-source build, and if so use that as the basedir too
571 $basedir = locateSyncProfile($out_basedir);
572 if ($basedir) {
573     $basedir = dirname($basedir) ;
574     $basedir =~ s=\\=/=g;
575     $quoted_basedir = "\Q$basedir";
576 }
577
578 # --------------------------------------------------------------------
579 # "main" function
580 # --------------------------------------------------------------------
581
582 while ( @ARGV ) {
583     my $var = 0;
584     my $val = 0;
585
586     #parse
587     my $arg = shift @ARGV;
588     if ($arg eq "-h" || $arg eq "-help" || $arg eq "-?" || $arg eq "?") {
589         $var = "show_help";
590         $val = "yes";
591     } elsif($arg eq "-copy") {
592         $var = "copy";
593         $val = "yes";
594     } elsif($arg eq "-o" || $arg eq "-outdir") {
595         $var = "output";
596         $val = shift @ARGV;
597     } elsif($arg eq "-showonly" || $arg eq "-remove-stale" || $arg eq "-windows" ||
598             $arg eq "-relative" || $arg eq "-check-includes") {
599         $var = substr($arg, 1);
600         $val = "yes";
601     } elsif($arg eq "-module-fwd") {
602         $var = "module_fwd";
603         $val = shift @ARGV;
604     } elsif($arg eq "-cache-module-fwd") {
605         $var = "cache_module_fwd";
606         $val = "yes";
607     } elsif($arg eq "-developer-build") {
608         $var = "developer_build";
609         $val = "yes";
610     } elsif($arg eq "-no-module-version-header") {
611         $var = "no_module_version_header";
612         $val = "yes";
613     } elsif($arg =~ /^-no-(.*)$/) {
614         $var = $1;
615         $val = "no";
616         #these are for commandline compat
617     } elsif($arg eq "-inc") {
618         $var = "output";
619         $val = shift @ARGV;
620     } elsif($arg eq "-module") {
621         $var = "module";
622         $val = shift @ARGV;
623     } elsif($arg eq "-separate-module") {
624         $var = "separate-module";
625         $val = shift @ARGV;
626     } elsif($arg eq "-show") {
627         $var = "showonly";
628         $val = "yes";
629     } elsif($arg eq "-quiet") {
630         $var = "quiet";
631         $val = "yes";
632     } elsif($arg eq "-private") {
633         $var = "create_private_headers";
634         $val = "yes";
635     } elsif($arg eq "-qtdir") {
636         $var = "qtdir";
637         $val = shift @ARGV;
638     } elsif($arg eq "-base-dir") {
639         # skip, it's been dealt with at the top of the file
640         shift @ARGV;
641         next;
642     } elsif($arg =~/^-/) {
643         print "Unknown option: $arg\n\n" if(!$var);
644         showUsage();
645     } else {
646         $basedir = locateSyncProfile($arg);
647         die "Could not find a sync.profile for '$arg'\n" if (!$basedir);
648         $basedir = dirname($basedir);
649         $basedir =~ s=\\=/=g;
650         $quoted_basedir = "\Q$basedir";
651         $var = "ignore";
652     }
653
654     #do something
655     if(!$var || $var eq "show_help") {
656         print "Unknown option: $arg\n\n" if(!$var);
657         showUsage();
658     } elsif ($var eq "copy") {
659         if($val eq "yes") {
660             $copy_headers++;
661         } elsif($showonly) {
662             $copy_headers--;
663         }
664     } elsif ($var eq "showonly") {
665         if($val eq "yes") {
666             $showonly++;
667         } elsif($showonly) {
668             $showonly--;
669         }
670     } elsif ($var eq "quiet") {
671         if($val eq "yes") {
672             $quiet++;
673         } elsif($quiet) {
674             $quiet--;
675         }
676     } elsif ($var eq "check-includes") {
677         if($val eq "yes") {
678             $check_includes++;
679         } elsif($check_includes) {
680             $check_includes--;
681         }
682     } elsif ($var eq "remove-stale") {
683         if($val eq "yes") {
684             $remove_stale++;
685         } elsif($remove_stale) {
686             $remove_stale--;
687         }
688     } elsif ($var eq "windows") {
689         if($val eq "yes") {
690             $force_win++;
691         } elsif($force_win) {
692             $force_win--;
693         }
694     } elsif ($var eq "relative") {
695         if($val eq "yes") {
696             $force_relative++;
697         } elsif($force_relative) {
698             $force_relative--;
699         }
700     } elsif ($var eq "module") {
701         print "module :$val:\n" unless $quiet;
702         die "No such module: $val" unless(defined $modules{$val});
703         push @modules_to_sync, $val;
704     } elsif ($var eq "separate-module") {
705         my ($module, $prodir, $headerdir) = split(/:/, $val);
706         $modules{$module} = $prodir;
707         push @modules_to_sync, $module;
708         $moduleheaders{$module} = $headerdir;
709         $create_uic_class_map = 0;
710     } elsif ($var eq "qtdir") {
711         if($val) {
712             $qtbasedir = $val;
713             $qtbasedir =~ s=\\=/=g;
714         } else {
715             die "The -qtdir option requires an argument";
716         }
717     } elsif ($var eq "module_fwd") {
718         $module_fwd = $val;
719     } elsif ($var eq "cache_module_fwd") {
720         $cache_module_fwd = 1;
721     } elsif ($var eq "developer_build") {
722         $developer_build = 1;
723     } elsif ($var eq "no_module_version_header") {
724             $no_module_version_header = 1;
725     } elsif ($var eq "output") {
726         my $outdir = $val;
727         if(checkRelative($outdir)) {
728             $out_basedir = getcwd();
729             chomp $out_basedir;
730             $out_basedir .= "/" . $outdir;
731         } else {
732             $out_basedir = $outdir;
733         }
734         # \ -> /
735         $out_basedir =~ s=\\=/=g;
736     }
737 }
738
739 # if the $qtbasedir neither has 'qtbase' somewhere in its path, nor a
740 # '.qmake.cache' file in its directory, we assume it's not a valid path
741 # (remember that a yet-to-be-built qtbase doesn't have this file either,
742 # thus the 'qtbase' path check!)
743 die "Cannot automatically detect/use provided path to QtBase's build directory!\n" .
744     "QTDIR detected/provided: " . (defined $qtbasedir ? $qtbasedir : "-none-") . "\n" .
745     "Please -qtdir option to provide the correct path.\nsyncqt failed"
746         if (!$qtbasedir || !-d "$qtbasedir/mkspecs");
747
748 # if we have no $basedir we cannot be sure which sources you want, so die
749 die "Could not find any sync.profile for your module!\nPass <module directory> to syncqt to sync your header files.\nsyncqt failed" if (!$basedir);
750
751 my @ignore_headers = ();
752 my $class_lib_map_contents = "";
753 our @ignore_for_master_contents = ();
754 our @ignore_for_include_check = ();
755 our @ignore_for_qt_begin_header_check = ();
756 our @ignore_for_qt_begin_namespace_check = ();
757 our @ignore_for_qt_module_check = ();
758 my %colliding_headers = ();
759 my %inject_headers = ( "$basedir/src/corelib/global" => ( "qconfig.h" ) ); # all from build dir
760
761 # load the module's sync.profile here, before we can
762 loadSyncProfile(\$basedir, \$out_basedir);
763
764 @modules_to_sync = keys(%modules) if($#modules_to_sync == -1);
765
766 $isunix = checkUnix; #cache checkUnix
767
768 # create path
769 mkpath "$out_basedir/include", !$quiet;
770 mkpath "$out_basedir/include/Qt", !$quiet;
771
772
773 foreach my $lib (@modules_to_sync) {
774     #iteration info
775     my $dir = $modules{$lib};
776     my $module_version = "";
777     my $module_major_version = "";
778     my $module_minor_version = "";
779     my $module_patch_version = "";
780
781     if (-e "$modulepris{$lib}") {
782         my $content = fileContents($modulepris{$lib});
783         my @version_rows = grep(/QT\..*\.VERSION/, split('\n', $content));
784         if(@version_rows) {
785             # We only pick the first one, since each module need a separate .pri file
786             $module_version = $version_rows[0];
787             chomp $module_version;
788             $module_version =~ s/^\s*QT\..*\.VERSION\s*=\s*([^#]+).*$/$1/;
789             $module_version =~ s/\s+$//;
790             my @versions = split(/\./, $module_version);
791             $module_major_version = $versions[0];
792             chomp $module_major_version;
793             $module_minor_version = $versions[1];
794             chomp $module_minor_version;
795             $module_patch_version = $versions[2];
796             chomp $module_patch_version;
797         }
798     }
799     print "WARNING: Module $lib\'s pri missing QT.<module>.VERSION variable! Private headers not versioned!\n" if (!$module_version);
800
801     my $pathtoheaders = "";
802     $pathtoheaders = $moduleheaders{$lib} if ($moduleheaders{$lib});
803
804     #information used after the syncing
805     my $pri_install_classes = "";
806     my $pri_install_files = "";
807     my $pri_install_pfiles = "";
808
809     my $libcapitals = $lib;
810     $libcapitals =~ y/a-z/A-Z/;
811     my $master_contents = "#ifndef QT_".$libcapitals."_MODULE_H\n#define QT_".$libcapitals."_MODULE_H\n";
812
813     #get dependencies
814     if(-e "$dir/" . basename($dir) . ".pro") {
815         if(open(F, "<$dir/" . basename($dir) . ".pro")) {
816             while(my $line = <F>) {
817                 chomp $line;
818                 if($line =~ /^ *QT *\+?= *([^\r\n]*)/) {
819                     foreach(split(/ /, $1)) {
820                         $_ =~ s/-private$//;
821                         my $content = $mastercontent{$_};
822                         $master_contents .= $content if ($content);
823                     }
824                 }
825             }
826             close(F);
827         }
828     }
829
830     #remove the old files
831     if($remove_stale) {
832         my @subdirs = ("$out_basedir/include/$lib");
833         foreach my $subdir (@subdirs) {
834             if (opendir DIR, $subdir) {
835                 while(my $t = readdir(DIR)) {
836                     my $file = "$subdir/$t";
837                     if(-d $file) {
838                         push @subdirs, $file unless($t eq "." || $t eq "..");
839                     } else {
840                         my @files = ($file);
841                         #push @files, "$out_basedir/include/Qt/$t" if(-e "$out_basedir/include/Qt/$t");
842                         foreach my $file (@files) {
843                            my $remove_file = 0;
844                            if(open(F, "<$file")) {
845                                 while(my $line = <F>) {
846                                     chomp $line;
847                                     if($line =~ /^\#include \"([^\"]*)\"$/) {
848                                         my $include = $1;
849                                         $include = $subdir . "/" . $include unless(substr($include, 0, 1) eq "/");
850                                         $remove_file = 1 unless(-e $include);
851                                     } else {
852                                         $remove_file = 0;
853                                         last;
854                                     }
855                                 }
856                                 close(F);
857                                 unlink $file if($remove_file);
858                             }
859                         }
860                     }
861                 }
862                 closedir DIR;
863             }
864
865         }
866     }
867
868     # create the version header files for each module
869     unless ($no_module_version_header) {
870         my $modulepri = $modulepris{$lib};
871         if (-e $modulepri) {
872             my $modulepriname = basename($modulepri);
873             my $moduleversionheader = "$modules{$lib}/" . lc($lib) . "version.h";
874             my $modulehexstring = sprintf("0x%02X%02X%02X", int($module_major_version), int($module_minor_version), int($module_patch_version));
875             open MODULE_VERSION_HEADER_FILE, ">$moduleversionheader";
876             print MODULE_VERSION_HEADER_FILE "/* This file was generated by syncqt with the info from sync.profile. */\n";
877             print MODULE_VERSION_HEADER_FILE "#ifndef QT_". uc($lib) . "_VERSION_H\n";
878             print MODULE_VERSION_HEADER_FILE "#define QT_". uc($lib) . "_VERSION_H\n";
879             print MODULE_VERSION_HEADER_FILE "\n";
880             print MODULE_VERSION_HEADER_FILE "#define " .uc($lib) . "_VERSION_STR \"" . $module_version . "\"\n";
881             print MODULE_VERSION_HEADER_FILE "\n";
882             print MODULE_VERSION_HEADER_FILE "#define " .uc($lib) . "_VERSION $modulehexstring\n", ;
883             print MODULE_VERSION_HEADER_FILE "\n";
884             print MODULE_VERSION_HEADER_FILE "#endif // QT_". uc($lib) . "_VERSION_H\n";
885         } elsif ($modulepri) {
886             print "WARNING: Module $lib\'s pri file '$modulepri' not found.\nSkipped creating module version header for $lib.\n";
887         }
888     }
889
890     #create the new ones
891     foreach my $current_dir (split(/;/, $dir)) {
892         my $headers_dir = $current_dir;
893         $headers_dir .= "/$pathtoheaders" if ($pathtoheaders);
894         #calc subdirs
895         my @subdirs = ($headers_dir);
896         foreach my $subdir (@subdirs) {
897             opendir DIR, $subdir or next;
898             while(my $t = readdir(DIR)) {
899                 push @subdirs, "$subdir/$t" if(-d "$subdir/$t" && !($t eq ".") &&
900                                                !($t eq "..") && !($t eq ".obj") &&
901                                                !($t eq ".moc") && !($t eq ".rcc") &&
902                                                !($t eq ".uic") && !($t eq "build"));
903             }
904             closedir DIR;
905         }
906
907         #calc files and "copy" them
908         foreach my $subdir (@subdirs) {
909             my @headers = findFiles($subdir, "^[-a-z0-9_]*\\.h\$" , 0);
910             if (defined $inject_headers{$subdir}) {
911                 foreach my $if ($inject_headers{$subdir}) {
912                     @headers = grep(!/^\Q$if\E$/, @headers); #in case we configure'd previously
913                     push @headers, "*".$if;
914                 }
915             }
916             foreach my $header (@headers) {
917                 my $shadow = ($header =~ s/^\*//);
918                 $header = 0 if($header =~ /^ui_.*.h/);
919                 foreach (@ignore_headers) {
920                     $header = 0 if($header eq $_);
921                 }
922                 if($header) {
923                     my $header_copies = 0;
924                     #figure out if it is a public header
925                     my $public_header = $header;
926                     if($public_header =~ /_p.h$/ || $public_header =~ /_pch.h$/) {
927                         $public_header = 0;
928                     } else {
929                         foreach (@ignore_for_master_contents) {
930                             $public_header = 0 if($header eq $_);
931                         }
932                     }
933
934                     my $iheader = $subdir . "/" . $header;
935                     $iheader =~ s/^\Q$basedir\E/$out_basedir/ if ($shadow);
936                     my @classes = $public_header ? classNames($iheader) : ();
937                     if($showonly) {
938                         print "$header [$lib]\n";
939                         foreach(@classes) {
940                             print "SYMBOL: $_\n";
941                         }
942                     } else {
943                         my $ts = (stat($iheader))[9];
944                         #find out all the places it goes..
945                         my @headers;
946                         if ($public_header) {
947                             @headers = ( "$out_basedir/include/$lib/$header" );
948
949                             # write forwarding headers to include/Qt
950                             if ($lib ne "phonon" && $subdir =~ /^$quoted_basedir\/src/) {
951                                 my $file_name = "$out_basedir/include/Qt/$header";
952                                 my $file_op = '>';
953                                 my $header_content = '';
954                                 if (exists $colliding_headers{$file_name}) {
955                                     $file_op = '>>';
956                                 } else {
957                                     $colliding_headers{$file_name} = 1;
958                                     my $warning_msg = 'Inclusion of header files from include/Qt is deprecated.';
959                                     $header_content = "#ifndef QT_NO_QT_INCLUDE_WARN\n" .
960                                                       "    #if defined(__GNUC__)\n" .
961                                                       "        #warning \"$warning_msg\"\n" .
962                                                       "    #elif defined(_MSC_VER)\n" .
963                                                       "        #pragma message(\"WARNING: $warning_msg\")\n" .
964                                                       "    #endif\n".
965                                                       "#endif\n\n";
966                                 }
967                                 $header_content .= '#include "' . "../$lib/$header" . "\"\n";
968                                 open HEADERFILE, $file_op, $file_name or die "unable to open '$file_name' : $!\n";
969                                 print HEADERFILE $header_content;
970                                 close HEADERFILE;
971                             }
972
973                             foreach my $full_class (@classes) {
974                                 my $header_base = basename($header);
975                                 # Strip namespaces:
976                                 my $class = $full_class;
977                                 $class =~ s/^.*:://;
978 #                               if ($class =~ m/::/) {
979 #                                  class =~ s,::,/,g;
980 #                               }
981                                 $class_lib_map_contents .= "QT_CLASS_LIB($full_class, $lib, $header_base)\n";
982                                 $header_copies++ if(syncHeader("$out_basedir/include/$lib/$class", "$out_basedir/include/$lib/$header", 0, $ts));
983
984                                 # KDE-Compat headers for Phonon
985                                 if ($lib eq "phonon") {
986                                     $header_copies++ if (syncHeader("$out_basedir/include/phonon_compat/Phonon/$class", "$out_basedir/include/$lib/$header", 0, $ts));
987                                 }
988                             }
989                         } elsif ($create_private_headers) {
990                             if ($module_version) {
991                                 @headers = ( "$out_basedir/include/$lib/$module_version/$lib/private/$header" );
992                             } else {
993                                 @headers = ( "$out_basedir/include/$lib/private/$header" );
994                             }
995                         }
996                         foreach(@headers) { #sync them
997                             $header_copies++ if(syncHeader($_, $iheader, $copy_headers && !$shadow, $ts));
998                         }
999
1000                         if($public_header) {
1001                             #put it into the master file
1002                             $master_contents .= "#include \"$public_header\"\n" if(shouldMasterInclude($iheader));
1003
1004                             #deal with the install directives
1005                             if($public_header) {
1006                                 my $pri_install_iheader = fixPaths($iheader, $current_dir);
1007                                 foreach my $class (@classes) {
1008                                     # Strip namespaces:
1009                                     $class =~ s/^.*:://;
1010 #                                   if ($class =~ m/::/) {
1011 #                                       $class =~ s,::,/,g;
1012 #                                   }
1013                                     my $class_header = fixPaths("$out_basedir/include/$lib/$class",
1014                                                                 $current_dir) . " ";
1015                                     $pri_install_classes .= $class_header
1016                                                                 unless($pri_install_classes =~ $class_header);
1017                                 }
1018                                 $pri_install_files.= "$pri_install_iheader ";;
1019                             }
1020                         }
1021                         else {
1022                             my $pri_install_iheader = fixPaths($iheader, $current_dir);
1023                             $pri_install_pfiles.= "$pri_install_iheader ";;
1024                         }
1025                     }
1026                     print "header created for $iheader ($header_copies)\n" if($header_copies > 0 && !$quiet);
1027                 }
1028             }
1029         }
1030     }
1031
1032     # close the master include:
1033     $master_contents .= "#endif\n";
1034
1035     unless($showonly) {
1036         my @master_includes;
1037         push @master_includes, "$out_basedir/include/$lib/$lib";
1038         push @master_includes, "$out_basedir/include/phonon_compat/Phonon/Phonon" if ($lib eq "phonon");
1039         foreach my $master_include (@master_includes) {
1040             #generate the "master" include file
1041             my @tmp = split(/;/,$modules{$lib});
1042             $pri_install_files .= fixPaths($master_include, $tmp[0]) . " "; #get the master file installed too
1043             if($master_include && -e $master_include) {
1044                 open MASTERINCLUDE, "<$master_include";
1045                 local $/;
1046                 binmode MASTERINCLUDE;
1047                 my $oldmaster = <MASTERINCLUDE>;
1048                 close MASTERINCLUDE;
1049                 $oldmaster =~ s/\r//g; # remove \r's , so comparison is ok on all platforms
1050                 $master_include = 0 if($oldmaster eq $master_contents);
1051             }
1052             if($master_include && $master_contents) {
1053                 my $master_dir = dirname($master_include);
1054                 mkpath $master_dir, !$quiet;
1055                 print "header (master) created for $lib\n" unless $quiet;
1056                 open MASTERINCLUDE, ">$master_include";
1057                 print MASTERINCLUDE $master_contents;
1058                 close MASTERINCLUDE;
1059             }
1060         }
1061
1062         #handle the headers.pri for each module
1063         my $headers_pri_contents = "";
1064         $headers_pri_contents .= "SYNCQT.HEADER_FILES = $pri_install_files\n";
1065         $headers_pri_contents .= "SYNCQT.HEADER_CLASSES = $pri_install_classes\n";
1066         $headers_pri_contents .= "SYNCQT.PRIVATE_HEADER_FILES = $pri_install_pfiles\n";
1067         my $headers_pri_file = "$out_basedir/include/$lib/headers.pri";
1068         if(-e $headers_pri_file) {
1069             open HEADERS_PRI_FILE, "<$headers_pri_file";
1070             local $/;
1071             binmode HEADERS_PRI_FILE;
1072             my $old_headers_pri_contents = <HEADERS_PRI_FILE>;
1073             close HEADERS_PRI_FILE;
1074             $old_headers_pri_contents =~ s/\r//g; # remove \r's , so comparison is ok on all platforms
1075             $headers_pri_file = 0 if($old_headers_pri_contents eq $headers_pri_contents);
1076         }
1077         if($headers_pri_file && $master_contents) {
1078             my $headers_pri_dir = dirname($headers_pri_file);
1079             mkpath $headers_pri_dir, !$quiet;
1080             print "headers.pri file created for $lib\n" unless $quiet;
1081             open HEADERS_PRI_FILE, ">$headers_pri_file";
1082             print HEADERS_PRI_FILE $headers_pri_contents;
1083             close HEADERS_PRI_FILE;
1084         }
1085
1086         # create forwarding module pri in qtbase/mkspecs/modules
1087         if ($module_fwd) {
1088             my $modulepri = $modulepris{$lib};
1089             if (-e $modulepri) {
1090                 my $modulepriname = basename($modulepri);
1091                 mkpath($module_fwd);
1092                 my $moduleprifwd = "$module_fwd/$modulepriname";
1093                 my $mod_base = $developer_build ? $basedir : $out_basedir;
1094                 my $mod_component_base = $developer_build ? $qtbasedir : $out_basedir;
1095                 open MODULE_PRI_FILE, ">$moduleprifwd" or die("Could not open $moduleprifwd for writing");
1096                 print MODULE_PRI_FILE "QT_MODULE_BASE = $mod_base\n";
1097                 print MODULE_PRI_FILE "QT_MODULE_BIN_BASE = $mod_component_base/bin\n";
1098                 print MODULE_PRI_FILE "QT_MODULE_INCLUDE_BASE = $out_basedir/include\n";
1099                 print MODULE_PRI_FILE "QT_MODULE_IMPORT_BASE = $mod_component_base/imports\n";
1100                 print MODULE_PRI_FILE "QT_MODULE_LIB_BASE = $mod_component_base/lib\n";
1101                 print MODULE_PRI_FILE "QT_MODULE_PLUGIN_BASE = $mod_component_base/plugins\n";
1102                 print MODULE_PRI_FILE "include($modulepri)\n";
1103                 close MODULE_PRI_FILE;
1104                 utime(time, (stat($modulepri))[9], $moduleprifwd);
1105                 if ($cache_module_fwd) {
1106                     my $cacheStatement = "QMAKE_EXTRA_MODULE_FORWARDS = \"$module_fwd\"";
1107                     my $cacheFile = "$out_basedir/.qmake.cache";
1108                     my $existingQmakeCache = fileContents($cacheFile);
1109                     # Skip if it's already there.
1110                     if ($existingQmakeCache !~ $cacheStatement) {
1111                         open QMAKE_CACHE_FILE, ">>$cacheFile" or die("Could not open $cacheFile for writing");
1112                         print QMAKE_CACHE_FILE "$cacheStatement\n";
1113                         close(QMAKE_CACHE_FILE);
1114                     }
1115                 }
1116             } elsif ($modulepri) {
1117                 print "WARNING: Module $lib\'s pri file '$modulepri' not found.\nSkipped creating forwarding pri for $lib.\n";
1118             }
1119         }
1120     }
1121 }
1122 unless($showonly || !$create_uic_class_map) {
1123     my $class_lib_map = "$out_basedir/src/tools/uic/qclass_lib_map.h";
1124     if(-e $class_lib_map) {
1125         open CLASS_LIB_MAP, "<$class_lib_map";
1126         local $/;
1127         binmode CLASS_LIB_MAP;
1128         my $old_class_lib_map_contents = <CLASS_LIB_MAP>;
1129         close CLASS_LIB_MAP;
1130         $old_class_lib_map_contents =~ s/\r//g; # remove \r's , so comparison is ok on all platforms
1131         $class_lib_map = 0 if($old_class_lib_map_contents eq $class_lib_map_contents);
1132     }
1133     if($class_lib_map) {
1134         my $class_lib_map_dir = dirname($class_lib_map);
1135         mkpath $class_lib_map_dir, !$quiet;
1136         open CLASS_LIB_MAP, ">$class_lib_map";
1137         print CLASS_LIB_MAP $class_lib_map_contents;
1138         close CLASS_LIB_MAP;
1139     }
1140 }
1141
1142 if($check_includes) {
1143     for my $lib (keys(%modules)) {
1144             #calc subdirs
1145             my @subdirs = ($modules{$lib});
1146             foreach my $subdir (@subdirs) {
1147                 opendir DIR, $subdir or die "Huh, directory ".$subdir." cannot be opened.";
1148                 while(my $t = readdir(DIR)) {
1149                     push @subdirs, "$subdir/$t" if(-d "$subdir/$t" && !($t eq ".") &&
1150                                                    !($t eq "..") && !($t eq ".obj") &&
1151                                                    !($t eq ".moc") && !($t eq ".rcc") &&
1152                                                    !($t eq ".uic") && !($t eq "build"));
1153                 }
1154                 closedir DIR;
1155             }
1156
1157             foreach my $subdir (@subdirs) {
1158                 my $header_skip_qt_module_test = 0;
1159                 foreach(@ignore_for_qt_module_check) {
1160                     foreach (split(/;/, $_)) {
1161                         $header_skip_qt_module_test = 1 if ($subdir =~ /^$_/);
1162                     }
1163                 }
1164                 my @headers = findFiles($subdir, "^[-a-z0-9_]*\\.h\$" , 0);
1165                 foreach my $header (@headers) {
1166                     my $header_skip_qt_begin_header_test = 0;
1167                     my $header_skip_qt_begin_namespace_test = 0;
1168                     $header = 0 if($header =~ /^ui_.*.h/);
1169                     foreach (@ignore_headers) {
1170                         $header = 0 if($header eq $_);
1171                     }
1172                     if($header) {
1173                         my $public_header = $header;
1174                         if($public_header =~ /_p.h$/ || $public_header =~ /_pch.h$/) {
1175                             $public_header = 0;
1176                         } else {
1177                             foreach (@ignore_for_master_contents) {
1178                                 $public_header = 0 if($header eq $_);
1179                             }
1180                             if($public_header) {
1181                                 foreach (@ignore_for_include_check) {
1182                                     $public_header = 0 if($header eq $_);
1183                                 }
1184                                 foreach(@ignore_for_qt_begin_header_check) {
1185                                     $header_skip_qt_begin_header_test = 1 if ($header eq $_);
1186                                 }
1187                                 foreach(@ignore_for_qt_begin_namespace_check) {
1188                                     $header_skip_qt_begin_namespace_test = 1 if ($header eq $_);
1189                                 }
1190                             }
1191                         }
1192
1193                         my $iheader = $subdir . "/" . $header;
1194                         if($public_header) {
1195                             if(open(F, "<$iheader")) {
1196                                 my $qt_module_found = 0;
1197                                 my $qt_begin_header_found = 0;
1198                                 my $qt_end_header_found = 0;
1199                                 my $qt_begin_namespace_found = 0;
1200                                 my $qt_end_namespace_found = 0;
1201                                 my $line;
1202                                 while($line = <F>) {
1203                                     chomp $line;
1204                                     my $output_line = 1;
1205                                     if($line =~ /^ *\# *pragma (qt_no_included_check|qt_sync_stop_processing)/) {
1206                                         last;
1207                                     } elsif($line =~ /^ *\# *include/) {
1208                                         my $include = $line;
1209                                         if($line =~ /<.*>/) {
1210                                             $include =~ s,.*<(.*)>.*,$1,;
1211                                         } elsif($line =~ /".*"/) {
1212                                             $include =~ s,.*"(.*)".*,$1,;
1213                                         } else {
1214                                             $include = 0;
1215                                         }
1216                                         if($include) {
1217                                             for my $trylib (keys(%modules)) {
1218                                                 if(-e "$out_basedir/include/$trylib/$include") {
1219                                                     print "WARNING: $iheader includes $include when it should include $trylib/$include\n";
1220                                                 }
1221                                             }
1222                                         }
1223                                     } elsif ($header_skip_qt_begin_header_test == 0 and $line =~ /^QT_BEGIN_HEADER\s*$/) {
1224                                         $qt_begin_header_found = 1;
1225                                     } elsif ($header_skip_qt_begin_header_test == 0 and $line =~ /^QT_END_HEADER\s*$/) {
1226                                         $qt_end_header_found = 1;
1227                                     } elsif ($header_skip_qt_begin_namespace_test == 0 and $line =~ /^QT_BEGIN_NAMESPACE\s*$/) {
1228                                         $qt_begin_namespace_found = 1;
1229                                     } elsif ($header_skip_qt_begin_namespace_test == 0 and $line =~ /^QT_END_NAMESPACE\s*$/) {
1230                                         $qt_end_namespace_found = 1;
1231                                     } elsif ($header_skip_qt_module_test == 0 and $line =~ /^QT_MODULE\(.*\)\s*$/) {
1232                                         $qt_module_found = 1;
1233                                     }
1234                                 }
1235                                 if ($header_skip_qt_begin_header_test == 0) {
1236                                     if ($qt_begin_header_found == 0) {
1237                                         print "WARNING: $iheader does not include QT_BEGIN_HEADER\n";
1238                                     }
1239
1240                                     if ($qt_begin_header_found && $qt_end_header_found == 0) {
1241                                         print "WARNING: $iheader has QT_BEGIN_HEADER but no QT_END_HEADER\n";
1242                                     }
1243                                 }
1244
1245                                 if ($header_skip_qt_begin_namespace_test == 0) {
1246                                     if ($qt_begin_namespace_found == 0) {
1247                                         print "WARNING: $iheader does not include QT_BEGIN_NAMESPACE\n";
1248                                     }
1249
1250                                     if ($qt_begin_namespace_found && $qt_end_namespace_found == 0) {
1251                                         print "WARNING: $iheader has QT_BEGIN_NAMESPACE but no QT_END_NAMESPACE\n";
1252                                     }
1253                                 }
1254
1255                                 if ($header_skip_qt_module_test == 0) {
1256                                     if ($qt_module_found == 0) {
1257                                         print "WARNING: $iheader does not include QT_MODULE\n";
1258                                     }
1259                                 }
1260                                 close(F);
1261                             }
1262                         }
1263                     }
1264                 }
1265             }
1266     }
1267 }
1268
1269 exit 0;