123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- #!/usr/bin/perl
- use Cwd;
- use File::Spec;
- use File::stat;
- our $top_dir = (File::Spec->splitpath(File::Spec->rel2abs($0)))[1];
- our $opts_file = "${top_dir}opts.pl";
- is_file_newer("${top_dir}configure.pl", $opts_file) and die "Build options out of date. Please run configure.pl first.\n";
- require $opts_file;
- my $targets_script = defined($ARGV[0]) ? $ARGV[0] : 'targets.pl';
- unless (-f $targets_script) {
- print "build.pl: target script '$targets_script' does not exist.\n";
- exit 1;
- }
- do $targets_script;
- 1;
- # is_file_newer($file, $than)
- # Checks if $file is newer than $than.
- sub is_file_newer {
- (-f $_[1]) or return 1;
- my $file = stat($_[0]);
- my $than = stat($_[1]);
- return $file->mtime >= $than->mtime;
- }
- # needs_building($file, $than)
- # Checks if targets or build options changed in addition to checking
- # whether the object file needs an update.
- sub needs_building {
- return is_file_newer($_[0], $_[1]) ||
- is_file_newer('targets.pl', $_[1]) ||
- is_file_newer($opts_file, $_[1]);
- }
- sub get_asm_cmd {
- return "jwasm $jwasm_args -zt1";
- }
- # get_cxx_cmd(\@includes, \@defines)
- sub get_cxx_cmd {
- my @cc_opts = ('g++', '-c');
- # OWORLD currently miscompiles at -O2 on gcc 4.3.3.
- #push (@cc_opts, $no_asm ? "-O2" : "-O1");
- defined($debug) and $debug and push (@cc_opts, "-g");
- push (@cc_opts, map { "-D$_" } @{$_[1]});
- push (@cc_opts, map { "-I$_" } @{$_[0]});
- return "@cc_opts";
- }
- sub get_wrc_cmd {
- return $platform =~ /^linux/ ? 'wrc' : 'windres';
- }
- sub link_exe {
- my ($exe, $obj_files, $libs, $lib_dirs) = @_;
- defined($exe) or return 1; # No exe targets here
- my $flag = 0;
- foreach my $i (@$obj_files) {
- unless (-f $i) {
- print "build.pl: missing file '$i' for linking.\n";
- exit 1;
- }
- # check modification times to see if we have to relink
- if (-f $exe) {
- is_file_newer($i, $exe) and $flag = 1;
- } else {
- $flag = 1;
- }
- }
- if ($flag) {
- my $linker = $platform =~ /^linux/ ? 'wineg++' : 'g++';
- my @linker_opts = ("-g -mno-cygwin");
- $debug or push(@linker_opts, "-mwindows");
-
- my $cmd = "$linker " .
- join(' ', @linker_opts) . ' ' .
- "@$obj_files " .
- join(' ', map { "-l$_" } @$libs) . ' ' .
- join(' ', map { "-L$_" } @$lib_dirs) . ' ' .
- "-o $exe";
- print $cmd,"\n";
- if (system $cmd) {
- print "build.pl: couldn't create executable '$exe'\n";
- exit 1;
- }
- }
- return 1;
- }
- # include_targets(@target_files)
- #
- # Usage: Use in your target files to include build stages found in
- # other directories. This will change directory to where your
- # target file is found in and execute the target script.
- #
- # Note that the new target file executed will have its own clean
- # scope. This forces you to redefine what is necessary to run
- # the building. It makes sense if you are logically grouping
- # various targets by their purpose.
- #
- # Returns paths to the built targets.
- #
- sub include_targets {
- my @built_targets;
- my $orig_dir = cwd;
- foreach my $i (@_) {
- unless (-f $i) {
- print "build.pl: target script '$i' does not exist.\n";
- exit 1;
- }
- # change directory
- my ($dir, $inc) = (File::Spec->splitpath($i))[1,2];
- ($dir) = $dir =~ /(.+?)\/?$/;
- unless (-d $dir && chdir $dir) {
- print "build.pl: unable to enter directory '$dir'.\n";
- exit 1;
- }
- print "Entering '$dir'.\n";
- # run script
- push (@built_targets, map { "$dir/$_" } do $inc);
- # go back to the original directory
- print "Leaving '$dir'.\n";
- unless (chdir $orig_dir) {
- print "build.pl: original directory disappeared.\n";
- exit 1;
- }
- }
- return @built_targets;
- }
- sub break_extension {
- my @parts = split('\.', $_[0]);
- my $extension = pop(@parts);
- my $name = join('.', @parts);
- return ($name, $extension);
- }
- # build_targets(\@files_to_build, \@includes, \@defines)
- #
- # Usage: Called from target script. An array of files
- # that are to be built is passed.
- # i.e. ('AM.cpp','7k.ico', 'IB.asm')
- # or qw(AM.cpp 7k.ico IB.asm)
- #
- # Pass the include paths and defines for the C++ compiler
- # as needed for the source files to be built.
- #
- sub build_targets {
- my $cxx_cmd;
- my $asm_cmd;
- my $wrc_cmd;
- my @built_objects;
- foreach my $i (@{$_[0]}) {
- my ($name, $extension) = break_extension($i);
- unless (defined($extension)) {
- print "build.pl: no extension to figure out the file type of '$i'\n";
- exit 1;
- }
- my $obj = "$name.o";
- if (needs_building($i, $obj)) {
- my $cmd;
- # get the command to build this type of file
- if ($extension eq 'cpp') {
- defined($cxx_cmd) or $cxx_cmd = get_cxx_cmd($_[1], $_[2]);
- $cmd = "$cxx_cmd $i -o $obj";
- } elsif ($extension eq 'asm') {
- defined($asm_cmd) or $asm_cmd = get_asm_cmd();
- $cmd = "$asm_cmd -Fo $name.o $i";
- } elsif ($extension eq 'rc') {
- defined($wrc_cmd) or $wrc_cmd = get_wrc_cmd();
- $cmd = "$wrc_cmd -i $i -o $name.o";
- } else {
- print "build.pl: cannot identify how to build file type '$extension'\n";
- exit 1;
- }
- print "$cmd\n";
- if (system $cmd) {
- print "build.pl: couldn't build '$i'. Stopping.\n";
- exit 1;
- }
- }
- push (@built_objects, $obj);
- }
- return @built_objects;
- }
|