PageRenderTime 58ms CodeModel.GetById 5ms RepoModel.GetById 0ms app.codeStats 1ms

/cons-2.2.0/cons

https://github.com/gitpan/AutoCons
Perl | 5713 lines | 4417 code | 731 blank | 565 comment | 523 complexity | 9fa817b66048fefa015c1b0d9428ea10 MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. #!/usr/bin/env perl
  2. # NOTE: Cons intentionally does not use the "perl -w" option or
  3. # "use strict." Because Cons "configuration files" are actually
  4. # Perl scripts, enabling those restrictions here would force them
  5. # on every user's config files, wanted or not. Would users write
  6. # "better" Construct and Conscript files if we forced "use strict"
  7. # on them? Probably. But we want people to use Cons to get work
  8. # done, not force everyone to become a Perl guru to use it, so we
  9. # don't insist.
  10. #
  11. # That said, Cons' code is both "perl -w" and "use strict" clean.
  12. # Regression tests keep the code honest by checking for warnings
  13. # and "use strict" failures.
  14. # $Id: cons.pl,v 1.129 2000/11/16 12:22:37 knight Exp $
  15. use vars qw( $ver_num $ver_rev $version );
  16. $ver_num = "2.2";
  17. $ver_rev = ".0";
  18. $version = sprintf "This is Cons %s%s " .
  19. '($Id: cons.pl,v 1.129 2000/11/16 12:22:37 knight Exp $)'. "\n",
  20. $ver_num, $ver_rev;
  21. # Cons: A Software Construction Tool.
  22. # Copyright (c) 1996-2000 Free Software Foundation, Inc.
  23. #
  24. # This program is free software; you can redistribute it and/or modify
  25. # it under the terms of the GNU General Public License as published by
  26. # the Free Software Foundation; either version 2 of the License, or
  27. # (at your option) any later version.
  28. #
  29. # This program is distributed in the hope that it will be useful,
  30. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  31. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  32. # GNU General Public License for more details.
  33. #
  34. # You should have received a copy of the GNU General Public License
  35. # along with this program; see the file COPYING. If not, write to
  36. # the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  37. # Boston, MA 02111-1307, USA.
  38. require 5.002;
  39. # See the NOTE above about why Cons doesn't "use strict".
  40. use integer;
  41. use Cwd;
  42. use File::Copy;
  43. use vars qw( $_WIN32 $_a $_exe $_o $_so );
  44. #------------------------------------------------------------------
  45. # Determine if running on win32 platform - either Windows NT or 95
  46. #------------------------------------------------------------------
  47. use vars qw( $PATH_SEPARATOR $iswin32 $_WIN32 $usage $indent @targets );
  48. BEGIN {
  49. use Config;
  50. # if the version is 5.003, we can check $^O
  51. if ($] < 5.003) {
  52. eval("require Win32");
  53. $_WIN32 = (!$@);
  54. } else {
  55. $_WIN32 = ($^O eq "MSWin32") ? 1 : 0;
  56. }
  57. # Fetch the PATH separator from Config;
  58. # provide our old defaults in case it's not set.
  59. $PATH_SEPARATOR = $Config{path_sep};
  60. $PATH_SEPARATOR = $_WIN32 ? ';' : ':' if ! defined $PATH_SEPARATOR;
  61. # Fetch file suffixes from Config,
  62. # accomodating differences in the Config variables
  63. # used by different Perl versions.
  64. $_exe = $Config{_exe};
  65. $_exe = $Config{exe_ext} if ! defined $_exe;
  66. $_exe = $_WIN32 ? '.exe' : '' if ! defined $_exe;
  67. $_o = $Config{_o};
  68. $_o = $Config{obj_ext} if ! defined $_o;
  69. $_o = $_WIN32 ? '.obj' : '.o' if ! defined $_o;
  70. $_a = $Config{_a};
  71. $_a = $Config{lib_ext} if ! defined $_a;
  72. $_a = $_WIN32 ? '.lib' : '.a' if ! defined $_a;
  73. $_so = ".$Config{so}";
  74. $_so = $_WIN32 ? '.dll' : '.so' if ! defined $_so;
  75. }
  76. # Flush stdout each time.
  77. $| = 1;
  78. # Seed random number generator.
  79. srand(time . $$); # this works better than time ^ $$ in perlfunc manpage.
  80. $usage = q(
  81. Usage: cons <arguments> -- <construct-args>
  82. Arguments can be any of the following, in any order:
  83. <targets> Build the specified targets. If <target> is a directory
  84. recursively build everything within that directory.
  85. +<pattern> Limit the cons scripts considered to just those that
  86. match <pattern>. Multiple + arguments are accepted.
  87. <name>=<val> Sets <name> to value <val> in the ARG hash passed to the
  88. top-level Construct file.
  89. -cc Show command that would have been executed, when
  90. retrieving from cache. No indication that the file
  91. has been retrieved is given; this is useful for
  92. generating build logs that can be compared with
  93. real build logs.
  94. -cd Disable all caching. Do not retrieve from cache nor
  95. flush to cache.
  96. -cr Build dependencies in random order. This is useful when
  97. building multiple similar trees with caching enabled.
  98. -cs Synchronize existing build targets that are found to be
  99. up-to-date with cache. This is useful if caching has
  100. been disabled with -cc or just recently enabled with
  101. UseCache.
  102. -d Enable dependency debugging.
  103. -f <file> Use the specified file instead of "Construct" (but first
  104. change to containing directory of <file>).
  105. -h Show a help message local to the current build if
  106. one such is defined, and exit.
  107. -k Keep going as far as possible after errors.
  108. -o <file> Read override file <file>.
  109. -p Show construction products in specified trees.
  110. -pa Show construction products and associated actions.
  111. -pw Show products and where they are defined.
  112. -q Be quiet about Installing and Removing targets.
  113. -r Remove construction products associated with <targets>
  114. -R <repos> Search for files in <repos>. Multiple -R <repos>
  115. directories are searched in the order specified.
  116. -t Traverse up the directory hierarchy looking for a
  117. Construct file, if none exists in the current directory.
  118. (Targets will be modified to be relative to the
  119. Construct file.)
  120. -v Show cons version and continue processing.
  121. -V Show cons version and exit.
  122. -wf <file> Write all filenames considered into <file>.
  123. -x Show this message and exit.
  124. Please report any suggestions through the cons-discuss@gnu.org mailing
  125. list.
  126. To subscribe, send mail to cons-discuss-request@gnu.org with body
  127. 'subscribe'.
  128. If you find a bug, please report it through the bug-cons@gnu.org
  129. mailing list.
  130. Information about CONS can be obtained from the official cons web site
  131. http://www.dsmit.com/cons/ or its mirrors (listed there).
  132. The cons maintainers can be contacted by email at cons-maintainers@gnu.org
  133. User documentation of cons is contained in cons and can be obtained
  134. by doing 'perldoc /path/to/cons'.
  135. );
  136. # Simplify program name, if it is a path.
  137. {
  138. my ($vol, $dir, $file) = File::Spec->splitpath(File::Spec->canonpath($0));
  139. $0 = $file;
  140. }
  141. # Default parameters.
  142. $param::topfile = 'Construct'; # Top-level construction file.
  143. $param::install = 1; # Show installations
  144. $param::build = 1; # Build targets
  145. ### $param::show = 1; # Show building of targets.
  146. $param::sigpro = 'md5'; # Signature protocol.
  147. $param::depfile = ''; # Write all deps out to this file
  148. $param::salt = ''; # Salt derived file signatures with this.
  149. $param::rep_sig_times_ok = 1; # Repository .consign times are in sync
  150. # w/files.
  151. $param::conscript_chdir = 0; # Change dir to Conscript directory
  152. $param::quiet = 0; # should we show the command being executed.
  153. #
  154. $indent = '';
  155. # Display a command while executing or otherwise. This
  156. # should be called by command builder action methods.
  157. sub showcom {
  158. print($indent . $_[0] . "\n");
  159. }
  160. # Default environment.
  161. # This contains only the completely platform-independent information
  162. # we can figure out. Platform-specific information (UNIX, Win32)
  163. # gets added below.
  164. @param::defaults = (
  165. 'SUFEXE' => $_exe, # '' on UNIX systems
  166. 'SUFLIB' => $_a, # '.a' on UNIX systems
  167. 'SUFLIBS' => "$_so:$_a", # '.so:.a' on UNIX
  168. 'SUFOBJ' => $_o, # '.o' on UNIX systems
  169. 'SUFMAP' => {
  170. '.c' => 'build::command::cc',
  171. '.s' => 'build::command::cc',
  172. '.S' => 'build::command::cc',
  173. '.C' => 'build::command::cxx',
  174. '.cc' => 'build::command::cxx',
  175. '.cxx'=> 'build::command::cxx',
  176. '.cpp'=> 'build::command::cxx',
  177. '.c++'=> 'build::command::cxx',
  178. '.C++'=> 'build::command::cxx',
  179. },
  180. );
  181. if ($_WIN32) {
  182. # Defaults for Win32.
  183. # Defined for VC++ 6.0 by Greg Spencer <greg_spencer@acm.org>.
  184. # Your mileage may vary.
  185. my @win = (
  186. 'CC' => 'cl',
  187. 'CFLAGS' => '/nologo',
  188. 'CCCOM' => '%CC %CFLAGS %_IFLAGS /c %< /Fo%>',
  189. 'CXX' => '%CC',
  190. 'CXXFLAGS' => '%CFLAGS',
  191. 'CXXCOM' => '%CXX %CXXFLAGS %_IFLAGS /c %< /Fo%>',
  192. 'INCDIRPREFIX' => '/I',
  193. 'LINK' => 'link',
  194. 'LINKCOM' => '%LINK %LDFLAGS /out:%> %< %_LDIRS %LIBS',
  195. 'LINKMODULECOM' => '%LD /r /o %> %<',
  196. 'LIBDIRPREFIX' => '/LIBPATH:',
  197. 'AR' => 'lib',
  198. 'ARFLAGS' => '/nologo ',
  199. 'ARCOM' => "%AR %ARFLAGS /out:%> %<",
  200. 'RANLIB' => '',
  201. 'LD' => 'link',
  202. 'LDFLAGS' => '/nologo ',
  203. 'PREFLIB' => '',
  204. );
  205. push(@param::defaults, @win);
  206. } else {
  207. # Defaults for a typical (?) UNIX platform.
  208. # Your mileage may vary.
  209. my @unix = (
  210. 'CC' => 'cc',
  211. 'CFLAGS' => '',
  212. 'CCCOM' => '%CC %CFLAGS %_IFLAGS -c %< -o %>',
  213. 'CXX' => '%CC',
  214. 'CXXFLAGS' => '%CFLAGS',
  215. 'CXXCOM' => '%CXX %CXXFLAGS %_IFLAGS -c %< -o %>',
  216. 'INCDIRPREFIX' => '-I',
  217. 'LINK' => '%CXX',
  218. 'LINKCOM' => '%LINK %LDFLAGS -o %> %< %_LDIRS %LIBS',
  219. 'LINKMODULECOM' => '%LD -r -o %> %<',
  220. 'LIBDIRPREFIX' => '-L',
  221. 'AR' => 'ar',
  222. 'ARFLAGS' => 'r', # rs?
  223. 'ARCOM' => "%AR %ARFLAGS %> %<\n%RANLIB %>",
  224. 'RANLIB' => 'ranlib',
  225. 'AS' => 'as',
  226. 'ASFLAGS' => '',
  227. 'ASCOM' => '%AS %ASFLAGS %< -o %>',
  228. 'LD' => 'ld',
  229. 'LDFLAGS' => '',
  230. 'PREFLIB' => 'lib',
  231. 'ENV' => { 'PATH' => '/bin:/usr/bin' },
  232. );
  233. push(@param::defaults, @unix);
  234. }
  235. # Handle command line arguments.
  236. while (@ARGV) {
  237. $_ = shift @ARGV;
  238. last if /^--$/; # Argument passing to Construct.
  239. &option, next if s/^-//;
  240. push (@param::include, $_), next if s/^\+//;
  241. &equate, next if /=/;
  242. push (@targets, $_), next;
  243. }
  244. sub option {
  245. my %opt = (
  246. 'cc' => sub { $param::cachecom = 1; },
  247. 'cd' => sub { $param::cachedisable = 1; },
  248. 'cr' => sub { $param::random = 1; },
  249. 'cs' => sub { $param::cachesync = 1; },
  250. 'd' => sub { $param::depends = 1; },
  251. 'h' => sub { $param::localhelp = 1; },
  252. 'k' => sub { $param::kflag = 1; },
  253. 'p' => sub { $param::pflag = 1;
  254. $param::build = 0; },
  255. 'pa' => sub { $param::pflag = 1;
  256. $param::aflag = 1;
  257. $indent = "... ";
  258. $param::build = 0; },
  259. 'pw' => sub { $param::pflag = 1;
  260. $param::wflag = 1;
  261. $param::build = 0; },
  262. 'q' => sub { $param::quiet = 1; },
  263. 'r' => sub { $param::rflag = 1;
  264. $param::build = 0; },
  265. 't' => sub { $param::traverse = 1; },
  266. 'v' => sub { print($version); },
  267. 'V' => sub { print($version), exit(0); },
  268. 'x' => sub { print($usage), exit 0; },
  269. );
  270. my %opt_arg = (
  271. 'f' => sub { $param::topfile = $_[0]; },
  272. 'o' => sub { $param::overfile = $_[0]; },
  273. 'R' => sub { script::Repository($_[0]); },
  274. 'wf' => sub { $param::depfile = $_[0]; },
  275. );
  276. if (defined $opt{$_}) {
  277. &{$opt{$_}}();
  278. return;
  279. }
  280. $_ =~ m/(.)(.*)/;
  281. if (defined $opt_arg{$1}) {
  282. if (! $2) {
  283. $_ = shift @ARGV;
  284. die("$0: -$1 option requires an argument.\n") if ! $_;
  285. }
  286. &{$opt_arg{$1}}($2 || $_);
  287. return;
  288. }
  289. $_ =~ m/(..)(.*)/;
  290. if (defined $opt_arg{$1}) {
  291. if (! $2) {
  292. $_ = shift @ARGV;
  293. die("$0: -$1 option requires an argument.\n") if ! $_;
  294. }
  295. &{$opt_arg{$1}}($2 || $_);
  296. return;
  297. }
  298. if ($_) {
  299. die qq($0: unrecognized option "-$_". Use -x for a usage message.\n);
  300. }
  301. }
  302. # Process an equate argument (var=val).
  303. sub equate {
  304. my($var, $val) = /([^=]*)=(.*)/;
  305. $script::ARG{$var} = $val;
  306. }
  307. # Define file signature protocol.
  308. 'sig'->select($param::sigpro);
  309. # Cleanup after an interrupt.
  310. $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = sub {
  311. $SIG{PIPE} = $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = 'IGNORE';
  312. $SIG{HUP} = $SIG{INT} if ! $main::_WIN32;
  313. warn("\n$0: killed\n");
  314. # Call this first, to make sure that this processing
  315. # occurs even if a child process does not die (and we
  316. # hang on the wait).
  317. sig::hash::END();
  318. wait();
  319. exit(1);
  320. };
  321. $SIG{HUP} = $SIG{INT} if ! $main::_WIN32;
  322. # Cleanup after a broken pipe (someone piped our stdout?)
  323. $SIG{PIPE} = sub {
  324. $SIG{PIPE} = $SIG{HUP} = $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = 'IGNORE';
  325. warn("\n$0: broken pipe\n");
  326. sig::hash::END();
  327. wait();
  328. exit(1);
  329. };
  330. if ($param::depfile) {
  331. open (main::DEPFILE, ">".$param::depfile) ||
  332. die ("$0: couldn't open $param::depfile ($!)\n");
  333. }
  334. # If the supplied top-level Conscript file is not in the
  335. # current directory, then change to that directory.
  336. {
  337. my ($vol, $dir, $file) = File::Spec->splitpath(File::Spec->canonpath($param::topfile));
  338. if ($vol || $dir) {
  339. my($cd) = File::Spec->catpath($vol, $dir, undef);
  340. chdir($cd) || die("$0: couldn't change to directory $cd ($!)\n");
  341. $param::topfile = $file;
  342. }
  343. }
  344. # Walk up the directory hierarchy looking for a Conscript file (if -t set).
  345. my($target_top);
  346. my(@targetdir) = ();
  347. if ($param::traverse && ! -f $param::topfile) {
  348. my($vol, $dirs, $file) = File::Spec->splitpath(cwd());
  349. my(@dirs) = (File::Spec->splitdir($dirs), $file);
  350. while (! -f File::Spec->catpath($vol, File::Spec->catdir(@dirs), $param::topfile)) {
  351. die("$0: unable to find $param::topfile.\n") if ! @dirs;
  352. unshift(@targetdir, pop(@dirs));
  353. }
  354. my($cwd) = File::Spec->catpath($vol, File::Spec->catdir(@dirs), '');
  355. print "$0: Entering directory `$cwd'\n";
  356. chdir($cwd);
  357. @targets = map {File::Spec->catdir(@targetdir, $_)} @targets;
  358. }
  359. # Set up $dir::top and $dir::cwd, now that we are in the right directory.
  360. dir::init();
  361. #
  362. if (@targetdir) {
  363. $target_top = $dir::top->lookupdir(File::Spec->catdir(@targetdir));
  364. }
  365. # Now handle override file.
  366. package override;
  367. if ($param::overfile) {
  368. my($ov) = $param::overfile;
  369. die qq($0: can\'t read override file "$ov" ($!)\n) if ! -f $ov; #'
  370. do $ov;
  371. if ($@) {
  372. chop($@);
  373. die qq($0: errors in override file "$ov" ($@)\n);
  374. }
  375. }
  376. # Provide this to user to setup override patterns.
  377. sub Override {
  378. my($re, @env) = @_;
  379. return if $param::overrides{$re}; # if identical, first will win.
  380. $param::overrides = 1;
  381. $param::overrides{$re} = \@env;
  382. push(@param::overrides, $re);
  383. }
  384. package main;
  385. use vars qw( %priority $errors );
  386. # Check script inclusion regexps
  387. my $re;
  388. for $re (@param::include) {
  389. if (! defined eval {"" =~ /$re/}) {
  390. my($err) = $@;
  391. $err =~ s/in regexp at .*$//;
  392. die("$0: error in regexp $err");
  393. }
  394. }
  395. # Read the top-level construct file and its included scripts.
  396. doscripts($param::topfile);
  397. # Status priorities. This lets us aggregate status for directories
  398. # and print an appropriate message (at the top-level).
  399. %priority =
  400. ('none' => 1, 'handled' => 2, 'built' => 3, 'unknown' => 4, 'errors' => 5);
  401. # If no targets were specified, supply default targets (if any).
  402. @targets = @param::default_targets if ! @targets;
  403. $errors = 0;
  404. # Build the supplied target patterns.
  405. my $tgt;
  406. for $tgt (map($dir::top->lookup($_), @targets)) {
  407. if ($target_top && ! $tgt->is_under($target_top)) {
  408. # A -t option was used, and this target is not underneath
  409. # the directory where we were invoked via -t.
  410. # If the target is a directory and the -t directory
  411. # is underneath it, then build the -t directory.
  412. if (ref $tgt ne "dir" || ! $target_top->is_under($tgt)) {
  413. next;
  414. }
  415. $tgt = $target_top;
  416. }
  417. buildtoptarget($tgt);
  418. }
  419. exit 0 + ($errors != 0);
  420. sub buildtoptarget {
  421. my($tgt) = @_;
  422. return if ! $tgt;
  423. my($status) = buildtarget($tgt);
  424. if ($status ne 'built') {
  425. my($path) = $tgt->path;
  426. if ($status eq "errors") {
  427. print qq($0: "$path" not remade because of errors.\n);
  428. $errors++;
  429. } elsif ($status eq "handled") {
  430. print qq($0: "$path" is up-to-date.\n);
  431. } elsif ($status eq "unknown") {
  432. # cons error already reported.
  433. $errors++;
  434. } elsif ($status eq "none") {
  435. # search for targets that may be linked to the given path.
  436. my @linked = dir::linked_targets($tgt) if $target_top;
  437. if (@linked) {
  438. my @names = map($_->path, @linked);
  439. print "Linked targets: @names\n" unless ($param::quiet);
  440. map(buildtoptarget($_), @linked);
  441. } else {
  442. print qq($0: nothing to be built in "$path".\n) if $param::build;
  443. }
  444. } else {
  445. print qq($0: don\'t know how to construct "$path".\n); #'
  446. $errors++;
  447. }
  448. }
  449. }
  450. # Build the supplied target directory or files. Return aggregated status.
  451. sub buildtarget {
  452. my($tgt) = @_;
  453. if (ref($tgt) eq "dir") {
  454. my($result) = "none";
  455. my($priority) = $priority{$result};
  456. if (exists $tgt->{member}) {
  457. my($members) = $tgt->{member};
  458. my $entry;
  459. for $entry (sort keys %$members) {
  460. next if $entry eq $dir::CURDIR || $entry eq $dir::UPDIR;
  461. my($tgt) = $members->{$entry};
  462. next if ref($tgt) ne "dir" && !exists($tgt->{builder});
  463. my($stat) = buildtarget($members->{$entry});
  464. my($pri) = $priority{$stat};
  465. if ($pri > $priority) {
  466. $priority = $pri;
  467. $result = $stat;
  468. }
  469. }
  470. }
  471. return $result;
  472. }
  473. if ($param::depends) {
  474. my($path) = $tgt->path;
  475. if ($tgt->{builder}) {
  476. my(@dep) = (@{$tgt->{dep}}, @{$tgt->{sources}});
  477. my($dep) = join(' ',map($_->path, @dep));
  478. print("Target $path: $dep\n");
  479. } else {
  480. print("Target $path: not a derived file\n");
  481. }
  482. }
  483. if ($param::build) {
  484. return build $tgt;
  485. } elsif ($param::pflag || $param::wflag || $param::aflag) {
  486. if ($tgt->{builder}) {
  487. if ($param::wflag) {
  488. print qq(${\$tgt->path}: $tgt->{script}\n);
  489. } elsif ($param::pflag) {
  490. print qq(${\$tgt->path}:\n) if $param::aflag;
  491. print qq(${\$tgt->path}\n) if !$param::aflag;
  492. }
  493. if ($param::aflag) {
  494. $tgt->{builder}->action($tgt);
  495. }
  496. }
  497. } elsif ($param::rflag && $tgt->{builder}) {
  498. my($path) = $tgt->path;
  499. if (-f $path) {
  500. if (unlink($path)) {
  501. print("Removed $path\n") unless ($param::quiet);
  502. } else {
  503. warn("$0: couldn't remove $path\n");
  504. }
  505. }
  506. }
  507. return "none";
  508. }
  509. package NameSpace;
  510. # Return a hash that maps the name of symbols in a namespace to an
  511. # array of refs for all types for which the name has a defined value.
  512. # A list of symbols may be specified; default is all symbols in the
  513. # name space.
  514. sub save {
  515. my $package = shift;
  516. my(%namerefs, $var, $type);
  517. no strict 'refs';
  518. @_ = keys %{$package."::"} if ! @_;
  519. foreach $var (@_) {
  520. $namerefs{$var} = [];
  521. my $fqvar = $package."::".$var;
  522. # If the scalar for this variable name doesn't already
  523. # exist, *foo{SCALAR} will autovivify the reference
  524. # instead of returning undef, so unlike the other types,
  525. # we have to dereference to find out if it exists.
  526. push(@{$namerefs{$var}}, *{$fqvar}{SCALAR})
  527. if defined ${*{$fqvar}{SCALAR}};
  528. foreach $type (qw(ARRAY HASH CODE IO)) {
  529. push(@{$namerefs{$var}}, *{$fqvar}{$type})
  530. if defined *{$fqvar}{$type};
  531. }
  532. }
  533. return \%namerefs;
  534. }
  535. # Remove the specified symbols from the namespace.
  536. # Default is to remove all.
  537. sub remove {
  538. my $package = shift;
  539. my(%namerefs, $var);
  540. no strict 'refs';
  541. @_ = keys %{$package."::"} if ! @_;
  542. foreach $var (@_) {
  543. delete ${$package."::"}{$var};
  544. }
  545. }
  546. # Restore values to symbols specified in a hash as returned
  547. # by NameSpace::save.
  548. sub restore {
  549. my($package, $namerefs) = @_;
  550. my($var, $ref);
  551. no strict 'refs';
  552. foreach $var (keys %$namerefs) {
  553. my $fqvar = $package."::".$var;
  554. foreach $ref (@{$namerefs->{$var}}) {
  555. *{$fqvar} = $ref;
  556. }
  557. }
  558. }
  559. # Support for "building" scripts, importing and exporting variables.
  560. # With the exception of the top-level routine here (invoked from the
  561. # main package by cons), these are all invoked by user scripts.
  562. package script;
  563. use vars qw( $ARG $caller_dir_path %special_var );
  564. BEGIN {
  565. # We can't Export or Import the following variables because Perl always
  566. # treats them as part of the "main::" package (see perlvar(1)).
  567. %special_var = map {$_ => 1} qw(ENV INC ARGV ARGVOUT SIG
  568. STDIN STDOUT STDERR);
  569. }
  570. # This is called from main to interpret/run the top-level Construct
  571. # file, passed in as the single argument.
  572. sub main::doscripts {
  573. my($script) = @_;
  574. Build($script);
  575. # Now set up the includes/excludes (after the Construct file is read).
  576. $param::include = join('|', @param::include);
  577. # Save the original variable names from the script package.
  578. # These will stay intact, but any other "script::" variables
  579. # defined in a Conscript file will get saved, deleted,
  580. # and (when necessary) restored.
  581. my(%orig_script_var) = map {$_ => 1} keys %script::;
  582. $caller_dir_path = undef;
  583. my $cwd = Cwd::cwd();
  584. my(@scripts) = pop(@priv::scripts);
  585. while ($priv::self = shift(@scripts)) {
  586. my($path) = $priv::self->{script}->rsrcpath;
  587. if (-f $path) {
  588. $dir::cwd = $priv::self->{script}->{dir};
  589. # Handle chdir to the Conscript file directory, if necessary.
  590. my ($vol, $dir, $file);
  591. if ($param::conscript_chdir) {
  592. ($vol, $dir, $file) = File::Spec->splitpath(File::Spec->canonpath($path));
  593. if ($vol ne '' || $dir ne '') {
  594. $caller_dir_path = File::Spec->catpath($vol, $dir, undef);
  595. chdir($caller_dir_path) ||
  596. die "Could not chdir to $caller_dir_path: $!\n";
  597. }
  598. } else {
  599. $file = $path;
  600. }
  601. # Actually process the Conscript file.
  602. do $file;
  603. # Save any variables defined by the Conscript file
  604. # so we can restore them later, if needed;
  605. # then delete them from the script:: namespace.
  606. my(@del) = grep(! $orig_script_var{$_}, keys %script::);
  607. if (@del) {
  608. $priv::self->{script}->{pkgvars} =
  609. NameSpace::save('script', @del);
  610. NameSpace::remove('script', @del);
  611. }
  612. if ($caller_dir_path) {
  613. chdir($cwd);
  614. $caller_dir_path = undef;
  615. }
  616. if ($@) {
  617. chomp($@);
  618. my $err = ($@ =~ /\n/ms) ? ":\n$@" : " ($@)";
  619. print qq($0: error in file "$path"$err\n);
  620. $run::errors++;
  621. } else {
  622. # Only process subsidiary scripts if no errors in parent.
  623. unshift(@scripts, @priv::scripts);
  624. }
  625. undef @priv::scripts;
  626. } else {
  627. my $where = '';
  628. my $cref = $priv::self->{script}->creator;
  629. if (defined $cref) {
  630. my($_foo, $script, $line, $sub) = @$cref;
  631. $where = " ($sub in $script, line $line)";
  632. }
  633. warn qq(Ignoring missing script "$path"$where);
  634. }
  635. }
  636. die("$0: script errors encountered: construction aborted\n")
  637. if $run::errors;
  638. }
  639. # Return caller info about the method being invoked.
  640. # This is everything from the Perl "caller" builtin function,
  641. # including which Construct/Conscript file, line number,
  642. # subroutine name, etc.
  643. sub caller_info {
  644. my($lev) = 1;
  645. my(@frame);
  646. do {
  647. @frame = caller ++$lev;
  648. if (defined($frame[3]) && $frame[3] eq '(eval)') {
  649. @frame = caller --$lev;
  650. if ($caller_dir_path) {
  651. $frame[1] = File::Spec->catfile($caller_dir_path, $frame[1]);
  652. }
  653. return @frame;
  654. }
  655. } while ($frame[3]);
  656. return;
  657. }
  658. # Link a directory to another. This simply means set up the *source*
  659. # for the directory to be the other directory.
  660. sub Link {
  661. dir::link(@_);
  662. }
  663. # Add directories to the repository search path for files.
  664. # We're careful about stripping our current directory from
  665. # the list, which we do by comparing the `pwd` results from
  666. # the current directory and the specified directory. This
  667. # is cumbersome, but assures that the paths will be reported
  668. # the same regardless of symbolic links.
  669. sub Repository {
  670. my($my_dir) = Cwd::cwd();
  671. my $dir;
  672. foreach $dir (@_) {
  673. my($d) = `$^X -e "use Cwd; chdir('$dir') && print cwd"`;
  674. next if ! $d || ! -d $d || $d eq $my_dir;
  675. # We know we can get away with passing undef to lookupdir
  676. # as the directory because $dir is an absolute path.
  677. push(@param::rpath, dir::lookupdir(undef, $dir));
  678. push @INC, $d;
  679. }
  680. }
  681. # Return the list of Repository directories specified.
  682. sub Repository_List {
  683. map($_->path, @param::rpath);
  684. }
  685. # Specify whether the .consign signature times in repository files are,
  686. # in fact, consistent with the times on the files themselves.
  687. sub Repository_Sig_Times_OK {
  688. $param::rep_sig_times_ok = shift;
  689. }
  690. # Specify whether we should chdir to the containing directories
  691. # of Conscript files.
  692. sub Conscript_chdir {
  693. $param::conscript_chdir = shift;
  694. }
  695. # Specify files/targets that must be present and built locally,
  696. # even if they exist already-built in a Repository.
  697. sub Local {
  698. my(@files) = map($dir::cwd->lookupfile($_), @_);
  699. map($_->local(1), @files);
  700. }
  701. # Export variables to any scripts invoked from this one.
  702. sub Export {
  703. my(@illegal) = grep($special_var{$_}, @_);
  704. if (@illegal) {
  705. die qq($0: cannot Export special Perl variables: @illegal\n);
  706. }
  707. @{$priv::self->{exports}} = grep(! defined $special_var{$_}, @_);
  708. }
  709. # Import variables from the export list of the caller
  710. # of the current script.
  711. sub Import {
  712. my(@illegal) = grep($special_var{$_}, @_);
  713. if (@illegal) {
  714. die qq($0: cannot Import special Perl variables: @illegal\n");
  715. }
  716. my($parent) = $priv::self->{parent};
  717. my($imports) = $priv::self->{imports};
  718. @{$priv::self->{exports}} = keys %$imports;
  719. my($var);
  720. foreach $var (grep(! defined $special_var{$_}, @_)) {
  721. if (!exists $imports->{$var}) {
  722. my($path) = $parent->{script}->path;
  723. die qq($0: variable "$var" not exported by file "$path"\n);
  724. }
  725. if (!defined $imports->{$var}) {
  726. my $path = $parent->{script}->path;
  727. my $err = "$0: variable \"$var\" exported but not " .
  728. "defined by file \"$path\"\n";
  729. die $err;
  730. }
  731. ${"script::$var"} = $imports->{$var};
  732. }
  733. }
  734. # Build an inferior script. That is, arrange to read and execute
  735. # the specified script, passing to it any exported variables from
  736. # the current script.
  737. sub Build {
  738. my(@files) = map($dir::cwd->lookupfile($_), @_);
  739. my(%imports) = map {$_ => ${"script::$_"}} @{$priv::self->{exports}};
  740. my $file;
  741. for $file (@files) {
  742. next if $param::include && $file->path !~ /$param::include/o;
  743. my($self) = {'script' => $file,
  744. 'parent' => $priv::self,
  745. 'imports' => \%imports};
  746. bless $self; # may want to bless into class of parent in future
  747. push(@priv::scripts, $self);
  748. }
  749. }
  750. # Set up regexps dependencies to ignore. Should only be called once.
  751. sub Ignore {
  752. die("Ignore called more than once\n") if $param::ignore;
  753. $param::ignore = join("|", map("($_)", @_)) if @_;
  754. }
  755. # Specification of default targets.
  756. sub Default {
  757. push(@param::default_targets, map($dir::cwd->lookup($_)->path, @_));
  758. }
  759. # Local Help. Should only be called once.
  760. sub Help {
  761. if ($param::localhelp) {
  762. print "@_\n";
  763. exit 2;
  764. }
  765. }
  766. # Return the build name(s) of a file or file list.
  767. sub FilePath {
  768. wantarray
  769. ? map($dir::cwd->lookupfile($_)->path, @_)
  770. : $dir::cwd->lookupfile($_[0])->path;
  771. }
  772. # Return the build name(s) of a directory or directory list.
  773. sub DirPath {
  774. wantarray
  775. ? map($dir::cwd->lookupdir($_)->path, @_)
  776. : $dir::cwd->lookupdir($_[0])->path;
  777. }
  778. # Split the search path provided into components. Look each up
  779. # relative to the current directory.
  780. # The usual path separator problems abound; for now we'll use :
  781. sub SplitPath {
  782. my($dirs) = @_;
  783. if (ref($dirs) ne "ARRAY") {
  784. $dirs = [ split(/$main::PATH_SEPARATOR/o, $dirs) ];
  785. }
  786. map { DirPath($_) } @$dirs;
  787. }
  788. # Return true if the supplied path is available as a source file
  789. # or is buildable (by rules seen to-date in the build).
  790. sub ConsPath {
  791. my($path) = @_;
  792. my($file) = $dir::cwd->lookup($path);
  793. return $file->accessible;
  794. }
  795. # Return the source path of the supplied path.
  796. sub SourcePath {
  797. wantarray
  798. ? map($dir::cwd->lookupfile($_)->rsrcpath, @_)
  799. : $dir::cwd->lookupfile($_[0])->rsrcpath;
  800. }
  801. # Search up the tree for the specified cache directory, starting with
  802. # the current directory. Returns undef if not found, 1 otherwise.
  803. # If the directory is found, then caching is enabled. The directory
  804. # must be readable and writable. If the argument "mixtargets" is provided,
  805. # then targets may be mixed in the cache (two targets may share the same
  806. # cache file--not recommended).
  807. sub UseCache($@) {
  808. my($dir, @args) = @_;
  809. # NOTE: it's important to process arguments here regardless of whether
  810. # the cache is disabled temporarily, since the mixtargets option affects
  811. # the salt for derived signatures.
  812. for (@args) {
  813. if ($_ eq "mixtargets") {
  814. # When mixtargets is enabled, we salt the target signatures.
  815. # This is done purely to avoid a scenario whereby if
  816. # mixtargets is turned on or off after doing builds, and
  817. # if cache synchronization with -cs is used, then
  818. # cache files may be shared in the cache itself (linked
  819. # under more than one name in the cache). This is not bad,
  820. # per se, but simply would mean that a cache cleaning algorithm
  821. # that looked for a link count of 1 would never find those
  822. # particular files; they would always appear to be in use.
  823. $param::salt = 'M' . $param::salt;
  824. $param::mixtargets = 1;
  825. } else {
  826. die qq($0: UseCache unrecognized option "$_"\n);
  827. }
  828. }
  829. if ($param::cachedisable) {
  830. warn("Note: caching disabled by -cd flag\n");
  831. return 1;
  832. }
  833. my($depth) = 15;
  834. while ($depth-- && ! -d $dir) {
  835. $dir = File::Spec->catdir($dir::UPDIR, $dir);
  836. }
  837. if (-d $dir) {
  838. $param::cache = $dir;
  839. return 1;
  840. }
  841. return undef;
  842. }
  843. # Salt the signature generator. The salt (a number of string) is added
  844. # into the signature of each derived file. Changing the salt will
  845. # force recompilation of all derived files.
  846. sub Salt($) {
  847. # We append the value, so that UseCache and Salt may be used
  848. # in either order without changing the signature calculation.
  849. $param::salt .= $_[0];
  850. }
  851. # Mark files (or directories) to not be removed before building.
  852. sub Precious {
  853. map($_->{precious} = 1, map($dir::cwd->lookup($_), @_));
  854. }
  855. # These methods are callable from Conscript files, via a cons
  856. # object. Procs beginning with _ are intended for internal use.
  857. package cons;
  858. use vars qw( %envcache );
  859. # This is passed the name of the base environment to instantiate.
  860. # Overrides to the base environment may also be passed in
  861. # as key/value pairs.
  862. sub new {
  863. my($package) = shift;
  864. my ($env) = {@param::defaults, @_};
  865. @{$env->{_envcopy}} = %$env; # Note: we never change PATH
  866. $env->{_cwd} = $dir::cwd; # Save directory of environment for
  867. bless $env, $package; # any deferred name interpretation.
  868. }
  869. # Clone an environment.
  870. # Note that the working directory will be the initial directory
  871. # of the original environment.
  872. sub clone {
  873. my($env) = shift;
  874. my $clone = {@{$env->{_envcopy}}, @_};
  875. @{$clone->{_envcopy}} = %$clone; # Note: we never change PATH
  876. $clone->{_cwd} = $env->{_cwd};
  877. bless $clone, ref $env;
  878. }
  879. # Create a flattened hash representing the environment.
  880. # It also contains a copy of the PATH, so that the path
  881. # may be modified if it is converted back to a hash.
  882. sub copy {
  883. my($env) = shift;
  884. (@{$env->{_envcopy}}, 'ENV' => {%{$env->{ENV}}}, @_)
  885. }
  886. # Resolve which environment to actually use for a given
  887. # target. This is just used for simple overrides.
  888. sub _resolve {
  889. return $_[0] if !$param::overrides;
  890. my($env, $tgt) = @_;
  891. my($path) = $tgt->path;
  892. my $re;
  893. for $re (@param::overrides) {
  894. next if $path !~ /$re/;
  895. # Found one. Return a combination of the original environment
  896. # and the override.
  897. my($ovr) = $param::overrides{$re};
  898. return $envcache{$env,$re} if $envcache{$env,$re};
  899. my($newenv) = {@{$env->{_envcopy}}, @$ovr};
  900. @{$newenv->{_envcopy}} = %$env;
  901. $newenv->{_cwd} = $env->{_cwd};
  902. return $envcache{$env,$re} = bless $newenv, ref $env;
  903. }
  904. return $env;
  905. }
  906. # Substitute construction environment variables into a string.
  907. # Internal function/method.
  908. sub _subst {
  909. my($env, $str) = @_;
  910. if (! defined $str) {
  911. return undef;
  912. } elsif (ref($str) eq "ARRAY") {
  913. return [ map($env->_subst($_), @$str) ];
  914. } else {
  915. # % expansion. %% gets converted to % later, so expand any
  916. # %keyword construction that doesn't have a % in front of it,
  917. # modulo multiple %% pairs in between.
  918. # In Perl 5.005 and later, we could actually do this in one regex
  919. # using a conditional expression as follows,
  920. # while ($str =~ s/($pre)\%(\{)?([_a-zA-Z]\w*)(?(2)\})/"$1".$env->{$3}/ge) {}
  921. # The following two-step approach is backwards-compatible
  922. # to (at least) Perl5.003.
  923. my $pre = '^|[^\%](?:\%\%)*';
  924. while (($str =~ s/($pre)\%([_a-zA-Z]\w*)/$1.($env->{$2}||'')/ge) ||
  925. ($str =~ s/($pre)\%\{([_a-zA-Z]\w*)\}/$1.($env->{$2}||'')/ge)) {}
  926. return $str;
  927. }
  928. }
  929. sub Install {
  930. my($env) = shift;
  931. my($tgtdir) = $dir::cwd->lookupdir($env->_subst(shift));
  932. my $file;
  933. for $file (map($dir::cwd->lookupfile($env->_subst($_)), @_)) {
  934. my($tgt) = $tgtdir->lookupfile($file->{entry});
  935. $tgt->bind(find build::install, $file);
  936. }
  937. }
  938. sub InstallAs {
  939. my $env = shift;
  940. my $tgt = shift;
  941. my $src = shift;
  942. my @sources = ();
  943. my @targets = ();
  944. if (ref $tgt) {
  945. die "InstallAs: Source is a file and target is a list!\n"
  946. if (!ref($src));
  947. @sources = @$src;
  948. @targets = @$tgt;
  949. } elsif (ref $src) {
  950. die "InstallAs: Target is a file and source is a list!\n";
  951. } else {
  952. push @sources, $src;
  953. push @targets, $tgt;
  954. }
  955. if ($#sources != $#targets) {
  956. my $tn = $#targets+1;
  957. my $sn = $#sources+1;
  958. die "InstallAs: Source file list ($sn) and target file list ($tn) " .
  959. "are inconsistent in length!\n";
  960. } else {
  961. foreach (0..$#sources) {
  962. my $tfile = $dir::cwd->lookupfile($env->_subst($targets[$_]));
  963. my $sfile = $dir::cwd->lookupfile($env->_subst($sources[$_]));
  964. $tfile->bind(find build::install, $sfile);
  965. }
  966. }
  967. }
  968. # Installation in a local build directory,
  969. # copying from the repository if it's already built there.
  970. # Functionally equivalent to:
  971. # Install $env $dir, $file;
  972. # Local "$dir/$file";
  973. sub Install_Local {
  974. my($env) = shift;
  975. my($tgtdir) = $dir::cwd->lookupdir($env->_subst(shift));
  976. my $file;
  977. for $file (map($dir::cwd->lookupfile($env->_subst($_)), @_)) {
  978. my($tgt) = $tgtdir->lookupfile($file->{entry});
  979. $tgt->bind(find build::install, $file);
  980. $tgt->local(1);
  981. }
  982. }
  983. sub Objects {
  984. my($env) = shift;
  985. map($dir::cwd->relpath($_),
  986. _Objects($env, map($dir::cwd->lookupfile($env->_subst($_)), @_)))
  987. }
  988. # Called with multiple source file references (or object files).
  989. # Returns corresponding object files references.
  990. sub _Objects {
  991. my($env) = shift;
  992. my($suffix) = $env->{SUFOBJ};
  993. map(_Object($env, $_, $_->{dir}->lookupfile($_->base_suf($suffix))), @_);
  994. }
  995. # Called with an object and source reference. If no object reference
  996. # is supplied, then the object file is determined implicitly from the
  997. # source file's extension. Sets up the appropriate rules for creating
  998. # the object from the source. Returns the object reference.
  999. sub _Object {
  1000. my($env, $src, $obj) = @_;
  1001. return $obj if $src eq $obj; # don't need to build self from self.
  1002. my($objenv) = $env->_resolve($obj);
  1003. my($suffix) = $src->suffix;
  1004. my($builder) = $env->{SUFMAP}{$suffix};
  1005. if ($builder) {
  1006. $obj->bind((find $builder($objenv)), $src);
  1007. } else {
  1008. die("don't know how to construct ${\$obj->path} from " .
  1009. "${\$src->path}.\n");
  1010. }
  1011. $obj
  1012. }
  1013. sub Program {
  1014. my($env) = shift;
  1015. my($tgt) = $dir::cwd->lookupfile(file::addsuffix($env->_subst(shift),
  1016. $env->{SUFEXE}));
  1017. my($progenv) = $env->_resolve($tgt);
  1018. $tgt->bind(find build::command::link($progenv, $progenv->{LINKCOM}),
  1019. $env->_Objects(map($dir::cwd->lookupfile($env->_subst($_)), @_)));
  1020. }
  1021. sub Module {
  1022. my($env) = shift;
  1023. my($tgt) = $dir::cwd->lookupfile($env->_subst(shift));
  1024. my($modenv) = $env->_resolve($tgt);
  1025. my($com) = pop(@_);
  1026. $tgt->bind(find build::command::link($modenv, $com),
  1027. $env->_Objects(map($dir::cwd->lookupfile($env->_subst($_)), @_)));
  1028. }
  1029. sub LinkedModule {
  1030. my($env) = shift;
  1031. my($tgt) = $dir::cwd->lookupfile($env->_subst(shift));
  1032. my($progenv) = $env->_resolve($tgt);
  1033. $tgt->bind(find build::command::linkedmodule
  1034. ($progenv, $progenv->{LINKMODULECOM}),
  1035. $env->_Objects(map($dir::cwd->lookupfile($env->_subst($_)), @_)));
  1036. }
  1037. sub Library {
  1038. my($env) = shift;
  1039. my($lib) = $dir::cwd->lookupfile(file::addsuffix($env->_subst(shift),
  1040. $env->{SUFLIB}));
  1041. my($libenv) = $env->_resolve($lib);
  1042. $lib->bind(find build::command::library($libenv),
  1043. $env->_Objects(map($dir::cwd->lookupfile($env->_subst($_)), @_)));
  1044. }
  1045. # Simple derivation: you provide target, source(s), command.
  1046. # Special variables substitute into the rule.
  1047. # Target may be a reference, in which case it is taken
  1048. # to be a multiple target (all targets built at once).
  1049. sub Command {
  1050. my($env) = shift;
  1051. my($tgt) = $env->_subst(shift);
  1052. my($com) = pop(@_);
  1053. my(@sources) = map($dir::cwd->lookupfile($env->_subst($_)), @_);
  1054. if (ref($tgt)) {
  1055. # A multi-target command.
  1056. my(@tgts) = map($dir::cwd->lookupfile($_), @$tgt);
  1057. die("empty target list in multi-target command\n") if !@tgts;
  1058. $env = $env->_resolve($tgts[0]);
  1059. my $builder = find build::command::user($env, $com, 'script');
  1060. my($multi) = build::multiple->new($builder, \@tgts);
  1061. for $tgt (@tgts) {
  1062. $tgt->bind($multi, @sources);
  1063. }
  1064. } else {
  1065. $tgt = $dir::cwd->lookupfile($tgt);
  1066. $env = $env->_resolve($tgt);
  1067. my $builder = find build::command::user($env, $com, 'script');
  1068. $tgt->bind($builder, @sources);
  1069. }
  1070. }
  1071. sub Depends {
  1072. my($env) = shift;
  1073. my($tgt) = $env->_subst(shift);
  1074. my(@deps) = map($dir::cwd->lookup($env->_subst($_)), @_);
  1075. if (! ref($tgt)) {
  1076. $tgt = [ $tgt ];
  1077. }
  1078. my($t);
  1079. foreach $t (map($dir::cwd->lookupfile($_), @$tgt)) {
  1080. push(@{$t->{dep}}, @deps);
  1081. }
  1082. }
  1083. # Setup a quick scanner for the specified input file, for the
  1084. # associated environment. Any use of the input file will cause the
  1085. # scanner to be invoked, once only. The scanner sees just one line at
  1086. # a time of the file, and is expected to return a list of
  1087. # dependencies.
  1088. sub QuickScan {
  1089. my($env, $code, $file, $path) = @_;
  1090. $dir::cwd->lookup($env->_subst($file))->{'srcscan',$env} =
  1091. find scan::quickscan($code, $env, $env->_subst($path));
  1092. }
  1093. # Generic builder module. Just a few default methods. Every derivable
  1094. # file must have a builder object of some sort attached. Usually
  1095. # builder objects are shared.
  1096. package build;
  1097. # Null signature for dynamic includes.
  1098. sub includes { () }
  1099. # Null signature for build script.
  1100. sub script { () }
  1101. # Not compatible with any other builder, by default.
  1102. sub compatible { 0 }
  1103. # Builder module for the Install command.
  1104. package build::install;
  1105. use vars qw( @ISA $installer );
  1106. BEGIN {
  1107. @ISA = qw(build);
  1108. bless $installer = {} # handle for this class.
  1109. }
  1110. sub find {
  1111. $installer
  1112. }
  1113. # Caching not supported for Install: generally install is trivial anyway,
  1114. # and we don't want to clutter the cache.
  1115. sub cachin { undef }
  1116. sub cachout { }
  1117. # Do the installation.
  1118. sub action {
  1119. my($self, $tgt) = @_;
  1120. my($src) = $tgt->{sources}[0];
  1121. main::showcom("Install ${\$src->rpath} as ${\$tgt->path}")
  1122. if ($param::install && !$param::quiet);
  1123. return unless $param::build;
  1124. futil::install($src->rpath, $tgt);
  1125. return 1;
  1126. }
  1127. # Builder module for generic UNIX commands.
  1128. package build::command;
  1129. use vars qw( @ISA %com );
  1130. BEGIN { @ISA = qw(build) }
  1131. sub find {
  1132. my ($class, $env, $com, $package) = @_;
  1133. $com = $env->_subst($com);
  1134. $package ||= '';
  1135. $com{$env,$com,$package} || do {
  1136. # Remove unwanted bits from signature -- those bracketed by %( ... %)
  1137. my $comsig = $com;
  1138. $comsig =~ s/^\@\s*//mg;
  1139. while ($comsig =~ s/%\(([^%]|%[^\(])*?%\)//g) { }
  1140. my $self = { env => $env, com => $com, 'package' => $package,
  1141. comsig => $comsig };
  1142. $com{$env,$com,$package} = bless $self, $class;
  1143. }
  1144. }
  1145. # Default cache in function.
  1146. sub cachin {
  1147. my($self, $tgt, $sig) = @_;
  1148. if (cache::in($tgt, $sig)) {
  1149. if ($param::cachecom) {
  1150. map { if (! s/^\@\s*//) { main::showcom($_) } } $self->getcoms($tgt);
  1151. } else {
  1152. printf("Retrieved %s from cache\n", $tgt->path)
  1153. unless ($param::quiet);
  1154. }
  1155. return 1;
  1156. }
  1157. return undef;
  1158. }
  1159. # Default cache out function.
  1160. sub cachout {
  1161. my($self, $tgt, $sig) = @_;
  1162. cache::out($tgt, $sig);
  1163. }
  1164. # internal routine to process variable options.
  1165. # f: return file part
  1166. # F: return file part, but strip any suffix
  1167. # d: return directory part
  1168. # b: return full path, but strip any suffix (a.k.a. return basename)
  1169. # s: return only the suffix (or an empty string, if no suffix is there)
  1170. # a: return the absolute path to the file
  1171. # no option: return full path to file
  1172. sub _variant {
  1173. my($opt, $file) = @_;
  1174. $opt = '' if ! defined $opt;
  1175. if ($opt eq 'f') { return $file->{entry}; }
  1176. elsif ($opt eq 'd') { return $file->{dir}->path; }
  1177. elsif ($opt eq 'F') {
  1178. my $subst = $file->{entry};
  1179. $subst =~ s/\.[^\.]+$//;
  1180. return $subst;
  1181. }
  1182. elsif ($opt eq 'b') {
  1183. my $subst = $file->path;
  1184. $subst =~ s/\.[^\.]+$//;
  1185. return $subst;
  1186. }
  1187. elsif ($opt eq 's') {
  1188. my $subst = $file->{entry};
  1189. $subst =~ m/(\.[^\.]+)$/;
  1190. return $1;
  1191. }
  1192. elsif ($opt eq 'a') {
  1193. my $path = $file->path;
  1194. if (! File::Spec->file_name_is_absolute($path)) {
  1195. $path = File::Spec->catfile(Cwd::cwd(), $path);
  1196. }
  1197. return $path;
  1198. }
  1199. else { return $file->path; }
  1200. }
  1201. # For the signature of a basic command, we don't bother
  1202. # including the command itself. This is not strictly correct,
  1203. # and if we wanted to be rigorous, we might want to insist
  1204. # that the command was checked for all the basic commands
  1205. # like gcc, etc. For this reason we don't have an includes
  1206. # method.
  1207. # Call this to get the command line script: an array of
  1208. # fully substituted commands.
  1209. sub getcoms {
  1210. my($self, $tgt) = @_;
  1211. my(@coms);
  1212. my $com;
  1213. for $com (split(/\n/, $self->{com})) {
  1214. my(@src) = (undef, @{$tgt->{sources}});
  1215. my(@src1) = @src;
  1216. next if $com =~ /^\s*$/;
  1217. # NOTE: we used to have a more elegant s//.../e solution
  1218. # for the items below, but this caused a bus error...
  1219. # Remove %( and %) -- those are only used to bracket parts
  1220. # of the command that we don't depend on.
  1221. $com =~ s/%[()]//g;
  1222. # Deal with %n, n=1,9 and variants.
  1223. while ($com =~ /%([1-9])(:([fdbsFa]?))?/) {
  1224. my($match) = $&;
  1225. my($src) = $src1[$1];
  1226. my($subst) = _variant($3, $src1[$1]->rfile);
  1227. undef $src[$1];
  1228. $com =~ s/$match/$subst/;
  1229. }
  1230. # Deal with %0 aka %> and variants.
  1231. while ($com =~ /%[0>](:([fdbsFa]?))?/) {
  1232. my($match) = $&;
  1233. my($subst) = _variant($2, $tgt);
  1234. $com =~ s/$match/$subst/;
  1235. }
  1236. # Deal with %< (all sources except %n's already used)
  1237. while ($com =~ /%<(:([fdbsFa]?))?/) {
  1238. my($match) = $&;
  1239. my @list = ();
  1240. foreach (@src) {
  1241. push(@list, _variant($2, $_->rfile)) if $_;
  1242. }
  1243. my($subst) = join(' ', @list);
  1244. $com =~ s/$match/$subst/;
  1245. }
  1246. # Deal with %[ %].
  1247. $com =~ s{%\[(.*?)%\]}{
  1248. my($func, @args) = grep { $_ ne '' } split(/\s+/, $1);
  1249. die("$0: \"$func\" is not defined.\n")
  1250. unless ($self->{env}->{$func});
  1251. &{$self->{env}->{$func}}(@args);
  1252. }gex;
  1253. # Convert left-over %% into %.
  1254. $com =~ s/%%/%/g;
  1255. # White space cleanup. XXX NO WAY FOR USER TO HAVE QUOTED SPACES
  1256. $com = join(' ', split(' ', $com));
  1257. next if $com =~ /^:/ && $com !~ /^:\S/;
  1258. push(@coms, $com);
  1259. }
  1260. @coms
  1261. }
  1262. # Build the target using the previously specified commands.
  1263. sub action {
  1264. my($self, $tgt) = @_;
  1265. my($env) = $self->{env};
  1266. if ($param::build) {
  1267. futil::mkdir($tgt->{dir});
  1268. unlink($tgt->path) if ! $tgt->precious;
  1269. }
  1270. # Set environment.
  1271. map(delete $ENV{$_}, keys %ENV);
  1272. %ENV = %{$env->{ENV}};
  1273. # Handle multi-line commands.
  1274. my $com;
  1275. for $com ($self->getcoms($tgt)) {
  1276. if ($com !~ s/^\@\s*//) {
  1277. main::showcom($com);
  1278. }
  1279. if ($param::build) {
  1280. if ($com =~ /^\[perl\]\s*/) {
  1281. my $perlcmd = $';
  1282. my $status;
  1283. {
  1284. # Restore the script package variables that were defined
  1285. # in the Conscript file that defined this [perl] build,
  1286. # so the code executes with the expected variables.
  1287. my($package) = $self->{'package'};
  1288. my($pkgvars) = $tgt->{conscript}->{pkgvars};
  1289. NameSpace::restore($package, $pkgvars) if $pkgvars;
  1290. # Actually execute the [perl] command to build the target.
  1291. $status = eval "package $package; $perlcmd";
  1292. # Clean up the namespace by deleting the package variables
  1293. # we just restored.
  1294. NameSpace::remove($package, keys %$pkgvars) if $pkgvars;
  1295. }
  1296. if (!defined($status)) {
  1297. warn "$0: *** Error during perl command eval: $@.\n";
  1298. return undef;
  1299. } elsif ($status == 0) {
  1300. warn "$0: *** Perl command returned $status (this indicates an error).\n";
  1301. return undef;
  1302. }
  1303. next;
  1304. }
  1305. #---------------------
  1306. # Can't fork on Win32
  1307. #---------------------
  1308. if ($main::_WIN32) {
  1309. system($com);
  1310. if ($?) {
  1311. my ($b0, $b1) = ($? & 0xFF, $? >> 8);
  1312. my $err = $b1 || $?;
  1313. my $path = $tgt->path;
  1314. my $warn = qq($0: *** [$path] Error $err);
  1315. $warn .= " (executable not found in path?)" if $b1 == 0xFF;
  1316. warn "$warn\n";
  1317. return undef;
  1318. }
  1319. } else {
  1320. my($pid) = fork();
  1321. die("$0: unable to fork child process ($!)\n") if !defined $pid;
  1322. if (!$pid) {
  1323. # This is the child. We eval the command to suppress -w
  1324. # warnings about not reaching the statements afterwards.
  1325. eval 'exec($com)';
  1326. $com =~ s/\s.*//;
  1327. die qq($0: failed to execute "$com" ($!). )
  1328. . qq(Is this an executable on path "$ENV{PATH}"?\n);
  1329. }
  1330. for (;;) {
  1331. do {} until wait() == $pid;
  1332. my ($b0, $b1) = ($? & 0xFF, $? >> 8);
  1333. # Don't actually see 0177 on stopped process; is this necessary?
  1334. next if $b0 == 0177; # process stopped; we can wait.
  1335. if ($b0) {
  1336. my($core, $sig) = ($b0 & 0200, $b0 & 0177);
  1337. my($coremsg) = $core ? "; core dumped" : "";
  1338. $com =~ s/\s.*//;
  1339. my $path = $tgt->path;
  1340. my $err = "$0: *** \[$path\] $com terminated by signal " .
  1341. "$sig$coremsg\n";
  1342. warn $err;
  1343. return undef;
  1344. }
  1345. if ($b1) {
  1346. my($path) = $tgt->path;
  1347. warn qq($0: *** [$path] Error $b1\n); # trying to be like make.
  1348. return undef;
  1349. }
  1350. last;
  1351. }
  1352. }
  1353. }
  1354. }
  1355. # success.
  1356. return 1;
  1357. }
  1358. # Return script signature.
  1359. sub script {
  1360. $_[0]->{comsig}
  1361. }
  1362. # Create a linked module.
  1363. package build::command::link;
  1364. use vars qw( @ISA );
  1365. BEGIN { @ISA = qw(build::command) }
  1366. # Find an appropriate linker.
  1367. sub find {
  1368. my($class, $env, $command) = @_;
  1369. if (!exists $env->{_LDIRS}) {
  1370. my($ldirs) = '';
  1371. my($wd) = $env->{_cwd};
  1372. my($pdirs) = $env->{LIBPATH};
  1373. if (! defined $pdirs) {
  1374. $pdirs = [ ];
  1375. } elsif (ref($pdirs) ne 'ARRAY') {
  1376. $pdirs = [ split(/$main::PATH_SEPARATOR/o, $pdirs) ];
  1377. }
  1378. my $dir;
  1379. for $dir (map($wd->lookupdir($env->_subst($_)), @$pdirs)) {
  1380. my($dpath) = $dir->path;
  1381. $ldirs .= " ".$env->{LIBDIRPREFIX}.$dpath;
  1382. next if File::Spec->file_name_is_absolute($dpath);
  1383. if (@param::rpath) {
  1384. my $d;
  1385. if ($dpath eq $dir::CURDIR) {
  1386. foreach $d (map($_->path, @param::rpath)) {
  1387. $ldirs .= " ".$env->{LIBDIRPREFIX}.$d;
  1388. }
  1389. } else {
  1390. foreach $d (map($_->path, @param::rpath)) {
  1391. $ldirs .= " ".$env->{LIBDIRPREFIX}.File::Spec->catfile($d, $dpath);
  1392. }
  1393. }
  1394. }
  1395. }
  1396. $env->{_LDIRS} = "%($ldirs%)";
  1397. }
  1398. # Introduce a new magic _LIBS symbol which allows to use the
  1399. # Unix-style -lNAME syntax for Win32 only. -lNAME will be replaced
  1400. # with %{PREFLIB}NAME%{SUFLIB}. <schwarze@isa.de> 1998-06-18
  1401. if ($main::_WIN32 && !exists $env->{_LIBS}) {
  1402. my $libs;
  1403. my $name;
  1404. for $name (split(' ', $env->_subst($env->{LIBS} || ''))) {
  1405. if ($name =~ /^-l(.*)/) {
  1406. $name = "$env->{PREFLIB}$1$env->{SUFLIB}";
  1407. }
  1408. $libs .= ' ' . $name;
  1409. }
  1410. $env->{_LIBS} = $libs ? "%($libs%)" : '';
  1411. }
  1412. bless find build::command($env, $command);
  1413. }
  1414. # Called from file::build. Make sure any libraries needed by the
  1415. # environment are built, and return the collected signatures
  1416. # of the libraries in the path.
  1417. sub includes {
  1418. return $_[0]->{sig} if exists $_[0]->{sig};
  1419. my($self, $tgt) = @_;
  1420. my($env) = $self->{env};
  1421. my($ewd) = $env->{_cwd};
  1422. my $ldirs = $env->{LIBPATH};
  1423. if (! defined $ldirs) {
  1424. $ldirs = [ ];
  1425. } elsif (ref($ldirs) ne 'ARRAY') {
  1426. $ldirs = [ split(/$main::PATH_SEPARATOR/o, $ldirs) ];
  1427. }
  1428. my @lpath = map($ewd->lookupdir($_), @$ldirs);
  1429. my(@sigs);
  1430. my(@names);
  1431. if ($main::_WIN32) {
  1432. # Pass %LIBS symbol through %-substituition
  1433. # <schwarze@isa.de> 1998-06-18
  1434. @names = split(' ', $env->_subst($env->{LIBS} || ''));
  1435. } else {
  1436. @names = split(' ', $env->{LIBS} || '');
  1437. }
  1438. my $name;
  1439. for $name (@names) {
  1440. my ($lpath, @allnames);
  1441. if ($name =~ /^-l(.*)/) {
  1442. # -l style names are looked up on LIBPATH, using all
  1443. # possible lib suffixes in the same search order the
  1444. # linker uses (according to SUFLIBS).
  1445. # Recognize new PREFLIB symbol, which should be 'lib' on
  1446. # Unix, and empty on Win32. TODO: What about shared
  1447. # library suffixes? <schwarze@isa.de> 1998-05-13
  1448. @allnames = map("$env->{PREFLIB}$1$_",
  1449. split(/:/, $env->{SUFLIBS}));
  1450. $lpath = \@lpath;
  1451. } else {
  1452. @allnames = ($name);
  1453. # On Win32, all library names are looked up in LIBPATH
  1454. # <schwarze@isa.de> 1998-05-13
  1455. if ($main::_WIN32) {
  1456. $lpath = [$dir::top, @lpath];
  1457. }
  1458. else {
  1459. $lpath = [$dir::top];
  1460. }
  1461. }
  1462. my $dir;
  1463. DIR: for $dir (@$lpath) {
  1464. my $n;
  1465. for $n (@allnames) {
  1466. my($lib) = $dir->lookup_accessible($n);
  1467. if ($lib) {
  1468. last DIR if $lib->ignore;
  1469. if ((build $lib) eq 'errors') {
  1470. $tgt->{status} = 'errors';
  1471. return undef;
  1472. }
  1473. push(@sigs, 'sig'->signature($lib));
  1474. last DIR;
  1475. }
  1476. }
  1477. }
  1478. }
  1479. $self->{sig} = 'sig'->collect(@sigs);
  1480. }
  1481. # Always compatible with other such builders, so the user
  1482. # can define a single program or module from multiple

Large files files are truncated, but you can click here to view the full file