build.pl 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. #!/usr/bin/perl
  2. use Cwd;
  3. use File::Spec;
  4. use File::stat;
  5. our $top_dir = (File::Spec->splitpath(File::Spec->rel2abs($0)))[1];
  6. our $opts_file = "${top_dir}opts.pl";
  7. is_file_newer("${top_dir}configure.pl", $opts_file) and die "Build options out of date. Please run configure.pl first.\n";
  8. require $opts_file;
  9. my $targets_script = defined($ARGV[0]) ? $ARGV[0] : 'targets.pl';
  10. unless (-f $targets_script) {
  11. print "build.pl: target script '$targets_script' does not exist.\n";
  12. exit 1;
  13. }
  14. do $targets_script;
  15. 1;
  16. # is_file_newer($file, $than)
  17. # Checks if $file is newer than $than.
  18. sub is_file_newer {
  19. (-f $_[1]) or return 1;
  20. my $file = stat($_[0]);
  21. my $than = stat($_[1]);
  22. return $file->mtime >= $than->mtime;
  23. }
  24. # needs_building($file, $than)
  25. # Checks if targets or build options changed in addition to checking
  26. # whether the object file needs an update.
  27. sub needs_building {
  28. return is_file_newer($_[0], $_[1]) ||
  29. is_file_newer('targets.pl', $_[1]) ||
  30. is_file_newer($opts_file, $_[1]);
  31. }
  32. sub get_asm_cmd {
  33. return "jwasm $jwasm_args -zt1";
  34. }
  35. # get_cxx_cmd(\@includes, \@defines)
  36. sub get_cxx_cmd {
  37. my @cc_opts = ('g++', '-c');
  38. # OWORLD currently miscompiles at -O2 on gcc 4.3.3.
  39. #push (@cc_opts, $no_asm ? "-O2" : "-O1");
  40. defined($debug) and $debug and push (@cc_opts, "-g");
  41. push (@cc_opts, map { "-D$_" } @{$_[1]});
  42. push (@cc_opts, map { "-I$_" } @{$_[0]});
  43. return "@cc_opts";
  44. }
  45. sub get_wrc_cmd {
  46. return $platform =~ /^linux/ ? 'wrc' : 'windres';
  47. }
  48. sub link_exe {
  49. my ($exe, $obj_files, $libs, $lib_dirs) = @_;
  50. defined($exe) or return 1; # No exe targets here
  51. my $flag = 0;
  52. foreach my $i (@$obj_files) {
  53. unless (-f $i) {
  54. print "build.pl: missing file '$i' for linking.\n";
  55. exit 1;
  56. }
  57. # check modification times to see if we have to relink
  58. if (-f $exe) {
  59. is_file_newer($i, $exe) and $flag = 1;
  60. } else {
  61. $flag = 1;
  62. }
  63. }
  64. if ($flag) {
  65. my $linker = $platform =~ /^linux/ ? 'wineg++' : 'g++';
  66. my @linker_opts = ("-g -mno-cygwin");
  67. $debug or push(@linker_opts, "-mwindows");
  68. my $cmd = "$linker " .
  69. join(' ', @linker_opts) . ' ' .
  70. "@$obj_files " .
  71. join(' ', map { "-l$_" } @$libs) . ' ' .
  72. join(' ', map { "-L$_" } @$lib_dirs) . ' ' .
  73. "-o $exe";
  74. print $cmd,"\n";
  75. if (system $cmd) {
  76. print "build.pl: couldn't create executable '$exe'\n";
  77. exit 1;
  78. }
  79. }
  80. return 1;
  81. }
  82. # include_targets(@target_files)
  83. #
  84. # Usage: Use in your target files to include build stages found in
  85. # other directories. This will change directory to where your
  86. # target file is found in and execute the target script.
  87. #
  88. # Note that the new target file executed will have its own clean
  89. # scope. This forces you to redefine what is necessary to run
  90. # the building. It makes sense if you are logically grouping
  91. # various targets by their purpose.
  92. #
  93. # Returns paths to the built targets.
  94. #
  95. sub include_targets {
  96. my @built_targets;
  97. my $orig_dir = cwd;
  98. foreach my $i (@_) {
  99. unless (-f $i) {
  100. print "build.pl: target script '$i' does not exist.\n";
  101. exit 1;
  102. }
  103. # change directory
  104. my ($dir, $inc) = (File::Spec->splitpath($i))[1,2];
  105. ($dir) = $dir =~ /(.+?)\/?$/;
  106. unless (-d $dir && chdir $dir) {
  107. print "build.pl: unable to enter directory '$dir'.\n";
  108. exit 1;
  109. }
  110. print "Entering '$dir'.\n";
  111. # run script
  112. push (@built_targets, map { "$dir/$_" } do $inc);
  113. # go back to the original directory
  114. print "Leaving '$dir'.\n";
  115. unless (chdir $orig_dir) {
  116. print "build.pl: original directory disappeared.\n";
  117. exit 1;
  118. }
  119. }
  120. return @built_targets;
  121. }
  122. sub break_extension {
  123. my @parts = split('\.', $_[0]);
  124. my $extension = pop(@parts);
  125. my $name = join('.', @parts);
  126. return ($name, $extension);
  127. }
  128. # build_targets(\@files_to_build, \@includes, \@defines)
  129. #
  130. # Usage: Called from target script. An array of files
  131. # that are to be built is passed.
  132. # i.e. ('AM.cpp','7k.ico', 'IB.asm')
  133. # or qw(AM.cpp 7k.ico IB.asm)
  134. #
  135. # Pass the include paths and defines for the C++ compiler
  136. # as needed for the source files to be built.
  137. #
  138. sub build_targets {
  139. my $cxx_cmd;
  140. my $asm_cmd;
  141. my $wrc_cmd;
  142. my @built_objects;
  143. foreach my $i (@{$_[0]}) {
  144. my ($name, $extension) = break_extension($i);
  145. unless (defined($extension)) {
  146. print "build.pl: no extension to figure out the file type of '$i'\n";
  147. exit 1;
  148. }
  149. my $obj = "$name.o";
  150. if (needs_building($i, $obj)) {
  151. my $cmd;
  152. # get the command to build this type of file
  153. if ($extension eq 'cpp') {
  154. defined($cxx_cmd) or $cxx_cmd = get_cxx_cmd($_[1], $_[2]);
  155. $cmd = "$cxx_cmd $i -o $obj";
  156. } elsif ($extension eq 'asm') {
  157. defined($asm_cmd) or $asm_cmd = get_asm_cmd();
  158. $cmd = "$asm_cmd -Fo $name.o $i";
  159. } elsif ($extension eq 'rc') {
  160. defined($wrc_cmd) or $wrc_cmd = get_wrc_cmd();
  161. $cmd = "$wrc_cmd -i $i -o $name.o";
  162. } else {
  163. print "build.pl: cannot identify how to build file type '$extension'\n";
  164. exit 1;
  165. }
  166. print "$cmd\n";
  167. if (system $cmd) {
  168. print "build.pl: couldn't build '$i'. Stopping.\n";
  169. exit 1;
  170. }
  171. }
  172. push (@built_objects, $obj);
  173. }
  174. return @built_objects;
  175. }