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