This is an automated email from the ASF dual-hosted git repository. janc pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-newt.git
The following commit(s) were added to refs/heads/master by this push: new a798fcc6 Add pkg.whole_archive flag to allow --whole_archive linker option to be set per package a798fcc6 is described below commit a798fcc687dd81857de7bb92e77711c9a74f0692 Author: Jocelyn Masserot <jocelynm...@yahoo.fr> AuthorDate: Wed Apr 10 15:04:51 2024 +0200 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. --- newt/builder/build.go | 21 ++++++++++++------ newt/builder/buildpackage.go | 10 +++++++++ newt/toolchain/compiler.go | 51 ++++++++++++++++++++++++++++++++------------ newt/toolchain/deps.go | 8 +++++-- util/util.go | 28 ++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 23 deletions(-) diff --git a/newt/builder/build.go b/newt/builder/build.go index d2fc0c9e..b611df3a 100644 --- a/newt/builder/build.go +++ b/newt/builder/build.go @@ -449,8 +449,9 @@ func (b *Builder) link(elfName string, linkerScripts []string, // Calculate the list of directories containing source .a files. var dirs []string + staticLibs := []util.StaticLib{} + for _, bpkg := range b.sortedBuildPackages() { - dirs = append(dirs, b.PkgBinDir(bpkg)) // Collect lflags from all constituent packages. Discard everything // from the compiler info except lflags; that is all that is relevant @@ -459,18 +460,23 @@ func (b *Builder) link(elfName string, linkerScripts []string, if err != nil { return err } + c.AddInfo(&toolchain.CompilerInfo{Lflags: ci.Lflags}) + fullANames, _ := filepath.Glob(b.PkgBinDir(bpkg) + "/*.a") + for _, archiveName := range fullANames { + s := util.NewStaticLib(archiveName, ci.WholeArch) + staticLibs = append(staticLibs, s) + } } dirs = append(dirs, extraADirs...) // Find all .a files in the input directories. - trimmedANames := []string{} - for _, dir := range dirs { + for _, dir := range extraADirs { fullANames, _ := filepath.Glob(dir + "/*.a") - for i, archiveName := range fullANames { - fullANames[i] = filepath.ToSlash(archiveName) + for _, archiveName := range fullANames { + s := util.NewStaticLib(archiveName, false) + staticLibs = append(staticLibs, s) } - trimmedANames = append(trimmedANames, fullANames...) } c.LinkerScripts = linkerScripts @@ -479,7 +485,8 @@ func (b *Builder) link(elfName string, linkerScripts []string, return err } - err = c.CompileElf(elfName, trimmedANames, keepSymbols, b.linkElf) + err = c.CompileElf(elfName, staticLibs, keepSymbols, b.linkElf) + if err != nil { return err } diff --git a/newt/builder/buildpackage.go b/newt/builder/buildpackage.go index b5a9135b..7bcd835d 100644 --- a/newt/builder/buildpackage.go +++ b/newt/builder/buildpackage.go @@ -166,6 +166,16 @@ func (bpkg *BuildPackage) CompilerInfo( util.OneTimeWarningError(err) expandFlags(ci.Aflags) + var strArray []string + // // Check if the package should be linked as whole or not + strArray, err = bpkg.rpkg.Lpkg.PkgY.GetValStringSlice("pkg.whole_archive", settings) + util.OneTimeWarningError(err) + for _, str := range strArray { + if strings.Contains(str, "true") { + ci.WholeArch = true + } + } + // Package-specific injected settings get specified as C flags on the // command line. for _, k := range bpkg.rpkg.Lpkg.InjectedSettings().Names() { diff --git a/newt/toolchain/compiler.go b/newt/toolchain/compiler.go index 82ee88c1..f84e16ed 100644 --- a/newt/toolchain/compiler.go +++ b/newt/toolchain/compiler.go @@ -61,6 +61,7 @@ type CompilerInfo struct { Aflags []string IgnoreFiles []*regexp.Regexp IgnoreDirs []*regexp.Regexp + WholeArch bool } type CompileCommand struct { @@ -170,6 +171,7 @@ func NewCompilerInfo() *CompilerInfo { ci.Aflags = []string{} ci.IgnoreFiles = []*regexp.Regexp{} ci.IgnoreDirs = []*regexp.Regexp{} + ci.WholeArch = false return ci } @@ -992,6 +994,15 @@ func (c *Compiler) getObjFiles(baseObjFiles []string) []string { return baseObjFiles } +func (c *Compiler) getStaticLibs(baseStaticLib []util.StaticLib) []util.StaticLib { + c.mutex.Lock() + for objName, _ := range c.objPathList { + baseStaticLib = append(baseStaticLib, util.NewStaticLib(objName, false)) + } + c.mutex.Unlock() + return baseStaticLib +} + // Calculates the command-line invocation necessary to link the specified elf // file. // @@ -1003,9 +1014,9 @@ func (c *Compiler) getObjFiles(baseObjFiles []string) []string { // // @return (success) The command tokens. func (c *Compiler) CompileBinaryCmd(dstFile string, options map[string]bool, - objFiles []string, keepSymbols []string, elfLib string) []string { + staticLib []util.StaticLib, keepSymbols []string, elfLib string) []string { - objList := c.getObjFiles(util.UniqueStrings(objFiles)) + libList := c.getStaticLibs(util.UniqueStaticLib(staticLib)) cmd := []string{ c.ccPath, @@ -1020,10 +1031,19 @@ func (c *Compiler) CompileBinaryCmd(dstFile string, options map[string]bool, if c.ldResolveCircularDeps { cmd = append(cmd, "-Wl,--start-group") - cmd = append(cmd, objList...) + } + + for _, lib := range libList { + if lib.WholeArch { + cmd = append(cmd, "-Wl,--whole-archive") + } + cmd = append(cmd, lib.File) + if lib.WholeArch { + cmd = append(cmd, "-Wl,--no-whole-archive") + } + } + if c.ldResolveCircularDeps { cmd = append(cmd, "-Wl,--end-group") - } else { - cmd = append(cmd, objList...) } if keepSymbols != nil { @@ -1059,23 +1079,25 @@ func (c *Compiler) CompileBinaryCmd(dstFile string, options map[string]bool, // gets generated. // @param objFiles An array of the source .o and .a filenames. func (c *Compiler) CompileBinary(dstFile string, options map[string]bool, - objFiles []string, keepSymbols []string, elfLib string) error { + staticLib []util.StaticLib, keepSymbols []string, elfLib string) error { // Make sure the compiler package info is added to the global set. c.ensureLclInfoAdded() - objList := c.getObjFiles(util.UniqueStrings(objFiles)) - util.StatusMessage(util.VERBOSITY_DEFAULT, "Linking %s\n", dstFile) - util.StatusMessage(util.VERBOSITY_VERBOSE, "Linking %s with input files %s\n", - dstFile, objList) + + libList := c.getStaticLibs(util.UniqueStaticLib(staticLib)) + + for _, lib := range libList { + util.StatusMessage(util.VERBOSITY_VERBOSE, "Linking %s with input files %s\n", dstFile, lib.File) + } if elfLib != "" { util.StatusMessage(util.VERBOSITY_VERBOSE, "Linking %s with rom image %s\n", dstFile, elfLib) } - cmd := c.CompileBinaryCmd(dstFile, options, objFiles, keepSymbols, elfLib) + cmd := c.CompileBinaryCmd(dstFile, options, libList, keepSymbols, elfLib) o, err := util.ShellCommand(cmd, nil) if err != nil { return err @@ -1204,7 +1226,7 @@ func (c *Compiler) PrintSize(elfFilename string) (string, error) { // @param options Some build options specifying how the elf file // gets generated. // @param objFiles An array of the source .o and .a filenames. -func (c *Compiler) CompileElf(binFile string, objFiles []string, +func (c *Compiler) CompileElf(binFile string, staticLib []util.StaticLib, keepSymbols []string, elfLib string) error { options := map[string]bool{"mapFile": c.ldMapFile, "listFile": true, "binFile": c.ldBinFile} @@ -1213,7 +1235,8 @@ func (c *Compiler) CompileElf(binFile string, objFiles []string, c.ensureLclInfoAdded() linkRequired, err := c.depTracker.LinkRequired(binFile, options, - objFiles, keepSymbols, elfLib) + staticLib, keepSymbols, elfLib) + if err != nil { return err } @@ -1221,7 +1244,7 @@ func (c *Compiler) CompileElf(binFile string, objFiles []string, if err := os.MkdirAll(filepath.Dir(binFile), 0755); err != nil { return util.NewNewtError(err.Error()) } - err := c.CompileBinary(binFile, options, objFiles, keepSymbols, elfLib) + err := c.CompileBinary(binFile, options, staticLib, keepSymbols, elfLib) if err != nil { return err } diff --git a/newt/toolchain/deps.go b/newt/toolchain/deps.go index ee6bc623..fa526f7a 100644 --- a/newt/toolchain/deps.go +++ b/newt/toolchain/deps.go @@ -328,12 +328,12 @@ func (tracker *DepTracker) ArchiveRequired(archiveFile string, // * One or more source object files has a newer modification time than the // library file. func (tracker *DepTracker) LinkRequired(dstFile string, - options map[string]bool, objFiles []string, + options map[string]bool, staticLib []util.StaticLib, keepSymbols []string, elfLib string) (bool, error) { // If the elf file was previously built with a different set of options, a // rebuild is required. - cmd := tracker.compiler.CompileBinaryCmd(dstFile, options, objFiles, keepSymbols, elfLib) + cmd := tracker.compiler.CompileBinaryCmd(dstFile, options, staticLib, keepSymbols, elfLib) if commandHasChanged(dstFile, cmd) { logRebuildReqdCmdChanged(dstFile) return true, nil @@ -365,7 +365,11 @@ func (tracker *DepTracker) LinkRequired(dstFile string, return true, nil } + var objFiles []string // Check timestamp of the linker script and all input libraries. + for _, obj := range staticLib { + objFiles = append(objFiles, obj.File) + } for _, ls := range tracker.compiler.LinkerScripts { objFiles = append(objFiles, ls) } diff --git a/util/util.go b/util/util.go index 41632bcc..5823762a 100644 --- a/util/util.go +++ b/util/util.go @@ -70,6 +70,19 @@ const ( VERBOSITY_VERBOSE = 3 ) +type StaticLib struct { + File string + WholeArch bool +} + +func NewStaticLib(file string, wholeArch bool) StaticLib { + s := StaticLib{ + File: file, + WholeArch: wholeArch, + } + return s +} + func (se *NewtError) Error() string { return se.Text } @@ -668,6 +681,21 @@ func UniqueStrings(elems []string) []string { return result } +// Removes all duplicate static lib from the specified array, while preserving +// order. +func UniqueStaticLib(libs []StaticLib) []StaticLib { + set := make(map[StaticLib]bool) + result := make([]StaticLib, 0) + + for _, lib := range libs { + if !set[lib] { + result = append(result, lib) + set[lib] = true + } + } + return result +} + // Sorts whitespace-delimited lists of strings. // // @param wsSepStrings A list of strings; each string contains one or