#!/usr/bin/perl | |
# | |
# Copyright Statement: | |
# -------------------- | |
# This software is protected by Copyright and the information contained | |
# herein is confidential. The software may not be copied and the information | |
# contained herein may not be used or disclosed except with the written | |
# permission of MediaTek Inc. (C) 2011 | |
# | |
# BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES | |
# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") | |
# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON | |
# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, | |
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF | |
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. | |
# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE | |
# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR | |
# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH | |
# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO | |
# NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S | |
# SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. | |
# | |
# BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE | |
# LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, | |
# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, | |
# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO | |
# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. | |
# | |
# THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE | |
# WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF | |
# LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND | |
# RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER | |
# THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC). | |
# | |
#***************************************************************************** | |
use strict; | |
use warnings; | |
use Cwd; | |
use Cwd 'abs_path'; | |
use Data::Dumper; | |
use File::Path; | |
use File::Basename; | |
use File::Compare; | |
use File::Copy; | |
use Getopt::Long; | |
my @_argv = ($0, @ARGV); | |
my $_argc = $#_argv + 1; | |
# ----------------------------------------------------------------------------- | |
my $Version = "20110428"; | |
# ----------------------------------------------------------------------------- | |
# Workaround. | |
my @ExcludedLib = ( | |
# Function kal_mem_cpy will be placed in SECONDARY_ROM and be used before ready due to multiply definition from kal_release.h. | |
'custom.lib', | |
# In file variant.cpp, static variables of class type are used, and it results in indeterminate order of initialization. | |
'gadget_lib.lib', | |
# For customer do vendor release | |
'gis.lib', | |
'init.lib', | |
# Different bin files in MAUI | |
'che.lib', | |
'bootloader.lib', | |
'fota.lib', | |
'sst_sec.lib', | |
'ssf.lib', | |
'lqt.lib', | |
# ... | |
); | |
# Ignore the following libraries for checking (see checkLib). | |
my %IgnoredLib = ( | |
"verno.lib" => 1, | |
); | |
# ----------------------------------------------------------------------------- | |
# Set default command. | |
my $Cmd_nm = ""; | |
my $Cmd_readelf = ""; | |
my $Cmd_strip = ""; | |
my $Cmd_armar = "armar"; | |
my $Cmd_armlink = "armlink"; | |
# ----------------------------------------------------------------------------- | |
# System Utilities | |
# Set default debug level. | |
my $DbgLevel = 1; | |
# Set default info level to display message in the screen. | |
my $InfoLevel = 0; | |
# Set current directory. | |
my $DirCur = cwd(); | |
# Set default temporary directory. | |
my $DirTemp = $DirCur . "/pl_temp"; | |
# Set default log file. | |
my $FileLog = $DirCur . "/" . basename(__FILE__) . ".log"; | |
unlink($FileLog); | |
# Set default err file. | |
my $FileErr = $DirCur . "/" . basename(__FILE__) . ".err"; | |
unlink($FileErr); | |
# Set default temporary file. | |
my $FileTmp = $DirCur . "/" . basename(__FILE__) . ".tmp"; | |
unlink($FileTmp); | |
my $Current_time = time; | |
# Write file specified by a global variable $FileLog. | |
sub sysWriteLog | |
{ | |
my ($log) = @_; | |
if (open(FILE_LOG, ">>" . $FileLog)) | |
{ | |
print(FILE_LOG $log); | |
close(FILE_LOG); | |
} | |
} | |
sub sysWriteErr | |
{ | |
my ($log) = @_; | |
if (open(FILE_LOG, ">>" . $FileLog)) | |
{ | |
print(FILE_LOG $log); | |
close(FILE_LOG); | |
} | |
if (open(FILE_ERR, ">>" . $FileErr)) | |
{ | |
print(FILE_ERR $log); | |
close(FILE_ERR); | |
} | |
} | |
BEGIN | |
{ | |
my $_dying = 0; | |
my $_msg = ""; | |
my $_ptrSub = 0; | |
my @_ptrArgs = (); | |
sub sysDieRegister | |
{ | |
my ($ptrSub, @ptrArgs) = @_; | |
$_ptrSub = $ptrSub; | |
@_ptrArgs = @ptrArgs; | |
} | |
sub sysDie | |
{ | |
my ($msg) = @_; | |
if (($_dying == 0) && $_ptrSub) | |
{ | |
$_dying = 1; | |
$_msg = $msg; | |
$_ptrSub->(@_ptrArgs); | |
$_dying = 0; | |
} | |
system("date/T >>" . $FileLog); | |
system("time/T >>" . $FileLog); | |
$msg = $_msg . "\n" . $msg if ($_dying); | |
die($msg); | |
} | |
} | |
# ----------------------------------------------------------------------------- | |
# Basic Utilities | |
sub utlDump | |
{ | |
my ($level, $ptr) = @_; | |
if (($level <= $InfoLevel) || ($level <= $DbgLevel)) | |
{ | |
my $msg = Dumper($ptr); | |
print($msg) if ($level <= $InfoLevel); | |
&sysWriteLog($msg) if ($level <= $DbgLevel); | |
} | |
} | |
sub utlSrcLoc | |
{ | |
my ($level) = @_; | |
my $filename = (caller($level + 1))[1]; | |
my $line = (caller($level))[2]; | |
my $subr = (caller($level + 1))[3]; | |
$subr =~ s/^.*://; | |
return "[" . $filename . ":" . $subr . ":" . $line . "]"; | |
} | |
sub utlLog | |
{ | |
my ($level, $msg) = @_; | |
if (($level <= $InfoLevel) || ($level <= $DbgLevel)) | |
{ | |
print($msg) if ($level <= $InfoLevel); | |
&sysWriteLog(&utlSrcLoc(1) . " " . $msg) if ($level <= $DbgLevel); | |
} | |
} | |
sub utlErr | |
{ | |
my ($level, $msg) = @_; | |
if (($level <= $InfoLevel) || ($level <= $DbgLevel)) | |
{ | |
print($msg) if ($level <= $InfoLevel); | |
&sysWriteErr(&utlSrcLoc(1) . " Error: " . $msg) if ($level <= $DbgLevel); | |
} | |
} | |
sub utlDie | |
{ | |
my ($msg, $level, $ignore) = @_; | |
$ignore = 0 if (not defined($ignore)); | |
$level = 1 if (not defined($level)); | |
$msg = &utlSrcLoc($level) . " Error: " . $msg . "\n"; | |
&sysWriteErr($msg); | |
&sysDie($msg) unless ($ignore); | |
} | |
sub utlExec | |
{ | |
my ($cmd) = @_; | |
my $ret = ""; | |
$cmd = $cmd . " 2>" . $FileTmp; | |
$ret = `$cmd`; | |
if ($? != 0) | |
{ | |
my @stderr = (); | |
if (open(FILE_TEMP, $FileTmp)) | |
{ | |
@stderr = <FILE_TEMP>; | |
close(FILE_TEMP); | |
} | |
&utlDie("Fail to execute command: \"" . $cmd . "\"\nSTDOUT: " . $ret . "\nSTDERR: @stderr\n", 2); | |
} | |
return split(/\n/, $ret); | |
} | |
sub utlSystem | |
{ | |
my ($cmd, $ignore) = @_; | |
my $ret = ""; | |
my $status = 0; | |
$ignore = 0 if (not defined($ignore)); | |
$cmd = $cmd . " 2>" . $FileTmp; | |
$ret = `$cmd`; | |
$status = $?; | |
if ($status != 0) | |
{ | |
my @stderr = (); | |
my $msg = ""; | |
if (open(FILE_TMP, $FileTmp)) | |
{ | |
@stderr = <FILE_TMP>; | |
close(FILE_TMP); | |
} | |
if (($ret ne "") || ("@stderr" ne "") || ($ignore <= 0)) | |
{ | |
$msg = "Fail to execute command: \"" . $cmd . "\"\nSTDOUT: " . $ret . "\nSTDERR: @stderr\n"; | |
print($msg) if ($ignore == 0); | |
&sysWriteErr(&utlSrcLoc(1) . " Error: " . $msg); | |
} | |
} | |
return $status; | |
} | |
# ----------------------------------------------------------------------------- | |
# Utilities | |
sub utlTrim | |
{ | |
my ($str) = @_; | |
$str =~ s/^\s+//; | |
$str =~ s/\s+$//; | |
return $str; | |
} | |
sub utlAbsPath | |
{ | |
my ($path) = @_; | |
return abs_path($path); | |
} | |
sub utlRmTree | |
{ | |
my ($path, $ignore, $level) = @_; | |
if (-e $path) | |
{ | |
my @list = glob($path . "/*"); | |
$ignore = 1 if (not defined($ignore)); | |
$level = 2 if (not defined($level)); | |
foreach my $file (@list) | |
{ | |
if (-d $file) | |
{ | |
&utlRmTree($file, $ignore, $level + 1); | |
} | |
else | |
{ | |
&utlDie("Fail to delete " . $file . " due to \"$!\"", $level, $ignore) unless (unlink($file)); | |
} | |
} | |
&utlDie("Fail to delete " . $path . " due to \"$!\"", $level, $ignore) unless (rmdir($path)); | |
} | |
} | |
sub utlMkDir | |
{ | |
my ($dir) = @_; | |
if (! -d $dir) | |
{ | |
mkdir($dir) or &utlDie("Fail to create " . $dir . " due to \"$!\"", 2); | |
} | |
} | |
sub utlChDir | |
{ | |
my ($dir) = @_; | |
chdir($dir) or &utlDie("Fail to change directory to " . $dir . " due to \"$!\"", 2); | |
} | |
sub utlRmFile | |
{ | |
my ($file) = @_; | |
if (-e $file) | |
{ | |
unlink($file) or &utlDie("Fail to delete " . $file . " due to \"$!\"", 2); | |
} | |
} | |
sub utlCpFile | |
{ | |
my ($src, $dst) = @_; | |
copy($src, $dst) or &utlDie("Fail to copy " . $src . " to " . $dst . " due to \"$!\"; please check available disk space", 2); | |
} | |
sub utlGetTimestamp | |
{ | |
my ($file) = @_; | |
return (stat($file))[9]; | |
} | |
# ----------------------------------------------------------------------------- | |
sub copyFiles | |
{ | |
my ($dirSrc, $dirDst) = @_; | |
&utlDie("Cannot find " . $dirSrc) unless (-e $dirSrc); | |
&utlDie("Cannot find " . $dirDst) unless (-e $dirDst); | |
my @fileList = glob($dirSrc . "/*"); | |
foreach my $src (@fileList) | |
{ | |
&utlCpFile($src, $dirDst) if (-f $src); | |
} | |
} | |
sub copyLib | |
{ | |
my ($ptrAryDir, $srcSuffix, $dstSuffix) = @_; | |
foreach my $dirLib (@$ptrAryDir) | |
{ | |
my $dirSrcLib = $dirLib . $srcSuffix; | |
my $dirDstLib = $dirLib . $dstSuffix; | |
&utlRmTree($dirDstLib); | |
&utlMkDir($dirDstLib); | |
©Files($dirSrcLib, $dirDstLib); | |
} | |
} | |
sub generateCppLibFile | |
{ | |
my ($ptrHahLib, $fileCppLib) = @_; | |
my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir}; | |
my $ptrHahLibUsage = $ptrHahLib->{ptrHahLibUsage}; | |
my $ptrHahCppLibTab = $ptrHahLib->{ptrHahSymTable}->{ptrHahCppLibTab}; | |
open(FILE_CPP_LIB, ">" . $fileCppLib) or &utlDie("Cannot open " . $fileCppLib); | |
foreach my $dirSrcLib (@$ptrAryLibDir) | |
{ | |
my @libList = glob($dirSrcLib . "/*.lib"); | |
foreach my $lib (@libList) | |
{ | |
my $libName = basename($lib); | |
next if ((not exists($ptrHahLibUsage->{$libName})) || (not exists($ptrHahCppLibTab->{$libName}))); | |
print(FILE_CPP_LIB $libName . "\n"); | |
} | |
} | |
close(FILE_CPP_LIB); | |
} | |
sub readCppLibFile | |
{ | |
my ($fileCppLib, $ptrHahSymTable) = @_; | |
my $ptrHahCppLibTab = {}; | |
&utlLog(1, "Reading C++ libraries from " . $fileCppLib . "\n"); | |
open(FILE_CPP_LIB, "<" . $fileCppLib) or &utlDie("Cannot open " . $fileCppLib); | |
foreach my $line (<FILE_CPP_LIB>) | |
{ | |
if ($line =~ /(\S+)/) | |
{ | |
$ptrHahCppLibTab->{$1} = 1; | |
} | |
} | |
close(FILE_CPP_LIB); | |
$ptrHahSymTable->{ptrHahCppLibTab} = $ptrHahCppLibTab; | |
} | |
use constant { | |
SYM_DEF => 1, | |
SYM_UNDEF => 2 | |
}; | |
sub addEntrySymToObj | |
{ | |
my ($ptrHahSymTable, $sym, $type, $lib, $obj) = @_; | |
my $ptrHahSymToObjTab = $ptrHahSymTable->{ptrHahSymToObjTab}; | |
if (not exists($ptrHahSymToObjTab->{$sym})) | |
{ | |
$ptrHahSymToObjTab->{$sym} = {}; | |
$ptrHahSymToObjTab->{$sym}->{+SYM_DEF} = {}; | |
$ptrHahSymToObjTab->{$sym}->{+SYM_UNDEF} = {}; | |
} | |
my $ptrHahLibObj = $ptrHahSymToObjTab->{$sym}->{$type}; | |
my $ptrHahMultiSymTab = $ptrHahSymTable->{ptrHahMultiSymTab}; | |
if ($ptrHahMultiSymTab && ($type == SYM_DEF) && (scalar keys(%$ptrHahLibObj) > 0)) | |
{ | |
&utlLog(3, "Multiply defined symbol " . $sym . " in " . $lib . "(" . $obj . ")\n"); | |
$ptrHahMultiSymTab->{$sym} = 1; | |
} | |
$ptrHahLibObj->{$lib} = {} if (not exists($ptrHahLibObj->{$lib})); | |
$ptrHahLibObj->{$lib}->{$obj} = 1; | |
} | |
sub loadSymTableByNm | |
{ | |
my ($ptrHahSymTable, $lib, $libName, $type) = @_; | |
my $ptrHahObjToSymTab = $ptrHahSymTable->{ptrHahObjToSymTab}; | |
my $ptrHahCppLibTab = $ptrHahSymTable->{ptrHahCppLibTab}; | |
my $obj = ""; | |
my @symTable = (); | |
&utlDie("Assert") if (($type != SYM_DEF) && ($type != SYM_UNDEF)); | |
if ($type == SYM_DEF) | |
{ | |
@symTable = &utlExec($Cmd_nm . " -g --defined-only " . $lib); | |
} | |
else | |
{ | |
@symTable = &utlExec($Cmd_nm . " -g -u " . $lib); | |
} | |
foreach my $line (@symTable) | |
{ | |
if ($line =~ /^(\S+):\s*$/) | |
{ | |
$obj = $1; | |
$ptrHahObjToSymTab->{$libName} = {} if (not exists($ptrHahObjToSymTab->{$libName})); | |
if (not exists($ptrHahObjToSymTab->{$libName}->{$obj})) | |
{ | |
$ptrHahObjToSymTab->{$libName}->{$obj} = {}; | |
$ptrHahObjToSymTab->{$libName}->{$obj}->{+SYM_DEF} = {}; | |
$ptrHahObjToSymTab->{$libName}->{$obj}->{+SYM_UNDEF} = {}; | |
} | |
} | |
elsif ($line =~ /\s+[^N]\s+(\S+)\s*$/) | |
{ | |
my $sym = $1; | |
&utlDie("Assert") if ($obj eq ""); | |
&utlLog(3, "Reading " . $sym . " from " . $libName . "(" . $obj . ")\n"); | |
$ptrHahObjToSymTab->{$libName}->{$obj}->{$type}->{$sym} = 1; | |
&addEntrySymToObj($ptrHahSymTable, $sym, $type, $libName, $obj); | |
$ptrHahCppLibTab->{$libName} = 1 if (($type == SYM_DEF) && ($sym =~ /^_Z/)); | |
} | |
} | |
} | |
sub loadSymTable | |
{ | |
my ($ptrHahLib, $fileCppLib) = @_; | |
my $ptrHahSymTable = $ptrHahLib->{ptrHahSymTable}; | |
if (not exists($ptrHahSymTable->{ptrHahObjToSymTab})) | |
{ | |
my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir}; | |
my $ptrHahLibUsage = $ptrHahLib->{ptrHahLibUsage}; | |
&utlLog(1, "Loading symbol tables...\n"); | |
$ptrHahSymTable->{ptrHahObjToSymTab} = {}; | |
$ptrHahSymTable->{ptrHahSymToObjTab} = {}; | |
$ptrHahSymTable->{ptrHahCppLibTab} = {}; | |
$ptrHahSymTable->{ptrHahMultiSymTab} = {}; | |
foreach my $dirSrcLib (@$ptrAryLibDir) | |
{ | |
my @libList = glob($dirSrcLib . "/*.lib"); | |
foreach my $lib (@libList) | |
{ | |
my $libName = basename($lib); | |
next if (not exists($ptrHahLibUsage->{$libName})); | |
&utlLog(1, "Loading " . $libName . "\n"); | |
&loadSymTableByNm($ptrHahSymTable, $lib, $libName, SYM_DEF); | |
&loadSymTableByNm($ptrHahSymTable, $lib, $libName, SYM_UNDEF); | |
} | |
} | |
&utlLog(3, "Dumping object to symbol table...\n"); | |
&utlDump(3, $ptrHahSymTable->{ptrHahObjToSymTab}); | |
&utlLog(3, "Dumping symbol to object table...\n"); | |
&utlDump(3, $ptrHahSymTable->{ptrHahSymToObjTab}); | |
&generateCppLibFile($ptrHahLib, $fileCppLib); | |
} | |
} | |
sub generateDbgLibFile | |
{ | |
my ($ptrHahLib, $suffix, $ptrHahNoDbgLib, $fileDbgLib, $stripDebugCount) = @_; | |
my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir}; | |
my $ptrHahLibUsage = $ptrHahLib->{ptrHahLibUsage}; | |
my $ptrHahCppLibTab = $ptrHahLib->{ptrHahSymTable}->{ptrHahCppLibTab}; | |
my $size = keys(%$ptrHahNoDbgLib); | |
my $count = 0; | |
my %libList = (); | |
foreach my $dirSrcLib (@$ptrAryLibDir) | |
{ | |
my @list = glob($dirSrcLib . $suffix . "/*.lib"); | |
foreach my $lib (@list) | |
{ | |
my $libName = basename($lib); | |
$libList{$libName} = -s $lib; | |
} | |
} | |
open(FILE_DBG_LIB, ">" . $fileDbgLib) or &utlDie("Cannot open " . $fileDbgLib); | |
print(FILE_DBG_LIB "PLEASE ADD \";\" IN THE BEGINNING OF THE LINE IN ORDER TO REMOVE DEBUG INFO. OF A CORRESPONDING LIBRARY\n\n"); | |
foreach my $libName (sort { $libList{$b} <=> $libList{$a} } (keys(%libList))) | |
{ | |
if (not exists($ptrHahLibUsage->{$libName})) | |
{ | |
&utlLog(1, "NOT stripping " . $libName . " due to no use\n"); | |
next; | |
} | |
if (exists($ptrHahCppLibTab->{$libName})) | |
{ | |
&utlLog(1, "NOT stripping " . $libName . " due to C++\n"); | |
next; | |
} | |
if (($size == 0) && ($count < $stripDebugCount)) | |
{ | |
$ptrHahNoDbgLib->{$libName} = 1; | |
$count++; | |
} | |
if (exists($ptrHahNoDbgLib->{$libName})) | |
{ | |
print(FILE_DBG_LIB "; " . $libName . " " . $libList{$libName} . "\n"); | |
} | |
else | |
{ | |
print(FILE_DBG_LIB $libName . " " . $libList{$libName} . "\n"); | |
} | |
} | |
close(FILE_DBG_LIB); | |
} | |
sub readDbgLibFile | |
{ | |
my ($fileDbgLib, $ptrHahNoDbgLib) = @_; | |
&utlLog(1, "Reading debug-needed libraries from " . $fileDbgLib . "\n"); | |
open(FILE_DBG_LIB, "<" . $fileDbgLib) or &utlDie("Cannot open " . $fileDbgLib); | |
foreach my $line (<FILE_DBG_LIB>) | |
{ | |
if ($line =~ /^\s*;\s*(\S+)/) | |
{ | |
$ptrHahNoDbgLib->{$1} = 1; | |
} | |
} | |
close(FILE_DBG_LIB); | |
} | |
sub removeDebugInfoGut | |
{ | |
my ($ptrHahLib, $suffix) = @_; | |
my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir}; | |
my $ptrHahLibUsage = $ptrHahLib->{ptrHahLibUsage}; | |
my $ptrHahNoDbgLib = $ptrHahLib->{ptrHahNoDbgLib}; | |
my $ptrHahCppLibTab = $ptrHahLib->{ptrHahSymTable}->{ptrHahCppLibTab}; | |
my $fileOpt = "__ARM_OPT__.txt"; | |
my $cwd = cwd(); | |
foreach my $dirSrcLib (@$ptrAryLibDir) | |
{ | |
my @libList = glob($dirSrcLib . $suffix . "/*.lib"); | |
foreach my $lib (@libList) | |
{ | |
my $libName = basename($lib); | |
if (exists($ptrHahLibUsage->{$libName}) && (not exists($ptrHahCppLibTab->{$libName})) && (exists($ptrHahNoDbgLib->{$libName}))) | |
{ | |
&utlLog(1, "Removing debug info of " . $libName . "\n"); | |
&utlMkDir($DirTemp); | |
&utlChDir($DirTemp); | |
my @objList = &utlExec($Cmd_armar . " -t " . $lib); | |
if (&utlSystem($Cmd_armar . " -x " . $lib) == 0) | |
{ | |
my $done = 1; | |
foreach my $obj (@objList) | |
{ | |
if (&utlSystem($Cmd_strip . " -d " . $obj) != 0) | |
{ | |
$done = 0; | |
last; | |
} | |
} | |
if ($done) | |
{ | |
open(FILE_OPT, ">" . $fileOpt) or &utlDie("Cannot open " . $fileOpt); | |
print(FILE_OPT "--create " . $lib . " @objList"); | |
close(FILE_OPT); | |
&utlSystem($Cmd_armar . " --via " . $fileOpt); | |
} | |
} | |
&utlChDir($cwd); | |
&utlRmTree($DirTemp); | |
} | |
} | |
} | |
} | |
sub removeDebugInfo | |
{ | |
my ($ptrHahLib, $suffix, $fileCppLib, $fileDbgLib, $stripDebugCount) = @_; | |
my $update = scalar keys(%{$ptrHahLib->{ptrHahLibNew}}); | |
if ((-e $fileCppLib) && ($update == 0)) | |
{ | |
&readCppLibFile($fileCppLib, $ptrHahLib->{ptrHahSymTable}); | |
} | |
else | |
{ | |
&loadSymTable($ptrHahLib, $fileCppLib); | |
} | |
&readDbgLibFile($fileDbgLib, $ptrHahLib->{ptrHahNoDbgLib}) if (-e $fileDbgLib); | |
&generateDbgLibFile($ptrHahLib, $suffix, $ptrHahLib->{ptrHahNoDbgLib}, $fileDbgLib, $stripDebugCount); | |
&removeDebugInfoGut($ptrHahLib, $suffix); | |
} | |
sub createDstLibDir | |
{ | |
my ($ptrHahLib) = @_; | |
my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir}; | |
my $suffix = $ptrHahLib->{suffix}; | |
foreach my $dirSrcLib (@$ptrAryLibDir) | |
{ | |
my $dirDstLib = $dirSrcLib . $suffix; | |
&utlLog(1, "Creating " . $dirDstLib ."\n"); | |
&utlRmTree($dirDstLib); | |
&utlMkDir($dirDstLib); | |
} | |
} | |
sub removeDstLibDir | |
{ | |
my ($ptrHahLib, $suffix, $dstSuffix) = @_; | |
my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir}; | |
foreach my $dirSrcLib (@$ptrAryLibDir) | |
{ | |
my $dirDstLib = $dirSrcLib . $suffix; | |
if (-e $dirDstLib) | |
{ | |
if ((not defined($dstSuffix)) || ($dstSuffix eq "")) | |
{ | |
&utlRmTree($dirDstLib); | |
} | |
else | |
{ | |
my $path = $dirSrcLib . $dstSuffix; | |
&utlLog(1, "Removing " . $path . "\n"); | |
&utlRmTree($path); | |
&utlLog(1, "Keeping partially-linked libraries in " . $path . "\n"); | |
if (not rename($dirDstLib, $path)) | |
{ | |
&utlLog(1, "Fail to rename directory " . $dirDstLib . " to " . $path . " due to \"$!\"\n"); | |
&utlLog(1, "Trying to copy files from " . $dirDstLib . " to " . $path . "\n"); | |
&utlMkDir($path); | |
©Files($dirDstLib, $path); | |
&utlRmTree($dirDstLib); | |
} | |
} | |
} | |
} | |
} | |
sub finalizeLib | |
{ | |
my ($ptrHahLib) = @_; | |
my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir}; | |
my $suffix = $ptrHahLib->{suffix}; | |
my $suffix_bak = $ptrHahLib->{suffix_bak}; | |
foreach my $dirSrcLib (@$ptrAryLibDir) | |
{ | |
my $dirDstLib = $dirSrcLib . $suffix; | |
my $dirSrcBak = $dirSrcLib . $suffix_bak; | |
&utlDie("Cannot find " . $dirDstLib) unless (-e $dirDstLib); | |
&utlDie("Unexpected directory " . $dirSrcBak) if (-e $dirSrcBak); | |
&utlMkDir($dirSrcBak); | |
©Files($dirSrcLib, $dirSrcBak); | |
©Files($dirDstLib, $dirSrcLib); | |
&utlRmTree($dirSrcBak); | |
&utlRmTree($dirDstLib); | |
} | |
} | |
# ----------------------------------------------------------------------------- | |
sub isPattern | |
{ | |
my ($str) = @_; | |
return 1 if (($str ne "*") && ($str =~ /[*?]+/)); | |
return 0; | |
} | |
sub regExp | |
{ | |
my ($expr) = @_; | |
$expr =~ s/\./\\./g; | |
$expr =~ s/\*/.*/g; | |
$expr =~ s/\?/./g; | |
return $expr; | |
} | |
sub hasRule | |
{ | |
my ($ptrHahRuleGut, $lib, $obj) = @_; | |
$lib = lc($lib); | |
$obj = lc($obj); | |
$lib = ®Exp($lib) if (&isPattern($lib)); | |
$obj = ®Exp($obj) if (&isPattern($obj)); | |
return 1 if (exists($ptrHahRuleGut->{$lib}) && exists($ptrHahRuleGut->{$lib}->{$obj})); | |
return 0; | |
} | |
sub loadRule | |
{ | |
my ($ptrHahRuleGut, $lib, $obj) = @_; | |
$lib = lc($lib); | |
$obj = lc($obj); | |
if (&isPattern($lib)) | |
{ | |
$ptrHahRuleGut->{regExpLib} = {} if (not exists($ptrHahRuleGut->{regExpLib})); | |
$lib = ®Exp($lib); | |
$ptrHahRuleGut->{regExpLib}->{$lib} = 1; | |
} | |
$ptrHahRuleGut->{$lib} = {} if (not exists($ptrHahRuleGut->{$lib})); | |
if (&isPattern($obj)) | |
{ | |
$ptrHahRuleGut->{$lib}->{regExpObj} = {} if (not exists($ptrHahRuleGut->{$lib}->{regExpObj})); | |
$obj = ®Exp($obj); | |
$ptrHahRuleGut->{$lib}->{regExpObj}->{$obj} = 1; | |
} | |
$ptrHahRuleGut->{$lib}->{$obj} = 1; | |
} | |
sub writeRule | |
{ | |
my ($hdlFileRule, $lib, $obj) = @_; | |
printf($hdlFileRule "%s(%s)\n", $lib, $obj) if ($hdlFileRule); | |
} | |
sub addRule | |
{ | |
my ($ptrHahRuleGut, $lib, $obj, $hdlFileRule) = @_; | |
if (not &hasRule($ptrHahRuleGut, $lib, $obj)) | |
{ | |
&loadRule($ptrHahRuleGut, $lib, $obj); | |
&writeRule($hdlFileRule, $lib, $obj); | |
} | |
} | |
# Return 1 if a library is specified in RULE to exclude; otherwise, return 0. | |
sub isExcludedLib | |
{ | |
my ($ptrHahRuleGut, $lib) = @_; | |
$lib = lc($lib); | |
return 1 if ( ( exists($ptrHahRuleGut->{$lib}) | |
&& exists($ptrHahRuleGut->{$lib}->{"*"})) | |
|| ( exists($ptrHahRuleGut->{"*"}) | |
&& exists($ptrHahRuleGut->{"*"}->{"*"}))); | |
foreach my $regExpLib (keys(%{$ptrHahRuleGut->{regExpLib}})) | |
{ | |
if (($lib =~ /($regExpLib)/) && exists($ptrHahRuleGut->{$regExpLib}->{"*"})) | |
{ | |
&loadRule($ptrHahRuleGut, $lib, "*"); | |
return 1; | |
} | |
} | |
return 0; | |
} | |
# Return 1 if an object is specified in RULE to exclude; otherwise, return 0. | |
sub isExcludedObj | |
{ | |
my ($ptrHahRuleGut, $lib, $obj) = @_; | |
$lib = lc($lib); | |
$obj = lc($obj); | |
return 1 if ( ( exists($ptrHahRuleGut->{$lib}) | |
&& ( exists($ptrHahRuleGut->{$lib}->{$obj}) | |
|| exists($ptrHahRuleGut->{$lib}->{"*"}))) | |
|| ( exists($ptrHahRuleGut->{"*"}) | |
&& exists($ptrHahRuleGut->{"*"}->{$obj})) | |
|| ( exists($ptrHahRuleGut->{"*"}) | |
&& exists($ptrHahRuleGut->{"*"}->{"*"}))); | |
if ( exists($ptrHahRuleGut->{"*"}) | |
&& exists($ptrHahRuleGut->{"*"}->{regExpObj})) | |
{ | |
foreach my $regExpObj (keys(%{$ptrHahRuleGut->{"*"}->{regExpObj}})) | |
{ | |
if ($obj =~ /($regExpObj)/) | |
{ | |
&loadRule($ptrHahRuleGut, $lib, $obj); | |
return 1; | |
} | |
} | |
} | |
foreach my $regExpLib (keys(%{$ptrHahRuleGut->{regExpLib}})) | |
{ | |
if ($lib =~ /($regExpLib)/) | |
{ | |
if (exists($ptrHahRuleGut->{$regExpLib}->{$obj})) | |
{ | |
&loadRule($ptrHahRuleGut, $lib, $obj); | |
return 1; | |
} | |
elsif (exists($ptrHahRuleGut->{$regExpLib}->{"*"})) | |
{ | |
&loadRule($ptrHahRuleGut, $lib, "*"); | |
return 1; | |
} | |
elsif (exists($ptrHahRuleGut->{$regExpLib}->{regExpObj})) | |
{ | |
foreach my $regExpObj (keys(%{$ptrHahRuleGut->{$regExpLib}->{regExpObj}})) | |
{ | |
if ($obj =~ /($regExpObj)/) | |
{ | |
&loadRule($ptrHahRuleGut, $lib, $obj); | |
return 1; | |
} | |
} | |
} | |
} | |
} | |
return 0; | |
} | |
sub readRuleFile | |
{ | |
my ($ptrHahRule) = @_; | |
my $fileRule = $ptrHahRule->{fileRule}; | |
my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut}; | |
&utlLog(1, "Reading rule from " . $fileRule . "\n"); | |
open(FILE_RULE, "<" . $fileRule) or &utlDie("Cannot open " . $fileRule); | |
foreach my $line (<FILE_RULE>) | |
{ | |
# library(object) | |
if ($line =~ /^\s*([^\(\)\s]+)\s*\(\s*([^\(\)\s]+)\s*\)/) | |
{ | |
my $lib = $1; | |
my $obj = $2; | |
&utlDie("Invalid rule: " . $line) if (($lib eq "*") && ($obj eq "*")); | |
&loadRule($ptrHahRuleGut, $lib, $obj) if (not &hasRule($ptrHahRuleGut, $lib, $obj)); | |
} | |
} | |
close(FILE_RULE); | |
&utlCpFile($fileRule, $ptrHahRule->{file}); | |
} | |
sub parseScatterFile | |
{ | |
my ($fileScatter, $ptrHahRule) = @_; | |
my $fileRule = $ptrHahRule->{file}; | |
my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut}; | |
&utlLog(1, "Parsing scatter file " . $fileScatter . " and outputting rules to " . $fileRule . "\n"); | |
open(FILE_RULE, ">" . $fileRule) or &utlDie("Cannot open " . $fileRule); | |
open(FILE_SCATTER, "<" . $fileScatter) or &utlDie("Cannot open " . $fileScatter); | |
foreach my $line (<FILE_SCATTER>) | |
{ | |
if ($line =~ /^\s*(\S+\.o\S*)/i) | |
{ | |
my $obj = $1; | |
next if ($obj =~ /^\*\.o/i); | |
&addRule($ptrHahRuleGut, "*", $obj, \*FILE_RULE); | |
} | |
} | |
close(FILE_SCATTER); | |
close(FILE_RULE); | |
} | |
sub generateFileNameList | |
{ | |
my ($file, $ptrAryFileName) = @_; | |
open(FILE_INPUT, "<" . $file) or &utlDie("Cannot open " . $file); | |
foreach my $line (<FILE_INPUT>) | |
{ | |
my @optList = split(/\s+/, $line); | |
foreach my $opt (@optList) | |
{ | |
push(@$ptrAryFileName, basename($1) . ".lib") if ($opt =~ /(\S+)\.lib(\(\S+\)|$)/); | |
} | |
} | |
close(FILE_INPUT); | |
} | |
sub readUserExclusionFile | |
{ | |
my ($ptrAryUserExclusionFile, $ptrHahRule) = @_; | |
my $fileRule = $ptrHahRule->{file}; | |
my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut}; | |
open(FILE_RULE, ">>" . $fileRule) or &utlDie("Cannot open " . $fileRule); | |
foreach my $file (@$ptrAryUserExclusionFile) | |
{ | |
my @nameList = (); | |
&utlLog(1, "Reading user exclusion from " . $file . "\n"); | |
&generateFileNameList($file, \@nameList); | |
foreach my $lib (@nameList) | |
{ | |
&utlLog(1, "Will exclude " . $lib . "\n"); | |
&addRule($ptrHahRuleGut, $lib, "*", \*FILE_RULE); | |
} | |
} | |
close(FILE_RULE); | |
} | |
sub readExclusionFile | |
{ | |
my ($fileExclusion, $ptrHahRule) = @_; | |
my $fileRule = $ptrHahRule->{file}; | |
my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut}; | |
&utlLog(1, "Reading exclusion from " . $fileExclusion . "\n"); | |
open(FILE_EXCLUSION, "<" . $fileExclusion) or &utlDie("Cannot open " . $fileExclusion); | |
open(FILE_RULE, ">>" . $fileRule) or &utlDie("Cannot open " . $fileRule); | |
foreach my $line (<FILE_EXCLUSION>) | |
{ | |
# library object | |
if ($line =~ /^\s*(\S+)\s+(\S+)/) | |
{ | |
my $lib = $1; | |
my $obj = $2; | |
&utlLog(1, "Will exclude " . $lib . "(" . $obj . ")\n"); | |
&addRule($ptrHahRuleGut, $lib, $obj, \*FILE_RULE); | |
} | |
} | |
close(FILE_RULE); | |
close(FILE_EXCLUSION); | |
} | |
sub writeExcludedLib | |
{ | |
my ($ptrAryExcludedLib, $ptrHahRule) = @_; | |
my $fileRule = $ptrHahRule->{file}; | |
my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut}; | |
&utlLog(1, "Writing built-in excluded libraries to " . $fileRule . "\n"); | |
open(FILE_RULE, ">>" . $fileRule) or &utlDie("Cannot open " . $fileRule); | |
foreach my $lib (@$ptrAryExcludedLib) | |
{ | |
&utlLog(1, "Will exclude " . $lib . "\n"); | |
&addRule($ptrHahRuleGut, $lib, "*", \*FILE_RULE); | |
} | |
close(FILE_RULE); | |
} | |
sub writeHint | |
{ | |
my ($hdlFileHint, $lib, $obj, $sym) = @_; | |
printf($hdlFileHint "%s %s %s\n", $lib, $sym, $obj) if ($hdlFileHint); | |
} | |
sub loadHint | |
{ | |
my ($ptrHahHintGut, $lib, $obj, $sym) = @_; | |
$ptrHahHintGut->{$sym} = {} if (not exists($ptrHahHintGut->{$sym})); | |
$ptrHahHintGut->{$sym}->{$obj} = {} if (not exists($ptrHahHintGut->{$sym}->{$obj})); | |
$ptrHahHintGut->{$sym}->{$obj}->{$lib} = 1; | |
} | |
sub addHint | |
{ | |
my ($ptrHahHintGut, $lib, $obj, $sym, $hdlFileHint) = @_; | |
if ( (not exists($ptrHahHintGut->{$sym})) | |
|| (not exists($ptrHahHintGut->{$sym}->{$obj})) | |
|| (not exists($ptrHahHintGut->{$sym}->{$obj}->{$lib}))) | |
{ | |
&loadHint($ptrHahHintGut, $lib, $obj, $sym); | |
&writeHint($hdlFileHint, $lib, $obj, $sym); | |
} | |
} | |
sub readHintFile | |
{ | |
my ($ptrHahHint, $ptrHahRule) = @_; | |
my $fileHint = $ptrHahHint->{fileHint}; | |
my $ptrHahHintGut = $ptrHahHint->{ptrHahGut}; | |
my $toRule = $ptrHahHint->{toRule}; | |
my $fileRule = $ptrHahRule->{file}; | |
my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut}; | |
&utlLog(1, "Reading hint from " . $fileHint . "\n"); | |
open(FILE_HINT, "<" . $fileHint) or &utlDie("Cannot open " . $fileHint); | |
open(FILE_RULE, ">>" . $fileRule) or &utlDie("Cannot open " . $fileRule); | |
foreach my $line (<FILE_HINT>) | |
{ | |
# library symbol object | |
if ($line =~ /^\s*(\S+)\s+(\S+)\s+(\S+)/) | |
{ | |
my $lib = $1; | |
my $sym = $2; | |
my $obj = $3; | |
&loadHint($ptrHahHintGut, $lib, $obj, $sym); | |
&addRule($ptrHahRuleGut, $lib, $obj, \*FILE_RULE) if ($toRule); | |
} | |
} | |
close(FILE_RULE); | |
close(FILE_HINT); | |
&utlCpFile($fileHint, $ptrHahHint->{file}); | |
} | |
sub generateLinkOptFile | |
{ | |
my ($ptrHahLib, $ptrHahRuleGut, $fileLinkOpt, $fileOutput) = @_; | |
my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir}; | |
my $fileOrig = $fileOutput . ".orig"; | |
my %libPath = (); | |
&utlCpFile($fileLinkOpt, $fileOrig); | |
foreach my $dirSrcLib (@$ptrAryLibDir) | |
{ | |
my @libList = glob($dirSrcLib . "/*.lib"); | |
foreach my $lib (@libList) | |
{ | |
my $libName = basename($lib); | |
if (exists($libPath{$libName})) | |
{ | |
$libPath{$libName} = ""; | |
} | |
else | |
{ | |
$libPath{$libName} = $dirSrcLib; | |
} | |
} | |
} | |
my $suffix = $ptrHahLib->{suffix}; | |
my $ptrHahLibUsage = $ptrHahLib->{ptrHahLibUsage}; | |
&utlLog(1, "Generating link option file " . $fileOutput . "\n"); | |
open(FILE_LINK_OPT, "<" . $fileLinkOpt) or &utlDie("Cannot open " . $fileLinkOpt); | |
open(FILE_OUTPUT, ">" . $fileOutput) or &utlDie("Cannot open " . $fileOutput); | |
foreach my $line (<FILE_LINK_OPT>) | |
{ | |
my @optList = split(/\s+/, $line); | |
foreach my $opt (@optList) | |
{ | |
my $found = 0; | |
if ($opt =~ /\.lib$/) | |
{ | |
my $libName = basename($opt); | |
if (exists($libPath{$libName}) && ($libPath{$libName} ne "")) | |
{ | |
if (($ptrHahRuleGut == 0) || (not &isExcludedLib($ptrHahRuleGut, $libName))) | |
{ | |
my $lib = $libPath{$libName}. $suffix . "/" . $libName; | |
$lib =~ s/\//\\/g; | |
print(FILE_OUTPUT " " . $lib); | |
$found = 1; | |
} | |
$ptrHahLibUsage->{$libName} = 1; | |
} | |
} | |
print(FILE_OUTPUT " " . $opt) unless ($found); | |
} | |
print(FILE_OUTPUT "\n"); | |
} | |
close(FILE_OUTPUT); | |
close(FILE_LINK_OPT); | |
foreach my $libName (keys(%libPath)) | |
{ | |
&utlLog(1, "NOT using " . $libName . " in link option file " . $fileLinkOpt . "\n") if (not exists($ptrHahLibUsage->{$libName})); | |
} | |
} | |
# ----------------------------------------------------------------------------- | |
sub partialLinkLibGut | |
{ | |
my ($lib, $libName, $dirDstLib, $ptrHahLib, $ptrHahRuleGut, $hdlFileRule, $ptrHahHintGut, $hdlFileHint) = @_; | |
my @objList = &utlExec($Cmd_armar . " -t " . $lib); | |
my $linkedObj = "__" . $libName . "_linked__.obj"; | |
&utlLog(3, "Analyzing " . $lib . " with @objList\n"); | |
if (grep {$_ eq $linkedObj} @objList) | |
{ | |
&utlLog(1, "Excluding " . $libName . " due to a linked object inside\n"); | |
&utlCpFile($lib, $dirDstLib . "/" . $libName); | |
} | |
elsif (&isExcludedLib($ptrHahRuleGut, $libName)) | |
{ | |
my $dstLib = $dirDstLib . "/" . $libName; | |
&utlLog(1, "Excluding " . $libName . "\n"); | |
&utlCpFile($lib, $dstLib); | |
} | |
else | |
{ | |
my $ptrAryPLObj = []; | |
my $ptrAryNonPLObj = []; | |
# Find out objects which can be partially linked according to rule. | |
foreach my $obj (@objList) | |
{ | |
if (&isExcludedObj($ptrHahRuleGut, $libName, $obj)) | |
{ | |
push(@$ptrAryNonPLObj, $obj); | |
} | |
else | |
{ | |
push(@$ptrAryPLObj, $obj); | |
} | |
} | |
if ($#$ptrAryPLObj < 1) | |
{ | |
&utlLog(1, "Excluding " . $libName . " due to one object for partial link\n"); | |
&addRule($ptrHahRuleGut, $libName, "*", $hdlFileRule); | |
&addHint($ptrHahHintGut, $libName, "*", "*", $hdlFileHint); | |
&utlCpFile($lib, $dirDstLib . "/" . $libName); | |
} | |
else | |
{ | |
my $fileOpt = "__ARM_OPT__.txt"; | |
my $cwd = cwd(); | |
my $err = 1; | |
my $cmd = ""; | |
&utlRmTree($DirTemp); | |
&utlMkDir($DirTemp); | |
&utlChDir($DirTemp); | |
$cmd = $Cmd_armar . " -x " . $lib; | |
if (&utlSystem($cmd, -1) == 0) | |
{ | |
# Partially link objects. | |
&utlDie("Assert: need at least 2 objects for partial link") unless ($#$ptrAryPLObj > 0); | |
$cmd = "@$ptrAryPLObj --partial --elf -o " . $linkedObj; | |
open(FILE_OPT, ">" . $fileOpt) or &utlDie("Cannot open " . $fileOpt); | |
print(FILE_OPT $cmd); | |
close(FILE_OPT); | |
&utlLog(1, $Cmd_armlink . " " . $cmd . "\n"); | |
$cmd = $Cmd_armlink . " --via " . $fileOpt . " >>" . $FileLog . " 2>&1"; | |
if (&utlSystem($cmd, -1) == 0) | |
{ | |
push(@$ptrAryNonPLObj, $linkedObj); | |
# Archive objects to create a library. | |
&utlLog(1, "Creating " . $libName . "\n"); | |
&utlLog(2, "Creating " . $libName . " with @$ptrAryNonPLObj\n"); | |
open(FILE_OPT, ">" . $fileOpt) or &utlDie("Cannot open " . $fileOpt); | |
printf(FILE_OPT "--create %s/%s @$ptrAryNonPLObj", $dirDstLib, $libName); | |
close(FILE_OPT); | |
$cmd = $Cmd_armar . " --via " . $fileOpt . " >>" . $FileLog . " 2>&1"; | |
$err = 0 if (&utlSystem($cmd, -1) == 0); | |
} | |
} | |
if ($err) | |
{ | |
if ((-e $fileOpt) && open(FILE_OPT, $fileOpt)) | |
{ | |
my @temp = <FILE_OPT>; | |
close(FILE_OPT); | |
&utlErr(1, "Dumping " . $fileOpt . ": @temp\n"); | |
} | |
&utlLog(1, "Excluding " . $libName . " due to failure to execute \"" . $cmd . "\"\n"); | |
&utlCpFile($lib, $dirDstLib . "/" . $libName); | |
} | |
&utlChDir($cwd); | |
&utlRmTree($DirTemp); | |
} | |
} | |
} | |
sub partialLinkLib | |
{ | |
my ($ptrHahLib, $ptrHahRule, $ptrHahHint, $ptrHahLibErr) = @_; | |
my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir}; | |
my $suffix = $ptrHahLib->{suffix}; | |
my $fileRule = $ptrHahRule->{file}; | |
my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut}; | |
my $fileHint = $ptrHahHint->{file}; | |
my $ptrHahHintGut = $ptrHahHint->{ptrHahGut}; | |
&utlLog(1, "Partially linking objects in the same libraries...\n"); | |
open(FILE_RULE, ">>" . $fileRule) or &utlDie("Cannot open " . $fileRule); | |
open(FILE_HINT, ">>" . $fileHint) or &utlDie("Cannot open " . $fileHint); | |
if ($ptrHahLibErr && (scalar keys(%$ptrHahLibErr) > 0)) | |
{ | |
foreach my $libName (keys(%$ptrHahLibErr)) | |
{ | |
foreach my $dirSrcLib (@$ptrAryLibDir) | |
{ | |
my $lib = $dirSrcLib . "/" . $libName; | |
if (-e $lib) | |
{ | |
my $dirDstLib = $dirSrcLib . $suffix; | |
&utlDie("Cannot find " . $dirSrcLib) unless (-e $dirSrcLib); | |
&utlDie("Cannot find " . $dirDstLib) unless (-e $dirDstLib); | |
&partialLinkLibGut($lib, $libName, $dirDstLib, $ptrHahLib, $ptrHahRuleGut, \*FILE_RULE, $ptrHahHintGut, \*FILE_HINT); | |
} | |
} | |
} | |
} | |
else | |
{ | |
my $ptrHahLibUsage = $ptrHahLib->{ptrHahLibUsage}; | |
foreach my $dirSrcLib (@$ptrAryLibDir) | |
{ | |
my @libList = glob($dirSrcLib . "/*.lib"); | |
my $dirDstLib = $dirSrcLib . $suffix; | |
&utlDie("Cannot find directory " . $dirDstLib) unless (-e $dirDstLib); | |
foreach my $lib (@libList) | |
{ | |
my $libName = basename($lib); | |
if (not exists($ptrHahLibUsage->{$libName})) | |
{ | |
my $dstLib = $dirDstLib . "/" . $libName; | |
&utlLog(1, "Excluding " . $libName . " due to no use in the link option file\n"); | |
&utlCpFile($lib, $dstLib); | |
} | |
else | |
{ | |
&partialLinkLibGut($lib, $libName, $dirDstLib, $ptrHahLib, $ptrHahRuleGut, \*FILE_RULE, $ptrHahHintGut, \*FILE_HINT); | |
} | |
} | |
} | |
} | |
close(FILE_HINT); | |
close(FILE_RULE); | |
} | |
use constant { | |
LINK_NONE => 2, | |
LINK_OK_STRIP => 1, | |
LINK_OK => 0, | |
LINK_OUT_OF_MEM => -1, | |
LINK_UNKNOWN => -2, | |
LINK_FAIL => -3, | |
}; | |
# Parse an error file from final link. | |
sub parseErrorFile | |
{ | |
my ($ptrHahError) = @_; | |
my $fileError = $ptrHahError->{file}; | |
my $ret = LINK_OK; | |
$ptrHahError->{ptrHahObjSymErr} = {}; | |
$ptrHahError->{ptrHahLibSymErr} = {}; | |
$ptrHahError->{ptrHahLibObjRef} = {}; | |
$ptrHahError->{ptrHahLibErr} = {}; | |
&utlLog(1, "Parsing linking error from " . $fileError . "\n"); | |
open(FILE_ERROR, "<" . $fileError) or &utlDie("Cannot open " . $fileError); | |
my $ptrHahObjSymErr = $ptrHahError->{ptrHahObjSymErr}; | |
my $ptrHahLibSymErr = $ptrHahError->{ptrHahLibSymErr}; | |
foreach my $line (<FILE_ERROR>) | |
{ | |
if ($line =~ /^Error: L6218E: Undefined symbol (\S+) \(referred from __(\S+)_linked__.obj\)/) | |
{ | |
$ptrHahLibSymErr->{$2} = {} if (not exists($ptrHahLibSymErr->{$2})); | |
$ptrHahLibSymErr->{$2}->{$1} = SYM_UNDEF if (not exists($ptrHahLibSymErr->{$2}->{$1})); | |
$ret = LINK_FAIL; | |
} | |
elsif ($line =~ /^Error: L6218E: Undefined symbol (\S+) \(referred from (\S+)\)/) | |
{ | |
$ptrHahObjSymErr->{$2} = {} if (not exists($ptrHahObjSymErr->{$2})); | |
$ptrHahObjSymErr->{$2}->{$1} = SYM_UNDEF if (not exists($ptrHahObjSymErr->{$2}->{$1})); | |
$ret = LINK_FAIL; | |
} | |
elsif ($line =~ /^Error: L6200E: Symbol (\S+) multiply defined \(by __(\S+)_linked__.obj and __(\S+)_linked__.obj\)/) | |
{ | |
$ptrHahLibSymErr->{$2} = {} if (not exists($ptrHahLibSymErr->{$2})); | |
$ptrHahLibSymErr->{$2}->{$1} = SYM_DEF if (not exists($ptrHahLibSymErr->{$2}->{$1})); | |
if ($2 ne $3) | |
{ | |
$ptrHahLibSymErr->{$3} = {} if (not exists($ptrHahLibSymErr->{$3})); | |
$ptrHahLibSymErr->{$3}->{$1} = SYM_DEF if (not exists($ptrHahLibSymErr->{$3}->{$1})); | |
} | |
$ret = LINK_FAIL; | |
} | |
elsif ($line =~ /^Error: L6200E: Symbol (\S+) multiply defined \(by __(\S+)_linked__.obj and (\S+)\)/) | |
{ | |
$ptrHahLibSymErr->{$2} = {} if (not exists($ptrHahLibSymErr->{$2})); | |
$ptrHahLibSymErr->{$2}->{$1} = SYM_DEF if (not exists($ptrHahLibSymErr->{$2}->{$1})); | |
$ret = LINK_FAIL; | |
} | |
elsif ($line =~ /^Error: L6200E: Symbol (\S+) multiply defined \(by (\S+) and __(\S+)_linked__.obj\)/) | |
{ | |
$ptrHahLibSymErr->{$3} = {} if (not exists($ptrHahLibSymErr->{$3})); | |
$ptrHahLibSymErr->{$3}->{$1} = SYM_DEF if (not exists($ptrHahLibSymErr->{$3}->{$1})); | |
$ret = LINK_FAIL; | |
} | |
elsif ($line =~ /^Error: L6200E: Symbol (\S+) multiply defined \(by (\S+) and (\S+)\)/) | |
{ | |
$ptrHahObjSymErr->{$2} = {} if (not exists($ptrHahObjSymErr->{$2})); | |
$ptrHahObjSymErr->{$2}->{$1} = SYM_DEF if (not exists($ptrHahObjSymErr->{$2}->{$1})); | |
$ptrHahObjSymErr->{$3} = {} if (not exists($ptrHahObjSymErr->{$3})); | |
$ptrHahObjSymErr->{$3}->{$1} = SYM_DEF if (not exists($ptrHahObjSymErr->{$3}->{$1})); | |
$ret = LINK_FAIL; | |
} | |
elsif ($line =~ /^Fatal error: L6000U: Out of memory/) | |
{ | |
&utlLog(1, $line); | |
$ret = LINK_OUT_OF_MEM; | |
last; | |
} | |
elsif ( ($line =~ /^Error:/) | |
|| ($line =~ /^Fatal error:/)) | |
{ | |
&utlLog(0, $line); | |
$ret = LINK_UNKNOWN; | |
last; | |
} | |
} | |
close(FILE_ERROR); | |
return $ret; | |
} | |
sub finalLink | |
{ | |
my ($extraOption, $fileLinkOption, $ptrHahError) = @_; | |
my $fileError = $ptrHahError->{file}; | |
my $fileOutput = $ptrHahError->{fileOutput}; | |
my $cmd = $Cmd_armlink . " " . $extraOption . " --via " . $fileLinkOption . " --errors " . $fileError; | |
&utlLog(1, "Executing \"" . $cmd . "\"\n"); | |
&utlSystem($cmd, 1); | |
&utlCpFile($fileError, $fileOutput) unless ($fileOutput eq ""); | |
return &parseErrorFile($ptrHahError); | |
} | |
BEGIN | |
{ | |
my $hasExcludedRedefinedSym = 0; | |
sub ruleOutObjWithRedefinedSym | |
{ | |
my ($ptrHahSymTable, $ptrHahRule, $ptrHahHint, $ptrHahLibErr) = @_; | |
my $ptrHahMultiSymTab = $ptrHahSymTable->{ptrHahMultiSymTab}; | |
if (($hasExcludedRedefinedSym == 0) && $ptrHahMultiSymTab && (scalar keys(%$ptrHahMultiSymTab) > 0)) | |
{ | |
my $ptrHahSymToObjTab = $ptrHahSymTable->{ptrHahSymToObjTab}; | |
my $fileRule = $ptrHahRule->{file}; | |
my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut}; | |
my $fileHint = $ptrHahHint->{file}; | |
my $ptrHahHintGut = $ptrHahHint->{ptrHahGut}; | |
open(FILE_RULE, ">>" . $fileRule) or &utlDie("Cannot open " . $fileRule); | |
open(FILE_HINT, ">>" . $fileHint) or &utlDie("Cannot open " . $fileHint); | |
foreach my $sym (keys(%$ptrHahMultiSymTab)) | |
{ | |
if ($sym !~ /^_Z/) | |
{ | |
my $ptrHahLibObj = $ptrHahSymToObjTab->{$sym}->{+SYM_DEF}; | |
foreach my $lib (keys(%$ptrHahLibObj)) | |
{ | |
if (not &hasRule($ptrHahRuleGut, $lib, "*")) | |
{ | |
foreach my $obj (keys(%{$ptrHahLibObj->{$lib}})) | |
{ | |
if (not &hasRule($ptrHahRuleGut, $lib, $obj)) | |
{ | |
&utlLog(1, "Adding rule to exclude " . $lib . "(" . $obj . ") due to redefinition of " . $sym . "\n"); | |
&addRule($ptrHahRuleGut, $lib, $obj, \*FILE_RULE); | |
&addHint($ptrHahHintGut, $lib, $obj, $sym, \*FILE_HINT); | |
$ptrHahLibErr->{$lib} = 1; | |
} | |
} | |
} | |
} | |
} | |
} | |
close(FILE_HINT); | |
close(FILE_RULE); | |
$hasExcludedRedefinedSym = 1; | |
} | |
} | |
} | |
sub ruleOutCppLib | |
{ | |
my ($ptrHahSymTable, $ptrHahRule, $ptrHahHint, $ptrHahLibErr) = @_; | |
my $ptrHahCppLibTab = $ptrHahSymTable->{ptrHahCppLibTab}; | |
if ($ptrHahCppLibTab && (scalar keys(%$ptrHahCppLibTab) > 0)) | |
{ | |
my $fileRule = $ptrHahRule->{file}; | |
my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut}; | |
my $fileHint = $ptrHahHint->{file}; | |
my $ptrHahHintGut = $ptrHahHint->{ptrHahGut}; | |
open(FILE_RULE, ">>" . $fileRule) or &utlDie("Cannot open " . $fileRule); | |
open(FILE_HINT, ">>" . $fileHint) or &utlDie("Cannot open " . $fileHint); | |
foreach my $lib (keys(%$ptrHahCppLibTab)) | |
{ | |
if (not &hasRule($ptrHahRuleGut, $lib, "*")) | |
{ | |
&utlLog(1, "Adding rule to exclude " . $lib . " due to C++\n"); | |
&addRule($ptrHahRuleGut, $lib, "*", \*FILE_RULE); | |
&addHint($ptrHahHintGut, $lib, "*", "*", \*FILE_HINT); | |
$ptrHahLibErr->{$lib} = 1; | |
} | |
} | |
close(FILE_HINT); | |
close(FILE_RULE); | |
} | |
} | |
BEGIN | |
{ | |
my $hasExcludedCppLib = 0; | |
sub handleObjSymErr | |
{ | |
my ($ptrHahSymTable, $ptrHahRule, $ptrHahHint, $ptrHahError, $excludeCppLib) = @_; | |
my $ptrHahObjSymErr = $ptrHahError->{ptrHahObjSymErr}; | |
if (scalar keys(%$ptrHahObjSymErr) > 0) | |
{ | |
my $ptrHahSymToObjTab = $ptrHahSymTable->{ptrHahSymToObjTab}; | |
my $ptrHahCppLibTab = $ptrHahSymTable->{ptrHahCppLibTab}; | |
my $ptrHahLibObjRef = $ptrHahError->{ptrHahLibObjRef}; | |
foreach my $obj (keys(%$ptrHahObjSymErr)) | |
{ | |
foreach my $sym (keys(%{$ptrHahObjSymErr->{$obj}})) | |
{ | |
my $type = $ptrHahObjSymErr->{$obj}->{$sym}; | |
my $ptrHahLibObj = $ptrHahSymToObjTab->{$sym}->{$type}; | |
foreach my $lib (keys(%$ptrHahLibObj)) | |
{ | |
if (exists($ptrHahLibObj->{$lib}->{$obj})) | |
{ | |
if (($hasExcludedCppLib == 1) || ($excludeCppLib == 0) || ($ptrHahCppLibTab == 0) || (not exists($ptrHahCppLibTab->{$lib}))) | |
{ | |
&utlLog(1, "Finding " . $obj . " with " . $sym . " from " . $lib . "\n"); | |
$ptrHahLibObjRef->{$lib} = {} if (not exists($ptrHahLibObjRef->{$lib})); | |
$ptrHahLibObjRef->{$lib}->{$obj} = 1; | |
} | |
} | |
} | |
} | |
} | |
if (($hasExcludedCppLib == 0) && $excludeCppLib) | |
{ | |
&ruleOutCppLib($ptrHahSymTable, $ptrHahRule, $ptrHahHint, $ptrHahError->{ptrHahLibErr}); | |
$hasExcludedCppLib = 1; | |
} | |
} | |
} | |
} | |
sub examineLibGut | |
{ | |
my ($lib, $ptrHahSymTable, $ptrHahRuleGut, $hdlFileRule, $ptrHahHintGut, $hdlFileHint, $ptrHahError) = @_; | |
my $ptrHahSymToObjTab = $ptrHahSymTable->{ptrHahSymToObjTab}; | |
my $ptrHahSymErr = $ptrHahError->{ptrHahLibSymErr}->{$lib}; | |
my $ptrHahLibErr = $ptrHahError->{ptrHahLibErr}; | |
if (not &hasRule($ptrHahRuleGut, $lib, "*")) | |
{ | |
&utlLog(1, "Examining " . $lib . "\n"); | |
foreach my $sym (keys(%$ptrHahSymErr)) | |
{ | |
my $type = $ptrHahSymErr->{$sym}; | |
foreach my $obj (keys(%{$ptrHahSymToObjTab->{$sym}->{$type}->{$lib}})) | |
{ | |
if (not &hasRule($ptrHahRuleGut, $lib, $obj)) | |
{ | |
&utlLog(1, "Adding rule to exclude " . $lib . "(" . $obj . ") due to error symbol " . $sym . "\n"); | |
&addRule($ptrHahRuleGut, $lib, $obj, $hdlFileRule); | |
&addHint($ptrHahHintGut, $lib, $obj, $sym, $hdlFileHint); | |
$ptrHahLibErr->{$lib} = 1; | |
} | |
} | |
} | |
} | |
} | |
sub examineLibGutExt | |
{ | |
my ($libRef, $ptrHahSymTable, $ptrHahRuleGut, $hdlFileRule, $ptrHahHintGut, $hdlFileHint, $ptrHahError, $ptrHahRefObjSet) = @_; | |
my $ptrHahObjToSymTab = $ptrHahSymTable->{ptrHahObjToSymTab}; | |
my $ptrHahSymToObjTab = $ptrHahSymTable->{ptrHahSymToObjTab}; | |
my $ptrHahLibErr = $ptrHahError->{ptrHahLibErr}; | |
my %excludedLib = (); | |
my @refObjList = (); | |
my $count = 0; | |
&utlLog(1, "Searching libraries/objects for referred symbols to exclude...\n"); | |
foreach my $objRef (keys(%{$ptrHahError->{ptrHahLibObjRef}->{$libRef}})) | |
{ | |
if ( (not exists($ptrHahRefObjSet->{$libRef})) | |
|| (not exists($ptrHahRefObjSet->{$libRef}->{$objRef}))) | |
{ | |
$ptrHahRefObjSet->{$libRef} = {} if (not exists($ptrHahRefObjSet->{$libRef})); | |
$ptrHahRefObjSet->{$libRef}->{$objRef} = 1; | |
} | |
elsif ($ptrHahRefObjSet->{$libRef}->{$objRef} != 1) | |
{ | |
next; | |
} | |
push(@refObjList, $libRef); | |
push(@refObjList, $objRef); | |
} | |
$count = $#refObjList + 1; | |
while ($count > 0) | |
{ | |
my $refLib = shift(@refObjList); | |
my $refObj = shift(@refObjList); | |
my @symDef = keys(%{$ptrHahObjToSymTab->{$refLib}->{$refObj}->{+SYM_DEF}}); | |
&utlLog(2, "Defined symbols in " . $refLib . "(" . $refObj . "): @symDef\n"); | |
$ptrHahRefObjSet->{$refLib}->{$refObj} = 2; | |
foreach my $symbol (@symDef) | |
{ | |
my $ptrHahLibObjSymUndef = $ptrHahSymToObjTab->{$symbol}->{+SYM_UNDEF}; | |
my @libList = keys(%$ptrHahLibObjSymUndef); | |
foreach my $lib (@libList) | |
{ | |
if (not exists($excludedLib{$lib})) | |
{ | |
if (&hasRule($ptrHahRuleGut, $lib, "*")) | |
{ | |
my @objList = keys(%{$ptrHahLibObjSymUndef->{$lib}}); | |
foreach my $obj (@objList) | |
{ | |
if ((not exists($ptrHahRefObjSet->{$lib})) || (not exists($ptrHahRefObjSet->{$lib}->{$obj}))) | |
{ | |
&utlLog(1, "Using " . $lib . "(" . $obj . ") to exclude objects due to reference to " . $symbol . " in " . $refLib . "(" . $refObj . ")\n"); | |
push(@refObjList, $lib); | |
push(@refObjList, $obj); | |
$ptrHahRefObjSet->{$lib} = {} if (not exists($ptrHahRefObjSet->{$lib})); | |
$ptrHahRefObjSet->{$lib}->{$obj} = 1; | |
} | |
} | |
} | |
else | |
{ | |
&utlLog(1, "Adding rule to exclude " . $lib . " due to reference to " . $symbol . " in " . $refLib . "(" . $refObj . ")\n"); | |
&addRule($ptrHahRuleGut, $lib, "*", $hdlFileRule); | |
&addHint($ptrHahHintGut, $lib, "*", "*", $hdlFileHint); | |
$ptrHahLibErr->{$lib} = 1; | |
$excludedLib{$lib} = 1; | |
} | |
} | |
} | |
} | |
last if (scalar keys(%excludedLib)); | |
$count = $#refObjList + 1; | |
&utlLog(2, "Referred objects(" . $count . "): @refObjList\n"); | |
} | |
} | |
sub examineLib | |
{ | |
my ($ptrHahSymTable, $ptrHahRule, $ptrHahHint, $ptrHahError) = @_; | |
my $fileRule = $ptrHahRule->{file}; | |
my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut}; | |
my $fileHint = $ptrHahHint->{file}; | |
my $ptrHahHintGut = $ptrHahHint->{ptrHahGut}; | |
my $ptrHahLibSymErr = $ptrHahError->{ptrHahLibSymErr}; | |
my $ptrHahLibObjRef = $ptrHahError->{ptrHahLibObjRef}; | |
my %refObjSet = (); | |
open(FILE_HINT, ">>" . $fileHint) or &utlDie("Cannot open " . $fileHint); | |
open(FILE_RULE, ">>" . $fileRule) or &utlDie("Cannot open " . $fileRule); | |
# Handle error symbols. | |
foreach my $lib (keys(%$ptrHahLibSymErr)) | |
{ | |
&examineLibGut($lib, $ptrHahSymTable, $ptrHahRuleGut, \*FILE_RULE, $ptrHahHintGut, \*FILE_HINT, $ptrHahError); | |
} | |
# Handle referred objects. | |
foreach my $lib (keys(%$ptrHahLibObjRef)) | |
{ | |
&examineLibGutExt($lib, $ptrHahSymTable, $ptrHahRuleGut, \*FILE_RULE, $ptrHahHintGut, \*FILE_HINT, $ptrHahError, \%refObjSet); | |
} | |
close(FILE_RULE); | |
close(FILE_HINT); | |
} | |
# ----------------------------------------------------------------------------- | |
sub getDisplayValue | |
{ | |
my ($formatStr, $value) = @_; | |
if ($formatStr =~ /!/) | |
{ | |
return "on" if ($value); | |
return "off"; | |
} | |
return $value; | |
} | |
sub help | |
{ | |
my ($ptrHahOptDesc) = @_; | |
printf("\nPartial Link Auto-Filter Script (%s) ver. %s\n", basename( __FILE__), $Version); | |
printf("\nOptions:\n\n"); | |
foreach my $key (sort(keys(%$ptrHahOptDesc))) | |
{ | |
printf("%s\n", $ptrHahOptDesc->{$key}->[1]); | |
printf("\t\t%s", $ptrHahOptDesc->{$key}->[2]); | |
printf(" (default: %s)", &getDisplayValue($ptrHahOptDesc->{$key}->[0], $ptrHahOptDesc->{$key}->[3])) if ($ptrHahOptDesc->{$key}->[3] ne ""); | |
printf("\n"); | |
} | |
printf("\nAn example:\n\n"); | |
printf("Command: perl %s --lib-dir=build\\ASTRO36V3_DEMO\\tdd128dpa\\MT6236o\\lib --lib-dir=mtk_lib\\MT6236\\S00\\tdd128dpa\\CMCC_TD0200_SEGE --scatter-file=custom\\system\\ASTRO36V3_DEMO_BB\\scatASTRO36V3_DEMO_FOTA.txt --link-option-file=make\\~sortedLibs.tmp --nm=pcore\\tools\\MinGW\\bin\\arm-none-eabi-nm.exe --readelf=pcore\\tools\\MinGW\\bin\\arm-none-eabi-readelf.exe --strip=pcore\\tools\\MinGW\\bin\\arm-none-eabi-strip.exe\n\n", __FILE__); | |
} | |
use constant { | |
TYPE_AUTO => 1, | |
TYPE_NORMAL => 2, | |
TYPE_PARTIAL => 3, | |
}; | |
sub getOption | |
{ | |
my ($ptrHahOpt, $ptrHahOptPath, $ptrHahOptPathMust) = @_; | |
my %optDesc = ( | |
"ptrAryLibDir" => [ "lib-dir=s", "--lib-dir=", "a path to a library directory for partial link", "" ], | |
"ptrAryUserExclusionFile" => [ "exclusion-file=s", "--exclusion-file=", "a path to a user exclusion file", "" ], | |
"fileScatter" => [ "scatter-file=s", "--scatter-file=", "a path to a scatter file", "" ], | |
"fileLinkOption" => [ "link-option-file=s", "--link-option-file=", "a path to a file with link options for final link", "" ], | |
"dirInfo" => [ "info-dir=s", "--info-dir=", "a path to a directory to access info", $ptrHahOptPathMust->{dirInfo} ], | |
"dirSave" => [ "save-dir=s", "--save-dir=", "a path to a directory to save log", $ptrHahOptPathMust->{dirSave} ], | |
"dirTemp" => [ "temp-dir=s", "--temp-dir=", "a path to a temp directory", $ptrHahOptPathMust->{dirTemp} . "/pl_temp" ], | |
"cmd_nm" => [ "nm=s", "--nm=", "a path to command nm", "" ], | |
"cmd_readelf" => [ "readelf=s", "--readelf=", "a path to command readelf", "" ], | |
"cmd_strip" => [ "strip=s", "--strip=", "a path to command strip", "" ], | |
"cmd_armar" => [ "armar=s", "--armar=", "a path to command armar", $Cmd_armar ], | |
"cmd_armlink" => [ "armlink=s", "--armlink=", "a path to command armlink", $Cmd_armlink ], | |
"fileLinkErr" => [ "link-err-file=s", "--link-err-file=", "a path to a file to output link error", "" ], | |
"reGenRule" => [ "regen-rule!", "--[no-]regen-rule", "re-generate rule", $ptrHahOpt->{reGenRule} ], | |
"reGenHint" => [ "regen-hint!", "--[no-]regen-hint", "re-generate hint", $ptrHahOpt->{reGenHint} ], | |
"hintToRule" => [ "hint-to-rule!", "--[no-]hint-to-rule", "convert hint to rule", $ptrHahOpt->{hintToRule} ], | |
"excludeCppLib" => [ "exclude-cpp-lib!", "--[no-]exclude-cpp-lib", "exclude all C++ libraries when errors happen", $ptrHahOpt->{excludeCppLib} ], | |
"passLimit" => [ "pass-limit=i", "--pass-limit=", "set limitation of the max. pass to resolve linking error", $ptrHahOpt->{passLimit} ], | |
"simulate" => [ "simulate!", "--[no-]simulate", "run the whole process without modifying libraries", $ptrHahOpt->{simulate} ], | |
"linkType" => [ "link-type=i", "--link-type=", "specify 1 for \"auto enabling partial link\", 2 for \"normal link\", or 3 for \"partial link\"", $ptrHahOpt->{linkType} ], | |
"libSizeInfo" => [ "lib-size-info!", "--[no-]lib-size-info", "generate library size info", $ptrHahOpt->{libSizeInfo} ], | |
"stripDebugInfo" => [ "strip-debug-info!", "--[no-]strip-debug-info", "strip debug info", $ptrHahOpt->{stripDebugInfo} ], | |
"stripDebugCount" => [ "strip-debug-count=i", "--strip-debug-count=", "set default count to strip debug info if \"pl_debug.txt\" is not available", $ptrHahOpt->{stripDebugCount} ], | |
"check" => [ "check!", "--[no-]check", "not to run if partial link is done last time", $ptrHahOpt->{check} ], | |
"forcePartialLink" => [ "force-partial-link!", "--[no-]force-partial-link", "force to run partial link only", $ptrHahOpt->{forcePartialLink} ], | |
"update" => [ "update!", "--[no-]update", "update libraries specified in \"--lib-dir=...\" with partially-linked ones", $ptrHahOpt->{update} ], | |
"save" => [ "save!", "--[no-]save", "save partially-linked libraries", $ptrHahOpt->{save} ], | |
"dbgLevel" => [ "debug-level=i", "--debug-level=", "set debug level", $DbgLevel ], | |
"infoLevel" => [ "info-level=i", "--info-level=", "set how much information displays in the screen", $InfoLevel ], | |
"help" => [ "help", "--help", "show this help", "" ], | |
); | |
if (!GetOptions( | |
$optDesc{ptrAryLibDir}[0] => \@{$ptrHahOptPathMust->{ptrAryLibDir}}, | |
$optDesc{ptrAryUserExclusionFile}[0] => \@{$ptrHahOptPath->{ptrAryUserExclusionFile}}, | |
$optDesc{fileScatter}[0] => \$ptrHahOptPathMust->{fileScatter}, | |
$optDesc{fileLinkOption}[0] => \$ptrHahOptPathMust->{fileLinkOption}, | |
$optDesc{dirInfo}[0] => \$ptrHahOptPathMust->{dirInfo}, | |
$optDesc{dirSave}[0] => \$ptrHahOptPathMust->{dirSave}, | |
$optDesc{dirTemp}[0] => \$ptrHahOptPathMust->{dirTemp}, | |
$optDesc{cmd_nm}[0] => \$ptrHahOptPathMust->{cmd_nm}, | |
$optDesc{cmd_readelf}[0] => \$ptrHahOptPathMust->{cmd_readelf}, | |
$optDesc{cmd_strip}[0] => \$ptrHahOptPathMust->{cmd_strip}, | |
$optDesc{cmd_armar}[0] => \$ptrHahOptPath->{cmd_armar}, | |
$optDesc{cmd_armlink}[0] => \$ptrHahOptPath->{cmd_armlink}, | |
$optDesc{fileLinkErr}[0] => \$ptrHahOptPath->{fileLinkErr}, | |
$optDesc{reGenRule}[0] => \$ptrHahOpt->{reGenRule}, | |
$optDesc{reGenHint}[0] => \$ptrHahOpt->{reGenHint}, | |
$optDesc{hintToRule}[0] => \$ptrHahOpt->{hintToRule}, | |
$optDesc{excludeCppLib}[0] => \$ptrHahOpt->{excludeCppLib}, | |
$optDesc{passLimit}[0] => \$ptrHahOpt->{passLimit}, | |
$optDesc{simulate}[0] => \$ptrHahOpt->{simulate}, | |
$optDesc{linkType}[0] => \$ptrHahOpt->{linkType}, | |
$optDesc{libSizeInfo}[0] => \$ptrHahOpt->{libSizeInfo}, | |
$optDesc{stripDebugInfo}[0] => \$ptrHahOpt->{stripDebugInfo}, | |
$optDesc{stripDebugCount}[0] => \$ptrHahOpt->{stripDebugCount}, | |
$optDesc{check}[0] => \$ptrHahOpt->{check}, | |
$optDesc{forcePartialLink}[0] => \$ptrHahOpt->{forcePartialLink}, | |
$optDesc{update}[0] => \$ptrHahOpt->{update}, | |
$optDesc{save}[0] => \$ptrHahOpt->{save}, | |
$optDesc{dbgLevel}[0] => \$DbgLevel, | |
$optDesc{infoLevel}[0] => \$InfoLevel, | |
$optDesc{help}[0] => \$ptrHahOpt->{help}) || $ptrHahOpt->{help}) | |
{ | |
&help(\%optDesc); | |
return 1; | |
} | |
foreach my $key (keys(%$ptrHahOptPath)) | |
{ | |
if (ref($ptrHahOptPath->{$key}) eq 'ARRAY') | |
{ | |
for (my $i = 0; $i <= $#{$ptrHahOptPath->{$key}}; $i++) | |
{ | |
$ptrHahOptPath->{$key}->[$i] = &utlTrim($ptrHahOptPath->{$key}->[$i]); | |
&utlDie("Value of option " . $optDesc{$key}[1] . " cannot be empty") if ($ptrHahOptPath->{$key}->[$i] eq ""); | |
$ptrHahOptPath->{$key}->[$i] = &utlAbsPath($ptrHahOptPath->{$key}->[$i]); | |
} | |
} | |
else | |
{ | |
$ptrHahOptPath->{$key} = &utlTrim($ptrHahOptPath->{$key}); | |
if ($ptrHahOptPath->{$key} ne "") | |
{ | |
if (($key eq "fileLinkErr") && (! -e $ptrHahOptPath->{$key})) | |
{ | |
my $path = dirname($ptrHahOptPath->{$key}); | |
my $fileName = basename($ptrHahOptPath->{$key}); | |
&utlDie("Cannot find " . $path) unless (-e $path); | |
$ptrHahOptPath->{$key} = &utlAbsPath($path) . "/" . $fileName; | |
} | |
else | |
{ | |
$ptrHahOptPath->{$key} = &utlAbsPath($ptrHahOptPath->{$key}); | |
} | |
} | |
elsif ($optDesc{$key}->[3] ne "") | |
{ | |
$ptrHahOptPath->{$key} = $optDesc{$key}->[3]; | |
} | |
} | |
} | |
foreach my $key (keys(%$ptrHahOptPathMust)) | |
{ | |
if (ref($ptrHahOptPathMust->{$key}) eq 'ARRAY') | |
{ | |
my $ptrAryPath = []; | |
&utlDie("Must specify " . $optDesc{$key}[1]) if ($#{$ptrHahOptPathMust->{$key}} < 0); | |
for (my $i = 0; $i <= $#{$ptrHahOptPathMust->{$key}}; $i++) | |
{ | |
my $path = $ptrHahOptPathMust->{$key}->[$i]; | |
$path = &utlTrim($path); | |
&utlDie("Value of option " . $optDesc{$key}[1] . " cannot be empty") if ($path eq ""); | |
if (-e $path) | |
{ | |
push(@$ptrAryPath, &utlAbsPath($path)); | |
} | |
else | |
{ | |
&utlLog(0, "Ignore " . $path . " due to no existence\n"); | |
} | |
} | |
&utlDie("No valid path is specified by option " . $optDesc{$key}[1]) unless ($#$ptrAryPath >= 0); | |
$ptrHahOptPathMust->{$key} = $ptrAryPath; | |
} | |
else | |
{ | |
$ptrHahOptPathMust->{$key} = &utlTrim($ptrHahOptPathMust->{$key}); | |
&utlDie("Value of option " . $optDesc{$key}[1] . " cannot be empty") if ($ptrHahOptPathMust->{$key} eq ""); | |
$ptrHahOptPathMust->{$key} = &utlAbsPath($ptrHahOptPathMust->{$key}); | |
} | |
} | |
if ( ($ptrHahOpt->{linkType} != TYPE_AUTO) | |
&& ($ptrHahOpt->{linkType} != TYPE_NORMAL) | |
&& ($ptrHahOpt->{linkType} != TYPE_PARTIAL)) | |
{ | |
&utlDie("Illegal value " . $ptrHahOpt->{linkType} . " for option " . $optDesc{linkType}[1]); | |
} | |
return 0; | |
} | |
sub formatCmd | |
{ | |
my ($cmd) = @_; | |
$cmd =~ s/\(/"("/g; | |
$cmd =~ s/\)/")"/g; | |
return $cmd; | |
} | |
sub dumpOpt | |
{ | |
my ($ptrHah) = @_; | |
foreach my $key (keys(%$ptrHah)) | |
{ | |
&utlLog(1, "-> " . $key . "\n"); | |
&utlDump(1, $ptrHah->{$key}); | |
} | |
} | |
BEGIN | |
{ | |
my $_file = ""; | |
sub setupErrorHandling | |
{ | |
my ($file) = @_; | |
&utlRmFile(dirname($file) . "/" . basename($FileErr)); | |
$_file = $file; | |
} | |
sub errorHandling | |
{ | |
if ($_file ne "") | |
{ | |
&utlCpFile($FileErr, $_file); | |
&utlCpFile($FileErr, dirname($_file)); | |
} | |
} | |
} | |
sub readIniFile | |
{ | |
my ($ptrHahIni) = @_; | |
my $fileIni = $ptrHahIni->{file}; | |
my $ptrHahAttr = $ptrHahIni->{ptrHahAttr}; | |
my $ptrHahValue = $ptrHahIni->{ptrHahValue}; | |
my $ptrHahOnOff = $ptrHahIni->{ptrHahOnOff}; | |
if (-e $fileIni) | |
{ | |
open(FILE_INI, "<" . $fileIni) or &utlDie("Cannot open " . $fileIni); | |
foreach my $line (<FILE_INI>) | |
{ | |
next if (($line =~ /^\s*$/) || ($line =~ /^\s*;/)); | |
# key = value | |
if ($line =~ /^\s*(\S+)\s*=\s*([-]?\d+)/) | |
{ | |
my $key = $1; | |
my $value = $2; | |
if (exists($ptrHahAttr->{$key})) | |
{ | |
$ptrHahAttr->{$key} = $value; | |
} | |
elsif (exists($ptrHahValue->{$key})) | |
{ | |
$ptrHahValue->{$key}->[0] = 1; | |
${$ptrHahValue->{$key}->[1]} = $value; | |
if ($#{$ptrHahValue->{$key}} > 1) | |
{ | |
my $found = 0; | |
for (my $i = 2; $i <= $#{$ptrHahValue->{$key}}; $i++) | |
{ | |
if ($value == $ptrHahValue->{$key}->[$i]) | |
{ | |
$found = 1; | |
last; | |
} | |
} | |
&utlDie("Invalid value \"" . $value . "\" for " . $key . " in " . $fileIni) unless ($found); | |
} | |
} | |
elsif (exists($ptrHahOnOff->{$key})) | |
{ | |
if (($value == 1) || ($value == 0)) | |
{ | |
$ptrHahOnOff->{$key}->[0] = 1; | |
${$ptrHahOnOff->{$key}->[1]} = $value; | |
} | |
else | |
{ | |
&utlDie("Invalid value \"" . $value . "\" for " . $key . " in " . $fileIni . "; should be 0 for disable and 1 for enable"); | |
} | |
} | |
else | |
{ | |
&utlDie("Invalid key \"" . $key . "\" in " . $fileIni); | |
} | |
} | |
else | |
{ | |
&utlDie("Unrecognized line \"" . $line . "\" in " . $fileIni); | |
} | |
} | |
close(FILE_INI); | |
} | |
} | |
sub writeIniFile | |
{ | |
my ($ptrHahIni) = @_; | |
my $fileIni = $ptrHahIni->{file}; | |
my $flag = $ptrHahIni->{flag}; | |
my $ptrHahAttr = $ptrHahIni->{ptrHahAttr}; | |
my $ptrHahValue = $ptrHahIni->{ptrHahValue}; | |
my $ptrHahOnOff = $ptrHahIni->{ptrHahOnOff}; | |
if ($flag != 0) | |
{ | |
open(FILE_INI, ">" . $fileIni) or &utlDie("Cannot open " . $fileIni); | |
print(FILE_INI "\n; DO NOT MODIFY THE FOLLOWING INFORMATION\n\n"); | |
foreach my $key (keys(%$ptrHahAttr)) | |
{ | |
print(FILE_INI $key . "=" . $ptrHahAttr->{$key} . "\n"); | |
} | |
print(FILE_INI "\n; UNCOMMENT THE FOLLOWING TO OVERRIDE CORRESPONDING SETTINGS BY REMOVING \";\"\n\n"); | |
foreach my $key (keys(%$ptrHahValue)) | |
{ | |
if ($ptrHahValue->{$key}->[0] != 0) | |
{ | |
print(FILE_INI $key . "=" . ${$ptrHahValue->{$key}->[1]} . "\n"); | |
} | |
else | |
{ | |
print(FILE_INI "; " . $key . "=" . ${$ptrHahValue->{$key}->[1]} . "\n"); | |
} | |
} | |
foreach my $key (keys(%$ptrHahOnOff)) | |
{ | |
if ($ptrHahOnOff->{$key}->[0] != 0) | |
{ | |
print(FILE_INI $key . "=" . ${$ptrHahOnOff->{$key}->[1]} . "\n"); | |
} | |
elsif (${$ptrHahOnOff->{$key}->[1]}) | |
{ | |
print(FILE_INI "; " . $key . "=0\n"); | |
} | |
else | |
{ | |
print(FILE_INI "; " . $key . "=1\n"); | |
} | |
} | |
close(FILE_INI); | |
} | |
} | |
sub setIni | |
{ | |
my ($ptrHahIni, $key, $value) = @_; | |
$ptrHahIni->{ptrHahAttr}->{$key} = $value; | |
$ptrHahIni->{flag} = 1; | |
} | |
sub syncLib | |
{ | |
my ($ptrHahLib) = @_; | |
my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir}; | |
my $suffix = $ptrHahLib->{suffix}; | |
my $suffix_bak = $ptrHahLib->{suffix_bak}; | |
foreach my $dirSrcLib (@$ptrAryLibDir) | |
{ | |
my $dirDstLib = $dirSrcLib . $suffix; | |
my $dirSrcBak = $dirSrcLib . $suffix_bak; | |
if ((-e $dirSrcBak) && (-e $dirDstLib)) | |
{ | |
my @libList = glob($dirSrcLib . "/*"); | |
foreach my $lib (@libList) | |
{ | |
if (-f $lib) | |
{ | |
my $libName = basename($lib); | |
my $timestamp = &utlGetTimestamp($lib); | |
my $libDst = $dirDstLib . "/" . $libName; | |
if ((-e $libDst) && ($timestamp == &utlGetTimestamp($libDst))) | |
{ | |
my $libSrcBak = $dirSrcBak . "/" . $libName; | |
if (-e $libSrcBak) | |
{ | |
&utlLog(1, "Restoring " . $libName . "\n"); | |
&utlCpFile($libSrcBak, $lib) if ($timestamp != &utlGetTimestamp($libSrcBak)); | |
} | |
} | |
} | |
} | |
} | |
&utlRmTree($dirSrcBak); | |
&utlRmTree($dirDstLib); | |
&utlRmTree($dirSrcLib . $ptrHahLib->{suffix_dbg}); | |
&utlRmTree($dirSrcLib . $ptrHahLib->{suffix_save}); | |
} | |
} | |
sub checkLib | |
{ | |
my ($ptrHahLib) = @_; | |
my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir}; | |
my $fileTimestamp = $ptrHahLib->{fileTimestamp}; | |
my $ptrHahLibNew = $ptrHahLib->{ptrHahLibNew}; | |
my $ptrHahLibUpdate = $ptrHahLib->{ptrHahLibUpdate}; | |
my %timestamp = (); | |
# Load timestamp of each library. | |
if (-e $fileTimestamp) | |
{ | |
open(FILE_TS, "<" . $fileTimestamp) or &utlDie("Cannot open " . $fileTimestamp); | |
foreach my $line (<FILE_TS>) | |
{ | |
if ($line =~ /^\s*(\S+)\s*(\S+)/) | |
{ | |
$timestamp{$1} = $2; | |
} | |
} | |
close(FILE_TS); | |
} | |
foreach my $dirSrcLib (@$ptrAryLibDir) | |
{ | |
my @libList = glob($dirSrcLib . "/*.lib"); | |
foreach my $lib (@libList) | |
{ | |
my $curTimestamp = (stat($lib))[9]; | |
my $libName = basename($lib); | |
next if (exists($IgnoredLib{$libName})); | |
if (not exists($timestamp{$libName})) | |
{ | |
$ptrHahLibNew->{$libName} = 1; | |
} | |
elsif ($curTimestamp > $timestamp{$libName}) | |
{ | |
$ptrHahLibUpdate->{$libName} = 1; | |
} | |
} | |
} | |
} | |
sub generateLibSize | |
{ | |
my ($ptrHahLib) = @_; | |
my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir}; | |
my $ptrHahLibNew = $ptrHahLib->{ptrHahLibNew}; | |
my $ptrHahLibUpdate = $ptrHahLib->{ptrHahLibUpdate}; | |
my $dirLibSize = $ptrHahLib->{dirLibSize}; | |
&utlMkDir($dirLibSize); | |
foreach my $dirSrcLib (@$ptrAryLibDir) | |
{ | |
my @libList = glob($dirSrcLib . "/*.lib"); | |
foreach my $lib (@libList) | |
{ | |
my $libName = basename($lib); | |
if (exists($ptrHahLibNew->{$libName}) || exists($ptrHahLibUpdate->{$libName})) | |
{ | |
&utlLog(1, "Generating size info for " . $libName . "\n"); | |
&utlSystem($Cmd_armar . " --sizes " . $lib . " >" . $dirLibSize . "/" . $libName . ".txt"); | |
} | |
} | |
} | |
} | |
sub normalLinkStrip | |
{ | |
my ($ptrHanLib, $ptrHahError, $fileCppLib, $fileDbgLib, $fileLinkOption, $stripDebugCount) = @_; | |
my $ret = 0; | |
©Lib($ptrHanLib->{ptrAryLibDir}, "", $ptrHanLib->{suffix}); | |
&removeDebugInfo($ptrHanLib, $ptrHanLib->{suffix}, $fileCppLib, $fileDbgLib, $stripDebugCount); | |
$ret = &finalLink("", $fileLinkOption, $ptrHahError); | |
&removeDstLibDir($ptrHanLib, $ptrHanLib->{suffix}, "") if ($ret == LINK_OK); | |
return $ret; | |
} | |
sub partialLink | |
{ | |
my ($ptrHahOpt, $ptrHahOptPath, $ptrHahOptPathMust, $ptrHahLib, $ptrHahError, $fileCppLib, $fileDbgLib, $fileLinkOption) = @_; | |
my %rule = ( | |
"file" => $ptrHahOptPathMust->{dirSave} . "/pl.rule", | |
"fileRule" => $ptrHahOptPathMust->{dirInfo} . "/pl_rule.txt", | |
"ptrHahGut" => {}, | |
); | |
my %hint = ( | |
"file" => $ptrHahOptPathMust->{dirSave} . "/pl.hint", | |
"fileHint" => $ptrHahOptPathMust->{dirInfo} . "/pl_hint.txt", | |
"toRule" => $ptrHahOpt->{hintToRule}, | |
"ptrHahGut" => {}, | |
"use" => 1, | |
); | |
my $fileExclusion = $ptrHahOptPathMust->{dirInfo} . "/pl_exclusion.txt"; | |
my $pass = 0; | |
my $ret = 1; | |
# Remove temporary files. | |
&utlRmFile($rule{file}); | |
&utlRmFile($hint{file}); | |
# Create temporary directories for partially-linked libraries. | |
&createDstLibDir($ptrHahLib); | |
if (($ptrHahOpt->{reGenRule} == 0) && (-e $rule{fileRule})) | |
{ | |
&readRuleFile(\%rule); | |
} | |
else | |
{ | |
# Parse scatter file and output rules to the rule file. | |
&parseScatterFile($ptrHahOptPathMust->{fileScatter}, \%rule); | |
# Read user exclusion file and output rules to the rule file. | |
&readUserExclusionFile($ptrHahOptPath->{ptrAryUserExclusionFile}, \%rule); | |
# Read exclusion file and output rules to the rule file. | |
&readExclusionFile($fileExclusion, \%rule) if (-e $fileExclusion); | |
# Write built-in excluded libraries to the rule file. | |
&writeExcludedLib(\@ExcludedLib, \%rule); | |
} | |
# Read hint file and output rules to the rule file. | |
&readHintFile(\%hint, \%rule) if (($ptrHahOpt->{reGenHint} == 0) && (-e $hint{fileHint})); | |
# Generate a link option file. | |
&generateLinkOptFile($ptrHahLib, $rule{ptrHahGut}, $ptrHahOptPathMust->{fileLinkOption}, $fileLinkOption); | |
&utlLog(2, "Dumping hint...\n"); | |
&utlDump(2, $hint{ptrHahGut}); | |
&utlLog(2, "Dumping rule...\n"); | |
&utlDump(2, $rule{ptrHahGut}); | |
while ($pass < $ptrHahOpt->{passLimit}) | |
{ | |
$pass++; | |
&utlLog(1, "Pass " . $pass . "...\n"); | |
# Set a file to output linking error. | |
$ptrHahError->{file} = $ptrHahOptPathMust->{dirSave} . "/pl_error_" . $pass . ".log"; | |
if ($pass != 1) | |
{ | |
&loadSymTable($ptrHahLib, $fileCppLib); | |
&ruleOutObjWithRedefinedSym($ptrHahLib->{ptrHahSymTable}, \%rule, \%hint, $ptrHahError->{ptrHahLibErr}); | |
# Find out libraries where objects with error symbols are located. | |
&utlLog(2, "Dumping errors from objects with symbols...\n"); | |
&utlDump(2, $ptrHahError->{ptrHahObjSymErr}); | |
&handleObjSymErr($ptrHahLib->{ptrHahSymTable}, \%rule, \%hint, $ptrHahError, $ptrHahOpt->{excludeCppLib}); | |
&utlLog(2, "Dumping errors from libraries with symbols...\n"); | |
&utlDump(2, $ptrHahError->{ptrHahLibSymErr}); | |
&examineLib($ptrHahLib->{ptrHahSymTable}, \%rule, \%hint, $ptrHahError); | |
last unless (scalar keys(%{$ptrHahError->{ptrHahLibErr}})); | |
&utlLog(3, "Dumping rule...\n"); | |
&utlDump(3, $rule{ptrHahGut}); | |
} | |
# Partially link objects in the same libraries according to rule and linking error. | |
$Current_time = time; | |
system("echo T_S,partialLinkLib,P,$Current_time >> $ptrHahOptPathMust->{dirSave}/PlinkTime.log"); | |
&partialLinkLib($ptrHahLib, \%rule, \%hint, $ptrHahError->{ptrHahLibErr}); | |
$Current_time = time; | |
system("echo T_E,partialLinkLib,P,$Current_time >> $ptrHahOptPathMust->{dirSave}/PlinkTime.log"); | |
# Link all by using command from a file specified in option. | |
$ret = &finalLink("--mangled", $fileLinkOption, $ptrHahError); | |
last if (($ret == LINK_OK) || ($ret == LINK_OUT_OF_MEM) || ($ret == LINK_UNKNOWN)); | |
} | |
if ($ret == LINK_OUT_OF_MEM) | |
{ | |
if ($ptrHahOpt->{stripDebugInfo}) | |
{ | |
&utlLog(0, "Trying link with debug info stripping due to \"Fatal error: L6000U: Out of memory.\"\n"); | |
$ptrHahError->{file} = $ptrHahOptPathMust->{dirSave} . "/pl_error_dbg.log"; | |
©Lib($ptrHahLib->{ptrAryLibDir}, $ptrHahLib->{suffix}, $ptrHahLib->{suffix_dbg}); | |
&removeDebugInfo($ptrHahLib, $ptrHahLib->{suffix}, $fileCppLib, $fileDbgLib, $ptrHahOpt->{stripDebugCount}); | |
$ret = &finalLink("", $fileLinkOption, $ptrHahError); | |
$ret = LINK_OK_STRIP if ($ret == LINK_OK); | |
if (($ret == LINK_OK_STRIP) || ($ret == LINK_OUT_OF_MEM)) | |
{ | |
&removeDstLibDir($ptrHahLib, $ptrHahLib->{suffix}, ""); | |
$ptrHahLib->{suffix} = $ptrHahLib->{suffix_dbg}; | |
} | |
} | |
} | |
if (($ret == LINK_OK) || ($ret == LINK_OK_STRIP) || ($ret == LINK_OUT_OF_MEM)) | |
{ | |
if ($ptrHahOpt->{simulate}) | |
{ | |
&removeDstLibDir($ptrHahLib, $ptrHahLib->{suffix}, $ptrHahLib->{suffix_save}); | |
} | |
elsif ($ptrHahOpt->{update} == 0) | |
{ | |
my $suffix = ""; | |
$suffix = $ptrHahLib->{suffix_save} if ($ptrHahOpt->{save}); | |
&removeDstLibDir($ptrHahLib, $ptrHahLib->{suffix}, $suffix); | |
&utlCpFile($rule{file}, $rule{fileRule}); | |
&utlCpFile($hint{file}, $hint{fileHint}); | |
} | |
else | |
{ | |
&finalizeLib($ptrHahLib); | |
&utlCpFile($rule{file}, $rule{fileRule}); | |
&utlCpFile($hint{file}, $hint{fileHint}); | |
} | |
} | |
elsif ($ret != LINK_OUT_OF_MEM) | |
{ | |
&removeDstLibDir($ptrHahLib, $ptrHahLib->{suffix}, ""); | |
&removeDstLibDir($ptrHahLib, $ptrHahLib->{suffix_dbg}, ""); | |
} | |
return $ret; | |
} | |
sub generateLibTimestamp | |
{ | |
my ($ptrHahLib) = @_; | |
my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir}; | |
my $fileTimestamp = $ptrHahLib->{fileTimestamp}; | |
&utlLog(1, "Generating library timestamp\n"); | |
open(FILE_TS, ">" . $fileTimestamp) or &utlDie("Cannot open " . $fileTimestamp); | |
foreach my $dirSrcLib (@$ptrAryLibDir) | |
{ | |
my @libList = glob($dirSrcLib . "/*.lib"); | |
foreach my $lib (@libList) | |
{ | |
my $timestamp = (stat($lib))[9]; | |
my $libName = basename($lib); | |
print(FILE_TS $libName . " " . $timestamp . "\n"); | |
} | |
} | |
close(FILE_TS); | |
} | |
sub main | |
{ | |
$Current_time = time; | |
my ($argc, $argv) = @_; | |
# Set options. | |
my %opt = ( | |
"reGenRule" => 1, | |
"reGenHint" => 0, | |
"hintToRule" => 1, | |
"excludeCppLib" => 0, | |
"passLimit" => 7, | |
"simulate" => 0, | |
"linkType" => TYPE_AUTO, | |
"libSizeInfo" => 1, | |
"stripDebugInfo" => 1, | |
"stripDebugCount" => 8, | |
"check" => 0, | |
"forcePartialLink" => 0, | |
"update" => 1, | |
"save" => 0, | |
"help" => 0, | |
); | |
# Set options with validated path values. | |
my %optPath = ( | |
"ptrAryUserExclusionFile" => [], | |
"cmd_armar" => "", | |
"cmd_armlink" => "", | |
"fileLinkErr" => "", | |
); | |
my %optPathMust = ( | |
"ptrAryLibDir" => [], | |
"cmd_nm" => "", | |
"cmd_readelf" => "", | |
"cmd_strip" => "", | |
"fileScatter" => "", | |
"fileLinkOption" => "", | |
"dirInfo" => cwd(), | |
"dirSave" => cwd(), | |
"dirTemp" => cwd(), | |
); | |
my $plink_start = time; | |
my $plink_end = ""; | |
return 2 if (&getOption(\%opt, \%optPath, \%optPathMust)); | |
system("echo T_S,Plink,P,$Current_time > $optPathMust{dirSave}/PlinkTime.log"); | |
# Set global variables. | |
$FileLog = $optPathMust{dirSave} . "/pl.log"; | |
system("date/T >" . $FileLog); | |
system("time/T >>" . $FileLog); | |
$FileErr = $optPathMust{dirSave} . "/pl.err"; | |
$FileTmp = $optPathMust{dirSave} . "/pl.tmp"; | |
$DirTemp = $optPathMust{dirTemp} . "/pl_temp"; | |
$Cmd_nm = &formatCmd($optPathMust{cmd_nm}); | |
$Cmd_readelf = &formatCmd($optPathMust{cmd_readelf}); | |
$Cmd_strip = &formatCmd($optPathMust{cmd_strip}); | |
$Cmd_armar = &formatCmd($optPath{cmd_armar}); | |
$Cmd_armlink = &formatCmd($optPath{cmd_armlink}); | |
# Show command line. | |
&utlLog(1, "[@$argv]\n"); | |
&utlLog(1, "Dumping options...\n"); | |
&dumpOpt(\%opt); | |
&dumpOpt(\%optPath); | |
&dumpOpt(\%optPathMust); | |
use constant { | |
STATE_NONE => 0, | |
STATE_NORMAL_LINK => 1, | |
STATE_NORMAL_LINK_STRIP => 2, | |
STATE_PARTIAL_LINK => 3, | |
}; | |
my %ini = ( | |
"file" => $optPathMust{dirInfo} . "/pl.ini", | |
"flag" => 0, | |
"ptrHahAttr" => { | |
"state" => STATE_NONE, | |
"link" => LINK_NONE, | |
}, | |
"ptrHahValue" => { | |
"pass_limit" => [ 0, \$opt{passLimit} ], | |
"link_type" => [ 0, \$opt{linkType}, TYPE_AUTO, TYPE_NORMAL, TYPE_PARTIAL ], | |
"strip_debug_count" => [ 0, \$opt{stripDebugCount} ], | |
}, | |
"ptrHahOnOff" => { | |
"regen_hint" => [ 0, \$opt{reGenHint} ], | |
"exclude_cpp_lib" => [ 0, \$opt{excludeCppLib} ], | |
"simulate" => [ 0, \$opt{simulate} ], | |
"strip_debug_info" => [ 0, \$opt{stripDebugInfo} ], | |
"check" => [ 0, \$opt{check} ], | |
"force_partial_link" => [ 0, \$opt{forcePartialLink} ], | |
"update" => [ 0, \$opt{update} ], | |
"save" => [ 0, \$opt{save} ], | |
}, | |
); | |
my %lib = ( | |
"ptrAryLibDir" => $optPathMust{ptrAryLibDir}, | |
"suffix" => "__PARTIAL_LINK_TEMPORARY", | |
"suffix_bak" => "__PARTIAL_LINK_SRC_BACKUP", | |
"suffix_dbg" => "__PARTIAL_LINK_DBG", | |
"suffix_save" => "__PARTIAL_LINK", | |
"fileTimestamp" => $optPathMust{dirInfo} . "/pl_timestamp.txt", | |
"dirLibSize" => $optPathMust{dirInfo} . "/pl_lib_size", | |
"ptrHahLibNew" => {}, | |
"ptrHahLibUpdate" => {}, | |
"ptrHahLibUsage" => {}, | |
"ptrHahNoDbgLib" => {}, | |
"ptrHahSymTable" => {}, | |
); | |
my %error = ( | |
"file" => "", | |
"fileOutput" => $optPath{fileLinkErr}, | |
"ptrHahObjSymErr" => 0, | |
"ptrHahLibSymErr" => 0, | |
"ptrHahLibObjRef" => 0, | |
"ptrHahLibErr" => 0, | |
); | |
my $fileCppLib = $optPathMust{dirInfo} . "/pl_cpp.txt"; | |
my $fileDbgLib = $optPathMust{dirInfo} . "/pl_debug.txt"; | |
my $fileLinkOption = $optPathMust{dirSave} . "/pl_link_opt.via"; | |
my $flagNormalLink = 0; | |
my $flagPartialLink = 0; | |
my $state = STATE_PARTIAL_LINK; | |
my $link = LINK_UNKNOWN; | |
my $ret = 1; | |
# Register an error handling. | |
&setupErrorHandling($error{fileOutput}); | |
&sysDieRegister(\&errorHandling); | |
&utlRmFile($FileErr); | |
&utlRmFile($FileTmp); | |
&utlRmTree($DirTemp); | |
&readIniFile(\%ini); | |
&syncLib(\%lib); | |
&checkLib(\%lib); | |
&generateLibSize(\%lib) if ($opt{libSizeInfo}); | |
&dumpOpt(\%ini); | |
&dumpOpt(\%lib); | |
if ( ($opt{check} != 0) | |
# Libraries are not updated. | |
&& (scalar keys(%{$lib{ptrHahLibNew}}) == 0) | |
&& (scalar keys(%{$lib{ptrHahLibUpdate}}) == 0) | |
# Libraries were partially linked successfully last time. | |
&& ($ini{ptrHahAttr}->{state} == STATE_PARTIAL_LINK) | |
&& ( ($ini{ptrHahAttr}->{link} == LINK_OK) | |
|| ($ini{ptrHahAttr}->{link} == LINK_OK_STRIP))) | |
{ | |
&utlLog(0, "Partial link is done last time\n"); | |
return 0; | |
} | |
# Decide what to do according to result from last time. | |
if ( ($opt{forcePartialLink} == 0) | |
# Stripping debug info is enabled. | |
&& ($opt{stripDebugInfo} != 0) | |
# Libraries are not updated. | |
&& (scalar keys(%{$lib{ptrHahLibNew}}) == 0) | |
&& (scalar keys(%{$lib{ptrHahLibUpdate}}) == 0) | |
# Libraries were stripped successfully last time. | |
&& ( ( ($ini{ptrHahAttr}->{state} == STATE_NORMAL_LINK_STRIP) | |
&& ( ($ini{ptrHahAttr}->{link} == LINK_OK) | |
|| ($ini{ptrHahAttr}->{link} == LINK_OUT_OF_MEM))) | |
|| ( ($ini{ptrHahAttr}->{state} == STATE_PARTIAL_LINK) | |
&& ( ($ini{ptrHahAttr}->{link} == LINK_OK_STRIP) | |
|| ($ini{ptrHahAttr}->{link} == LINK_OUT_OF_MEM))))) | |
{ | |
$state = STATE_NORMAL_LINK_STRIP; | |
} | |
elsif ( ($opt{forcePartialLink} != 0) | |
|| ($opt{linkType} == TYPE_PARTIAL)) | |
{ | |
$state = STATE_PARTIAL_LINK; | |
} | |
else | |
{ | |
$state = STATE_NORMAL_LINK; | |
} | |
while (1) | |
{ | |
my $curState = $state; | |
if ($curState == STATE_NORMAL_LINK) | |
{ | |
&utlLog(0, "Trying normal link...\n"); | |
$flagNormalLink = 1; | |
$error{file} = $optPathMust{dirSave} . "/pl_error_normal.log"; | |
$link = &finalLink("", $optPathMust{fileLinkOption}, \%error); | |
if ($link == LINK_OUT_OF_MEM) | |
{ | |
if ($opt{linkType} == TYPE_AUTO) | |
{ | |
$state = STATE_PARTIAL_LINK if ($flagPartialLink == 0); | |
} | |
elsif ($opt{linkType} == TYPE_NORMAL) | |
{ | |
$state = STATE_NORMAL_LINK_STRIP if ($opt{stripDebugInfo}); | |
} | |
} | |
} | |
elsif ($curState == STATE_NORMAL_LINK_STRIP) | |
{ | |
&utlLog(0, "Trying normal link with debug info stripping...\n"); | |
&generateLinkOptFile(\%lib, 0, $optPathMust{fileLinkOption}, $fileLinkOption); | |
$error{file} = $optPathMust{dirSave} . "/pl_error_dbg.log"; | |
$link = &normalLinkStrip(\%lib, \%error, $fileCppLib, $fileDbgLib, $fileLinkOption, $opt{stripDebugCount}); | |
} | |
elsif ($curState == STATE_PARTIAL_LINK) | |
{ | |
&utlLog(0, "Trying partial link...\n"); | |
$flagPartialLink = 1; | |
$link = &partialLink(\%opt, \%optPath, \%optPathMust, \%lib, \%error, $fileCppLib, $fileDbgLib, $fileLinkOption); | |
$state = STATE_NORMAL_LINK if (($opt{forcePartialLink} == 0) && ($flagNormalLink == 0) && ($link != LINK_OK) && ($link != LINK_OK_STRIP) && ($link != LINK_OUT_OF_MEM)); | |
} | |
if (($link == LINK_OK) || ($link == LINK_OK_STRIP)) | |
{ | |
&utlLog(0, "Succeed to link\n"); | |
&generateLibTimestamp(\%lib) unless ($opt{simulate}); | |
$ret = 0; | |
} | |
elsif ($link == LINK_OUT_OF_MEM) | |
{ | |
&utlLog(0, "Fail to link due to \"Fatal error: L6000U: Out of memory.\"\n"); | |
next if ($state != $curState); | |
&generateLibTimestamp(\%lib) if (($opt{simulate} == 0) && ($state == STATE_PARTIAL_LINK)); | |
if ($opt{stripDebugInfo}) | |
{ | |
&utlLog(0, "PLEASE EDIT \"pl_debug.txt\" TO REMOVE MORE DEBUG INFO FROM LIBRARIES\n"); | |
} | |
else | |
{ | |
&utlLog(0, "PLEASE ENABLE \"--strip-debug-info\" TO REMOVE DEBUG INFO OF LIBRARIES\n"); | |
} | |
} | |
else | |
{ | |
&utlLog(0, "Fail to link\n"); | |
} | |
last if ($state == $curState); | |
} | |
&setIni(\%ini, "state", $state) if ($opt{update}); | |
&setIni(\%ini, "link", $link); | |
&writeIniFile(\%ini) unless ($opt{simulate}); | |
system("date/T >>" . $FileLog); | |
system("time/T >>" . $FileLog); | |
$plink_end = time; | |
$Current_time = time; | |
system("echo T_E,Plink,P,$Current_time >> $optPathMust{dirSave}/PlinkTime.log"); | |
if ($ENV{MBIS_BUILD_TIME_TMP} =~ /mbis/) | |
{ | |
system("echo T_S,Plink,P,$plink_start >> $ENV{MBIS_BUILD_TIME_TMP}"); | |
system("echo T_E,Plink,P,$plink_end >> $ENV{MBIS_BUILD_TIME_TMP}"); | |
} | |
return $ret; | |
} | |
# ----------------------------------------------------------------------------- | |
exit &main($_argc, \@_argv); |