6138a1cbc81b8134732a15a7df9f10e78a3e9c08
[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     my $pri_install_qpafiles = "";
864
865     my $libcapitals = $lib;
866     $libcapitals =~ y/a-z/A-Z/;
867     my $master_contents = "#ifndef QT_".$libcapitals."_MODULE_H\n#define QT_".$libcapitals."_MODULE_H\n";
868
869     #get dependencies
870     if(-e "$dir/" . basename($dir) . ".pro") {
871         if(open(F, "<$dir/" . basename($dir) . ".pro")) {
872             while(my $line = <F>) {
873                 chomp $line;
874                 if($line =~ /^ *QT *\+?= *([^\r\n]*)/) {
875                     foreach(split(/ /, $1)) {
876                         $_ =~ s/-private$//;
877                         my $content = $mastercontent{$_};
878                         $master_contents .= $content if ($content);
879                     }
880                 }
881             }
882             close(F);
883         }
884     }
885
886     #remove the old files
887     if($remove_stale) {
888         my @subdirs = ("$out_basedir/include/$lib");
889         foreach my $subdir (@subdirs) {
890             if (opendir DIR, $subdir) {
891                 foreach my $t (sort readdir(DIR)) {
892                     my $file = "$subdir/$t";
893                     if(-d $file) {
894                         push @subdirs, $file unless($t eq "." || $t eq "..");
895                     } else {
896                         my @files = ($file);
897                         #push @files, "$out_basedir/include/Qt/$t" if(-e "$out_basedir/include/Qt/$t");
898                         foreach my $file (@files) {
899                            my $remove_file = 0;
900                            if(open(F, "<$file")) {
901                                 while(my $line = <F>) {
902                                     chomp $line;
903                                     if($line =~ /^\#include \"([^\"]*)\"$/) {
904                                         my $include = $1;
905                                         $include = $subdir . "/" . $include unless(substr($include, 0, 1) eq "/");
906                                         $remove_file = 1 unless(-e $include);
907                                     } else {
908                                         $remove_file = 0;
909                                         last;
910                                     }
911                                 }
912                                 close(F);
913                                 unlink $file if($remove_file);
914                             }
915                         }
916                     }
917                 }
918                 closedir DIR;
919             }
920
921         }
922     }
923
924     # create the version header files for each module
925     unless ($no_module_version_header) {
926         my $modulepri = $modulepris{$lib};
927         if (-e $modulepri) {
928             my $modulepriname = basename($modulepri);
929             # FIXME: this creates a file in the source location for shadow-builds
930             my $moduleversionheader = "$modules{$lib}/" . lc($lib) . "version.h";
931             my $modulehexstring = sprintf("0x%02X%02X%02X", $module_major_version, $module_minor_version, $module_patch_version);
932             open MODULE_VERSION_HEADER_FILE, ">$moduleversionheader" or die "Can't open $moduleversionheader for writing";
933             print MODULE_VERSION_HEADER_FILE "/* This file was generated by syncqt with the info from sync.profile. */\n";
934             print MODULE_VERSION_HEADER_FILE "#ifndef QT_". uc($lib) . "_VERSION_H\n";
935             print MODULE_VERSION_HEADER_FILE "#define QT_". uc($lib) . "_VERSION_H\n";
936             print MODULE_VERSION_HEADER_FILE "\n";
937             print MODULE_VERSION_HEADER_FILE "#define " .uc($lib) . "_VERSION_STR \"" . $module_version . "\"\n";
938             print MODULE_VERSION_HEADER_FILE "\n";
939             print MODULE_VERSION_HEADER_FILE "#define " .uc($lib) . "_VERSION $modulehexstring\n", ;
940             print MODULE_VERSION_HEADER_FILE "\n";
941             print MODULE_VERSION_HEADER_FILE "#endif // QT_". uc($lib) . "_VERSION_H\n";
942             close MODULE_VERSION_HEADER_FILE;
943             $moduleversionheader = "<srcbase>" . substr($moduleversionheader, length($basedir)) if ($verbose_level < 2);
944             print "$lib: created version header $moduleversionheader\n" if($verbose_level);
945         } elsif ($modulepri) {
946             print "$lib: WARNING: Module\'s pri file '$modulepri' not found.\n$lib: Skipped creating module version header.\n";
947         }
948     }
949
950     #create the new ones
951     foreach my $current_dir (split(/;/, $dir)) {
952         my @headers_paths = split(/;/, $pathtoheaders);
953         if (@headers_paths) {
954             @headers_paths = map { "$current_dir/$_" } @headers_paths;
955         } else {
956             push @headers_paths, $current_dir;
957         }
958
959         foreach my $headers_dir (@headers_paths) {
960             #calc subdirs
961             my @subdirs = ($headers_dir);
962             foreach my $subdir (@subdirs) {
963                 if ($subdir =~ /\/doc$/) {
964                     next;
965                 }
966                 opendir DIR, $subdir or next;
967                 foreach my $t (sort readdir(DIR)) {
968                     push @subdirs, "$subdir/$t" if(-d "$subdir/$t" && !($t eq ".") &&
969                                                    !($t eq "..") && !($t eq ".obj") &&
970                                                    !($t eq ".moc") && !($t eq ".rcc") &&
971                                                    !($t eq ".uic") && !($t eq "build"));
972                 }
973                 closedir DIR;
974             }
975
976             #calc files and "copy" them
977             foreach my $subdir (@subdirs) {
978                 my @headers = findFiles($subdir, "^[-a-z0-9_]*\\.h\$" , 0);
979                 if (defined $inject_headers{$subdir}) {
980                     foreach my $if ($inject_headers{$subdir}) {
981                         @headers = grep(!/^\Q$if\E$/, @headers); #in case we configure'd previously
982                         push @headers, "*".$if;
983                     }
984                 }
985                 my $header_dirname = "";
986                 foreach my $header (@headers) {
987                     my $shadow = ($header =~ s/^\*//);
988                     $header = 0 if($header =~ /^ui_.*.h/);
989                     foreach (@ignore_headers) {
990                         $header = 0 if($header eq $_);
991                     }
992                     if($header) {
993                         my $header_copies = 0;
994                         #figure out if it is a public header
995                         my $public_header = $header;
996                         my $qpa_header = 0;
997                         if($public_header =~ /^qplatform/) {
998                             $public_header = 0;
999                             $qpa_header = 1;
1000                         } elsif($allheadersprivate || $public_header =~ /_p.h$/ || $public_header =~ /_pch.h$/) {
1001                             $public_header = 0;
1002                         } else {
1003                             foreach (@ignore_for_master_contents) {
1004                                 $public_header = 0 if($header eq $_);
1005                             }
1006                         }
1007
1008                         my $iheader = $subdir . "/" . $header;
1009                         $iheader =~ s/^\Q$basedir\E/$out_basedir/ if ($shadow);
1010                         my @classes = $public_header ? classNames($iheader) : ();
1011                         if($showonly) {
1012                             print "$header [$lib]\n";
1013                             foreach(@classes) {
1014                                 print "SYMBOL: $_\n";
1015                             }
1016                         } else {
1017                             my $ts = (stat($iheader))[9];
1018                             #find out all the places it goes..
1019                             my @headers;
1020                             if ($public_header) {
1021                                 @headers = ( "$out_basedir/include/$lib/$header" );
1022                                 foreach my $full_class (@classes) {
1023                                     my $header_base = basename($header);
1024                                     # Strip namespaces:
1025                                     my $class = $full_class;
1026                                     $class =~ s/^.*:://;
1027     #                               if ($class =~ m/::/) {
1028     #                                  class =~ s,::,/,g;
1029     #                               }
1030
1031                                     if (defined $explicitheaders{$lib}{$class}) {
1032                                         $header_copies++ if(syncHeader($lib, "$out_basedir/include/$lib/$class", "$out_basedir/include/$lib/$explicitheaders{$lib}{$class}", 0, $ts));
1033                                     } else {
1034                                         $class_lib_map_contents .= "QT_CLASS_LIB($full_class, $lib, $header_base)\n";
1035                                         $header_copies++ if(syncHeader($lib, "$out_basedir/include/$lib/$class", "$out_basedir/include/$lib/$header", 0, $ts));
1036                                     }
1037
1038                                     # KDE-Compat headers for Phonon
1039                                     if ($lib eq "phonon") {
1040                                         $header_copies++ if (syncHeader($lib, "$out_basedir/include/phonon_compat/Phonon/$class", "$out_basedir/include/$lib/$header", 0, $ts));
1041                                     }
1042                                 }
1043
1044                                 if ($explicitheaders{$lib}{basename($header)}) {
1045                                     $header_copies++ if(syncHeader($lib, "$out_basedir/include/$lib/$explicitheaders{$lib}{basename($header)}", "$out_basedir/include/$lib/$header", 0, $ts));
1046                                 }
1047
1048                             } elsif ($create_private_headers && !$qpa_header) {
1049                                 if ($module_version) {
1050                                     @headers = ( "$out_basedir/include/$lib/$module_version/$lib/private/$header" );
1051                                 } else {
1052                                     @headers = ( "$out_basedir/include/$lib/private/$header" );
1053                                 }
1054                             } elsif ($create_private_headers) {
1055                                 if ($module_version) {
1056                                     @headers = ( "$out_basedir/include/$lib/$module_version/$lib/qpa/$header" );
1057                                 } else {
1058                                     @headers = ( "$out_basedir/include/$lib/qpa/$header" );
1059                                 }
1060                             }
1061
1062                             foreach(@headers) { #sync them
1063                                 $header_copies++ if(syncHeader($lib, $_, $iheader, $copy_headers && !$shadow, $ts));
1064                             }
1065
1066                             if($public_header) {
1067                                 #put it into the master file
1068                                 $master_contents .= "#include \"$public_header\"\n" if(shouldMasterInclude($iheader));
1069
1070                                 #deal with the install directives
1071                                 if($public_header) {
1072                                     my $pri_install_iheader = fixPaths($iheader, $current_dir);
1073                                     foreach my $class (@classes) {
1074                                         # Strip namespaces:
1075                                         $class =~ s/^.*:://;
1076     #                                   if ($class =~ m/::/) {
1077     #                                       $class =~ s,::,/,g;
1078     #                                   }
1079                                         my $class_header = fixPaths("$out_basedir/include/$lib/$class",
1080                                                                     $current_dir) . " ";
1081                                         $pri_install_classes .= $class_header
1082                                                                     unless($pri_install_classes =~ $class_header);
1083                                     }
1084                                     if ($explicitheaders{$lib}{basename($iheader)}) {
1085                                         my $compat_header = fixPaths("$out_basedir/include/$lib/$explicitheaders{$lib}{basename($iheader)}", $current_dir) . " ";
1086                                         $pri_install_files .= $compat_header unless($pri_install_files =~ $compat_header);
1087                                     }
1088                                     $pri_install_files.= "$pri_install_iheader ";;
1089                                 }
1090                             }
1091                             elsif ($qpa_header) {
1092                                 my $pri_install_iheader = fixPaths($iheader, $current_dir);
1093                                 $pri_install_qpafiles.= "$pri_install_iheader ";;
1094                             }
1095                             else {
1096                                 my $pri_install_iheader = fixPaths($iheader, $current_dir);
1097                                 $pri_install_pfiles.= "$pri_install_iheader ";;
1098                             }
1099                         }
1100
1101                         if ($verbose_level && $header_copies) {
1102                             my $new_header_dirname = dirname($iheader);
1103                             $new_header_dirname = "<srcbase>" . substr($new_header_dirname, length($basedir)) if ($new_header_dirname && $verbose_level < 2);
1104                             my $header_base = basename($iheader);
1105                             if ($verbose_level < 3) {
1106                                 my $line_prefix = ",";
1107                                 if ($new_header_dirname ne $header_dirname) {
1108                                     $line_prefix = "$lib: created fwd-include header(s) for $new_header_dirname/ {";
1109                                     $line_prefix = " }\n".$line_prefix if ($header_dirname);
1110                                     $header_dirname = $new_header_dirname;
1111                                 } else {
1112                                     $line_prefix = ",";
1113                                 }
1114                                 print "$line_prefix $header_base ($header_copies)";
1115                             } else { # $verbose_level >= 3
1116                                 $iheader = "<srcbase>" . substr($iheader, length($basedir)) if ($verbose_level == 3);
1117                                 print "$lib: created $header_copies fwd-include headers for $iheader\n";
1118                             }
1119                         }
1120                     }
1121                 }
1122                 print " }\n" if ($header_dirname && $verbose_level > 0 && $verbose_level < 3);
1123             }
1124         }
1125     }
1126
1127     # close the master include:
1128     $master_contents .= "#endif\n";
1129
1130     unless($showonly) {
1131         # create deprecated headers
1132         my $first = 1;
1133         while (my ($header, $include) = each %{$deprecatedheaders{$lib}}) {
1134             my $public_header = 0;
1135             $public_header = 1 unless ($allheadersprivate || ($header =~ /_p\.h$/));
1136             next unless ($public_header || $create_private_headers);
1137
1138             my $header_path = "$out_basedir/include/$lib/";
1139             unless ($public_header) {
1140                 if ($module_version) {
1141                     $header_path .= "$module_version/$lib/private/";
1142                 } else {
1143                     $header_path .= "private/";
1144                 }
1145             }
1146             $header_path .= "$header";
1147
1148             unless (-e $header_path) {
1149                 my $guard = "DEPRECATED_HEADER_" . $lib . "_" . $header;
1150                 $guard =~ s/([^a-zA-Z0-9_])/_/g;
1151
1152                 my $header_dir = dirname($header_path);
1153                 make_path($header_dir, $lib, $verbose_level);
1154
1155                 open(HEADER, ">$header_path") || die "Could not open $header_path for writing: $!\n";
1156                 print HEADER "#ifndef $guard\n";
1157                 print HEADER "#define $guard\n";
1158                 my $warning = "Header <$lib/";
1159                 $warning .= "private/" unless ($public_header);
1160                 $warning .= "$header> is deprecated. Please include <$include> instead.";
1161                 print HEADER "#if defined(__GNUC__)\n";
1162                 print HEADER "#  warning $warning\n";
1163                 print HEADER "#elif defined(_MSC_VER)\n";
1164                 print HEADER "#  pragma message (\"$warning\")\n";
1165                 print HEADER "#endif\n";
1166                 print HEADER "#include <$include>\n";
1167                 if ($public_header) {
1168                     print HEADER "#if 0\n";
1169                     print HEADER "#pragma qt_no_master_include\n";
1170                     print HEADER "#endif\n";
1171                 }
1172                 print HEADER "#endif\n";
1173                 close HEADER;
1174
1175                 if ($verbose_level < 3) {
1176                     my $line_prefix = ",";
1177                     $line_prefix = "$lib: created deprecated header(s) {" if ($first);
1178                     print "$line_prefix $header";
1179                 } else {
1180                     print "$lib: created deprecated header $header => $include\n";
1181                 }
1182                 $first = 0;
1183             }
1184
1185             my $addendum = fixPaths($header_path, $dir) . " ";
1186             if ($public_header) {
1187                 $pri_install_files .=  $addendum;
1188             } else {
1189                 $pri_install_pfiles .=  $addendum;
1190             }
1191         }
1192         if ($verbose_level < 3) {
1193             print " }\n" unless ($first);
1194         }
1195
1196         my @master_includes;
1197         push @master_includes, "$out_basedir/include/$lib/$lib";
1198         push @master_includes, "$out_basedir/include/phonon_compat/Phonon/Phonon" if ($lib eq "phonon");
1199         foreach my $master_include (@master_includes) {
1200             #generate the "master" include file
1201             my @tmp = split(/;/,$modules{$lib});
1202             $pri_install_files .= fixPaths($master_include, $tmp[0]) . " "; #get the master file installed too
1203             if($master_include && -e $master_include) {
1204                 open MASTERINCLUDE, "<$master_include";
1205                 local $/;
1206                 binmode MASTERINCLUDE;
1207                 my $oldmaster = <MASTERINCLUDE>;
1208                 close MASTERINCLUDE;
1209                 $oldmaster =~ s/\r//g; # remove \r's , so comparison is ok on all platforms
1210                 $master_include = 0 if($oldmaster eq $master_contents);
1211             }
1212             if($master_include && $master_contents) {
1213                 my $master_dir = dirname($master_include);
1214                 make_path($master_dir, $lib, $verbose_level);
1215                 open MASTERINCLUDE, ">$master_include";
1216                 print MASTERINCLUDE $master_contents;
1217                 close MASTERINCLUDE;
1218                 print "$lib: created header (master) file\n" if($verbose_level);
1219             }
1220         }
1221
1222         #handle the headers.pri for each module
1223         my $headers_pri_contents = "";
1224         $headers_pri_contents .= "SYNCQT.HEADER_FILES = $pri_install_files\n";
1225         $headers_pri_contents .= "SYNCQT.HEADER_CLASSES = $pri_install_classes\n";
1226         $headers_pri_contents .= "SYNCQT.PRIVATE_HEADER_FILES = $pri_install_pfiles\n";
1227         $headers_pri_contents .= "SYNCQT.QPA_HEADER_FILES = $pri_install_qpafiles\n";
1228         my $headers_pri_file = "$out_basedir/include/$lib/headers.pri";
1229         if(-e $headers_pri_file) {
1230             open HEADERS_PRI_FILE, "<$headers_pri_file";
1231             local $/;
1232             binmode HEADERS_PRI_FILE;
1233             my $old_headers_pri_contents = <HEADERS_PRI_FILE>;
1234             close HEADERS_PRI_FILE;
1235             $old_headers_pri_contents =~ s/\r//g; # remove \r's , so comparison is ok on all platforms
1236             $headers_pri_file = 0 if($old_headers_pri_contents eq $headers_pri_contents);
1237         }
1238         if($headers_pri_file && $master_contents) {
1239             my $headers_pri_dir = dirname($headers_pri_file);
1240             make_path($headers_pri_dir, $lib, $verbose_level);
1241             open HEADERS_PRI_FILE, ">$headers_pri_file";
1242             print HEADERS_PRI_FILE $headers_pri_contents;
1243             close HEADERS_PRI_FILE;
1244             print "$lib: created headers.pri file\n" if($verbose_level);
1245         }
1246
1247         # create forwarding module pri in qtbase/mkspecs/modules
1248         if ($module_fwd) {
1249             my $modulepri = $modulepris{$lib};
1250             if (-e $modulepri) {
1251                 my $modulepriname = basename($modulepri);
1252                 make_path($module_fwd, $lib, $verbose_level);
1253                 my $moduleprifwd = "$module_fwd/$modulepriname";
1254                 my $mod_base = $basedir;
1255                 my $mod_component_base = $developer_build ? $qtbasedir : $out_basedir;
1256                 open MODULE_PRI_FILE, ">$moduleprifwd" or die("Could not open $moduleprifwd for writing");
1257                 print MODULE_PRI_FILE "QT_MODULE_BASE = $mod_base\n";
1258                 print MODULE_PRI_FILE "QT_MODULE_BIN_BASE = $mod_component_base/bin\n";
1259                 print MODULE_PRI_FILE "QT_MODULE_INCLUDE_BASE = $out_basedir/include\n";
1260                 print MODULE_PRI_FILE "QT_MODULE_IMPORT_BASE = $mod_component_base/imports\n";
1261                 print MODULE_PRI_FILE "QT_MODULE_LIB_BASE = $mod_component_base/lib\n";
1262                 print MODULE_PRI_FILE "QT_MODULE_PLUGIN_BASE = $mod_component_base/plugins\n";
1263                 print MODULE_PRI_FILE "include($modulepri)\n";
1264                 close MODULE_PRI_FILE;
1265                 utime(time, (stat($modulepri))[9], $moduleprifwd);
1266                 if ($cache_module_fwd) {
1267                     my $cacheStatement = "QMAKE_EXTRA_MODULE_FORWARDS = \"$module_fwd\"";
1268                     my $cacheFile = "$out_basedir/.qmake.cache";
1269                     my $existingQmakeCache = fileContents($cacheFile);
1270                     # Skip if it's already there.
1271                     if ($existingQmakeCache !~ $cacheStatement) {
1272                         open QMAKE_CACHE_FILE, ">>$cacheFile" or die("Could not open $cacheFile for writing");
1273                         print QMAKE_CACHE_FILE "$cacheStatement\n";
1274                         close(QMAKE_CACHE_FILE);
1275                     }
1276                 }
1277             } elsif ($modulepri) {
1278                 print "$lib: WARNING: Module\'s pri file '$modulepri' not found.\n$lib: Skipped creating forwarding pri.\n";
1279             }
1280         }
1281     }
1282 }
1283 unless($showonly || !$create_uic_class_map) {
1284     my $class_lib_map = "$out_basedir/src/tools/uic/qclass_lib_map.h";
1285     if(-e $class_lib_map) {
1286         open CLASS_LIB_MAP, "<$class_lib_map";
1287         local $/;
1288         binmode CLASS_LIB_MAP;
1289         my $old_class_lib_map_contents = <CLASS_LIB_MAP>;
1290         close CLASS_LIB_MAP;
1291         $old_class_lib_map_contents =~ s/\r//g; # remove \r's , so comparison is ok on all platforms
1292         $class_lib_map = 0 if($old_class_lib_map_contents eq $class_lib_map_contents);
1293     }
1294     if($class_lib_map) {
1295         my $class_lib_map_dir = dirname($class_lib_map);
1296         make_path($class_lib_map_dir, "<outdir>", $verbose_level);
1297         open CLASS_LIB_MAP, ">$class_lib_map";
1298         print CLASS_LIB_MAP $class_lib_map_contents;
1299         close CLASS_LIB_MAP;
1300     }
1301 }
1302
1303 if($check_includes) {
1304     for my $lib (keys(%modules)) {
1305             #calc subdirs
1306             my @subdirs = ($modules{$lib});
1307             foreach my $subdir (@subdirs) {
1308                 opendir DIR, $subdir or die "Huh, directory ".$subdir." cannot be opened.";
1309                 foreach my $t (sort readdir(DIR)) {
1310                     push @subdirs, "$subdir/$t" if(-d "$subdir/$t" && !($t eq ".") &&
1311                                                    !($t eq "..") && !($t eq ".obj") &&
1312                                                    !($t eq ".moc") && !($t eq ".rcc") &&
1313                                                    !($t eq ".uic") && !($t eq "build"));
1314                 }
1315                 closedir DIR;
1316             }
1317
1318             foreach my $subdir (@subdirs) {
1319                 my $header_skip_qt_module_test = 0;
1320                 foreach(@ignore_for_qt_module_check) {
1321                     foreach (split(/;/, $_)) {
1322                         $header_skip_qt_module_test = 1 if ($subdir =~ /^$_/);
1323                     }
1324                 }
1325                 my @headers = findFiles($subdir, "^[-a-z0-9_]*\\.h\$" , 0);
1326                 foreach my $header (@headers) {
1327                     my $header_skip_qt_begin_header_test = 0;
1328                     my $header_skip_qt_begin_namespace_test = 0;
1329                     $header = 0 if($header =~ /^ui_.*.h/);
1330                     foreach (@ignore_headers) {
1331                         $header = 0 if($header eq $_);
1332                     }
1333                     if($header) {
1334                         my $public_header = $header;
1335                         if($public_header =~ /_p.h$/ || $public_header =~ /_pch.h$/) {
1336                             $public_header = 0;
1337                         } elsif ($public_header =~ /^qplatform/) {
1338                             $public_header = 0;
1339                         } else {
1340                             foreach (@ignore_for_master_contents) {
1341                                 $public_header = 0 if($header eq $_);
1342                             }
1343                             if($public_header) {
1344                                 foreach (@ignore_for_include_check) {
1345                                     $public_header = 0 if($header eq $_);
1346                                 }
1347                                 foreach(@ignore_for_qt_begin_header_check) {
1348                                     $header_skip_qt_begin_header_test = 1 if ($header eq $_);
1349                                 }
1350                                 foreach(@ignore_for_qt_begin_namespace_check) {
1351                                     $header_skip_qt_begin_namespace_test = 1 if ($header eq $_);
1352                                 }
1353                             }
1354                         }
1355
1356                         my $iheader = $subdir . "/" . $header;
1357                         if($public_header) {
1358                             if(open(F, "<$iheader")) {
1359                                 my $qt_begin_header_found = 0;
1360                                 my $qt_end_header_found = 0;
1361                                 my $qt_begin_namespace_found = 0;
1362                                 my $qt_end_namespace_found = 0;
1363                                 my $line;
1364                                 while($line = <F>) {
1365                                     chomp $line;
1366                                     my $output_line = 1;
1367                                     if($line =~ /^ *\# *pragma (qt_no_included_check|qt_sync_stop_processing)/) {
1368                                         last;
1369                                     } elsif($line =~ /^ *\# *include/) {
1370                                         my $include = $line;
1371                                         if($line =~ /<.*>/) {
1372                                             $include =~ s,.*<(.*)>.*,$1,;
1373                                         } elsif($line =~ /".*"/) {
1374                                             $include =~ s,.*"(.*)".*,$1,;
1375                                         } else {
1376                                             $include = 0;
1377                                         }
1378                                         if($include) {
1379                                             for my $trylib (keys(%modules)) {
1380                                                 if(-e "$out_basedir/include/$trylib/$include") {
1381                                                     print "$lib: WARNING: $iheader includes $include when it should include $trylib/$include\n";
1382                                                 }
1383                                             }
1384                                         }
1385                                     } elsif ($header_skip_qt_begin_header_test == 0 and $line =~ /^QT_BEGIN_HEADER\s*$/) {
1386                                         $qt_begin_header_found = 1;
1387                                     } elsif ($header_skip_qt_begin_header_test == 0 and $line =~ /^QT_END_HEADER\s*$/) {
1388                                         $qt_end_header_found = 1;
1389                                     } elsif ($header_skip_qt_begin_namespace_test == 0 and $line =~ /^QT_BEGIN_NAMESPACE\s*$/) {
1390                                         $qt_begin_namespace_found = 1;
1391                                     } elsif ($header_skip_qt_begin_namespace_test == 0 and $line =~ /^QT_END_NAMESPACE\s*$/) {
1392                                         $qt_end_namespace_found = 1;
1393                                     }
1394                                 }
1395                                 if ($header_skip_qt_begin_header_test == 0) {
1396                                     if ($qt_begin_header_found == 0) {
1397                                         print "$lib: WARNING: $iheader does not include QT_BEGIN_HEADER\n";
1398                                     }
1399
1400                                     if ($qt_begin_header_found && $qt_end_header_found == 0) {
1401                                         print "$lib: WARNING: $iheader has QT_BEGIN_HEADER but no QT_END_HEADER\n";
1402                                     }
1403                                 }
1404
1405                                 if ($header_skip_qt_begin_namespace_test == 0) {
1406                                     if ($qt_begin_namespace_found == 0) {
1407                                         print "$lib: WARNING: $iheader does not include QT_BEGIN_NAMESPACE\n";
1408                                     }
1409
1410                                     if ($qt_begin_namespace_found && $qt_end_namespace_found == 0) {
1411                                         print "$lib: WARNING: $iheader has QT_BEGIN_NAMESPACE but no QT_END_NAMESPACE\n";
1412                                     }
1413                                 }
1414
1415                                 close(F);
1416                             }
1417                         }
1418                     }
1419                 }
1420             }
1421     }
1422 }
1423
1424 # Do configure tests now (pass some things along)
1425 # fatal tests have a non zero return
1426 # If the generator is not set (e.g. someone invoking syncqt as part of configure etc, then don't run tests either)
1427 unless ($showonly || $makefile_generator eq '') {
1428     my $configtests = dirname($0)."/qtmodule-configtests";
1429     if (! -f $configtests) {
1430         $configtests = $qtbasedir."/bin/qtmodule-configtests";
1431     }
1432     if (! -f $configtests) {
1433         warn "Unable to locate qtmodule-configtests script - config tests disabled.\n";
1434     } else {
1435         if (system($EXECUTABLE_NAME, $configtests, $basedir, $out_basedir, $qtbasedir, $makefile_generator)) {
1436             die "$configtests exited with status $?";
1437         }
1438     }
1439 }
1440
1441 exit 0;