#! /usr/pkg/bin/perl -w
#
# $eterna$
#
# run netbsd 'mknative-gcc' for a list of platforms

$version = 'runmknative $Revision$' . "\n";

require 'getopts.pl';
#use Getopt::Std;

$help = 'runmknative [options] [<arch list>]
main options:
     -B                  bootstrap; set MKGCC=no and MKCXX=no
     -e                  just print environment, no builds
     -g version          handle GCC version <version> (GCC 4.1, 4.5 and 4.8 [default] supported)
     -G                  check GCC crtstuff
     -h                  print this help
     -j N                pass "-jN" to make
     -k                  ignore system failure
     -K                  ignore single arch failure
     -L                  display arch list as environment
     -M                  display arch list as machine:arch
     -n                  no run
     -N newconfigdir     set NEWCONFIGDIR env var (default: /home/current/src)
     -o baseobjdir       set objdir (default: /var/obj/mknative)
     -r                  do not build "<arch list>" (no default)
     -s srcdir           set srcdir (default: /usr/src)
     -T tool             tool to build (default "gcc")
     -v                  version
uptime options:
     -c                  do not obj/dependall/install crtstuff, csu
     -i                  do not do libgcc4 obj & includes
     -l                  do not obj/dependall/install libgcc or lib
     -m                  do not install gmp/mpfr/mpc
     -O                  do not to distrib-dirs, obj and global includes
     -S                  do not install in src/share/mk
     -t                  do not build tools
';

$opt_B = $opt_e = $opt_c = $opt_m = $opt_r = $opt_O = $opt_i = $opt_t = $opt_v = $opt_h = $opt_s = $opt_o = $opt_j = $opt_l = $opt_N = $opt_S = $opt_L = $opt_M = '';

$opt_n = 0;
$opt_k = 0;
$opt_K = 0;
$opt_G = 0;

Getopts('Bceg:Ghij:kKlLmMN:no:Ors:StT:v');

$opt_g = "4.8" if not defined $opt_g;
$opt_T = "gcc" if not defined $opt_T;

die $version if $opt_v;
die $help if $opt_h;

die $help if $opt_g ne "4.1" and $opt_g ne "4.5" and $opt_g ne "4.8";

my $srcdir = $opt_s || "/usr/src";
my $objdirbase = $opt_o || "/var/obj/mknative";
my $tool = $opt_T;
my $target = "native-$tool";

if ($tool eq "libgcc") {
	$target = "bootstrap-libgcc";
	$tool = "gcc";
	$opt_i = 1;
	$opt_l = 1;
	$opt_m = 1;
}

my $cur_machine = '';

# these are special since we don't normally install them so ./configure
# fails to find them.
my @gcc_dep_libs = ();

my $libgcc4;
my $libcrtstuff4;
if ($opt_g eq "4.1") {
	$libgcc4 = "$srcdir/gnu/lib/libgcc4";
	$libcrtstuff4 = "$srcdir/gnu/lib/crtstuff4";
	$ENV{HAVE_GCC} = "4";
} else {
	$libgcc4 = "$srcdir/external/gpl3/gcc/lib/libgcc";
	$libcrtstuff4 = "$srcdir/external/gpl3/gcc/lib/crtstuff";
	my $mpcdir = "$srcdir/external/lgpl3/mpc/lib/libmpc";
	if ( ! -f $mpcdir ) {
		my $mpcdir = "$srcdir/external/lgpl2/mpc/lib/libmpc";
	}
	@gcc_dep_libs = ("$srcdir/external/lgpl3/gmp/lib/libgmp",
			 "$srcdir/external/lgpl3/mpfr/lib/libmpfr",
			 $mpcdir);
	$ENV{HAVE_GCC} = ($opt_g eq "4.5") ? "45" : "48";
}
my $libcsu = "$srcdir/lib/csu";
my $libdes = "$srcdir/lib/libdes";
my $libc = "$srcdir/lib/libc";
my $liblua = "$srcdir/external/mit/lua/lib/liblua";
my $libm = "$srcdir/lib/libm";
my $lib = "$srcdir/lib";
my $sharemk = "$srcdir/share/mk";
my $tools_tooldir = "$srcdir/tools/$tool";

# force this on.
$ENV{MKMAINTAINERTOOLS} = "yes";

my @mkgcc = $opt_B ? ("MKGCC=no") : ();
my @mkcxx = $opt_B ? ("MKCXX=no") : ();

# anything else to add here?  MKPIC?
if (0) {
#$ENV{MKCRYPTO} = "no";
$ENV{MKLINT} = "no";
#$ENV{MKPROFILE} = "no";
#$ENV{MKSHARE} = "no";
$ENV{MKMAN} = "no";
$ENV{MKDOC} = "no";
$ENV{MKGDB} = "no";
$ENV{MKPUFFS} = "no";
$ENV{MKCROSSGDB} = "no";
$ENV{MKCOMPAT} = "no";
}
$ENV{MKINFO} = "no";
$ENV{MKHTML} = "no";
$ENV{MKRUMP} = "no";
$ENV{MAKECONF} = "/dev/null";
$ENV{MAKEVERBOSE} = "1";
if ($opt_N) {
	$ENV{NEWCONFIGDIR} = $opt_N;
} else {
	my $nsrcdir = $srcdir;
	$nsrcdir =~ s,^/usr/src,/home/current/src,;
	$nsrcdir =~ s,^/usr/([0-9]+)/src,/home/netbsd-$1/src,;
	$ENV{NEWCONFIGDIR} = $nsrcdir;
}

my @minusj = ();
@minusj = ("-j$opt_j") if $opt_j;

sub cmd {
	print "running: @_\n";
	if (not $opt_n and system (@_)) {
		return 1 if $opt_k;
		return 0 if $opt_K;
		die "system failed ($cur_machine): $?"
	}
	return 1;
}

sub cd {
	print "chdir to: $_[0]\n";
	return if $opt_n;
	chdir $_[0] or die "can't chdir $_[0]: $!\n";
}

mkdir "$objdirbase" unless -d "$objdirbase";

my $uname_s = `uname -s`; chomp $uname_s;
my $uname_r = `uname -r`; chomp $uname_r;
my $uname_m = `uname -m || uname -p`; chomp $uname_m;
$host_ostype = "$uname_s-$uname_r-$uname_m";

my %def_buildlist;
while (<DATA>) {
	next if /^#/;

	my ($machine, $arch);
	if (m/(\w+):(\w+)/) {
		$machine = $_;
		$arch = $2;
	} else {
		($machine, $arch) = split " ";
	}
	$def_buildlist{$machine} = $arch;
}

my %buildlist;
if (@ARGV) {
	while (@ARGV) {
		my $build_machine = shift @ARGV;
		my $arch;

		if ($build_machine =~ m/(\w+):(\w+)/) {
			$machine = $1;
			$arch = $2;
		} else {
			$machine = $build_machine;
			$arch = $def_buildlist{$machine};
		}

		die "don't know \"arch\" for $machine, try ${machine}:arch\n"
			unless $arch;
		$buildlist{$build_machine} = $arch;
	}
	if ($opt_r) {
		my %keeplist;
		my $machine;

		for $machine (keys %def_buildlist) {
			next if defined $buildlist{$machine};
			$keeplist{$machine} = $def_buildlist{$machine};
		}
		%buildlist = %keeplist;
	}
} else {
	%buildlist = %def_buildlist;
}

for my $machine (sort keys %buildlist) {
	my $arch;

	if ($machine =~ m/(\w+):(\w+)/) {
		$machine = $1;
		$arch = $2;
	} else {
		$arch = $buildlist{$machine};
	}

	if ($opt_L) {
		print "MACHINE=$machine MACHINE_ARCH=$arch\n";
		next;
	}

	if ($opt_M) {
		if ($machine eq $arch) {
			print "$machine\n";
		} else {
			print "${machine}:$arch\n";
		}
		next;
	}

	$cur_machine = $machine;

	# /var/obj/$MACHINE$MACHINE_ARCH:N$MACHINE:C/(.)/-\1/
	my $objdirbasemachine;
	if ($machine ne $arch) {
		$objdirbasemachine = "$objdirbase/${machine}-${arch}";
	} else {
		$objdirbasemachine = "$objdirbase/${machine}";
	}

	#$ENV{MAKEOBJDIRPREFIX} = $objdirbasemachine;

	if ($opt_e) {
		for my $e (keys %ENV) {
			print "$e=$ENV{$e}\n";
		}
		next;
	}

	print "MAKEOBJDIRPREFIX=$objdirbasemachine\n";
	mkdir "$objdirbasemachine" unless -d "$objdirbasemachine";

	cd $srcdir;
	my $tooldir = "$objdirbasemachine$srcdir/tooldir.$host_ostype";
	my $bindir = "$tooldir/bin";
	my $nbmake = "$bindir/nbmake-$machine";

	unless ($opt_t) {
		cmd "./build.sh", @minusj, "-M", $objdirbasemachine, "-uUm", $machine, "-a", $arch, "tools" or next;
	}

	unless ($opt_O) {
		my @tools = ("MKGCC=yes", "MKBFD=no");
		#@tools = ("MKGCC=no", "MKBFD=no");
		cmd $nbmake, @minusj, "obj", @tools or next;
		cmd $nbmake, @minusj, "do-distrib-dirs", @tools or next;
		cmd $nbmake, @minusj, "includes", @tools, @mkgcc or next;
	}

	unless ($opt_S) {
		cd $sharemk;
		cmd $nbmake, @minusj, "install" or next;
	}

	unless ($opt_i) {
		cd $libgcc4;
		cmd $nbmake, @minusj, "obj" or next;
		cmd $nbmake, @minusj, "includes" or next;
	}

	unless ($opt_c) {
		if ($opt_G) {
			print "running: $nbmake -V USE_COMPILERCRTSTUFF\n";
			my $gcc_crtstuff = `$nbmake -V USE_COMPILERCRTSTUFF`;
			chomp($gcc_crtstuff);
			print "got: $gcc_crtstuff\n";
			my @libs = ();
			if ($gcc_crtstuff eq "yes") {
				push @libs, $libcrtstuff4;
			}
		}
		push @libs, $libcsu;
		unless ($opt_i) {
			push @libs, $libgcc4;
		}
		for $dir (@libs) {
			cd $dir;
			cmd $nbmake, @minusj, "obj", "MKGCC=yes", "MKBFD=no" or next;
			cmd $nbmake, @minusj, "dependall", "MKGCC=yes", "MKBFD=no" or next;
			cmd $nbmake, @minusj, "install", "MKGCC=yes", "MKBFD=no" or next;
		}
	}

	unless ($opt_l) {
		#for $dir ($libc, $libm, $liblua, $lib) {
			#cd $dir;
			#cmd $nbmake, @minusj, "obj", @mkgcc, "MKBFD=no", @mkcxx or next;
			#cmd $nbmake, @minusj, "build_install", @mkgcc, "MKBFD=no", @mkcxx or next;
			#cmd $nbmake, @minusj, "install", @mkgcc, "MKBFD=no", @mkcxx or next;
		#}
		cd $lib;
		cmd $nbmake, @minusj, "build_install", @mkgcc, "MKBFD=no", @mkcxx or next;
	}

	unless ($opt_m) {
		if ($tool eq 'gcc') {
			for $dir (@gcc_dep_libs) {
				cd $dir;
				cmd $nbmake, @minusj, "obj", "LIBISPRIVATE=no", "MKPIC=no", "MKPROFILE=no" or next;
				cmd $nbmake, @minusj, "dependall", "LIBISPRIVATE=no", "MKPIC=no", "MKPROFILE=no" or next;
				cmd $nbmake, @minusj, "includes", "LIBISPRIVATE=no", "MKPIC=no", "MKPROFILE=no" or next;
				cmd $nbmake, @minusj, "install", "LIBISPRIVATE=no", "MKPIC=no", "MKPROFILE=no" or next;
			}
		}
	}

	unless ($tool eq '') {
		cd $tools_tooldir;

		cmd $nbmake, "obj", "$target" or next;
	}
}

exit

__DATA__
alpha alpha
amd64 x86_64
shark arm
evbarm:armeb
evbarm:earm
evbarm:earmeb
evbarm:earmhf
evbarm:earmhfeb
evbarm:earmv4
evbarm:earmv4eb
evbarm:earmv6
evbarm:earmv6eb
evbarm:earmv6hf
evbarm:earmv6hfeb
evbarm:earmv7
evbarm:earmv7eb
evbarm:earmv7hf
evbarm:earmv7hfeb
evbmips mips64el
#evbppc powerpc64
hppa hppa
landisk sh3el
i386 i386
macppc powerpc
mmeye sh3eb
mvme68k m68k
newsmips mipseb
pmax mipsel
sgimips mips64eb
sparc sparc
sparc64 sparc64
# not gcc
#evbarm64:aarch64
#evbarm64:aarch64eb
# not on netbsd-7
#riscv:riscv32
#riscv:riscv64
#or1k or1k
#evbcf coldfire
# sun2 doesn't work with gcc 4.8 (yet?)
sun2 m68000
vax vax
#ia64 ia64
