blob: de6d38c5a2a6ea5f7413bb7e2885445a27feae4f [file] [log] [blame]
yu.dongc33b3072024-08-21 23:14:49 -07001#!/usr/bin/perl
2#
3# Copyright Statement:
4# --------------------
5# This software is protected by Copyright and the information contained
6# herein is confidential. The software may not be copied and the information
7# contained herein may not be used or disclosed except with the written
8# permission of MediaTek Inc. (C) 2011
9#
10# BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
11# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
12# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
13# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
14# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
15# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
16# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
17# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
18# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
19# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
20# NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
21# SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
22#
23# BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
24# LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
25# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
26# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
27# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
28#
29# THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
30# WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
31# LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
32# RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
33# THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
34#
35#*****************************************************************************
36
37use strict;
38use warnings;
39use Cwd;
40use Cwd 'abs_path';
41use Data::Dumper;
42use File::Path;
43use File::Basename;
44use File::Compare;
45use File::Copy;
46use Getopt::Long;
47
48my @_argv = ($0, @ARGV);
49my $_argc = $#_argv + 1;
50
51# -----------------------------------------------------------------------------
52
53my $Version = "20110428";
54
55# -----------------------------------------------------------------------------
56
57# Workaround.
58my @ExcludedLib = (
59 # Function kal_mem_cpy will be placed in SECONDARY_ROM and be used before ready due to multiply definition from kal_release.h.
60 'custom.lib',
61 # In file variant.cpp, static variables of class type are used, and it results in indeterminate order of initialization.
62 'gadget_lib.lib',
63 # For customer do vendor release
64 'gis.lib',
65 'init.lib',
66 # Different bin files in MAUI
67 'che.lib',
68 'bootloader.lib',
69 'fota.lib',
70 'sst_sec.lib',
71 'ssf.lib',
72 'lqt.lib',
73 # ...
74);
75
76# Ignore the following libraries for checking (see checkLib).
77my %IgnoredLib = (
78 "verno.lib" => 1,
79);
80
81# -----------------------------------------------------------------------------
82
83# Set default command.
84my $Cmd_nm = "";
85my $Cmd_readelf = "";
86my $Cmd_strip = "";
87my $Cmd_armar = "armar";
88my $Cmd_armlink = "armlink";
89
90# -----------------------------------------------------------------------------
91# System Utilities
92
93# Set default debug level.
94my $DbgLevel = 1;
95
96# Set default info level to display message in the screen.
97my $InfoLevel = 0;
98
99# Set current directory.
100my $DirCur = cwd();
101
102# Set default temporary directory.
103my $DirTemp = $DirCur . "/pl_temp";
104
105# Set default log file.
106my $FileLog = $DirCur . "/" . basename(__FILE__) . ".log";
107unlink($FileLog);
108
109# Set default err file.
110my $FileErr = $DirCur . "/" . basename(__FILE__) . ".err";
111unlink($FileErr);
112
113# Set default temporary file.
114my $FileTmp = $DirCur . "/" . basename(__FILE__) . ".tmp";
115unlink($FileTmp);
116
117my $Current_time = time;
118
119# Write file specified by a global variable $FileLog.
120sub sysWriteLog
121{
122 my ($log) = @_;
123
124 if (open(FILE_LOG, ">>" . $FileLog))
125 {
126 print(FILE_LOG $log);
127 close(FILE_LOG);
128 }
129}
130
131sub sysWriteErr
132{
133 my ($log) = @_;
134
135 if (open(FILE_LOG, ">>" . $FileLog))
136 {
137 print(FILE_LOG $log);
138 close(FILE_LOG);
139 }
140 if (open(FILE_ERR, ">>" . $FileErr))
141 {
142 print(FILE_ERR $log);
143 close(FILE_ERR);
144 }
145}
146
147BEGIN
148{
149 my $_dying = 0;
150 my $_msg = "";
151 my $_ptrSub = 0;
152 my @_ptrArgs = ();
153
154 sub sysDieRegister
155 {
156 my ($ptrSub, @ptrArgs) = @_;
157
158 $_ptrSub = $ptrSub;
159 @_ptrArgs = @ptrArgs;
160 }
161
162 sub sysDie
163 {
164 my ($msg) = @_;
165
166 if (($_dying == 0) && $_ptrSub)
167 {
168 $_dying = 1;
169 $_msg = $msg;
170 $_ptrSub->(@_ptrArgs);
171 $_dying = 0;
172 }
173 system("date/T >>" . $FileLog);
174 system("time/T >>" . $FileLog);
175 $msg = $_msg . "\n" . $msg if ($_dying);
176 die($msg);
177 }
178}
179
180# -----------------------------------------------------------------------------
181# Basic Utilities
182
183sub utlDump
184{
185 my ($level, $ptr) = @_;
186
187 if (($level <= $InfoLevel) || ($level <= $DbgLevel))
188 {
189 my $msg = Dumper($ptr);
190
191 print($msg) if ($level <= $InfoLevel);
192 &sysWriteLog($msg) if ($level <= $DbgLevel);
193 }
194}
195
196sub utlSrcLoc
197{
198 my ($level) = @_;
199 my $filename = (caller($level + 1))[1];
200 my $line = (caller($level))[2];
201 my $subr = (caller($level + 1))[3];
202
203 $subr =~ s/^.*://;
204 return "[" . $filename . ":" . $subr . ":" . $line . "]";
205}
206
207sub utlLog
208{
209 my ($level, $msg) = @_;
210
211 if (($level <= $InfoLevel) || ($level <= $DbgLevel))
212 {
213 print($msg) if ($level <= $InfoLevel);
214 &sysWriteLog(&utlSrcLoc(1) . " " . $msg) if ($level <= $DbgLevel);
215 }
216}
217
218sub utlErr
219{
220 my ($level, $msg) = @_;
221
222 if (($level <= $InfoLevel) || ($level <= $DbgLevel))
223 {
224 print($msg) if ($level <= $InfoLevel);
225 &sysWriteErr(&utlSrcLoc(1) . " Error: " . $msg) if ($level <= $DbgLevel);
226 }
227}
228
229sub utlDie
230{
231 my ($msg, $level, $ignore) = @_;
232
233 $ignore = 0 if (not defined($ignore));
234 $level = 1 if (not defined($level));
235 $msg = &utlSrcLoc($level) . " Error: " . $msg . "\n";
236 &sysWriteErr($msg);
237 &sysDie($msg) unless ($ignore);
238}
239
240sub utlExec
241{
242 my ($cmd) = @_;
243 my $ret = "";
244
245 $cmd = $cmd . " 2>" . $FileTmp;
246 $ret = `$cmd`;
247
248 if ($? != 0)
249 {
250 my @stderr = ();
251
252 if (open(FILE_TEMP, $FileTmp))
253 {
254 @stderr = <FILE_TEMP>;
255 close(FILE_TEMP);
256 }
257 &utlDie("Fail to execute command: \"" . $cmd . "\"\nSTDOUT: " . $ret . "\nSTDERR: @stderr\n", 2);
258 }
259 return split(/\n/, $ret);
260}
261
262sub utlSystem
263{
264 my ($cmd, $ignore) = @_;
265 my $ret = "";
266 my $status = 0;
267
268 $ignore = 0 if (not defined($ignore));
269 $cmd = $cmd . " 2>" . $FileTmp;
270 $ret = `$cmd`;
271 $status = $?;
272
273 if ($status != 0)
274 {
275 my @stderr = ();
276 my $msg = "";
277
278 if (open(FILE_TMP, $FileTmp))
279 {
280 @stderr = <FILE_TMP>;
281 close(FILE_TMP);
282 }
283 if (($ret ne "") || ("@stderr" ne "") || ($ignore <= 0))
284 {
285 $msg = "Fail to execute command: \"" . $cmd . "\"\nSTDOUT: " . $ret . "\nSTDERR: @stderr\n";
286 print($msg) if ($ignore == 0);
287 &sysWriteErr(&utlSrcLoc(1) . " Error: " . $msg);
288 }
289 }
290 return $status;
291}
292
293# -----------------------------------------------------------------------------
294# Utilities
295
296sub utlTrim
297{
298 my ($str) = @_;
299
300 $str =~ s/^\s+//;
301 $str =~ s/\s+$//;
302
303 return $str;
304}
305
306sub utlAbsPath
307{
308 my ($path) = @_;
309
310 return abs_path($path);
311}
312
313sub utlRmTree
314{
315 my ($path, $ignore, $level) = @_;
316
317 if (-e $path)
318 {
319 my @list = glob($path . "/*");
320
321 $ignore = 1 if (not defined($ignore));
322 $level = 2 if (not defined($level));
323
324 foreach my $file (@list)
325 {
326 if (-d $file)
327 {
328 &utlRmTree($file, $ignore, $level + 1);
329 }
330 else
331 {
332 &utlDie("Fail to delete " . $file . " due to \"$!\"", $level, $ignore) unless (unlink($file));
333 }
334 }
335 &utlDie("Fail to delete " . $path . " due to \"$!\"", $level, $ignore) unless (rmdir($path));
336 }
337}
338
339sub utlMkDir
340{
341 my ($dir) = @_;
342
343 if (! -d $dir)
344 {
345 mkdir($dir) or &utlDie("Fail to create " . $dir . " due to \"$!\"", 2);
346 }
347}
348
349sub utlChDir
350{
351 my ($dir) = @_;
352
353 chdir($dir) or &utlDie("Fail to change directory to " . $dir . " due to \"$!\"", 2);
354}
355
356sub utlRmFile
357{
358 my ($file) = @_;
359
360 if (-e $file)
361 {
362 unlink($file) or &utlDie("Fail to delete " . $file . " due to \"$!\"", 2);
363 }
364}
365
366sub utlCpFile
367{
368 my ($src, $dst) = @_;
369
370 copy($src, $dst) or &utlDie("Fail to copy " . $src . " to " . $dst . " due to \"$!\"; please check available disk space", 2);
371}
372
373sub utlGetTimestamp
374{
375 my ($file) = @_;
376
377 return (stat($file))[9];
378}
379
380# -----------------------------------------------------------------------------
381
382sub copyFiles
383{
384 my ($dirSrc, $dirDst) = @_;
385 &utlDie("Cannot find " . $dirSrc) unless (-e $dirSrc);
386 &utlDie("Cannot find " . $dirDst) unless (-e $dirDst);
387
388 my @fileList = glob($dirSrc . "/*");
389
390 foreach my $src (@fileList)
391 {
392 &utlCpFile($src, $dirDst) if (-f $src);
393 }
394}
395
396sub copyLib
397{
398 my ($ptrAryDir, $srcSuffix, $dstSuffix) = @_;
399
400 foreach my $dirLib (@$ptrAryDir)
401 {
402 my $dirSrcLib = $dirLib . $srcSuffix;
403 my $dirDstLib = $dirLib . $dstSuffix;
404
405 &utlRmTree($dirDstLib);
406 &utlMkDir($dirDstLib);
407 &copyFiles($dirSrcLib, $dirDstLib);
408 }
409}
410
411sub generateCppLibFile
412{
413 my ($ptrHahLib, $fileCppLib) = @_;
414 my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir};
415 my $ptrHahLibUsage = $ptrHahLib->{ptrHahLibUsage};
416 my $ptrHahCppLibTab = $ptrHahLib->{ptrHahSymTable}->{ptrHahCppLibTab};
417
418 open(FILE_CPP_LIB, ">" . $fileCppLib) or &utlDie("Cannot open " . $fileCppLib);
419
420 foreach my $dirSrcLib (@$ptrAryLibDir)
421 {
422 my @libList = glob($dirSrcLib . "/*.lib");
423
424 foreach my $lib (@libList)
425 {
426 my $libName = basename($lib);
427
428 next if ((not exists($ptrHahLibUsage->{$libName})) || (not exists($ptrHahCppLibTab->{$libName})));
429 print(FILE_CPP_LIB $libName . "\n");
430 }
431 }
432
433 close(FILE_CPP_LIB);
434}
435
436sub readCppLibFile
437{
438 my ($fileCppLib, $ptrHahSymTable) = @_;
439 my $ptrHahCppLibTab = {};
440
441 &utlLog(1, "Reading C++ libraries from " . $fileCppLib . "\n");
442 open(FILE_CPP_LIB, "<" . $fileCppLib) or &utlDie("Cannot open " . $fileCppLib);
443
444 foreach my $line (<FILE_CPP_LIB>)
445 {
446 if ($line =~ /(\S+)/)
447 {
448 $ptrHahCppLibTab->{$1} = 1;
449 }
450 }
451
452 close(FILE_CPP_LIB);
453 $ptrHahSymTable->{ptrHahCppLibTab} = $ptrHahCppLibTab;
454}
455
456use constant {
457 SYM_DEF => 1,
458 SYM_UNDEF => 2
459};
460
461sub addEntrySymToObj
462{
463 my ($ptrHahSymTable, $sym, $type, $lib, $obj) = @_;
464 my $ptrHahSymToObjTab = $ptrHahSymTable->{ptrHahSymToObjTab};
465
466 if (not exists($ptrHahSymToObjTab->{$sym}))
467 {
468 $ptrHahSymToObjTab->{$sym} = {};
469 $ptrHahSymToObjTab->{$sym}->{+SYM_DEF} = {};
470 $ptrHahSymToObjTab->{$sym}->{+SYM_UNDEF} = {};
471 }
472
473 my $ptrHahLibObj = $ptrHahSymToObjTab->{$sym}->{$type};
474 my $ptrHahMultiSymTab = $ptrHahSymTable->{ptrHahMultiSymTab};
475
476 if ($ptrHahMultiSymTab && ($type == SYM_DEF) && (scalar keys(%$ptrHahLibObj) > 0))
477 {
478 &utlLog(3, "Multiply defined symbol " . $sym . " in " . $lib . "(" . $obj . ")\n");
479 $ptrHahMultiSymTab->{$sym} = 1;
480 }
481
482 $ptrHahLibObj->{$lib} = {} if (not exists($ptrHahLibObj->{$lib}));
483 $ptrHahLibObj->{$lib}->{$obj} = 1;
484}
485
486sub loadSymTableByNm
487{
488 my ($ptrHahSymTable, $lib, $libName, $type) = @_;
489 my $ptrHahObjToSymTab = $ptrHahSymTable->{ptrHahObjToSymTab};
490 my $ptrHahCppLibTab = $ptrHahSymTable->{ptrHahCppLibTab};
491 my $obj = "";
492 my @symTable = ();
493
494 &utlDie("Assert") if (($type != SYM_DEF) && ($type != SYM_UNDEF));
495 if ($type == SYM_DEF)
496 {
497 @symTable = &utlExec($Cmd_nm . " -g --defined-only " . $lib);
498 }
499 else
500 {
501 @symTable = &utlExec($Cmd_nm . " -g -u " . $lib);
502 }
503
504 foreach my $line (@symTable)
505 {
506 if ($line =~ /^(\S+):\s*$/)
507 {
508 $obj = $1;
509 $ptrHahObjToSymTab->{$libName} = {} if (not exists($ptrHahObjToSymTab->{$libName}));
510 if (not exists($ptrHahObjToSymTab->{$libName}->{$obj}))
511 {
512 $ptrHahObjToSymTab->{$libName}->{$obj} = {};
513 $ptrHahObjToSymTab->{$libName}->{$obj}->{+SYM_DEF} = {};
514 $ptrHahObjToSymTab->{$libName}->{$obj}->{+SYM_UNDEF} = {};
515 }
516 }
517 elsif ($line =~ /\s+[^N]\s+(\S+)\s*$/)
518 {
519 my $sym = $1;
520 &utlDie("Assert") if ($obj eq "");
521 &utlLog(3, "Reading " . $sym . " from " . $libName . "(" . $obj . ")\n");
522 $ptrHahObjToSymTab->{$libName}->{$obj}->{$type}->{$sym} = 1;
523 &addEntrySymToObj($ptrHahSymTable, $sym, $type, $libName, $obj);
524 $ptrHahCppLibTab->{$libName} = 1 if (($type == SYM_DEF) && ($sym =~ /^_Z/));
525 }
526 }
527}
528
529sub loadSymTable
530{
531 my ($ptrHahLib, $fileCppLib) = @_;
532 my $ptrHahSymTable = $ptrHahLib->{ptrHahSymTable};
533
534 if (not exists($ptrHahSymTable->{ptrHahObjToSymTab}))
535 {
536 my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir};
537 my $ptrHahLibUsage = $ptrHahLib->{ptrHahLibUsage};
538
539 &utlLog(1, "Loading symbol tables...\n");
540
541 $ptrHahSymTable->{ptrHahObjToSymTab} = {};
542 $ptrHahSymTable->{ptrHahSymToObjTab} = {};
543 $ptrHahSymTable->{ptrHahCppLibTab} = {};
544 $ptrHahSymTable->{ptrHahMultiSymTab} = {};
545
546 foreach my $dirSrcLib (@$ptrAryLibDir)
547 {
548 my @libList = glob($dirSrcLib . "/*.lib");
549
550 foreach my $lib (@libList)
551 {
552 my $libName = basename($lib);
553
554 next if (not exists($ptrHahLibUsage->{$libName}));
555
556 &utlLog(1, "Loading " . $libName . "\n");
557 &loadSymTableByNm($ptrHahSymTable, $lib, $libName, SYM_DEF);
558 &loadSymTableByNm($ptrHahSymTable, $lib, $libName, SYM_UNDEF);
559 }
560 }
561 &utlLog(3, "Dumping object to symbol table...\n");
562 &utlDump(3, $ptrHahSymTable->{ptrHahObjToSymTab});
563 &utlLog(3, "Dumping symbol to object table...\n");
564 &utlDump(3, $ptrHahSymTable->{ptrHahSymToObjTab});
565
566 &generateCppLibFile($ptrHahLib, $fileCppLib);
567 }
568}
569
570sub generateDbgLibFile
571{
572 my ($ptrHahLib, $suffix, $ptrHahNoDbgLib, $fileDbgLib, $stripDebugCount) = @_;
573 my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir};
574 my $ptrHahLibUsage = $ptrHahLib->{ptrHahLibUsage};
575 my $ptrHahCppLibTab = $ptrHahLib->{ptrHahSymTable}->{ptrHahCppLibTab};
576 my $size = keys(%$ptrHahNoDbgLib);
577 my $count = 0;
578 my %libList = ();
579
580 foreach my $dirSrcLib (@$ptrAryLibDir)
581 {
582 my @list = glob($dirSrcLib . $suffix . "/*.lib");
583
584 foreach my $lib (@list)
585 {
586 my $libName = basename($lib);
587
588 $libList{$libName} = -s $lib;
589 }
590 }
591
592 open(FILE_DBG_LIB, ">" . $fileDbgLib) or &utlDie("Cannot open " . $fileDbgLib);
593
594 print(FILE_DBG_LIB "PLEASE ADD \";\" IN THE BEGINNING OF THE LINE IN ORDER TO REMOVE DEBUG INFO. OF A CORRESPONDING LIBRARY\n\n");
595
596 foreach my $libName (sort { $libList{$b} <=> $libList{$a} } (keys(%libList)))
597 {
598 if (not exists($ptrHahLibUsage->{$libName}))
599 {
600 &utlLog(1, "NOT stripping " . $libName . " due to no use\n");
601 next;
602 }
603 if (exists($ptrHahCppLibTab->{$libName}))
604 {
605 &utlLog(1, "NOT stripping " . $libName . " due to C++\n");
606 next;
607 }
608 if (($size == 0) && ($count < $stripDebugCount))
609 {
610 $ptrHahNoDbgLib->{$libName} = 1;
611 $count++;
612 }
613 if (exists($ptrHahNoDbgLib->{$libName}))
614 {
615 print(FILE_DBG_LIB "; " . $libName . " " . $libList{$libName} . "\n");
616 }
617 else
618 {
619 print(FILE_DBG_LIB $libName . " " . $libList{$libName} . "\n");
620 }
621 }
622
623 close(FILE_DBG_LIB);
624}
625
626sub readDbgLibFile
627{
628 my ($fileDbgLib, $ptrHahNoDbgLib) = @_;
629
630 &utlLog(1, "Reading debug-needed libraries from " . $fileDbgLib . "\n");
631
632 open(FILE_DBG_LIB, "<" . $fileDbgLib) or &utlDie("Cannot open " . $fileDbgLib);
633
634 foreach my $line (<FILE_DBG_LIB>)
635 {
636 if ($line =~ /^\s*;\s*(\S+)/)
637 {
638 $ptrHahNoDbgLib->{$1} = 1;
639 }
640 }
641
642 close(FILE_DBG_LIB);
643}
644
645sub removeDebugInfoGut
646{
647 my ($ptrHahLib, $suffix) = @_;
648 my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir};
649 my $ptrHahLibUsage = $ptrHahLib->{ptrHahLibUsage};
650 my $ptrHahNoDbgLib = $ptrHahLib->{ptrHahNoDbgLib};
651 my $ptrHahCppLibTab = $ptrHahLib->{ptrHahSymTable}->{ptrHahCppLibTab};
652 my $fileOpt = "__ARM_OPT__.txt";
653 my $cwd = cwd();
654
655 foreach my $dirSrcLib (@$ptrAryLibDir)
656 {
657 my @libList = glob($dirSrcLib . $suffix . "/*.lib");
658
659 foreach my $lib (@libList)
660 {
661 my $libName = basename($lib);
662
663 if (exists($ptrHahLibUsage->{$libName}) && (not exists($ptrHahCppLibTab->{$libName})) && (exists($ptrHahNoDbgLib->{$libName})))
664 {
665 &utlLog(1, "Removing debug info of " . $libName . "\n");
666 &utlMkDir($DirTemp);
667 &utlChDir($DirTemp);
668
669 my @objList = &utlExec($Cmd_armar . " -t " . $lib);
670
671 if (&utlSystem($Cmd_armar . " -x " . $lib) == 0)
672 {
673 my $done = 1;
674
675 foreach my $obj (@objList)
676 {
677 if (&utlSystem($Cmd_strip . " -d " . $obj) != 0)
678 {
679 $done = 0;
680 last;
681 }
682 }
683 if ($done)
684 {
685 open(FILE_OPT, ">" . $fileOpt) or &utlDie("Cannot open " . $fileOpt);
686 print(FILE_OPT "--create " . $lib . " @objList");
687 close(FILE_OPT);
688 &utlSystem($Cmd_armar . " --via " . $fileOpt);
689 }
690 }
691
692 &utlChDir($cwd);
693 &utlRmTree($DirTemp);
694 }
695 }
696 }
697}
698
699sub removeDebugInfo
700{
701 my ($ptrHahLib, $suffix, $fileCppLib, $fileDbgLib, $stripDebugCount) = @_;
702 my $update = scalar keys(%{$ptrHahLib->{ptrHahLibNew}});
703
704 if ((-e $fileCppLib) && ($update == 0))
705 {
706 &readCppLibFile($fileCppLib, $ptrHahLib->{ptrHahSymTable});
707 }
708 else
709 {
710 &loadSymTable($ptrHahLib, $fileCppLib);
711 }
712 &readDbgLibFile($fileDbgLib, $ptrHahLib->{ptrHahNoDbgLib}) if (-e $fileDbgLib);
713 &generateDbgLibFile($ptrHahLib, $suffix, $ptrHahLib->{ptrHahNoDbgLib}, $fileDbgLib, $stripDebugCount);
714 &removeDebugInfoGut($ptrHahLib, $suffix);
715}
716
717sub createDstLibDir
718{
719 my ($ptrHahLib) = @_;
720 my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir};
721 my $suffix = $ptrHahLib->{suffix};
722
723 foreach my $dirSrcLib (@$ptrAryLibDir)
724 {
725 my $dirDstLib = $dirSrcLib . $suffix;
726
727 &utlLog(1, "Creating " . $dirDstLib ."\n");
728 &utlRmTree($dirDstLib);
729 &utlMkDir($dirDstLib);
730 }
731}
732
733sub removeDstLibDir
734{
735 my ($ptrHahLib, $suffix, $dstSuffix) = @_;
736 my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir};
737
738 foreach my $dirSrcLib (@$ptrAryLibDir)
739 {
740 my $dirDstLib = $dirSrcLib . $suffix;
741
742 if (-e $dirDstLib)
743 {
744 if ((not defined($dstSuffix)) || ($dstSuffix eq ""))
745 {
746 &utlRmTree($dirDstLib);
747 }
748 else
749 {
750 my $path = $dirSrcLib . $dstSuffix;
751
752 &utlLog(1, "Removing " . $path . "\n");
753 &utlRmTree($path);
754 &utlLog(1, "Keeping partially-linked libraries in " . $path . "\n");
755 if (not rename($dirDstLib, $path))
756 {
757 &utlLog(1, "Fail to rename directory " . $dirDstLib . " to " . $path . " due to \"$!\"\n");
758 &utlLog(1, "Trying to copy files from " . $dirDstLib . " to " . $path . "\n");
759 &utlMkDir($path);
760 &copyFiles($dirDstLib, $path);
761 &utlRmTree($dirDstLib);
762 }
763 }
764 }
765 }
766}
767
768sub finalizeLib
769{
770 my ($ptrHahLib) = @_;
771 my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir};
772 my $suffix = $ptrHahLib->{suffix};
773 my $suffix_bak = $ptrHahLib->{suffix_bak};
774
775 foreach my $dirSrcLib (@$ptrAryLibDir)
776 {
777 my $dirDstLib = $dirSrcLib . $suffix;
778 my $dirSrcBak = $dirSrcLib . $suffix_bak;
779
780 &utlDie("Cannot find " . $dirDstLib) unless (-e $dirDstLib);
781 &utlDie("Unexpected directory " . $dirSrcBak) if (-e $dirSrcBak);
782 &utlMkDir($dirSrcBak);
783 &copyFiles($dirSrcLib, $dirSrcBak);
784 &copyFiles($dirDstLib, $dirSrcLib);
785 &utlRmTree($dirSrcBak);
786 &utlRmTree($dirDstLib);
787 }
788}
789
790# -----------------------------------------------------------------------------
791
792sub isPattern
793{
794 my ($str) = @_;
795
796 return 1 if (($str ne "*") && ($str =~ /[*?]+/));
797 return 0;
798}
799
800sub regExp
801{
802 my ($expr) = @_;
803
804 $expr =~ s/\./\\./g;
805 $expr =~ s/\*/.*/g;
806 $expr =~ s/\?/./g;
807
808 return $expr;
809}
810
811sub hasRule
812{
813 my ($ptrHahRuleGut, $lib, $obj) = @_;
814
815 $lib = lc($lib);
816 $obj = lc($obj);
817 $lib = &regExp($lib) if (&isPattern($lib));
818 $obj = &regExp($obj) if (&isPattern($obj));
819 return 1 if (exists($ptrHahRuleGut->{$lib}) && exists($ptrHahRuleGut->{$lib}->{$obj}));
820 return 0;
821}
822
823sub loadRule
824{
825 my ($ptrHahRuleGut, $lib, $obj) = @_;
826
827 $lib = lc($lib);
828 $obj = lc($obj);
829 if (&isPattern($lib))
830 {
831 $ptrHahRuleGut->{regExpLib} = {} if (not exists($ptrHahRuleGut->{regExpLib}));
832 $lib = &regExp($lib);
833 $ptrHahRuleGut->{regExpLib}->{$lib} = 1;
834 }
835 $ptrHahRuleGut->{$lib} = {} if (not exists($ptrHahRuleGut->{$lib}));
836 if (&isPattern($obj))
837 {
838 $ptrHahRuleGut->{$lib}->{regExpObj} = {} if (not exists($ptrHahRuleGut->{$lib}->{regExpObj}));
839 $obj = &regExp($obj);
840 $ptrHahRuleGut->{$lib}->{regExpObj}->{$obj} = 1;
841 }
842 $ptrHahRuleGut->{$lib}->{$obj} = 1;
843}
844
845sub writeRule
846{
847 my ($hdlFileRule, $lib, $obj) = @_;
848
849 printf($hdlFileRule "%s(%s)\n", $lib, $obj) if ($hdlFileRule);
850}
851
852sub addRule
853{
854 my ($ptrHahRuleGut, $lib, $obj, $hdlFileRule) = @_;
855
856 if (not &hasRule($ptrHahRuleGut, $lib, $obj))
857 {
858 &loadRule($ptrHahRuleGut, $lib, $obj);
859 &writeRule($hdlFileRule, $lib, $obj);
860 }
861}
862
863# Return 1 if a library is specified in RULE to exclude; otherwise, return 0.
864sub isExcludedLib
865{
866 my ($ptrHahRuleGut, $lib) = @_;
867
868 $lib = lc($lib);
869 return 1 if ( ( exists($ptrHahRuleGut->{$lib})
870 && exists($ptrHahRuleGut->{$lib}->{"*"}))
871 || ( exists($ptrHahRuleGut->{"*"})
872 && exists($ptrHahRuleGut->{"*"}->{"*"})));
873
874 foreach my $regExpLib (keys(%{$ptrHahRuleGut->{regExpLib}}))
875 {
876 if (($lib =~ /($regExpLib)/) && exists($ptrHahRuleGut->{$regExpLib}->{"*"}))
877 {
878 &loadRule($ptrHahRuleGut, $lib, "*");
879 return 1;
880 }
881 }
882 return 0;
883}
884
885# Return 1 if an object is specified in RULE to exclude; otherwise, return 0.
886sub isExcludedObj
887{
888 my ($ptrHahRuleGut, $lib, $obj) = @_;
889
890 $lib = lc($lib);
891 $obj = lc($obj);
892 return 1 if ( ( exists($ptrHahRuleGut->{$lib})
893 && ( exists($ptrHahRuleGut->{$lib}->{$obj})
894 || exists($ptrHahRuleGut->{$lib}->{"*"})))
895 || ( exists($ptrHahRuleGut->{"*"})
896 && exists($ptrHahRuleGut->{"*"}->{$obj}))
897 || ( exists($ptrHahRuleGut->{"*"})
898 && exists($ptrHahRuleGut->{"*"}->{"*"})));
899
900 if ( exists($ptrHahRuleGut->{"*"})
901 && exists($ptrHahRuleGut->{"*"}->{regExpObj}))
902 {
903 foreach my $regExpObj (keys(%{$ptrHahRuleGut->{"*"}->{regExpObj}}))
904 {
905 if ($obj =~ /($regExpObj)/)
906 {
907 &loadRule($ptrHahRuleGut, $lib, $obj);
908 return 1;
909 }
910 }
911 }
912
913 foreach my $regExpLib (keys(%{$ptrHahRuleGut->{regExpLib}}))
914 {
915 if ($lib =~ /($regExpLib)/)
916 {
917 if (exists($ptrHahRuleGut->{$regExpLib}->{$obj}))
918 {
919 &loadRule($ptrHahRuleGut, $lib, $obj);
920 return 1;
921 }
922 elsif (exists($ptrHahRuleGut->{$regExpLib}->{"*"}))
923 {
924 &loadRule($ptrHahRuleGut, $lib, "*");
925 return 1;
926 }
927 elsif (exists($ptrHahRuleGut->{$regExpLib}->{regExpObj}))
928 {
929 foreach my $regExpObj (keys(%{$ptrHahRuleGut->{$regExpLib}->{regExpObj}}))
930 {
931 if ($obj =~ /($regExpObj)/)
932 {
933 &loadRule($ptrHahRuleGut, $lib, $obj);
934 return 1;
935 }
936 }
937 }
938 }
939 }
940 return 0;
941}
942
943sub readRuleFile
944{
945 my ($ptrHahRule) = @_;
946 my $fileRule = $ptrHahRule->{fileRule};
947 my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut};
948
949 &utlLog(1, "Reading rule from " . $fileRule . "\n");
950
951 open(FILE_RULE, "<" . $fileRule) or &utlDie("Cannot open " . $fileRule);
952
953 foreach my $line (<FILE_RULE>)
954 {
955 # library(object)
956 if ($line =~ /^\s*([^\(\)\s]+)\s*\(\s*([^\(\)\s]+)\s*\)/)
957 {
958 my $lib = $1;
959 my $obj = $2;
960
961 &utlDie("Invalid rule: " . $line) if (($lib eq "*") && ($obj eq "*"));
962 &loadRule($ptrHahRuleGut, $lib, $obj) if (not &hasRule($ptrHahRuleGut, $lib, $obj));
963 }
964 }
965
966 close(FILE_RULE);
967
968 &utlCpFile($fileRule, $ptrHahRule->{file});
969}
970
971sub parseScatterFile
972{
973 my ($fileScatter, $ptrHahRule) = @_;
974 my $fileRule = $ptrHahRule->{file};
975 my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut};
976
977 &utlLog(1, "Parsing scatter file " . $fileScatter . " and outputting rules to " . $fileRule . "\n");
978
979 open(FILE_RULE, ">" . $fileRule) or &utlDie("Cannot open " . $fileRule);
980 open(FILE_SCATTER, "<" . $fileScatter) or &utlDie("Cannot open " . $fileScatter);
981
982 foreach my $line (<FILE_SCATTER>)
983 {
984 if ($line =~ /^\s*(\S+\.o\S*)/i)
985 {
986 my $obj = $1;
987
988 next if ($obj =~ /^\*\.o/i);
989 &addRule($ptrHahRuleGut, "*", $obj, \*FILE_RULE);
990 }
991 }
992
993 close(FILE_SCATTER);
994 close(FILE_RULE);
995}
996
997sub generateFileNameList
998{
999 my ($file, $ptrAryFileName) = @_;
1000
1001 open(FILE_INPUT, "<" . $file) or &utlDie("Cannot open " . $file);
1002
1003 foreach my $line (<FILE_INPUT>)
1004 {
1005 my @optList = split(/\s+/, $line);
1006
1007 foreach my $opt (@optList)
1008 {
1009 push(@$ptrAryFileName, basename($1) . ".lib") if ($opt =~ /(\S+)\.lib(\(\S+\)|$)/);
1010 }
1011 }
1012
1013 close(FILE_INPUT);
1014}
1015
1016sub readUserExclusionFile
1017{
1018 my ($ptrAryUserExclusionFile, $ptrHahRule) = @_;
1019 my $fileRule = $ptrHahRule->{file};
1020 my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut};
1021
1022 open(FILE_RULE, ">>" . $fileRule) or &utlDie("Cannot open " . $fileRule);
1023
1024 foreach my $file (@$ptrAryUserExclusionFile)
1025 {
1026 my @nameList = ();
1027
1028 &utlLog(1, "Reading user exclusion from " . $file . "\n");
1029
1030 &generateFileNameList($file, \@nameList);
1031 foreach my $lib (@nameList)
1032 {
1033 &utlLog(1, "Will exclude " . $lib . "\n");
1034 &addRule($ptrHahRuleGut, $lib, "*", \*FILE_RULE);
1035 }
1036 }
1037
1038 close(FILE_RULE);
1039}
1040
1041sub readExclusionFile
1042{
1043 my ($fileExclusion, $ptrHahRule) = @_;
1044 my $fileRule = $ptrHahRule->{file};
1045 my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut};
1046
1047 &utlLog(1, "Reading exclusion from " . $fileExclusion . "\n");
1048
1049 open(FILE_EXCLUSION, "<" . $fileExclusion) or &utlDie("Cannot open " . $fileExclusion);
1050 open(FILE_RULE, ">>" . $fileRule) or &utlDie("Cannot open " . $fileRule);
1051
1052 foreach my $line (<FILE_EXCLUSION>)
1053 {
1054 # library object
1055 if ($line =~ /^\s*(\S+)\s+(\S+)/)
1056 {
1057 my $lib = $1;
1058 my $obj = $2;
1059
1060 &utlLog(1, "Will exclude " . $lib . "(" . $obj . ")\n");
1061 &addRule($ptrHahRuleGut, $lib, $obj, \*FILE_RULE);
1062 }
1063 }
1064
1065 close(FILE_RULE);
1066 close(FILE_EXCLUSION);
1067}
1068
1069sub writeExcludedLib
1070{
1071 my ($ptrAryExcludedLib, $ptrHahRule) = @_;
1072 my $fileRule = $ptrHahRule->{file};
1073 my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut};
1074
1075 &utlLog(1, "Writing built-in excluded libraries to " . $fileRule . "\n");
1076
1077 open(FILE_RULE, ">>" . $fileRule) or &utlDie("Cannot open " . $fileRule);
1078
1079 foreach my $lib (@$ptrAryExcludedLib)
1080 {
1081 &utlLog(1, "Will exclude " . $lib . "\n");
1082 &addRule($ptrHahRuleGut, $lib, "*", \*FILE_RULE);
1083 }
1084
1085 close(FILE_RULE);
1086}
1087
1088sub writeHint
1089{
1090 my ($hdlFileHint, $lib, $obj, $sym) = @_;
1091
1092 printf($hdlFileHint "%s %s %s\n", $lib, $sym, $obj) if ($hdlFileHint);
1093}
1094
1095sub loadHint
1096{
1097 my ($ptrHahHintGut, $lib, $obj, $sym) = @_;
1098
1099 $ptrHahHintGut->{$sym} = {} if (not exists($ptrHahHintGut->{$sym}));
1100 $ptrHahHintGut->{$sym}->{$obj} = {} if (not exists($ptrHahHintGut->{$sym}->{$obj}));
1101 $ptrHahHintGut->{$sym}->{$obj}->{$lib} = 1;
1102}
1103
1104sub addHint
1105{
1106 my ($ptrHahHintGut, $lib, $obj, $sym, $hdlFileHint) = @_;
1107
1108 if ( (not exists($ptrHahHintGut->{$sym}))
1109 || (not exists($ptrHahHintGut->{$sym}->{$obj}))
1110 || (not exists($ptrHahHintGut->{$sym}->{$obj}->{$lib})))
1111 {
1112 &loadHint($ptrHahHintGut, $lib, $obj, $sym);
1113 &writeHint($hdlFileHint, $lib, $obj, $sym);
1114 }
1115}
1116
1117sub readHintFile
1118{
1119 my ($ptrHahHint, $ptrHahRule) = @_;
1120 my $fileHint = $ptrHahHint->{fileHint};
1121 my $ptrHahHintGut = $ptrHahHint->{ptrHahGut};
1122 my $toRule = $ptrHahHint->{toRule};
1123 my $fileRule = $ptrHahRule->{file};
1124 my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut};
1125
1126 &utlLog(1, "Reading hint from " . $fileHint . "\n");
1127
1128 open(FILE_HINT, "<" . $fileHint) or &utlDie("Cannot open " . $fileHint);
1129 open(FILE_RULE, ">>" . $fileRule) or &utlDie("Cannot open " . $fileRule);
1130
1131 foreach my $line (<FILE_HINT>)
1132 {
1133 # library symbol object
1134 if ($line =~ /^\s*(\S+)\s+(\S+)\s+(\S+)/)
1135 {
1136 my $lib = $1;
1137 my $sym = $2;
1138 my $obj = $3;
1139
1140 &loadHint($ptrHahHintGut, $lib, $obj, $sym);
1141 &addRule($ptrHahRuleGut, $lib, $obj, \*FILE_RULE) if ($toRule);
1142 }
1143 }
1144
1145 close(FILE_RULE);
1146 close(FILE_HINT);
1147
1148 &utlCpFile($fileHint, $ptrHahHint->{file});
1149}
1150
1151sub generateLinkOptFile
1152{
1153 my ($ptrHahLib, $ptrHahRuleGut, $fileLinkOpt, $fileOutput) = @_;
1154 my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir};
1155 my $fileOrig = $fileOutput . ".orig";
1156 my %libPath = ();
1157
1158 &utlCpFile($fileLinkOpt, $fileOrig);
1159
1160 foreach my $dirSrcLib (@$ptrAryLibDir)
1161 {
1162 my @libList = glob($dirSrcLib . "/*.lib");
1163
1164 foreach my $lib (@libList)
1165 {
1166 my $libName = basename($lib);
1167
1168 if (exists($libPath{$libName}))
1169 {
1170 $libPath{$libName} = "";
1171 }
1172 else
1173 {
1174 $libPath{$libName} = $dirSrcLib;
1175 }
1176 }
1177 }
1178
1179 my $suffix = $ptrHahLib->{suffix};
1180 my $ptrHahLibUsage = $ptrHahLib->{ptrHahLibUsage};
1181
1182 &utlLog(1, "Generating link option file " . $fileOutput . "\n");
1183
1184 open(FILE_LINK_OPT, "<" . $fileLinkOpt) or &utlDie("Cannot open " . $fileLinkOpt);
1185 open(FILE_OUTPUT, ">" . $fileOutput) or &utlDie("Cannot open " . $fileOutput);
1186
1187 foreach my $line (<FILE_LINK_OPT>)
1188 {
1189 my @optList = split(/\s+/, $line);
1190
1191 foreach my $opt (@optList)
1192 {
1193 my $found = 0;
1194
1195 if ($opt =~ /\.lib$/)
1196 {
1197 my $libName = basename($opt);
1198
1199 if (exists($libPath{$libName}) && ($libPath{$libName} ne ""))
1200 {
1201 if (($ptrHahRuleGut == 0) || (not &isExcludedLib($ptrHahRuleGut, $libName)))
1202 {
1203 my $lib = $libPath{$libName}. $suffix . "/" . $libName;
1204
1205 $lib =~ s/\//\\/g;
1206 print(FILE_OUTPUT " " . $lib);
1207 $found = 1;
1208 }
1209 $ptrHahLibUsage->{$libName} = 1;
1210 }
1211 }
1212 print(FILE_OUTPUT " " . $opt) unless ($found);
1213 }
1214 print(FILE_OUTPUT "\n");
1215 }
1216
1217 close(FILE_OUTPUT);
1218 close(FILE_LINK_OPT);
1219
1220 foreach my $libName (keys(%libPath))
1221 {
1222 &utlLog(1, "NOT using " . $libName . " in link option file " . $fileLinkOpt . "\n") if (not exists($ptrHahLibUsage->{$libName}));
1223 }
1224}
1225
1226# -----------------------------------------------------------------------------
1227
1228sub partialLinkLibGut
1229{
1230 my ($lib, $libName, $dirDstLib, $ptrHahLib, $ptrHahRuleGut, $hdlFileRule, $ptrHahHintGut, $hdlFileHint) = @_;
1231 my @objList = &utlExec($Cmd_armar . " -t " . $lib);
1232 my $linkedObj = "__" . $libName . "_linked__.obj";
1233
1234 &utlLog(3, "Analyzing " . $lib . " with @objList\n");
1235
1236 if (grep {$_ eq $linkedObj} @objList)
1237 {
1238 &utlLog(1, "Excluding " . $libName . " due to a linked object inside\n");
1239 &utlCpFile($lib, $dirDstLib . "/" . $libName);
1240 }
1241 elsif (&isExcludedLib($ptrHahRuleGut, $libName))
1242 {
1243 my $dstLib = $dirDstLib . "/" . $libName;
1244
1245 &utlLog(1, "Excluding " . $libName . "\n");
1246 &utlCpFile($lib, $dstLib);
1247 }
1248 else
1249 {
1250 my $ptrAryPLObj = [];
1251 my $ptrAryNonPLObj = [];
1252
1253 # Find out objects which can be partially linked according to rule.
1254 foreach my $obj (@objList)
1255 {
1256 if (&isExcludedObj($ptrHahRuleGut, $libName, $obj))
1257 {
1258 push(@$ptrAryNonPLObj, $obj);
1259 }
1260 else
1261 {
1262 push(@$ptrAryPLObj, $obj);
1263 }
1264 }
1265 if ($#$ptrAryPLObj < 1)
1266 {
1267 &utlLog(1, "Excluding " . $libName . " due to one object for partial link\n");
1268 &addRule($ptrHahRuleGut, $libName, "*", $hdlFileRule);
1269 &addHint($ptrHahHintGut, $libName, "*", "*", $hdlFileHint);
1270 &utlCpFile($lib, $dirDstLib . "/" . $libName);
1271 }
1272 else
1273 {
1274 my $fileOpt = "__ARM_OPT__.txt";
1275 my $cwd = cwd();
1276 my $err = 1;
1277 my $cmd = "";
1278
1279 &utlRmTree($DirTemp);
1280 &utlMkDir($DirTemp);
1281 &utlChDir($DirTemp);
1282
1283 $cmd = $Cmd_armar . " -x " . $lib;
1284 if (&utlSystem($cmd, -1) == 0)
1285 {
1286 # Partially link objects.
1287 &utlDie("Assert: need at least 2 objects for partial link") unless ($#$ptrAryPLObj > 0);
1288 $cmd = "@$ptrAryPLObj --partial --elf -o " . $linkedObj;
1289 open(FILE_OPT, ">" . $fileOpt) or &utlDie("Cannot open " . $fileOpt);
1290 print(FILE_OPT $cmd);
1291 close(FILE_OPT);
1292 &utlLog(1, $Cmd_armlink . " " . $cmd . "\n");
1293 $cmd = $Cmd_armlink . " --via " . $fileOpt . " >>" . $FileLog . " 2>&1";
1294 if (&utlSystem($cmd, -1) == 0)
1295 {
1296 push(@$ptrAryNonPLObj, $linkedObj);
1297
1298 # Archive objects to create a library.
1299 &utlLog(1, "Creating " . $libName . "\n");
1300 &utlLog(2, "Creating " . $libName . " with @$ptrAryNonPLObj\n");
1301 open(FILE_OPT, ">" . $fileOpt) or &utlDie("Cannot open " . $fileOpt);
1302 printf(FILE_OPT "--create %s/%s @$ptrAryNonPLObj", $dirDstLib, $libName);
1303 close(FILE_OPT);
1304 $cmd = $Cmd_armar . " --via " . $fileOpt . " >>" . $FileLog . " 2>&1";
1305 $err = 0 if (&utlSystem($cmd, -1) == 0);
1306 }
1307 }
1308 if ($err)
1309 {
1310 if ((-e $fileOpt) && open(FILE_OPT, $fileOpt))
1311 {
1312 my @temp = <FILE_OPT>;
1313
1314 close(FILE_OPT);
1315 &utlErr(1, "Dumping " . $fileOpt . ": @temp\n");
1316 }
1317 &utlLog(1, "Excluding " . $libName . " due to failure to execute \"" . $cmd . "\"\n");
1318 &utlCpFile($lib, $dirDstLib . "/" . $libName);
1319 }
1320
1321 &utlChDir($cwd);
1322 &utlRmTree($DirTemp);
1323 }
1324 }
1325}
1326
1327sub partialLinkLib
1328{
1329 my ($ptrHahLib, $ptrHahRule, $ptrHahHint, $ptrHahLibErr) = @_;
1330 my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir};
1331 my $suffix = $ptrHahLib->{suffix};
1332 my $fileRule = $ptrHahRule->{file};
1333 my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut};
1334 my $fileHint = $ptrHahHint->{file};
1335 my $ptrHahHintGut = $ptrHahHint->{ptrHahGut};
1336
1337 &utlLog(1, "Partially linking objects in the same libraries...\n");
1338 open(FILE_RULE, ">>" . $fileRule) or &utlDie("Cannot open " . $fileRule);
1339 open(FILE_HINT, ">>" . $fileHint) or &utlDie("Cannot open " . $fileHint);
1340
1341 if ($ptrHahLibErr && (scalar keys(%$ptrHahLibErr) > 0))
1342 {
1343 foreach my $libName (keys(%$ptrHahLibErr))
1344 {
1345 foreach my $dirSrcLib (@$ptrAryLibDir)
1346 {
1347 my $lib = $dirSrcLib . "/" . $libName;
1348
1349 if (-e $lib)
1350 {
1351 my $dirDstLib = $dirSrcLib . $suffix;
1352
1353 &utlDie("Cannot find " . $dirSrcLib) unless (-e $dirSrcLib);
1354 &utlDie("Cannot find " . $dirDstLib) unless (-e $dirDstLib);
1355 &partialLinkLibGut($lib, $libName, $dirDstLib, $ptrHahLib, $ptrHahRuleGut, \*FILE_RULE, $ptrHahHintGut, \*FILE_HINT);
1356 }
1357 }
1358 }
1359 }
1360 else
1361 {
1362 my $ptrHahLibUsage = $ptrHahLib->{ptrHahLibUsage};
1363
1364 foreach my $dirSrcLib (@$ptrAryLibDir)
1365 {
1366 my @libList = glob($dirSrcLib . "/*.lib");
1367 my $dirDstLib = $dirSrcLib . $suffix;
1368
1369 &utlDie("Cannot find directory " . $dirDstLib) unless (-e $dirDstLib);
1370
1371 foreach my $lib (@libList)
1372 {
1373 my $libName = basename($lib);
1374
1375 if (not exists($ptrHahLibUsage->{$libName}))
1376 {
1377 my $dstLib = $dirDstLib . "/" . $libName;
1378
1379 &utlLog(1, "Excluding " . $libName . " due to no use in the link option file\n");
1380 &utlCpFile($lib, $dstLib);
1381 }
1382 else
1383 {
1384 &partialLinkLibGut($lib, $libName, $dirDstLib, $ptrHahLib, $ptrHahRuleGut, \*FILE_RULE, $ptrHahHintGut, \*FILE_HINT);
1385 }
1386 }
1387 }
1388 }
1389
1390 close(FILE_HINT);
1391 close(FILE_RULE);
1392}
1393
1394use constant {
1395 LINK_NONE => 2,
1396 LINK_OK_STRIP => 1,
1397 LINK_OK => 0,
1398 LINK_OUT_OF_MEM => -1,
1399 LINK_UNKNOWN => -2,
1400 LINK_FAIL => -3,
1401};
1402
1403# Parse an error file from final link.
1404sub parseErrorFile
1405{
1406 my ($ptrHahError) = @_;
1407 my $fileError = $ptrHahError->{file};
1408 my $ret = LINK_OK;
1409
1410 $ptrHahError->{ptrHahObjSymErr} = {};
1411 $ptrHahError->{ptrHahLibSymErr} = {};
1412 $ptrHahError->{ptrHahLibObjRef} = {};
1413 $ptrHahError->{ptrHahLibErr} = {};
1414
1415 &utlLog(1, "Parsing linking error from " . $fileError . "\n");
1416 open(FILE_ERROR, "<" . $fileError) or &utlDie("Cannot open " . $fileError);
1417
1418 my $ptrHahObjSymErr = $ptrHahError->{ptrHahObjSymErr};
1419 my $ptrHahLibSymErr = $ptrHahError->{ptrHahLibSymErr};
1420
1421 foreach my $line (<FILE_ERROR>)
1422 {
1423 if ($line =~ /^Error: L6218E: Undefined symbol (\S+) \(referred from __(\S+)_linked__.obj\)/)
1424 {
1425 $ptrHahLibSymErr->{$2} = {} if (not exists($ptrHahLibSymErr->{$2}));
1426 $ptrHahLibSymErr->{$2}->{$1} = SYM_UNDEF if (not exists($ptrHahLibSymErr->{$2}->{$1}));
1427 $ret = LINK_FAIL;
1428 }
1429 elsif ($line =~ /^Error: L6218E: Undefined symbol (\S+) \(referred from (\S+)\)/)
1430 {
1431 $ptrHahObjSymErr->{$2} = {} if (not exists($ptrHahObjSymErr->{$2}));
1432 $ptrHahObjSymErr->{$2}->{$1} = SYM_UNDEF if (not exists($ptrHahObjSymErr->{$2}->{$1}));
1433 $ret = LINK_FAIL;
1434 }
1435 elsif ($line =~ /^Error: L6200E: Symbol (\S+) multiply defined \(by __(\S+)_linked__.obj and __(\S+)_linked__.obj\)/)
1436 {
1437 $ptrHahLibSymErr->{$2} = {} if (not exists($ptrHahLibSymErr->{$2}));
1438 $ptrHahLibSymErr->{$2}->{$1} = SYM_DEF if (not exists($ptrHahLibSymErr->{$2}->{$1}));
1439 if ($2 ne $3)
1440 {
1441 $ptrHahLibSymErr->{$3} = {} if (not exists($ptrHahLibSymErr->{$3}));
1442 $ptrHahLibSymErr->{$3}->{$1} = SYM_DEF if (not exists($ptrHahLibSymErr->{$3}->{$1}));
1443 }
1444 $ret = LINK_FAIL;
1445 }
1446 elsif ($line =~ /^Error: L6200E: Symbol (\S+) multiply defined \(by __(\S+)_linked__.obj and (\S+)\)/)
1447 {
1448 $ptrHahLibSymErr->{$2} = {} if (not exists($ptrHahLibSymErr->{$2}));
1449 $ptrHahLibSymErr->{$2}->{$1} = SYM_DEF if (not exists($ptrHahLibSymErr->{$2}->{$1}));
1450 $ret = LINK_FAIL;
1451 }
1452 elsif ($line =~ /^Error: L6200E: Symbol (\S+) multiply defined \(by (\S+) and __(\S+)_linked__.obj\)/)
1453 {
1454 $ptrHahLibSymErr->{$3} = {} if (not exists($ptrHahLibSymErr->{$3}));
1455 $ptrHahLibSymErr->{$3}->{$1} = SYM_DEF if (not exists($ptrHahLibSymErr->{$3}->{$1}));
1456 $ret = LINK_FAIL;
1457 }
1458 elsif ($line =~ /^Error: L6200E: Symbol (\S+) multiply defined \(by (\S+) and (\S+)\)/)
1459 {
1460 $ptrHahObjSymErr->{$2} = {} if (not exists($ptrHahObjSymErr->{$2}));
1461 $ptrHahObjSymErr->{$2}->{$1} = SYM_DEF if (not exists($ptrHahObjSymErr->{$2}->{$1}));
1462 $ptrHahObjSymErr->{$3} = {} if (not exists($ptrHahObjSymErr->{$3}));
1463 $ptrHahObjSymErr->{$3}->{$1} = SYM_DEF if (not exists($ptrHahObjSymErr->{$3}->{$1}));
1464 $ret = LINK_FAIL;
1465 }
1466 elsif ($line =~ /^Fatal error: L6000U: Out of memory/)
1467 {
1468 &utlLog(1, $line);
1469 $ret = LINK_OUT_OF_MEM;
1470 last;
1471 }
1472 elsif ( ($line =~ /^Error:/)
1473 || ($line =~ /^Fatal error:/))
1474 {
1475 &utlLog(0, $line);
1476 $ret = LINK_UNKNOWN;
1477 last;
1478 }
1479 }
1480
1481 close(FILE_ERROR);
1482 return $ret;
1483}
1484
1485sub finalLink
1486{
1487 my ($extraOption, $fileLinkOption, $ptrHahError) = @_;
1488 my $fileError = $ptrHahError->{file};
1489 my $fileOutput = $ptrHahError->{fileOutput};
1490 my $cmd = $Cmd_armlink . " " . $extraOption . " --via " . $fileLinkOption . " --errors " . $fileError;
1491
1492 &utlLog(1, "Executing \"" . $cmd . "\"\n");
1493 &utlSystem($cmd, 1);
1494 &utlCpFile($fileError, $fileOutput) unless ($fileOutput eq "");
1495 return &parseErrorFile($ptrHahError);
1496}
1497
1498BEGIN
1499{
1500 my $hasExcludedRedefinedSym = 0;
1501
1502 sub ruleOutObjWithRedefinedSym
1503 {
1504 my ($ptrHahSymTable, $ptrHahRule, $ptrHahHint, $ptrHahLibErr) = @_;
1505 my $ptrHahMultiSymTab = $ptrHahSymTable->{ptrHahMultiSymTab};
1506
1507 if (($hasExcludedRedefinedSym == 0) && $ptrHahMultiSymTab && (scalar keys(%$ptrHahMultiSymTab) > 0))
1508 {
1509 my $ptrHahSymToObjTab = $ptrHahSymTable->{ptrHahSymToObjTab};
1510 my $fileRule = $ptrHahRule->{file};
1511 my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut};
1512 my $fileHint = $ptrHahHint->{file};
1513 my $ptrHahHintGut = $ptrHahHint->{ptrHahGut};
1514
1515 open(FILE_RULE, ">>" . $fileRule) or &utlDie("Cannot open " . $fileRule);
1516 open(FILE_HINT, ">>" . $fileHint) or &utlDie("Cannot open " . $fileHint);
1517
1518 foreach my $sym (keys(%$ptrHahMultiSymTab))
1519 {
1520 if ($sym !~ /^_Z/)
1521 {
1522 my $ptrHahLibObj = $ptrHahSymToObjTab->{$sym}->{+SYM_DEF};
1523
1524 foreach my $lib (keys(%$ptrHahLibObj))
1525 {
1526 if (not &hasRule($ptrHahRuleGut, $lib, "*"))
1527 {
1528 foreach my $obj (keys(%{$ptrHahLibObj->{$lib}}))
1529 {
1530 if (not &hasRule($ptrHahRuleGut, $lib, $obj))
1531 {
1532 &utlLog(1, "Adding rule to exclude " . $lib . "(" . $obj . ") due to redefinition of " . $sym . "\n");
1533 &addRule($ptrHahRuleGut, $lib, $obj, \*FILE_RULE);
1534 &addHint($ptrHahHintGut, $lib, $obj, $sym, \*FILE_HINT);
1535 $ptrHahLibErr->{$lib} = 1;
1536 }
1537 }
1538 }
1539 }
1540 }
1541 }
1542
1543 close(FILE_HINT);
1544 close(FILE_RULE);
1545
1546 $hasExcludedRedefinedSym = 1;
1547 }
1548 }
1549}
1550
1551sub ruleOutCppLib
1552{
1553 my ($ptrHahSymTable, $ptrHahRule, $ptrHahHint, $ptrHahLibErr) = @_;
1554 my $ptrHahCppLibTab = $ptrHahSymTable->{ptrHahCppLibTab};
1555
1556 if ($ptrHahCppLibTab && (scalar keys(%$ptrHahCppLibTab) > 0))
1557 {
1558 my $fileRule = $ptrHahRule->{file};
1559 my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut};
1560 my $fileHint = $ptrHahHint->{file};
1561 my $ptrHahHintGut = $ptrHahHint->{ptrHahGut};
1562
1563 open(FILE_RULE, ">>" . $fileRule) or &utlDie("Cannot open " . $fileRule);
1564 open(FILE_HINT, ">>" . $fileHint) or &utlDie("Cannot open " . $fileHint);
1565
1566 foreach my $lib (keys(%$ptrHahCppLibTab))
1567 {
1568 if (not &hasRule($ptrHahRuleGut, $lib, "*"))
1569 {
1570 &utlLog(1, "Adding rule to exclude " . $lib . " due to C++\n");
1571 &addRule($ptrHahRuleGut, $lib, "*", \*FILE_RULE);
1572 &addHint($ptrHahHintGut, $lib, "*", "*", \*FILE_HINT);
1573 $ptrHahLibErr->{$lib} = 1;
1574 }
1575 }
1576
1577 close(FILE_HINT);
1578 close(FILE_RULE);
1579 }
1580}
1581
1582BEGIN
1583{
1584 my $hasExcludedCppLib = 0;
1585
1586 sub handleObjSymErr
1587 {
1588 my ($ptrHahSymTable, $ptrHahRule, $ptrHahHint, $ptrHahError, $excludeCppLib) = @_;
1589 my $ptrHahObjSymErr = $ptrHahError->{ptrHahObjSymErr};
1590
1591 if (scalar keys(%$ptrHahObjSymErr) > 0)
1592 {
1593 my $ptrHahSymToObjTab = $ptrHahSymTable->{ptrHahSymToObjTab};
1594 my $ptrHahCppLibTab = $ptrHahSymTable->{ptrHahCppLibTab};
1595 my $ptrHahLibObjRef = $ptrHahError->{ptrHahLibObjRef};
1596
1597 foreach my $obj (keys(%$ptrHahObjSymErr))
1598 {
1599 foreach my $sym (keys(%{$ptrHahObjSymErr->{$obj}}))
1600 {
1601 my $type = $ptrHahObjSymErr->{$obj}->{$sym};
1602 my $ptrHahLibObj = $ptrHahSymToObjTab->{$sym}->{$type};
1603
1604 foreach my $lib (keys(%$ptrHahLibObj))
1605 {
1606 if (exists($ptrHahLibObj->{$lib}->{$obj}))
1607 {
1608 if (($hasExcludedCppLib == 1) || ($excludeCppLib == 0) || ($ptrHahCppLibTab == 0) || (not exists($ptrHahCppLibTab->{$lib})))
1609 {
1610 &utlLog(1, "Finding " . $obj . " with " . $sym . " from " . $lib . "\n");
1611 $ptrHahLibObjRef->{$lib} = {} if (not exists($ptrHahLibObjRef->{$lib}));
1612 $ptrHahLibObjRef->{$lib}->{$obj} = 1;
1613 }
1614 }
1615 }
1616 }
1617 }
1618 if (($hasExcludedCppLib == 0) && $excludeCppLib)
1619 {
1620 &ruleOutCppLib($ptrHahSymTable, $ptrHahRule, $ptrHahHint, $ptrHahError->{ptrHahLibErr});
1621 $hasExcludedCppLib = 1;
1622 }
1623 }
1624 }
1625}
1626
1627sub examineLibGut
1628{
1629 my ($lib, $ptrHahSymTable, $ptrHahRuleGut, $hdlFileRule, $ptrHahHintGut, $hdlFileHint, $ptrHahError) = @_;
1630 my $ptrHahSymToObjTab = $ptrHahSymTable->{ptrHahSymToObjTab};
1631 my $ptrHahSymErr = $ptrHahError->{ptrHahLibSymErr}->{$lib};
1632 my $ptrHahLibErr = $ptrHahError->{ptrHahLibErr};
1633
1634 if (not &hasRule($ptrHahRuleGut, $lib, "*"))
1635 {
1636 &utlLog(1, "Examining " . $lib . "\n");
1637
1638 foreach my $sym (keys(%$ptrHahSymErr))
1639 {
1640 my $type = $ptrHahSymErr->{$sym};
1641
1642 foreach my $obj (keys(%{$ptrHahSymToObjTab->{$sym}->{$type}->{$lib}}))
1643 {
1644 if (not &hasRule($ptrHahRuleGut, $lib, $obj))
1645 {
1646 &utlLog(1, "Adding rule to exclude " . $lib . "(" . $obj . ") due to error symbol " . $sym . "\n");
1647 &addRule($ptrHahRuleGut, $lib, $obj, $hdlFileRule);
1648 &addHint($ptrHahHintGut, $lib, $obj, $sym, $hdlFileHint);
1649 $ptrHahLibErr->{$lib} = 1;
1650 }
1651 }
1652 }
1653 }
1654}
1655
1656sub examineLibGutExt
1657{
1658 my ($libRef, $ptrHahSymTable, $ptrHahRuleGut, $hdlFileRule, $ptrHahHintGut, $hdlFileHint, $ptrHahError, $ptrHahRefObjSet) = @_;
1659 my $ptrHahObjToSymTab = $ptrHahSymTable->{ptrHahObjToSymTab};
1660 my $ptrHahSymToObjTab = $ptrHahSymTable->{ptrHahSymToObjTab};
1661 my $ptrHahLibErr = $ptrHahError->{ptrHahLibErr};
1662 my %excludedLib = ();
1663 my @refObjList = ();
1664 my $count = 0;
1665
1666 &utlLog(1, "Searching libraries/objects for referred symbols to exclude...\n");
1667
1668 foreach my $objRef (keys(%{$ptrHahError->{ptrHahLibObjRef}->{$libRef}}))
1669 {
1670 if ( (not exists($ptrHahRefObjSet->{$libRef}))
1671 || (not exists($ptrHahRefObjSet->{$libRef}->{$objRef})))
1672 {
1673 $ptrHahRefObjSet->{$libRef} = {} if (not exists($ptrHahRefObjSet->{$libRef}));
1674 $ptrHahRefObjSet->{$libRef}->{$objRef} = 1;
1675 }
1676 elsif ($ptrHahRefObjSet->{$libRef}->{$objRef} != 1)
1677 {
1678 next;
1679 }
1680 push(@refObjList, $libRef);
1681 push(@refObjList, $objRef);
1682 }
1683 $count = $#refObjList + 1;
1684 while ($count > 0)
1685 {
1686 my $refLib = shift(@refObjList);
1687 my $refObj = shift(@refObjList);
1688 my @symDef = keys(%{$ptrHahObjToSymTab->{$refLib}->{$refObj}->{+SYM_DEF}});
1689
1690 &utlLog(2, "Defined symbols in " . $refLib . "(" . $refObj . "): @symDef\n");
1691 $ptrHahRefObjSet->{$refLib}->{$refObj} = 2;
1692
1693 foreach my $symbol (@symDef)
1694 {
1695 my $ptrHahLibObjSymUndef = $ptrHahSymToObjTab->{$symbol}->{+SYM_UNDEF};
1696 my @libList = keys(%$ptrHahLibObjSymUndef);
1697
1698 foreach my $lib (@libList)
1699 {
1700 if (not exists($excludedLib{$lib}))
1701 {
1702 if (&hasRule($ptrHahRuleGut, $lib, "*"))
1703 {
1704 my @objList = keys(%{$ptrHahLibObjSymUndef->{$lib}});
1705
1706 foreach my $obj (@objList)
1707 {
1708 if ((not exists($ptrHahRefObjSet->{$lib})) || (not exists($ptrHahRefObjSet->{$lib}->{$obj})))
1709 {
1710 &utlLog(1, "Using " . $lib . "(" . $obj . ") to exclude objects due to reference to " . $symbol . " in " . $refLib . "(" . $refObj . ")\n");
1711 push(@refObjList, $lib);
1712 push(@refObjList, $obj);
1713 $ptrHahRefObjSet->{$lib} = {} if (not exists($ptrHahRefObjSet->{$lib}));
1714 $ptrHahRefObjSet->{$lib}->{$obj} = 1;
1715 }
1716 }
1717 }
1718 else
1719 {
1720 &utlLog(1, "Adding rule to exclude " . $lib . " due to reference to " . $symbol . " in " . $refLib . "(" . $refObj . ")\n");
1721 &addRule($ptrHahRuleGut, $lib, "*", $hdlFileRule);
1722 &addHint($ptrHahHintGut, $lib, "*", "*", $hdlFileHint);
1723 $ptrHahLibErr->{$lib} = 1;
1724 $excludedLib{$lib} = 1;
1725 }
1726 }
1727 }
1728 }
1729 last if (scalar keys(%excludedLib));
1730 $count = $#refObjList + 1;
1731 &utlLog(2, "Referred objects(" . $count . "): @refObjList\n");
1732 }
1733}
1734
1735sub examineLib
1736{
1737 my ($ptrHahSymTable, $ptrHahRule, $ptrHahHint, $ptrHahError) = @_;
1738 my $fileRule = $ptrHahRule->{file};
1739 my $ptrHahRuleGut = $ptrHahRule->{ptrHahGut};
1740 my $fileHint = $ptrHahHint->{file};
1741 my $ptrHahHintGut = $ptrHahHint->{ptrHahGut};
1742 my $ptrHahLibSymErr = $ptrHahError->{ptrHahLibSymErr};
1743 my $ptrHahLibObjRef = $ptrHahError->{ptrHahLibObjRef};
1744 my %refObjSet = ();
1745
1746 open(FILE_HINT, ">>" . $fileHint) or &utlDie("Cannot open " . $fileHint);
1747 open(FILE_RULE, ">>" . $fileRule) or &utlDie("Cannot open " . $fileRule);
1748
1749 # Handle error symbols.
1750 foreach my $lib (keys(%$ptrHahLibSymErr))
1751 {
1752 &examineLibGut($lib, $ptrHahSymTable, $ptrHahRuleGut, \*FILE_RULE, $ptrHahHintGut, \*FILE_HINT, $ptrHahError);
1753 }
1754
1755 # Handle referred objects.
1756 foreach my $lib (keys(%$ptrHahLibObjRef))
1757 {
1758 &examineLibGutExt($lib, $ptrHahSymTable, $ptrHahRuleGut, \*FILE_RULE, $ptrHahHintGut, \*FILE_HINT, $ptrHahError, \%refObjSet);
1759 }
1760
1761 close(FILE_RULE);
1762 close(FILE_HINT);
1763}
1764
1765# -----------------------------------------------------------------------------
1766
1767sub getDisplayValue
1768{
1769 my ($formatStr, $value) = @_;
1770
1771 if ($formatStr =~ /!/)
1772 {
1773 return "on" if ($value);
1774 return "off";
1775 }
1776 return $value;
1777}
1778
1779sub help
1780{
1781 my ($ptrHahOptDesc) = @_;
1782
1783 printf("\nPartial Link Auto-Filter Script (%s) ver. %s\n", basename( __FILE__), $Version);
1784 printf("\nOptions:\n\n");
1785
1786 foreach my $key (sort(keys(%$ptrHahOptDesc)))
1787 {
1788 printf("%s\n", $ptrHahOptDesc->{$key}->[1]);
1789 printf("\t\t%s", $ptrHahOptDesc->{$key}->[2]);
1790 printf(" (default: %s)", &getDisplayValue($ptrHahOptDesc->{$key}->[0], $ptrHahOptDesc->{$key}->[3])) if ($ptrHahOptDesc->{$key}->[3] ne "");
1791 printf("\n");
1792 }
1793 printf("\nAn example:\n\n");
1794 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__);
1795}
1796
1797use constant {
1798 TYPE_AUTO => 1,
1799 TYPE_NORMAL => 2,
1800 TYPE_PARTIAL => 3,
1801};
1802
1803sub getOption
1804{
1805 my ($ptrHahOpt, $ptrHahOptPath, $ptrHahOptPathMust) = @_;
1806 my %optDesc = (
1807 "ptrAryLibDir" => [ "lib-dir=s", "--lib-dir=", "a path to a library directory for partial link", "" ],
1808 "ptrAryUserExclusionFile" => [ "exclusion-file=s", "--exclusion-file=", "a path to a user exclusion file", "" ],
1809 "fileScatter" => [ "scatter-file=s", "--scatter-file=", "a path to a scatter file", "" ],
1810 "fileLinkOption" => [ "link-option-file=s", "--link-option-file=", "a path to a file with link options for final link", "" ],
1811 "dirInfo" => [ "info-dir=s", "--info-dir=", "a path to a directory to access info", $ptrHahOptPathMust->{dirInfo} ],
1812 "dirSave" => [ "save-dir=s", "--save-dir=", "a path to a directory to save log", $ptrHahOptPathMust->{dirSave} ],
1813 "dirTemp" => [ "temp-dir=s", "--temp-dir=", "a path to a temp directory", $ptrHahOptPathMust->{dirTemp} . "/pl_temp" ],
1814 "cmd_nm" => [ "nm=s", "--nm=", "a path to command nm", "" ],
1815 "cmd_readelf" => [ "readelf=s", "--readelf=", "a path to command readelf", "" ],
1816 "cmd_strip" => [ "strip=s", "--strip=", "a path to command strip", "" ],
1817 "cmd_armar" => [ "armar=s", "--armar=", "a path to command armar", $Cmd_armar ],
1818 "cmd_armlink" => [ "armlink=s", "--armlink=", "a path to command armlink", $Cmd_armlink ],
1819 "fileLinkErr" => [ "link-err-file=s", "--link-err-file=", "a path to a file to output link error", "" ],
1820 "reGenRule" => [ "regen-rule!", "--[no-]regen-rule", "re-generate rule", $ptrHahOpt->{reGenRule} ],
1821 "reGenHint" => [ "regen-hint!", "--[no-]regen-hint", "re-generate hint", $ptrHahOpt->{reGenHint} ],
1822 "hintToRule" => [ "hint-to-rule!", "--[no-]hint-to-rule", "convert hint to rule", $ptrHahOpt->{hintToRule} ],
1823 "excludeCppLib" => [ "exclude-cpp-lib!", "--[no-]exclude-cpp-lib", "exclude all C++ libraries when errors happen", $ptrHahOpt->{excludeCppLib} ],
1824 "passLimit" => [ "pass-limit=i", "--pass-limit=", "set limitation of the max. pass to resolve linking error", $ptrHahOpt->{passLimit} ],
1825 "simulate" => [ "simulate!", "--[no-]simulate", "run the whole process without modifying libraries", $ptrHahOpt->{simulate} ],
1826 "linkType" => [ "link-type=i", "--link-type=", "specify 1 for \"auto enabling partial link\", 2 for \"normal link\", or 3 for \"partial link\"", $ptrHahOpt->{linkType} ],
1827 "libSizeInfo" => [ "lib-size-info!", "--[no-]lib-size-info", "generate library size info", $ptrHahOpt->{libSizeInfo} ],
1828 "stripDebugInfo" => [ "strip-debug-info!", "--[no-]strip-debug-info", "strip debug info", $ptrHahOpt->{stripDebugInfo} ],
1829 "stripDebugCount" => [ "strip-debug-count=i", "--strip-debug-count=", "set default count to strip debug info if \"pl_debug.txt\" is not available", $ptrHahOpt->{stripDebugCount} ],
1830 "check" => [ "check!", "--[no-]check", "not to run if partial link is done last time", $ptrHahOpt->{check} ],
1831 "forcePartialLink" => [ "force-partial-link!", "--[no-]force-partial-link", "force to run partial link only", $ptrHahOpt->{forcePartialLink} ],
1832 "update" => [ "update!", "--[no-]update", "update libraries specified in \"--lib-dir=...\" with partially-linked ones", $ptrHahOpt->{update} ],
1833 "save" => [ "save!", "--[no-]save", "save partially-linked libraries", $ptrHahOpt->{save} ],
1834 "dbgLevel" => [ "debug-level=i", "--debug-level=", "set debug level", $DbgLevel ],
1835 "infoLevel" => [ "info-level=i", "--info-level=", "set how much information displays in the screen", $InfoLevel ],
1836 "help" => [ "help", "--help", "show this help", "" ],
1837 );
1838
1839 if (!GetOptions(
1840 $optDesc{ptrAryLibDir}[0] => \@{$ptrHahOptPathMust->{ptrAryLibDir}},
1841 $optDesc{ptrAryUserExclusionFile}[0] => \@{$ptrHahOptPath->{ptrAryUserExclusionFile}},
1842 $optDesc{fileScatter}[0] => \$ptrHahOptPathMust->{fileScatter},
1843 $optDesc{fileLinkOption}[0] => \$ptrHahOptPathMust->{fileLinkOption},
1844 $optDesc{dirInfo}[0] => \$ptrHahOptPathMust->{dirInfo},
1845 $optDesc{dirSave}[0] => \$ptrHahOptPathMust->{dirSave},
1846 $optDesc{dirTemp}[0] => \$ptrHahOptPathMust->{dirTemp},
1847 $optDesc{cmd_nm}[0] => \$ptrHahOptPathMust->{cmd_nm},
1848 $optDesc{cmd_readelf}[0] => \$ptrHahOptPathMust->{cmd_readelf},
1849 $optDesc{cmd_strip}[0] => \$ptrHahOptPathMust->{cmd_strip},
1850 $optDesc{cmd_armar}[0] => \$ptrHahOptPath->{cmd_armar},
1851 $optDesc{cmd_armlink}[0] => \$ptrHahOptPath->{cmd_armlink},
1852 $optDesc{fileLinkErr}[0] => \$ptrHahOptPath->{fileLinkErr},
1853 $optDesc{reGenRule}[0] => \$ptrHahOpt->{reGenRule},
1854 $optDesc{reGenHint}[0] => \$ptrHahOpt->{reGenHint},
1855 $optDesc{hintToRule}[0] => \$ptrHahOpt->{hintToRule},
1856 $optDesc{excludeCppLib}[0] => \$ptrHahOpt->{excludeCppLib},
1857 $optDesc{passLimit}[0] => \$ptrHahOpt->{passLimit},
1858 $optDesc{simulate}[0] => \$ptrHahOpt->{simulate},
1859 $optDesc{linkType}[0] => \$ptrHahOpt->{linkType},
1860 $optDesc{libSizeInfo}[0] => \$ptrHahOpt->{libSizeInfo},
1861 $optDesc{stripDebugInfo}[0] => \$ptrHahOpt->{stripDebugInfo},
1862 $optDesc{stripDebugCount}[0] => \$ptrHahOpt->{stripDebugCount},
1863 $optDesc{check}[0] => \$ptrHahOpt->{check},
1864 $optDesc{forcePartialLink}[0] => \$ptrHahOpt->{forcePartialLink},
1865 $optDesc{update}[0] => \$ptrHahOpt->{update},
1866 $optDesc{save}[0] => \$ptrHahOpt->{save},
1867 $optDesc{dbgLevel}[0] => \$DbgLevel,
1868 $optDesc{infoLevel}[0] => \$InfoLevel,
1869 $optDesc{help}[0] => \$ptrHahOpt->{help}) || $ptrHahOpt->{help})
1870 {
1871 &help(\%optDesc);
1872 return 1;
1873 }
1874
1875 foreach my $key (keys(%$ptrHahOptPath))
1876 {
1877 if (ref($ptrHahOptPath->{$key}) eq 'ARRAY')
1878 {
1879 for (my $i = 0; $i <= $#{$ptrHahOptPath->{$key}}; $i++)
1880 {
1881 $ptrHahOptPath->{$key}->[$i] = &utlTrim($ptrHahOptPath->{$key}->[$i]);
1882 &utlDie("Value of option " . $optDesc{$key}[1] . " cannot be empty") if ($ptrHahOptPath->{$key}->[$i] eq "");
1883 $ptrHahOptPath->{$key}->[$i] = &utlAbsPath($ptrHahOptPath->{$key}->[$i]);
1884 }
1885 }
1886 else
1887 {
1888 $ptrHahOptPath->{$key} = &utlTrim($ptrHahOptPath->{$key});
1889 if ($ptrHahOptPath->{$key} ne "")
1890 {
1891 if (($key eq "fileLinkErr") && (! -e $ptrHahOptPath->{$key}))
1892 {
1893 my $path = dirname($ptrHahOptPath->{$key});
1894 my $fileName = basename($ptrHahOptPath->{$key});
1895
1896 &utlDie("Cannot find " . $path) unless (-e $path);
1897 $ptrHahOptPath->{$key} = &utlAbsPath($path) . "/" . $fileName;
1898 }
1899 else
1900 {
1901 $ptrHahOptPath->{$key} = &utlAbsPath($ptrHahOptPath->{$key});
1902 }
1903 }
1904 elsif ($optDesc{$key}->[3] ne "")
1905 {
1906 $ptrHahOptPath->{$key} = $optDesc{$key}->[3];
1907 }
1908 }
1909 }
1910 foreach my $key (keys(%$ptrHahOptPathMust))
1911 {
1912 if (ref($ptrHahOptPathMust->{$key}) eq 'ARRAY')
1913 {
1914 my $ptrAryPath = [];
1915
1916 &utlDie("Must specify " . $optDesc{$key}[1]) if ($#{$ptrHahOptPathMust->{$key}} < 0);
1917 for (my $i = 0; $i <= $#{$ptrHahOptPathMust->{$key}}; $i++)
1918 {
1919 my $path = $ptrHahOptPathMust->{$key}->[$i];
1920
1921 $path = &utlTrim($path);
1922 &utlDie("Value of option " . $optDesc{$key}[1] . " cannot be empty") if ($path eq "");
1923 if (-e $path)
1924 {
1925 push(@$ptrAryPath, &utlAbsPath($path));
1926 }
1927 else
1928 {
1929 &utlLog(0, "Ignore " . $path . " due to no existence\n");
1930 }
1931 }
1932 &utlDie("No valid path is specified by option " . $optDesc{$key}[1]) unless ($#$ptrAryPath >= 0);
1933 $ptrHahOptPathMust->{$key} = $ptrAryPath;
1934 }
1935 else
1936 {
1937 $ptrHahOptPathMust->{$key} = &utlTrim($ptrHahOptPathMust->{$key});
1938 &utlDie("Value of option " . $optDesc{$key}[1] . " cannot be empty") if ($ptrHahOptPathMust->{$key} eq "");
1939 $ptrHahOptPathMust->{$key} = &utlAbsPath($ptrHahOptPathMust->{$key});
1940 }
1941 }
1942
1943 if ( ($ptrHahOpt->{linkType} != TYPE_AUTO)
1944 && ($ptrHahOpt->{linkType} != TYPE_NORMAL)
1945 && ($ptrHahOpt->{linkType} != TYPE_PARTIAL))
1946 {
1947 &utlDie("Illegal value " . $ptrHahOpt->{linkType} . " for option " . $optDesc{linkType}[1]);
1948 }
1949 return 0;
1950}
1951
1952sub formatCmd
1953{
1954 my ($cmd) = @_;
1955
1956 $cmd =~ s/\(/"("/g;
1957 $cmd =~ s/\)/")"/g;
1958
1959 return $cmd;
1960}
1961
1962sub dumpOpt
1963{
1964 my ($ptrHah) = @_;
1965
1966 foreach my $key (keys(%$ptrHah))
1967 {
1968 &utlLog(1, "-> " . $key . "\n");
1969 &utlDump(1, $ptrHah->{$key});
1970 }
1971}
1972
1973BEGIN
1974{
1975 my $_file = "";
1976
1977 sub setupErrorHandling
1978 {
1979 my ($file) = @_;
1980
1981 &utlRmFile(dirname($file) . "/" . basename($FileErr));
1982 $_file = $file;
1983 }
1984
1985 sub errorHandling
1986 {
1987 if ($_file ne "")
1988 {
1989 &utlCpFile($FileErr, $_file);
1990 &utlCpFile($FileErr, dirname($_file));
1991 }
1992 }
1993}
1994
1995sub readIniFile
1996{
1997 my ($ptrHahIni) = @_;
1998 my $fileIni = $ptrHahIni->{file};
1999 my $ptrHahAttr = $ptrHahIni->{ptrHahAttr};
2000 my $ptrHahValue = $ptrHahIni->{ptrHahValue};
2001 my $ptrHahOnOff = $ptrHahIni->{ptrHahOnOff};
2002
2003 if (-e $fileIni)
2004 {
2005 open(FILE_INI, "<" . $fileIni) or &utlDie("Cannot open " . $fileIni);
2006
2007 foreach my $line (<FILE_INI>)
2008 {
2009 next if (($line =~ /^\s*$/) || ($line =~ /^\s*;/));
2010
2011 # key = value
2012 if ($line =~ /^\s*(\S+)\s*=\s*([-]?\d+)/)
2013 {
2014 my $key = $1;
2015 my $value = $2;
2016
2017 if (exists($ptrHahAttr->{$key}))
2018 {
2019 $ptrHahAttr->{$key} = $value;
2020 }
2021 elsif (exists($ptrHahValue->{$key}))
2022 {
2023 $ptrHahValue->{$key}->[0] = 1;
2024 ${$ptrHahValue->{$key}->[1]} = $value;
2025
2026 if ($#{$ptrHahValue->{$key}} > 1)
2027 {
2028 my $found = 0;
2029
2030 for (my $i = 2; $i <= $#{$ptrHahValue->{$key}}; $i++)
2031 {
2032 if ($value == $ptrHahValue->{$key}->[$i])
2033 {
2034 $found = 1;
2035 last;
2036 }
2037 }
2038 &utlDie("Invalid value \"" . $value . "\" for " . $key . " in " . $fileIni) unless ($found);
2039 }
2040 }
2041 elsif (exists($ptrHahOnOff->{$key}))
2042 {
2043 if (($value == 1) || ($value == 0))
2044 {
2045 $ptrHahOnOff->{$key}->[0] = 1;
2046 ${$ptrHahOnOff->{$key}->[1]} = $value;
2047 }
2048 else
2049 {
2050 &utlDie("Invalid value \"" . $value . "\" for " . $key . " in " . $fileIni . "; should be 0 for disable and 1 for enable");
2051 }
2052 }
2053 else
2054 {
2055 &utlDie("Invalid key \"" . $key . "\" in " . $fileIni);
2056 }
2057 }
2058 else
2059 {
2060 &utlDie("Unrecognized line \"" . $line . "\" in " . $fileIni);
2061 }
2062 }
2063
2064 close(FILE_INI);
2065 }
2066}
2067
2068sub writeIniFile
2069{
2070 my ($ptrHahIni) = @_;
2071 my $fileIni = $ptrHahIni->{file};
2072 my $flag = $ptrHahIni->{flag};
2073 my $ptrHahAttr = $ptrHahIni->{ptrHahAttr};
2074 my $ptrHahValue = $ptrHahIni->{ptrHahValue};
2075 my $ptrHahOnOff = $ptrHahIni->{ptrHahOnOff};
2076
2077 if ($flag != 0)
2078 {
2079 open(FILE_INI, ">" . $fileIni) or &utlDie("Cannot open " . $fileIni);
2080
2081 print(FILE_INI "\n; DO NOT MODIFY THE FOLLOWING INFORMATION\n\n");
2082
2083 foreach my $key (keys(%$ptrHahAttr))
2084 {
2085 print(FILE_INI $key . "=" . $ptrHahAttr->{$key} . "\n");
2086 }
2087
2088 print(FILE_INI "\n; UNCOMMENT THE FOLLOWING TO OVERRIDE CORRESPONDING SETTINGS BY REMOVING \";\"\n\n");
2089
2090 foreach my $key (keys(%$ptrHahValue))
2091 {
2092 if ($ptrHahValue->{$key}->[0] != 0)
2093 {
2094 print(FILE_INI $key . "=" . ${$ptrHahValue->{$key}->[1]} . "\n");
2095 }
2096 else
2097 {
2098 print(FILE_INI "; " . $key . "=" . ${$ptrHahValue->{$key}->[1]} . "\n");
2099 }
2100 }
2101 foreach my $key (keys(%$ptrHahOnOff))
2102 {
2103 if ($ptrHahOnOff->{$key}->[0] != 0)
2104 {
2105 print(FILE_INI $key . "=" . ${$ptrHahOnOff->{$key}->[1]} . "\n");
2106 }
2107 elsif (${$ptrHahOnOff->{$key}->[1]})
2108 {
2109 print(FILE_INI "; " . $key . "=0\n");
2110 }
2111 else
2112 {
2113 print(FILE_INI "; " . $key . "=1\n");
2114 }
2115 }
2116
2117 close(FILE_INI);
2118 }
2119}
2120
2121sub setIni
2122{
2123 my ($ptrHahIni, $key, $value) = @_;
2124
2125 $ptrHahIni->{ptrHahAttr}->{$key} = $value;
2126 $ptrHahIni->{flag} = 1;
2127}
2128
2129sub syncLib
2130{
2131 my ($ptrHahLib) = @_;
2132 my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir};
2133 my $suffix = $ptrHahLib->{suffix};
2134 my $suffix_bak = $ptrHahLib->{suffix_bak};
2135
2136 foreach my $dirSrcLib (@$ptrAryLibDir)
2137 {
2138 my $dirDstLib = $dirSrcLib . $suffix;
2139 my $dirSrcBak = $dirSrcLib . $suffix_bak;
2140
2141 if ((-e $dirSrcBak) && (-e $dirDstLib))
2142 {
2143 my @libList = glob($dirSrcLib . "/*");
2144
2145 foreach my $lib (@libList)
2146 {
2147 if (-f $lib)
2148 {
2149 my $libName = basename($lib);
2150 my $timestamp = &utlGetTimestamp($lib);
2151 my $libDst = $dirDstLib . "/" . $libName;
2152
2153 if ((-e $libDst) && ($timestamp == &utlGetTimestamp($libDst)))
2154 {
2155 my $libSrcBak = $dirSrcBak . "/" . $libName;
2156
2157 if (-e $libSrcBak)
2158 {
2159 &utlLog(1, "Restoring " . $libName . "\n");
2160 &utlCpFile($libSrcBak, $lib) if ($timestamp != &utlGetTimestamp($libSrcBak));
2161 }
2162 }
2163 }
2164 }
2165 }
2166 &utlRmTree($dirSrcBak);
2167 &utlRmTree($dirDstLib);
2168 &utlRmTree($dirSrcLib . $ptrHahLib->{suffix_dbg});
2169 &utlRmTree($dirSrcLib . $ptrHahLib->{suffix_save});
2170 }
2171}
2172
2173sub checkLib
2174{
2175 my ($ptrHahLib) = @_;
2176 my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir};
2177 my $fileTimestamp = $ptrHahLib->{fileTimestamp};
2178 my $ptrHahLibNew = $ptrHahLib->{ptrHahLibNew};
2179 my $ptrHahLibUpdate = $ptrHahLib->{ptrHahLibUpdate};
2180 my %timestamp = ();
2181
2182 # Load timestamp of each library.
2183 if (-e $fileTimestamp)
2184 {
2185 open(FILE_TS, "<" . $fileTimestamp) or &utlDie("Cannot open " . $fileTimestamp);
2186
2187 foreach my $line (<FILE_TS>)
2188 {
2189 if ($line =~ /^\s*(\S+)\s*(\S+)/)
2190 {
2191 $timestamp{$1} = $2;
2192 }
2193 }
2194
2195 close(FILE_TS);
2196 }
2197
2198 foreach my $dirSrcLib (@$ptrAryLibDir)
2199 {
2200 my @libList = glob($dirSrcLib . "/*.lib");
2201
2202 foreach my $lib (@libList)
2203 {
2204 my $curTimestamp = (stat($lib))[9];
2205 my $libName = basename($lib);
2206
2207 next if (exists($IgnoredLib{$libName}));
2208
2209 if (not exists($timestamp{$libName}))
2210 {
2211 $ptrHahLibNew->{$libName} = 1;
2212 }
2213 elsif ($curTimestamp > $timestamp{$libName})
2214 {
2215 $ptrHahLibUpdate->{$libName} = 1;
2216 }
2217 }
2218 }
2219}
2220
2221sub generateLibSize
2222{
2223 my ($ptrHahLib) = @_;
2224 my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir};
2225 my $ptrHahLibNew = $ptrHahLib->{ptrHahLibNew};
2226 my $ptrHahLibUpdate = $ptrHahLib->{ptrHahLibUpdate};
2227 my $dirLibSize = $ptrHahLib->{dirLibSize};
2228
2229 &utlMkDir($dirLibSize);
2230
2231 foreach my $dirSrcLib (@$ptrAryLibDir)
2232 {
2233 my @libList = glob($dirSrcLib . "/*.lib");
2234
2235 foreach my $lib (@libList)
2236 {
2237 my $libName = basename($lib);
2238
2239 if (exists($ptrHahLibNew->{$libName}) || exists($ptrHahLibUpdate->{$libName}))
2240 {
2241 &utlLog(1, "Generating size info for " . $libName . "\n");
2242 &utlSystem($Cmd_armar . " --sizes " . $lib . " >" . $dirLibSize . "/" . $libName . ".txt");
2243 }
2244 }
2245 }
2246}
2247
2248sub normalLinkStrip
2249{
2250 my ($ptrHanLib, $ptrHahError, $fileCppLib, $fileDbgLib, $fileLinkOption, $stripDebugCount) = @_;
2251 my $ret = 0;
2252
2253 &copyLib($ptrHanLib->{ptrAryLibDir}, "", $ptrHanLib->{suffix});
2254 &removeDebugInfo($ptrHanLib, $ptrHanLib->{suffix}, $fileCppLib, $fileDbgLib, $stripDebugCount);
2255 $ret = &finalLink("", $fileLinkOption, $ptrHahError);
2256 &removeDstLibDir($ptrHanLib, $ptrHanLib->{suffix}, "") if ($ret == LINK_OK);
2257 return $ret;
2258}
2259
2260sub partialLink
2261{
2262 my ($ptrHahOpt, $ptrHahOptPath, $ptrHahOptPathMust, $ptrHahLib, $ptrHahError, $fileCppLib, $fileDbgLib, $fileLinkOption) = @_;
2263 my %rule = (
2264 "file" => $ptrHahOptPathMust->{dirSave} . "/pl.rule",
2265 "fileRule" => $ptrHahOptPathMust->{dirInfo} . "/pl_rule.txt",
2266 "ptrHahGut" => {},
2267 );
2268 my %hint = (
2269 "file" => $ptrHahOptPathMust->{dirSave} . "/pl.hint",
2270 "fileHint" => $ptrHahOptPathMust->{dirInfo} . "/pl_hint.txt",
2271 "toRule" => $ptrHahOpt->{hintToRule},
2272 "ptrHahGut" => {},
2273 "use" => 1,
2274 );
2275 my $fileExclusion = $ptrHahOptPathMust->{dirInfo} . "/pl_exclusion.txt";
2276 my $pass = 0;
2277 my $ret = 1;
2278
2279 # Remove temporary files.
2280 &utlRmFile($rule{file});
2281 &utlRmFile($hint{file});
2282
2283 # Create temporary directories for partially-linked libraries.
2284 &createDstLibDir($ptrHahLib);
2285
2286 if (($ptrHahOpt->{reGenRule} == 0) && (-e $rule{fileRule}))
2287 {
2288 &readRuleFile(\%rule);
2289 }
2290 else
2291 {
2292 # Parse scatter file and output rules to the rule file.
2293 &parseScatterFile($ptrHahOptPathMust->{fileScatter}, \%rule);
2294
2295 # Read user exclusion file and output rules to the rule file.
2296 &readUserExclusionFile($ptrHahOptPath->{ptrAryUserExclusionFile}, \%rule);
2297
2298 # Read exclusion file and output rules to the rule file.
2299 &readExclusionFile($fileExclusion, \%rule) if (-e $fileExclusion);
2300
2301 # Write built-in excluded libraries to the rule file.
2302 &writeExcludedLib(\@ExcludedLib, \%rule);
2303 }
2304
2305 # Read hint file and output rules to the rule file.
2306 &readHintFile(\%hint, \%rule) if (($ptrHahOpt->{reGenHint} == 0) && (-e $hint{fileHint}));
2307
2308 # Generate a link option file.
2309 &generateLinkOptFile($ptrHahLib, $rule{ptrHahGut}, $ptrHahOptPathMust->{fileLinkOption}, $fileLinkOption);
2310
2311 &utlLog(2, "Dumping hint...\n");
2312 &utlDump(2, $hint{ptrHahGut});
2313 &utlLog(2, "Dumping rule...\n");
2314 &utlDump(2, $rule{ptrHahGut});
2315
2316 while ($pass < $ptrHahOpt->{passLimit})
2317 {
2318 $pass++;
2319 &utlLog(1, "Pass " . $pass . "...\n");
2320
2321 # Set a file to output linking error.
2322 $ptrHahError->{file} = $ptrHahOptPathMust->{dirSave} . "/pl_error_" . $pass . ".log";
2323
2324 if ($pass != 1)
2325 {
2326 &loadSymTable($ptrHahLib, $fileCppLib);
2327 &ruleOutObjWithRedefinedSym($ptrHahLib->{ptrHahSymTable}, \%rule, \%hint, $ptrHahError->{ptrHahLibErr});
2328
2329 # Find out libraries where objects with error symbols are located.
2330 &utlLog(2, "Dumping errors from objects with symbols...\n");
2331 &utlDump(2, $ptrHahError->{ptrHahObjSymErr});
2332 &handleObjSymErr($ptrHahLib->{ptrHahSymTable}, \%rule, \%hint, $ptrHahError, $ptrHahOpt->{excludeCppLib});
2333
2334 &utlLog(2, "Dumping errors from libraries with symbols...\n");
2335 &utlDump(2, $ptrHahError->{ptrHahLibSymErr});
2336 &examineLib($ptrHahLib->{ptrHahSymTable}, \%rule, \%hint, $ptrHahError);
2337
2338 last unless (scalar keys(%{$ptrHahError->{ptrHahLibErr}}));
2339 &utlLog(3, "Dumping rule...\n");
2340 &utlDump(3, $rule{ptrHahGut});
2341 }
2342
2343 # Partially link objects in the same libraries according to rule and linking error.
2344 $Current_time = time;
2345 system("echo T_S,partialLinkLib,P,$Current_time >> $ptrHahOptPathMust->{dirSave}/PlinkTime.log");
2346 &partialLinkLib($ptrHahLib, \%rule, \%hint, $ptrHahError->{ptrHahLibErr});
2347 $Current_time = time;
2348 system("echo T_E,partialLinkLib,P,$Current_time >> $ptrHahOptPathMust->{dirSave}/PlinkTime.log");
2349
2350 # Link all by using command from a file specified in option.
2351 $ret = &finalLink("--mangled", $fileLinkOption, $ptrHahError);
2352 last if (($ret == LINK_OK) || ($ret == LINK_OUT_OF_MEM) || ($ret == LINK_UNKNOWN));
2353 }
2354 if ($ret == LINK_OUT_OF_MEM)
2355 {
2356 if ($ptrHahOpt->{stripDebugInfo})
2357 {
2358 &utlLog(0, "Trying link with debug info stripping due to \"Fatal error: L6000U: Out of memory.\"\n");
2359 $ptrHahError->{file} = $ptrHahOptPathMust->{dirSave} . "/pl_error_dbg.log";
2360 &copyLib($ptrHahLib->{ptrAryLibDir}, $ptrHahLib->{suffix}, $ptrHahLib->{suffix_dbg});
2361 &removeDebugInfo($ptrHahLib, $ptrHahLib->{suffix}, $fileCppLib, $fileDbgLib, $ptrHahOpt->{stripDebugCount});
2362 $ret = &finalLink("", $fileLinkOption, $ptrHahError);
2363 $ret = LINK_OK_STRIP if ($ret == LINK_OK);
2364 if (($ret == LINK_OK_STRIP) || ($ret == LINK_OUT_OF_MEM))
2365 {
2366 &removeDstLibDir($ptrHahLib, $ptrHahLib->{suffix}, "");
2367 $ptrHahLib->{suffix} = $ptrHahLib->{suffix_dbg};
2368 }
2369 }
2370 }
2371 if (($ret == LINK_OK) || ($ret == LINK_OK_STRIP) || ($ret == LINK_OUT_OF_MEM))
2372 {
2373 if ($ptrHahOpt->{simulate})
2374 {
2375 &removeDstLibDir($ptrHahLib, $ptrHahLib->{suffix}, $ptrHahLib->{suffix_save});
2376 }
2377 elsif ($ptrHahOpt->{update} == 0)
2378 {
2379 my $suffix = "";
2380
2381 $suffix = $ptrHahLib->{suffix_save} if ($ptrHahOpt->{save});
2382 &removeDstLibDir($ptrHahLib, $ptrHahLib->{suffix}, $suffix);
2383 &utlCpFile($rule{file}, $rule{fileRule});
2384 &utlCpFile($hint{file}, $hint{fileHint});
2385 }
2386 else
2387 {
2388 &finalizeLib($ptrHahLib);
2389 &utlCpFile($rule{file}, $rule{fileRule});
2390 &utlCpFile($hint{file}, $hint{fileHint});
2391 }
2392 }
2393 elsif ($ret != LINK_OUT_OF_MEM)
2394 {
2395 &removeDstLibDir($ptrHahLib, $ptrHahLib->{suffix}, "");
2396 &removeDstLibDir($ptrHahLib, $ptrHahLib->{suffix_dbg}, "");
2397 }
2398 return $ret;
2399}
2400
2401sub generateLibTimestamp
2402{
2403 my ($ptrHahLib) = @_;
2404 my $ptrAryLibDir = $ptrHahLib->{ptrAryLibDir};
2405 my $fileTimestamp = $ptrHahLib->{fileTimestamp};
2406
2407 &utlLog(1, "Generating library timestamp\n");
2408 open(FILE_TS, ">" . $fileTimestamp) or &utlDie("Cannot open " . $fileTimestamp);
2409
2410 foreach my $dirSrcLib (@$ptrAryLibDir)
2411 {
2412 my @libList = glob($dirSrcLib . "/*.lib");
2413
2414 foreach my $lib (@libList)
2415 {
2416 my $timestamp = (stat($lib))[9];
2417 my $libName = basename($lib);
2418
2419 print(FILE_TS $libName . " " . $timestamp . "\n");
2420 }
2421 }
2422
2423 close(FILE_TS);
2424}
2425
2426sub main
2427{
2428 $Current_time = time;
2429 my ($argc, $argv) = @_;
2430 # Set options.
2431 my %opt = (
2432 "reGenRule" => 1,
2433 "reGenHint" => 0,
2434 "hintToRule" => 1,
2435 "excludeCppLib" => 0,
2436 "passLimit" => 7,
2437 "simulate" => 0,
2438 "linkType" => TYPE_AUTO,
2439 "libSizeInfo" => 1,
2440 "stripDebugInfo" => 1,
2441 "stripDebugCount" => 8,
2442 "check" => 0,
2443 "forcePartialLink" => 0,
2444 "update" => 1,
2445 "save" => 0,
2446 "help" => 0,
2447 );
2448 # Set options with validated path values.
2449 my %optPath = (
2450 "ptrAryUserExclusionFile" => [],
2451 "cmd_armar" => "",
2452 "cmd_armlink" => "",
2453 "fileLinkErr" => "",
2454 );
2455 my %optPathMust = (
2456 "ptrAryLibDir" => [],
2457 "cmd_nm" => "",
2458 "cmd_readelf" => "",
2459 "cmd_strip" => "",
2460 "fileScatter" => "",
2461 "fileLinkOption" => "",
2462 "dirInfo" => cwd(),
2463 "dirSave" => cwd(),
2464 "dirTemp" => cwd(),
2465 );
2466 my $plink_start = time;
2467 my $plink_end = "";
2468
2469 return 2 if (&getOption(\%opt, \%optPath, \%optPathMust));
2470 system("echo T_S,Plink,P,$Current_time > $optPathMust{dirSave}/PlinkTime.log");
2471
2472 # Set global variables.
2473 $FileLog = $optPathMust{dirSave} . "/pl.log";
2474 system("date/T >" . $FileLog);
2475 system("time/T >>" . $FileLog);
2476 $FileErr = $optPathMust{dirSave} . "/pl.err";
2477 $FileTmp = $optPathMust{dirSave} . "/pl.tmp";
2478 $DirTemp = $optPathMust{dirTemp} . "/pl_temp";
2479 $Cmd_nm = &formatCmd($optPathMust{cmd_nm});
2480 $Cmd_readelf = &formatCmd($optPathMust{cmd_readelf});
2481 $Cmd_strip = &formatCmd($optPathMust{cmd_strip});
2482 $Cmd_armar = &formatCmd($optPath{cmd_armar});
2483 $Cmd_armlink = &formatCmd($optPath{cmd_armlink});
2484
2485 # Show command line.
2486 &utlLog(1, "[@$argv]\n");
2487
2488 &utlLog(1, "Dumping options...\n");
2489 &dumpOpt(\%opt);
2490 &dumpOpt(\%optPath);
2491 &dumpOpt(\%optPathMust);
2492
2493 use constant {
2494 STATE_NONE => 0,
2495 STATE_NORMAL_LINK => 1,
2496 STATE_NORMAL_LINK_STRIP => 2,
2497 STATE_PARTIAL_LINK => 3,
2498 };
2499 my %ini = (
2500 "file" => $optPathMust{dirInfo} . "/pl.ini",
2501 "flag" => 0,
2502 "ptrHahAttr" => {
2503 "state" => STATE_NONE,
2504 "link" => LINK_NONE,
2505 },
2506 "ptrHahValue" => {
2507 "pass_limit" => [ 0, \$opt{passLimit} ],
2508 "link_type" => [ 0, \$opt{linkType}, TYPE_AUTO, TYPE_NORMAL, TYPE_PARTIAL ],
2509 "strip_debug_count" => [ 0, \$opt{stripDebugCount} ],
2510 },
2511 "ptrHahOnOff" => {
2512 "regen_hint" => [ 0, \$opt{reGenHint} ],
2513 "exclude_cpp_lib" => [ 0, \$opt{excludeCppLib} ],
2514 "simulate" => [ 0, \$opt{simulate} ],
2515 "strip_debug_info" => [ 0, \$opt{stripDebugInfo} ],
2516 "check" => [ 0, \$opt{check} ],
2517 "force_partial_link" => [ 0, \$opt{forcePartialLink} ],
2518 "update" => [ 0, \$opt{update} ],
2519 "save" => [ 0, \$opt{save} ],
2520 },
2521 );
2522 my %lib = (
2523 "ptrAryLibDir" => $optPathMust{ptrAryLibDir},
2524 "suffix" => "__PARTIAL_LINK_TEMPORARY",
2525 "suffix_bak" => "__PARTIAL_LINK_SRC_BACKUP",
2526 "suffix_dbg" => "__PARTIAL_LINK_DBG",
2527 "suffix_save" => "__PARTIAL_LINK",
2528 "fileTimestamp" => $optPathMust{dirInfo} . "/pl_timestamp.txt",
2529 "dirLibSize" => $optPathMust{dirInfo} . "/pl_lib_size",
2530 "ptrHahLibNew" => {},
2531 "ptrHahLibUpdate" => {},
2532 "ptrHahLibUsage" => {},
2533 "ptrHahNoDbgLib" => {},
2534 "ptrHahSymTable" => {},
2535 );
2536 my %error = (
2537 "file" => "",
2538 "fileOutput" => $optPath{fileLinkErr},
2539 "ptrHahObjSymErr" => 0,
2540 "ptrHahLibSymErr" => 0,
2541 "ptrHahLibObjRef" => 0,
2542 "ptrHahLibErr" => 0,
2543 );
2544 my $fileCppLib = $optPathMust{dirInfo} . "/pl_cpp.txt";
2545 my $fileDbgLib = $optPathMust{dirInfo} . "/pl_debug.txt";
2546 my $fileLinkOption = $optPathMust{dirSave} . "/pl_link_opt.via";
2547 my $flagNormalLink = 0;
2548 my $flagPartialLink = 0;
2549 my $state = STATE_PARTIAL_LINK;
2550 my $link = LINK_UNKNOWN;
2551 my $ret = 1;
2552
2553 # Register an error handling.
2554 &setupErrorHandling($error{fileOutput});
2555 &sysDieRegister(\&errorHandling);
2556
2557 &utlRmFile($FileErr);
2558 &utlRmFile($FileTmp);
2559 &utlRmTree($DirTemp);
2560
2561 &readIniFile(\%ini);
2562 &syncLib(\%lib);
2563 &checkLib(\%lib);
2564 &generateLibSize(\%lib) if ($opt{libSizeInfo});
2565
2566 &dumpOpt(\%ini);
2567 &dumpOpt(\%lib);
2568
2569 if ( ($opt{check} != 0)
2570 # Libraries are not updated.
2571 && (scalar keys(%{$lib{ptrHahLibNew}}) == 0)
2572 && (scalar keys(%{$lib{ptrHahLibUpdate}}) == 0)
2573 # Libraries were partially linked successfully last time.
2574 && ($ini{ptrHahAttr}->{state} == STATE_PARTIAL_LINK)
2575 && ( ($ini{ptrHahAttr}->{link} == LINK_OK)
2576 || ($ini{ptrHahAttr}->{link} == LINK_OK_STRIP)))
2577 {
2578 &utlLog(0, "Partial link is done last time\n");
2579 return 0;
2580 }
2581
2582 # Decide what to do according to result from last time.
2583 if ( ($opt{forcePartialLink} == 0)
2584 # Stripping debug info is enabled.
2585 && ($opt{stripDebugInfo} != 0)
2586 # Libraries are not updated.
2587 && (scalar keys(%{$lib{ptrHahLibNew}}) == 0)
2588 && (scalar keys(%{$lib{ptrHahLibUpdate}}) == 0)
2589 # Libraries were stripped successfully last time.
2590 && ( ( ($ini{ptrHahAttr}->{state} == STATE_NORMAL_LINK_STRIP)
2591 && ( ($ini{ptrHahAttr}->{link} == LINK_OK)
2592 || ($ini{ptrHahAttr}->{link} == LINK_OUT_OF_MEM)))
2593 || ( ($ini{ptrHahAttr}->{state} == STATE_PARTIAL_LINK)
2594 && ( ($ini{ptrHahAttr}->{link} == LINK_OK_STRIP)
2595 || ($ini{ptrHahAttr}->{link} == LINK_OUT_OF_MEM)))))
2596 {
2597 $state = STATE_NORMAL_LINK_STRIP;
2598 }
2599 elsif ( ($opt{forcePartialLink} != 0)
2600 || ($opt{linkType} == TYPE_PARTIAL))
2601 {
2602 $state = STATE_PARTIAL_LINK;
2603 }
2604 else
2605 {
2606 $state = STATE_NORMAL_LINK;
2607 }
2608
2609 while (1)
2610 {
2611 my $curState = $state;
2612
2613 if ($curState == STATE_NORMAL_LINK)
2614 {
2615 &utlLog(0, "Trying normal link...\n");
2616 $flagNormalLink = 1;
2617 $error{file} = $optPathMust{dirSave} . "/pl_error_normal.log";
2618 $link = &finalLink("", $optPathMust{fileLinkOption}, \%error);
2619 if ($link == LINK_OUT_OF_MEM)
2620 {
2621 if ($opt{linkType} == TYPE_AUTO)
2622 {
2623 $state = STATE_PARTIAL_LINK if ($flagPartialLink == 0);
2624 }
2625 elsif ($opt{linkType} == TYPE_NORMAL)
2626 {
2627 $state = STATE_NORMAL_LINK_STRIP if ($opt{stripDebugInfo});
2628 }
2629 }
2630 }
2631 elsif ($curState == STATE_NORMAL_LINK_STRIP)
2632 {
2633 &utlLog(0, "Trying normal link with debug info stripping...\n");
2634 &generateLinkOptFile(\%lib, 0, $optPathMust{fileLinkOption}, $fileLinkOption);
2635 $error{file} = $optPathMust{dirSave} . "/pl_error_dbg.log";
2636 $link = &normalLinkStrip(\%lib, \%error, $fileCppLib, $fileDbgLib, $fileLinkOption, $opt{stripDebugCount});
2637 }
2638 elsif ($curState == STATE_PARTIAL_LINK)
2639 {
2640 &utlLog(0, "Trying partial link...\n");
2641 $flagPartialLink = 1;
2642 $link = &partialLink(\%opt, \%optPath, \%optPathMust, \%lib, \%error, $fileCppLib, $fileDbgLib, $fileLinkOption);
2643 $state = STATE_NORMAL_LINK if (($opt{forcePartialLink} == 0) && ($flagNormalLink == 0) && ($link != LINK_OK) && ($link != LINK_OK_STRIP) && ($link != LINK_OUT_OF_MEM));
2644 }
2645 if (($link == LINK_OK) || ($link == LINK_OK_STRIP))
2646 {
2647 &utlLog(0, "Succeed to link\n");
2648 &generateLibTimestamp(\%lib) unless ($opt{simulate});
2649 $ret = 0;
2650 }
2651 elsif ($link == LINK_OUT_OF_MEM)
2652 {
2653 &utlLog(0, "Fail to link due to \"Fatal error: L6000U: Out of memory.\"\n");
2654 next if ($state != $curState);
2655 &generateLibTimestamp(\%lib) if (($opt{simulate} == 0) && ($state == STATE_PARTIAL_LINK));
2656 if ($opt{stripDebugInfo})
2657 {
2658 &utlLog(0, "PLEASE EDIT \"pl_debug.txt\" TO REMOVE MORE DEBUG INFO FROM LIBRARIES\n");
2659 }
2660 else
2661 {
2662 &utlLog(0, "PLEASE ENABLE \"--strip-debug-info\" TO REMOVE DEBUG INFO OF LIBRARIES\n");
2663 }
2664 }
2665 else
2666 {
2667 &utlLog(0, "Fail to link\n");
2668 }
2669 last if ($state == $curState);
2670 }
2671 &setIni(\%ini, "state", $state) if ($opt{update});
2672 &setIni(\%ini, "link", $link);
2673 &writeIniFile(\%ini) unless ($opt{simulate});
2674 system("date/T >>" . $FileLog);
2675 system("time/T >>" . $FileLog);
2676 $plink_end = time;
2677 $Current_time = time;
2678 system("echo T_E,Plink,P,$Current_time >> $optPathMust{dirSave}/PlinkTime.log");
2679 if ($ENV{MBIS_BUILD_TIME_TMP} =~ /mbis/)
2680 {
2681 system("echo T_S,Plink,P,$plink_start >> $ENV{MBIS_BUILD_TIME_TMP}");
2682 system("echo T_E,Plink,P,$plink_end >> $ENV{MBIS_BUILD_TIME_TMP}");
2683 }
2684 return $ret;
2685}
2686
2687# -----------------------------------------------------------------------------
2688
2689exit &main($_argc, \@_argv);