Skip to content

Commit bb42ebe

Browse files
authored
builder: use ar-chives for linking big sketches (was: use the @ syntax to reduce command line length if needed) (#961)
* Small cosmetic changes * Create an archive file if the number of object files is too big This should fix the command line too big issue on Windows. * fixed comments * When exploiting ar-chives make a .a file for each soruce subfolder This is required because gcc-ar checks if an object file is already in the archive by looking ONLY at the filename WITHOUT the path, so it may happens that, for example, an object file named "subdir/spi.o", already inside the archive, may be overwritten by an object file in "anotherdir/spi.o" only because they are both named spi.o and even if they are compiled on different directories. * using paths.PathList to keep objectFileList
1 parent 27381c5 commit bb42ebe

File tree

3 files changed

+35
-6
lines changed

3 files changed

+35
-6
lines changed

Diff for: legacy/builder/constants/constants.go

-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ const BUILD_PROPERTIES_COMPILER_WARNING_FLAGS = "compiler.warning_flags"
3131
const BUILD_PROPERTIES_FQBN = "build.fqbn"
3232
const BUILD_PROPERTIES_INCLUDES = "includes"
3333
const BUILD_PROPERTIES_OBJECT_FILE = "object_file"
34-
const BUILD_PROPERTIES_OBJECT_FILES = "object_files"
3534
const BUILD_PROPERTIES_PATTERN = "pattern"
3635
const BUILD_PROPERTIES_PID = "pid"
3736
const BUILD_PROPERTIES_PREPROCESSED_FILE_PATH = "preprocessed_file_path"

Diff for: legacy/builder/phases/libraries_builder.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func compileLibraries(ctx *types.Context, libraries libraries.List, buildPath *p
112112
if err != nil {
113113
return nil, errors.WithStack(err)
114114
}
115-
objectFiles = append(objectFiles, libraryObjectFiles...)
115+
objectFiles.AddAll(libraryObjectFiles)
116116

117117
ctx.Progress.CompleteStep()
118118
builder_utils.PrintProgressIfProgressEnabledAndMachineLogger(ctx)

Diff for: legacy/builder/phases/linker.go

+34-4
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,47 @@ func (s *Linker) Run(ctx *types.Context) error {
5757
}
5858

5959
func link(ctx *types.Context, objectFiles paths.PathList, coreDotARelPath *paths.Path, coreArchiveFilePath *paths.Path, buildProperties *properties.Map) error {
60-
quotedObjectFiles := utils.Map(objectFiles.AsStrings(), wrapWithDoubleQuotes)
61-
objectFileList := strings.Join(quotedObjectFiles, constants.SPACE)
60+
objectFileList := strings.Join(utils.Map(objectFiles.AsStrings(), wrapWithDoubleQuotes), " ")
61+
62+
// If command line length is too big (> 30000 chars), try to collect the object files into archives
63+
// and use that archives to complete the build.
64+
if len(objectFileList) > 30000 {
65+
66+
// We must create an object file for each visited directory: this is required becuase gcc-ar checks
67+
// if an object file is already in the archive by looking ONLY at the filename WITHOUT the path, so
68+
// it may happen that a subdir/spi.o inside the archive may be overwritten by a anotherdir/spi.o
69+
// because thery are both named spi.o.
70+
71+
properties := buildProperties.Clone()
72+
archives := paths.NewPathList()
73+
for _, object := range objectFiles {
74+
archive := object.Parent().Join("objs.a")
75+
if !archives.Contains(archive) {
76+
archives.Add(archive)
77+
// Cleanup old archives
78+
_ = archive.Remove()
79+
}
80+
properties.Set("archive_file", archive.Base())
81+
properties.SetPath("archive_file_path", archive)
82+
properties.SetPath("object_file", object)
83+
_, _, err := builder_utils.ExecRecipe(ctx, properties, constants.RECIPE_AR_PATTERN, false, utils.ShowIfVerbose /* stdout */, utils.Show /* stderr */)
84+
if err != nil {
85+
return err
86+
}
87+
}
88+
89+
objectFileList = strings.Join(utils.Map(archives.AsStrings(), wrapWithDoubleQuotes), " ")
90+
objectFileList = "-Wl,--whole-archive " + objectFileList + " -Wl,--no-whole-archive"
91+
}
6292

6393
properties := buildProperties.Clone()
6494
properties.Set(constants.BUILD_PROPERTIES_COMPILER_C_ELF_FLAGS, properties.Get(constants.BUILD_PROPERTIES_COMPILER_C_ELF_FLAGS))
6595
properties.Set(constants.BUILD_PROPERTIES_COMPILER_WARNING_FLAGS, properties.Get(constants.BUILD_PROPERTIES_COMPILER_WARNING_FLAGS+"."+ctx.WarningsLevel))
6696
properties.Set(constants.BUILD_PROPERTIES_ARCHIVE_FILE, coreDotARelPath.String())
6797
properties.Set(constants.BUILD_PROPERTIES_ARCHIVE_FILE_PATH, coreArchiveFilePath.String())
68-
properties.Set(constants.BUILD_PROPERTIES_OBJECT_FILES, objectFileList)
98+
properties.Set("object_files", objectFileList)
6999

70-
_, _, err := builder_utils.ExecRecipe(ctx, properties, constants.RECIPE_C_COMBINE_PATTERN, false /* stdout */, utils.ShowIfVerbose /* stderr */, utils.Show)
100+
_, _, err := builder_utils.ExecRecipe(ctx, properties, constants.RECIPE_C_COMBINE_PATTERN, false, utils.ShowIfVerbose /* stdout */, utils.Show /* stderr */)
71101
return err
72102
}
73103

0 commit comments

Comments
 (0)