#!/usr/local/bin/perl

# Take a .a file (or files) and make a corresponding .so for it.
# Unbundles the .as and rebundles them as a .so

use strict;
use Cwd ( );
use File::Basename ( );
use File::Copy ( );
use File::Find ( );
use File::Path ( );
use File::Spec ( );

my $usage = "mksofora.pl so-file a-file1 a-file2 ...";

my ($soFile, @aoFiles) = @ARGV;

(defined($soFile) && ($soFile =~ /\.so$/)) or die($usage);
(scalar(@aoFiles) > 0) or die($usage);

my @bad = grep { ($_ !~ /\.a$/) && ($_ !~ /\.o$/) } @aoFiles;
(scalar(@bad) == 0) or die($usage);

$soFile = mkAbs($soFile);
@aoFiles = map { mkAbs($_) } @aoFiles;

my $rand = int(rand() * 0xFFFF);

my $messDir = Cwd::cwd() . "/mess$rand";

(! -d $messDir) or die($messDir);
mkdir($messDir, 0777) or die($messDir);

my $origDir = Cwd::cwd();

Cwd::chdir($messDir);


# extract all the .o files from the .a files
# each .a gets its own subdirectory to avoid name collision
for (@aoFiles) {
	my $a = $_;
	# At this point $a is a full path and is NEVER in the directory
	# we are about to make.
	my $aBase = File::Basename::basename($a);
	my $d = $aBase . "_dir";
	mkdir($d, 0777) or die($d);
	Cwd::chdir($d) or die($d);
	if ($a =~ /\.o$/) {
		# The argument is just a .o
		File::Copy::copy($a, $aBase);
	} else {
		# .a, so break it down
		system("ar -x " . $a);
	}
	Cwd::chdir($messDir) or die($messDir);
}

@main::oFiles = ( );
File::Find::find(\&wantDotO, $messDir);


my $cmd = "CC -o $soFile -G " . join(" ", @main::oFiles);

system($cmd);

Cwd::chdir($origDir);

File::Path::rmtree($messDir);

exit;
############

sub wantDotO {
	my $bn = $_;
	if (-f $bn && $bn =~ /\.o$/) {
		push(@main::oFiles, $File::Find::name);
	}
}

sub mkAbs {
	# would rather use $File::Spec->rel2abs( ) but for some reason that
	# disappeared
	my ($fn, @extra) = @_;
	my $dn = File::Basename::dirname($fn);
	my $bn = File::Basename::basename($fn);
	$dn = Cwd::abs_path($dn);
	return $dn . '/' . $bn;
}
