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