syncqt.pl 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218
  1. #!/usr/bin/env perl
  2. #############################################################################
  3. ##
  4. ## Copyright (C) 2016 The Qt Company Ltd.
  5. ## Copyright (C) 2016 Intel Corporation.
  6. ## Contact: https://www.qt.io/licensing/
  7. ##
  8. ## This file is part of the build configuration tools of the Qt Toolkit.
  9. ##
  10. ## $QT_BEGIN_LICENSE:LGPL$
  11. ## Commercial License Usage
  12. ## Licensees holding valid commercial Qt licenses may use this file in
  13. ## accordance with the commercial license agreement provided with the
  14. ## Software or, alternatively, in accordance with the terms contained in
  15. ## a written agreement between you and The Qt Company. For licensing terms
  16. ## and conditions see https://www.qt.io/terms-conditions. For further
  17. ## information use the contact form at https://www.qt.io/contact-us.
  18. ##
  19. ## GNU Lesser General Public License Usage
  20. ## Alternatively, this file may be used under the terms of the GNU Lesser
  21. ## General Public License version 3 as published by the Free Software
  22. ## Foundation and appearing in the file LICENSE.LGPL3 included in the
  23. ## packaging of this file. Please review the following information to
  24. ## ensure the GNU Lesser General Public License version 3 requirements
  25. ## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
  26. ##
  27. ## GNU General Public License Usage
  28. ## Alternatively, this file may be used under the terms of the GNU
  29. ## General Public License version 2.0 or (at your option) the GNU General
  30. ## Public license version 3 or any later version approved by the KDE Free
  31. ## Qt Foundation. The licenses are as published by the Free Software
  32. ## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
  33. ## included in the packaging of this file. Please review the following
  34. ## information to ensure the GNU General Public License requirements will
  35. ## be met: https://www.gnu.org/licenses/gpl-2.0.html and
  36. ## https://www.gnu.org/licenses/gpl-3.0.html.
  37. ##
  38. ## $QT_END_LICENSE$
  39. ##
  40. #############################################################################
  41. #
  42. # Synchronizes Qt header files - internal development tool.
  43. #
  44. # use packages -------------------------------------------------------
  45. use File::Basename;
  46. use File::Path;
  47. use File::Spec;
  48. use Cwd;
  49. use Cwd 'abs_path';
  50. use Config;
  51. use strict;
  52. use warnings;
  53. use English qw(-no_match_vars );
  54. my $normalizePath_fixDrive = ($^O eq "msys" ? 1 : 0);
  55. ######################################################################
  56. # Syntax: normalizePath(\$path)
  57. # Params: Reference to a path that's going to be normalized.
  58. #
  59. # Purpose: Converts the path into a form that can be used as include
  60. # path from C++ sources and qmake's .pro files.
  61. # Only relevant on Windows.
  62. # Returns: -none-
  63. ######################################################################
  64. sub normalizePath {
  65. my $s = shift;
  66. $$s =~ s=\\=/=g;
  67. if ($normalizePath_fixDrive && ($$s =~ m,^/([a-zA-Z])/(.*), || $$s =~ m,^([a-zA-Z]):/(.*),)) {
  68. $$s = lc($1) . ":/$2";
  69. }
  70. }
  71. # set output basedir to be where ever syncqt is run from
  72. our $out_basedir = getcwd();
  73. normalizePath(\$out_basedir);
  74. our $basedir;
  75. our $quoted_basedir;
  76. # Make sure we use Windows line endings for chomp and friends on Windows.
  77. $INPUT_RECORD_SEPARATOR = "\r\n" if ($^O eq "msys");
  78. # will be defined based on the modules sync.profile
  79. our (%modules, %moduleheaders, @allmoduleheadersprivate, %classnames, %deprecatedheaders);
  80. our @qpa_headers = ();
  81. # will be derived from sync.profile
  82. our %reverse_classnames = ();
  83. my %ignore_for_include_check = ();
  84. my %ignore_for_qt_begin_namespace_check = ();
  85. # global variables (modified by options)
  86. my $isunix = 0;
  87. my $module = 0;
  88. my $showonly = 0;
  89. my $verbose_level = 1;
  90. my $remove_stale = 1;
  91. my $force_win = 0;
  92. my $force_relative = 0;
  93. my $check_includes = 0;
  94. my $copy_headers = 0;
  95. my $create_private_headers = 1;
  96. my $minimal = 0;
  97. my $module_version = 0;
  98. my @modules_to_sync ;
  99. $force_relative = 1 if ( -d "/System/Library/Frameworks" );
  100. # functions ----------------------------------------------------------
  101. ######################################################################
  102. # Syntax: showUsage()
  103. # Params: -none-
  104. #
  105. # Purpose: Show the usage of the script.
  106. # Returns: -none-
  107. ######################################################################
  108. sub showUsage
  109. {
  110. print "$0 usage:\n";
  111. print " <module directory> Specifies which module to sync header files for (required for shadow builds!)\n\n";
  112. print " -copy Copy headers instead of include-fwd(default: " . ($copy_headers ? "yes" : "no") . ")\n";
  113. print " -remove-stale Removes stale headers (default: " . ($remove_stale ? "yes" : "no") . ")\n";
  114. print " -relative Force relative symlinks (default: " . ($force_relative ? "yes" : "no") . ")\n";
  115. print " -windows Force platform to Windows (default: " . ($force_win ? "yes" : "no") . ")\n";
  116. print " -showonly Show action but not perform (default: " . ($showonly ? "yes" : "no") . ")\n";
  117. print " -minimal Do not create CamelCase headers (default: " . ($minimal ? "yes" : "no") . ")\n";
  118. print " -outdir <PATH> Specify output directory for sync (default: $out_basedir)\n";
  119. print " -version <VERSION> Specify the module's version (default: detect from qglobal.h)\n";
  120. print " -quiet Only report problems, not activity (same as -verbose 0)\n";
  121. print " -v, -verbose <level> Sets the verbosity level (max. 4) (default: $verbose_level)\n";
  122. print " The short form increases the level by +1\n";
  123. print " -separate-module <NAME>:<PROFILEDIR>:<HEADERDIR>\n";
  124. print " Create headers for <NAME> with original headers in\n";
  125. print " <HEADERDIR> relative to <PROFILEDIR> \n";
  126. print " -private Force copy private headers (default: " . ($create_private_headers ? "yes" : "no") . ")\n";
  127. print " -help This help\n";
  128. exit 0;
  129. }
  130. ######################################################################
  131. # Syntax: checkUnix()
  132. # Params: -none-
  133. #
  134. # Purpose: Check if script runs on a Unix system or not. Cygwin
  135. # systems are _not_ detected as Unix systems.
  136. # Returns: 1 if a unix system, else 0.
  137. ######################################################################
  138. sub checkUnix {
  139. my ($r) = 0;
  140. if ( $force_win != 0) {
  141. return 0;
  142. } elsif ( -f "/bin/uname" ) {
  143. $r = 1;
  144. (-f "\\bin\\uname") && ($r = 0);
  145. } elsif ( -f "/usr/bin/uname" ) {
  146. $r = 1;
  147. (-f "\\usr\\bin\\uname") && ($r = 0);
  148. }
  149. if($r) {
  150. $_ = $Config{'osname'};
  151. $r = 0 if( /(ms)|(cyg)win/i );
  152. }
  153. return $r;
  154. }
  155. sub checkRelative {
  156. my ($dir) = @_;
  157. return 0 if($dir =~ /^\//);
  158. return 0 if(!checkUnix() && $dir =~ /[a-zA-Z]:[\/\\]/);
  159. return 1;
  160. }
  161. ######################################################################
  162. # Syntax: shouldMasterInclude(iheader)
  163. # Params: iheader, string, filename to verify inclusion
  164. #
  165. # Purpose: Determines if header should be in the master include file.
  166. # Returns: 0 if file contains "#pragma qt_no_master_include" or not
  167. # able to open, else 1.
  168. ######################################################################
  169. sub shouldMasterInclude {
  170. my ($iheader) = @_;
  171. return 0 if (basename($iheader) =~ /_/);
  172. return 0 if (basename($iheader) =~ /qconfig/);
  173. if (open(F, "<$iheader")) {
  174. while (<F>) {
  175. chomp;
  176. chop if /\r$/;
  177. return 0 if (/^\#pragma qt_no_master_include$/);
  178. }
  179. close(F);
  180. } else {
  181. return 0;
  182. }
  183. return 1;
  184. }
  185. ######################################################################
  186. # Syntax: classNames(iheader, clean)
  187. # Params: iheader, string, filename to parse for classname "symlinks"
  188. # (out) clean, boolean, will be set to false if the header isn't clean
  189. #
  190. # Purpose: Scans through iheader to find all classnames that should be
  191. # synced into library's include structure.
  192. # Returns: List of all class names in a file.
  193. ######################################################################
  194. sub classNames {
  195. my @ret;
  196. my ($iheader, $clean) = @_;
  197. $$clean = 1;
  198. my $ihdrbase = basename($iheader);
  199. my $classname = $classnames{$ihdrbase};
  200. push @ret, split(/,/, $classname) if ($classname);
  201. my $parsable = "";
  202. if(open(F, "<$iheader")) {
  203. while(<F>) {
  204. my $line = $_;
  205. chomp $line;
  206. chop $line if ($line =~ /\r$/);
  207. if($line =~ /^\#/) {
  208. $$clean = 0 if ($line =~ m/^#pragma qt_sync_skip_header_check/);
  209. return @ret if($line =~ m/^#pragma qt_sync_stop_processing/);
  210. push(@ret, $1) if($line =~ m/^#pragma qt_class\(([^)]*)\)[\r\n]*$/);
  211. $line = 0;
  212. }
  213. if($line) {
  214. $line =~ s,//.*$,,; #remove c++ comments
  215. $line .= ";" if($line =~ m/^Q_[A-Z_0-9]*\(.*\)[\r\n]*$/); #qt macro
  216. $line .= ";" if($line =~ m/^QT_(BEGIN|END)_HEADER[\r\n]*$/); #qt macro
  217. $line .= ";" if($line =~ m/^QT_(BEGIN|END)_NAMESPACE(_[A-Z]+)*[\r\n]*$/); #qt macro
  218. $line .= ";" if($line =~ m/^QT_MODULE\(.*\)[\r\n]*$/); # QT_MODULE macro
  219. $line .= ";" if($line =~ m/^QT_WARNING_(PUSH|POP|DISABLE_\w+\(.*\))[\r\n]*$/); # qt macros
  220. $parsable .= " " . $line;
  221. }
  222. }
  223. close(F);
  224. }
  225. my $last_definition = 0;
  226. my @namespaces;
  227. for(my $i = 0; $i < length($parsable); $i++) {
  228. my $definition = 0;
  229. my $character = substr($parsable, $i, 1);
  230. if($character eq "/" && substr($parsable, $i+1, 1) eq "*") { #I parse like this for greedy reasons
  231. for($i+=2; $i < length($parsable); $i++) {
  232. my $end = substr($parsable, $i, 2);
  233. if($end eq "*/") {
  234. $last_definition = $i+2;
  235. $i++;
  236. last;
  237. }
  238. }
  239. } elsif($character eq "{") {
  240. my $brace_depth = 1;
  241. my $block_start = $i + 1;
  242. BLOCK: for($i+=1; $i < length($parsable); $i++) {
  243. my $ignore = substr($parsable, $i, 1);
  244. if($ignore eq "{") {
  245. $brace_depth++;
  246. } elsif($ignore eq "}") {
  247. $brace_depth--;
  248. unless($brace_depth) {
  249. for(my $i2 = $i+1; $i2 < length($parsable); $i2++) {
  250. my $end = substr($parsable, $i2, 1);
  251. if($end eq ";" || $end ne " ") {
  252. $definition = substr($parsable, $last_definition, $block_start - $last_definition) . "}";
  253. $i = $i2 if($end eq ";");
  254. $last_definition = $i + 1;
  255. last BLOCK;
  256. }
  257. }
  258. }
  259. }
  260. }
  261. } elsif($character eq ";") {
  262. $definition = substr($parsable, $last_definition, $i - $last_definition + 1);
  263. $last_definition = $i + 1;
  264. } elsif($character eq "}") {
  265. # a naked } must be a namespace ending
  266. # if it's not a namespace, it's eaten by the loop above
  267. pop @namespaces;
  268. $last_definition = $i + 1;
  269. }
  270. if (substr($parsable, $last_definition, $i - $last_definition + 1) =~ m/ namespace ([^ ]*) /
  271. && substr($parsable, $i+1, 1) eq "{") {
  272. push @namespaces, $1;
  273. # Eat the opening { so that the condensing loop above doesn't see it
  274. $i++;
  275. $last_definition = $i + 1;
  276. }
  277. if($definition) {
  278. $definition =~ s=[\n\r]==g;
  279. my @symbols;
  280. my $post_kw = qr/Q_DECL_FINAL|final|sealed/; # add here macros and keywords that go after the class-name of a class definition
  281. if($definition =~ m/^ *typedef *.*\(\*([^\)]*)\)\(.*\);$/) {
  282. push @symbols, $1;
  283. } elsif($definition =~ m/^ *typedef +(.*) +([^ ]*);$/) {
  284. push @symbols, $2;
  285. } elsif($definition =~ m/^ *(template *<.*> *)?(class|struct) +([^ <>]* +)?((?!$post_kw)[^<\s]+) ?(<[^>]*> ?)?\s*(?:$post_kw)?\s*((,|:)\s*(public|protected|private) *.*)? *\{\}$/o) {
  286. push @symbols, $4;
  287. } elsif($definition =~ m/^ *Q_DECLARE_.*ITERATOR\((.*)\);$/) {
  288. push @symbols, "Q" . $1 . "Iterator";
  289. push @symbols, "QMutable" . $1 . "Iterator";
  290. }
  291. our $publicclassregexp;
  292. foreach my $symbol (@symbols) {
  293. $symbol = (join("::", @namespaces) . "::" . $symbol) if (scalar @namespaces);
  294. my $revhdr = $reverse_classnames{$symbol};
  295. next if (defined($revhdr) and $revhdr ne $ihdrbase);
  296. if ($symbol =~ /^Q[^:]*$/) { # no-namespace, starting with Q
  297. push @ret, $symbol;
  298. } elsif (defined($publicclassregexp)) {
  299. push @ret, $symbol if ($symbol =~ $publicclassregexp);
  300. }
  301. }
  302. }
  303. }
  304. return @ret;
  305. }
  306. sub check_header {
  307. my ($lib, $header, $iheader, $public_header, $private_header) = @_;
  308. my $header_skip_qt_begin_namespace_test = 0;
  309. if ($public_header) {
  310. return if ($ignore_for_include_check{$header});
  311. $header_skip_qt_begin_namespace_test = 1 if ($ignore_for_qt_begin_namespace_check{$header});
  312. }
  313. open(F, "<$iheader") or return;
  314. my $qt_begin_namespace_found = 0;
  315. my $qt_end_namespace_found = 0;
  316. my $qt_namespace_suffix = "";
  317. my $line;
  318. my $stop_processing = 0;
  319. my $we_mean_it = 0;
  320. while ($line = <F>) {
  321. chomp $line;
  322. my $output_line = 1;
  323. if ($line =~ /^ *\# *pragma (qt_no_included_check|qt_sync_stop_processing)/) {
  324. $stop_processing = 1;
  325. last;
  326. }
  327. if ($line =~ /^ *\# *include/) {
  328. my $include = $line;
  329. if ($line =~ /<.*>/) {
  330. $include =~ s,.*<(.*)>.*,$1,;
  331. } elsif ($line =~ /".*"/) {
  332. $include =~ s,.*"(.*)".*,$1,;
  333. } else {
  334. $include = 0;
  335. }
  336. if ($include && $public_header) {
  337. print STDERR "$lib: ERROR: $iheader includes private header $include\n" if ($include =~ /_p\.h$/);
  338. for my $trylib (keys(%modules)) {
  339. if (-e "$out_basedir/include/$trylib/$include") {
  340. print STDERR "$lib: WARNING: $iheader includes $include when it should include $trylib/$include\n";
  341. }
  342. }
  343. }
  344. } elsif (!$private_header) {
  345. if ($header_skip_qt_begin_namespace_test == 0 and $line =~ /^QT_BEGIN_NAMESPACE(_[A-Z_]+)?\s*$/) {
  346. $qt_namespace_suffix = defined($1) ? $1 : "";
  347. $qt_begin_namespace_found = 1;
  348. } elsif ($header_skip_qt_begin_namespace_test == 0 and $line =~ /^QT_END_NAMESPACE$qt_namespace_suffix\s*$/) {
  349. $qt_end_namespace_found = 1;
  350. }
  351. } elsif ($line =~ "^// We mean it.") {
  352. ++$we_mean_it;
  353. }
  354. }
  355. if ($public_header) {
  356. if ($header_skip_qt_begin_namespace_test == 0 and $stop_processing == 0) {
  357. if ($qt_begin_namespace_found == 0) {
  358. print STDERR "$lib: WARNING: $iheader does not include QT_BEGIN_NAMESPACE\n";
  359. }
  360. if ($qt_begin_namespace_found && $qt_end_namespace_found == 0) {
  361. print STDERR "$lib: WARNING: $iheader has QT_BEGIN_NAMESPACE$qt_namespace_suffix but no QT_END_NAMESPACE$qt_namespace_suffix\n";
  362. }
  363. }
  364. } elsif ($private_header) {
  365. print STDERR "$lib: WARNING: $iheader does not have the \"We mean it.\" warning\n" if (!$we_mean_it);
  366. }
  367. close(F);
  368. }
  369. sub make_path {
  370. my ($dir, $lib, $be_verbose) = @_;
  371. unless(-e $dir) {
  372. mkpath $dir;
  373. $dir = "<outbase>" . substr($dir, length($out_basedir)) if ($be_verbose < 3);
  374. print "$lib: mkpath $dir\n" if ($be_verbose > 1);
  375. }
  376. }
  377. ######################################################################
  378. # Syntax: syncHeader(header, iheader, copy, timestamp)
  379. # Params: header, string, filename to create "symlink" for
  380. # iheader, string, destination name of symlink
  381. # copy, forces header to be a copy of iheader
  382. # timestamp, the requested modification time if copying
  383. #
  384. # Purpose: Syncronizes header to iheader
  385. # Returns: 1 if successful, else 0.
  386. ######################################################################
  387. sub syncHeader {
  388. my ($lib, $header, $iheader, $copy, $ts) = @_;
  389. normalizePath(\$iheader);
  390. normalizePath(\$header);
  391. return copyFile($lib, $iheader, $header) if($copy);
  392. unless(-e $header) {
  393. my $header_dir = dirname($header);
  394. make_path($header_dir, $lib, $verbose_level);
  395. #write it
  396. my $iheader_out = fixPaths($iheader, $header_dir);
  397. open(HEADER, ">$header") || die "Could not open $header for writing: $!\n";
  398. print HEADER "#include \"$iheader_out\"\n";
  399. close HEADER;
  400. if(defined($ts)) {
  401. utime(time, $ts, $header) or die "$iheader, $header";
  402. }
  403. return 1;
  404. }
  405. return 0;
  406. }
  407. ######################################################################
  408. # Syntax: fixPaths(file, dir)
  409. # Params: file, string, filepath to be made relative to dir
  410. # dir, string, dirpath for point of origin
  411. #
  412. # Purpose: file is made relative (if possible) of dir.
  413. # Returns: String with the above applied conversion.
  414. ######################################################################
  415. sub cleanupPath {
  416. my ($file) = @_;
  417. normalizePath(\$file);
  418. while ($file =~ s,/[^/]+/\.\./,/,) {}
  419. return $file;
  420. }
  421. sub fixPaths {
  422. my ($file, $dir) = @_;
  423. my $out = File::Spec->abs2rel(cleanupPath($file), cleanupPath($dir));
  424. $out =~ s,\\,/,g;
  425. $out = "\"$out\"" if ($out =~ / /);
  426. return $out;
  427. }
  428. ######################################################################
  429. # Syntax: fileContents(filename)
  430. # Params: filename, string, filename of file to return contents
  431. #
  432. # Purpose: Get the contents of a file.
  433. # Returns: String with contents of the file, or empty string if file
  434. # doens't exist.
  435. # Warning: Dies if it does exist but script cannot get read access.
  436. ######################################################################
  437. sub fileContents {
  438. my ($filename) = @_;
  439. my $filecontents = "";
  440. if (-e $filename) {
  441. open(I, "< $filename") || die "Could not open $filename for reading, read block?";
  442. local $/;
  443. binmode I;
  444. $filecontents = <I>;
  445. close I;
  446. }
  447. return $filecontents;
  448. }
  449. ######################################################################
  450. # Syntax: writeFile(filename, contents)
  451. # Params: filename, string, filename of file to write
  452. # contents, string, new contents for the file
  453. #
  454. # Purpose: Write file with given contents. If new contents match old
  455. # ones, do no change the file's timestamp.
  456. # Returns: 1 if the file's contents changed.
  457. ######################################################################
  458. sub writeFile {
  459. my ($filename, $contents, $lib, $what) = @_;
  460. my $oldcontents = fileContents($filename);
  461. $oldcontents =~ s/\r//g; # remove \r's , so comparison is ok on all platforms
  462. if ($oldcontents ne $contents) {
  463. open(O, "> " . $filename) || die "Could not open $filename for writing: $!\n";
  464. print O $contents;
  465. close O;
  466. if ($lib && $verbose_level) {
  467. my $action = ($oldcontents eq "") ? "created" : "updated";
  468. print "$lib: $action $what\n";
  469. }
  470. return 1;
  471. }
  472. return 0;
  473. }
  474. ######################################################################
  475. # Syntax: fileCompare(file1, file2)
  476. # Params: file1, string, filename of first file
  477. # file2, string, filename of second file
  478. #
  479. # Purpose: Determines if files are equal, and which one is newer.
  480. # Returns: 0 if files are equal no matter the timestamp, -1 if file1
  481. # is newer, 1 if file2 is newer.
  482. ######################################################################
  483. sub fileCompare {
  484. my ($file1, $file2) = @_;
  485. my $file1contents = fileContents($file1);
  486. my $file2contents = fileContents($file2);
  487. if (! -e $file1) { return 1; }
  488. if (! -e $file2) { return -1; }
  489. return $file1contents ne $file2contents ? (stat($file2))[9] <=> (stat($file1))[9] : 0;
  490. }
  491. ######################################################################
  492. # Syntax: copyFile(file, ifile)
  493. # Params: file, string, filename to create duplicate for
  494. # ifile, string, destination name of duplicate
  495. #
  496. # Purpose: Keeps files in sync so changes in the newer file will be
  497. # written to the other.
  498. # Returns: 1 if files were synced, else 0.
  499. # Warning: Dies if script cannot get write access.
  500. ######################################################################
  501. sub copyFile
  502. {
  503. my ($lib, $file,$ifile, $copy,$knowdiff,$filecontents,$ifilecontents) = @_;
  504. # Bi-directional synchronization
  505. open( I, "< " . $file ) || die "Could not open $file for reading";
  506. local $/;
  507. binmode I;
  508. $filecontents = <I>;
  509. close I;
  510. if ( open(I, "< " . $ifile) ) {
  511. local $/;
  512. binmode I;
  513. $ifilecontents = <I>;
  514. close I;
  515. $copy = fileCompare($file, $ifile);
  516. $knowdiff = 0,
  517. } else {
  518. $copy = -1;
  519. $knowdiff = 1;
  520. }
  521. if ( $knowdiff || ($filecontents ne $ifilecontents) ) {
  522. if ( $copy > 0 ) {
  523. my $file_dir = dirname($file);
  524. make_path($file_dir, $lib, $verbose_level);
  525. open(O, "> " . $file) || die "Could not open $file for writing (no write permission?)";
  526. local $/;
  527. binmode O;
  528. print O $ifilecontents;
  529. close O;
  530. utime time, (stat($ifile))[9], $file;
  531. return 1;
  532. } elsif ( $copy < 0 ) {
  533. my $ifile_dir = dirname($ifile);
  534. make_path($ifile_dir, $lib, $verbose_level);
  535. open(O, "> " . $ifile) || die "Could not open $ifile for writing (no write permission?)";
  536. local $/;
  537. binmode O;
  538. print O $filecontents;
  539. close O;
  540. utime time, (stat($file))[9], $ifile;
  541. return 1;
  542. }
  543. }
  544. return 0;
  545. }
  546. ######################################################################
  547. # Syntax: findFiles(dir, match, descend)
  548. # Params: dir, string, directory to search for name
  549. # match, string, regular expression to match in dir
  550. # descend, integer, 0 = non-recursive search
  551. # 1 = recurse search into subdirectories
  552. #
  553. # Purpose: Finds files matching a regular expression.
  554. # Returns: List of matching files.
  555. #
  556. # Examples:
  557. # findFiles("/usr","\.cpp$",1) - finds .cpp files in /usr and below
  558. # findFiles("/tmp","^#",0) - finds #* files in /tmp
  559. ######################################################################
  560. sub findFiles {
  561. my ($dir,$match,$descend) = @_;
  562. my ($file,$p,@files);
  563. local(*D);
  564. normalizePath(\$dir);
  565. ($dir eq "") && ($dir = ".");
  566. if ( opendir(D,$dir) ) {
  567. if ( $dir eq "." ) {
  568. $dir = "";
  569. } else {
  570. ($dir =~ /\/$/) || ($dir .= "/");
  571. }
  572. foreach $file ( sort readdir(D) ) {
  573. next if ( $file =~ /^\.\.?$/ );
  574. $p = $file;
  575. ($file =~ /$match/) && (push @files, $p);
  576. if ( $descend && -d $p && ! -l $p ) {
  577. push @files, &findFiles($p,$match,$descend);
  578. }
  579. }
  580. closedir(D);
  581. }
  582. return @files;
  583. }
  584. sub listSubdirs {
  585. my @subdirs = @_;
  586. foreach my $subdir (@subdirs) {
  587. opendir DIR, $subdir or die "Huh, directory ".$subdir." cannot be opened.";
  588. foreach my $t (sort readdir(DIR)) {
  589. push @subdirs, "$subdir/$t" if(-d "$subdir/$t" && !($t eq ".") &&
  590. !($t eq "..") && !($t eq ".obj") &&
  591. !($t eq ".moc") && !($t eq ".rcc") &&
  592. !($t eq ".uic") && !($t eq "build") &&
  593. !($t eq "doc"));
  594. }
  595. closedir DIR;
  596. }
  597. return @subdirs;
  598. }
  599. ######################################################################
  600. # Syntax: loadSyncProfile()
  601. #
  602. # Purpose: Locates the sync.profile.
  603. # Returns: Hashmap of module name -> directory.
  604. ######################################################################
  605. sub loadSyncProfile {
  606. my ($srcbase, $outbase) = @_;
  607. if ($verbose_level) {
  608. print("<srcbase> = $$srcbase \n");
  609. print("<outbase> = $$outbase \n");
  610. }
  611. my $syncprofile = "$$srcbase/sync.profile";
  612. my $result;
  613. unless ($result = do "$syncprofile") {
  614. die "syncqt couldn't parse $syncprofile: $@" if $@;
  615. die "syncqt couldn't execute $syncprofile: $!" unless defined $result;
  616. }
  617. for my $fn (keys %classnames) {
  618. for my $cn (split(/,/, $classnames{$fn})) {
  619. $reverse_classnames{$cn} = $fn;
  620. }
  621. }
  622. return $result;
  623. }
  624. sub basePrettify {
  625. my ($arg) = @_;
  626. $$arg =~ s,^\Q$basedir\E,<srcbase>,;
  627. $$arg =~ s,^\Q$out_basedir\E,<outbase>,;
  628. }
  629. sub cleanPath {
  630. my ($arg) = @_;
  631. while ($arg =~ s,[^/]+/\.\.(/|$),,) {}
  632. return $arg;
  633. }
  634. sub locateSyncProfile
  635. {
  636. my ($directory) = @_;
  637. $directory = abs_path($directory);
  638. while (1) {
  639. my $file = $directory."/sync.profile";
  640. return $file if (-e $file);
  641. my $odir = $directory;
  642. $directory = dirname($directory);
  643. return undef if ($directory eq $odir);
  644. }
  645. }
  646. sub isQpaHeader
  647. {
  648. my ($header) = @_;
  649. foreach my $qpa_header (@qpa_headers) {
  650. return 1 if ($header =~ $qpa_header);
  651. }
  652. return 0;
  653. }
  654. # check if this is an in-source build, and if so use that as the basedir too
  655. $basedir = locateSyncProfile($out_basedir);
  656. if ($basedir) {
  657. $basedir = dirname($basedir) ;
  658. normalizePath(\$basedir);
  659. $quoted_basedir = "\Q$basedir";
  660. }
  661. # --------------------------------------------------------------------
  662. # "main" function
  663. # --------------------------------------------------------------------
  664. while ( @ARGV ) {
  665. my $var = 0;
  666. my $val = 0;
  667. #parse
  668. my $arg = shift @ARGV;
  669. if ($arg eq "-h" || $arg eq "-help" || $arg eq "-?" || $arg eq "?") {
  670. $var = "show_help";
  671. $val = "yes";
  672. } elsif($arg eq "-copy") {
  673. $var = "copy";
  674. $val = "yes";
  675. } elsif($arg eq "-o" || $arg eq "-outdir") {
  676. $var = "output";
  677. $val = shift @ARGV;
  678. } elsif($arg eq "-showonly" || $arg eq "-remove-stale" || $arg eq "-windows" ||
  679. $arg eq "-relative" || $arg eq "-check-includes") {
  680. $var = substr($arg, 1);
  681. $val = "yes";
  682. } elsif($arg =~ /^-no-(.*)$/) {
  683. $var = $1;
  684. $val = "no";
  685. #these are for commandline compat
  686. } elsif($arg eq "-inc") {
  687. $var = "output";
  688. $val = shift @ARGV;
  689. } elsif($arg eq "-module") {
  690. $var = "module";
  691. $val = shift @ARGV;
  692. } elsif($arg eq "-separate-module") {
  693. $var = "separate-module";
  694. $val = shift @ARGV;
  695. } elsif($arg eq "-show") {
  696. $var = "showonly";
  697. $val = "yes";
  698. } elsif($arg eq "-quiet") {
  699. $var = "verbose";
  700. $val = "0";
  701. } elsif($arg eq "-v") {
  702. $var = "verbose";
  703. $val = "yes";
  704. } elsif($arg eq "-verbose") {
  705. $var = "verbose";
  706. $val = shift @ARGV;
  707. } elsif($arg eq "-minimal") {
  708. $var = "minimal";
  709. $val = "yes";
  710. } elsif($arg eq "-private") {
  711. $var = "create_private_headers";
  712. $val = "yes";
  713. } elsif($arg eq "-version") {
  714. $var = "version";
  715. $val = shift @ARGV;
  716. } elsif($arg =~/^-/) {
  717. print STDERR "ERROR: Unknown option: $arg\n\n" if (!$var);
  718. showUsage();
  719. } else {
  720. $basedir = locateSyncProfile($arg);
  721. die "Could not find a sync.profile for '$arg'\n" if (!$basedir);
  722. $basedir = dirname($basedir);
  723. normalizePath(\$basedir);
  724. $quoted_basedir = "\Q$basedir";
  725. $var = "ignore";
  726. }
  727. #do something
  728. if(!$var || $var eq "show_help") {
  729. print STDERR "ERROR: Unknown option: $arg\n\n" if (!$var);
  730. showUsage();
  731. } elsif ($var eq "copy") {
  732. if($val eq "yes") {
  733. $copy_headers++;
  734. } elsif($showonly) {
  735. $copy_headers--;
  736. }
  737. } elsif ($var eq "showonly") {
  738. if($val eq "yes") {
  739. $showonly++;
  740. } elsif($showonly) {
  741. $showonly--;
  742. }
  743. } elsif ($var eq "verbose") {
  744. if($val eq "yes") {
  745. $verbose_level++;
  746. } elsif($val eq "no" && $verbose_level) {
  747. $verbose_level--;
  748. } else {
  749. $verbose_level = int($val);
  750. }
  751. } elsif ($var eq "check-includes") {
  752. if($val eq "yes") {
  753. $check_includes++;
  754. } elsif($check_includes) {
  755. $check_includes--;
  756. }
  757. } elsif ($var eq "remove-stale") {
  758. if($val eq "yes") {
  759. $remove_stale++;
  760. } elsif($remove_stale) {
  761. $remove_stale--;
  762. }
  763. } elsif ($var eq "windows") {
  764. if($val eq "yes") {
  765. $force_win++;
  766. } elsif($force_win) {
  767. $force_win--;
  768. }
  769. } elsif ($var eq "relative") {
  770. if($val eq "yes") {
  771. $force_relative++;
  772. } elsif($force_relative) {
  773. $force_relative--;
  774. }
  775. } elsif ($var eq "minimal") {
  776. if($val eq "yes") {
  777. $minimal++;
  778. } elsif($minimal) {
  779. $minimal--;
  780. }
  781. } elsif ($var eq "module") {
  782. push @modules_to_sync, $val;
  783. } elsif ($var eq "separate-module") {
  784. my ($module, $prodir, $headerdir) = split(/:/, $val);
  785. $modules{$module} = $prodir;
  786. push @modules_to_sync, $module;
  787. $moduleheaders{$module} = $headerdir;
  788. } elsif ($var eq "version") {
  789. if($val) {
  790. $module_version = $val;
  791. } else {
  792. die "The -version option requires an argument";
  793. }
  794. } elsif ($var eq "output") {
  795. my $outdir = $val;
  796. if(checkRelative($outdir)) {
  797. $out_basedir = getcwd();
  798. chomp $out_basedir;
  799. $out_basedir .= "/" . $outdir;
  800. } else {
  801. $out_basedir = $outdir;
  802. }
  803. normalizePath(\$out_basedir);
  804. }
  805. }
  806. # if we have no $basedir we cannot be sure which sources you want, so die
  807. die "Could not find any sync.profile for your module!\nPass <module directory> to syncqt to sync your header files.\nsyncqt failed" if (!$basedir);
  808. die "The -version argument is mandatory" if (!$module_version);
  809. our @ignore_headers = ();
  810. our @ignore_for_master_contents = ();
  811. our @ignore_for_include_check = ();
  812. our @ignore_for_qt_begin_namespace_check = ();
  813. our @ignore_for_qt_module_check = ();
  814. our %inject_headers = ();
  815. # load the module's sync.profile here, before we can
  816. loadSyncProfile(\$basedir, \$out_basedir);
  817. @modules_to_sync = keys(%modules) if($#modules_to_sync == -1);
  818. my %allmoduleheadersprivate = map { $_ => 1 } @allmoduleheadersprivate;
  819. %ignore_for_include_check = map { $_ => 1 } @ignore_for_include_check;
  820. %ignore_for_qt_begin_namespace_check = map { $_ => 1 } @ignore_for_qt_begin_namespace_check;
  821. $isunix = checkUnix; #cache checkUnix
  822. foreach my $lib (@modules_to_sync) {
  823. die "No such module: $lib" unless(defined $modules{$lib});
  824. #iteration info
  825. my $module = $modules{$lib};
  826. my $is_qt = !($module =~ s/^!//);
  827. my @dirs = split(/;/, $module);
  828. my $dir = $dirs[0];
  829. shift @dirs if ($dir =~ s/^>//);
  830. my $pathtoheaders = "";
  831. $pathtoheaders = $moduleheaders{$lib} if ($moduleheaders{$lib});
  832. my $allheadersprivate = 0;
  833. $allheadersprivate = 1 if $allmoduleheadersprivate{$lib};
  834. #information used after the syncing
  835. my $pri_install_classes = "";
  836. my $pri_install_files = "";
  837. my $pri_install_pfiles = "";
  838. my $pri_install_qpafiles = "";
  839. my $pri_injections = "";
  840. my $pri_clean_files = "";
  841. my $libcapitals = uc($lib);
  842. my $master_contents =
  843. "#ifndef QT_".$libcapitals."_MODULE_H\n" .
  844. "#define QT_".$libcapitals."_MODULE_H\n" .
  845. "#include <$lib/${lib}Depends>\n";
  846. #remove the old files
  847. if($remove_stale) {
  848. my %injections = ();
  849. for my $p (keys %inject_headers) {
  850. next unless ($p =~ /^\Q$dir\E(\/|$)/);
  851. my $sp = $p;
  852. $sp =~ s,^\Q$basedir\E/,$out_basedir/,;
  853. for my $n (@{$inject_headers{$p}}) {
  854. $injections{$sp."/".$n} = 1;
  855. }
  856. }
  857. my @subdirs = ("$out_basedir/include/$lib");
  858. foreach my $subdir (@subdirs) {
  859. if (opendir DIR, $subdir) {
  860. foreach my $t (sort { $b cmp $a } readdir(DIR)) {
  861. my $file = "$subdir/$t";
  862. if(-d $file) {
  863. push @subdirs, $file unless($t eq "." || $t eq "..");
  864. } else {
  865. my @files = ($file);
  866. #push @files, "$out_basedir/include/Qt/$t" if(-e "$out_basedir/include/Qt/$t");
  867. foreach my $file (@files) {
  868. my $remove_file = 0;
  869. if(open(F, "<$file")) {
  870. while(my $line = <F>) {
  871. chomp $line;
  872. if($line =~ /^\#include \"([^\"]*)\"$/) {
  873. my $include = $1;
  874. $include = $subdir . "/" . $include unless(substr($include, 0, 1) eq "/");
  875. $remove_file = 1 unless(-e $include or defined $injections{cleanPath($include)});
  876. } else {
  877. $remove_file = 0;
  878. last;
  879. }
  880. }
  881. close(F);
  882. unlink $file if($remove_file);
  883. }
  884. }
  885. }
  886. }
  887. closedir DIR;
  888. }
  889. }
  890. }
  891. #create the new ones
  892. foreach my $current_dir (@dirs) {
  893. my $thisprivate = 0;
  894. ($current_dir =~ s/^\^//) and $thisprivate = 1;
  895. my @headers_paths = split(/;/, $pathtoheaders);
  896. if (@headers_paths) {
  897. @headers_paths = map { "$current_dir/$_" } @headers_paths;
  898. } else {
  899. push @headers_paths, $current_dir;
  900. }
  901. foreach my $headers_dir (@headers_paths) {
  902. #calc subdirs
  903. my @subdirs = listSubdirs($headers_dir);
  904. #calc files and "copy" them
  905. foreach my $subdir (@subdirs) {
  906. my @headers = findFiles($subdir, "^[-a-z0-9_]*\\.h\$" , 0);
  907. if (defined $inject_headers{$subdir}) {
  908. foreach my $if (@{$inject_headers{$subdir}}) {
  909. @headers = grep(!/^\Q$if\E$/, @headers); #in case we configure'd previously
  910. push @headers, "*".$if;
  911. }
  912. }
  913. my $header_dirname = "";
  914. foreach my $header (@headers) {
  915. my $shadow = ($header =~ s/^\*//);
  916. $header = 0 if ($header =~ /^ui_.*\.h$/);
  917. foreach (@ignore_headers) {
  918. $header = 0 if($header eq $_);
  919. }
  920. if($header) {
  921. my $header_copies = 0;
  922. #figure out if it is a public header
  923. my $public_header = $header;
  924. my $qpa_header = 0;
  925. if(isQpaHeader($public_header)) {
  926. $public_header = 0;
  927. $qpa_header = 1;
  928. } elsif ($allheadersprivate || $thisprivate || $public_header =~ /_p(ch)?\.h$/) {
  929. $public_header = 0;
  930. } else {
  931. foreach (@ignore_for_master_contents) {
  932. $public_header = 0 if($header eq $_);
  933. }
  934. }
  935. my $clean_header;
  936. my $iheader = $subdir . "/" . $header;
  937. $iheader =~ s/^\Q$basedir\E/$out_basedir/ if ($shadow);
  938. if ($check_includes) {
  939. # We need both $public_header and $private_header because QPA headers count as neither
  940. my $private_header = !$public_header && !$qpa_header
  941. && $header =~ /_p\.h$/ && $subdir !~ /3rdparty/;
  942. check_header($lib, $header, $iheader, $public_header, $private_header);
  943. }
  944. my @classes = $public_header && (!$minimal && $is_qt) ? classNames($iheader, \$clean_header) : ();
  945. if($showonly) {
  946. print "$header [$lib]\n";
  947. foreach(@classes) {
  948. print "SYMBOL: $_\n";
  949. }
  950. } else {
  951. my $ts = $shadow ? 0 : (stat($iheader))[9];
  952. #find out all the places it goes..
  953. my $oheader;
  954. if ($public_header) {
  955. $oheader = "$out_basedir/include/$lib/$header";
  956. foreach my $full_class (@classes) {
  957. my $header_base = basename($header);
  958. # Strip namespaces:
  959. my $class = $full_class;
  960. $class =~ s/^.*:://;
  961. # if ($class =~ m/::/) {
  962. # class =~ s,::,/,g;
  963. # }
  964. $header_copies++ if (!$shadow && syncHeader($lib, "$out_basedir/include/$lib/$class", "$out_basedir/include/$lib/$header", 0, $ts));
  965. }
  966. } elsif ($create_private_headers && !$qpa_header) {
  967. $oheader = "$out_basedir/include/$lib/$module_version/$lib/private/$header";
  968. } elsif ($create_private_headers) {
  969. $oheader = "$out_basedir/include/$lib/$module_version/$lib/qpa/$header";
  970. }
  971. $header_copies++ if (!$shadow && syncHeader($lib, $oheader, $iheader, $copy_headers, $ts));
  972. my $pri_install_iheader = fixPaths($iheader, $dir);
  973. my $injection = "";
  974. if($public_header) {
  975. #put it into the master file
  976. $master_contents .= "#include \"$public_header\"\n" if (!$shadow && shouldMasterInclude($iheader));
  977. #deal with the install directives
  978. foreach my $class (@classes) {
  979. # Strip namespaces:
  980. $class =~ s/^.*:://;
  981. # if ($class =~ m/::/) {
  982. # $class =~ s,::,/,g;
  983. # }
  984. my $class_header = fixPaths("$out_basedir/include/$lib/$class", $dir) . " ";
  985. $pri_install_classes .= $class_header
  986. unless($pri_install_classes =~ $class_header);
  987. $injection .= ":$class";
  988. }
  989. $pri_install_files.= "$pri_install_iheader ";;
  990. $pri_clean_files .= "$pri_install_iheader " if ($clean_header);
  991. }
  992. elsif ($qpa_header) {
  993. $pri_install_qpafiles.= "$pri_install_iheader ";;
  994. }
  995. else {
  996. $pri_install_pfiles.= "$pri_install_iheader ";;
  997. }
  998. $pri_injections .= fixPaths($iheader, "$out_basedir/include/$lib")
  999. .":".fixPaths($oheader, "$out_basedir/include/$lib")
  1000. .$injection." " if ($shadow);
  1001. }
  1002. if ($verbose_level && $header_copies) {
  1003. my $new_header_dirname = dirname($iheader);
  1004. basePrettify(\$new_header_dirname) if ($new_header_dirname && $verbose_level < 2);
  1005. my $header_base = basename($iheader);
  1006. if ($verbose_level < 3) {
  1007. my $line_prefix = ",";
  1008. if ($new_header_dirname ne $header_dirname) {
  1009. $line_prefix = "$lib: created fwd-include header(s) for $new_header_dirname/ {";
  1010. $line_prefix = " }\n".$line_prefix if ($header_dirname);
  1011. $header_dirname = $new_header_dirname;
  1012. } else {
  1013. $line_prefix = ",";
  1014. }
  1015. print "$line_prefix $header_base ($header_copies)";
  1016. } else { # $verbose_level >= 3
  1017. basePrettify(\$iheader) if ($verbose_level == 3);
  1018. print "$lib: created $header_copies fwd-include headers for $iheader\n";
  1019. }
  1020. }
  1021. }
  1022. }
  1023. print " }\n" if ($header_dirname && $verbose_level > 0 && $verbose_level < 3);
  1024. }
  1025. }
  1026. }
  1027. # close the master include:
  1028. $master_contents .=
  1029. "#include \"".lc($lib)."version.h\"\n" .
  1030. "#endif\n";
  1031. unless ($showonly || $minimal || !$is_qt) {
  1032. # create deprecated headers
  1033. my $first = 1;
  1034. while (my ($header, $include) = each %{$deprecatedheaders{$lib}}) {
  1035. my $public_header = 0;
  1036. $public_header = 1 unless ($allheadersprivate || ($header =~ /_p\.h$/));
  1037. next unless ($public_header || $create_private_headers);
  1038. my $header_path = "$out_basedir/include/$lib/";
  1039. unless ($public_header) {
  1040. $header_path .= "$module_version/$lib/private/";
  1041. }
  1042. $header_path .= "$header";
  1043. unless (-e $header_path) {
  1044. my $guard = "DEPRECATED_HEADER_" . $lib . "_" . $header;
  1045. $guard =~ s/([^a-zA-Z0-9_])/_/g;
  1046. my $header_dir = dirname($header_path);
  1047. make_path($header_dir, $lib, $verbose_level);
  1048. my $hdrcont =
  1049. "#ifndef $guard\n" .
  1050. "#define $guard\n";
  1051. my $warning = "Header <$lib/";
  1052. $warning .= "private/" unless ($public_header);
  1053. $warning .= "$header> is deprecated. Please include <$include> instead.";
  1054. $hdrcont .=
  1055. "#if defined(__GNUC__)\n" .
  1056. "# warning $warning\n" .
  1057. "#elif defined(_MSC_VER)\n" .
  1058. "# pragma message (\"$warning\")\n" .
  1059. "#endif\n" .
  1060. "#include <$include>\n";
  1061. if ($public_header) {
  1062. $hdrcont .=
  1063. "#if 0\n" .
  1064. "#pragma qt_no_master_include\n" .
  1065. "#endif\n";
  1066. }
  1067. $hdrcont .=
  1068. "#endif\n";
  1069. if (writeFile($header_path, $hdrcont)) {
  1070. if ($verbose_level < 3) {
  1071. my $line_prefix = ",";
  1072. $line_prefix = "$lib: created deprecated header(s) {" if ($first);
  1073. print "$line_prefix $header";
  1074. } else {
  1075. print "$lib: created deprecated header $header => $include\n";
  1076. }
  1077. $first = 0;
  1078. }
  1079. }
  1080. my $addendum = fixPaths($header_path, $dir) . " ";
  1081. if ($public_header) {
  1082. $pri_install_files .= $addendum;
  1083. } else {
  1084. $pri_install_pfiles .= $addendum;
  1085. }
  1086. }
  1087. if ($verbose_level < 3) {
  1088. print " }\n" unless ($first);
  1089. }
  1090. # module version header
  1091. my $vheader = "$out_basedir/include/$lib/".lc($lib)."version.h";
  1092. my $VHeader = "$out_basedir/include/$lib/${lib}Version";
  1093. syncHeader($lib, $VHeader, $vheader, 0);
  1094. $pri_install_files .= fixPaths($vheader, $dir) . " ";
  1095. $pri_install_classes .= fixPaths($VHeader, $dir) . " ";
  1096. my @versions = split(/\./, $module_version);
  1097. my $modulehexstring = sprintf("0x%02X%02X%02X", $versions[0], $versions[1], $versions[2]);
  1098. my $vhdrcont =
  1099. "/* This file was generated by syncqt. */\n".
  1100. "#ifndef QT_".uc($lib)."_VERSION_H\n".
  1101. "#define QT_".uc($lib)."_VERSION_H\n".
  1102. "\n".
  1103. "#define ".uc($lib)."_VERSION_STR \"".$module_version."\"\n".
  1104. "\n".
  1105. "#define ".uc($lib)."_VERSION ".$modulehexstring."\n".
  1106. "\n".
  1107. "#endif // QT_".uc($lib)."_VERSION_H\n";
  1108. writeFile($vheader, $vhdrcont, $lib, "version header");
  1109. my $master_include = "$out_basedir/include/$lib/$lib";
  1110. $pri_install_files .= fixPaths($master_include, $dir) . " ";
  1111. writeFile($master_include, $master_contents, $lib, "master header");
  1112. }
  1113. unless ($showonly || $minimal) {
  1114. #handle the headers.pri for each module
  1115. my $headers_pri_contents = "";
  1116. $headers_pri_contents .= "SYNCQT.HEADER_FILES = $pri_install_files\n";
  1117. $headers_pri_contents .= "SYNCQT.HEADER_CLASSES = $pri_install_classes\n";
  1118. $headers_pri_contents .= "SYNCQT.PRIVATE_HEADER_FILES = $pri_install_pfiles\n";
  1119. $headers_pri_contents .= "SYNCQT.QPA_HEADER_FILES = $pri_install_qpafiles\n";
  1120. $headers_pri_contents .= "SYNCQT.CLEAN_HEADER_FILES = $pri_clean_files\n";
  1121. $headers_pri_contents .= "SYNCQT.INJECTIONS = $pri_injections\n";
  1122. my $headers_pri_file = "$out_basedir/include/$lib/headers.pri";
  1123. writeFile($headers_pri_file, $headers_pri_contents, $lib, "headers.pri file");
  1124. }
  1125. }
  1126. exit 0;