source: trunk/bin/syncqt

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

syncqt: Paths in headers.pri must be relative to QTDIR.

These paths are used in .pro files located in the Qt source tree (QTDIR)
so they must be relative to it in order to get correct final paths (not to
the build directory which differs in shadow builds).

The code only worked with shadow builds only if the shadow build tree
was located in the same parent directory as the Qt source tree (i.e.
/home/bob/Coding/qt and /home/bob/Coding/qt-build). This is not always
the case.

  • Property svn:executable set to *
File size: 46.0 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[, no_rebase])
345# Params: file, string, filepath to be made relative to dir
346# dir, string, dirpath for point of origin
347# no_rebase, disables changing $basedir to $out_basedir in
348# $file
349#
350# Purpose: file is made relative (if possible) of dir.
351# Returns: String with the above applied conversion.
352######################################################################
353sub fixPaths {
354 my ($file, $dir, $no_rebase) = @_;
355 $dir =~ s=^$basedir/=$out_basedir/= if(!$no_rebase && !($basedir eq $out_basedir));
356 $file =~ s=\\=/=g;
357 $file =~ s/\+/\\+/g;
358 $dir =~ s=\\=/=g;
359 $dir =~ s/\+/\\+/g;
360
361 #setup
362 my $ret = $file;
363 $ret =~ s,/cygdrive/([a-zA-Z])/,$1:/,g;
364 my $file_dir = dirname($file);
365 if($file_dir eq ".") {
366 $file_dir = getcwd();
367 $file_dir =~ s=\\=/=g;
368 }
369 $file_dir =~ s,/cygdrive/([a-zA-Z])/,$1:/,g;
370 if($dir eq ".") {
371 $dir = getcwd();
372 $dir =~ s=\\=/=g;
373 }
374 $dir =~ s,/cygdrive/([a-zA-Z])/,$1:/,g;
375 return basename($file) if($file_dir eq $dir);
376
377 #guts
378 my $match_dir = 0;
379 for(my $i = 1; $i < length($file_dir); $i++) {
380 my $slash = index($file_dir, "/", $i);
381 last if($slash == -1);
382 my $tmp = substr($file_dir, 0, $slash);
383 last unless($dir =~ m,^$tmp/,);
384 $match_dir = $tmp;
385 $i = $slash;
386 }
387 if($match_dir) {
388 my $after = substr($dir, length($match_dir));
389 my $count = ($after =~ tr,/,,);
390 my $dots = "";
391 for(my $i = 0; $i < $count; $i++) {
392 $dots .= "../";
393 }
394 $ret =~ s,^$match_dir,$dots,;
395 }
396 $ret =~ s,/+,/,g;
397 return $ret;
398}
399
400######################################################################
401# Syntax: fileContents(filename)
402# Params: filename, string, filename of file to return contents
403#
404# Purpose: Get the contents of a file.
405# Returns: String with contents of the file, or empty string if file
406# doens't exist.
407# Warning: Dies if it does exist but script cannot get read access.
408######################################################################
409sub fileContents {
410 my ($filename) = @_;
411 my $filecontents = "";
412 if (-e $filename) {
413 open(I, "< $filename") || die "Could not open $filename for reading, read block?";
414 local $/;
415 binmode I;
416 $filecontents = <I>;
417 close I;
418 }
419 return $filecontents;
420}
421
422######################################################################
423# Syntax: fileCompare(file1, file2)
424# Params: file1, string, filename of first file
425# file2, string, filename of second file
426#
427# Purpose: Determines if files are equal, and which one is newer.
428# Returns: 0 if files are equal no matter the timestamp, -1 if file1
429# is newer, 1 if file2 is newer.
430######################################################################
431sub fileCompare {
432 my ($file1, $file2) = @_;
433 my $file1contents = fileContents($file1);
434 my $file2contents = fileContents($file2);
435 if (! -e $file1) { return 1; }
436 if (! -e $file2) { return -1; }
437 return $file1contents ne $file2contents ? (stat($file2))[9] <=> (stat($file1))[9] : 0;
438}
439
440######################################################################
441# Syntax: copyFile(file, ifile)
442# Params: file, string, filename to create duplicate for
443# ifile, string, destination name of duplicate
444#
445# Purpose: Keeps files in sync so changes in the newer file will be
446# written to the other.
447# Returns: 1 if files were synced, else 0.
448# Warning: Dies if script cannot get write access.
449######################################################################
450sub copyFile
451{
452 my ($file,$ifile, $copy,$knowdiff,$filecontents,$ifilecontents) = @_;
453 # Bi-directional synchronization
454 open( I, "< " . $file ) || die "Could not open $file for reading";
455 local $/;
456 binmode I;
457 $filecontents = <I>;
458 close I;
459 if ( open(I, "< " . $ifile) ) {
460 local $/;
461 binmode I;
462 $ifilecontents = <I>;
463 close I;
464 $copy = fileCompare($file, $ifile);
465 $knowdiff = 0,
466 } else {
467 $copy = -1;
468 $knowdiff = 1;
469 }
470
471 if ( $knowdiff || ($filecontents ne $ifilecontents) ) {
472 if ( $copy > 0 ) {
473 my $file_dir = dirname($file);
474 mkpath $file_dir, !$quiet unless(-e $file_dir);
475 open(O, "> " . $file) || die "Could not open $file for writing (no write permission?)";
476 local $/;
477 binmode O;
478 print O $ifilecontents;
479 close O;
480 utime time, (stat($ifile))[9], $file;
481 return 1;
482 } elsif ( $copy < 0 ) {
483 my $ifile_dir = dirname($ifile);
484 mkpath $ifile_dir, !$quiet unless(-e $ifile_dir);
485 open(O, "> " . $ifile) || die "Could not open $ifile for writing (no write permission?)";
486 local $/;
487 binmode O;
488 print O $filecontents;
489 close O;
490 utime time, (stat($file))[9], $ifile;
491 return 1;
492 }
493 }
494 return 0;
495}
496
497######################################################################
498# Syntax: symlinkFile(file, ifile)
499# Params: file, string, filename to create "symlink" for
500# ifile, string, destination name of symlink
501#
502# Purpose: File is symlinked to ifile (or copied if filesystem doesn't
503# support symlink).
504# Returns: 1 on success, else 0.
505######################################################################
506sub symlinkFile
507{
508 my ($file,$ifile) = @_;
509
510 if ($isunix) {
511 print "symlink created for $file " unless $quiet;
512 if ( $force_relative && ($ifile =~ /^$basedir/)) {
513 my $t = getcwd();
514 my $c = -1;
515 my $p = "../";
516 $t =~ s-^$basedir/--;
517 $p .= "../" while( ($c = index( $t, "/", $c + 1)) != -1 );
518 $file =~ s-^$basedir/-$p-;
519 print " ($file)\n" unless $quiet;
520 }
521 print "\n" unless $quiet;
522 return symlink($file, $ifile);
523 }
524 return copyFile($file, $ifile);
525}
526
527######################################################################
528# Syntax: findFiles(dir, match, descend)
529# Params: dir, string, directory to search for name
530# match, string, regular expression to match in dir
531# descend, integer, 0 = non-recursive search
532# 1 = recurse search into subdirectories
533#
534# Purpose: Finds files matching a regular expression.
535# Returns: List of matching files.
536#
537# Examples:
538# findFiles("/usr","\.cpp$",1) - finds .cpp files in /usr and below
539# findFiles("/tmp","^#",0) - finds #* files in /tmp
540######################################################################
541sub findFiles {
542 my ($dir,$match,$descend) = @_;
543 my ($file,$p,@files);
544 local(*D);
545 $dir =~ s=\\=/=g;
546 ($dir eq "") && ($dir = ".");
547 if ( opendir(D,$dir) ) {
548 if ( $dir eq "." ) {
549 $dir = "";
550 } else {
551 ($dir =~ /\/$/) || ($dir .= "/");
552 }
553 foreach $file ( sort readdir(D) ) {
554 next if ( $file =~ /^\.\.?$/ );
555 $p = $file;
556 ($file =~ /$match/) && (push @files, $p);
557 if ( $descend && -d $p && ! -l $p ) {
558 push @files, &findFiles($p,$match,$descend);
559 }
560 }
561 closedir(D);
562 }
563 return @files;
564}
565
566# --------------------------------------------------------------------
567# "main" function
568# --------------------------------------------------------------------
569
570while ( @ARGV ) {
571 my $var = 0;
572 my $val = 0;
573
574 #parse
575 my $arg = shift @ARGV;
576 if ($arg eq "-h" || $arg eq "-help" || $arg eq "?") {
577 $var = "show_help";
578 $val = "yes";
579 } elsif($arg eq "-copy") {
580 $var = "copy";
581 $val = "yes";
582 } elsif($arg eq "-o" || $arg eq "-outdir") {
583 $var = "output";
584 $val = shift @ARGV;
585 } elsif($arg eq "-showonly" || $arg eq "-remove-stale" || $arg eq "-windows" ||
586 $arg eq "-relative" || $arg eq "-check-includes") {
587 $var = substr($arg, 1);
588 $val = "yes";
589 } elsif($arg =~ /^-no-(.*)$/) {
590 $var = $1;
591 $val = "no";
592 #these are for commandline compat
593 } elsif($arg eq "-inc") {
594 $var = "output";
595 $val = shift @ARGV;
596 } elsif($arg eq "-module") {
597 $var = "module";
598 $val = shift @ARGV;
599 } elsif($arg eq "-separate-module") {
600 $var = "separate-module";
601 $val = shift @ARGV;
602 } elsif($arg eq "-show") {
603 $var = "showonly";
604 $val = "yes";
605 } elsif($arg eq "-quiet") {
606 $var = "quiet";
607 $val = "yes";
608 } elsif($arg eq "-base-dir") {
609 # skip, it's been dealt with at the top of the file
610 shift @ARGV;
611 next;
612 }
613
614 #do something
615 if(!$var || $var eq "show_help") {
616 print "Unknown option: $arg\n\n" if(!$var);
617 showUsage();
618 } elsif ($var eq "copy") {
619 if($val eq "yes") {
620 $copy_headers++;
621 } elsif($showonly) {
622 $copy_headers--;
623 }
624 } elsif ($var eq "showonly") {
625 if($val eq "yes") {
626 $showonly++;
627 } elsif($showonly) {
628 $showonly--;
629 }
630 } elsif ($var eq "quiet") {
631 if($val eq "yes") {
632 $quiet++;
633 } elsif($quiet) {
634 $quiet--;
635 }
636 } elsif ($var eq "check-includes") {
637 if($val eq "yes") {
638 $check_includes++;
639 } elsif($check_includes) {
640 $check_includes--;
641 }
642 } elsif ($var eq "remove-stale") {
643 if($val eq "yes") {
644 $remove_stale++;
645 } elsif($remove_stale) {
646 $remove_stale--;
647 }
648 } elsif ($var eq "windows") {
649 if($val eq "yes") {
650 $force_win++;
651 } elsif($force_win) {
652 $force_win--;
653 }
654 } elsif ($var eq "relative") {
655 if($val eq "yes") {
656 $force_relative++;
657 } elsif($force_relative) {
658 $force_relative--;
659 }
660 } elsif ($var eq "module") {
661 print "module :$val:\n" unless $quiet;
662 die "No such module: $val" unless(defined $modules{$val});
663 push @modules_to_sync, $val;
664 } elsif ($var eq "separate-module") {
665 my ($module, $prodir, $headerdir) = split(/:/, $val);
666 $modules{$module} = $prodir;
667 push @modules_to_sync, $module;
668 $moduleheaders{$module} = $headerdir;
669 $create_uic_class_map = 0;
670 $create_private_headers = 0;
671 } elsif ($var eq "output") {
672 my $outdir = $val;
673 if(checkRelative($outdir)) {
674 $out_basedir = getcwd();
675 chomp $out_basedir;
676 $out_basedir .= "/" . $outdir;
677 } else {
678 $out_basedir = $outdir;
679 }
680 # \ -> /
681 $out_basedir =~ s=\\=/=g;
682 }
683}
684@modules_to_sync = keys(%modules) if($#modules_to_sync == -1);
685
686$isunix = checkUnix; #cache checkUnix
687
688# create path
689mkpath "$out_basedir/include", !$quiet;
690mkpath "$out_basedir/include/Qt", !$quiet;
691
692my @ignore_headers = ();
693my $class_lib_map_contents = "";
694my @ignore_for_master_contents = ( "qt.h", "qpaintdevicedefs.h" );
695my @ignore_for_include_check = ( "qatomic.h" );
696my @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" );
697my @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" );
698my @ignore_for_qt_module_check = ( "$modules{QtCore}/arch", "$modules{QtCore}/global", "$modules{QtSql}/drivers", "$modules{QtTest}", "$modules{QtDesigner}", "$modules{QtUiTools}", "$modules{QtDBus}", "$modules{phonon}" );
699my %colliding_headers = ();
700my %inject_headers = ( "$basedir/src/corelib/global" => ( "qconfig.h" ) ); # all from build dir
701
702foreach my $lib (@modules_to_sync) {
703 #iteration info
704 my $dir = $modules{$lib};
705 my $pathtoheaders = "";
706 $pathtoheaders = $moduleheaders{$lib} if ($moduleheaders{$lib});
707
708 #information used after the syncing
709 my $pri_install_classes = "";
710 my $pri_install_files = "";
711 my $pri_install_pfiles = "";
712
713 my $libcapitals = $lib;
714 $libcapitals =~ y/a-z/A-Z/;
715 my $master_contents = "#ifndef QT_".$libcapitals."_MODULE_H\n#define QT_".$libcapitals."_MODULE_H\n";
716
717 #get dependencies
718 if(-e "$dir/" . basename($dir) . ".pro") {
719 if(open(F, "<$dir/" . basename($dir) . ".pro")) {
720 while(my $line = <F>) {
721 chomp $line;
722 if($line =~ /^ *QT *\+?= *([^\r\n]*)/) {
723 foreach(split(/ /, $1)) {
724 $master_contents .= "#include <QtCore/QtCore>\n" if($_ eq "core");
725 $master_contents .= "#include <QtGui/QtGui>\n" if($_ eq "gui");
726 $master_contents .= "#include <QtNetwork/QtNetwork>\n" if($_ eq "network");
727 $master_contents .= "#include <QtSvg/QtSvg>\n" if($_ eq "svg");
728 $master_contents .= "#include <QtDeclarative/QtDeclarative>\n" if($_ eq "declarative");
729 $master_contents .= "#include <QtScript/QtScript>\n" if($_ eq "script");
730 $master_contents .= "#include <QtScriptTools/QtScriptTools>\n" if($_ eq "scripttools");
731 $master_contents .= "#include <Qt3Support/Qt3Support>\n" if($_ eq "qt3support");
732 $master_contents .= "#include <QtSql/QtSql>\n" if($_ eq "sql");
733 $master_contents .= "#include <QtXml/QtXml>\n" if($_ eq "xml");
734 $master_contents .= "#include <QtXmlPatterns/QtXmlPatterns>\n" if($_ eq "xmlpatterns");
735 $master_contents .= "#include <QtOpenGL/QtOpenGL>\n" if($_ eq "opengl");
736 $master_contents .= "#include <QtOpenVG/QtOpenVG>\n" if($_ eq "openvg");
737 }
738 }
739 }
740 close(F);
741 }
742 }
743
744 #remove the old files
745 if($remove_stale) {
746 my @subdirs = ("$out_basedir/include/$lib");
747 foreach my $subdir (@subdirs) {
748 if (opendir DIR, $subdir) {
749 while(my $t = readdir(DIR)) {
750 my $file = "$subdir/$t";
751 if(-d $file) {
752 push @subdirs, $file unless($t eq "." || $t eq "..");
753 } else {
754 my @files = ($file);
755 #push @files, "$out_basedir/include/Qt/$t" if(-e "$out_basedir/include/Qt/$t");
756 foreach my $file (@files) {
757 my $remove_file = 0;
758 if(open(F, "<$file")) {
759 while(my $line = <F>) {
760 chomp $line;
761 if($line =~ /^\#include \"([^\"]*)\"$/) {
762 my $include = $1;
763 $include = $subdir . "/" . $include unless(substr($include, 0, 1) eq "/");
764 $remove_file = 1 unless(-e $include);
765 } else {
766 $remove_file = 0;
767 last;
768 }
769 }
770 close(F);
771 unlink $file if($remove_file);
772 }
773 }
774 }
775 }
776 closedir DIR;
777 }
778
779 }
780 }
781
782 #create the new ones
783 foreach my $current_dir (split(/;/, $dir)) {
784 my $headers_dir = $current_dir;
785 $headers_dir .= "/$pathtoheaders" if ($pathtoheaders);
786 #calc subdirs
787 my @subdirs = ($headers_dir);
788 foreach my $subdir (@subdirs) {
789 opendir DIR, $subdir or next;
790 while(my $t = readdir(DIR)) {
791 push @subdirs, "$subdir/$t" if(-d "$subdir/$t" && !($t eq ".") &&
792 !($t eq "..") && !($t eq ".obj") &&
793 !($t eq ".moc") && !($t eq ".rcc") &&
794 !($t eq ".uic") && !($t eq "build"));
795 }
796 closedir DIR;
797 }
798
799 #calc files and "copy" them
800 foreach my $subdir (@subdirs) {
801 my @headers = findFiles($subdir, "^[-a-z0-9_]*\\.h\$" , 0);
802 if (defined $inject_headers{$subdir}) {
803 foreach my $if ($inject_headers{$subdir}) {
804 @headers = grep(!/^\Q$if\E$/, @headers); #in case we configure'd previously
805 push @headers, "*".$if;
806 }
807 }
808 foreach my $header (@headers) {
809 my $shadow = ($header =~ s/^\*//);
810 $header = 0 if($header =~ /^ui_.*.h/);
811 foreach (@ignore_headers) {
812 $header = 0 if($header eq $_);
813 }
814 if($header) {
815 my $header_copies = 0;
816 #figure out if it is a public header
817 my $public_header = $header;
818 if($public_header =~ /_p.h$/ || $public_header =~ /_pch.h$/) {
819 $public_header = 0;
820 } else {
821 foreach (@ignore_for_master_contents) {
822 $public_header = 0 if($header eq $_);
823 }
824 }
825
826 my $iheader = $subdir . "/" . $header;
827 $iheader =~ s/^\Q$basedir\E/$out_basedir/ if ($shadow);
828 my @classes = $public_header ? classNames($iheader) : ();
829 if($showonly) {
830 print "$header [$lib]\n";
831 foreach(@classes) {
832 print "SYMBOL: $_\n";
833 }
834 } else {
835 my $ts = (stat($iheader))[9];
836 #find out all the places it goes..
837 my @headers;
838 if ($public_header) {
839 @headers = ( "$out_basedir/include/$lib/$header" );
840
841 # write forwarding headers to include/Qt
842 if ($lib ne "phonon" && $subdir =~ /^$basedir\/src/) {
843 my $file_name = "$out_basedir/include/Qt/$header";
844 my $file_op = '>';
845 my $header_content = '';
846 if (exists $colliding_headers{$file_name}) {
847 $file_op = '>>';
848 } else {
849 $colliding_headers{$file_name} = 1;
850 my $warning_msg = 'Inclusion of header files from include/Qt is deprecated.';
851 $header_content = "#ifndef QT_NO_QT_INCLUDE_WARN\n" .
852 " #if defined(__GNUC__)\n" .
853 " #warning \"$warning_msg\"\n" .
854 " #elif defined(_MSC_VER)\n" .
855 " #pragma message(\"WARNING: $warning_msg\")\n" .
856 " #endif\n".
857 "#endif\n\n";
858 }
859 $header_content .= '#include "' . "../$lib/$header" . "\"\n";
860 open HEADERFILE, $file_op, $file_name or die "unable to open '$file_name' : $!\n";
861 print HEADERFILE $header_content;
862 close HEADERFILE;
863 }
864
865 foreach my $full_class (@classes) {
866 my $header_base = basename($header);
867 # Strip namespaces:
868 my $class = $full_class;
869 $class =~ s/^.*:://;
870# if ($class =~ m/::/) {
871# class =~ s,::,/,g;
872# }
873 $class_lib_map_contents .= "QT_CLASS_LIB($full_class, $lib, $header_base)\n";
874 $header_copies++ if(syncHeader("$out_basedir/include/$lib/$class", "$out_basedir/include/$lib/$header", 0, $ts));
875
876 # KDE-Compat headers for Phonon
877 if ($lib eq "phonon") {
878 $header_copies++ if (syncHeader("$out_basedir/include/phonon_compat/Phonon/$class", "$out_basedir/include/$lib/$header", 0, $ts));
879 }
880 }
881 } elsif ($create_private_headers) {
882 @headers = ( "$out_basedir/include/$lib/private/$header" );
883 }
884 foreach(@headers) { #sync them
885 $header_copies++ if(syncHeader($_, $iheader, $copy_headers && !$shadow, $ts));
886 }
887
888 if($public_header) {
889 #put it into the master file
890 $master_contents .= "#include \"$public_header\"\n" if(shouldMasterInclude($iheader));
891
892 #deal with the install directives
893 if($public_header) {
894 my $pri_install_iheader = fixPaths($iheader, $current_dir, 1);
895 foreach my $class (@classes) {
896 # Strip namespaces:
897 $class =~ s/^.*:://;
898# if ($class =~ m/::/) {
899# $class =~ s,::,/,g;
900# }
901 my $class_header = fixPaths("$out_basedir/include/$lib/$class",
902 $current_dir, 1) . " ";
903 $pri_install_classes .= $class_header
904 unless($pri_install_classes =~ $class_header);
905 }
906 $pri_install_files.= "$pri_install_iheader ";;
907 }
908 }
909 else {
910 my $pri_install_iheader = fixPaths($iheader, $current_dir, 1);
911 $pri_install_pfiles.= "$pri_install_iheader ";;
912 }
913 }
914 print "header created for $iheader ($header_copies)\n" if($header_copies > 0 && !$quiet);
915 }
916 }
917 }
918 }
919
920 # close the master include:
921 $master_contents .= "#endif\n";
922
923 unless($showonly) {
924 my @master_includes;
925 push @master_includes, "$out_basedir/include/$lib/$lib";
926 push @master_includes, "$out_basedir/include/phonon_compat/Phonon/Phonon" if ($lib eq "phonon");
927 foreach my $master_include (@master_includes) {
928 #generate the "master" include file
929 my @tmp = split(/;/,$modules{$lib});
930 $pri_install_files .= fixPaths($master_include, $tmp[0]) . " "; #get the master file installed too
931 if($master_include && -e $master_include) {
932 open MASTERINCLUDE, "<$master_include";
933 local $/;
934 binmode MASTERINCLUDE;
935 my $oldmaster = <MASTERINCLUDE>;
936 close MASTERINCLUDE;
937 $oldmaster =~ s/\r//g; # remove \r's , so comparison is ok on all platforms
938 $master_include = 0 if($oldmaster eq $master_contents);
939 }
940 if($master_include && $master_contents) {
941 my $master_dir = dirname($master_include);
942 mkpath $master_dir, !$quiet;
943 print "header (master) created for $lib\n" unless $quiet;
944 open MASTERINCLUDE, ">$master_include";
945 print MASTERINCLUDE $master_contents;
946 close MASTERINCLUDE;
947 }
948 }
949
950 #handle the headers.pri for each module
951 my $headers_pri_contents = "";
952 $headers_pri_contents .= "SYNCQT.HEADER_FILES = $pri_install_files\n";
953 $headers_pri_contents .= "SYNCQT.HEADER_CLASSES = $pri_install_classes\n";
954 $headers_pri_contents .= "SYNCQT.PRIVATE_HEADER_FILES = $pri_install_pfiles\n";
955 my $headers_pri_file = "$out_basedir/include/$lib/headers.pri";
956 if(-e $headers_pri_file) {
957 open HEADERS_PRI_FILE, "<$headers_pri_file";
958 local $/;
959 binmode HEADERS_PRI_FILE;
960 my $old_headers_pri_contents = <HEADERS_PRI_FILE>;
961 close HEADERS_PRI_FILE;
962 $old_headers_pri_contents =~ s/\r//g; # remove \r's , so comparison is ok on all platforms
963 $headers_pri_file = 0 if($old_headers_pri_contents eq $headers_pri_contents);
964 }
965 if($headers_pri_file && $master_contents) {
966 my $headers_pri_dir = dirname($headers_pri_file);
967 mkpath $headers_pri_dir, !$quiet;
968 print "headers.pri file created for $lib\n" unless $quiet;
969 open HEADERS_PRI_FILE, ">$headers_pri_file";
970 print HEADERS_PRI_FILE $headers_pri_contents;
971 close HEADERS_PRI_FILE;
972 }
973 }
974}
975unless($showonly || !$create_uic_class_map) {
976 my $class_lib_map = "$out_basedir/src/tools/uic/qclass_lib_map.h";
977 if(-e $class_lib_map) {
978 open CLASS_LIB_MAP, "<$class_lib_map";
979 local $/;
980 binmode CLASS_LIB_MAP;
981 my $old_class_lib_map_contents = <CLASS_LIB_MAP>;
982 close CLASS_LIB_MAP;
983 $old_class_lib_map_contents =~ s/\r//g; # remove \r's , so comparison is ok on all platforms
984 $class_lib_map = 0 if($old_class_lib_map_contents eq $class_lib_map_contents);
985 }
986 if($class_lib_map) {
987 my $class_lib_map_dir = dirname($class_lib_map);
988 mkpath $class_lib_map_dir, !$quiet;
989 open CLASS_LIB_MAP, ">$class_lib_map";
990 print CLASS_LIB_MAP $class_lib_map_contents;
991 close CLASS_LIB_MAP;
992 }
993}
994
995if($check_includes) {
996 for my $lib (keys(%modules)) {
997 #calc subdirs
998 my @subdirs = ($modules{$lib});
999 foreach my $subdir (@subdirs) {
1000 opendir DIR, $subdir or die "Huh, directory ".$subdir." cannot be opened.";
1001 while(my $t = readdir(DIR)) {
1002 push @subdirs, "$subdir/$t" if(-d "$subdir/$t" && !($t eq ".") &&
1003 !($t eq "..") && !($t eq ".obj") &&
1004 !($t eq ".moc") && !($t eq ".rcc") &&
1005 !($t eq ".uic") && !($t eq "build"));
1006 }
1007 closedir DIR;
1008 }
1009
1010 foreach my $subdir (@subdirs) {
1011 my $header_skip_qt_module_test = 0;
1012 foreach(@ignore_for_qt_module_check) {
1013 foreach (split(/;/, $_)) {
1014 $header_skip_qt_module_test = 1 if ($subdir =~ /^$_/);
1015 }
1016 }
1017 my @headers = findFiles($subdir, "^[-a-z0-9_]*\\.h\$" , 0);
1018 foreach my $header (@headers) {
1019 my $header_skip_qt_begin_header_test = 0;
1020 my $header_skip_qt_begin_namespace_test = 0;
1021 $header = 0 if($header =~ /^ui_.*.h/);
1022 foreach (@ignore_headers) {
1023 $header = 0 if($header eq $_);
1024 }
1025 if($header) {
1026 my $public_header = $header;
1027 if($public_header =~ /_p.h$/ || $public_header =~ /_pch.h$/) {
1028 $public_header = 0;
1029 } else {
1030 foreach (@ignore_for_master_contents) {
1031 $public_header = 0 if($header eq $_);
1032 }
1033 if($public_header) {
1034 foreach (@ignore_for_include_check) {
1035 $public_header = 0 if($header eq $_);
1036 }
1037 foreach(@ignore_for_qt_begin_header_check) {
1038 $header_skip_qt_begin_header_test = 1 if ($header eq $_);
1039 }
1040 foreach(@ignore_for_qt_begin_namespace_check) {
1041 $header_skip_qt_begin_namespace_test = 1 if ($header eq $_);
1042 }
1043 }
1044 }
1045
1046 my $iheader = $subdir . "/" . $header;
1047 if($public_header) {
1048 if(open(F, "<$iheader")) {
1049 my $qt_module_found = 0;
1050 my $qt_begin_header_found = 0;
1051 my $qt_end_header_found = 0;
1052 my $qt_begin_namespace_found = 0;
1053 my $qt_end_namespace_found = 0;
1054 my $line;
1055 while($line = <F>) {
1056 chomp $line;
1057 my $output_line = 1;
1058 if($line =~ /^ *\# *pragma (qt_no_included_check|qt_sync_stop_processing)/) {
1059 last;
1060 } elsif($line =~ /^ *\# *include/) {
1061 my $include = $line;
1062 if($line =~ /<.*>/) {
1063 $include =~ s,.*<(.*)>.*,$1,;
1064 } elsif($line =~ /".*"/) {
1065 $include =~ s,.*"(.*)".*,$1,;
1066 } else {
1067 $include = 0;
1068 }
1069 if($include) {
1070 for my $trylib (keys(%modules)) {
1071 if(-e "$out_basedir/include/$trylib/$include") {
1072 print "WARNING: $iheader includes $include when it should include $trylib/$include\n";
1073 }
1074 }
1075 }
1076 } elsif ($header_skip_qt_begin_header_test == 0 and $line =~ /^QT_BEGIN_HEADER\s*$/) {
1077 $qt_begin_header_found = 1;
1078 } elsif ($header_skip_qt_begin_header_test == 0 and $line =~ /^QT_END_HEADER\s*$/) {
1079 $qt_end_header_found = 1;
1080 } elsif ($header_skip_qt_begin_namespace_test == 0 and $line =~ /^QT_BEGIN_NAMESPACE\s*$/) {
1081 $qt_begin_namespace_found = 1;
1082 } elsif ($header_skip_qt_begin_namespace_test == 0 and $line =~ /^QT_END_NAMESPACE\s*$/) {
1083 $qt_end_namespace_found = 1;
1084 } elsif ($header_skip_qt_module_test == 0 and $line =~ /^QT_MODULE\(.*\)\s*$/) {
1085 $qt_module_found = 1;
1086 }
1087 }
1088 if ($header_skip_qt_begin_header_test == 0) {
1089 if ($qt_begin_header_found == 0) {
1090 print "WARNING: $iheader does not include QT_BEGIN_HEADER\n";
1091 }
1092
1093 if ($qt_begin_header_found && $qt_end_header_found == 0) {
1094 print "WARNING: $iheader has QT_BEGIN_HEADER but no QT_END_HEADER\n";
1095 }
1096 }
1097
1098 if ($header_skip_qt_begin_namespace_test == 0) {
1099 if ($qt_begin_namespace_found == 0) {
1100 print "WARNING: $iheader does not include QT_BEGIN_NAMESPACE\n";
1101 }
1102
1103 if ($qt_begin_namespace_found && $qt_end_namespace_found == 0) {
1104 print "WARNING: $iheader has QT_BEGIN_NAMESPACE but no QT_END_NAMESPACE\n";
1105 }
1106 }
1107
1108 if ($header_skip_qt_module_test == 0) {
1109 if ($qt_module_found == 0) {
1110 print "WARNING: $iheader does not include QT_MODULE\n";
1111 }
1112 }
1113 close(F);
1114 }
1115 }
1116 }
1117 }
1118 }
1119 }
1120}
1121
1122exit 0;
Note: See TracBrowser for help on using the repository browser.