buildcc.PL 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. #! perl
  2. use Config;
  3. use File::Basename qw(&basename &dirname);
  4. use File::Spec;
  5. use Cwd;
  6. # List explicitly here the variables you want Configure to
  7. # generate. Metaconfig only looks for shell variables, so you
  8. # have to mention them as if they were shell variables, not
  9. # %Config entries. Thus you write
  10. # $startperl
  11. # to ensure Configure will look for $Config{startperl}.
  12. # Wanted: $archlibexp
  13. # This forces PL files to create target in same directory as PL file.
  14. # This is so that make depend always knows where to find PL derivatives.
  15. my $origdir = cwd;
  16. chdir dirname($0);
  17. my $file = basename($0, '.PL');
  18. $file .= '.com' if $^O eq 'VMS';
  19. open OUT,">",$file or die "Can't create $file: $!";
  20. print "Extracting $file (with variable substitutions)\n";
  21. # In this section, perl variables will be expanded during extraction.
  22. # You can use $Config{...} to use Configure variables.
  23. print OUT <<"!GROK!THIS!";
  24. $Config{startperl}
  25. eval 'exec $Config{perlpath} -S \$0 \${1+"\$@"}'
  26. if \$running_under_some_shell;
  27. --\$running_under_some_shell;
  28. !GROK!THIS!
  29. # In the following, perl variables are not expanded during extraction.
  30. print OUT <<'!NO!SUBS!';
  31. # Version 1.00, Reini Urban, 2013-02-11 09:52:10
  32. use strict;
  33. use warnings;
  34. use 5.006_000;
  35. use FileHandle;
  36. use Config;
  37. use Fcntl qw(:DEFAULT :flock);
  38. use File::Temp qw(tempfile);
  39. use File::Basename qw(basename dirname);
  40. use File::Path qw(mkpath);
  41. # use Cwd;
  42. use Pod::Usage;
  43. # Time::HiRes does not work with 5.6
  44. use Time::HiRes qw(gettimeofday tv_interval);
  45. our $VERSION = 1.00;
  46. $| = 1;
  47. eval { require B::C::Config; };
  48. sub is_win32();
  49. our ($logfh, $Options);
  50. $SIG{INT} = sub { exit(); } if exists $SIG{INT}; # exit gracefully and clean up after ourselves.
  51. # usage: vprint [level] msg args
  52. sub vprint {
  53. my $level;
  54. if (@_ == 1) {
  55. $level = 1;
  56. } elsif ($_[0] =~ /^-?\d$/) {
  57. $level = shift;
  58. } else {
  59. # well, they forgot to use a number; means >0
  60. $level = 0;
  61. }
  62. my $msg = "@_";
  63. $msg .= "\n" unless substr($msg, -1) eq "\n";
  64. if (opt('v') > $level)
  65. {
  66. if (opt('log')) {
  67. print $logfh "$0: $msg" ;
  68. } else {
  69. print "$0: $msg";
  70. }
  71. }
  72. }
  73. sub vsystem {
  74. if (opt('dryrun')) {
  75. print "@_\n";
  76. } else {
  77. system(@_);
  78. }
  79. }
  80. # parse most options thru to perlcc, just use -m|--module and -l:s|--local=path
  81. sub parse_argv {
  82. $Options = {};
  83. if (grep /^-m$/, @ARGV) {
  84. $Options->{m}++;
  85. @ARGV = grep !/^-m$/, @ARGV;
  86. }
  87. if (my ($l) = grep /^-l(.*)$/, @ARGV) {
  88. if ($l) {
  89. $l =~ s/^=//;
  90. $Options->{l} = $l;
  91. } else {
  92. # check next ARGV for -
  93. $Options->{l} = '~/.perl5/pcc';
  94. }
  95. @ARGV = grep !/^-l(.*)$/, @ARGV;
  96. }
  97. }
  98. sub opt(*) {
  99. my $opt = shift;
  100. return exists($Options->{$opt}) && ($Options->{$opt} || 0);
  101. }
  102. # File spawning and error collecting
  103. sub spawnit {
  104. my $command = shift;
  105. my (@error,@output,$errname,$errcode);
  106. if (opt('dryrun')) {
  107. print "$command\n";;
  108. }
  109. elsif ($Options->{spawn}) {
  110. (undef, $errname) = tempfile("pccXXXXX");
  111. {
  112. my $pid = open (S_OUT, "$command 2>$errname |")
  113. or _die("Couldn't spawn the compiler.\n");
  114. $errcode = $?;
  115. my $kid;
  116. do {
  117. $kid = waitpid($pid, 0);
  118. } while $kid > 0;
  119. @output = <S_OUT>;
  120. }
  121. open (S_ERROR, $errname) or _die("Couldn't read the error file.\n");
  122. @error = <S_ERROR>;
  123. close S_ERROR;
  124. close S_OUT;
  125. unlink $errname or _die("Can't unlink error file $errname\n");
  126. } else {
  127. @output = split /\n/, `$command`;
  128. }
  129. return (\@output, \@error, $errcode);
  130. }
  131. sub version {
  132. require B::C::Flags;
  133. no warnings 'once';
  134. my $BC_VERSION = $B::C::Flags::VERSION . $B::C::REVISION;
  135. return "buildcc $VERSION, B-C-${BC_VERSION} built for $Config{perlpath} $Config{archname}\n";
  136. }
  137. sub helpme {
  138. print version(),"\n";
  139. if (opt('v')) {
  140. pod2usage( -verbose => opt('v') );
  141. } else {
  142. pod2usage( -verbose => 0 );
  143. }
  144. }
  145. sub relativize {
  146. my ($args) = @_;
  147. return() if ($args =~ m"^[/\\]");
  148. return("./$args");
  149. }
  150. sub _die {
  151. my @args = ("$0: ", @_);
  152. $logfh->print(@args) if opt('log');
  153. print STDERR @args;
  154. exit(); # should die eventually. However, needed so that a 'make compile'
  155. # can compile all the way through to the end for standard dist.
  156. }
  157. sub _usage_and_die {
  158. _die(<<EOU);
  159. Usage:
  160. $0 [-o executable] [-h] [-m] -l [path] source.pl
  161. buildcc -o hello hello.pl # pass thru perlcc
  162. buildcc -m app.pl # detects dependencies for app.pl, write them to app.mak,
  163. # and compile all into shared modules and app
  164. buildcc -l -m app.pl # use local ~/.perl5/pcc/ path
  165. buildcc -l=~/pcc -m app.pl # use local ~/pcc/ path
  166. EOU
  167. }
  168. sub run {
  169. my (@commands) = @_;
  170. my $t0 = [gettimeofday] if opt('time');
  171. print interruptrun(@commands) if (!opt('log'));
  172. $logfh->print(interruptrun(@commands)) if (opt('log'));
  173. my $elapsed = tv_interval ( $t0 ) if opt('time');
  174. vprint -1, "r time: $elapsed" if opt('time');
  175. }
  176. sub interruptrun {
  177. my (@commands) = @_;
  178. my $command = join('', @commands);
  179. local(*FD);
  180. my $pid = open(FD, "$command |");
  181. my $text;
  182. local($SIG{HUP}, $SIG{INT}) if exists $SIG{HUP};
  183. $SIG{HUP} = $SIG{INT} = sub { kill 9, $pid; exit } if exists $SIG{HUP};
  184. my $needalarm =
  185. ($ENV{PERLCC_TIMEOUT} &&
  186. exists $SIG{ALRM} &&
  187. $Config{'osname'} ne 'MSWin32' &&
  188. $command =~ m"(^|\s)perlcc\s");
  189. eval {
  190. local($SIG{ALRM}) = sub { die "INFINITE LOOP"; } if exists $SIG{ALRM};
  191. alarm($ENV{PERLCC_TIMEOUT}) if $needalarm;
  192. $text = join('', <FD>);
  193. alarm(0) if $needalarm;
  194. };
  195. if ($@) {
  196. eval { kill 'HUP', $pid };
  197. vprint 0, "SYSTEM TIMEOUT (infinite loop?)\n";
  198. }
  199. close(FD);
  200. return($text);
  201. }
  202. sub is_win32() { $^O =~ m/^MSWin/ }
  203. sub is_msvc() { is_win32 && $Config{cc} =~ m/^cl/i }
  204. __END__
  205. =head1 NAME
  206. buildcc - build an executable with shared modules from a perl script
  207. =head1 SYNOPSIS
  208. buildcc -o hello hello.pl # pass thru perlcc
  209. buildcc -m app.pl # detects dependencies for app.pl, write them to app.mak,
  210. # and compile all into shared modules and app
  211. buildcc -l -m app.pl # use local ~/.perl5/pcc/ path
  212. buildcc -l=~/pcc -m app.pl # use local ~/pcc/ path
  213. =head1 DESCRIPTION
  214. F<buildcc> is a C<perlcc -m> frontend to detect and maintain perlcc compiled perl
  215. modules as compiled shared libraries.
  216. It creates a F<.mak> file for the compiled script with all dependencies.
  217. C<-l> uses a local path for all compiled shared modules. Otherwise it checks if
  218. F< 'sitearch'/pcc/> is writable and puts/searches the modules there if so.
  219. All other options are passed thru to perlcc verbatim.
  220. =head1 OPTIONS
  221. =over 4
  222. =item -m
  223. Create a .mak for the module depencencies, and create the target.
  224. =item -l [path]
  225. Use the given local path as prefix for the created shared modules.
  226. =back
  227. =cut
  228. # Local Variables:
  229. # mode: cperl
  230. # cperl-indent-level: 4
  231. # fill-column: 100
  232. # End:
  233. # vim: expandtab shiftwidth=4:
  234. !NO!SUBS!
  235. close OUT or die "Can't close $file: $!";
  236. chmod 0755, $file or die "Can't reset permissions for $file: $!\n";
  237. exec("$Config{'eunicefix'} $file") if $Config{'eunicefix'} ne ':';
  238. chdir $origdir;