BEGIN {
if ($ENV{'PERL_LIB'}) {
push(@INC, $ENV{'PERL_LIB'});
} else {
my($plib) = `echo ~rcdev/xbs-Current/plib`;
chomp($plib);
push(@INC, $plib);
}
}
use File::Basename;
use Getopt::Long;
use Cwd;
select((select(STDOUT), $| = 1)[0]);
select((select(STDERR), $| = 1)[0]);
if ( $> ) {
my ($args) = join(' ', @ARGV);
($progname = $0) =~ s|^.*/||;
print "\n";
print "*** WARNING: buildit should be run as root. We recommend using the\n";
print "*** following command to run this buildit attempt as the root user:\n";
print "***\n";
print "*** sudo $progname $args\n";
sleep 10;
}
$ENV{GROUP} = 'wheel' if $> == 0;
$ENV{'PATH'} = '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin';
$ENV{'RC_OBJCUNIQUE_SILENT'} = 'YES';
$ENV{'INSTALLED_PRODUCT_ASIDES'} = 'YES';
$ENV{'SEPARATE_STRIP'} = 'YES';
umask(022);
@archList = (
'hppa',
'i386',
'm68k',
'ppc',
'ppc64',
'sparc'
);
chomp($hostname = `hostname`);
($buildit = $0) =~ s|^.*/(.*)$|$1|;
&main();
sub usage
{
print "@_\n" if @_;
print <<END_OF_USAGE;
Usage: $buildit <projectSourceDirectory>
[-release <release name>]
[-arch <archName>]*
[-noclean]
[-noinstall]
[-noinstallhdrs]
[-noinstallsrc]
[-noverify]
[-nosum]
[-noprebind]
[-noperms]
[-notilde]
[-merge <mergeDir>]
[-target <buildTarget>]
[-buildstyle <buildStyle>]
[-project <projectName>]
[-othercflags <cflags>]
[-- other arguments]
For more detailed information, enter \"$buildit -help\".
END_OF_USAGE
exit 1;
}
sub help
{
print <<END_OF_HELP;
Usage: $buildit projectSourceDirectory [build options] [-- other arguments]
Mandatory argument:
projectSourceDirectory The root directory of project source tree
(can be absolute or relative path to the project source tree)
Build options:
-release Use RC_CFLAGS (compiler flags) from specified release
(use release name like Cheetah, Puma, Jaguar, ...)
-arch <archName> Build with specified architectures(s)
(-arch can be multiply specified: -arch ppc -arch ppc64 -arch i386)
(default is native architecture if no -arch is specified)
-noclean Disables deletion of {OBJ,SYM,DST}ROOT before start of build
-noinstall Disables invocation of install (build) target
-noinstallhdrs Disables invocation of installhdrs target
-noinstallsrc Disables invocation of installsrc target
-noverify Disables verification of project DSTROOT after build
-nosum Disables before-and-after checksumming of project source
-noprebind Disables prebinding
-noperms Disables permissions setting on DSTROOT after build
-notilde Disables inclusion of '~' character in DSTROOT, etc., paths
-noarchwarn Disables warning about not building architecture for local machine
-merge <mergeDir> Merges resulting DSTROOT into \"mergeDir\"
-target <buildTarget> Specifies an alternate Make or Jam build target
-buildstyle <buildStyle> Specifies a ProjectBuilder buildstyle
-project <projectName> Project name to be used for verification exceptions
-othercflags <cflags> Specified cflags are appended to RC_CFLAGS for build
Other arguments:
Other arguments can be passed to the build (that is, to Make or Jam) by putting them
at the end of the buildit argument list following a double dash (\"--\").
Arguments that contain whitespace should be enclosed in quotes.
Examples:
buildit .
buildit myProjectDirectory -arch ppc
buildit myProjectDirectory -target install_debug
buildit myProjectDirectory -noinstall -merge /
buildit myProjectDirectory -noclean -othercflags \"-DMY_SWITCH -O3 -no-nasty-warnings\"
buildit myProjectDirectory -noinstallsrc -- -d \"NEXT_ROOT = /Network/Servers/builder/BuildRoot\"
END_OF_HELP
exit 0;
}
sub parseArgs
{
$release = '';
@archs = ();
$noclean = '';
$noinstall = '';
$noinstallhdrs = '';
$noinstallsrc = '';
$noverify = '';
$nosum = '';
$noprebind = '';
$noperms = '';
$notilde = '';
$noarchwarn = '';
$merge = '';
$target = '';
$buildstyle = '';
$project = '';
$othercflags = '';
$help = '';
&usage() unless @ARGV and GetOptions(
'release=s' => \$release,
'arch:s@' => \@archs,
'noclean' => \$noclean,
'noinstall' => \$noinstall,
'noinstallhdrs' => \$noinstallhdrs,
'noinstallsrc' => \$noinstallsrc,
'noverify' => \$noverify,
'nosum' => \$nosum,
'noprebind' => \$noprebind,
'noperms' => \$noperms,
'notilde' => \$notilde,
'noarchwarn' => \$noarchwarn,
'merge=s' => \$merge,
'target=s' => \$target,
'buildstyle=s' => \$buildstyle,
'project=s' => \$project,
'othercflags=s' => \$othercflags,
'help' => \$help,
);
&help() if $help;
$release = &defaultRelease() unless $release;
warn "**** WARNING **** Can't get the release name for the OS version on your machine\n" unless $release;
if (scalar(@archs) == 0) {
chomp(my ($arch) = `arch`);
push(@archs, $arch);
}
my @bogusArchs = ();
my %knownArch;
grep($knownArch{$_}++, @archList);
foreach my $arch ( @archs ) {
push(@bogusArchs, $arch) unless $knownArch{$arch};
}
die "**** ERROR **** The following specified archs are not supported by buildit: @bogusArchs\n" if @bogusArchs;
if ($merge and !$noarchwarn) {
my $myArch = `arch`;
chomp($myArch);
my @matches = grep(/^$myArch/, @archs);
unless (@matches) {
print "**** WARNING **** The root you are about to produce does not contain the architecture of the machine on which you're building. ";
while (1) {
print "Continue? ([y]/n) ";
chomp($reply = <STDIN>);
if ($reply eq "y" or $reply eq "Y" or $reply eq "") {
last;
}
if ($reply eq "n" or $reply eq "N") {
exit(1);
}
}
}
}
$rc = (getpwnam('rc'))[7];
$viewPath = "$rc/Software/$release" if $rc;
&usage("No project directory specified") unless @ARGV;
$projectSourceDirectory = shift(@ARGV);
@otherArguments = @ARGV;
}
sub main
{
my ($origNextRoot) = $ENV{'NEXT_ROOT'};
&parseArgs(); &sourceSetupForRelease($release);
if (!defined($ENV{'LD_SEG_ADDR_TABLE'})) {
my ($seg_addr_table) = "/AppleInternal/Developer/seg_addr_table";
if ( -f $seg_addr_table) {
print "setting LD_SEG_ADDR_TABLE to '$seg_addr_table'\n";
$ENV{'LD_SEG_ADDR_TABLE'} = $seg_addr_table;
}
}
print "setting LD_TWOLEVEL_NAMESPACE\n";
$ENV{'LD_TWOLEVEL_NAMESPACE'} = 'YES';
if ($origNextRoot) {
$NEXT_ROOT = $origNextRoot;
} elsif ($release eq 'Beaker' && &defaultRelease() ne 'Beaker') {
$NEXT_ROOT = '/Local/Public/MacOSX';
} else {
$setup = "$viewPath/Updates/Newest$release/.crossRoot";
if (-f $setup) {
chomp($NEXT_ROOT = `cat $setup`);
} else {
$NEXT_ROOT = defined($ENV{'NEXT_ROOT'}) ? $ENV{'NEXT_ROOT'} : '';
}
}
if ($noprebind) {
delete($ENV{'LD_PREBIND'});
} else {
$ENV{'LD_PREBIND'}='';
}
chdir($projectSourceDirectory)
|| die "Can't change directory to $projectSourceDirectory: $!\n";
$projectSourceDirectory = getcwd();
$projectVersion = &basename($projectSourceDirectory);
($project = $projectVersion) =~ s/^(.*)-.*$/$1/ unless $project;
($projectSourceVersion = $projectVersion) =~ s/^.*-(.*)$/$1/;
$projectSourceVersion = '' unless $projectSourceVersion and $projectSourceVersion ne $projectVersion;
&makeRootsDirectory($projectVersion);
if ($notilde) {
$srcRoot = "$rootsDirectory/$projectVersion";
$objRoot = "$rootsDirectory/$projectVersion.obj";
$symRoot = "$rootsDirectory/$projectVersion.sym";
$dstRoot = "$rootsDirectory/$projectVersion.dst";
$hdrObjRoot = "$rootsDirectory/$projectVersion.hdrObj";
$hdrSymRoot = "$rootsDirectory/$projectVersion.hdrSym";
$hdrDstRoot = "$rootsDirectory/$projectVersion.hdrDst";
$buildLog = "$rootsDirectory/$projectVersion.log";
$hdrLog = "$rootsDirectory/$projectVersion.hdrlog";
$preBom = "$rootsDirectory/$projectVersion.prebom";
$postBom = "$rootsDirectory/$projectVersion.postbom";
$subRoot = "/usr/local/objs";
} else {
$srcRoot = "$rootsDirectory/$projectVersion";
$objRoot = "$rootsDirectory/$projectVersion~obj";
$symRoot = "$rootsDirectory/$projectVersion~sym";
$dstRoot = "$rootsDirectory/$projectVersion~dst";
$hdrObjRoot = "$rootsDirectory/$projectVersion~hdrObj";
$hdrSymRoot = "$rootsDirectory/$projectVersion~hdrSym";
$hdrDstRoot = "$rootsDirectory/$projectVersion~hdrDst";
$buildLog = "$rootsDirectory/$projectVersion~log";
$hdrLog = "$rootsDirectory/$projectVersion~hdrlog";
$preBom = "$rootsDirectory/$projectVersion~prebom";
$postBom = "$rootsDirectory/$projectVersion~postbom";
$subRoot = "/usr/local/objs";
}
$ENV{'CC_PRINT_OPTIONS_FILE'} = "$symRoot/.CC_PRINT_OPTIONS"
if $ENV{'CC_PRINT_OPTIONS'};
&getBuildTool($projectSourceDirectory);
if ($noinstallsrc) {
$srcRoot = $projectSourceDirectory;
} else {
&installsrc();
}
&verifySrc($srcRoot)
unless $noverify;
&checksum($srcRoot, $preBom)
unless $nosum;
&cleanRoots($objRoot, $symRoot, $dstRoot,
$hdrObjRoot, $hdrSymRoot, $hdrDstRoot)
unless $noclean;
&buildParameters();
&build('installhdrs', $hdrLog)
unless $noinstallhdrs;
&setPerms($hdrDstRoot) unless $noinstallhdrs or $noperms;
&doMerge($hdrDstRoot, $hdrLog);
&build('install', $buildLog)
unless $noinstall;
&setPerms($dstRoot) unless $noinstall or $noperms;
&verify($dstRoot, $buildLog)
unless $noverify;
&doMerge($dstRoot, $buildLog);
&checksum($srcRoot, $postBom)
unless $nosum;
&compareBoms($preBom, $postBom)
unless $nosum;
print "\n*** $buildit ***: Done\n";
exit(0);
}
sub makeRootsDirectory
{
my($projectVersion) = @_;
if (defined($ENV{'BUILDIT_DIR'} && $ENV{'BUILDIT_DIR'})) {
$rootsDirectory = "$ENV{'BUILDIT_DIR'}/$projectVersion.roots";
} else {
$rootsDirectory = "/private/tmp/$projectVersion.roots";
}
&mkdirs($rootsDirectory) unless -d $rootsDirectory;
}
sub mkdirs
{
my($dir) = @_;
if (! -d $dir) {
&mkdirs(&dirname($dir));
mkdir($dir, 0755) || die "Can't mkdir $dir: $!\n";
}
}
sub getBuildTool
{
my($projectSourceDirectory) = @_;
$projectInfo = (-x '/usr/bin/projectInfo') ? '/usr/bin/projectInfo' : '';
if (!$projectInfo) {
$buildTool = 'make';
$buildDirectory = '';
$buildParams{'RC_OS'} = 'nextstep';
return;
}
if ( -f "$viewPath/Updates/Newest$release/.osName" ) {
chomp($buildParams{'RC_OS'} = `cat $viewPath/Updates/Newest$release/.osName`);
} elsif ( -f "$viewPath/.osName" ) {
chomp($buildParams{'RC_OS'} = `cat $viewPath/.osName`);
} elsif ( -f "$viewPath/.releaseOSName" ) {
chomp($buildParams{'RC_OS'} = `cat $viewPath/.releaseOSName`);
} else {
if ( -d "/System/Developer/Makefiles/pb_makefiles" ) {
$buildParams{'RC_OS'} = 'teflon';
} elsif ( -f "$NEXT_ROOT/NextDeveloper/Makefiles/pb_makefiles/platform.make" ) {
$platformFile = "$NEXT_ROOT/NextDeveloper/Makefiles/pb_makefiles/platform.make";
open(PLATFORMFILE, "< $platformFile")
|| die "Can't open $platformFile: $!\n";
while (<PLATFORMFILE>) {
m/^\s*(\S*)\s*=\s*(\S*)\s*$/;
if ($1 eq 'PLATFORM_OS') {
$buildParams{'RC_OS'} = $2;
}
}
close(PLATFORMFILE);
if (!$buildParams{'RC_OS'}) {
die "Can't get PLATFORM_OS value from $platformFile\n";
}
} else { $buildParams{'RC_OS'} = 'nextstep';
}
}
chomp($buildTool = `$projectInfo NEXTSTEP_BUILDTOOL -inDirectory "$projectSourceDirectory"`);
die "$projectInfo reported errors accessing key NEXTSTEP_BUILDTOOL in $projectSourceDirectory"
if $?;
if (!$buildTool) {
chomp($buildTool = `$projectInfo BUILDTOOL -inDirectory "$projectSourceDirectory"`);
die "$projectInfo reported errors accessing key BUILDTOOL in $projectSourceDirectory"
if $?;
}
if (!$buildTool) {
$buildTool = 'make';
$buildDirectory = '';
return;
}
$buildDirectory = `$projectInfo NEXTSTEP_BUILDDIR -inDirectory "$projectSourceDirectory"`;
die "$projectInfo reported errors accessing key NEXTSTEP_BUILDDIR in $projectSourceDirectory"
if $?;
if (!$buildDirectory) {
$buildDirectory = `$projectInfo BUILDDIR -inDirectory "$projectSourceDirectory"`;
die "$projectInfo reported errors accessing key BUILDDIR in $projectSourceDirectory"
if $?;
}
chomp($buildDirectory);
}
sub installsrc
{
if (-d $srcRoot) {
print "\n*** $buildit ***: Removing existing SRCROOT $srcRoot ...\n";
&removeDirectory($srcRoot);
}
&mkdirs($srcRoot);
print "\n*** $buildit ***: Invoking installsrc target ...\n";
print "$buildTool installsrc \"SRCROOT=$srcRoot\"\n";
system($buildTool, 'installsrc', "SRCROOT=$srcRoot");
if ($?) {
print "Removing $srcRoot ... ";
&removeDirectory($srcRoot);
exit 1;
}
print "\n*** $buildit ***: Cleaning the installed sources ...\n";
chdir($srcRoot)
|| die "Can't change directory to $srcRoot: $!\n";
if (!$buildDirectory) {
print "$buildTool clean \"SRCROOT=$srcRoot\"\n";
system($buildTool, 'clean', "SRCROOT=$srcRoot");
if ($?) {
chdir("/")
|| die "Can't change directory to /: $!\n";
print "Removing $srcRoot ... ";
&removeDirectory($srcRoot);
exit 1;
}
} else {
print "$buildTool clean " .
"\"SRCROOT=$srcRoot\" " .
"\"OBJROOT=$srcRoot\" " .
"\"SYMROOT=$srcRoot\"\n";
system($buildTool, 'clean',
"SRCROOT=$srcRoot",
"OBJROOT=$srcRoot",
"SYMROOT=$srcRoot");
if ($?) {
chdir("/")
|| die "Can't change directory to /: $!\n";
print "Removing $srcRoot ... ";
&removeDirectory($srcRoot);
exit 1;
}
}
print "\n*** $buildit ***: Chmod'ing $srcRoot ...\n";
system('chmod', '-R', 'a-w', $srcRoot);
if ($?) {
chdir("/")
|| die "Can't change directory to /: $!\n";
print "Removing $srcRoot ... ";
&removeDirectory($srcRoot);
exit 1;
}
}
sub scanForDylibsWithBadInstallNames
{
my($dstroot) = @_;
return unless -x "/usr/local/bin/check_dylib";
return unless -x "/usr/bin/redo_prebinding";
return unless -f "/Local/Developer/seg_addr_table";
my($cwd) = getcwd();
chdir($dstroot) or die "**** ERROR **** Can't chdir to $dstroot\n";
open(FIND, "find . -type f -exec /usr/bin/redo_prebinding -i -d {} \\; -print |")
or die "Can't run find command on $dstroot\n";
$dylibError = 0;
while ($foundDylib = <FIND>) {
chomp($foundDylib);
$foundDylib =~ s|^\.||;
$foundDylibPath = "$dstroot$foundDylib";
$cmd = "/usr/local/bin/check_dylib $foundDylibPath -install_name $foundDylib -seg_addr_table /Local/Developer/seg_addr_table";
$checkStat = system($cmd);
$checkStat >>= 8;
if ($checkStat == 2) {
$dylibError = 1;
print "\n**** ERROR **** Dylib $foundDylibPath has an incorrect install_name. The incorrect install_name can be examined by running \"otool -L $foundDylibPath\". The correct install_name is $foundDylib\n";
}
}
close(FIND);
print "\n";
if ($dylibError) {
exit(1);
}
chdir($cwd) or die "**** ERROR **** Can't chdir to $cwd\n";
}
sub setPerms
{
my($dstRoot) = @_;
my($rcdev) = (getpwnam('rcdev'))[7];
print "\n*** $buildit ***: Setting permissions in $dstRoot ...\n";
if ( ! -f "$rcdev/plib/Permissions.pm" ) {
warn "Can't find Permissions.pm, permissions will not be set\n";
return;
}
require "Permissions.pm";
&Permissions::applyPermissionsToDirectory($viewPath, $dstRoot);
}
sub verify
{
my($dstroot, $log) = @_;
local($verifyStatus, $verifyLog, $plib, $fatal);
local($rcdev) = (getpwnam('rcdev'))[7];
print "\n*** $buildit ***: Verifying $project $dstroot ...\n";
&scanForDylibsWithBadInstallNames($dstroot);
if ( ! -f "$rcdev/plib/Verify.pm" ) {
warn "Can't find ~rcdev/plib/Verify.pm, skipping verification\n";
return;
}
require "Verify.pm";
&Verify::readVerifyConfig("Newest$release");
$verifyStatus = &Verify::verifyProject($project, $dstroot);
$verifyLog = &Verify::errorLog();
if ($verifyLog) {
$fatal = ($verifyStatus) ? ", and the overall project build has failed" : "";
print "\nYour project has verification failures$fatal. The list of verification failures follows below.\n\n";
print "Consult the following web page for descriptions of these errors:\n\n";
print " http://xbs.apple.com/Docs/Verification.html\n\n";
print "The verification failures are:\n\n";
print "$verifyLog";
open(LOG, ">>$log")
|| die "Can't open $log: $!\n";
select(LOG); $| = 1;
select(STDOUT);
print LOG "\nYour project has verification failures$fatal. The list of verification failures follows below.\n\n";
print LOG "Consult the following web page for descriptions of these errors:\n\n";
print LOG " http://xbs.apple.com/Docs/Verification.html\n\n";
print LOG "The verification failures are:\n\n";
print LOG "$verifyLog";
close(LOG);
die ("Verification failed with exit status $verifyStatus\n") if ($verifyStatus);
}
}
sub verifySrc
{
my($srcroot) = @_;
local($verifyStatus, $verifyLog, $plib, $fatal);
local($rcdev) = (getpwnam('rcdev'))[7];
print "\n*** $buildit ***: Verifying $project $srcroot ...\n";
if ( ! -f "$rcdev/plib/Verify.pm" ) {
warn "Can't find ~rcdev/plib/Verify.pm, skipping verification\n";
return;
}
require "Verify.pm";
my $verifyConfig = -e "$viewPath/.Verification/SourceVerify.config" ?
"$viewPath/.Verification/SourceVerify.config" :
"$rcdev/xbs-Current/config/SourceVerify.config";
$verifyConfig = "SourceVerify.config" unless -e verifyConfig;
if (&Verify::readConfigFile($verifyConfig)) {
print "skipping ... \n";
return;
}
$verifyStatus = &Verify::verifyProject($project, $srcroot);
$verifyLog = &Verify::errorLog();
if ($verifyLog) {
$fatal = ($verifyStatus) ? ", and the overall project build has failed" : "";
print "\nYour project sources have verification failures$fatal. The list of verification failures follows below.\n\n";
print "Consult the following web page for descriptions of these errors:\n\n";
print " http://xbs.apple.com/Docs/Verification.html\n\n";
print "The verification failures are:\n\n";
print "$verifyLog";
die ("Verification failed with exit status $verifyStatus\n") if ($verifyStatus);
}
}
sub checksum
{
my($directory, $bomFile) = @_;
if (-f $bomFile) {
unlink($bomFile)
|| die "Can't unlink $bomFile: $!\n";
}
print "\n*** $buildit ***: Checksumming $srcRoot ...\n";
executeCommand('mkbom', $directory, $bomFile);
}
sub compareBoms
{
my($bom1, $bom2) = @_;
my($tmp1, $tmp2) = ("$bom1.lsbom", "$bom2.lsbom");
my($diffFile) = &dirname($bom1) . "/bomDiff.$$";
print "\n*** $buildit ***: Comparing source checksums ...\n";
die "$bom1: $?\n"
if system("lsbom $bom1 | sort > $tmp1");
die "$bom2: $?\n"
if system("lsbom $bom2 | sort > $tmp2");
system("diff $tmp1 $tmp2 > $diffFile");
if (-s $diffFile) {
print "**** WARNING **** The following project source files were modified:\n";
system("cat $diffFile");
}
unlink($tmp1, $tmp2, $diffFile);
}
sub cleanRoots
{
my(@roots) = @_;
print "\n*** $buildit ***: Cleaning up the binary roots ...\n";
foreach $root (@roots) {
&removeDirectory($root)
if -d $root;
&mkdirs($root);
}
}
sub defaultRelease {
local($file, $result, @list);
if ( -x '/usr/bin/sw_vers' ) {
open(SW_VERS, "/usr/bin/sw_vers |")
or die "**** ERROR **** Can't run /usr/bin/sw_vers: $!\n";
while ($line = <SW_VERS>) {
next unless $line =~ m|BuildVersion:|;
chomp($line);
$systemBuildVersion = (split('\s+', $line))[1];
last if $systemBuildVersion;
}
close(SW_VERS);
if ($systemBuildVersion) {
($majorNumber = $systemBuildVersion) =~ s|^([0-9]+).*$|$1|;
if ($majorNumber) {
$mapFile = `echo ~rc/Data/release_to_majorNumber.map`;
chomp($mapFile);
if ( -f $mapFile) {
open(MAPFILE, "< $mapFile")
or die "**** ERROR **** Can't open $mapFile: $!\n";
while ($entry = <MAPFILE>) {
next unless $entry =~ m|^\s*[0-9]|;
chomp($entry);
$entry =~ s|^\s+||;
($number, $releaseName) = split('\s+', $entry);
if ($number == $majorNumber) {
return $releaseName;
}
}
}
}
}
}
@list = (
'/System/Library/CoreServices/release_name',
'/System/Library/CoreServices/software_version',
'/NextLibrary/CoreServices/release_name',
'/NextLibrary/CoreServices/software_version',
'/usr/lib/NextStep/software_version',
);
foreach $file (@list) {
if (-f $file) {
chomp ($result = `cat $file | tail -1`);
$result =~ s/\d+[a-zA-Z]\d*[a-z]?$//;
last;
}
}
return $result;
}
sub cflagsForRelease {
local($release) = @_;
local($result,$setup, @lines, $line);
$setup = "$viewPath/Updates/Newest$release/.setupBuildEnvironment";
if (-f $setup) {
open (SETUP, $setup) or die ("can't open $file: $_");
chomp(@lines = <SETUP>);
close(SETUP);
foreach $line (@lines) {
if ($line =~ /^setenv MORE_RC_CFLAGS/) {
($result = $line) =~ s/^setenv MORE_RC_CFLAGS//;
$result =~ s/^\s*\"(.*)\"\s*$/$1/;
last;
}
}
}
return $result;
}
sub sourceSetupForRelease {
local($release) = @_;
local($key, $value ,$setup, @lines, $line);
$setup = "$viewPath/Updates/Newest$release/.setupBuildEnvironment";
if (-f $setup) {
open (SETUP, $setup) or die ("can't open $file: $_");
chomp($top = <SETUP>);
close(SETUP);
if ($top =~ /perl/) {
eval (`cat $setup`) || die ("can't eval setup file: $file");
} else {
system ("/bin/echo unsetenv \\* > /tmp/setup.$$");
system ("/bin/cat $setup >> /tmp/setup.$$");
system ("/bin/echo printenv >> /tmp/setup.$$");
chomp ($line = `/bin/csh /tmp/setup.$$`);
@lines = split ('\n', $line);
foreach (@lines) {
if (/^(\S+)=(.*)$/) {
$ENV{$1}=$2;
}
}
unlink "/tmp/setup.$$";
}
}
}
sub buildParameters
{
foreach $arch (@archList) {
$buildParams{"RC_$arch"} = '';
}
$buildParams{'RC_ARCHS'} = join(' ', @archs);
foreach $arch (@archs) {
if ($buildParams{'RC_CFLAGS'}) {
$buildParams{'RC_CFLAGS'} .= " -arch $arch";
} else {
$buildParams{'RC_CFLAGS'} = "-arch $arch";
}
$buildParams{"RC_$arch"} = 'YES';
}
$buildParams{'RC_CFLAGS'} .= " -pipe";
$buildParams{'RC_NONARCH_CFLAGS'} = "-pipe";
$buildParams{'RC_CFLAGS'} .= " $othercflags"
if $othercflags;
$buildParams{'RC_NONARCH_CFLAGS'} .= " $othercflags"
if $othercflags;
$buildParams{'RC_CFLAGS'} .= " $ENV{'MORE_RC_CFLAGS'}"
if (defined($ENV{'MORE_RC_CFLAGS'}));
$buildParams{'RC_NONARCH_CFLAGS'} .= " $ENV{'MORE_RC_CFLAGS'}"
if (defined($ENV{'MORE_RC_CFLAGS'}));
if ($release) {
$buildParams{'RC_RELEASE'} = $release;
} else {
$buildParams{'RC_RELEASE'} = 'undefined';
}
$ENV{'RC_XBS'} = 'YES';
$buildParams{'RC_XBS'} = "$ENV{'RC_XBS'}";
$ENV{'RC_JASPER'} = 'YES';
$buildParams{'RC_JASPER'} = "$ENV{'RC_JASPER'}";
$ENV{'NEXT_ROOT'} = $NEXT_ROOT if $NEXT_ROOT;
}
sub removeDirectory
{
my($directory) = @_;
&executeCommand('find', $directory, '-type', 'd', '-exec', 'chmod', '+w', '{}', ';');
&executeCommand('rm', '-rf', $directory);
}
sub writeLogHeader
{
my($phase) = @_;
$plusLine = "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
open(CC, "cc -v 2>&1 |") or die "**** ERROR **** cc -v failed: $!";
while (<CC>) {
next unless /version/;
s/^.*Inc\. //;
$ccVersion = $_;
chomp($ccVersion);
last;
}
close(CC);
my($cctoolsADotOut) = "/tmp/__XX__buildit__cctools.a.out__XX__";
open(CCTOOLS, "as -v < /dev/null -o $cctoolsADotOut 2>&1 |") or die "**** ERROR **** as -v: $!";
while (<CCTOOLS>) {
next unless /version/;
s/^.*Inc\. //;
$ccToolsVersion = $_;
chomp($ccToolsVersion);
last;
}
close(CCTOOLS);
unlink($cctoolsADotOut);
print LOG $plusLine;
printf LOG "STARTING $buildit ($phase) of $projectVersion on %s", `date`;
print LOG $plusLine;
print LOG "Build configuration:\n";
print LOG " Build host: $hostname\n";
print LOG " Build Tool: $buildTool\n";
printf LOG " Build Target: %s\n", ($target ? $target : $phase);
print LOG " Target Update: \n";
print LOG " Build Layer: \n";
printf LOG " Search path: %s\n", $ENV{'PATH'};
print LOG " cc version: $ccVersion\n";
print LOG " cctools version: $ccToolsVersion\n";
print LOG $plusLine;
print LOG "Build parameters are:\n";
print LOG " SRCROOT: $srcRoot\n";
if ($phase eq 'install') {
print LOG " OBJROOT: $objRoot\n";
print LOG " SYMROOT: $symRoot\n";
print LOG " DSTROOT: $dstRoot\n";
} else {
print LOG " OBJROOT: $hdrObjRoot\n";
print LOG " SYMROOT: $hdrSymRoot\n";
print LOG " DSTROOT: $hdrDstRoot\n";
}
print LOG " RC_ProjectName: $project\n";
print LOG " RC_ProjectSourceVersion: $projectSourceVersion\n";
print LOG " RC_ProjectBuildVersion: 1\n";
print LOG " RC_ReleaseStatus: Development\n";
printf LOG " RC_CFLAGS: %s\n", $buildParams{'RC_CFLAGS'};
printf LOG " RC_NONARCH_CFLAGS: %s\n", $buildParams{'RC_NONARCH_CFLAGS'};
printf LOG " RC_ARCHS: %s\n", $buildParams{'RC_ARCHS'};
printf LOG " RC_hppa: %s\n", $buildParams{'RC_hppa'};
printf LOG " RC_i386: %s\n", $buildParams{'RC_i386'};
printf LOG " RC_m68k: %s\n", $buildParams{'RC_m68k'};
printf LOG " RC_ppc: %s\n", $buildParams{'RC_ppc'};
printf LOG " RC_ppc64: %s\n", $buildParams{'RC_ppc64'};
printf LOG " RC_sparc: %s\n", $buildParams{'RC_sparc'};
printf LOG " RC_RELEASE: %s\n", $buildParams{'RC_RELEASE'};
printf LOG " RC_OS: %s\n", $buildParams{'RC_OS'};
print LOG " RC_DEVROOT: \n";
printf LOG " RC_XBS: %s\n", $buildParams{'RC_XBS'};
printf LOG " RC_JASPER: %s\n", $buildParams{'RC_JASPER'};
printf LOG " NEXT_ROOT: %s\n", $NEXT_ROOT;
printf LOG " Prebinding: %s\n", (exists($ENV{'LD_PREBIND'}) ? "YES" : "NO");
printf LOG " Other Args: %s\n", join(' ', @otherArguments);
print LOG $plusLine;
print LOG "Environment variables:\n";
my($maxLength) = 0;
for $envVar ( keys(%ENV) ) {
$keyLength = length($envVar);
$maxLength = $keyLength if $keyLength > $maxLength;
}
for $envVar ( sort(keys(%ENV)) ) {
printf LOG "%-${maxLength}s \"%s\"\n", $envVar, $ENV{$envVar};
}
print LOG $plusLine;
}
sub writeLogFooter
{
my($phase) = @_;
print LOG "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
printf LOG "FINISHED $buildit ($phase) of $projectVersion on %s", `date`;
print LOG "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
}
sub doMake
{
my($log, $phase) = @_;
MAKEFORK:
{
if ($pid = fork()) { close(WRITE);
while(<READ>) {
print LOG $_;
print $_;
}
waitpid($pid, 0);
my($childStatus) = $? / 256;
exit($childStatus) if $childStatus;
exit(0);
} elsif (defined($pid)) { close(READ);
close(STDOUT);
close(STDERR);
open(STDOUT, ">&WRITE")
|| die "Can't dupe STDOUT to WRITE\n";
open(STDERR, ">&WRITE")
|| die "Can't dupe STDERR to WRITE\n";
&printMakeCommand();
exec(@makeCommand);
} elsif ($! =~ /No more process/) {
sleep 5;
redo MAKEFORK;
} else {
die "$buildit: Can't fork make process: $!\n";
}
}
}
sub doMerge
{
my($root, $log) = @_;
my($mergeSrc);
return unless $merge;
open(LOG, ">>$log")
|| die "Can't open $log: $!\n";
select(LOG); $| = 1;
select(STDOUT);
print LOG "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
printf LOG "Merging $root to $merge\n";
print LOG "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
print "\n*** $buildit ***: Merging $root to $merge\n";
&mkdirs($merge);
open(SAVEOUT, ">&STDOUT");
open(SAVEERR, ">&STDERR");
open(STDOUT, ">&LOG") || die "Can't open $log: $!\n";
open(STDERR, ">&LOG") || die "Can't open $log: $!\n";
&executeCommand("ditto -V $root $merge");
close(STDOUT);
close(STDERR);
open(STDOUT, ">&SAVEOUT") || die "Can't open $log: $!\n";
open(STDERR, ">&SAVEERR") || die "Can't open $log: $!\n";
close(SAVEOUT);
close(SAVEERR);
close(LOG);
}
sub doTee
{
my($log, $phase) = @_;
TEEFORK:
{
if ($pid = fork()) { waitpid($pid, 0);
exit($? / 256) if $?;
} elsif (defined($pid)) { pipe(READ, WRITE);
&doMake($log, $phase);
} elsif ($! =~ /No more process/) {
sleep 5;
redo TEEFORK;
} else {
die "$buildit: Can't fork tee process: $!\n";
}
}
}
sub consMakeCommand
{
my($phase) = @_;
@makeCommand = ();
push(@makeCommand, $buildTool);
if ($buildTool =~ /(pb)|(pbx)|(xcode)build$/) {
push(@makeCommand, $phase);
push(@makeCommand, '-target', $target) if $target;
push(@makeCommand, '-buildstyle', $buildstyle) if $buildstyle;
} else { if ($phase eq 'install') {
push(@makeCommand, ($target ? $target : $phase));
} else {
push(@makeCommand, $phase);
}
}
push(@makeCommand, "SRCROOT=$srcRoot");
if ($phase eq 'install') {
push(@makeCommand, "OBJROOT=$objRoot");
push(@makeCommand, "SYMROOT=$symRoot");
push(@makeCommand, "DSTROOT=$dstRoot");
} else {
push(@makeCommand, "OBJROOT=$hdrObjRoot");
push(@makeCommand, "SYMROOT=$hdrSymRoot");
push(@makeCommand, "DSTROOT=$hdrDstRoot");
}
push(@makeCommand, "SUBLIBROOTS=$subRoot");
push(@makeCommand, "RC_XBS=$buildParams{'RC_XBS'}");
push(@makeCommand, "RC_JASPER=$buildParams{'RC_JASPER'}");
push(@makeCommand, "RC_CFLAGS=$buildParams{'RC_CFLAGS'}");
push(@makeCommand, "RC_NONARCH_CFLAGS=$buildParams{'RC_NONARCH_CFLAGS'}");
push(@makeCommand, "RC_ARCHS=$buildParams{'RC_ARCHS'}");
push(@makeCommand, "RC_hppa=$buildParams{'RC_hppa'}");
push(@makeCommand, "RC_i386=$buildParams{'RC_i386'}");
push(@makeCommand, "RC_m68k=$buildParams{'RC_m68k'}");
push(@makeCommand, "RC_ppc=$buildParams{'RC_ppc'}");
push(@makeCommand, "RC_ppc64=$buildParams{'RC_ppc64'}");
push(@makeCommand, "RC_sparc=$buildParams{'RC_sparc'}");
push(@makeCommand, "RC_OS=$buildParams{'RC_OS'}");
push(@makeCommand, "RC_RELEASE=$buildParams{'RC_RELEASE'}");
push(@makeCommand, "RC_ProjectName=$project");
push(@makeCommand, "RC_ProjectSourceVersion=$projectSourceVersion");
push(@makeCommand, "RC_ProjectBuildVersion=1");
push(@makeCommand, "RC_ReleaseStatus=Development");
push(@makeCommand, "NEXT_ROOT=$NEXT_ROOT");
push(@makeCommand, @otherArguments);
}
sub printMakeCommand
{
for ($i = 0; $i <= $ if ($makeCommand[$i] =~ /\s/) {
print "\"$makeCommand[$i]\" ";
} else {
print "$makeCommand[$i] ";
}
}
print "\n";
}
sub build
{
my($phase, $log) = @_;
print "\n*** $buildit ***: $buildTool $phase ...\n";
open(LOG, ">$log")
|| die "Can't open $log: $!\n";
select(LOG); $| = 1;
select(STDOUT);
&writeLogHeader($phase);
&consMakeCommand($phase);
&doTee($log, $phase);
&writeLogFooter($phase);
close(LOG);
}
sub executeCommand
{
system(@_);
if ( $? ) {
$lowByte = ($? & 0377);
if ($lowByte == 0177) {
die "Command \"@_\" has been stopped\n";
} elsif ($lowByte) {
$sigNum = ($lowByte & 0177);
print "Command \"@_\" was terminated by signal $sigNum.\n";
if ($lowByte & 0200) {
print "Core dumped.\n";
}
exit 1;
}
$childExitStatus = (($? >> 8) & 0377);
die "Command \"@_\" failed with exit status $childExitStatus\n" ;
}
}
sub printenv {
foreach (sort keys %ENV) {
print "$_: $ENV{$_}\n";
}
}