Skip to content

Commit a798fcc

Browse files
authored
Add pkg.whole_archive flag to allow --whole_archive linker option to be set per package
Depending on the project, it might be useful to have the ability to link a package surrounded by "--whole-archive" and "--no-whole-archive" flags.
1 parent 63ba0c2 commit a798fcc

File tree

5 files changed

+95
-23
lines changed

5 files changed

+95
-23
lines changed

newt/builder/build.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -449,8 +449,9 @@ func (b *Builder) link(elfName string, linkerScripts []string,
449449

450450
// Calculate the list of directories containing source .a files.
451451
var dirs []string
452+
staticLibs := []util.StaticLib{}
453+
452454
for _, bpkg := range b.sortedBuildPackages() {
453-
dirs = append(dirs, b.PkgBinDir(bpkg))
454455

455456
// Collect lflags from all constituent packages. Discard everything
456457
// from the compiler info except lflags; that is all that is relevant
@@ -459,18 +460,23 @@ func (b *Builder) link(elfName string, linkerScripts []string,
459460
if err != nil {
460461
return err
461462
}
463+
462464
c.AddInfo(&toolchain.CompilerInfo{Lflags: ci.Lflags})
465+
fullANames, _ := filepath.Glob(b.PkgBinDir(bpkg) + "/*.a")
466+
for _, archiveName := range fullANames {
467+
s := util.NewStaticLib(archiveName, ci.WholeArch)
468+
staticLibs = append(staticLibs, s)
469+
}
463470
}
464471
dirs = append(dirs, extraADirs...)
465472

466473
// Find all .a files in the input directories.
467-
trimmedANames := []string{}
468-
for _, dir := range dirs {
474+
for _, dir := range extraADirs {
469475
fullANames, _ := filepath.Glob(dir + "/*.a")
470-
for i, archiveName := range fullANames {
471-
fullANames[i] = filepath.ToSlash(archiveName)
476+
for _, archiveName := range fullANames {
477+
s := util.NewStaticLib(archiveName, false)
478+
staticLibs = append(staticLibs, s)
472479
}
473-
trimmedANames = append(trimmedANames, fullANames...)
474480
}
475481

476482
c.LinkerScripts = linkerScripts
@@ -479,7 +485,8 @@ func (b *Builder) link(elfName string, linkerScripts []string,
479485
return err
480486
}
481487

482-
err = c.CompileElf(elfName, trimmedANames, keepSymbols, b.linkElf)
488+
err = c.CompileElf(elfName, staticLibs, keepSymbols, b.linkElf)
489+
483490
if err != nil {
484491
return err
485492
}

newt/builder/buildpackage.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,16 @@ func (bpkg *BuildPackage) CompilerInfo(
166166
util.OneTimeWarningError(err)
167167
expandFlags(ci.Aflags)
168168

169+
var strArray []string
170+
// // Check if the package should be linked as whole or not
171+
strArray, err = bpkg.rpkg.Lpkg.PkgY.GetValStringSlice("pkg.whole_archive", settings)
172+
util.OneTimeWarningError(err)
173+
for _, str := range strArray {
174+
if strings.Contains(str, "true") {
175+
ci.WholeArch = true
176+
}
177+
}
178+
169179
// Package-specific injected settings get specified as C flags on the
170180
// command line.
171181
for _, k := range bpkg.rpkg.Lpkg.InjectedSettings().Names() {

newt/toolchain/compiler.go

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ type CompilerInfo struct {
6161
Aflags []string
6262
IgnoreFiles []*regexp.Regexp
6363
IgnoreDirs []*regexp.Regexp
64+
WholeArch bool
6465
}
6566

6667
type CompileCommand struct {
@@ -170,6 +171,7 @@ func NewCompilerInfo() *CompilerInfo {
170171
ci.Aflags = []string{}
171172
ci.IgnoreFiles = []*regexp.Regexp{}
172173
ci.IgnoreDirs = []*regexp.Regexp{}
174+
ci.WholeArch = false
173175

174176
return ci
175177
}
@@ -992,6 +994,15 @@ func (c *Compiler) getObjFiles(baseObjFiles []string) []string {
992994
return baseObjFiles
993995
}
994996

997+
func (c *Compiler) getStaticLibs(baseStaticLib []util.StaticLib) []util.StaticLib {
998+
c.mutex.Lock()
999+
for objName, _ := range c.objPathList {
1000+
baseStaticLib = append(baseStaticLib, util.NewStaticLib(objName, false))
1001+
}
1002+
c.mutex.Unlock()
1003+
return baseStaticLib
1004+
}
1005+
9951006
// Calculates the command-line invocation necessary to link the specified elf
9961007
// file.
9971008
//
@@ -1003,9 +1014,9 @@ func (c *Compiler) getObjFiles(baseObjFiles []string) []string {
10031014
//
10041015
// @return (success) The command tokens.
10051016
func (c *Compiler) CompileBinaryCmd(dstFile string, options map[string]bool,
1006-
objFiles []string, keepSymbols []string, elfLib string) []string {
1017+
staticLib []util.StaticLib, keepSymbols []string, elfLib string) []string {
10071018

1008-
objList := c.getObjFiles(util.UniqueStrings(objFiles))
1019+
libList := c.getStaticLibs(util.UniqueStaticLib(staticLib))
10091020

10101021
cmd := []string{
10111022
c.ccPath,
@@ -1020,10 +1031,19 @@ func (c *Compiler) CompileBinaryCmd(dstFile string, options map[string]bool,
10201031

10211032
if c.ldResolveCircularDeps {
10221033
cmd = append(cmd, "-Wl,--start-group")
1023-
cmd = append(cmd, objList...)
1034+
}
1035+
1036+
for _, lib := range libList {
1037+
if lib.WholeArch {
1038+
cmd = append(cmd, "-Wl,--whole-archive")
1039+
}
1040+
cmd = append(cmd, lib.File)
1041+
if lib.WholeArch {
1042+
cmd = append(cmd, "-Wl,--no-whole-archive")
1043+
}
1044+
}
1045+
if c.ldResolveCircularDeps {
10241046
cmd = append(cmd, "-Wl,--end-group")
1025-
} else {
1026-
cmd = append(cmd, objList...)
10271047
}
10281048

10291049
if keepSymbols != nil {
@@ -1059,23 +1079,25 @@ func (c *Compiler) CompileBinaryCmd(dstFile string, options map[string]bool,
10591079
// gets generated.
10601080
// @param objFiles An array of the source .o and .a filenames.
10611081
func (c *Compiler) CompileBinary(dstFile string, options map[string]bool,
1062-
objFiles []string, keepSymbols []string, elfLib string) error {
1082+
staticLib []util.StaticLib, keepSymbols []string, elfLib string) error {
10631083

10641084
// Make sure the compiler package info is added to the global set.
10651085
c.ensureLclInfoAdded()
10661086

1067-
objList := c.getObjFiles(util.UniqueStrings(objFiles))
1068-
10691087
util.StatusMessage(util.VERBOSITY_DEFAULT, "Linking %s\n", dstFile)
1070-
util.StatusMessage(util.VERBOSITY_VERBOSE, "Linking %s with input files %s\n",
1071-
dstFile, objList)
1088+
1089+
libList := c.getStaticLibs(util.UniqueStaticLib(staticLib))
1090+
1091+
for _, lib := range libList {
1092+
util.StatusMessage(util.VERBOSITY_VERBOSE, "Linking %s with input files %s\n", dstFile, lib.File)
1093+
}
10721094

10731095
if elfLib != "" {
10741096
util.StatusMessage(util.VERBOSITY_VERBOSE, "Linking %s with rom image %s\n",
10751097
dstFile, elfLib)
10761098
}
10771099

1078-
cmd := c.CompileBinaryCmd(dstFile, options, objFiles, keepSymbols, elfLib)
1100+
cmd := c.CompileBinaryCmd(dstFile, options, libList, keepSymbols, elfLib)
10791101
o, err := util.ShellCommand(cmd, nil)
10801102
if err != nil {
10811103
return err
@@ -1204,7 +1226,7 @@ func (c *Compiler) PrintSize(elfFilename string) (string, error) {
12041226
// @param options Some build options specifying how the elf file
12051227
// gets generated.
12061228
// @param objFiles An array of the source .o and .a filenames.
1207-
func (c *Compiler) CompileElf(binFile string, objFiles []string,
1229+
func (c *Compiler) CompileElf(binFile string, staticLib []util.StaticLib,
12081230
keepSymbols []string, elfLib string) error {
12091231
options := map[string]bool{"mapFile": c.ldMapFile,
12101232
"listFile": true, "binFile": c.ldBinFile}
@@ -1213,15 +1235,16 @@ func (c *Compiler) CompileElf(binFile string, objFiles []string,
12131235
c.ensureLclInfoAdded()
12141236

12151237
linkRequired, err := c.depTracker.LinkRequired(binFile, options,
1216-
objFiles, keepSymbols, elfLib)
1238+
staticLib, keepSymbols, elfLib)
1239+
12171240
if err != nil {
12181241
return err
12191242
}
12201243
if linkRequired {
12211244
if err := os.MkdirAll(filepath.Dir(binFile), 0755); err != nil {
12221245
return util.NewNewtError(err.Error())
12231246
}
1224-
err := c.CompileBinary(binFile, options, objFiles, keepSymbols, elfLib)
1247+
err := c.CompileBinary(binFile, options, staticLib, keepSymbols, elfLib)
12251248
if err != nil {
12261249
return err
12271250
}

newt/toolchain/deps.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,12 +328,12 @@ func (tracker *DepTracker) ArchiveRequired(archiveFile string,
328328
// * One or more source object files has a newer modification time than the
329329
// library file.
330330
func (tracker *DepTracker) LinkRequired(dstFile string,
331-
options map[string]bool, objFiles []string,
331+
options map[string]bool, staticLib []util.StaticLib,
332332
keepSymbols []string, elfLib string) (bool, error) {
333333

334334
// If the elf file was previously built with a different set of options, a
335335
// rebuild is required.
336-
cmd := tracker.compiler.CompileBinaryCmd(dstFile, options, objFiles, keepSymbols, elfLib)
336+
cmd := tracker.compiler.CompileBinaryCmd(dstFile, options, staticLib, keepSymbols, elfLib)
337337
if commandHasChanged(dstFile, cmd) {
338338
logRebuildReqdCmdChanged(dstFile)
339339
return true, nil
@@ -365,7 +365,11 @@ func (tracker *DepTracker) LinkRequired(dstFile string,
365365
return true, nil
366366
}
367367

368+
var objFiles []string
368369
// Check timestamp of the linker script and all input libraries.
370+
for _, obj := range staticLib {
371+
objFiles = append(objFiles, obj.File)
372+
}
369373
for _, ls := range tracker.compiler.LinkerScripts {
370374
objFiles = append(objFiles, ls)
371375
}

util/util.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,19 @@ const (
7070
VERBOSITY_VERBOSE = 3
7171
)
7272

73+
type StaticLib struct {
74+
File string
75+
WholeArch bool
76+
}
77+
78+
func NewStaticLib(file string, wholeArch bool) StaticLib {
79+
s := StaticLib{
80+
File: file,
81+
WholeArch: wholeArch,
82+
}
83+
return s
84+
}
85+
7386
func (se *NewtError) Error() string {
7487
return se.Text
7588
}
@@ -668,6 +681,21 @@ func UniqueStrings(elems []string) []string {
668681
return result
669682
}
670683

684+
// Removes all duplicate static lib from the specified array, while preserving
685+
// order.
686+
func UniqueStaticLib(libs []StaticLib) []StaticLib {
687+
set := make(map[StaticLib]bool)
688+
result := make([]StaticLib, 0)
689+
690+
for _, lib := range libs {
691+
if !set[lib] {
692+
result = append(result, lib)
693+
set[lib] = true
694+
}
695+
}
696+
return result
697+
}
698+
671699
// Sorts whitespace-delimited lists of strings.
672700
//
673701
// @param wsSepStrings A list of strings; each string contains one or

0 commit comments

Comments
 (0)