source: trunk/bin/syncqt@ 858

Last change on this file since 858 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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