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