From 89d7d392ac3f5aba40af276750a2d8548c5365c7 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 8 Mar 2017 17:08:42 +0100 Subject: [PATCH 1/4] Add precompiled field to library.properties A precompiled library should provide: - a header file defining the functions (like a normal library) - some folders named after {build.mcu} containing the precompiled files It should declare - precompiled=true in its library.properties The precompiled files can be either static (.a) or dynamic (.so). In the latter case, the maintainer should take extra care to ensure that the exported symbol versions are matching the remote board's --- src/arduino.cc/builder/constants/constants.go | 1 + src/arduino.cc/builder/libraries_loader.go | 1 + src/arduino.cc/builder/types/types.go | 1 + 3 files changed, 3 insertions(+) diff --git a/src/arduino.cc/builder/constants/constants.go b/src/arduino.cc/builder/constants/constants.go index cdbdb72b..22df1522 100644 --- a/src/arduino.cc/builder/constants/constants.go +++ b/src/arduino.cc/builder/constants/constants.go @@ -137,6 +137,7 @@ const LIBRARY_LICENSE = "license" const LIBRARY_MAINTAINER = "maintainer" const LIBRARY_NAME = "name" const LIBRARY_PARAGRAPH = "paragraph" +const LIBRARY_PRECOMPILED = "precompiled" const LIBRARY_PROPERTIES = "library.properties" const LIBRARY_SENTENCE = "sentence" const LIBRARY_URL = "url" diff --git a/src/arduino.cc/builder/libraries_loader.go b/src/arduino.cc/builder/libraries_loader.go index 1e4b70e5..5063615e 100644 --- a/src/arduino.cc/builder/libraries_loader.go +++ b/src/arduino.cc/builder/libraries_loader.go @@ -192,6 +192,7 @@ func makeNewLibrary(libraryFolder string, debugLevel int, logger i18n.Logger) (* library.URL = strings.TrimSpace(libProperties[constants.LIBRARY_URL]) library.IsLegacy = false library.DotALinkage = strings.TrimSpace(libProperties[constants.LIBRARY_DOT_A_LINKAGE]) == "true" + library.Precompiled = strings.TrimSpace(libProperties[constants.LIBRARY_PRECOMPILED]) == "true" library.Properties = libProperties return library, nil diff --git a/src/arduino.cc/builder/types/types.go b/src/arduino.cc/builder/types/types.go index eac16891..457fabfb 100644 --- a/src/arduino.cc/builder/types/types.go +++ b/src/arduino.cc/builder/types/types.go @@ -170,6 +170,7 @@ type Library struct { Name string Archs []string DotALinkage bool + Precompiled bool IsLegacy bool Version string Author string From 998741d18e204eb891885c362195fb11b357d063 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 8 Mar 2017 17:12:42 +0100 Subject: [PATCH 2/4] Add RealName filed to struct Library As of now, Library.Name maps to the folder it resides in, not the name declared in library.properties It could be a bug or a feature, anyway since need to we use the real library name, extract it and save in the structure --- src/arduino.cc/builder/libraries_loader.go | 1 + src/arduino.cc/builder/types/types.go | 1 + 2 files changed, 2 insertions(+) diff --git a/src/arduino.cc/builder/libraries_loader.go b/src/arduino.cc/builder/libraries_loader.go index 5063615e..434dce3b 100644 --- a/src/arduino.cc/builder/libraries_loader.go +++ b/src/arduino.cc/builder/libraries_loader.go @@ -184,6 +184,7 @@ func makeNewLibrary(libraryFolder string, debugLevel int, logger i18n.Logger) (* library.License = libProperties[constants.LIBRARY_LICENSE] library.Name = filepath.Base(libraryFolder) + library.RealName = strings.TrimSpace(libProperties[constants.LIBRARY_NAME]) library.Version = strings.TrimSpace(libProperties[constants.LIBRARY_VERSION]) library.Author = strings.TrimSpace(libProperties[constants.LIBRARY_AUTHOR]) library.Maintainer = strings.TrimSpace(libProperties[constants.LIBRARY_MAINTAINER]) diff --git a/src/arduino.cc/builder/types/types.go b/src/arduino.cc/builder/types/types.go index 457fabfb..a58b62c2 100644 --- a/src/arduino.cc/builder/types/types.go +++ b/src/arduino.cc/builder/types/types.go @@ -168,6 +168,7 @@ type Library struct { UtilityFolder string Layout LibraryLayout Name string + RealName string Archs []string DotALinkage bool Precompiled bool From d2ff99cdf9c798ca3b1acffaf88d47f23eca4199 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 8 Mar 2017 17:16:34 +0100 Subject: [PATCH 3/4] Allow precompiled objects to be included in the build Combined with Library.precompiled flag, allows a developer to ship a precompiled library. The linker (ld in our case) needs static libraries to be explicitely included in the build (it doesn't try any heuristic). Luckily, "including" a dynamic library in this way works as well, so we can avoid the "-L" and "-l" dance --- .../builder/phases/libraries_builder.go | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/arduino.cc/builder/phases/libraries_builder.go b/src/arduino.cc/builder/phases/libraries_builder.go index 816c512f..01107409 100644 --- a/src/arduino.cc/builder/phases/libraries_builder.go +++ b/src/arduino.cc/builder/phases/libraries_builder.go @@ -31,6 +31,7 @@ package phases import ( "path/filepath" + "strings" "arduino.cc/builder/builder_utils" "arduino.cc/builder/constants" @@ -40,6 +41,8 @@ import ( "arduino.cc/properties" ) +var PRECOMPILED_LIBRARIES_VALID_EXTENSIONS = map[string]bool{".a": true, ".so": true} + type LibrariesBuilder struct{} func (s *LibrariesBuilder) Run(ctx *types.Context) error { @@ -93,6 +96,24 @@ func compileLibrary(library *types.Library, buildPath string, buildProperties pr } objectFiles := []string{} + + if library.Precompiled { + // search for files with PRECOMPILED_LIBRARIES_VALID_EXTENSIONS + extensions := func(ext string) bool { return PRECOMPILED_LIBRARIES_VALID_EXTENSIONS[ext] } + + filePaths := []string{} + mcu := buildProperties[constants.BUILD_PROPERTIES_BUILD_MCU] + err := utils.FindFilesInFolder(&filePaths, filepath.Join(library.SrcFolder, mcu), extensions, true) + if err != nil { + return nil, i18n.WrapError(err) + } + for _, path := range filePaths { + if strings.Contains(filepath.Base(path), library.RealName) { + objectFiles = append(objectFiles, path) + } + } + } + if library.Layout == types.LIBRARY_RECURSIVE { objectFiles, err = builder_utils.CompileFilesRecursive(objectFiles, library.SrcFolder, libraryBuildPath, buildProperties, includes, verbose, warningsLevel, logger) if err != nil { From 358be9b7cdeade7f85444f27a7cde42c03d47683 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 8 Mar 2017 17:20:58 +0100 Subject: [PATCH 4/4] Add LDFLAGS to library properties and use to link dynamic libs Since ld uses absolute paths in certain conditions, adopt a different strategy for dynamic libraries. "compiler.c.elf.extra_flags" must be defined and used in "recipe.c.combine" (at least) --- src/arduino.cc/builder/constants/constants.go | 2 ++ src/arduino.cc/builder/libraries_loader.go | 1 + .../builder/phases/libraries_builder.go | 33 +++++++++++++++++-- src/arduino.cc/builder/types/types.go | 1 + 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/arduino.cc/builder/constants/constants.go b/src/arduino.cc/builder/constants/constants.go index 22df1522..dcbf7063 100644 --- a/src/arduino.cc/builder/constants/constants.go +++ b/src/arduino.cc/builder/constants/constants.go @@ -48,6 +48,7 @@ const BUILD_PROPERTIES_BUILD_SYSTEM_PATH = "build.system.path" const BUILD_PROPERTIES_BUILD_VARIANT = "build.variant" const BUILD_PROPERTIES_BUILD_VARIANT_PATH = "build.variant.path" const BUILD_PROPERTIES_COMPILER_C_ELF_FLAGS = "compiler.c.elf.flags" +const BUILD_PROPERTIES_COMPILER_C_ELF_EXTRAFLAGS = "compiler.c.elf.extra_flags" const BUILD_PROPERTIES_COMPILER_CPP_FLAGS = "compiler.cpp.flags" const BUILD_PROPERTIES_COMPILER_PATH = "compiler.path" const BUILD_PROPERTIES_COMPILER_WARNING_FLAGS = "compiler.warning_flags" @@ -138,6 +139,7 @@ const LIBRARY_MAINTAINER = "maintainer" const LIBRARY_NAME = "name" const LIBRARY_PARAGRAPH = "paragraph" const LIBRARY_PRECOMPILED = "precompiled" +const LIBRARY_LDFLAGS = "ldflags" const LIBRARY_PROPERTIES = "library.properties" const LIBRARY_SENTENCE = "sentence" const LIBRARY_URL = "url" diff --git a/src/arduino.cc/builder/libraries_loader.go b/src/arduino.cc/builder/libraries_loader.go index 434dce3b..0fd3bfd9 100644 --- a/src/arduino.cc/builder/libraries_loader.go +++ b/src/arduino.cc/builder/libraries_loader.go @@ -194,6 +194,7 @@ func makeNewLibrary(libraryFolder string, debugLevel int, logger i18n.Logger) (* library.IsLegacy = false library.DotALinkage = strings.TrimSpace(libProperties[constants.LIBRARY_DOT_A_LINKAGE]) == "true" library.Precompiled = strings.TrimSpace(libProperties[constants.LIBRARY_PRECOMPILED]) == "true" + library.LDflags = strings.TrimSpace(libProperties[constants.LIBRARY_LDFLAGS]) library.Properties = libProperties return library, nil diff --git a/src/arduino.cc/builder/phases/libraries_builder.go b/src/arduino.cc/builder/phases/libraries_builder.go index 01107409..34c832a3 100644 --- a/src/arduino.cc/builder/phases/libraries_builder.go +++ b/src/arduino.cc/builder/phases/libraries_builder.go @@ -41,7 +41,8 @@ import ( "arduino.cc/properties" ) -var PRECOMPILED_LIBRARIES_VALID_EXTENSIONS = map[string]bool{".a": true, ".so": true} +var PRECOMPILED_LIBRARIES_VALID_EXTENSIONS_STATIC = map[string]bool{".a": true} +var PRECOMPILED_LIBRARIES_VALID_EXTENSIONS_DYNAMIC = map[string]bool{".so": true} type LibrariesBuilder struct{} @@ -67,6 +68,34 @@ func (s *LibrariesBuilder) Run(ctx *types.Context) error { ctx.LibrariesObjectFiles = objectFiles + // Search for precompiled libraries + fixLDFLAGforPrecompiledLibraries(ctx, libraries) + + return nil +} + +func fixLDFLAGforPrecompiledLibraries(ctx *types.Context, libraries []*types.Library) error { + + for _, library := range libraries { + if library.Precompiled { + // add library src path to compiler.c.elf.extra_flags + // use library.Name as lib name and srcPath/{mcpu} as location + mcu := ctx.BuildProperties[constants.BUILD_PROPERTIES_BUILD_MCU] + path := filepath.Join(library.SrcFolder, mcu) + // find all library names in the folder and prepend -l + filePaths := []string{} + libs_cmd := library.LDflags + " " + extensions := func(ext string) bool { return PRECOMPILED_LIBRARIES_VALID_EXTENSIONS_DYNAMIC[ext] } + utils.FindFilesInFolder(&filePaths, path, extensions, true) + for _, lib := range filePaths { + name := strings.TrimSuffix(filepath.Base(lib), filepath.Ext(lib)) + // strip "lib" first occurrence + name = strings.Replace(name, "lib", "", 1) + libs_cmd += "-l" + name + " " + } + ctx.BuildProperties[constants.BUILD_PROPERTIES_COMPILER_C_ELF_EXTRAFLAGS] += "\"-L" + path + "\" " + libs_cmd + } + } return nil } @@ -99,7 +128,7 @@ func compileLibrary(library *types.Library, buildPath string, buildProperties pr if library.Precompiled { // search for files with PRECOMPILED_LIBRARIES_VALID_EXTENSIONS - extensions := func(ext string) bool { return PRECOMPILED_LIBRARIES_VALID_EXTENSIONS[ext] } + extensions := func(ext string) bool { return PRECOMPILED_LIBRARIES_VALID_EXTENSIONS_STATIC[ext] } filePaths := []string{} mcu := buildProperties[constants.BUILD_PROPERTIES_BUILD_MCU] diff --git a/src/arduino.cc/builder/types/types.go b/src/arduino.cc/builder/types/types.go index a58b62c2..e7063450 100644 --- a/src/arduino.cc/builder/types/types.go +++ b/src/arduino.cc/builder/types/types.go @@ -172,6 +172,7 @@ type Library struct { Archs []string DotALinkage bool Precompiled bool + LDflags string IsLegacy bool Version string Author string