diff --git a/README.md b/README.md index 61471f14..457fd27d 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This tool generates function prototypes and gathers library paths, providing `gc ### Usage -* `-compile` or `-dump-prefs`: Optional. If omitted, defaults to `-compile`. `-dump-prefs` will just print all build preferences used, `-compile` will use those preferences to run the actual compiler. +* `-compile` or `-dump-prefs` or `-preprocess`: Optional. If omitted, defaults to `-compile`. `-dump-prefs` will just print all build preferences used, `-compile` will use those preferences to run the actual compiler, `-preprocess` will only print preprocessed code to stdout. * `-hardware`: Mandatory. Folder containing Arduino platforms. An example is the `hardware` folder shipped with the Arduino IDE, or the `packages` folder created by Arduino Boards Manager. Can be specified multiple times. If conflicting hardware definitions are specified, the last one wins. @@ -27,14 +27,14 @@ This tool generates function prototypes and gathers library paths, providing `gc * `-verbose`: Optional, turns on verbose mode. +* `-quiet`: Optional, supresses almost every output. + * `-debug-level`: Optional, defaults to "5". Used for debugging. Set it to 10 when submitting an issue. * `-ide-version`: Optional, defaults to "10600". The version of the Arduino IDE which is using this tool. * `-logger`: Optional, can be "human" or "machine". Defaults to "human". If "machine", messages emitted will be in a format which the Arduino IDE understands and that it uses for I18N. -* `-lib-discovery-recursion-depth`: Optional. Defaults to 4. How deep should library discovery go down looking for included libraries. - * `-version`: if specified, prints version and exits. * `-build-options-file`: it specifies path to a local `build.options.json` file (see paragraph below), which allows you to omit specifying params such as `-hardware`, `-tools`, `-libraries`, `-fqbn`, `-pref` and `-ide-version`. diff --git a/main.go b/main.go index 4387a941..cdba4273 100644 --- a/main.go +++ b/main.go @@ -47,10 +47,11 @@ import ( "syscall" ) -const VERSION = "1.0.5" +const VERSION = "1.3.8" -const FLAG_COMPILE = "compile" -const FLAG_DUMP_PREFS = "dump-prefs" +const FLAG_ACTION_COMPILE = "compile" +const FLAG_ACTION_PREPROCESS = "preprocess" +const FLAG_ACTION_DUMP_PREFS = "dump-prefs" const FLAG_BUILD_OPTIONS_FILE = "build-options-file" const FLAG_HARDWARE = "hardware" const FLAG_TOOLS = "tools" @@ -61,6 +62,7 @@ const FLAG_FQBN = "fqbn" const FLAG_IDE_VERSION = "ide-version" const FLAG_BUILD_PATH = "build-path" const FLAG_VERBOSE = "verbose" +const FLAG_QUIET = "quiet" const FLAG_DEBUG_LEVEL = "debug-level" const FLAG_WARNINGS = "warnings" const FLAG_WARNINGS_NONE = "none" @@ -70,7 +72,6 @@ const FLAG_WARNINGS_ALL = "all" const FLAG_LOGGER = "logger" const FLAG_LOGGER_HUMAN = "human" const FLAG_LOGGER_MACHINE = "machine" -const FLAG_LIB_DISCOVERY_RECURSION_PATH = "lib-discovery-recursion-depth" const FLAG_VERSION = "version" const FLAG_VID_PID = "vid-pid" @@ -97,6 +98,7 @@ func (h *slice) Set(csv string) error { } var compileFlag *bool +var preprocessFlag *bool var dumpPrefsFlag *bool var buildOptionsFileFlag *string var hardwareFoldersFlag slice @@ -108,16 +110,17 @@ var fqbnFlag *string var ideVersionFlag *string var buildPathFlag *string var verboseFlag *bool +var quietFlag *bool var debugLevelFlag *int -var libraryDiscoveryRecursionDepthFlag *int var warningsLevelFlag *string var loggerFlag *string var versionFlag *bool var vidPidFlag *string func init() { - compileFlag = flag.Bool(FLAG_COMPILE, false, "compiles the given sketch") - dumpPrefsFlag = flag.Bool(FLAG_DUMP_PREFS, false, "dumps build properties used when compiling") + compileFlag = flag.Bool(FLAG_ACTION_COMPILE, false, "compiles the given sketch") + preprocessFlag = flag.Bool(FLAG_ACTION_PREPROCESS, false, "preprocess the given sketch") + dumpPrefsFlag = flag.Bool(FLAG_ACTION_DUMP_PREFS, false, "dumps build properties used when compiling") buildOptionsFileFlag = flag.String(FLAG_BUILD_OPTIONS_FILE, "", "Instead of specifying --"+FLAG_HARDWARE+", --"+FLAG_TOOLS+" etc every time, you can load all such options from a file") flag.Var(&hardwareFoldersFlag, FLAG_HARDWARE, "Specify a 'hardware' folder. Can be added multiple times for specifying multiple 'hardware' folders") flag.Var(&toolsFoldersFlag, FLAG_TOOLS, "Specify a 'tools' folder. Can be added multiple times for specifying multiple 'tools' folders") @@ -128,10 +131,10 @@ func init() { ideVersionFlag = flag.String(FLAG_IDE_VERSION, "10600", "fake IDE version") buildPathFlag = flag.String(FLAG_BUILD_PATH, "", "build path") verboseFlag = flag.Bool(FLAG_VERBOSE, false, "if 'true' prints lots of stuff") + quietFlag = flag.Bool(FLAG_QUIET, false, "if 'true' doesn't print any warnings or progress or whatever") debugLevelFlag = flag.Int(FLAG_DEBUG_LEVEL, builder.DEFAULT_DEBUG_LEVEL, "Turns on debugging messages. The higher, the chattier") warningsLevelFlag = flag.String(FLAG_WARNINGS, "", "Sets warnings level. Available values are '"+FLAG_WARNINGS_NONE+"', '"+FLAG_WARNINGS_DEFAULT+"', '"+FLAG_WARNINGS_MORE+"' and '"+FLAG_WARNINGS_ALL+"'") loggerFlag = flag.String(FLAG_LOGGER, FLAG_LOGGER_HUMAN, "Sets type of logger. Available values are '"+FLAG_LOGGER_HUMAN+"', '"+FLAG_LOGGER_MACHINE+"'") - libraryDiscoveryRecursionDepthFlag = flag.Int(FLAG_LIB_DISCOVERY_RECURSION_PATH, builder.DEFAULT_LIBRARY_DISCOVERY_RECURSION_DEPTH, "How deep should library discovery go down looking for included libraries") versionFlag = flag.Bool(FLAG_VERSION, false, "prints version and exits") vidPidFlag = flag.String(FLAG_VID_PID, "", "specify to use vid/pid specific build properties, as defined in boards.txt") } @@ -149,19 +152,6 @@ func main() { return } - compile := *compileFlag - dumpPrefs := *dumpPrefsFlag - - if compile && dumpPrefs { - fmt.Fprintln(os.Stderr, "You can either specify --"+FLAG_COMPILE+" or --"+FLAG_DUMP_PREFS+", not both") - defer os.Exit(1) - return - } - - if !compile && !dumpPrefs { - compile = true - } - context := make(map[string]interface{}) buildOptions := make(map[string]string) @@ -252,7 +242,7 @@ func main() { return } - err = os.MkdirAll(buildPath, os.FileMode(0755)) + err = utils.EnsureFolderExists(buildPath) if err != nil { printCompleteError(err) defer os.Exit(1) @@ -265,13 +255,6 @@ func main() { context[constants.CTX_VIDPID] = *vidPidFlag } - if compile && flag.NArg() == 0 { - fmt.Fprintln(os.Stderr, "Last parameter must be the sketch to compile") - flag.Usage() - defer os.Exit(1) - return - } - if flag.NArg() > 0 { sketchLocation := flag.Arg(0) sketchLocation, err := gohasissues.Unquote(sketchLocation) @@ -283,6 +266,11 @@ func main() { context[constants.CTX_SKETCH_LOCATION] = sketchLocation } + if *verboseFlag && *quietFlag { + *verboseFlag = false + *quietFlag = false + } + context[constants.CTX_VERBOSE] = *verboseFlag ideVersion := "" @@ -301,20 +289,26 @@ func main() { context[constants.CTX_DEBUG_LEVEL] = *debugLevelFlag } - if *libraryDiscoveryRecursionDepthFlag > 0 { - context[constants.CTX_LIBRARY_DISCOVERY_RECURSION_DEPTH] = *libraryDiscoveryRecursionDepthFlag - } - - if *loggerFlag == FLAG_LOGGER_MACHINE { + if *quietFlag { + context[constants.CTX_LOGGER] = i18n.NoopLogger{} + } else if *loggerFlag == FLAG_LOGGER_MACHINE { context[constants.CTX_LOGGER] = i18n.MachineLogger{} } else { context[constants.CTX_LOGGER] = i18n.HumanLogger{} } - if compile { - err = builder.RunBuilder(context) - } else if dumpPrefs { + if *dumpPrefsFlag { err = builder.RunParseHardwareAndDumpBuildProperties(context) + } else if *preprocessFlag { + err = builder.RunPreprocess(context) + } else { + if flag.NArg() == 0 { + fmt.Fprintln(os.Stderr, "Last parameter must be the sketch to compile") + flag.Usage() + defer os.Exit(1) + return + } + err = builder.RunBuilder(context) } exitCode := 0 diff --git a/src/arduino.cc/builder/add_additional_entries_to_context.go b/src/arduino.cc/builder/add_additional_entries_to_context.go index 5729634a..742c0be1 100644 --- a/src/arduino.cc/builder/add_additional_entries_to_context.go +++ b/src/arduino.cc/builder/add_additional_entries_to_context.go @@ -76,16 +76,13 @@ func (s *AddAdditionalEntriesToContext) Run(context map[string]interface{}) erro context[constants.CTX_DEBUG_LEVEL] = DEFAULT_DEBUG_LEVEL } - if !utils.MapHas(context, constants.CTX_LIBRARY_DISCOVERY_RECURSION_DEPTH) { - context[constants.CTX_LIBRARY_DISCOVERY_RECURSION_DEPTH] = DEFAULT_LIBRARY_DISCOVERY_RECURSION_DEPTH - } - sourceFiles := &types.UniqueStringQueue{} context[constants.CTX_COLLECTED_SOURCE_FILES_QUEUE] = sourceFiles foldersWithSources := &types.UniqueSourceFolderQueue{} context[constants.CTX_FOLDERS_WITH_SOURCES_QUEUE] = foldersWithSources context[constants.CTX_LIBRARY_RESOLUTION_RESULTS] = make(map[string]types.LibraryResolutionResult) + context[constants.CTX_HARDWARE_REWRITE_RESULTS] = make(map[*types.Platform][]types.PlatforKeyRewrite) return nil } diff --git a/src/arduino.cc/builder/add_build_board_property_if_missing.go b/src/arduino.cc/builder/add_build_board_property_if_missing.go index ef422d14..b819a424 100644 --- a/src/arduino.cc/builder/add_build_board_property_if_missing.go +++ b/src/arduino.cc/builder/add_build_board_property_if_missing.go @@ -48,7 +48,7 @@ func (s *AddBuildBoardPropertyIfMissing) Run(context map[string]interface{}) err for _, board := range platform.Boards { if board.Properties[constants.BUILD_PROPERTIES_BUILD_BOARD] == constants.EMPTY_STRING { board.Properties[constants.BUILD_PROPERTIES_BUILD_BOARD] = strings.ToUpper(platform.PlatformId + "_" + board.BoardId) - logger.Fprintln(os.Stderr, constants.MSG_MISSING_BUILD_BOARD, aPackage.PackageId, platform.PlatformId, board.BoardId, board.Properties[constants.BUILD_PROPERTIES_BUILD_BOARD]) + logger.Fprintln(os.Stdout, constants.LOG_LEVEL_WARN, constants.MSG_MISSING_BUILD_BOARD, aPackage.PackageId, platform.PlatformId, board.BoardId, board.Properties[constants.BUILD_PROPERTIES_BUILD_BOARD]) } } } diff --git a/src/arduino.cc/builder/additional_sketch_files_copier.go b/src/arduino.cc/builder/additional_sketch_files_copier.go index 90d4189a..2bceb723 100644 --- a/src/arduino.cc/builder/additional_sketch_files_copier.go +++ b/src/arduino.cc/builder/additional_sketch_files_copier.go @@ -33,8 +33,8 @@ import ( "arduino.cc/builder/constants" "arduino.cc/builder/types" "arduino.cc/builder/utils" + "bytes" "io/ioutil" - "os" "path/filepath" ) @@ -44,7 +44,7 @@ func (s *AdditionalSketchFilesCopier) Run(context map[string]interface{}) error sketch := context[constants.CTX_SKETCH].(*types.Sketch) sketchBuildPath := context[constants.CTX_SKETCH_BUILD_PATH].(string) - err := os.MkdirAll(sketchBuildPath, os.FileMode(0755)) + err := utils.EnsureFolderExists(sketchBuildPath) if err != nil { return utils.WrapError(err) } @@ -58,15 +58,32 @@ func (s *AdditionalSketchFilesCopier) Run(context map[string]interface{}) error } targetFilePath := filepath.Join(sketchBuildPath, relativePath) - os.MkdirAll(filepath.Dir(targetFilePath), os.FileMode(0755)) + err = utils.EnsureFolderExists(filepath.Dir(targetFilePath)) + if err != nil { + return utils.WrapError(err) + } bytes, err := ioutil.ReadFile(file.Name) if err != nil { return utils.WrapError(err) } - ioutil.WriteFile(targetFilePath, bytes, os.FileMode(0644)) + if targetFileChanged(bytes, targetFilePath) { + err := utils.WriteFileBytes(targetFilePath, bytes) + if err != nil { + return utils.WrapError(err) + } + } } return nil } + +func targetFileChanged(currentBytes []byte, targetFilePath string) bool { + oldBytes, err := ioutil.ReadFile(targetFilePath) + if err != nil { + return true + } + + return bytes.Compare(currentBytes, oldBytes) != 0 +} diff --git a/src/arduino.cc/builder/builder.go b/src/arduino.cc/builder/builder.go index 78179748..9fb4206f 100644 --- a/src/arduino.cc/builder/builder.go +++ b/src/arduino.cc/builder/builder.go @@ -37,11 +37,12 @@ import ( "os" "reflect" "strconv" + "time" ) var MAIN_FILE_VALID_EXTENSIONS = map[string]bool{".ino": true, ".pde": true} -var ADDITIONAL_FILE_VALID_EXTENSIONS = map[string]bool{".h": true, ".c": true, ".hpp": true, ".cpp": true} -var ADDITIONAL_FILE_VALID_EXTENSIONS_NO_HEADERS = map[string]bool{".c": true, ".cpp": true} +var ADDITIONAL_FILE_VALID_EXTENSIONS = map[string]bool{".h": true, ".c": true, ".hpp": true, ".cpp": true, ".s": true} +var ADDITIONAL_FILE_VALID_EXTENSIONS_NO_HEADERS = map[string]bool{".c": true, ".cpp": true, ".s": true} var LIBRARY_MANDATORY_PROPERTIES = []string{constants.LIBRARY_NAME, constants.LIBRARY_VERSION, constants.LIBRARY_AUTHOR, constants.LIBRARY_MAINTAINER} var LIBRARY_NOT_SO_MANDATORY_PROPERTIES = []string{constants.LIBRARY_SENTENCE, constants.LIBRARY_PARAGRAPH, constants.LIBRARY_URL} @@ -62,7 +63,6 @@ const DEFAULT_DEBUG_LEVEL = 5 const DEFAULT_WARNINGS_LEVEL = "none" const DEFAULT_SOFTWARE = "ARDUINO" const DEFAULT_BUILD_CORE = "arduino" -const DEFAULT_LIBRARY_DISCOVERY_RECURSION_DEPTH = 4 type Builder struct{} @@ -77,6 +77,8 @@ func (s *Builder) Run(context map[string]interface{}) error { &ContainerBuildOptions{}, + &WarnAboutPlatformRewrites{}, + &RecipeByPrefixSuffixRunner{Prefix: constants.HOOKS_PREBUILD, Suffix: constants.HOOKS_PATTERN_SUFFIX}, &ContainerMergeCopySketchFiles{}, @@ -92,6 +94,7 @@ func (s *Builder) Run(context map[string]interface{}) error { &RecipeByPrefixSuffixRunner{Prefix: constants.HOOKS_SKETCH_POSTBUILD, Suffix: constants.HOOKS_PATTERN_SUFFIX}, &RecipeByPrefixSuffixRunner{Prefix: constants.HOOKS_LIBRARIES_PREBUILD, Suffix: constants.HOOKS_PATTERN_SUFFIX}, + &UnusedCompiledLibrariesRemover{}, &phases.LibrariesBuilder{}, &RecipeByPrefixSuffixRunner{Prefix: constants.HOOKS_LIBRARIES_POSTBUILD, Suffix: constants.HOOKS_PATTERN_SUFFIX}, @@ -128,6 +131,35 @@ func (s *Builder) Run(context map[string]interface{}) error { return otherErr } +type Preprocess struct{} + +func (s *Preprocess) Run(context map[string]interface{}) error { + commands := []types.Command{ + &SetupHumanLoggerIfMissing{}, + + &GenerateBuildPathIfMissing{}, + &EnsureBuildPathExists{}, + + &ContainerSetupHardwareToolsLibsSketchAndProps{}, + + &ContainerBuildOptions{}, + + &RecipeByPrefixSuffixRunner{Prefix: constants.HOOKS_PREBUILD, Suffix: constants.HOOKS_PATTERN_SUFFIX}, + + &ContainerMergeCopySketchFiles{}, + + &ContainerFindIncludes{}, + + &WarnAboutArchIncompatibleLibraries{}, + + &ContainerAddPrototypes{}, + + &PrintPreprocessedSource{}, + } + + return runCommands(context, commands, true) +} + type ParseHardwareAndDumpBuildProperties struct{} func (s *ParseHardwareAndDumpBuildProperties) Run(context map[string]interface{}) error { @@ -171,13 +203,13 @@ func printProgressIfProgressEnabledAndMachineLogger(progressEnabled bool, contex log := utils.Logger(context) if log.Name() == "machine" { - log.Println(constants.MSG_PROGRESS, strconv.FormatFloat(float64(progress), 'f', 2, 32)) + log.Println(constants.LOG_LEVEL_INFO, constants.MSG_PROGRESS, strconv.FormatFloat(float64(progress), 'f', 2, 32)) } } func PrintRingNameIfDebug(context map[string]interface{}, command types.Command) { if utils.DebugLevel(context) >= 10 { - utils.Logger(context).Fprintln(os.Stderr, constants.MSG_RUNNING_COMMAND, reflect.Indirect(reflect.ValueOf(command)).Type().Name()) + utils.Logger(context).Fprintln(os.Stdout, constants.LOG_LEVEL_DEBUG, constants.MSG_RUNNING_COMMAND, strconv.FormatInt(time.Now().Unix(), 10), reflect.Indirect(reflect.ValueOf(command)).Type().Name()) } } @@ -190,3 +222,8 @@ func RunParseHardwareAndDumpBuildProperties(context map[string]interface{}) erro command := ParseHardwareAndDumpBuildProperties{} return command.Run(context) } + +func RunPreprocess(context map[string]interface{}) error { + command := Preprocess{} + return command.Run(context) +} diff --git a/src/arduino.cc/builder/builder_utils/utils.go b/src/arduino.cc/builder/builder_utils/utils.go index 2c83ad6a..18ab284e 100644 --- a/src/arduino.cc/builder/builder_utils/utils.go +++ b/src/arduino.cc/builder/builder_utils/utils.go @@ -34,8 +34,10 @@ import ( "arduino.cc/builder/i18n" "arduino.cc/builder/props" "arduino.cc/builder/utils" + "bytes" "fmt" "os" + "os/exec" "path/filepath" "strings" ) @@ -136,7 +138,7 @@ func compileFileWithRecipe(sourcePath string, source string, buildPath string, b } properties[constants.BUILD_PROPERTIES_OBJECT_FILE] = filepath.Join(buildPath, relativeSource+".o") - err = os.MkdirAll(filepath.Dir(properties[constants.BUILD_PROPERTIES_OBJECT_FILE]), os.FileMode(0755)) + err = utils.EnsureFolderExists(filepath.Dir(properties[constants.BUILD_PROPERTIES_OBJECT_FILE])) if err != nil { return "", utils.WrapError(err) } @@ -152,7 +154,7 @@ func compileFileWithRecipe(sourcePath string, source string, buildPath string, b return "", utils.WrapError(err) } } else if verbose { - logger.Println(constants.MSG_USING_PREVIOUS_COMPILED_FILE, properties[constants.BUILD_PROPERTIES_OBJECT_FILE]) + logger.Println(constants.LOG_LEVEL_INFO, constants.MSG_USING_PREVIOUS_COMPILED_FILE, properties[constants.BUILD_PROPERTIES_OBJECT_FILE]) } return properties[constants.BUILD_PROPERTIES_OBJECT_FILE], nil @@ -278,6 +280,27 @@ func ArchiveCompiledFiles(buildPath string, archiveFile string, objectFiles []st } func ExecRecipe(properties map[string]string, recipe string, removeUnsetProperties bool, echoCommandLine bool, echoOutput bool, logger i18n.Logger) ([]byte, error) { + command, err := PrepareCommandForRecipe(properties, recipe, removeUnsetProperties, echoCommandLine, echoOutput, logger) + if err != nil { + return nil, utils.WrapError(err) + } + + if echoOutput { + command.Stdout = os.Stdout + } + + command.Stderr = os.Stderr + + if echoOutput { + err := command.Run() + return nil, utils.WrapError(err) + } + + bytes, err := command.Output() + return bytes, utils.WrapError(err) +} + +func PrepareCommandForRecipe(properties map[string]string, recipe string, removeUnsetProperties bool, echoCommandLine bool, echoOutput bool, logger i18n.Logger) (*exec.Cmd, error) { pattern := properties[recipe] if pattern == constants.EMPTY_STRING { return nil, utils.ErrorfWithLogger(logger, constants.MSG_PATTERN_MISSING, recipe) @@ -301,19 +324,19 @@ func ExecRecipe(properties map[string]string, recipe string, removeUnsetProperti fmt.Println(commandLine) } - if echoOutput { - command.Stdout = os.Stdout - } - - command.Stderr = os.Stderr + return command, nil +} - if echoOutput { - err := command.Run() - return nil, utils.WrapError(err) +func ExecRecipeCollectStdErr(properties map[string]string, recipe string, removeUnsetProperties bool, echoCommandLine bool, echoOutput bool, logger i18n.Logger) (string, error) { + command, err := PrepareCommandForRecipe(properties, recipe, removeUnsetProperties, echoCommandLine, echoOutput, logger) + if err != nil { + return "", utils.WrapError(err) } - bytes, err := command.Output() - return bytes, utils.WrapError(err) + buffer := &bytes.Buffer{} + command.Stderr = buffer + command.Run() + return string(buffer.Bytes()), nil } func RemoveHyphenMDDFlagFromGCCCommandLine(properties map[string]string) { diff --git a/src/arduino.cc/builder/coan_runner.go b/src/arduino.cc/builder/coan_runner.go index 2e3b3ad6..f4630621 100644 --- a/src/arduino.cc/builder/coan_runner.go +++ b/src/arduino.cc/builder/coan_runner.go @@ -35,8 +35,6 @@ import ( "arduino.cc/builder/props" "arduino.cc/builder/utils" "fmt" - "io/ioutil" - "os" "path/filepath" "regexp" ) @@ -51,13 +49,13 @@ func (s *CoanRunner) Run(context map[string]interface{}) error { verbose := context[constants.CTX_VERBOSE].(bool) preprocPath := context[constants.CTX_PREPROC_PATH].(string) - err := os.MkdirAll(preprocPath, os.FileMode(0755)) + err := utils.EnsureFolderExists(preprocPath) if err != nil { return utils.WrapError(err) } coanTargetFileName := filepath.Join(preprocPath, constants.FILE_COAN_TARGET) - err = ioutil.WriteFile(coanTargetFileName, []byte(source), os.FileMode(0644)) + err = utils.WriteFile(coanTargetFileName, source) if err != nil { return utils.WrapError(err) } diff --git a/src/arduino.cc/builder/collect_all_source_files_from_folders_with_sources.go b/src/arduino.cc/builder/collect_all_source_files_from_folders_with_sources.go index ef2548dc..d9b26c60 100644 --- a/src/arduino.cc/builder/collect_all_source_files_from_folders_with_sources.go +++ b/src/arduino.cc/builder/collect_all_source_files_from_folders_with_sources.go @@ -68,8 +68,10 @@ func (s *CollectAllSourceFilesFromFoldersWithSources) Run(context map[string]int } func collectByWalk(filePaths *[]string, folder string) error { - checkExtensionFunc := func(ext string) bool { - return ADDITIONAL_FILE_VALID_EXTENSIONS_NO_HEADERS[ext] + checkExtensionFunc := func(filePath string) bool { + name := filepath.Base(filePath) + ext := strings.ToLower(filepath.Ext(filePath)) + return !strings.HasPrefix(name, ".") && ADDITIONAL_FILE_VALID_EXTENSIONS_NO_HEADERS[ext] } walkFunc := utils.CollectAllReadableFiles(filePaths, checkExtensionFunc) err := gohasissues.Walk(folder, walkFunc) diff --git a/src/arduino.cc/builder/collect_ctags_from_sketch_files.go b/src/arduino.cc/builder/collect_ctags_from_sketch_files.go new file mode 100644 index 00000000..a836c4d3 --- /dev/null +++ b/src/arduino.cc/builder/collect_ctags_from_sketch_files.go @@ -0,0 +1,64 @@ +/* + * This file is part of Arduino Builder. + * + * Arduino Builder is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + */ + +package builder + +import ( + "arduino.cc/builder/constants" + "arduino.cc/builder/types" + "arduino.cc/builder/utils" + "strings" +) + +type CollectCTagsFromSketchFiles struct{} + +func (s *CollectCTagsFromSketchFiles) Run(context map[string]interface{}) error { + sketch := context[constants.CTX_SKETCH].(*types.Sketch) + sketchFileNames := collectSketchFileNamesFrom(sketch) + + ctags := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]*types.CTag) + ctagsOfSketch := []*types.CTag{} + for _, ctag := range ctags { + if utils.SliceContains(sketchFileNames, strings.Replace(ctag.Filename, "\\\\", "\\", -1)) { + ctagsOfSketch = append(ctagsOfSketch, ctag) + } + } + + context[constants.CTX_COLLECTED_CTAGS] = ctagsOfSketch + + return nil +} + +func collectSketchFileNamesFrom(sketch *types.Sketch) []string { + fileNames := []string{sketch.MainFile.Name} + for _, file := range sketch.OtherSketchFiles { + fileNames = append(fileNames, file.Name) + } + return fileNames +} diff --git a/src/arduino.cc/builder/compare_prototypes_from_source_and_preproc_source.go b/src/arduino.cc/builder/compare_prototypes_from_source_and_preproc_source.go index 35556e91..7139da2d 100644 --- a/src/arduino.cc/builder/compare_prototypes_from_source_and_preproc_source.go +++ b/src/arduino.cc/builder/compare_prototypes_from_source_and_preproc_source.go @@ -32,23 +32,31 @@ package builder import ( "arduino.cc/builder/constants" "arduino.cc/builder/types" - "arduino.cc/builder/utils" ) type ComparePrototypesFromSourceAndPreprocSource struct{} func (s *ComparePrototypesFromSourceAndPreprocSource) Run(context map[string]interface{}) error { - prototypesOfSource := context[constants.CTX_PROTOTYPES_OF_SOURCE].([]*types.Prototype) - prototypesOfPreprocSource := context[constants.CTX_PROTOTYPES_OF_PREPROC_SOURCE].([]*types.Prototype) + ctagsOfSource := context[constants.CTX_CTAGS_OF_SOURCE].([]*types.CTag) + ctagsOfPreprocSource := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]*types.CTag) - actualPrototypes := []*types.Prototype{} - for _, prototypeOfPreprocSource := range prototypesOfPreprocSource { - if utils.SliceContainsPrototype(prototypesOfSource, prototypeOfPreprocSource) { - actualPrototypes = append(actualPrototypes, prototypeOfPreprocSource) + actualCTags := []*types.CTag{} + for _, ctagOfPreprocSource := range ctagsOfPreprocSource { + if sliceContainsCTag(ctagsOfSource, ctagOfPreprocSource) { + actualCTags = append(actualCTags, ctagOfPreprocSource) } } - context[constants.CTX_PROTOTYPES] = actualPrototypes + context[constants.CTX_COLLECTED_CTAGS] = actualCTags return nil } + +func sliceContainsCTag(slice []*types.CTag, target *types.CTag) bool { + for _, value := range slice { + if value.FunctionName == target.FunctionName { + return true + } + } + return false +} diff --git a/src/arduino.cc/builder/constants/constants.go b/src/arduino.cc/builder/constants/constants.go index 48e9cd32..d80d232c 100644 --- a/src/arduino.cc/builder/constants/constants.go +++ b/src/arduino.cc/builder/constants/constants.go @@ -60,6 +60,7 @@ const BUILD_PROPERTIES_OBJECT_FILE = "object_file" const BUILD_PROPERTIES_OBJECT_FILES = "object_files" const BUILD_PROPERTIES_PATTERN = "pattern" const BUILD_PROPERTIES_PID = "pid" +const BUILD_PROPERTIES_PREPROCESSED_FILE_PATH = "preprocessed_file_path" const BUILD_PROPERTIES_RUNTIME_HARDWARE_PATH = "runtime.hardware.path" const BUILD_PROPERTIES_RUNTIME_OS = "runtime.os" const BUILD_PROPERTIES_RUNTIME_PLATFORM_PATH = "runtime.platform.path" @@ -82,39 +83,43 @@ const CTX_BUILD_PATH = "buildPath" const CTX_BUILD_PROPERTIES = "buildProperties" const CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION = "runtime.ide.version" const CTX_BUILT_IN_LIBRARIES_FOLDERS = "builtInLibrariesFolders" +const CTX_COLLECTED_CTAGS = "collectedCTags" const CTX_COLLECTED_SOURCE_FILES_QUEUE = "collectedSourceFilesQueue" const CTX_CORE_BUILD_PATH = "coreBuildPath" +const CTX_CTAGS_OF_PREPROC_SOURCE = "ctagsOfPreprocSource" +const CTX_CTAGS_OF_SOURCE = "ctagsOfSource" const CTX_CTAGS_OUTPUT = "ctagsOutput" -const CTX_CTAGS_TEMP_FILE_NAME = "ctagsTempFileName" +const CTX_CTAGS_TEMP_FILE_PATH = "ctagsTempFilePath" const CTX_CUSTOM_BUILD_PROPERTIES = "customBuildProperties" const CTX_DEBUG_LEVEL = "debugLevel" -const CTX_FIRST_FUNCTION_AT_LINE = "firstFunctionAtLine" +const CTX_FILE_PATH_TO_READ = "filePathToRead" const CTX_FOLDERS_WITH_SOURCES_QUEUE = "foldersWithSourcesQueue" const CTX_FQBN = "fqbn" const CTX_GCC_MINUS_E_SOURCE = "gccMinusESource" const CTX_GCC_MINUS_M_OUTPUT = "gccMinusMOutput" const CTX_HARDWARE_FOLDERS = "hardwareFolders" const CTX_HARDWARE = "hardware" +const CTX_HARDWARE_REWRITE_RESULTS = "hardwareRewriteResults" const CTX_HEADER_TO_LIBRARIES = "headerToLibraries" const CTX_IMPORTED_LIBRARIES = "importedLibraries" const CTX_INCLUDE_FOLDERS = "includeFolders" const CTX_INCLUDE_SECTION = "includeSection" const CTX_INCLUDES = "includes" +const CTX_INCLUDES_JUST_FOUND = "includesJustFound" const CTX_LIBRARIES_BUILD_PATH = "librariesBuildPath" const CTX_LIBRARIES_FOLDERS = "librariesFolders" const CTX_LIBRARIES = "libraries" -const CTX_LIBRARY_DISCOVERY_RECURSION_DEPTH = "libraryDiscoveryRecursionDepth" const CTX_LIBRARY_RESOLUTION_RESULTS = "libraryResolutionResults" const CTX_LINE_OFFSET = "lineOffset" +const CTX_LINE_WHERE_TO_INSERT_PROTOTYPES = "lineWhereToInsertPrototypes" const CTX_LOGGER = "logger" +const CTX_OBJECT_FILES_CORE = "objectFilesCore" const CTX_OBJECT_FILES_LIBRARIES = "objectFilesLibraries" const CTX_OBJECT_FILES_SKETCH = "objectFilesSketch" const CTX_OTHER_LIBRARIES_FOLDERS = "otherLibrariesFolders" const CTX_PLATFORM_KEYS_REWRITE = "platformKeysRewrite" const CTX_PREPROC_PATH = "preprocPath" const CTX_PROTOTYPE_SECTION = "prototypeSection" -const CTX_PROTOTYPES_OF_PREPROC_SOURCE = "prototypesOfPreprocSource" -const CTX_PROTOTYPES_OF_SOURCE = "prototypesOfSource" const CTX_PROTOTYPES = "prototypes" const CTX_SKETCH_BUILD_PATH = "sketchBuildPath" const CTX_SKETCH_LOCATION = "sketchLocation" @@ -134,6 +139,7 @@ const FILE_BOARDS_TXT = "boards.txt" const FILE_BUILTIN_TOOLS_VERSIONS_TXT = "builtin_tools_versions.txt" const FILE_COAN_TARGET = "coan_target.cpp" const FILE_CTAGS_TARGET = "ctags_target.cpp" +const FILE_CTAGS_TARGET_FOR_GCC_MINUS_E = "ctags_target_for_gcc_minus_e.cpp" const FILE_GCC_PREPROC_TARGET = "gcc_preproc_target.cpp" const FILE_PLATFORM_KEYS_REWRITE_TXT = "platform.keys.rewrite.txt" const FILE_PLATFORM_LOCAL_TXT = "platform.local.txt" @@ -195,6 +201,10 @@ const LIBRARY_PROPERTIES = "library.properties" const LIBRARY_SENTENCE = "sentence" const LIBRARY_URL = "url" const LIBRARY_VERSION = "version" +const LOG_LEVEL_DEBUG = "debug" +const LOG_LEVEL_ERROR = "error" +const LOG_LEVEL_INFO = "info" +const LOG_LEVEL_WARN = "warn" const MSG_ARCH_FOLDER_NOT_SUPPORTED = "'arch' folder is no longer supported! See http://goo.gl/gfFJzU for more information" const MSG_BOARD_UNKNOWN = "Board {0} (platform {1}, package {2}) is unknown" const MSG_BOOTLOADER_FILE_MISSING = "Bootloader file specified but missing: {0}" @@ -205,7 +215,7 @@ const MSG_LIB_LEGACY = "(legacy)" const MSG_LIBRARIES_MULTIPLE_LIBS_FOUND_FOR = "Multiple libraries were found for \"{0}\"" const MSG_LIBRARIES_NOT_USED = " Not used: {0}" const MSG_LIBRARIES_USED = " Used: {0}" -const MSG_LIBRARY_CAN_USE_SRC_AND_UTILITY_FOLDERS = "Library can't use both 'src' and 'utility' folders." +const MSG_LIBRARY_CAN_USE_SRC_AND_UTILITY_FOLDERS = "Library can't use both 'src' and 'utility' folders. Double check {0}" const MSG_LIBRARY_INCOMPATIBLE_ARCH = "WARNING: library {0} claims to run on {1} architecture(s) and may be incompatible with your current board which runs on {2} architecture(s)." const MSG_LOOKING_FOR_RECIPES = "Looking for recipes like {0}*{1}" const MSG_MISSING_BUILD_BOARD = "Board {0}:{1}:{2} doesn''t define a ''build.board'' preference. Auto-set to: {3}" @@ -216,10 +226,13 @@ const MSG_PATTERN_MISSING = "{0} pattern is missing" const MSG_PLATFORM_UNKNOWN = "Platform {0} (package {1}) is unknown" const MSG_PROGRESS = "Progress {0}" const MSG_PROP_IN_LIBRARY = "Missing '{0}' from library in {1}" -const MSG_RUNNING_COMMAND = "Running: {0}" +const MSG_RUNNING_COMMAND = "Ts: {0} - Running: {1}" const MSG_RUNNING_RECIPE = "Running recipe: {0}" const MSG_SETTING_BUILD_PATH = "Setting build path to {0}" const MSG_SKETCH_CANT_BE_IN_BUILDPATH = "Sketch cannot be located in build path. Please specify a different build path" +const MSG_SKIPPING_TAG_ALREADY_DEFINED = "Skipping tag {0} because prototype is already defined" +const MSG_SKIPPING_TAG_BECAUSE_HAS_FIELD = "Skipping tag {0} because it has field {0}" +const MSG_SKIPPING_TAG_WITH_REASON = "Skipping tag {0}. Reason: {1}" const MSG_UNHANDLED_TYPE_IN_CONTEXT = "Unhandled type {0} in context key {1}" const MSG_UNKNOWN_SKETCH_EXT = "Unknown sketch file extension: {0}" const MSG_USING_LIBRARY_AT_VERSION = "Using library {0} at version {1} in folder: {2} {3}" diff --git a/src/arduino.cc/builder/container_add_prototypes.go b/src/arduino.cc/builder/container_add_prototypes.go index 90993e43..427a3056 100644 --- a/src/arduino.cc/builder/container_add_prototypes.go +++ b/src/arduino.cc/builder/container_add_prototypes.go @@ -39,14 +39,13 @@ type ContainerAddPrototypes struct{} func (s *ContainerAddPrototypes) Run(context map[string]interface{}) error { commands := []types.Command{ - &GCCPreprocRunner{}, - &CTagsTargetFileSaver{SourceField: constants.CTX_GCC_MINUS_E_SOURCE}, + &GCCPreprocRunner{TargetFileName: constants.FILE_CTAGS_TARGET_FOR_GCC_MINUS_E}, + &ReadFileAndStoreInContext{TargetField: constants.CTX_GCC_MINUS_E_SOURCE}, + &CTagsTargetFileSaver{SourceField: constants.CTX_GCC_MINUS_E_SOURCE, TargetFileName: constants.FILE_CTAGS_TARGET_FOR_GCC_MINUS_E}, &CTagsRunner{}, - &CTagsParser{PrototypesField: constants.CTX_PROTOTYPES_OF_PREPROC_SOURCE}, - &CTagsTargetFileSaver{SourceField: constants.CTX_SOURCE}, - &CTagsRunner{}, - &CTagsParser{PrototypesField: constants.CTX_PROTOTYPES_OF_SOURCE}, - &ComparePrototypesFromSourceAndPreprocSource{}, + &CTagsParser{}, + &CollectCTagsFromSketchFiles{}, + &CTagsToPrototypes{}, &PrototypesAdder{}, &SketchSaver{}, } diff --git a/src/arduino.cc/builder/container_find_includes.go b/src/arduino.cc/builder/container_find_includes.go index 92593d80..35408f21 100644 --- a/src/arduino.cc/builder/container_find_includes.go +++ b/src/arduino.cc/builder/container_find_includes.go @@ -44,22 +44,11 @@ func (s *ContainerFindIncludes) Run(context map[string]interface{}) error { return utils.WrapError(err) } - sketch := context[constants.CTX_SKETCH].(*types.Sketch) sketchBuildPath := context[constants.CTX_SKETCH_BUILD_PATH].(string) - wheelSpins := context[constants.CTX_LIBRARY_DISCOVERY_RECURSION_DEPTH].(int) - for i := 0; i < wheelSpins; i++ { - commands := []types.Command{ - &IncludesFinderWithGCC{SourceFile: filepath.Join(sketchBuildPath, filepath.Base(sketch.MainFile.Name)+".cpp")}, - &GCCMinusMOutputParser{}, - &IncludesToIncludeFolders{}, - } - - for _, command := range commands { - err := runCommand(context, command) - if err != nil { - return utils.WrapError(err) - } - } + sketch := context[constants.CTX_SKETCH].(*types.Sketch) + err = findIncludesUntilDone(context, filepath.Join(sketchBuildPath, filepath.Base(sketch.MainFile.Name)+".cpp")) + if err != nil { + return utils.WrapError(err) } foldersWithSources := context[constants.CTX_FOLDERS_WITH_SOURCES_QUEUE].(*types.UniqueSourceFolderQueue) @@ -78,24 +67,24 @@ func (s *ContainerFindIncludes) Run(context map[string]interface{}) error { return utils.WrapError(err) } - sourceFiles := context[constants.CTX_COLLECTED_SOURCE_FILES_QUEUE].(*types.UniqueStringQueue) + sourceFilePaths := context[constants.CTX_COLLECTED_SOURCE_FILES_QUEUE].(*types.UniqueStringQueue) - for !sourceFiles.Empty() { - commands := []types.Command{ - &IncludesFinderWithGCC{SourceFile: sourceFiles.Pop().(string)}, - &GCCMinusMOutputParser{}, - &IncludesToIncludeFolders{}, - &CollectAllSourceFilesFromFoldersWithSources{}, + for !sourceFilePaths.Empty() { + err = findIncludesUntilDone(context, sourceFilePaths.Pop().(string)) + if err != nil { + return utils.WrapError(err) } - - for _, command := range commands { - err := runCommand(context, command) - if err != nil { - return utils.WrapError(err) - } + err := runCommand(context, &CollectAllSourceFilesFromFoldersWithSources{}) + if err != nil { + return utils.WrapError(err) } } + err = runCommand(context, &FailIfImportedLibraryIsWrong{}) + if err != nil { + return utils.WrapError(err) + } + return nil } @@ -107,3 +96,31 @@ func runCommand(context map[string]interface{}, command types.Command) error { } return nil } + +func findIncludesUntilDone(context map[string]interface{}, sourceFilePath string) error { + targetFilePath := utils.NULLFile() + importedLibraries := context[constants.CTX_IMPORTED_LIBRARIES].([]*types.Library) + done := false + for !done { + commands := []types.Command{ + &GCCPreprocRunnerForDiscoveringIncludes{SourceFilePath: sourceFilePath, TargetFilePath: targetFilePath}, + &IncludesFinderWithRegExp{ContextField: constants.CTX_GCC_MINUS_E_SOURCE}, + &IncludesToIncludeFolders{}, + } + for _, command := range commands { + err := runCommand(context, command) + if err != nil { + return utils.WrapError(err) + } + } + if len(context[constants.CTX_INCLUDES_JUST_FOUND].([]string)) == 0 { + done = true + } else if len(context[constants.CTX_IMPORTED_LIBRARIES].([]*types.Library)) == len(importedLibraries) { + err := runCommand(context, &GCCPreprocRunner{TargetFileName: constants.FILE_CTAGS_TARGET_FOR_GCC_MINUS_E}) + return utils.WrapError(err) + } + importedLibraries = context[constants.CTX_IMPORTED_LIBRARIES].([]*types.Library) + context[constants.CTX_INCLUDES_JUST_FOUND] = []string{} + } + return nil +} diff --git a/src/arduino.cc/builder/ctags_parser.go b/src/arduino.cc/builder/ctags_parser.go index 073f209c..09a01d51 100644 --- a/src/arduino.cc/builder/ctags_parser.go +++ b/src/arduino.cc/builder/ctags_parser.go @@ -33,181 +33,210 @@ import ( "arduino.cc/builder/constants" "arduino.cc/builder/types" "arduino.cc/builder/utils" + "os" + "reflect" + "runtime" "strconv" "strings" ) -const FIELD_KIND = "kind" -const FIELD_LINE = "line" -const FIELD_SIGNATURE = "signature" -const FIELD_RETURNTYPE = "returntype" -const FIELD_CODE = "code" -const FIELD_FUNCTION_NAME = "functionName" -const FIELD_CLASS = "class" -const FIELD_STRUCT = "struct" -const FIELD_SKIP = "skipMe" - const KIND_PROTOTYPE = "prototype" +const KIND_FUNCTION = "function" -const TEMPLATE = "template" +//const KIND_PROTOTYPE_MODIFIERS = "prototype_modifiers" -var FIELDS = map[string]bool{"kind": true, "line": true, "typeref": true, "signature": true, "returntype": true, "class": true, "struct": true} -var KNOWN_TAG_KINDS = map[string]bool{"prototype": true, "function": true} +const TEMPLATE = "template" +const STATIC = "static" -type CTagsParser struct { - PrototypesField string +var KNOWN_TAG_KINDS = map[string]bool{ + "prototype": true, + "function": true, } +type CTagsParser struct{} + func (s *CTagsParser) Run(context map[string]interface{}) error { rows := strings.Split(context[constants.CTX_CTAGS_OUTPUT].(string), "\n") rows = removeEmpty(rows) - var tags []map[string]string + var tags []*types.CTag for _, row := range rows { tags = append(tags, parseTag(row)) } - tags = filterOutUnknownTags(tags) - tags = filterOutTagsWithField(tags, FIELD_CLASS) - tags = filterOutTagsWithField(tags, FIELD_STRUCT) - tags = skipTagsWhere(tags, signatureContainsDefaultArg) - tags = addPrototypes(tags) - tags = removeDefinedProtypes(tags) - tags = removeDuplicate(tags) - - if len(tags) > 0 { - line, err := strconv.Atoi(tags[0][FIELD_LINE]) - if err != nil { - return utils.WrapError(err) - } - context[constants.CTX_FIRST_FUNCTION_AT_LINE] = line - } - - prototypes := toPrototypes(tags) + skipTagsWhere(tags, tagIsUnknown, context) + skipTagsWhere(tags, tagIsUnhandled, context) + skipTagsWhere(tags, signatureContainsDefaultArg, context) + addPrototypes(tags) + removeDefinedProtypes(tags, context) + removeDuplicate(tags) + skipTagsWhere(tags, prototypeAndCodeDontMatch, context) - context[s.PrototypesField] = prototypes + context[constants.CTX_CTAGS_OF_PREPROC_SOURCE] = tags return nil } -func toPrototypes(tags []map[string]string) []*types.Prototype { - prototypes := []*types.Prototype{} +func addPrototypes(tags []*types.CTag) { for _, tag := range tags { - if tag[FIELD_SKIP] != "true" { - ctag := types.Prototype{FunctionName: tag[FIELD_FUNCTION_NAME], Prototype: tag[KIND_PROTOTYPE], Fields: tag} - prototypes = append(prototypes, &ctag) + if !tag.SkipMe { + addPrototype(tag) } } - return prototypes } -func addPrototypes(tags []map[string]string) []map[string]string { - for _, tag := range tags { - addPrototype(tag) - } - return tags -} - -func addPrototype(tag map[string]string) { - if strings.Index(tag[FIELD_RETURNTYPE], TEMPLATE) == 0 || strings.Index(tag[FIELD_CODE], TEMPLATE) == 0 { - code := tag[FIELD_CODE] +func addPrototype(tag *types.CTag) { + if strings.Index(tag.Returntype, TEMPLATE) == 0 || strings.Index(tag.Code, TEMPLATE) == 0 { + code := tag.Code if strings.Contains(code, "{") { code = code[:strings.Index(code, "{")] } else { code = code[:strings.LastIndex(code, ")")+1] } - tag[KIND_PROTOTYPE] = code + ";" - } else { - tag[KIND_PROTOTYPE] = tag[FIELD_RETURNTYPE] + " " + tag[FIELD_FUNCTION_NAME] + tag[FIELD_SIGNATURE] + ";" + tag.Prototype = code + ";" + return + } + + tag.Prototype = tag.Returntype + " " + tag.FunctionName + tag.Signature + ";" + + tag.PrototypeModifiers = "" + if strings.Index(tag.Code, STATIC+" ") != -1 { + tag.PrototypeModifiers = tag.PrototypeModifiers + " " + STATIC } + tag.PrototypeModifiers = strings.TrimSpace(tag.PrototypeModifiers) } -func removeDefinedProtypes(tags []map[string]string) []map[string]string { +func removeDefinedProtypes(tags []*types.CTag, context map[string]interface{}) { definedPrototypes := make(map[string]bool) for _, tag := range tags { - if tag[FIELD_KIND] == KIND_PROTOTYPE { - definedPrototypes[tag[KIND_PROTOTYPE]] = true + if tag.Kind == KIND_PROTOTYPE { + definedPrototypes[tag.Prototype] = true } } - var newTags []map[string]string for _, tag := range tags { - if !definedPrototypes[tag[KIND_PROTOTYPE]] { - newTags = append(newTags, tag) + if definedPrototypes[tag.Prototype] { + if utils.DebugLevel(context) >= 10 { + utils.Logger(context).Fprintln(os.Stdout, constants.LOG_LEVEL_DEBUG, constants.MSG_SKIPPING_TAG_ALREADY_DEFINED, tag.FunctionName) + } + tag.SkipMe = true } } - return newTags } -func removeDuplicate(tags []map[string]string) []map[string]string { +func removeDuplicate(tags []*types.CTag) { definedPrototypes := make(map[string]bool) - var newTags []map[string]string for _, tag := range tags { - if !definedPrototypes[tag[KIND_PROTOTYPE]] { - newTags = append(newTags, tag) - definedPrototypes[tag[KIND_PROTOTYPE]] = true + if !definedPrototypes[tag.Prototype] { + definedPrototypes[tag.Prototype] = true + } else { + tag.SkipMe = true } } - return newTags } -type skipFuncType func(tag map[string]string) bool +type skipFuncType func(tag *types.CTag) bool -func skipTagsWhere(tags []map[string]string, skipFuncs ...skipFuncType) []map[string]string { +func skipTagsWhere(tags []*types.CTag, skipFunc skipFuncType, context map[string]interface{}) { for _, tag := range tags { - skip := skipFuncs[0](tag) - for _, skipFunc := range skipFuncs[1:] { - skip = skip || skipFunc(tag) + if !tag.SkipMe { + skip := skipFunc(tag) + if skip && utils.DebugLevel(context) >= 10 { + utils.Logger(context).Fprintln(os.Stdout, constants.LOG_LEVEL_DEBUG, constants.MSG_SKIPPING_TAG_WITH_REASON, tag.FunctionName, runtime.FuncForPC(reflect.ValueOf(skipFunc).Pointer()).Name()) + } + tag.SkipMe = skip } - tag[FIELD_SKIP] = strconv.FormatBool(skip) } - return tags } -func signatureContainsDefaultArg(tag map[string]string) bool { - return strings.Contains(tag[FIELD_SIGNATURE], "=") +func signatureContainsDefaultArg(tag *types.CTag) bool { + return strings.Contains(tag.Signature, "=") } -func filterOutTagsWithField(tags []map[string]string, field string) []map[string]string { - var newTags []map[string]string - for _, tag := range tags { - if tag[field] == constants.EMPTY_STRING { - newTags = append(newTags, tag) - } +func prototypeAndCodeDontMatch(tag *types.CTag) bool { + if tag.SkipMe { + return true } - return newTags + + code := removeSpacesAndTabs(tag.Code) + prototype := removeSpacesAndTabs(tag.Prototype) + prototype = removeTralingSemicolon(prototype) + + return strings.Index(code, prototype) == -1 } -func filterOutUnknownTags(tags []map[string]string) []map[string]string { - var newTags []map[string]string - for _, tag := range tags { - if KNOWN_TAG_KINDS[tag[FIELD_KIND]] { - newTags = append(newTags, tag) - } +func removeTralingSemicolon(s string) string { + return s[0 : len(s)-1] +} + +func removeSpacesAndTabs(s string) string { + s = strings.Replace(s, " ", "", -1) + s = strings.Replace(s, "\t", "", -1) + return s +} + +func tagIsUnhandled(tag *types.CTag) bool { + return !isHandled(tag) +} + +func isHandled(tag *types.CTag) bool { + if tag.Class != "" { + return false + } + if tag.Struct != "" { + return false } - return newTags + if tag.Namespace != "" { + return false + } + return true +} + +func tagIsUnknown(tag *types.CTag) bool { + return !KNOWN_TAG_KINDS[tag.Kind] } -func parseTag(row string) map[string]string { - tag := make(map[string]string) +func parseTag(row string) *types.CTag { + tag := &types.CTag{} parts := strings.Split(row, "\t") - tag[FIELD_FUNCTION_NAME] = parts[0] - parts = parts[1:] + tag.FunctionName = parts[0] + tag.Filename = parts[1] + + parts = parts[2:] for _, part := range parts { if strings.Contains(part, ":") { - field := part[:strings.Index(part, ":")] - if FIELDS[field] { - tag[field] = strings.TrimSpace(part[strings.Index(part, ":")+1:]) + colon := strings.Index(part, ":") + field := part[:colon] + value := strings.TrimSpace(part[colon+1:]) + switch field { + case "kind": + tag.Kind = value + case "line": + val, _ := strconv.Atoi(value) + // TODO: Check err from strconv.Atoi + tag.Line = val + case "typeref": + tag.Typeref = value + case "signature": + tag.Signature = value + case "returntype": + tag.Returntype = value + case "class": + tag.Class = value + case "struct": + tag.Struct = value + case "namespace": + tag.Namespace = value } } } if strings.Contains(row, "/^") && strings.Contains(row, "$/;") { - tag[FIELD_CODE] = row[strings.Index(row, "/^")+2 : strings.Index(row, "$/;")] + tag.Code = row[strings.Index(row, "/^")+2 : strings.Index(row, "$/;")] } return tag diff --git a/src/arduino.cc/builder/ctags_runner.go b/src/arduino.cc/builder/ctags_runner.go index 219ee928..20c9eb7c 100644 --- a/src/arduino.cc/builder/ctags_runner.go +++ b/src/arduino.cc/builder/ctags_runner.go @@ -41,11 +41,11 @@ type CTagsRunner struct{} func (s *CTagsRunner) Run(context map[string]interface{}) error { buildProperties := context[constants.CTX_BUILD_PROPERTIES].(map[string]string) - ctagsTargetFileName := context[constants.CTX_CTAGS_TEMP_FILE_NAME].(string) + ctagsTargetFilePath := context[constants.CTX_CTAGS_TEMP_FILE_PATH].(string) logger := context[constants.CTX_LOGGER].(i18n.Logger) properties := utils.MergeMapsOfStrings(make(map[string]string), buildProperties, props.SubTree(props.SubTree(buildProperties, constants.BUILD_PROPERTIES_TOOLS_KEY), constants.CTAGS)) - properties[constants.BUILD_PROPERTIES_SOURCE_FILE] = ctagsTargetFileName + properties[constants.BUILD_PROPERTIES_SOURCE_FILE] = ctagsTargetFilePath pattern := properties[constants.BUILD_PROPERTIES_PATTERN] if pattern == constants.EMPTY_STRING { diff --git a/src/arduino.cc/builder/ctags_target_file_saver.go b/src/arduino.cc/builder/ctags_target_file_saver.go index c98467ab..f6fe259a 100644 --- a/src/arduino.cc/builder/ctags_target_file_saver.go +++ b/src/arduino.cc/builder/ctags_target_file_saver.go @@ -32,31 +32,30 @@ package builder import ( "arduino.cc/builder/constants" "arduino.cc/builder/utils" - "io/ioutil" - "os" "path/filepath" ) type CTagsTargetFileSaver struct { - SourceField string + SourceField string + TargetFileName string } func (s *CTagsTargetFileSaver) Run(context map[string]interface{}) error { source := context[s.SourceField].(string) preprocPath := context[constants.CTX_PREPROC_PATH].(string) - err := os.MkdirAll(preprocPath, os.FileMode(0755)) + err := utils.EnsureFolderExists(preprocPath) if err != nil { return utils.WrapError(err) } - ctagsTargetFileName := filepath.Join(preprocPath, constants.FILE_CTAGS_TARGET) - err = ioutil.WriteFile(ctagsTargetFileName, []byte(source), os.FileMode(0644)) + ctagsTargetFilePath := filepath.Join(preprocPath, s.TargetFileName) + err = utils.WriteFile(ctagsTargetFilePath, source) if err != nil { return utils.WrapError(err) } - context[constants.CTX_CTAGS_TEMP_FILE_NAME] = ctagsTargetFileName + context[constants.CTX_CTAGS_TEMP_FILE_PATH] = ctagsTargetFilePath return nil } diff --git a/src/arduino.cc/builder/ctags_to_prototypes.go b/src/arduino.cc/builder/ctags_to_prototypes.go new file mode 100644 index 00000000..d8cde83b --- /dev/null +++ b/src/arduino.cc/builder/ctags_to_prototypes.go @@ -0,0 +1,124 @@ +/* + * This file is part of Arduino Builder. + * + * Arduino Builder is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + */ + +package builder + +import ( + "arduino.cc/builder/constants" + "arduino.cc/builder/types" + "strings" +) + +type CTagsToPrototypes struct{} + +func (s *CTagsToPrototypes) Run(context map[string]interface{}) error { + tags := context[constants.CTX_COLLECTED_CTAGS].([]*types.CTag) + + lineWhereToInsertPrototypes := findLineWhereToInsertPrototypes(tags) + if lineWhereToInsertPrototypes != -1 { + context[constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES] = lineWhereToInsertPrototypes + } + + prototypes := toPrototypes(tags) + context[constants.CTX_PROTOTYPES] = prototypes + + return nil +} + +func findLineWhereToInsertPrototypes(tags []*types.CTag) int { + firstFunctionLine := firstFunctionAtLine(tags) + firstFunctionPointerAsArgument := firstFunctionPointerUsedAsArgument(tags) + if firstFunctionLine != -1 && firstFunctionPointerAsArgument != -1 { + if firstFunctionLine < firstFunctionPointerAsArgument { + return firstFunctionLine + } else { + return firstFunctionPointerAsArgument + } + } else if firstFunctionLine == -1 { + return firstFunctionPointerAsArgument + } else { + return firstFunctionLine + } +} + +func firstFunctionPointerUsedAsArgument(tags []*types.CTag) int { + functionNames := collectFunctionNames(tags) + for _, tag := range tags { + if functionNameUsedAsFunctionPointerIn(tag, functionNames) { + return tag.Line + } + } + return -1 +} + +func functionNameUsedAsFunctionPointerIn(tag *types.CTag, functionNames []string) bool { + for _, functionName := range functionNames { + if strings.Index(tag.Code, "&"+functionName) != -1 { + return true + } + } + return false +} + +func collectFunctionNames(tags []*types.CTag) []string { + names := []string{} + for _, tag := range tags { + if tag.Kind == KIND_FUNCTION { + names = append(names, tag.FunctionName) + } + } + return names +} + +func firstFunctionAtLine(tags []*types.CTag) int { + for _, tag := range tags { + if !tagIsUnknown(tag) && isHandled(tag) && tag.Kind == KIND_FUNCTION { + return tag.Line + } + } + return -1 +} + +func toPrototypes(tags []*types.CTag) []*types.Prototype { + prototypes := []*types.Prototype{} + for _, tag := range tags { + if !tag.SkipMe { + prototype := &types.Prototype{ + FunctionName: tag.FunctionName, + File: tag.Filename, + Prototype: tag.Prototype, + Modifiers: tag.PrototypeModifiers, + Line: tag.Line, + //Fields: tag, + } + prototypes = append(prototypes, prototype) + } + } + return prototypes +} diff --git a/src/arduino.cc/builder/ensure_buildpath_exists.go b/src/arduino.cc/builder/ensure_buildpath_exists.go index 7f343c8b..d3fc6dc5 100644 --- a/src/arduino.cc/builder/ensure_buildpath_exists.go +++ b/src/arduino.cc/builder/ensure_buildpath_exists.go @@ -32,7 +32,6 @@ package builder import ( "arduino.cc/builder/constants" "arduino.cc/builder/utils" - "os" ) type EnsureBuildPathExists struct{} @@ -40,7 +39,7 @@ type EnsureBuildPathExists struct{} func (s *EnsureBuildPathExists) Run(context map[string]interface{}) error { buildPath := context[constants.CTX_BUILD_PATH].(string) - err := os.MkdirAll(buildPath, os.FileMode(0755)) + err := utils.EnsureFolderExists(buildPath) if err != nil { return utils.WrapError(err) } diff --git a/src/arduino.cc/builder/fail_if_imported_library_is_wrong.go b/src/arduino.cc/builder/fail_if_imported_library_is_wrong.go new file mode 100644 index 00000000..ab261996 --- /dev/null +++ b/src/arduino.cc/builder/fail_if_imported_library_is_wrong.go @@ -0,0 +1,70 @@ +/* + * This file is part of Arduino Builder. + * + * Arduino Builder is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + */ + +package builder + +import ( + "arduino.cc/builder/constants" + "arduino.cc/builder/i18n" + "arduino.cc/builder/types" + "arduino.cc/builder/utils" + "os" + "path/filepath" +) + +type FailIfImportedLibraryIsWrong struct{} + +func (s *FailIfImportedLibraryIsWrong) Run(context map[string]interface{}) error { + if !utils.MapHas(context, constants.CTX_IMPORTED_LIBRARIES) { + return nil + } + + logger := context[constants.CTX_LOGGER].(i18n.Logger) + importedLibraries := context[constants.CTX_IMPORTED_LIBRARIES].([]*types.Library) + + for _, library := range importedLibraries { + if !library.IsLegacy { + if stat, err := os.Stat(filepath.Join(library.Folder, constants.LIBRARY_FOLDER_ARCH)); err == nil && stat.IsDir() { + return utils.ErrorfWithLogger(logger, constants.MSG_ARCH_FOLDER_NOT_SUPPORTED) + } + for _, propName := range LIBRARY_MANDATORY_PROPERTIES { + if _, ok := library.Properties[propName]; !ok { + return utils.ErrorfWithLogger(logger, constants.MSG_PROP_IN_LIBRARY, propName, library.Folder) + } + } + if library.Layout == types.LIBRARY_RECURSIVE { + if stat, err := os.Stat(filepath.Join(library.Folder, constants.LIBRARY_FOLDER_UTILITY)); err == nil && stat.IsDir() { + return utils.ErrorfWithLogger(logger, constants.MSG_LIBRARY_CAN_USE_SRC_AND_UTILITY_FOLDERS, library.Folder) + } + } + } + } + + return nil +} diff --git a/src/arduino.cc/builder/gcc_minus_m_output_parser.go b/src/arduino.cc/builder/gcc_minus_m_output_parser.go index d9a2c6de..757181ca 100644 --- a/src/arduino.cc/builder/gcc_minus_m_output_parser.go +++ b/src/arduino.cc/builder/gcc_minus_m_output_parser.go @@ -60,12 +60,7 @@ func (s *GCCMinusMOutputParser) Run(context map[string]interface{}) error { return nil } - previousIncludes := utils.SliceToMapStringBool(context[constants.CTX_INCLUDES].([]string), true) - currentIncludes := utils.SliceToMapStringBool(includes, true) - - mergedIncludes := utils.MergeMapsOfStringBool(previousIncludes, currentIncludes) - - context[constants.CTX_INCLUDES] = utils.KeysOfMapOfStringBool(mergedIncludes) + context[constants.CTX_INCLUDES] = utils.AddStringsToStringsSet(context[constants.CTX_INCLUDES].([]string), includes) return nil } diff --git a/src/arduino.cc/builder/gcc_preproc_runner.go b/src/arduino.cc/builder/gcc_preproc_runner.go index b3b18d72..5c5b87d1 100644 --- a/src/arduino.cc/builder/gcc_preproc_runner.go +++ b/src/arduino.cc/builder/gcc_preproc_runner.go @@ -39,29 +39,73 @@ import ( "strings" ) -type GCCPreprocRunner struct{} +type GCCPreprocRunner struct { + TargetFileName string +} func (s *GCCPreprocRunner) Run(context map[string]interface{}) error { - buildProperties := utils.GetMapStringStringOrDefault(context, constants.CTX_BUILD_PROPERTIES) - properties := utils.MergeMapsOfStrings(make(map[string]string), buildProperties) - sketchBuildPath := context[constants.CTX_SKETCH_BUILD_PATH].(string) sketch := context[constants.CTX_SKETCH].(*types.Sketch) - properties[constants.BUILD_PROPERTIES_SOURCE_FILE] = filepath.Join(sketchBuildPath, filepath.Base(sketch.MainFile.Name)+".cpp") + properties, targetFilePath, err := prepareGCCPreprocRecipeProperties(context, filepath.Join(sketchBuildPath, filepath.Base(sketch.MainFile.Name)+".cpp"), s.TargetFileName) + if err != nil { + return utils.WrapError(err) + } - includes := context[constants.CTX_INCLUDE_FOLDERS].([]string) - includes = utils.Map(includes, utils.WrapWithHyphenI) - properties[constants.BUILD_PROPERTIES_INCLUDES] = strings.Join(includes, constants.SPACE) - builder_utils.RemoveHyphenMDDFlagFromGCCCommandLine(properties) + verbose := context[constants.CTX_VERBOSE].(bool) + logger := context[constants.CTX_LOGGER].(i18n.Logger) + _, err = builder_utils.ExecRecipe(properties, constants.RECIPE_PREPROC_MACROS, true, verbose, false, logger) + if err != nil { + return utils.WrapError(err) + } + + context[constants.CTX_FILE_PATH_TO_READ] = targetFilePath + + return nil +} + +type GCCPreprocRunnerForDiscoveringIncludes struct { + SourceFilePath string + TargetFilePath string +} + +func (s *GCCPreprocRunnerForDiscoveringIncludes) Run(context map[string]interface{}) error { + properties, _, err := prepareGCCPreprocRecipeProperties(context, s.SourceFilePath, s.TargetFilePath) + if err != nil { + return utils.WrapError(err) + } verbose := context[constants.CTX_VERBOSE].(bool) logger := context[constants.CTX_LOGGER].(i18n.Logger) - output, err := builder_utils.ExecRecipe(properties, constants.RECIPE_PREPROC_MACROS, true, verbose, false, logger) + stderr, err := builder_utils.ExecRecipeCollectStdErr(properties, constants.RECIPE_PREPROC_MACROS, true, verbose, false, logger) if err != nil { return utils.WrapError(err) } - context[constants.CTX_GCC_MINUS_E_SOURCE] = string(output) + context[constants.CTX_GCC_MINUS_E_SOURCE] = string(stderr) return nil } + +func prepareGCCPreprocRecipeProperties(context map[string]interface{}, sourceFilePath string, targetFilePath string) (map[string]string, string, error) { + if targetFilePath != utils.NULLFile() { + preprocPath := context[constants.CTX_PREPROC_PATH].(string) + err := utils.EnsureFolderExists(preprocPath) + if err != nil { + return nil, "", utils.WrapError(err) + } + targetFilePath = filepath.Join(preprocPath, targetFilePath) + } + + buildProperties := utils.GetMapStringStringOrDefault(context, constants.CTX_BUILD_PROPERTIES) + properties := utils.MergeMapsOfStrings(make(map[string]string), buildProperties) + + properties[constants.BUILD_PROPERTIES_SOURCE_FILE] = sourceFilePath + properties[constants.BUILD_PROPERTIES_PREPROCESSED_FILE_PATH] = targetFilePath + + includes := context[constants.CTX_INCLUDE_FOLDERS].([]string) + includes = utils.Map(includes, utils.WrapWithHyphenI) + properties[constants.BUILD_PROPERTIES_INCLUDES] = strings.Join(includes, constants.SPACE) + builder_utils.RemoveHyphenMDDFlagFromGCCCommandLine(properties) + + return properties, targetFilePath, nil +} diff --git a/src/arduino.cc/builder/gcc_preproc_source_saver.go b/src/arduino.cc/builder/gcc_preproc_source_saver.go index bdb1ac75..43d8e494 100644 --- a/src/arduino.cc/builder/gcc_preproc_source_saver.go +++ b/src/arduino.cc/builder/gcc_preproc_source_saver.go @@ -32,8 +32,6 @@ package builder import ( "arduino.cc/builder/constants" "arduino.cc/builder/utils" - "io/ioutil" - "os" "path/filepath" ) @@ -41,13 +39,13 @@ type GCCPreprocSourceSaver struct{} func (s *GCCPreprocSourceSaver) Run(context map[string]interface{}) error { preprocPath := context[constants.CTX_PREPROC_PATH].(string) - err := os.MkdirAll(preprocPath, os.FileMode(0755)) + err := utils.EnsureFolderExists(preprocPath) if err != nil { return utils.WrapError(err) } source := context[constants.CTX_SOURCE].(string) - err = ioutil.WriteFile(filepath.Join(preprocPath, constants.FILE_GCC_PREPROC_TARGET), []byte(source), os.FileMode(0644)) + err = utils.WriteFile(filepath.Join(preprocPath, constants.FILE_GCC_PREPROC_TARGET), source) return utils.WrapError(err) } diff --git a/src/arduino.cc/builder/generate_buildpath_if_missing.go b/src/arduino.cc/builder/generate_buildpath_if_missing.go index 89a3fb35..5a04272d 100644 --- a/src/arduino.cc/builder/generate_buildpath_if_missing.go +++ b/src/arduino.cc/builder/generate_buildpath_if_missing.go @@ -33,8 +33,6 @@ import ( "arduino.cc/builder/constants" "arduino.cc/builder/i18n" "arduino.cc/builder/utils" - "crypto/md5" - "encoding/hex" "os" "path/filepath" "strings" @@ -48,8 +46,7 @@ func (s *GenerateBuildPathIfMissing) Run(context map[string]interface{}) error { } sketchLocation := context[constants.CTX_SKETCH_LOCATION].(string) - md5sumBytes := md5.Sum([]byte(sketchLocation)) - md5sum := hex.EncodeToString(md5sumBytes[:]) + md5sum := utils.MD5Sum([]byte(sketchLocation)) buildPath := filepath.Join(os.TempDir(), "arduino-sketch-"+strings.ToUpper(md5sum)) _, err := os.Stat(buildPath) @@ -59,7 +56,7 @@ func (s *GenerateBuildPathIfMissing) Run(context map[string]interface{}) error { if utils.DebugLevel(context) > 5 { logger := context[constants.CTX_LOGGER].(i18n.Logger) - logger.Fprintln(os.Stderr, constants.MSG_SETTING_BUILD_PATH, buildPath) + logger.Fprintln(os.Stdout, constants.LOG_LEVEL_WARN, constants.MSG_SETTING_BUILD_PATH, buildPath) } context[constants.CTX_BUILD_PATH] = buildPath diff --git a/src/arduino.cc/builder/hardware/platform.keys.rewrite.txt b/src/arduino.cc/builder/hardware/platform.keys.rewrite.txt index fccaca39..4e8c93fb 100644 --- a/src/arduino.cc/builder/hardware/platform.keys.rewrite.txt +++ b/src/arduino.cc/builder/hardware/platform.keys.rewrite.txt @@ -36,3 +36,7 @@ new.10.recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} old.11.recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mmcu={build.mcu} -o "{build.path}/{build.project_name}.elf" {object_files} "{build.path}/{archive_file}" "-L{build.path}" -lm new.11.recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mmcu={build.mcu} -o "{build.path}/{build.project_name}.elf" {object_files} "{archive_file_path}" "-L{build.path}" -lm + +#generic again +old.12.recipe.preproc.macros="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} {preproc.macros.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" +new.12.recipe.preproc.macros="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} {preproc.macros.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{preprocessed_file_path}" \ No newline at end of file diff --git a/src/arduino.cc/builder/hardware/platform.txt b/src/arduino.cc/builder/hardware/platform.txt index c75396dc..8adc28a3 100644 --- a/src/arduino.cc/builder/hardware/platform.txt +++ b/src/arduino.cc/builder/hardware/platform.txt @@ -2,14 +2,15 @@ # ------------------------------ tools.ctags.path={runtime.tools.ctags.path} tools.ctags.cmd.path={path}/ctags -tools.ctags.pattern="{cmd.path}" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns "{source_file}" +tools.ctags.pattern="{cmd.path}" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives "{source_file}" # additional entries tools.avrdude.path={runtime.tools.avrdude.path} preproc.includes.flags=-w -x c++ -M -MG -MP -recipe.preproc.includes="{compiler.path}{compiler.cpp.cmd}" {preproc.includes.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" +preproc.includes.compatibility_flags={build.mbed_api_include} {build.nRF51822_api_include} {build.ble_api_include} {compiler.libsam.c.flags} {compiler.arm.cmsis.path} {build.variant_system_include} +recipe.preproc.includes="{compiler.path}{compiler.cpp.cmd}" {preproc.includes.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {preproc.includes.compatibility_flags} {includes} "{source_file}" preproc.macros.flags=-w -x c++ -E -CC preproc.macros.compatibility_flags={build.mbed_api_include} {build.nRF51822_api_include} {build.ble_api_include} {compiler.libsam.c.flags} {compiler.arm.cmsis.path} {build.variant_system_include} -recipe.preproc.macros="{compiler.path}{compiler.cpp.cmd}" {compiler.cpreprocessor.flags} {compiler.cpp.flags} {preproc.macros.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {preproc.macros.compatibility_flags} {includes} "{source_file}" +recipe.preproc.macros="{compiler.path}{compiler.cpp.cmd}" {compiler.cpreprocessor.flags} {compiler.cpp.flags} {preproc.macros.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {preproc.macros.compatibility_flags} {includes} "{source_file}" -o "{preprocessed_file_path}" diff --git a/src/arduino.cc/builder/i18n/i18n.go b/src/arduino.cc/builder/i18n/i18n.go index bfeff72a..2769e587 100644 --- a/src/arduino.cc/builder/i18n/i18n.go +++ b/src/arduino.cc/builder/i18n/i18n.go @@ -43,19 +43,29 @@ import ( var PLACEHOLDER = regexp.MustCompile("{(\\d)}") type Logger interface { - Fprintln(w io.Writer, format string, a ...interface{}) - Println(format string, a ...interface{}) + Fprintln(w io.Writer, level string, format string, a ...interface{}) + Println(level string, format string, a ...interface{}) Name() string } +type NoopLogger struct{} + +func (s NoopLogger) Fprintln(w io.Writer, level string, format string, a ...interface{}) {} + +func (s NoopLogger) Println(level string, format string, a ...interface{}) {} + +func (s NoopLogger) Name() string { + return "noop" +} + type HumanLogger struct{} -func (s HumanLogger) Fprintln(w io.Writer, format string, a ...interface{}) { +func (s HumanLogger) Fprintln(w io.Writer, level string, format string, a ...interface{}) { fmt.Fprintln(w, Format(format, a...)) } -func (s HumanLogger) Println(format string, a ...interface{}) { - s.Fprintln(os.Stdout, Format(format, a...)) +func (s HumanLogger) Println(level string, format string, a ...interface{}) { + s.Fprintln(os.Stdout, level, Format(format, a...)) } func (s HumanLogger) Name() string { @@ -64,7 +74,7 @@ func (s HumanLogger) Name() string { type MachineLogger struct{} -func (s MachineLogger) printWithoutFormatting(w io.Writer, format string, a []interface{}) { +func (s MachineLogger) printWithoutFormatting(w io.Writer, level string, format string, a []interface{}) { a = append([]interface{}(nil), a...) for idx, value := range a { typeof := reflect.Indirect(reflect.ValueOf(value)).Kind() @@ -72,16 +82,16 @@ func (s MachineLogger) printWithoutFormatting(w io.Writer, format string, a []in a[idx] = url.QueryEscape(value.(string)) } } - fmt.Fprintf(w, "===%s ||| %s", format, a) + fmt.Fprintf(w, "===%s ||| %s ||| %s", level, format, a) fmt.Fprintln(w) } -func (s MachineLogger) Fprintln(w io.Writer, format string, a ...interface{}) { - s.printWithoutFormatting(w, format, a) +func (s MachineLogger) Fprintln(w io.Writer, level string, format string, a ...interface{}) { + s.printWithoutFormatting(w, level, format, a) } -func (s MachineLogger) Println(format string, a ...interface{}) { - s.printWithoutFormatting(os.Stdout, format, a) +func (s MachineLogger) Println(level string, format string, a ...interface{}) { + s.printWithoutFormatting(os.Stdout, level, format, a) } func (s MachineLogger) Name() string { diff --git a/src/arduino.cc/builder/includes_finder_with_regexp.go b/src/arduino.cc/builder/includes_finder_with_regexp.go index 874454ef..6fa357a3 100644 --- a/src/arduino.cc/builder/includes_finder_with_regexp.go +++ b/src/arduino.cc/builder/includes_finder_with_regexp.go @@ -31,24 +31,34 @@ package builder import ( "arduino.cc/builder/constants" + "arduino.cc/builder/utils" "regexp" "strings" ) -var INCLUDE_REGEXP = regexp.MustCompile("(?ms)^\\s*#include\\s*[<\"](\\S+)[\">]") +var INCLUDE_REGEXP = regexp.MustCompile("(?ms)^\\s*#[ \t]*include\\s*[<\"](\\S+)[\">]") -type IncludesFinderWithRegExp struct{} +type IncludesFinderWithRegExp struct { + ContextField string +} func (s *IncludesFinderWithRegExp) Run(context map[string]interface{}) error { - source := context[constants.CTX_SOURCE].(string) + source := context[s.ContextField].(string) matches := INCLUDE_REGEXP.FindAllStringSubmatch(source, -1) - var includes []string + includes := []string{} for _, match := range matches { includes = append(includes, strings.TrimSpace(match[1])) } - context[constants.CTX_INCLUDES] = includes + context[constants.CTX_INCLUDES_JUST_FOUND] = includes + + if !utils.MapHas(context, constants.CTX_INCLUDES) { + context[constants.CTX_INCLUDES] = includes + return nil + } + + context[constants.CTX_INCLUDES] = utils.AddStringsToStringsSet(context[constants.CTX_INCLUDES].([]string), includes) return nil } diff --git a/src/arduino.cc/builder/libraries_loader.go b/src/arduino.cc/builder/libraries_loader.go index ef66412f..0c043801 100644 --- a/src/arduino.cc/builder/libraries_loader.go +++ b/src/arduino.cc/builder/libraries_loader.go @@ -129,15 +129,6 @@ func makeNewLibrary(libraryFolder string, debugLevel int, logger i18n.Logger) (* properties[constants.LIBRARY_MAINTAINER] = properties[constants.LIBRARY_EMAIL] } - if stat, err := os.Stat(filepath.Join(libraryFolder, constants.LIBRARY_FOLDER_ARCH)); err == nil && stat.IsDir() { - return nil, utils.ErrorfWithLogger(logger, constants.MSG_ARCH_FOLDER_NOT_SUPPORTED) - } - - for _, propName := range LIBRARY_MANDATORY_PROPERTIES { - if _, ok := properties[propName]; !ok { - return nil, utils.ErrorfWithLogger(logger, constants.MSG_PROP_IN_LIBRARY, propName, libraryFolder) - } - } for _, propName := range LIBRARY_NOT_SO_MANDATORY_PROPERTIES { if properties[propName] == constants.EMPTY_STRING { properties[propName] = "-" @@ -148,9 +139,6 @@ func makeNewLibrary(libraryFolder string, debugLevel int, logger i18n.Logger) (* if stat, err := os.Stat(filepath.Join(libraryFolder, constants.LIBRARY_FOLDER_SRC)); err == nil && stat.IsDir() { library.Layout = types.LIBRARY_RECURSIVE library.SrcFolder = filepath.Join(libraryFolder, constants.LIBRARY_FOLDER_SRC) - if stat, err := os.Stat(filepath.Join(libraryFolder, constants.LIBRARY_FOLDER_UTILITY)); err == nil && stat.IsDir() { - return nil, utils.ErrorfWithLogger(logger, constants.MSG_LIBRARY_CAN_USE_SRC_AND_UTILITY_FOLDERS) - } } else { library.Layout = types.LIBRARY_FLAT library.SrcFolder = libraryFolder @@ -164,7 +152,9 @@ func makeNewLibrary(libraryFolder string, debugLevel int, logger i18n.Logger) (* if debugLevel > 0 { for _, subFolder := range subFolders { if utils.IsSCCSOrHiddenFile(subFolder) { - logger.Fprintln(os.Stderr, constants.MSG_WARNING_SPURIOUS_FILE_IN_LIB, filepath.Base(subFolder.Name()), properties[constants.LIBRARY_NAME]) + if !utils.IsSCCSFile(subFolder) && utils.IsHiddenFile(subFolder) { + logger.Fprintln(os.Stdout, constants.LOG_LEVEL_WARN, constants.MSG_WARNING_SPURIOUS_FILE_IN_LIB, filepath.Base(subFolder.Name()), properties[constants.LIBRARY_NAME]) + } } } } @@ -179,7 +169,7 @@ func makeNewLibrary(libraryFolder string, debugLevel int, logger i18n.Logger) (* properties[constants.LIBRARY_CATEGORY] = strings.TrimSpace(properties[constants.LIBRARY_CATEGORY]) if !LIBRARY_CATEGORIES[properties[constants.LIBRARY_CATEGORY]] { - logger.Fprintln(os.Stderr, constants.MSG_WARNING_LIB_INVALID_CATEGORY, properties[constants.LIBRARY_CATEGORY], properties[constants.LIBRARY_NAME], constants.LIB_CATEGORY_UNCATEGORIZED) + logger.Fprintln(os.Stdout, constants.LOG_LEVEL_WARN, constants.MSG_WARNING_LIB_INVALID_CATEGORY, properties[constants.LIBRARY_CATEGORY], properties[constants.LIBRARY_NAME], constants.LIB_CATEGORY_UNCATEGORIZED) properties[constants.LIBRARY_CATEGORY] = constants.LIB_CATEGORY_UNCATEGORIZED } library.Category = properties[constants.LIBRARY_CATEGORY] @@ -199,6 +189,7 @@ func makeNewLibrary(libraryFolder string, debugLevel int, logger i18n.Logger) (* library.URL = strings.TrimSpace(properties[constants.LIBRARY_URL]) library.IsLegacy = false library.DotALinkage = strings.TrimSpace(properties[constants.LIBRARY_DOT_A_LINKAGE]) == "true" + library.Properties = properties return library, nil } diff --git a/src/arduino.cc/builder/merge_sketch_with_bootloader.go b/src/arduino.cc/builder/merge_sketch_with_bootloader.go index 69fbfbc8..0d73afc4 100644 --- a/src/arduino.cc/builder/merge_sketch_with_bootloader.go +++ b/src/arduino.cc/builder/merge_sketch_with_bootloader.go @@ -32,9 +32,9 @@ package builder import ( "arduino.cc/builder/constants" "arduino.cc/builder/i18n" + "arduino.cc/builder/props" "arduino.cc/builder/types" "arduino.cc/builder/utils" - "io/ioutil" "os" "path/filepath" "strings" @@ -71,10 +71,11 @@ func (s *MergeSketchWithBootloader) Run(context map[string]interface{}) error { } else { bootloader = buildProperties[constants.BUILD_PROPERTIES_BOOTLOADER_FILE] } + bootloader = props.ExpandPropsInString(buildProperties, bootloader) bootloaderPath := filepath.Join(buildProperties[constants.BUILD_PROPERTIES_RUNTIME_PLATFORM_PATH], constants.FOLDER_BOOTLOADERS, bootloader) if _, err := os.Stat(bootloaderPath); err != nil { - logger.Fprintln(os.Stderr, constants.MSG_BOOTLOADER_FILE_MISSING, bootloaderPath) + logger.Fprintln(os.Stdout, constants.LOG_LEVEL_WARN, constants.MSG_BOOTLOADER_FILE_MISSING, bootloaderPath) return nil } @@ -101,5 +102,5 @@ func merge(builtSketchPath, bootloaderPath, mergedSketchPath string) error { sketch = append(sketch, row) } - return ioutil.WriteFile(mergedSketchPath, []byte(strings.Join(sketch, "\n")), os.FileMode(0644)) + return utils.WriteFile(mergedSketchPath, strings.Join(sketch, "\n")) } diff --git a/src/arduino.cc/builder/phases/core_builder.go b/src/arduino.cc/builder/phases/core_builder.go index 67a44f4d..cf1c761d 100644 --- a/src/arduino.cc/builder/phases/core_builder.go +++ b/src/arduino.cc/builder/phases/core_builder.go @@ -34,7 +34,6 @@ import ( "arduino.cc/builder/constants" "arduino.cc/builder/i18n" "arduino.cc/builder/utils" - "os" ) type CoreBuilder struct{} @@ -46,26 +45,27 @@ func (s *CoreBuilder) Run(context map[string]interface{}) error { warningsLevel := context[constants.CTX_WARNINGS_LEVEL].(string) logger := context[constants.CTX_LOGGER].(i18n.Logger) - err := os.MkdirAll(coreBuildPath, os.FileMode(0755)) + err := utils.EnsureFolderExists(coreBuildPath) if err != nil { return utils.WrapError(err) } - archiveFile, err := compileCore(coreBuildPath, buildProperties, verbose, warningsLevel, logger) + archiveFile, objectFiles, err := compileCore(coreBuildPath, buildProperties, verbose, warningsLevel, logger) if err != nil { return utils.WrapError(err) } context[constants.CTX_ARCHIVE_FILE_PATH_CORE] = archiveFile + context[constants.CTX_OBJECT_FILES_CORE] = objectFiles return nil } -func compileCore(buildPath string, buildProperties map[string]string, verbose bool, warningsLevel string, logger i18n.Logger) (string, error) { +func compileCore(buildPath string, buildProperties map[string]string, verbose bool, warningsLevel string, logger i18n.Logger) (string, []string, error) { coreFolder := buildProperties[constants.BUILD_PROPERTIES_BUILD_CORE_PATH] variantFolder := buildProperties[constants.BUILD_PROPERTIES_BUILD_VARIANT_PATH] - var includes []string + includes := []string{} includes = append(includes, coreFolder) if variantFolder != constants.EMPTY_STRING { includes = append(includes, variantFolder) @@ -74,25 +74,23 @@ func compileCore(buildPath string, buildProperties map[string]string, verbose bo var err error - var variantObjectFiles []string + variantObjectFiles := []string{} if variantFolder != constants.EMPTY_STRING { variantObjectFiles, err = builder_utils.CompileFiles(variantObjectFiles, variantFolder, true, buildPath, buildProperties, includes, verbose, warningsLevel, logger) if err != nil { - return "", utils.WrapError(err) + return "", nil, utils.WrapError(err) } } coreObjectFiles, err := builder_utils.CompileFiles([]string{}, coreFolder, true, buildPath, buildProperties, includes, verbose, warningsLevel, logger) if err != nil { - return "", utils.WrapError(err) + return "", nil, utils.WrapError(err) } - objectFiles := append(coreObjectFiles, variantObjectFiles...) - - archiveFile, err := builder_utils.ArchiveCompiledFiles(buildPath, "core.a", objectFiles, buildProperties, verbose, logger) + archiveFile, err := builder_utils.ArchiveCompiledFiles(buildPath, "core.a", coreObjectFiles, buildProperties, verbose, logger) if err != nil { - return "", utils.WrapError(err) + return "", nil, utils.WrapError(err) } - return archiveFile, nil + return archiveFile, variantObjectFiles, nil } diff --git a/src/arduino.cc/builder/phases/libraries_builder.go b/src/arduino.cc/builder/phases/libraries_builder.go index fd8753de..bb01f8e8 100644 --- a/src/arduino.cc/builder/phases/libraries_builder.go +++ b/src/arduino.cc/builder/phases/libraries_builder.go @@ -51,7 +51,7 @@ func (s *LibrariesBuilder) Run(context map[string]interface{}) error { warningsLevel := context[constants.CTX_WARNINGS_LEVEL].(string) logger := context[constants.CTX_LOGGER].(i18n.Logger) - err := os.MkdirAll(librariesBuildPath, os.FileMode(0755)) + err := utils.EnsureFolderExists(librariesBuildPath) if err != nil { return utils.WrapError(err) } @@ -83,7 +83,7 @@ func compileLibraries(libraries []*types.Library, buildPath string, buildPropert func compileLibrary(library *types.Library, buildPath string, buildProperties map[string]string, includes []string, verbose bool, warningsLevel string, logger i18n.Logger) ([]string, error) { libraryBuildPath := filepath.Join(buildPath, library.Name) - err := os.MkdirAll(libraryBuildPath, os.FileMode(0755)) + err := utils.EnsureFolderExists(libraryBuildPath) if err != nil { return nil, utils.WrapError(err) } diff --git a/src/arduino.cc/builder/phases/linker.go b/src/arduino.cc/builder/phases/linker.go index 347f9959..7b9fd319 100644 --- a/src/arduino.cc/builder/phases/linker.go +++ b/src/arduino.cc/builder/phases/linker.go @@ -43,10 +43,12 @@ type Linker struct{} func (s *Linker) Run(context map[string]interface{}) error { objectFilesSketch := context[constants.CTX_OBJECT_FILES_SKETCH].([]string) objectFilesLibraries := context[constants.CTX_OBJECT_FILES_LIBRARIES].([]string) + objectFilesCore := context[constants.CTX_OBJECT_FILES_CORE].([]string) var objectFiles []string objectFiles = append(objectFiles, objectFilesSketch...) objectFiles = append(objectFiles, objectFilesLibraries...) + objectFiles = append(objectFiles, objectFilesCore...) coreArchiveFilePath := context[constants.CTX_ARCHIVE_FILE_PATH_CORE].(string) buildPath := context[constants.CTX_BUILD_PATH].(string) diff --git a/src/arduino.cc/builder/phases/sketch_builder.go b/src/arduino.cc/builder/phases/sketch_builder.go index e5f70ac9..27d26d59 100644 --- a/src/arduino.cc/builder/phases/sketch_builder.go +++ b/src/arduino.cc/builder/phases/sketch_builder.go @@ -34,7 +34,6 @@ import ( "arduino.cc/builder/constants" "arduino.cc/builder/i18n" "arduino.cc/builder/utils" - "os" ) type SketchBuilder struct{} @@ -48,13 +47,13 @@ func (s *SketchBuilder) Run(context map[string]interface{}) error { warningsLevel := context[constants.CTX_WARNINGS_LEVEL].(string) logger := context[constants.CTX_LOGGER].(i18n.Logger) - err := os.MkdirAll(sketchBuildPath, os.FileMode(0755)) + err := utils.EnsureFolderExists(sketchBuildPath) if err != nil { return utils.WrapError(err) } var objectFiles []string - objectFiles, err = builder_utils.CompileFiles(objectFiles, sketchBuildPath, false, sketchBuildPath, buildProperties, includes, verbose, warningsLevel, logger) + objectFiles, err = builder_utils.CompileFiles(objectFiles, sketchBuildPath, true, sketchBuildPath, buildProperties, includes, verbose, warningsLevel, logger) if err != nil { return utils.WrapError(err) } diff --git a/src/arduino.cc/builder/print_preprocessed_source.go b/src/arduino.cc/builder/print_preprocessed_source.go new file mode 100644 index 00000000..5a444d10 --- /dev/null +++ b/src/arduino.cc/builder/print_preprocessed_source.go @@ -0,0 +1,45 @@ +/* + * This file is part of Arduino Builder. + * + * Arduino Builder is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + */ + +package builder + +import ( + "arduino.cc/builder/constants" + "fmt" +) + +type PrintPreprocessedSource struct{} + +func (s *PrintPreprocessedSource) Run(context map[string]interface{}) error { + source := context[constants.CTX_GCC_MINUS_E_SOURCE].(string) + + fmt.Println(source) + + return nil +} diff --git a/src/arduino.cc/builder/print_used_and_not_used_libraries.go b/src/arduino.cc/builder/print_used_and_not_used_libraries.go index 88cbfbd3..7979e6b6 100644 --- a/src/arduino.cc/builder/print_used_and_not_used_libraries.go +++ b/src/arduino.cc/builder/print_used_and_not_used_libraries.go @@ -50,10 +50,10 @@ func (s *PrintUsedAndNotUsedLibraries) Run(context map[string]interface{}) error for header, libResResult := range libraryResolutionResults { if !libResResult.IsLibraryFromPlatform { - logger.Fprintln(os.Stderr, constants.MSG_LIBRARIES_MULTIPLE_LIBS_FOUND_FOR, header) - logger.Fprintln(os.Stderr, constants.MSG_LIBRARIES_USED, libResResult.Library.Folder) + logger.Fprintln(os.Stdout, constants.LOG_LEVEL_WARN, constants.MSG_LIBRARIES_MULTIPLE_LIBS_FOUND_FOR, header) + logger.Fprintln(os.Stdout, constants.LOG_LEVEL_WARN, constants.MSG_LIBRARIES_USED, libResResult.Library.Folder) for _, notUsedLibrary := range libResResult.NotUsedLibraries { - logger.Fprintln(os.Stderr, constants.MSG_LIBRARIES_NOT_USED, notUsedLibrary.Folder) + logger.Fprintln(os.Stdout, constants.LOG_LEVEL_WARN, constants.MSG_LIBRARIES_NOT_USED, notUsedLibrary.Folder) } } } diff --git a/src/arduino.cc/builder/print_used_libraries_if_verbose.go b/src/arduino.cc/builder/print_used_libraries_if_verbose.go index 20c96965..c3528a1a 100644 --- a/src/arduino.cc/builder/print_used_libraries_if_verbose.go +++ b/src/arduino.cc/builder/print_used_libraries_if_verbose.go @@ -33,6 +33,7 @@ import ( "arduino.cc/builder/constants" "arduino.cc/builder/i18n" "arduino.cc/builder/types" + "arduino.cc/builder/utils" "time" ) @@ -42,7 +43,7 @@ func (s *PrintUsedLibrariesIfVerbose) Run(context map[string]interface{}) error verbose := context[constants.CTX_VERBOSE].(bool) logger := context[constants.CTX_LOGGER].(i18n.Logger) - if !verbose { + if !verbose || !utils.MapHas(context, constants.CTX_IMPORTED_LIBRARIES) { return nil } @@ -54,9 +55,9 @@ func (s *PrintUsedLibrariesIfVerbose) Run(context map[string]interface{}) error legacy = constants.MSG_LIB_LEGACY } if library.Version == constants.EMPTY_STRING { - logger.Println(constants.MSG_USING_LIBRARY, library.Name, library.Folder, legacy) + logger.Println(constants.LOG_LEVEL_INFO, constants.MSG_USING_LIBRARY, library.Name, library.Folder, legacy) } else { - logger.Println(constants.MSG_USING_LIBRARY_AT_VERSION, library.Name, library.Version, library.Folder, legacy) + logger.Println(constants.LOG_LEVEL_INFO, constants.MSG_USING_LIBRARY_AT_VERSION, library.Name, library.Version, library.Folder, legacy) } } diff --git a/src/arduino.cc/builder/prototypes_adder.go b/src/arduino.cc/builder/prototypes_adder.go index d550f239..fe58c8b5 100644 --- a/src/arduino.cc/builder/prototypes_adder.go +++ b/src/arduino.cc/builder/prototypes_adder.go @@ -43,27 +43,20 @@ func (s *PrototypesAdder) Run(context map[string]interface{}) error { source := context[constants.CTX_SOURCE].(string) sourceRows := strings.Split(source, "\n") - if !utils.MapHas(context, constants.CTX_FIRST_FUNCTION_AT_LINE) { + if !utils.MapHas(context, constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES) { return nil } - firstFunctionLine := context[constants.CTX_FIRST_FUNCTION_AT_LINE].(int) + firstFunctionLine := context[constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES].(int) if firstFunctionOutsideOfSource(firstFunctionLine, sourceRows) { return nil } - firstFunctionChar := len(strings.Join(sourceRows[:firstFunctionLine-1], "\n")) + 1 - if firstFunctionLine > 1 { - firstFunctionLine -= context[constants.CTX_LINE_OFFSET].(int) - } + firstFunctionChar := len(strings.Join(sourceRows[:firstFunctionLine+context[constants.CTX_LINE_OFFSET].(int)-1], "\n")) + 1 prototypeSection := composePrototypeSection(firstFunctionLine, context[constants.CTX_PROTOTYPES].([]*types.Prototype)) context[constants.CTX_PROTOTYPE_SECTION] = prototypeSection source = source[:firstFunctionChar] + prototypeSection + source[firstFunctionChar:] - includeSection := composeIncludeArduinoSection() - context[constants.CTX_INCLUDE_SECTION] = includeSection - source = includeSection + source - context[constants.CTX_SOURCE] = source return nil @@ -75,7 +68,7 @@ func composePrototypeSection(line int, prototypes []*types.Prototype) string { } str := joinPrototypes(prototypes) - str += "#line " + str += "\n#line " str += strconv.Itoa(line) str += "\n" @@ -83,18 +76,17 @@ func composePrototypeSection(line int, prototypes []*types.Prototype) string { } func joinPrototypes(prototypes []*types.Prototype) string { - join := "" + prototypesSlice := []string{} for _, proto := range prototypes { - join = join + proto.Prototype + "\n" + prototypesSlice = append(prototypesSlice, "#line "+strconv.Itoa(proto.Line)+" \""+proto.File+"\"") + prototypeParts := []string{} + if proto.Modifiers != "" { + prototypeParts = append(prototypeParts, proto.Modifiers) + } + prototypeParts = append(prototypeParts, proto.Prototype) + prototypesSlice = append(prototypesSlice, strings.Join(prototypeParts, " ")) } - return join -} - -func composeIncludeArduinoSection() string { - str := "#include \n" - str += "#line 1\n" - - return str + return strings.Join(prototypesSlice, "\n") } func firstFunctionOutsideOfSource(firstFunctionLine int, sourceRows []string) bool { diff --git a/src/arduino.cc/builder/read_file_and_store_in_context.go b/src/arduino.cc/builder/read_file_and_store_in_context.go new file mode 100644 index 00000000..03eaa2a9 --- /dev/null +++ b/src/arduino.cc/builder/read_file_and_store_in_context.go @@ -0,0 +1,51 @@ +/* + * This file is part of Arduino Builder. + * + * Arduino Builder is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + */ + +package builder + +import ( + "arduino.cc/builder/constants" + "arduino.cc/builder/utils" + "io/ioutil" +) + +type ReadFileAndStoreInContext struct { + TargetField string +} + +func (s *ReadFileAndStoreInContext) Run(context map[string]interface{}) error { + bytes, err := ioutil.ReadFile(context[constants.CTX_FILE_PATH_TO_READ].(string)) + if err != nil { + return utils.WrapError(err) + } + + context[s.TargetField] = string(bytes) + + return nil +} diff --git a/src/arduino.cc/builder/recipe_runner.go b/src/arduino.cc/builder/recipe_runner.go index 706528d3..05d3920d 100644 --- a/src/arduino.cc/builder/recipe_runner.go +++ b/src/arduino.cc/builder/recipe_runner.go @@ -47,7 +47,7 @@ type RecipeByPrefixSuffixRunner struct { func (s *RecipeByPrefixSuffixRunner) Run(context map[string]interface{}) error { logger := context[constants.CTX_LOGGER].(i18n.Logger) if utils.DebugLevel(context) >= 10 { - logger.Fprintln(os.Stderr, constants.MSG_LOOKING_FOR_RECIPES, s.Prefix, s.Suffix) + logger.Fprintln(os.Stdout, constants.LOG_LEVEL_DEBUG, constants.MSG_LOOKING_FOR_RECIPES, s.Prefix, s.Suffix) } buildProperties := utils.GetMapStringStringOrDefault(context, constants.CTX_BUILD_PROPERTIES) @@ -58,7 +58,7 @@ func (s *RecipeByPrefixSuffixRunner) Run(context map[string]interface{}) error { properties := utils.MergeMapsOfStrings(make(map[string]string), buildProperties) for _, recipe := range recipes { if utils.DebugLevel(context) >= 10 { - logger.Fprintln(os.Stderr, constants.MSG_RUNNING_RECIPE, recipe) + logger.Fprintln(os.Stdout, constants.LOG_LEVEL_DEBUG, constants.MSG_RUNNING_RECIPE, recipe) } _, err := builder_utils.ExecRecipe(properties, recipe, false, verbose, verbose, logger) if err != nil { diff --git a/src/arduino.cc/builder/rewrite_hardware_keys.go b/src/arduino.cc/builder/rewrite_hardware_keys.go index 042254f4..b027165a 100644 --- a/src/arduino.cc/builder/rewrite_hardware_keys.go +++ b/src/arduino.cc/builder/rewrite_hardware_keys.go @@ -31,10 +31,8 @@ package builder import ( "arduino.cc/builder/constants" - "arduino.cc/builder/i18n" "arduino.cc/builder/types" "arduino.cc/builder/utils" - "os" ) type RewriteHardwareKeys struct{} @@ -46,9 +44,7 @@ func (s *RewriteHardwareKeys) Run(context map[string]interface{}) error { packages := context[constants.CTX_HARDWARE].(*types.Packages) platformKeysRewrite := context[constants.CTX_PLATFORM_KEYS_REWRITE].(types.PlatforKeysRewrite) - logger := context[constants.CTX_LOGGER].(i18n.Logger) - - warn := utils.DebugLevel(context) > 0 + hardwareRewriteResults := context[constants.CTX_HARDWARE_REWRITE_RESULTS].(map[*types.Platform][]types.PlatforKeyRewrite) for _, aPackage := range packages.Packages { for _, platform := range aPackage.Platforms { @@ -56,9 +52,9 @@ func (s *RewriteHardwareKeys) Run(context map[string]interface{}) error { for _, rewrite := range platformKeysRewrite.Rewrites { if platform.Properties[rewrite.Key] != constants.EMPTY_STRING && platform.Properties[rewrite.Key] == rewrite.OldValue { platform.Properties[rewrite.Key] = rewrite.NewValue - if warn { - logger.Fprintln(os.Stderr, constants.MSG_WARNING_PLATFORM_OLD_VALUES, platform.Properties[constants.PLATFORM_NAME], rewrite.Key+"="+rewrite.OldValue, rewrite.Key+"="+rewrite.NewValue) - } + appliedRewrites := rewritesAppliedToPlatform(platform, hardwareRewriteResults) + appliedRewrites = append(appliedRewrites, rewrite) + hardwareRewriteResults[platform] = appliedRewrites } } } @@ -67,3 +63,10 @@ func (s *RewriteHardwareKeys) Run(context map[string]interface{}) error { return nil } + +func rewritesAppliedToPlatform(platform *types.Platform, hardwareRewriteResults map[*types.Platform][]types.PlatforKeyRewrite) []types.PlatforKeyRewrite { + if hardwareRewriteResults[platform] == nil { + hardwareRewriteResults[platform] = []types.PlatforKeyRewrite{} + } + return hardwareRewriteResults[platform] +} diff --git a/src/arduino.cc/builder/sketch_loader.go b/src/arduino.cc/builder/sketch_loader.go index 62ffd655..2c2ec10c 100644 --- a/src/arduino.cc/builder/sketch_loader.go +++ b/src/arduino.cc/builder/sketch_loader.go @@ -87,8 +87,10 @@ func (s *SketchLoader) Run(context map[string]interface{}) error { func collectAllSketchFiles(from string) ([]string, error) { filePaths := []string{} - checkExtensionFunc := func(ext string) bool { - return MAIN_FILE_VALID_EXTENSIONS[ext] || ADDITIONAL_FILE_VALID_EXTENSIONS[ext] + checkExtensionFunc := func(filePath string) bool { + name := filepath.Base(filePath) + ext := strings.ToLower(filepath.Ext(filePath)) + return !strings.HasPrefix(name, ".") && MAIN_FILE_VALID_EXTENSIONS[ext] || ADDITIONAL_FILE_VALID_EXTENSIONS[ext] } walkFunc := utils.CollectAllReadableFiles(&filePaths, checkExtensionFunc) err := gohasissues.Walk(from, walkFunc) diff --git a/src/arduino.cc/builder/sketch_saver.go b/src/arduino.cc/builder/sketch_saver.go index 01f10ae4..1a6bfb57 100644 --- a/src/arduino.cc/builder/sketch_saver.go +++ b/src/arduino.cc/builder/sketch_saver.go @@ -33,8 +33,6 @@ import ( "arduino.cc/builder/constants" "arduino.cc/builder/types" "arduino.cc/builder/utils" - "io/ioutil" - "os" "path/filepath" ) @@ -45,11 +43,11 @@ func (s *SketchSaver) Run(context map[string]interface{}) error { sketchBuildPath := context[constants.CTX_SKETCH_BUILD_PATH].(string) source := context[constants.CTX_SOURCE].(string) - err := os.MkdirAll(sketchBuildPath, os.FileMode(0755)) + err := utils.EnsureFolderExists(sketchBuildPath) if err != nil { return utils.WrapError(err) } - err = ioutil.WriteFile(filepath.Join(sketchBuildPath, filepath.Base(sketch.MainFile.Name)+".cpp"), []byte(source), os.FileMode(0644)) + err = utils.WriteFile(filepath.Join(sketchBuildPath, filepath.Base(sketch.MainFile.Name)+".cpp"), source) return utils.WrapError(err) } diff --git a/src/arduino.cc/builder/sketch_source_merger.go b/src/arduino.cc/builder/sketch_source_merger.go index 197ecb92..1e99a57f 100644 --- a/src/arduino.cc/builder/sketch_source_merger.go +++ b/src/arduino.cc/builder/sketch_source_merger.go @@ -41,21 +41,35 @@ type SketchSourceMerger struct{} func (s *SketchSourceMerger) Run(context map[string]interface{}) error { sketch := context[constants.CTX_SKETCH].(*types.Sketch) - source := addPreprocLine(&sketch.MainFile) + lineOffset := 0 + includeSection := composeIncludeArduinoSection() + lineOffset += 2 + context[constants.CTX_INCLUDE_SECTION] = includeSection + + source := includeSection + source += addSourceWrappedWithLineDirective(&sketch.MainFile) + lineOffset += 1 for _, file := range sketch.OtherSketchFiles { - source += addPreprocLine(&file) + source += addSourceWrappedWithLineDirective(&file) } - context[constants.CTX_LINE_OFFSET] = 1 + context[constants.CTX_LINE_OFFSET] = lineOffset context[constants.CTX_SOURCE] = source return nil } -func addPreprocLine(sketch *types.SketchFile) string { +func addSourceWrappedWithLineDirective(sketch *types.SketchFile) string { source := "#line 1 \"" + strings.Replace(sketch.Name, "\\", "\\\\", -1) + "\"\n" source += sketch.Source source += "\n" return source } + +func composeIncludeArduinoSection() string { + str := "#include \n" + str += "#line 1\n" + + return str +} diff --git a/src/arduino.cc/builder/store_build_options_map.go b/src/arduino.cc/builder/store_build_options_map.go index a0d221ec..4e2172a4 100644 --- a/src/arduino.cc/builder/store_build_options_map.go +++ b/src/arduino.cc/builder/store_build_options_map.go @@ -31,8 +31,7 @@ package builder import ( "arduino.cc/builder/constants" - "io/ioutil" - "os" + "arduino.cc/builder/utils" "path/filepath" ) @@ -42,7 +41,7 @@ func (s *StoreBuildOptionsMap) Run(context map[string]interface{}) error { buildPath := context[constants.CTX_BUILD_PATH].(string) buildOptionsJson := context[constants.CTX_BUILD_OPTIONS_JSON].(string) - ioutil.WriteFile(filepath.Join(buildPath, constants.BUILD_OPTIONS_FILE), []byte(buildOptionsJson), os.FileMode(0644)) + utils.WriteFile(filepath.Join(buildPath, constants.BUILD_OPTIONS_FILE), buildOptionsJson) return nil } diff --git a/src/arduino.cc/builder/target_board_resolver.go b/src/arduino.cc/builder/target_board_resolver.go index d34409e9..fc67917d 100644 --- a/src/arduino.cc/builder/target_board_resolver.go +++ b/src/arduino.cc/builder/target_board_resolver.go @@ -68,15 +68,15 @@ func (s *TargetBoardResolver) Run(context map[string]interface{}) error { context[constants.CTX_TARGET_PLATFORM] = targetPlatform context[constants.CTX_TARGET_BOARD] = targetBoard + if len(fqbnParts) > 3 { + addAdditionalPropertiesToTargetBoard(targetBoard, fqbnParts[3]) + } + core := targetBoard.Properties[constants.BUILD_PROPERTIES_BUILD_CORE] if core == constants.EMPTY_STRING { core = DEFAULT_BUILD_CORE } - if len(fqbnParts) > 3 { - addAdditionalPropertiesToTargetBoard(targetBoard, fqbnParts[3]) - } - var corePlatform *types.Platform coreParts := strings.Split(core, ":") if len(coreParts) > 1 { diff --git a/src/arduino.cc/builder/test/add_additional_entries_to_context_test.go b/src/arduino.cc/builder/test/add_additional_entries_to_context_test.go index 7001a01e..416f5335 100644 --- a/src/arduino.cc/builder/test/add_additional_entries_to_context_test.go +++ b/src/arduino.cc/builder/test/add_additional_entries_to_context_test.go @@ -52,7 +52,6 @@ func TestAddAdditionalEntriesToContextNoBuildPath(t *testing.T) { require.NotNil(t, context[constants.CTX_WARNINGS_LEVEL]) require.NotNil(t, context[constants.CTX_VERBOSE]) require.NotNil(t, context[constants.CTX_DEBUG_LEVEL]) - require.NotNil(t, context[constants.CTX_LIBRARY_DISCOVERY_RECURSION_DEPTH]) require.True(t, context[constants.CTX_COLLECTED_SOURCE_FILES_QUEUE].(*types.UniqueStringQueue).Empty()) require.True(t, context[constants.CTX_FOLDERS_WITH_SOURCES_QUEUE].(*types.UniqueSourceFolderQueue).Empty()) @@ -76,7 +75,6 @@ func TestAddAdditionalEntriesToContextWithBuildPath(t *testing.T) { require.NotNil(t, context[constants.CTX_WARNINGS_LEVEL]) require.NotNil(t, context[constants.CTX_VERBOSE]) require.NotNil(t, context[constants.CTX_DEBUG_LEVEL]) - require.NotNil(t, context[constants.CTX_LIBRARY_DISCOVERY_RECURSION_DEPTH]) require.True(t, context[constants.CTX_COLLECTED_SOURCE_FILES_QUEUE].(*types.UniqueStringQueue).Empty()) require.True(t, context[constants.CTX_FOLDERS_WITH_SOURCES_QUEUE].(*types.UniqueSourceFolderQueue).Empty()) diff --git a/src/arduino.cc/builder/test/additional_sketch_files_copier_test.go b/src/arduino.cc/builder/test/additional_sketch_files_copier_test.go index 2659ea71..326f6d77 100644 --- a/src/arduino.cc/builder/test/additional_sketch_files_copier_test.go +++ b/src/arduino.cc/builder/test/additional_sketch_files_copier_test.go @@ -39,6 +39,7 @@ import ( "path/filepath" "sort" "testing" + "time" ) type ByFileInfoName []os.FileInfo @@ -78,14 +79,55 @@ func TestCopyOtherFiles(t *testing.T) { files, err1 := gohasissues.ReadDir(filepath.Join(buildPath, constants.FOLDER_SKETCH)) NoError(t, err1) - require.Equal(t, 2, len(files)) + require.Equal(t, 3, len(files)) sort.Sort(ByFileInfoName(files)) require.Equal(t, "header.h", files[0].Name()) - require.Equal(t, "subfolder", files[1].Name()) + require.Equal(t, "s_file.S", files[1].Name()) + require.Equal(t, "subfolder", files[2].Name()) files, err1 = gohasissues.ReadDir(filepath.Join(buildPath, constants.FOLDER_SKETCH, "subfolder")) NoError(t, err1) require.Equal(t, 1, len(files)) require.Equal(t, "helper.h", files[0].Name()) } + +func TestCopyOtherFilesOnlyIfChanged(t *testing.T) { + context := make(map[string]interface{}) + + buildPath := SetupBuildPath(t, context) + defer os.RemoveAll(buildPath) + + context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch1", "sketch.ino") + + commands := []types.Command{ + &builder.SetupHumanLoggerIfMissing{}, + &builder.AddAdditionalEntriesToContext{}, + &builder.SketchLoader{}, + &builder.AdditionalSketchFilesCopier{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + headerStatBefore, err := os.Stat(filepath.Join(buildPath, constants.FOLDER_SKETCH, "header.h")) + NoError(t, err) + + time.Sleep(2 * time.Second) + + context = make(map[string]interface{}) + context[constants.CTX_BUILD_PATH] = buildPath + context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch1", "sketch.ino") + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + headerStatAfter, err := os.Stat(filepath.Join(buildPath, constants.FOLDER_SKETCH, "header.h")) + NoError(t, err) + + require.Equal(t, headerStatBefore.ModTime().Unix(), headerStatAfter.ModTime().Unix()) +} diff --git a/src/arduino.cc/builder/test/builder_test.go b/src/arduino.cc/builder/test/builder_test.go index eab664be..3ec2c459 100644 --- a/src/arduino.cc/builder/test/builder_test.go +++ b/src/arduino.cc/builder/test/builder_test.go @@ -34,6 +34,7 @@ import ( "arduino.cc/builder/constants" "github.com/stretchr/testify/require" "os" + "os/exec" "path/filepath" "testing" ) @@ -53,8 +54,8 @@ func TestBuilderEmptySketch(t *testing.T) { context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" - // context[constants.CTX_VERBOSE] = true - // context[constants.CTX_DEBUG_LEVEL] = 10 + context[constants.CTX_VERBOSE] = true + context[constants.CTX_DEBUG_LEVEL] = 10 command := builder.Builder{} err := command.Run(context) @@ -62,7 +63,7 @@ func TestBuilderEmptySketch(t *testing.T) { _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_CORE, "HardwareSerial.cpp.o")) NoError(t, err) - _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_PREPROC, constants.FILE_CTAGS_TARGET)) + _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_PREPROC, constants.FILE_CTAGS_TARGET_FOR_GCC_MINUS_E)) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_SKETCH, "sketch.ino.cpp.o")) NoError(t, err) @@ -87,6 +88,7 @@ func TestBuilderBridge(t *testing.T) { context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" + context[constants.CTX_VERBOSE] = true command := builder.Builder{} err := command.Run(context) @@ -94,7 +96,7 @@ func TestBuilderBridge(t *testing.T) { _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_CORE, "HardwareSerial.cpp.o")) NoError(t, err) - _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_PREPROC, constants.FILE_CTAGS_TARGET)) + _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_PREPROC, constants.FILE_CTAGS_TARGET_FOR_GCC_MINUS_E)) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_SKETCH, "Bridge.ino.cpp.o")) NoError(t, err) @@ -128,7 +130,7 @@ func TestBuilderSketchWithConfig(t *testing.T) { _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_CORE, "HardwareSerial.cpp.o")) NoError(t, err) - _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_PREPROC, constants.FILE_CTAGS_TARGET)) + _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_PREPROC, constants.FILE_CTAGS_TARGET_FOR_GCC_MINUS_E)) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_SKETCH, "sketch_with_config.ino.cpp.o")) NoError(t, err) @@ -166,7 +168,7 @@ func TestBuilderBridgeTwice(t *testing.T) { _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_CORE, "HardwareSerial.cpp.o")) NoError(t, err) - _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_PREPROC, constants.FILE_CTAGS_TARGET)) + _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_PREPROC, constants.FILE_CTAGS_TARGET_FOR_GCC_MINUS_E)) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_SKETCH, "Bridge.ino.cpp.o")) NoError(t, err) @@ -201,11 +203,11 @@ func TestBuilderBridgeSAM(t *testing.T) { _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_CORE, "syscalls_sam3.c.o")) NoError(t, err) - _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_CORE, "USB", "HID.cpp.o")) + _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_CORE, "USB", "PluggableUSB.cpp.o")) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_CORE, "avr", "dtostrf.c.d")) NoError(t, err) - _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_PREPROC, constants.FILE_CTAGS_TARGET)) + _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_PREPROC, constants.FILE_CTAGS_TARGET_FOR_GCC_MINUS_E)) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_SKETCH, "Bridge.ino.cpp.o")) NoError(t, err) @@ -215,6 +217,11 @@ func TestBuilderBridgeSAM(t *testing.T) { NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_LIBRARIES, "Bridge", "Mailbox.cpp.o")) NoError(t, err) + + cmd := exec.Command(filepath.Join("downloaded_tools", "arm-none-eabi-gcc", "4.8.3-2014q1", "bin", "arm-none-eabi-objdump"), "-f", filepath.Join(buildPath, constants.FOLDER_CORE, "core.a")) + bytes, err := cmd.CombinedOutput() + NoError(t, err) + require.NotContains(t, string(bytes), "variant.cpp.o") } func TestBuilderBridgeRedBearLab(t *testing.T) { @@ -239,7 +246,7 @@ func TestBuilderBridgeRedBearLab(t *testing.T) { _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_CORE, "HardwareSerial.cpp.o")) NoError(t, err) - _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_PREPROC, constants.FILE_CTAGS_TARGET)) + _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_PREPROC, constants.FILE_CTAGS_TARGET_FOR_GCC_MINUS_E)) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_SKETCH, "Bridge.ino.cpp.o")) NoError(t, err) @@ -313,3 +320,53 @@ func TestBuilderSketchWithOldLib(t *testing.T) { err := command.Run(context) NoError(t, err) } + +func TestBuilderSketchWithSubfolders(t *testing.T) { + DownloadCoresAndToolsAndLibraries(t) + + context := make(map[string]interface{}) + + buildPath := SetupBuildPath(t, context) + defer os.RemoveAll(buildPath) + + context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} + context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} + context[constants.CTX_FQBN] = "arduino:avr:uno" + context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch_with_subfolders", "sketch_with_subfolders.ino") + context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} + context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} + context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" + + command := builder.Builder{} + err := command.Run(context) + NoError(t, err) +} + +func TestBuilderSketchBuildPathContainsUnusedPreviouslyCompiledLibrary(t *testing.T) { + DownloadCoresAndToolsAndLibraries(t) + + context := make(map[string]interface{}) + + buildPath := SetupBuildPath(t, context) + defer os.RemoveAll(buildPath) + + NoError(t, os.MkdirAll(filepath.Join(buildPath, constants.FOLDER_LIBRARIES, "SPI"), os.FileMode(0755))) + + context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} + context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} + context[constants.CTX_FQBN] = "arduino:avr:leonardo" + context[constants.CTX_SKETCH_LOCATION] = filepath.Join("downloaded_libraries", "Bridge", "examples", "Bridge", "Bridge.ino") + context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} + context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} + context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" + + command := builder.Builder{} + err := command.Run(context) + NoError(t, err) + + _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_LIBRARIES, "SPI")) + require.Error(t, err) + require.True(t, os.IsNotExist(err)) + _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_LIBRARIES, "Bridge")) + NoError(t, err) +} diff --git a/src/arduino.cc/builder/test/builder_utils_test.go b/src/arduino.cc/builder/test/builder_utils_test.go index 1fe1aa14..dcb85509 100644 --- a/src/arduino.cc/builder/test/builder_utils_test.go +++ b/src/arduino.cc/builder/test/builder_utils_test.go @@ -31,6 +31,7 @@ package test import ( "arduino.cc/builder/builder_utils" + "arduino.cc/builder/utils" "github.com/stretchr/testify/require" "io/ioutil" "os" @@ -119,7 +120,7 @@ func TestObjFileIsUpToDateDepIsNewer(t *testing.T) { headerFile := tempFile(t, "header") defer os.RemoveAll(headerFile) - ioutil.WriteFile(depFile, []byte(objFile+": \\\n\t"+sourceFile+" \\\n\t"+headerFile), os.FileMode(0644)) + utils.WriteFile(depFile, objFile+": \\\n\t"+sourceFile+" \\\n\t"+headerFile) upToDate, err := builder_utils.ObjFileIsUpToDate(sourceFile, objFile, depFile) NoError(t, err) @@ -140,7 +141,7 @@ func TestObjFileIsUpToDateDepIsOlder(t *testing.T) { depFile := tempFile(t, "dep") defer os.RemoveAll(depFile) - ioutil.WriteFile(depFile, []byte(objFile+": \\\n\t"+sourceFile+" \\\n\t"+headerFile), os.FileMode(0644)) + utils.WriteFile(depFile, objFile+": \\\n\t"+sourceFile+" \\\n\t"+headerFile) upToDate, err := builder_utils.ObjFileIsUpToDate(sourceFile, objFile, depFile) NoError(t, err) @@ -163,7 +164,7 @@ func TestObjFileIsUpToDateDepIsWrong(t *testing.T) { headerFile := tempFile(t, "header") defer os.RemoveAll(headerFile) - ioutil.WriteFile(depFile, []byte(sourceFile+": \\\n\t"+sourceFile+" \\\n\t"+headerFile), os.FileMode(0644)) + utils.WriteFile(depFile, sourceFile+": \\\n\t"+sourceFile+" \\\n\t"+headerFile) upToDate, err := builder_utils.ObjFileIsUpToDate(sourceFile, objFile, depFile) NoError(t, err) diff --git a/src/arduino.cc/builder/test/coan_runner_test.go b/src/arduino.cc/builder/test/coan_runner_test.go index 02d4cd54..0393455b 100644 --- a/src/arduino.cc/builder/test/coan_runner_test.go +++ b/src/arduino.cc/builder/test/coan_runner_test.go @@ -54,7 +54,7 @@ func TestCoanRunner(t *testing.T) { context[constants.CTX_FQBN] = "arduino:avr:leonardo" context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch2", "SketchWithIfDef.ino") context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, diff --git a/src/arduino.cc/builder/test/ctags_output/TestCTagsParserFunctionPointer.txt b/src/arduino.cc/builder/test/ctags_output/TestCTagsParserFunctionPointer.txt new file mode 100644 index 00000000..b36c5928 --- /dev/null +++ b/src/arduino.cc/builder/test/ctags_output/TestCTagsParserFunctionPointer.txt @@ -0,0 +1,4 @@ +t1Callback /tmp/test547238273/preproc/ctags_target.cpp /^Task t1(&t1Callback);$/;" kind:variable line:2 +t1Callback /tmp/test547238273/preproc/ctags_target.cpp /^void t1Callback() {}$/;" kind:function line:3 signature:() returntype:void +setup /tmp/test547238273/preproc/ctags_target.cpp /^void setup() {}$/;" kind:function line:4 signature:() returntype:void +loop /tmp/test547238273/preproc/ctags_target.cpp /^void loop() {}$/;" kind:function line:5 signature:() returntype:void diff --git a/src/arduino.cc/builder/test/ctags_output/TestCTagsParserFunctionPointers.txt b/src/arduino.cc/builder/test/ctags_output/TestCTagsParserFunctionPointers.txt new file mode 100644 index 00000000..0aa1e06a --- /dev/null +++ b/src/arduino.cc/builder/test/ctags_output/TestCTagsParserFunctionPointers.txt @@ -0,0 +1,5 @@ +setup /tmp/test907446433/preproc/ctags_target.cpp /^void setup(){$/;" kind:function line:2 signature:() returntype:void +loop /tmp/test907446433/preproc/ctags_target.cpp /^void loop(){}$/;" kind:function line:5 signature:() returntype:void +func /tmp/test907446433/preproc/ctags_target.cpp /^void (*func())(){$/;" kind:function line:7 signature:() returntype:void +funcArr /tmp/test907446433/preproc/ctags_target.cpp /^int (&funcArr())[5]{$/;" kind:function line:11 signature:() returntype:int +funcCombo /tmp/test907446433/preproc/ctags_target.cpp /^void (*(&funcCombo(void (*(&in)[5])(int)))[5])(int){$/;" kind:function line:15 signature:(void (*(&in)[5])(int)) returntype:void diff --git a/src/arduino.cc/builder/test/ctags_output/TestCTagsParserNamespace.txt b/src/arduino.cc/builder/test/ctags_output/TestCTagsParserNamespace.txt new file mode 100644 index 00000000..8a12c235 --- /dev/null +++ b/src/arduino.cc/builder/test/ctags_output/TestCTagsParserNamespace.txt @@ -0,0 +1,4 @@ +value /tmp/test030883150/preproc/ctags_target.cpp /^ int value() {$/;" kind:function line:3 namespace:Test signature:() returntype:int +setup /tmp/test030883150/preproc/ctags_target.cpp /^void setup() {}$/;" kind:function line:8 signature:() returntype:void +loop /tmp/test030883150/preproc/ctags_target.cpp /^void loop() {}$/;" kind:function line:9 signature:() returntype:void + diff --git a/src/arduino.cc/builder/test/ctags_output/TestCTagsParserStatic.txt b/src/arduino.cc/builder/test/ctags_output/TestCTagsParserStatic.txt new file mode 100644 index 00000000..ec1bdb14 --- /dev/null +++ b/src/arduino.cc/builder/test/ctags_output/TestCTagsParserStatic.txt @@ -0,0 +1,3 @@ +setup /tmp/test542833488/preproc/ctags_target.cpp /^void setup(){}$/;" kind:function line:2 signature:() returntype:void +loop /tmp/test542833488/preproc/ctags_target.cpp /^void loop(){}$/;" kind:function line:3 signature:() returntype:void +doStuff /tmp/test542833488/preproc/ctags_target.cpp /^static void doStuff() {}$/;" kind:function line:4 signature:() returntype:void diff --git a/src/arduino.cc/builder/test/ctags_parser_test.go b/src/arduino.cc/builder/test/ctags_parser_test.go index efae491c..cb6353dc 100644 --- a/src/arduino.cc/builder/test/ctags_parser_test.go +++ b/src/arduino.cc/builder/test/ctags_parser_test.go @@ -47,17 +47,44 @@ func TestCTagsParserShouldListPrototypes(t *testing.T) { context[constants.CTX_CTAGS_OUTPUT] = string(bytes) - ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES} + ctagsParser := builder.CTagsParser{} ctagsParser.Run(context) - prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) - - require.Equal(t, 5, len(prototypes)) - require.Equal(t, "void setup();", prototypes[0].Prototype) - require.Equal(t, "void loop();", prototypes[1].Prototype) - require.Equal(t, "void digitalCommand(YunClient client);", prototypes[2].Prototype) - require.Equal(t, "void analogCommand(YunClient client);", prototypes[3].Prototype) - require.Equal(t, "void modeCommand(YunClient client);", prototypes[4].Prototype) + ctags := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]*types.CTag) + + require.Equal(t, 8, len(ctags)) + idx := 0 + require.Equal(t, "server", ctags[idx].FunctionName) + require.Equal(t, "variable", ctags[idx].Kind) + require.Equal(t, "/tmp/sketch7210316334309249705.cpp", ctags[idx].Filename) + idx++ + require.Equal(t, "setup", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + require.Equal(t, "/tmp/sketch7210316334309249705.cpp", ctags[idx].Filename) + idx++ + require.Equal(t, "loop", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + require.Equal(t, "/tmp/sketch7210316334309249705.cpp", ctags[idx].Filename) + idx++ + require.Equal(t, "process", ctags[idx].FunctionName) + require.Equal(t, "prototype", ctags[idx].Kind) + require.Equal(t, "/tmp/sketch7210316334309249705.cpp", ctags[idx].Filename) + idx++ + require.Equal(t, "process", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + require.Equal(t, "/tmp/sketch7210316334309249705.cpp", ctags[idx].Filename) + idx++ + require.Equal(t, "digitalCommand", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + require.Equal(t, "/tmp/sketch7210316334309249705.cpp", ctags[idx].Filename) + idx++ + require.Equal(t, "analogCommand", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + require.Equal(t, "/tmp/sketch7210316334309249705.cpp", ctags[idx].Filename) + idx++ + require.Equal(t, "modeCommand", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + require.Equal(t, "/tmp/sketch7210316334309249705.cpp", ctags[idx].Filename) } func TestCTagsParserShouldListTemplates(t *testing.T) { @@ -68,15 +95,22 @@ func TestCTagsParserShouldListTemplates(t *testing.T) { context[constants.CTX_CTAGS_OUTPUT] = string(bytes) - ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES} + ctagsParser := builder.CTagsParser{} ctagsParser.Run(context) - prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) - - require.Equal(t, 3, len(prototypes)) - require.Equal(t, "template T minimum (T a, T b);", prototypes[0].Prototype) - require.Equal(t, "void setup();", prototypes[1].Prototype) - require.Equal(t, "void loop();", prototypes[2].Prototype) + ctags := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]*types.CTag) + + require.Equal(t, 3, len(ctags)) + idx := 0 + require.Equal(t, "minimum", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + require.Equal(t, "(T a, T b)", ctags[idx].Signature) + idx++ + require.Equal(t, "setup", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "loop", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) } func TestCTagsParserShouldListTemplates2(t *testing.T) { @@ -87,16 +121,26 @@ func TestCTagsParserShouldListTemplates2(t *testing.T) { context[constants.CTX_CTAGS_OUTPUT] = string(bytes) - ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES} + ctagsParser := builder.CTagsParser{} ctagsParser.Run(context) - prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) - - require.Equal(t, 4, len(prototypes)) - require.Equal(t, "void setup();", prototypes[0].Prototype) - require.Equal(t, "void loop();", prototypes[1].Prototype) - require.Equal(t, "template int SRAM_writeAnything(int ee, const T& value);", prototypes[2].Prototype) - require.Equal(t, "template int SRAM_readAnything(int ee, T& value);", prototypes[3].Prototype) + ctags := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]*types.CTag) + + require.Equal(t, 4, len(ctags)) + idx := 0 + require.Equal(t, "setup", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "loop", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "SRAM_writeAnything", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + require.Equal(t, "(int ee, const T& value)", ctags[idx].Signature) + idx++ + require.Equal(t, "SRAM_readAnything", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + require.Equal(t, "(int ee, T& value)", ctags[idx].Signature) } func TestCTagsParserShouldDealWithClasses(t *testing.T) { @@ -107,12 +151,18 @@ func TestCTagsParserShouldDealWithClasses(t *testing.T) { context[constants.CTX_CTAGS_OUTPUT] = string(bytes) - ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES} + ctagsParser := builder.CTagsParser{} ctagsParser.Run(context) - prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) + ctags := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]*types.CTag) - require.Equal(t, 0, len(prototypes)) + require.Equal(t, 2, len(ctags)) + idx := 0 + require.Equal(t, "SleepCycle", ctags[idx].FunctionName) + require.Equal(t, "prototype", ctags[idx].Kind) + idx++ + require.Equal(t, "SleepCycle", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) } func TestCTagsParserShouldDealWithStructs(t *testing.T) { @@ -123,15 +173,28 @@ func TestCTagsParserShouldDealWithStructs(t *testing.T) { context[constants.CTX_CTAGS_OUTPUT] = string(bytes) - ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES} + ctagsParser := builder.CTagsParser{} ctagsParser.Run(context) - prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) - - require.Equal(t, 3, len(prototypes)) - require.Equal(t, "void setup();", prototypes[0].Prototype) - require.Equal(t, "void loop();", prototypes[1].Prototype) - require.Equal(t, "void dostuff(A_NEW_TYPE * bar);", prototypes[2].Prototype) + ctags := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]*types.CTag) + + require.Equal(t, 5, len(ctags)) + idx := 0 + require.Equal(t, "A_NEW_TYPE", ctags[idx].FunctionName) + require.Equal(t, "struct", ctags[idx].Kind) + idx++ + require.Equal(t, "foo", ctags[idx].FunctionName) + require.Equal(t, "variable", ctags[idx].Kind) + require.Equal(t, "struct:A_NEW_TYPE", ctags[idx].Typeref) + idx++ + require.Equal(t, "setup", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "loop", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "dostuff", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) } func TestCTagsParserShouldDealWithMacros(t *testing.T) { @@ -142,17 +205,36 @@ func TestCTagsParserShouldDealWithMacros(t *testing.T) { context[constants.CTX_CTAGS_OUTPUT] = string(bytes) - ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES} + ctagsParser := builder.CTagsParser{} ctagsParser.Run(context) - prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) - - require.Equal(t, 5, len(prototypes)) - require.Equal(t, "void setup();", prototypes[0].Prototype) - require.Equal(t, "void loop();", prototypes[1].Prototype) - require.Equal(t, "void debug();", prototypes[2].Prototype) - require.Equal(t, "void disabledIsDefined();", prototypes[3].Prototype) - require.Equal(t, "int useMyType(MyType type);", prototypes[4].Prototype) + ctags := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]*types.CTag) + + require.Equal(t, 8, len(ctags)) + idx := 0 + require.Equal(t, "DEBUG", ctags[idx].FunctionName) + require.Equal(t, "macro", ctags[idx].Kind) + idx++ + require.Equal(t, "DISABLED", ctags[idx].FunctionName) + require.Equal(t, "macro", ctags[idx].Kind) + idx++ + require.Equal(t, "hello", ctags[idx].FunctionName) + require.Equal(t, "variable", ctags[idx].Kind) + idx++ + require.Equal(t, "setup", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "loop", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "debug", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "disabledIsDefined", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "useMyType", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) } func TestCTagsParserShouldDealFunctionWithDifferentSignatures(t *testing.T) { @@ -163,13 +245,21 @@ func TestCTagsParserShouldDealFunctionWithDifferentSignatures(t *testing.T) { context[constants.CTX_CTAGS_OUTPUT] = string(bytes) - ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES} + ctagsParser := builder.CTagsParser{} ctagsParser.Run(context) - prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) - - require.Equal(t, 1, len(prototypes)) - require.Equal(t, "boolean getBytes( byte addr, int amount );", prototypes[0].Prototype) + ctags := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]*types.CTag) + + require.Equal(t, 3, len(ctags)) + idx := 0 + require.Equal(t, "getBytes", ctags[idx].FunctionName) + require.Equal(t, "prototype", ctags[idx].Kind) + idx++ + require.Equal(t, "getBytes", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "getBytes", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) } func TestCTagsParserClassMembersAreFilteredOut(t *testing.T) { @@ -180,14 +270,30 @@ func TestCTagsParserClassMembersAreFilteredOut(t *testing.T) { context[constants.CTX_CTAGS_OUTPUT] = string(bytes) - ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES} + ctagsParser := builder.CTagsParser{} ctagsParser.Run(context) - prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) - - require.Equal(t, 2, len(prototypes)) - require.Equal(t, "void setup();", prototypes[0].Prototype) - require.Equal(t, "void loop();", prototypes[1].Prototype) + ctags := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]*types.CTag) + + require.Equal(t, 5, len(ctags)) + idx := 0 + require.Equal(t, "set_values", ctags[idx].FunctionName) + require.Equal(t, "prototype", ctags[idx].Kind) + require.Equal(t, "Rectangle", ctags[idx].Class) + idx++ + require.Equal(t, "area", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + require.Equal(t, "Rectangle", ctags[idx].Class) + idx++ + require.Equal(t, "set_values", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + require.Equal(t, "Rectangle", ctags[idx].Class) + idx++ + require.Equal(t, "setup", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "loop", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) } func TestCTagsParserStructWithFunctions(t *testing.T) { @@ -198,14 +304,38 @@ func TestCTagsParserStructWithFunctions(t *testing.T) { context[constants.CTX_CTAGS_OUTPUT] = string(bytes) - ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES} + ctagsParser := builder.CTagsParser{} ctagsParser.Run(context) - prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) - - require.Equal(t, 2, len(prototypes)) - require.Equal(t, "void setup();", prototypes[0].Prototype) - require.Equal(t, "void loop();", prototypes[1].Prototype) + ctags := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]*types.CTag) + + require.Equal(t, 8, len(ctags)) + idx := 0 + require.Equal(t, "sensorData", ctags[idx].FunctionName) + require.Equal(t, "struct", ctags[idx].Kind) + idx++ + require.Equal(t, "sensorData", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + require.Equal(t, "sensorData", ctags[idx].Struct) + idx++ + require.Equal(t, "sensorData", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + require.Equal(t, "sensorData", ctags[idx].Struct) + idx++ + require.Equal(t, "sensors", ctags[idx].FunctionName) + require.Equal(t, "variable", ctags[idx].Kind) + idx++ + require.Equal(t, "sensor1", ctags[idx].FunctionName) + require.Equal(t, "variable", ctags[idx].Kind) + idx++ + require.Equal(t, "sensor2", ctags[idx].FunctionName) + require.Equal(t, "variable", ctags[idx].Kind) + idx++ + require.Equal(t, "setup", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "loop", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) } func TestCTagsParserDefaultArguments(t *testing.T) { @@ -216,12 +346,133 @@ func TestCTagsParserDefaultArguments(t *testing.T) { context[constants.CTX_CTAGS_OUTPUT] = string(bytes) - ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES} + ctagsParser := builder.CTagsParser{} + ctagsParser.Run(context) + + ctags := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]*types.CTag) + + require.Equal(t, 3, len(ctags)) + idx := 0 + require.Equal(t, "test", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + require.Equal(t, "(int x = 1)", ctags[idx].Signature) + idx++ + require.Equal(t, "setup", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "loop", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) +} + +func TestCTagsParserNamespace(t *testing.T) { + context := make(map[string]interface{}) + + bytes, err := ioutil.ReadFile(filepath.Join("ctags_output", "TestCTagsParserNamespace.txt")) + NoError(t, err) + + context[constants.CTX_CTAGS_OUTPUT] = string(bytes) + + ctagsParser := builder.CTagsParser{} + ctagsParser.Run(context) + + ctags := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]*types.CTag) + + require.Equal(t, 3, len(ctags)) + idx := 0 + require.Equal(t, "value", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + require.Equal(t, "Test", ctags[idx].Namespace) + idx++ + require.Equal(t, "setup", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "loop", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) +} + +func TestCTagsParserStatic(t *testing.T) { + context := make(map[string]interface{}) + + bytes, err := ioutil.ReadFile(filepath.Join("ctags_output", "TestCTagsParserStatic.txt")) + NoError(t, err) + + context[constants.CTX_CTAGS_OUTPUT] = string(bytes) + + ctagsParser := builder.CTagsParser{} + ctagsParser.Run(context) + + ctags := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]*types.CTag) + + require.Equal(t, 3, len(ctags)) + idx := 0 + require.Equal(t, "setup", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "loop", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "doStuff", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) +} + +func TestCTagsParserFunctionPointer(t *testing.T) { + context := make(map[string]interface{}) + + bytes, err := ioutil.ReadFile(filepath.Join("ctags_output", "TestCTagsParserFunctionPointer.txt")) + NoError(t, err) + + context[constants.CTX_CTAGS_OUTPUT] = string(bytes) + + ctagsParser := builder.CTagsParser{} + ctagsParser.Run(context) + + ctags := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]*types.CTag) + + require.Equal(t, 4, len(ctags)) + idx := 0 + require.Equal(t, "t1Callback", ctags[idx].FunctionName) + require.Equal(t, "variable", ctags[idx].Kind) + idx++ + require.Equal(t, "t1Callback", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "setup", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "loop", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) +} + +func TestCTagsParserFunctionPointers(t *testing.T) { + context := make(map[string]interface{}) + + bytes, err := ioutil.ReadFile(filepath.Join("ctags_output", "TestCTagsParserFunctionPointers.txt")) + NoError(t, err) + + context[constants.CTX_CTAGS_OUTPUT] = string(bytes) + + ctagsParser := builder.CTagsParser{} ctagsParser.Run(context) - prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) + ctags := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]*types.CTag) + + require.Equal(t, 5, len(ctags)) + idx := 0 + require.Equal(t, "setup", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "loop", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "func", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + idx++ + require.Equal(t, "funcArr", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + require.Equal(t, "()", ctags[idx].Signature) + idx++ + require.Equal(t, "funcCombo", ctags[idx].FunctionName) + require.Equal(t, "function", ctags[idx].Kind) + require.Equal(t, "(void (*(&in)[5])(int))", ctags[idx].Signature) - require.Equal(t, 2, len(prototypes)) - require.Equal(t, "void setup();", prototypes[0].Prototype) - require.Equal(t, "void loop();", prototypes[1].Prototype) } diff --git a/src/arduino.cc/builder/test/ctags_runner_test.go b/src/arduino.cc/builder/test/ctags_runner_test.go index 0a0420c2..9abab566 100644 --- a/src/arduino.cc/builder/test/ctags_runner_test.go +++ b/src/arduino.cc/builder/test/ctags_runner_test.go @@ -48,14 +48,15 @@ func TestCTagsRunner(t *testing.T) { buildPath := SetupBuildPath(t, context) defer os.RemoveAll(buildPath) + sketchLocation := Abs(t, filepath.Join("downloaded_libraries", "Bridge", "examples", "Bridge", "Bridge.ino")) context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} context[constants.CTX_FQBN] = "arduino:avr:leonardo" - context[constants.CTX_SKETCH_LOCATION] = filepath.Join("downloaded_libraries", "Bridge", "examples", "Bridge", "Bridge.ino") + context[constants.CTX_SKETCH_LOCATION] = sketchLocation context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -68,7 +69,7 @@ func TestCTagsRunner(t *testing.T) { &builder.PrintUsedLibrariesIfVerbose{}, &builder.WarnAboutArchIncompatibleLibraries{}, - &builder.CTagsTargetFileSaver{SourceField: constants.CTX_SOURCE}, + &builder.CTagsTargetFileSaver{SourceField: constants.CTX_SOURCE, TargetFileName: constants.FILE_CTAGS_TARGET}, &builder.CTagsRunner{}, } @@ -77,14 +78,14 @@ func TestCTagsRunner(t *testing.T) { NoError(t, err) } - ctagsTempFileName := context[constants.CTX_CTAGS_TEMP_FILE_NAME].(string) - expectedOutput := "server " + ctagsTempFileName + " /^BridgeServer server;$/;\" kind:variable line:32\n" + - "setup " + ctagsTempFileName + " /^void setup() {$/;\" kind:function line:34 signature:() returntype:void\n" + - "loop " + ctagsTempFileName + " /^void loop() {$/;\" kind:function line:47 signature:() returntype:void\n" + - "process " + ctagsTempFileName + " /^void process(BridgeClient client) {$/;\" kind:function line:63 signature:(BridgeClient client) returntype:void\n" + - "digitalCommand " + ctagsTempFileName + " /^void digitalCommand(BridgeClient client) {$/;\" kind:function line:83 signature:(BridgeClient client) returntype:void\n" + - "analogCommand " + ctagsTempFileName + " /^void analogCommand(BridgeClient client) {$/;\" kind:function line:110 signature:(BridgeClient client) returntype:void\n" + - "modeCommand " + ctagsTempFileName + " /^void modeCommand(BridgeClient client) {$/;\" kind:function line:150 signature:(BridgeClient client) returntype:void\n" + sketchLocation = strings.Replace(sketchLocation, "\\", "\\\\", -1) + expectedOutput := "server " + sketchLocation + " /^BridgeServer server;$/;\" kind:variable line:31\n" + + "setup " + sketchLocation + " /^void setup() {$/;\" kind:function line:33 signature:() returntype:void\n" + + "loop " + sketchLocation + " /^void loop() {$/;\" kind:function line:46 signature:() returntype:void\n" + + "process " + sketchLocation + " /^void process(BridgeClient client) {$/;\" kind:function line:62 signature:(BridgeClient client) returntype:void\n" + + "digitalCommand " + sketchLocation + " /^void digitalCommand(BridgeClient client) {$/;\" kind:function line:82 signature:(BridgeClient client) returntype:void\n" + + "analogCommand " + sketchLocation + " /^void analogCommand(BridgeClient client) {$/;\" kind:function line:109 signature:(BridgeClient client) returntype:void\n" + + "modeCommand " + sketchLocation + " /^void modeCommand(BridgeClient client) {$/;\" kind:function line:149 signature:(BridgeClient client) returntype:void\n" require.Equal(t, expectedOutput, strings.Replace(context[constants.CTX_CTAGS_OUTPUT].(string), "\r\n", "\n", -1)) } @@ -97,14 +98,15 @@ func TestCTagsRunnerSketchWithClass(t *testing.T) { buildPath := SetupBuildPath(t, context) defer os.RemoveAll(buildPath) + sketchLocation := Abs(t, filepath.Join("sketch_with_class", "sketch.ino")) context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} context[constants.CTX_FQBN] = "arduino:avr:leonardo" - context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch_with_class", "sketch.ino") + context[constants.CTX_SKETCH_LOCATION] = sketchLocation context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -117,7 +119,7 @@ func TestCTagsRunnerSketchWithClass(t *testing.T) { &builder.PrintUsedLibrariesIfVerbose{}, &builder.WarnAboutArchIncompatibleLibraries{}, - &builder.CTagsTargetFileSaver{SourceField: constants.CTX_SOURCE}, + &builder.CTagsTargetFileSaver{SourceField: constants.CTX_SOURCE, TargetFileName: constants.FILE_CTAGS_TARGET}, &builder.CTagsRunner{}, } @@ -126,12 +128,12 @@ func TestCTagsRunnerSketchWithClass(t *testing.T) { NoError(t, err) } - ctagsTempFileName := context[constants.CTX_CTAGS_TEMP_FILE_NAME].(string) - expectedOutput := "set_values\t" + ctagsTempFileName + "\t/^ void set_values (int,int);$/;\"\tkind:prototype\tline:5\tclass:Rectangle\tsignature:(int,int)\treturntype:void\n" + - "area\t" + ctagsTempFileName + "\t/^ int area() {return width*height;}$/;\"\tkind:function\tline:6\tclass:Rectangle\tsignature:()\treturntype:int\n" + - "set_values\t" + ctagsTempFileName + "\t/^void Rectangle::set_values (int x, int y) {$/;\"\tkind:function\tline:9\tclass:Rectangle\tsignature:(int x, int y)\treturntype:void\n" + - "setup\t" + ctagsTempFileName + "\t/^void setup() {$/;\"\tkind:function\tline:14\tsignature:()\treturntype:void\n" + - "loop\t" + ctagsTempFileName + "\t/^void loop() {$/;\"\tkind:function\tline:18\tsignature:()\treturntype:void\n" + sketchLocation = strings.Replace(sketchLocation, "\\", "\\\\", -1) + expectedOutput := "set_values\t" + sketchLocation + "\t/^ void set_values (int,int);$/;\"\tkind:prototype\tline:4\tclass:Rectangle\tsignature:(int,int)\treturntype:void\n" + + "area\t" + sketchLocation + "\t/^ int area() {return width*height;}$/;\"\tkind:function\tline:5\tclass:Rectangle\tsignature:()\treturntype:int\n" + + "set_values\t" + sketchLocation + "\t/^void Rectangle::set_values (int x, int y) {$/;\"\tkind:function\tline:8\tclass:Rectangle\tsignature:(int x, int y)\treturntype:void\n" + + "setup\t" + sketchLocation + "\t/^void setup() {$/;\"\tkind:function\tline:13\tsignature:()\treturntype:void\n" + + "loop\t" + sketchLocation + "\t/^void loop() {$/;\"\tkind:function\tline:17\tsignature:()\treturntype:void\n" require.Equal(t, expectedOutput, strings.Replace(context[constants.CTX_CTAGS_OUTPUT].(string), "\r\n", "\n", -1)) } @@ -144,10 +146,58 @@ func TestCTagsRunnerSketchWithTypename(t *testing.T) { buildPath := SetupBuildPath(t, context) defer os.RemoveAll(buildPath) + sketchLocation := Abs(t, filepath.Join("sketch_with_typename", "sketch.ino")) + context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} + context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} + context[constants.CTX_FQBN] = "arduino:avr:leonardo" + context[constants.CTX_SKETCH_LOCATION] = sketchLocation + context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" + context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} + context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} + context[constants.CTX_VERBOSE] = true + + commands := []types.Command{ + &builder.SetupHumanLoggerIfMissing{}, + + &builder.ContainerSetupHardwareToolsLibsSketchAndProps{}, + + &builder.ContainerMergeCopySketchFiles{}, + + &builder.ContainerFindIncludes{}, + + &builder.PrintUsedLibrariesIfVerbose{}, + &builder.WarnAboutArchIncompatibleLibraries{}, + &builder.CTagsTargetFileSaver{SourceField: constants.CTX_SOURCE, TargetFileName: constants.FILE_CTAGS_TARGET}, + &builder.CTagsRunner{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + sketchLocation = strings.Replace(sketchLocation, "\\", "\\\\", -1) + expectedOutput := "Foo\t" + sketchLocation + "\t/^ struct Foo{$/;\"\tkind:struct\tline:2\n" + + "setup\t" + sketchLocation + "\t/^void setup() {$/;\"\tkind:function\tline:6\tsignature:()\treturntype:void\n" + + "loop\t" + sketchLocation + "\t/^void loop() {}$/;\"\tkind:function\tline:10\tsignature:()\treturntype:void\n" + + "func\t" + sketchLocation + "\t/^typename Foo::Bar func(){$/;\"\tkind:function\tline:12\tsignature:()\treturntype:Foo::Bar\n" + + require.Equal(t, expectedOutput, strings.Replace(context[constants.CTX_CTAGS_OUTPUT].(string), "\r\n", "\n", -1)) +} + +func TestCTagsRunnerSketchWithNamespace(t *testing.T) { + DownloadCoresAndToolsAndLibraries(t) + + context := make(map[string]interface{}) + + buildPath := SetupBuildPath(t, context) + defer os.RemoveAll(buildPath) + + sketchLocation := Abs(t, filepath.Join("sketch_with_namespace", "sketch.ino")) context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} context[constants.CTX_FQBN] = "arduino:avr:leonardo" - context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch_with_typename", "sketch.ino") + context[constants.CTX_SKETCH_LOCATION] = sketchLocation context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} @@ -164,7 +214,7 @@ func TestCTagsRunnerSketchWithTypename(t *testing.T) { &builder.PrintUsedLibrariesIfVerbose{}, &builder.WarnAboutArchIncompatibleLibraries{}, - &builder.CTagsTargetFileSaver{SourceField: constants.CTX_SOURCE}, + &builder.CTagsTargetFileSaver{SourceField: constants.CTX_SOURCE, TargetFileName: constants.FILE_CTAGS_TARGET}, &builder.CTagsRunner{}, } @@ -173,11 +223,10 @@ func TestCTagsRunnerSketchWithTypename(t *testing.T) { NoError(t, err) } - ctagsTempFileName := context[constants.CTX_CTAGS_TEMP_FILE_NAME].(string) - expectedOutput := "Foo\t" + ctagsTempFileName + "\t/^ struct Foo{$/;\"\tkind:struct\tline:3\n" + - "setup\t" + ctagsTempFileName + "\t/^void setup() {$/;\"\tkind:function\tline:7\tsignature:()\treturntype:void\n" + - "loop\t" + ctagsTempFileName + "\t/^void loop() {}$/;\"\tkind:function\tline:11\tsignature:()\treturntype:void\n" + - "func\t" + ctagsTempFileName + "\t/^typename Foo::Bar func(){$/;\"\tkind:function\tline:13\tsignature:()\treturntype:Foo::Bar\n" + sketchLocation = strings.Replace(sketchLocation, "\\", "\\\\", -1) + expectedOutput := "value\t" + sketchLocation + "\t/^\tint value() {$/;\"\tkind:function\tline:2\tnamespace:Test\tsignature:()\treturntype:int\n" + + "setup\t" + sketchLocation + "\t/^void setup() {}$/;\"\tkind:function\tline:7\tsignature:()\treturntype:void\n" + + "loop\t" + sketchLocation + "\t/^void loop() {}$/;\"\tkind:function\tline:8\tsignature:()\treturntype:void\n" require.Equal(t, expectedOutput, strings.Replace(context[constants.CTX_CTAGS_OUTPUT].(string), "\r\n", "\n", -1)) } diff --git a/src/arduino.cc/builder/test/ctags_to_prototypes_test.go b/src/arduino.cc/builder/test/ctags_to_prototypes_test.go new file mode 100644 index 00000000..c0a4ed6c --- /dev/null +++ b/src/arduino.cc/builder/test/ctags_to_prototypes_test.go @@ -0,0 +1,469 @@ +/* + * This file is part of Arduino Builder. + * + * Arduino Builder is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + */ + +package test + +import ( + "arduino.cc/builder" + "arduino.cc/builder/constants" + "arduino.cc/builder/types" + "github.com/stretchr/testify/require" + "io/ioutil" + "path/filepath" + "testing" +) + +func TestCTagsToPrototypesShouldListPrototypes(t *testing.T) { + context := make(map[string]interface{}) + + bytes, err := ioutil.ReadFile(filepath.Join("ctags_output", "TestCTagsParserShouldListPrototypes.txt")) + NoError(t, err) + + context[constants.CTX_CTAGS_OUTPUT] = string(bytes) + + commands := []types.Command{ + &builder.CTagsParser{}, + &CopyContextKeys{From: constants.CTX_CTAGS_OF_PREPROC_SOURCE, To: constants.CTX_COLLECTED_CTAGS}, + &builder.CTagsToPrototypes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) + + require.Equal(t, 5, len(prototypes)) + require.Equal(t, "void setup();", prototypes[0].Prototype) + require.Equal(t, "/tmp/sketch7210316334309249705.cpp", prototypes[0].File) + require.Equal(t, "void loop();", prototypes[1].Prototype) + require.Equal(t, "void digitalCommand(YunClient client);", prototypes[2].Prototype) + require.Equal(t, "void analogCommand(YunClient client);", prototypes[3].Prototype) + require.Equal(t, "void modeCommand(YunClient client);", prototypes[4].Prototype) + + prototypeLine := context[constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES].(int) + require.Equal(t, 33, prototypeLine) +} + +func TestCTagsToPrototypesShouldListTemplates(t *testing.T) { + context := make(map[string]interface{}) + + bytes, err := ioutil.ReadFile(filepath.Join("ctags_output", "TestCTagsParserShouldListTemplates.txt")) + NoError(t, err) + + context[constants.CTX_CTAGS_OUTPUT] = string(bytes) + + commands := []types.Command{ + &builder.CTagsParser{}, + &CopyContextKeys{From: constants.CTX_CTAGS_OF_PREPROC_SOURCE, To: constants.CTX_COLLECTED_CTAGS}, + &builder.CTagsToPrototypes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) + + require.Equal(t, 3, len(prototypes)) + require.Equal(t, "template T minimum (T a, T b);", prototypes[0].Prototype) + require.Equal(t, "/tmp/sketch8398023134925534708.cpp", prototypes[0].File) + require.Equal(t, "void setup();", prototypes[1].Prototype) + require.Equal(t, "void loop();", prototypes[2].Prototype) + + prototypeLine := context[constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES].(int) + require.Equal(t, 2, prototypeLine) +} + +func TestCTagsToPrototypesShouldListTemplates2(t *testing.T) { + context := make(map[string]interface{}) + + bytes, err := ioutil.ReadFile(filepath.Join("ctags_output", "TestCTagsParserShouldListTemplates2.txt")) + NoError(t, err) + + context[constants.CTX_CTAGS_OUTPUT] = string(bytes) + + commands := []types.Command{ + &builder.CTagsParser{}, + &CopyContextKeys{From: constants.CTX_CTAGS_OF_PREPROC_SOURCE, To: constants.CTX_COLLECTED_CTAGS}, + &builder.CTagsToPrototypes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) + + require.Equal(t, 4, len(prototypes)) + require.Equal(t, "void setup();", prototypes[0].Prototype) + require.Equal(t, "/tmp/sketch463160524247569568.cpp", prototypes[0].File) + require.Equal(t, "void loop();", prototypes[1].Prototype) + require.Equal(t, "template int SRAM_writeAnything(int ee, const T& value);", prototypes[2].Prototype) + require.Equal(t, "template int SRAM_readAnything(int ee, T& value);", prototypes[3].Prototype) + + prototypeLine := context[constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES].(int) + require.Equal(t, 1, prototypeLine) +} + +func TestCTagsToPrototypesShouldDealWithClasses(t *testing.T) { + context := make(map[string]interface{}) + + bytes, err := ioutil.ReadFile(filepath.Join("ctags_output", "TestCTagsParserShouldDealWithClasses.txt")) + NoError(t, err) + + context[constants.CTX_CTAGS_OUTPUT] = string(bytes) + + commands := []types.Command{ + &builder.CTagsParser{}, + &CopyContextKeys{From: constants.CTX_CTAGS_OF_PREPROC_SOURCE, To: constants.CTX_COLLECTED_CTAGS}, + &builder.CTagsToPrototypes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) + + require.Equal(t, 0, len(prototypes)) + + prototypeLine := context[constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES].(int) + require.Equal(t, 8, prototypeLine) +} + +func TestCTagsToPrototypesShouldDealWithStructs(t *testing.T) { + context := make(map[string]interface{}) + + bytes, err := ioutil.ReadFile(filepath.Join("ctags_output", "TestCTagsParserShouldDealWithStructs.txt")) + NoError(t, err) + + context[constants.CTX_CTAGS_OUTPUT] = string(bytes) + + commands := []types.Command{ + &builder.CTagsParser{}, + &CopyContextKeys{From: constants.CTX_CTAGS_OF_PREPROC_SOURCE, To: constants.CTX_COLLECTED_CTAGS}, + &builder.CTagsToPrototypes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) + + require.Equal(t, 3, len(prototypes)) + require.Equal(t, "void setup();", prototypes[0].Prototype) + require.Equal(t, "/tmp/sketch8930345717354294915.cpp", prototypes[0].File) + require.Equal(t, "void loop();", prototypes[1].Prototype) + require.Equal(t, "void dostuff(A_NEW_TYPE * bar);", prototypes[2].Prototype) + + prototypeLine := context[constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES].(int) + require.Equal(t, 9, prototypeLine) +} + +func TestCTagsToPrototypesShouldDealWithMacros(t *testing.T) { + context := make(map[string]interface{}) + + bytes, err := ioutil.ReadFile(filepath.Join("ctags_output", "TestCTagsParserShouldDealWithMacros.txt")) + NoError(t, err) + + context[constants.CTX_CTAGS_OUTPUT] = string(bytes) + + commands := []types.Command{ + &builder.CTagsParser{}, + &CopyContextKeys{From: constants.CTX_CTAGS_OF_PREPROC_SOURCE, To: constants.CTX_COLLECTED_CTAGS}, + &builder.CTagsToPrototypes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) + + require.Equal(t, 5, len(prototypes)) + require.Equal(t, "void setup();", prototypes[0].Prototype) + require.Equal(t, "/tmp/sketch5976699731718729500.cpp", prototypes[0].File) + require.Equal(t, "void loop();", prototypes[1].Prototype) + require.Equal(t, "void debug();", prototypes[2].Prototype) + require.Equal(t, "void disabledIsDefined();", prototypes[3].Prototype) + require.Equal(t, "int useMyType(MyType type);", prototypes[4].Prototype) + + prototypeLine := context[constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES].(int) + require.Equal(t, 18, prototypeLine) +} + +func TestCTagsToPrototypesShouldDealFunctionWithDifferentSignatures(t *testing.T) { + context := make(map[string]interface{}) + + bytes, err := ioutil.ReadFile(filepath.Join("ctags_output", "TestCTagsParserShouldDealFunctionWithDifferentSignatures.txt")) + NoError(t, err) + + context[constants.CTX_CTAGS_OUTPUT] = string(bytes) + + commands := []types.Command{ + &builder.CTagsParser{}, + &CopyContextKeys{From: constants.CTX_CTAGS_OF_PREPROC_SOURCE, To: constants.CTX_COLLECTED_CTAGS}, + &builder.CTagsToPrototypes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) + + require.Equal(t, 1, len(prototypes)) + require.Equal(t, "boolean getBytes( byte addr, int amount );", prototypes[0].Prototype) + require.Equal(t, "/tmp/test260613593/preproc/ctags_target.cpp", prototypes[0].File) + + prototypeLine := context[constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES].(int) + require.Equal(t, 5031, prototypeLine) +} + +func TestCTagsToPrototypesClassMembersAreFilteredOut(t *testing.T) { + context := make(map[string]interface{}) + + bytes, err := ioutil.ReadFile(filepath.Join("ctags_output", "TestCTagsParserClassMembersAreFilteredOut.txt")) + NoError(t, err) + + context[constants.CTX_CTAGS_OUTPUT] = string(bytes) + + commands := []types.Command{ + &builder.CTagsParser{}, + &CopyContextKeys{From: constants.CTX_CTAGS_OF_PREPROC_SOURCE, To: constants.CTX_COLLECTED_CTAGS}, + &builder.CTagsToPrototypes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) + + require.Equal(t, 2, len(prototypes)) + require.Equal(t, "void setup();", prototypes[0].Prototype) + require.Equal(t, "/tmp/test834438754/preproc/ctags_target.cpp", prototypes[0].File) + require.Equal(t, "void loop();", prototypes[1].Prototype) + + prototypeLine := context[constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES].(int) + require.Equal(t, 14, prototypeLine) +} + +func TestCTagsToPrototypesStructWithFunctions(t *testing.T) { + context := make(map[string]interface{}) + + bytes, err := ioutil.ReadFile(filepath.Join("ctags_output", "TestCTagsParserStructWithFunctions.txt")) + NoError(t, err) + + context[constants.CTX_CTAGS_OUTPUT] = string(bytes) + + commands := []types.Command{ + &builder.CTagsParser{}, + &CopyContextKeys{From: constants.CTX_CTAGS_OF_PREPROC_SOURCE, To: constants.CTX_COLLECTED_CTAGS}, + &builder.CTagsToPrototypes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) + + require.Equal(t, 2, len(prototypes)) + require.Equal(t, "void setup();", prototypes[0].Prototype) + require.Equal(t, "/tmp/build7315640391316178285.tmp/preproc/ctags_target.cpp", prototypes[0].File) + require.Equal(t, "void loop();", prototypes[1].Prototype) + + prototypeLine := context[constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES].(int) + require.Equal(t, 16, prototypeLine) +} + +func TestCTagsToPrototypesDefaultArguments(t *testing.T) { + context := make(map[string]interface{}) + + bytes, err := ioutil.ReadFile(filepath.Join("ctags_output", "TestCTagsParserDefaultArguments.txt")) + NoError(t, err) + + context[constants.CTX_CTAGS_OUTPUT] = string(bytes) + + commands := []types.Command{ + &builder.CTagsParser{}, + &CopyContextKeys{From: constants.CTX_CTAGS_OF_PREPROC_SOURCE, To: constants.CTX_COLLECTED_CTAGS}, + &builder.CTagsToPrototypes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) + + require.Equal(t, 2, len(prototypes)) + require.Equal(t, "void setup();", prototypes[0].Prototype) + require.Equal(t, "/tmp/test179252494/preproc/ctags_target.cpp", prototypes[0].File) + require.Equal(t, "void loop();", prototypes[1].Prototype) + + prototypeLine := context[constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES].(int) + require.Equal(t, 2, prototypeLine) +} + +func TestCTagsToPrototypesNamespace(t *testing.T) { + context := make(map[string]interface{}) + + bytes, err := ioutil.ReadFile(filepath.Join("ctags_output", "TestCTagsParserNamespace.txt")) + NoError(t, err) + + context[constants.CTX_CTAGS_OUTPUT] = string(bytes) + + commands := []types.Command{ + &builder.CTagsParser{}, + &CopyContextKeys{From: constants.CTX_CTAGS_OF_PREPROC_SOURCE, To: constants.CTX_COLLECTED_CTAGS}, + &builder.CTagsToPrototypes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) + + require.Equal(t, 2, len(prototypes)) + require.Equal(t, "void setup();", prototypes[0].Prototype) + require.Equal(t, "/tmp/test030883150/preproc/ctags_target.cpp", prototypes[0].File) + require.Equal(t, "void loop();", prototypes[1].Prototype) + + prototypeLine := context[constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES].(int) + require.Equal(t, 8, prototypeLine) +} + +func TestCTagsToPrototypesStatic(t *testing.T) { + context := make(map[string]interface{}) + + bytes, err := ioutil.ReadFile(filepath.Join("ctags_output", "TestCTagsParserStatic.txt")) + NoError(t, err) + + context[constants.CTX_CTAGS_OUTPUT] = string(bytes) + + commands := []types.Command{ + &builder.CTagsParser{}, + &CopyContextKeys{From: constants.CTX_CTAGS_OF_PREPROC_SOURCE, To: constants.CTX_COLLECTED_CTAGS}, + &builder.CTagsToPrototypes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) + + require.Equal(t, 3, len(prototypes)) + require.Equal(t, "void setup();", prototypes[0].Prototype) + require.Equal(t, "/tmp/test542833488/preproc/ctags_target.cpp", prototypes[0].File) + require.Equal(t, "void loop();", prototypes[1].Prototype) + require.Equal(t, "void doStuff();", prototypes[2].Prototype) + require.Equal(t, "static", prototypes[2].Modifiers) + + prototypeLine := context[constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES].(int) + require.Equal(t, 2, prototypeLine) +} + +func TestCTagsToPrototypesFunctionPointer(t *testing.T) { + context := make(map[string]interface{}) + + bytes, err := ioutil.ReadFile(filepath.Join("ctags_output", "TestCTagsParserFunctionPointer.txt")) + NoError(t, err) + + context[constants.CTX_CTAGS_OUTPUT] = string(bytes) + + commands := []types.Command{ + &builder.CTagsParser{}, + &CopyContextKeys{From: constants.CTX_CTAGS_OF_PREPROC_SOURCE, To: constants.CTX_COLLECTED_CTAGS}, + &builder.CTagsToPrototypes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) + + require.Equal(t, 3, len(prototypes)) + require.Equal(t, "void t1Callback();", prototypes[0].Prototype) + require.Equal(t, "/tmp/test547238273/preproc/ctags_target.cpp", prototypes[0].File) + require.Equal(t, "void setup();", prototypes[1].Prototype) + require.Equal(t, "void loop();", prototypes[2].Prototype) + + prototypeLine := context[constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES].(int) + require.Equal(t, 2, prototypeLine) +} + +func TestCTagsToPrototypesFunctionPointers(t *testing.T) { + context := make(map[string]interface{}) + + bytes, err := ioutil.ReadFile(filepath.Join("ctags_output", "TestCTagsParserFunctionPointers.txt")) + NoError(t, err) + + context[constants.CTX_CTAGS_OUTPUT] = string(bytes) + + commands := []types.Command{ + &builder.CTagsParser{}, + &CopyContextKeys{From: constants.CTX_CTAGS_OF_PREPROC_SOURCE, To: constants.CTX_COLLECTED_CTAGS}, + &builder.CTagsToPrototypes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype) + + require.Equal(t, 2, len(prototypes)) + require.Equal(t, "void setup();", prototypes[0].Prototype) + require.Equal(t, "/tmp/test907446433/preproc/ctags_target.cpp", prototypes[0].File) + require.Equal(t, "void loop();", prototypes[1].Prototype) + + prototypeLine := context[constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES].(int) + require.Equal(t, 2, prototypeLine) +} diff --git a/src/arduino.cc/builder/test/downloaded_stuff_patches/.gitkeep b/src/arduino.cc/builder/test/downloaded_stuff_patches/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/arduino.cc/builder/test/downloaded_stuff_patches/avr_platform_patch.patch b/src/arduino.cc/builder/test/downloaded_stuff_patches/avr_platform_patch.patch deleted file mode 100644 index 57e3f495..00000000 --- a/src/arduino.cc/builder/test/downloaded_stuff_patches/avr_platform_patch.patch +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/downloaded_hardware/arduino/avr/platform.txt b/downloaded_hardware/arduino/avr/platform.txt -index 537fcc5..4e526d9 100644 ---- a/downloaded_hardware/arduino/avr/platform.txt -+++ b/downloaded_hardware/arduino/avr/platform.txt -@@ -81,6 +81,12 @@ recipe.size.regex=^(?:\.text|\.data|\.bootloader)\s+([0-9]+).* - recipe.size.regex.data=^(?:\.data|\.bss|\.noinit)\s+([0-9]+).* - recipe.size.regex.eeprom=^(?:\.eeprom)\s+([0-9]+).* - -+## Preprocessor -+preproc.includes.flags=-w -x c++ -M -MG -MP -+recipe.preproc.includes="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} {preproc.includes.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" -+ -+preproc.macros.flags=-w -x c++ -E -CC -+recipe.preproc.macros="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} {preproc.macros.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" - - # AVR Uploader/Programmers tools - # ------------------------------ diff --git a/src/arduino.cc/builder/test/hardware/platform.txt b/src/arduino.cc/builder/test/hardware/platform.txt index 0755c3ab..25054c03 100644 --- a/src/arduino.cc/builder/test/hardware/platform.txt +++ b/src/arduino.cc/builder/test/hardware/platform.txt @@ -1,9 +1,3 @@ -# ctags -# ------------------------------ -tools.ctags.path={runtime.tools.ctags.path} -tools.ctags.cmd.path={path}/ctags -tools.ctags.pattern="{cmd.path}" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns "{source_file}" - # coan # ------------------------------ tools.coan.path={runtime.tools.coan.path} diff --git a/src/arduino.cc/builder/test/hardware/watterott/avr/boards.txt b/src/arduino.cc/builder/test/hardware/watterott/avr/boards.txt new file mode 100644 index 00000000..be844787 --- /dev/null +++ b/src/arduino.cc/builder/test/hardware/watterott/avr/boards.txt @@ -0,0 +1,130 @@ +# VID 0x6666 is a prototype product Vendor ID +# http://www.linux-usb.org/usb.ids + +menu.speed=Speed +menu.core=Core +menu.info=Info + + +# ATmega32u4 @ 16 MHz +atmega32u4.name=ATmega32u4 +atmega32u4.menu.speed.16mhz=16 MHz +atmega32u4.menu.speed.16mhz.build.f_cpu=16000000L +atmega32u4.menu.speed.16mhz.bootloader.file=caterina_16mhz.hex +atmega32u4.menu.speed.8mhz=8 MHz +atmega32u4.menu.speed.8mhz.build.f_cpu=8000000L +atmega32u4.menu.speed.8mhz.bootloader.file=caterina_8mhz.hex +atmega32u4.vid.0=0x1D50 +atmega32u4.pid.0=0x60B0 +atmega32u4.vid.1=0x6666 +atmega32u4.pid.1=0x60B0 +atmega32u4.vid.2=0x2341 +atmega32u4.pid.2=0x0036 +atmega32u4.vid.3=0x2341 +atmega32u4.pid.3=0x8036 +atmega32u4.vid.4=0x2A03 +atmega32u4.pid.4=0x0036 +atmega32u4.vid.5=0x2A03 +atmega32u4.pid.5=0x8036 +atmega32u4.bootloader.tool=avrdude +atmega32u4.bootloader.low_fuses=0xff +atmega32u4.bootloader.high_fuses=0xd8 +atmega32u4.bootloader.extended_fuses=0xcb +#atmega32u4.bootloader.file=caterina_16mhz.hex +atmega32u4.bootloader.unlock_bits=0x3F +atmega32u4.bootloader.lock_bits=0x2F +atmega32u4.upload.tool=avrdude +atmega32u4.upload.protocol=avr109 +atmega32u4.upload.maximum_size=28672 +atmega32u4.upload.maximum_data_size=2560 +atmega32u4.upload.speed=57600 +atmega32u4.upload.disable_flushing=true +atmega32u4.upload.use_1200bps_touch=true +atmega32u4.upload.wait_for_upload_port=true +atmega32u4.build.mcu=atmega32u4 +#atmega32u4.build.f_cpu=16000000L +atmega32u4.build.vid=0x6666 +atmega32u4.build.pid=0x60B0 +atmega32u4.build.usb_product="USB IO Board" +atmega32u4.build.usb_manufacturer="ATmega32u4" +atmega32u4.build.board=AVR_LEONARDO +atmega32u4.build.core=arduino:arduino +atmega32u4.build.variant=leonardo +atmega32u4.build.extra_flags={build.usb_flags} -DMOUSE_ABS_ENABLED + + +# ATtiny841 @ internal 8 MHz +attiny841.name=ATtiny841 (8 MHz) +# use Standard Arduino Core +attiny841.menu.core.arduino=Standard Arduino +attiny841.menu.core.arduino.build.core=arduino:arduino +attiny841.menu.core.arduino.build.variant=tiny14 +# use Spence Konde Core: https://github.com/SpenceKonde/arduino-tiny-841/ +attiny841.menu.core.spencekonde=ATtiny841 (by Spence Konde) +#attiny841.menu.core.spencekonde.build.core=arduino-tiny-841:tiny +attiny841.menu.core.spencekonde.build.core=tiny841 +attiny841.menu.core.spencekonde.build.variant=tiny14 +# info menu item +attiny841.menu.info.info=Press Reset, when Uploading is shown. +attiny841.vid.0=0x16D0 +attiny841.pid.0=0x0753 +attiny841.bootloader.tool=avrdude +attiny841.bootloader.low_fuses=0xE2 +attiny841.bootloader.high_fuses=0xDD +attiny841.bootloader.extended_fuses=0xFE +attiny841.bootloader.unlock_bits=0xFF +attiny841.bootloader.lock_bits=0xFF +attiny841.bootloader.file=micronucleus-t841.hex +attiny841.upload.tool=micronucleus +attiny841.upload.protocol=usb +attiny841.upload.wait_for_upload_port=false +attiny841.upload.use_1200bps_touch=false +attiny841.upload.disable_flushing=false +attiny841.upload.maximum_size=6500 +attiny841.build.mcu=attiny841 +attiny841.build.f_cpu=8000000L +attiny841.build.board=AVR_ATTINY841 +#attiny841.build.core=arduino:arduino +#attiny841.build.variant=tiny14 + + +# ATtiny85 @ internal 16.5 MHz +attiny85.name=ATtiny85 (16.5 MHz) +# use Standard Arduino Core +attiny85.menu.core.arduino=Standard Arduino +attiny85.menu.core.arduino.build.board=AVR_ATTINY85 +attiny85.menu.core.arduino.build.core=arduino:arduino +attiny85.menu.core.arduino.build.variant=tiny8 +# use Spence Konde Core: https://github.com/SpenceKonde/ATTinyCore +attiny85.menu.core.spencekonde=ATtiny85 (by Spence Konde) +attiny85.menu.core.spencekonde.build.board=AVR_ATTINY85 +#attiny85.menu.core.spencekonde.build.core=ATTinyCore:tiny +attiny85.menu.core.spencekonde.build.core=tiny85 +attiny85.menu.core.spencekonde.build.variant=tiny8 +# use Digistump Core: https://github.com/digistump/DigistumpArduino +attiny85.menu.core.digistump=Digistump/Digispark +attiny85.menu.core.digistump.build.board=AVR_DIGISPARK +attiny85.menu.core.digistump.build.core=digistump:tiny +attiny85.menu.core.digistump.build.variant=digispark +# info menu item +attiny85.menu.info.info=Press Reset, when Uploading is shown. +attiny85.vid.0=0x16D0 +attiny85.pid.0=0x0753 +attiny85.bootloader.tool=avrdude +attiny85.bootloader.low_fuses=0xE1 +attiny85.bootloader.high_fuses=0xDD +attiny85.bootloader.extended_fuses=0xFE +attiny85.bootloader.unlock_bits=0xFF +attiny85.bootloader.lock_bits=0xFF +attiny85.bootloader.file=micronucleus-t85.hex +attiny85.upload.tool=micronucleus +attiny85.upload.protocol=usb +attiny85.upload.wait_for_upload_port=false +attiny85.upload.use_1200bps_touch=false +attiny85.upload.disable_flushing=false +attiny85.upload.maximum_size=6300 +attiny85.build.mcu=attiny85 +attiny85.build.f_cpu=16500000L +attiny85.build.board=AVR_ATTINY85 +#attiny85.build.core=arduino:arduino +#attiny85.build.variant=tiny8 diff --git a/src/arduino.cc/builder/test/hardware/watterott/avr/platform.txt b/src/arduino.cc/builder/test/hardware/watterott/avr/platform.txt new file mode 100644 index 00000000..13d46cea --- /dev/null +++ b/src/arduino.cc/builder/test/hardware/watterott/avr/platform.txt @@ -0,0 +1,146 @@ + +# Watterott AVR Core and platform. +# ------------------------------ +# +# For more info: +# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5-3rd-party-Hardware-specification + +name=Watterott AVR Boards +version=1.0.0 + +# AVR compile variables +# --------------------- + +compiler.warning_flags=-w +compiler.warning_flags.none=-w +compiler.warning_flags.default= +compiler.warning_flags.more=-Wall +compiler.warning_flags.all=-Wall -Wextra + +# Default "compiler.path" is correct, change only if you want to overidde the initial value +#compiler.path={runtime.ide.path}/hardware/tools/avr/bin/ +compiler.path={runtime.tools.avr-gcc.path}/bin/ +compiler.c.cmd=avr-gcc +compiler.c.flags=-c -g -Os {compiler.warning_flags} -ffunction-sections -fdata-sections -MMD +# -w flag added to avoid printing a wrong warning http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59396 +# This is fixed in gcc 4.8.3 and will be removed as soon as we update the toolchain +compiler.c.elf.flags=-Os {compiler.warning_flags} -Wl,--gc-sections +compiler.c.elf.cmd=avr-gcc +compiler.S.flags=-c -g -x assembler-with-cpp +compiler.cpp.cmd=avr-g++ +compiler.cpp.flags=-c -g -Os {compiler.warning_flags} -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD +compiler.ar.cmd=avr-ar +compiler.ar.flags=rcs +compiler.objcopy.cmd=avr-objcopy +compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 +compiler.elf2hex.flags=-O ihex -R .eeprom +compiler.elf2hex.cmd=avr-objcopy +compiler.ldflags= +compiler.size.cmd=avr-size + +# This can be overriden in boards.txt +build.extra_flags= + +# These can be overridden in platform.local.txt +compiler.c.extra_flags= +compiler.c.elf.extra_flags= +compiler.S.extra_flags= +compiler.cpp.extra_flags= +compiler.ar.extra_flags= +compiler.objcopy.eep.extra_flags= +compiler.elf2hex.extra_flags= + +# AVR compile patterns +# -------------------- + +## Compile c files +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" + +## Compile c++ files +recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" + +## Compile S files +recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.S.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" + +## Create archives +recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{build.path}/{archive_file}" "{object_file}" + +## Combine gc-sections, archives, and objects +recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mmcu={build.mcu} {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" {object_files} "{build.path}/{archive_file}" "-L{build.path}" -lm + +## Create output files (.eep and .hex) +recipe.objcopy.eep.pattern="{compiler.path}{compiler.objcopy.cmd}" {compiler.objcopy.eep.flags} {compiler.objcopy.eep.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.eep" +recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex" + +## Save hex +recipe.output.tmp_file={build.project_name}.hex +recipe.output.save_file={build.project_name}.{build.variant}.hex + +## Compute size +recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" +recipe.size.regex=^(?:\.text|\.data|\.bootloader)\s+([0-9]+).* +recipe.size.regex.data=^(?:\.data|\.bss|\.noinit)\s+([0-9]+).* +recipe.size.regex.eeprom=^(?:\.eeprom)\s+([0-9]+).* + +## Preprocessor +preproc.includes.flags=-w -x c++ -M -MG -MP +recipe.preproc.includes="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} {preproc.includes.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" +preproc.macros.flags=-w -x c++ -E -CC +recipe.preproc.macros="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} {preproc.macros.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" + + +# AVR Uploader/Programmers tools +# ------------------------------ + +## AVRdude +#tools.avrdude.path={runtime.ide.path}/hardware/tools/avr/ +tools.avrdude.path={runtime.tools.avrdude.path} +tools.avrdude.cmd.path={path}/bin/avrdude +#tools.avrdude.config.path={path}/etc/avrdude.conf +tools.avrdude.config.path={runtime.platform.path}/tools/avrdude.conf + +tools.avrdude.upload.params.verbose=-v +tools.avrdude.upload.params.quiet=-q -q +tools.avrdude.upload.pattern="{cmd.path}" "-C{config.path}" {upload.verbose} -p{build.mcu} -c{upload.protocol} -P{serial.port} -b{upload.speed} -D "-Uflash:w:{build.path}/{build.project_name}.hex:i" + +tools.avrdude.program.params.verbose=-v +tools.avrdude.program.params.quiet=-q -q +tools.avrdude.program.pattern="{cmd.path}" "-C{config.path}" {program.verbose} -p{build.mcu} -c{protocol} -P{serial.port} {program.extra_params} "-Uflash:w:{build.path}/{build.project_name}.hex:i" + +tools.avrdude.erase.params.verbose=-v +tools.avrdude.erase.params.quiet=-q -q +tools.avrdude.erase.pattern="{cmd.path}" "-C{config.path}" {erase.verbose} -p{build.mcu} -c{protocol} -P{serial.port} {program.extra_params} -e -Ulock:w:{bootloader.unlock_bits}:m -Uefuse:w:{bootloader.extended_fuses}:m -Uhfuse:w:{bootloader.high_fuses}:m -Ulfuse:w:{bootloader.low_fuses}:m + +tools.avrdude.bootloader.params.verbose=-v +tools.avrdude.bootloader.params.quiet=-q -q +tools.avrdude.bootloader.pattern="{cmd.path}" "-C{config.path}" {bootloader.verbose} -p{build.mcu} -c{protocol} -P{serial.port} {program.extra_params} "-Uflash:w:{runtime.platform.path}/bootloaders/{bootloader.file}:i" -Ulock:w:{bootloader.lock_bits}:m + +## Micronucleus +tools.micronucleus.path={runtime.tools.micronucleus.path} +tools.micronucleus.cmd=micronucleus +tools.micronucleus.cmd.windows=micronucleus.exe + +tools.micronucleus.upload.params.verbose= +tools.micronucleus.upload.params.quiet= +tools.micronucleus.upload.pattern="{path}/{cmd}" --run --timeout 60 "{build.path}/{build.project_name}.hex" + +tools.micronucleus.program.params.verbose= +tools.micronucleus.program.params.quiet= +tools.micronucleus.program.pattern="{path}/{cmd}" --run --timeout 60 "{build.path}/{build.project_name}.hex" + +tools.micronucleus.erase.params.verbose= +tools.micronucleus.erase.params.quiet= +tools.micronucleus.erase.pattern= +#tools.micronucleus.erase.pattern="{path}/{cmd}" --erase-only --timeout 60 + +tools.micronucleus.bootloader.params.verbose= +tools.micronucleus.bootloader.params.quiet= +tools.micronucleus.bootloader.pattern="{path}/{cmd}" --run --timeout 60 "{runtime.platform.path}/bootloaders/{bootloader.file}" + + +# USB Default Flags +# Default blank usb manufacturer will be filled it at compile time +# - from numeric vendor ID, set to Unknown otherwise +build.usb_manufacturer="Unknown" +build.usb_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' + diff --git a/src/arduino.cc/builder/test/hardware/watterott/avr/programmers.txt b/src/arduino.cc/builder/test/hardware/watterott/avr/programmers.txt new file mode 100644 index 00000000..e69de29b diff --git a/src/arduino.cc/builder/test/hardware_loader_test.go b/src/arduino.cc/builder/test/hardware_loader_test.go index 27d7ad9f..e0fec6e3 100644 --- a/src/arduino.cc/builder/test/hardware_loader_test.go +++ b/src/arduino.cc/builder/test/hardware_loader_test.go @@ -55,7 +55,7 @@ func TestLoadHardware(t *testing.T) { } packages := context[constants.CTX_HARDWARE].(*types.Packages) - require.Equal(t, 1, len(packages.Packages)) + require.Equal(t, 2, len(packages.Packages)) require.NotNil(t, packages.Packages["arduino"]) require.Equal(t, 2, len(packages.Packages["arduino"].Platforms)) @@ -79,7 +79,7 @@ func TestLoadHardware(t *testing.T) { require.Equal(t, "AVRISP mkII", avrPlatform.Programmers["avrispmkii"][constants.PROGRAMMER_NAME]) require.Equal(t, "{runtime.tools.ctags.path}", packages.Properties["tools.ctags.path"]) - require.Equal(t, "\"{cmd.path}\" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns \"{source_file}\"", packages.Properties["tools.ctags.pattern"]) + require.Equal(t, "\"{cmd.path}\" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives \"{source_file}\"", packages.Properties["tools.ctags.pattern"]) require.Equal(t, "{runtime.tools.avrdude.path}", packages.Properties["tools.avrdude.path"]) require.Equal(t, "-w -x c++ -E -CC", packages.Properties["preproc.macros.flags"]) } @@ -105,9 +105,9 @@ func TestLoadHardwareMixingUserHardwareFolder(t *testing.T) { if runtime.GOOS == "windows" { //a package is a symlink, and windows does not support them - require.Equal(t, 2, len(packages.Packages)) - } else { require.Equal(t, 3, len(packages.Packages)) + } else { + require.Equal(t, 4, len(packages.Packages)) } require.NotNil(t, packages.Packages["arduino"]) @@ -144,7 +144,7 @@ func TestLoadHardwareMixingUserHardwareFolder(t *testing.T) { require.False(t, utils.MapStringStringHas(myAVRPlatformAvrArch.Properties, "preproc.includes.flags")) require.Equal(t, "{runtime.tools.ctags.path}", packages.Properties["tools.ctags.path"]) - require.Equal(t, "\"{cmd.path}\" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns \"{source_file}\"", packages.Properties["tools.ctags.pattern"]) + require.Equal(t, "\"{cmd.path}\" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives \"{source_file}\"", packages.Properties["tools.ctags.pattern"]) require.Equal(t, "{runtime.tools.avrdude.path}", packages.Properties["tools.avrdude.path"]) require.Equal(t, "-w -x c++ -E -CC", packages.Properties["preproc.macros.flags"]) require.Equal(t, "{build.mbed_api_include} {build.nRF51822_api_include} {build.ble_api_include} {compiler.libsam.c.flags} {compiler.arm.cmsis.path} {build.variant_system_include}", packages.Properties["preproc.macros.compatibility_flags"]) @@ -222,9 +222,9 @@ func TestLoadLotsOfHardware(t *testing.T) { if runtime.GOOS == "windows" { //a package is a symlink, and windows does not support them - require.Equal(t, 4, len(packages.Packages)) - } else { require.Equal(t, 5, len(packages.Packages)) + } else { + require.Equal(t, 6, len(packages.Packages)) } require.NotNil(t, packages.Packages["arduino"]) diff --git a/src/arduino.cc/builder/test/helper.go b/src/arduino.cc/builder/test/helper.go index 50560b27..0bdffa51 100644 --- a/src/arduino.cc/builder/test/helper.go +++ b/src/arduino.cc/builder/test/helper.go @@ -95,3 +95,13 @@ func (s ByLibraryName) Swap(i, j int) { func (s ByLibraryName) Less(i, j int) bool { return s[i].Name < s[j].Name } + +type CopyContextKeys struct { + From string + To string +} + +func (s *CopyContextKeys) Run(context map[string]interface{}) error { + context[s.To] = context[s.From] + return nil +} diff --git a/src/arduino.cc/builder/test/helper_tools_downloader.go b/src/arduino.cc/builder/test/helper_tools_downloader.go index f9b34ba2..04e18c54 100644 --- a/src/arduino.cc/builder/test/helper_tools_downloader.go +++ b/src/arduino.cc/builder/test/helper_tools_downloader.go @@ -84,22 +84,25 @@ type Core struct { func DownloadCoresAndToolsAndLibraries(t *testing.T) { cores := []Core{ - Core{Maintainer: "arduino", Arch: "avr", Version: "1.6.8"}, - Core{Maintainer: "arduino", Arch: "sam", Version: "1.6.4"}, + Core{Maintainer: "arduino", Arch: "avr", Version: "1.6.9"}, + Core{Maintainer: "arduino", Arch: "sam", Version: "1.6.5"}, } boardsManagerCores := []Core{ - Core{Maintainer: "arduino", Arch: "samd", Version: "1.6.1"}, + Core{Maintainer: "arduino", Arch: "samd", Version: "1.6.2"}, } boardsManagerRedBearCores := []Core{ Core{Maintainer: "RedBearLab", Arch: "avr", Version: "1.0.0", Url: "https://redbearlab.github.io/arduino/Blend/blend_boards.zip"}, } + toolsMultipleVersions := []Tool{ + Tool{Name: "bossac", Version: "1.6.1-arduino"}, + Tool{Name: "bossac", Version: "1.5-arduino"}, + } + tools := []Tool{ Tool{Name: "avrdude", Version: "6.0.1-arduino5"}, - Tool{Name: "bossac", Version: "1.3a-arduino"}, - Tool{Name: "bossac", Version: "1.5-arduino"}, Tool{Name: "avr-gcc", Version: "4.8.1-arduino5"}, Tool{Name: "arm-none-eabi-gcc", Version: "4.8.3-2014q1"}, Tool{Name: "coan", Version: "5.2", OsUrls: []OsUrl{ @@ -108,17 +111,18 @@ func DownloadCoresAndToolsAndLibraries(t *testing.T) { OsUrl{Os: "i686-mingw32", Url: "http://downloads.arduino.cc/tools/coan-5.2-i686-mingw32.zip"}, OsUrl{Os: "x86_64-apple-darwin", Url: "http://downloads.arduino.cc/tools/coan-5.2-x86_64-apple-darwin.zip"}, }}, - Tool{Name: "ctags", Version: "5.8-arduino2", + Tool{Name: "ctags", Version: "5.8-arduino5", OsUrls: []OsUrl{ - OsUrl{Os: "i686-pc-linux-gnu", Url: "http://downloads.arduino.cc/tools/ctags-5.8-arduino2-i686-pc-linux-gnu.tar.bz2"}, - OsUrl{Os: "x86_64-pc-linux-gnu", Url: "http://downloads.arduino.cc/tools/ctags-5.8-arduino2-x86_64-pc-linux-gnu.tar.bz2"}, - OsUrl{Os: "i686-mingw32", Url: "http://downloads.arduino.cc/tools/ctags-5.8-arduino2-i686-mingw32.zip"}, - OsUrl{Os: "x86_64-apple-darwin", Url: "http://downloads.arduino.cc/tools/ctags-5.8-arduino2-x86_64-apple-darwin.zip"}, + OsUrl{Os: "i686-pc-linux-gnu", Url: "http://downloads.arduino.cc/tools/ctags-5.8-arduino5-i686-pc-linux-gnu.tar.bz2"}, + OsUrl{Os: "x86_64-pc-linux-gnu", Url: "http://downloads.arduino.cc/tools/ctags-5.8-arduino5-x86_64-pc-linux-gnu.tar.bz2"}, + OsUrl{Os: "i686-mingw32", Url: "http://downloads.arduino.cc/tools/ctags-5.8-arduino5-i686-mingw32.zip"}, + OsUrl{Os: "x86_64-apple-darwin", Url: "http://downloads.arduino.cc/tools/ctags-5.8-arduino5-x86_64-apple-darwin.zip"}, }}, } boardsManagerTools := []Tool{ Tool{Name: "openocd", Version: "0.9.0-arduino", Package: "arduino"}, + Tool{Name: "CMSIS", Version: "4.0.0-atmel", Package: "arduino"}, } boardsManagerRFduinoTools := []Tool{ @@ -133,12 +137,11 @@ func DownloadCoresAndToolsAndLibraries(t *testing.T) { Library{Name: "Robot IR Remote", Version: "1.0.2"}, } - download(t, cores, boardsManagerCores, boardsManagerRedBearCores, tools, boardsManagerTools, boardsManagerRFduinoTools, libraries) + download(t, cores, boardsManagerCores, boardsManagerRedBearCores, tools, toolsMultipleVersions, boardsManagerTools, boardsManagerRFduinoTools, libraries) patchFiles(t) } -// FIXME: once patched cores are released, patching them will be unnecessary func patchFiles(t *testing.T) { files, err := ioutil.ReadDir(PATCHES_FOLDER) NoError(t, err) @@ -151,13 +154,13 @@ func patchFiles(t *testing.T) { NoError(t, err) operations, err := patchSet.Apply(ioutil.ReadFile) for _, op := range operations { - ioutil.WriteFile(op.Dst, op.Data, os.FileMode(0644)) + utils.WriteFileBytes(op.Dst, op.Data) } } } } -func download(t *testing.T, cores, boardsManagerCores, boardsManagerRedBearCores []Core, tools, boardsManagerTools, boardsManagerRFduinoTools []Tool, libraries []Library) { +func download(t *testing.T, cores, boardsManagerCores, boardsManagerRedBearCores []Core, tools, toolsMultipleVersions, boardsManagerTools, boardsManagerRFduinoTools []Tool, libraries []Library) { allCoresDownloaded, err := allCoresAlreadyDownloadedAndUnpacked(HARDWARE_FOLDER, cores) NoError(t, err) if allCoresDownloaded && @@ -166,6 +169,7 @@ func download(t *testing.T, cores, boardsManagerCores, boardsManagerRedBearCores allBoardsManagerToolsAlreadyDownloadedAndUnpacked(BOARD_MANAGER_FOLDER, boardsManagerTools) && allBoardsManagerToolsAlreadyDownloadedAndUnpacked(BOARD_MANAGER_FOLDER, boardsManagerRFduinoTools) && allToolsAlreadyDownloadedAndUnpacked(TOOLS_FOLDER, tools) && + allToolsAlreadyDownloadedAndUnpacked(TOOLS_FOLDER, toolsMultipleVersions) && allLibrariesAlreadyDownloadedAndUnpacked(LIBRARIES_FOLDER, libraries) { return } @@ -182,6 +186,9 @@ func download(t *testing.T, cores, boardsManagerCores, boardsManagerRedBearCores err = downloadTools(tools, index) NoError(t, err) + err = downloadToolsMultipleVersions(toolsMultipleVersions, index) + NoError(t, err) + err = downloadBoardsManagerTools(boardsManagerTools, index) NoError(t, err) @@ -279,7 +286,36 @@ func downloadTools(tools []Tool, index map[string]interface{}) error { if err != nil { return utils.WrapError(err) } - err = downloadAndUnpackTool(tool, url, TOOLS_FOLDER) + err = downloadAndUnpackTool(tool, url, TOOLS_FOLDER, true) + if err != nil { + return utils.WrapError(err) + } + } + + return nil +} + +func downloadToolsMultipleVersions(tools []Tool, index map[string]interface{}) error { + host := translateGOOSGOARCHToPackageIndexValue() + + for _, tool := range tools { + if !toolAlreadyDownloadedAndUnpacked(TOOLS_FOLDER, tool) { + _, err := os.Stat(filepath.Join(TOOLS_FOLDER, tool.Name)) + if err == nil { + err = os.RemoveAll(filepath.Join(TOOLS_FOLDER, tool.Name)) + if err != nil { + return utils.WrapError(err) + } + } + } + } + + for _, tool := range tools { + url, err := findToolUrl(index, tool, host) + if err != nil { + return utils.WrapError(err) + } + err = downloadAndUnpackTool(tool, url, TOOLS_FOLDER, false) if err != nil { return utils.WrapError(err) } @@ -422,8 +458,16 @@ func downloadAndUnpackCore(core Core, url string, targetPath string) error { } defer os.RemoveAll(unpackFolder) + _, err = os.Stat(filepath.Join(targetPath, core.Maintainer, core.Arch)) + if err == nil { + err = os.RemoveAll(filepath.Join(targetPath, core.Maintainer, core.Arch)) + if err != nil { + return utils.WrapError(err) + } + } + if len(files) == 1 && files[0].IsDir() { - err = os.MkdirAll(filepath.Join(targetPath, core.Maintainer), os.FileMode(0755)) + err = utils.EnsureFolderExists(filepath.Join(targetPath, core.Maintainer)) if err != nil { return utils.WrapError(err) } @@ -432,7 +476,7 @@ func downloadAndUnpackCore(core Core, url string, targetPath string) error { return utils.WrapError(err) } } else { - err = os.MkdirAll(filepath.Join(targetPath, core.Maintainer, core.Arch), os.FileMode(0755)) + err = utils.EnsureFolderExists(filepath.Join(targetPath, core.Maintainer, core.Arch)) if err != nil { return utils.WrapError(err) } @@ -463,8 +507,16 @@ func downloadAndUnpackBoardManagerCore(core Core, url string, targetPath string) } defer os.RemoveAll(unpackFolder) + _, err = os.Stat(filepath.Join(targetPath, core.Maintainer, "hardware", core.Arch)) + if err == nil { + err = os.RemoveAll(filepath.Join(targetPath, core.Maintainer, "hardware", core.Arch)) + if err != nil { + return utils.WrapError(err) + } + } + if len(files) == 1 && files[0].IsDir() { - err = os.MkdirAll(filepath.Join(targetPath, core.Maintainer, "hardware", core.Arch), os.FileMode(0755)) + err = utils.EnsureFolderExists(filepath.Join(targetPath, core.Maintainer, "hardware", core.Arch)) if err != nil { return utils.WrapError(err) } @@ -473,7 +525,7 @@ func downloadAndUnpackBoardManagerCore(core Core, url string, targetPath string) return utils.WrapError(err) } } else { - err = os.MkdirAll(filepath.Join(targetPath, core.Maintainer, "hardware", core.Arch, core.Version), os.FileMode(0755)) + err = utils.EnsureFolderExists(filepath.Join(targetPath, core.Maintainer, "hardware", core.Arch, core.Version)) if err != nil { return utils.WrapError(err) } @@ -505,7 +557,7 @@ func downloadAndUnpackBoardsManagerTool(tool Tool, url string, targetPath string defer os.RemoveAll(unpackFolder) if len(files) == 1 && files[0].IsDir() { - err = os.MkdirAll(filepath.Join(targetPath, tool.Package, constants.FOLDER_TOOLS, tool.Name), os.FileMode(0755)) + err = utils.EnsureFolderExists(filepath.Join(targetPath, tool.Package, constants.FOLDER_TOOLS, tool.Name)) if err != nil { return utils.WrapError(err) } @@ -514,7 +566,7 @@ func downloadAndUnpackBoardsManagerTool(tool Tool, url string, targetPath string return utils.WrapError(err) } } else { - err = os.MkdirAll(filepath.Join(targetPath, tool.Package, constants.FOLDER_TOOLS, tool.Name, tool.Version), os.FileMode(0755)) + err = utils.EnsureFolderExists(filepath.Join(targetPath, tool.Package, constants.FOLDER_TOOLS, tool.Name, tool.Version)) if err != nil { return utils.WrapError(err) } @@ -529,7 +581,7 @@ func downloadAndUnpackBoardsManagerTool(tool Tool, url string, targetPath string return nil } -func downloadAndUnpackTool(tool Tool, url string, targetPath string) error { +func downloadAndUnpackTool(tool Tool, url string, targetPath string, deleteIfMissing bool) error { if toolAlreadyDownloadedAndUnpacked(targetPath, tool) { return nil } @@ -545,16 +597,18 @@ func downloadAndUnpackTool(tool Tool, url string, targetPath string) error { } defer os.RemoveAll(unpackFolder) - _, err = os.Stat(filepath.Join(targetPath, tool.Name)) - if err == nil { - err = os.RemoveAll(filepath.Join(targetPath, tool.Name)) - if err != nil { - return utils.WrapError(err) + if deleteIfMissing { + _, err = os.Stat(filepath.Join(targetPath, tool.Name)) + if err == nil { + err = os.RemoveAll(filepath.Join(targetPath, tool.Name)) + if err != nil { + return utils.WrapError(err) + } } } if len(files) == 1 && files[0].IsDir() { - err = os.MkdirAll(filepath.Join(targetPath, tool.Name), os.FileMode(0755)) + err = utils.EnsureFolderExists(filepath.Join(targetPath, tool.Name)) if err != nil { return utils.WrapError(err) } @@ -563,7 +617,7 @@ func downloadAndUnpackTool(tool Tool, url string, targetPath string) error { return utils.WrapError(err) } } else { - err = os.MkdirAll(filepath.Join(targetPath, tool.Name, tool.Version), os.FileMode(0755)) + err = utils.EnsureFolderExists(filepath.Join(targetPath, tool.Name, tool.Version)) if err != nil { return utils.WrapError(err) } @@ -601,7 +655,7 @@ func downloadAndUnpack(url string) (string, []os.FileInfo, error) { } res.Body.Close() - ioutil.WriteFile(archiveFilePath, bytes, os.FileMode(0644)) + utils.WriteFileBytes(archiveFilePath, bytes) cmd := buildUnpackCmd(archiveFilePath) out, err := cmd.CombinedOutput() diff --git a/src/arduino.cc/builder/test/i18n_test.go b/src/arduino.cc/builder/test/i18n_test.go index eb838207..9836c731 100644 --- a/src/arduino.cc/builder/test/i18n_test.go +++ b/src/arduino.cc/builder/test/i18n_test.go @@ -30,6 +30,7 @@ package test import ( + "arduino.cc/builder/constants" "arduino.cc/builder/i18n" "fmt" "github.com/stretchr/testify/require" @@ -64,8 +65,8 @@ func TestI18NSyntax(t *testing.T) { func TestI18NInheritance(t *testing.T) { var logger i18n.Logger logger = i18n.HumanLogger{} - logger.Println("good {0} {1}", "morning", "vietnam!") + logger.Println(constants.LOG_LEVEL_INFO, "good {0} {1}", "morning", "vietnam!") logger = i18n.MachineLogger{} - logger.Println("good {0} {1}", "morning", "vietnam!") + logger.Println(constants.LOG_LEVEL_INFO, "good {0} {1}", "morning", "vietnam!") } diff --git a/src/arduino.cc/builder/test/includes_finder_with_gcc_test.go b/src/arduino.cc/builder/test/includes_finder_with_gcc_test.go index 8c2808a5..7f2c3e11 100644 --- a/src/arduino.cc/builder/test/includes_finder_with_gcc_test.go +++ b/src/arduino.cc/builder/test/includes_finder_with_gcc_test.go @@ -54,7 +54,7 @@ func TestIncludesFinderWithGCC(t *testing.T) { context[constants.CTX_FQBN] = "arduino:avr:leonardo" context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch2", "SketchWithIfDef.ino") context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -71,12 +71,7 @@ func TestIncludesFinderWithGCC(t *testing.T) { NoError(t, err) } - require.NotNil(t, context[constants.CTX_INCLUDES]) - includes := context[constants.CTX_INCLUDES].([]string) - require.Equal(t, 2, len(includes)) - sort.Strings(includes) - require.Equal(t, filepath.Join(buildPath, constants.FOLDER_SKETCH, "empty_1.h"), includes[0]) - require.Equal(t, filepath.Join(buildPath, constants.FOLDER_SKETCH, "empty_2.h"), includes[1]) + require.Nil(t, context[constants.CTX_INCLUDES]) } func TestIncludesFinderWithGCCSketchWithConfig(t *testing.T) { @@ -94,7 +89,7 @@ func TestIncludesFinderWithGCCSketchWithConfig(t *testing.T) { context[constants.CTX_FQBN] = "arduino:avr:leonardo" context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch_with_config", "sketch_with_config.ino") context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -113,8 +108,7 @@ func TestIncludesFinderWithGCCSketchWithConfig(t *testing.T) { require.NotNil(t, context[constants.CTX_INCLUDES]) includes := context[constants.CTX_INCLUDES].([]string) - require.True(t, utils.SliceContains(includes, filepath.Join(buildPath, constants.FOLDER_SKETCH, "config.h"))) - require.True(t, utils.SliceContains(includes, filepath.Join(buildPath, constants.FOLDER_SKETCH, "includes")+"/de bug.h")) + require.Equal(t, 1, len(includes)) require.True(t, utils.SliceContains(includes, "Bridge.h")) importedLibraries := context[constants.CTX_IMPORTED_LIBRARIES].([]*types.Library) @@ -136,7 +130,7 @@ func TestIncludesFinderWithGCCSketchWithDependendLibraries(t *testing.T) { context[constants.CTX_FQBN] = "arduino:avr:leonardo" context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch_with_dependend_libraries", "sketch.ino") context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -155,16 +149,13 @@ func TestIncludesFinderWithGCCSketchWithDependendLibraries(t *testing.T) { require.NotNil(t, context[constants.CTX_INCLUDES]) includes := context[constants.CTX_INCLUDES].([]string) - require.Equal(t, 7, len(includes)) + require.Equal(t, 4, len(includes)) sort.Strings(includes) - require.Equal(t, Abs(t, filepath.Join("dependent_libraries", "library1"))+"/library1.h", includes[0]) - require.Equal(t, Abs(t, filepath.Join("dependent_libraries", "library2"))+"/library2.h", includes[1]) - require.Equal(t, Abs(t, filepath.Join("dependent_libraries", "library3"))+"/library3.h", includes[2]) - require.Equal(t, "library1.h", includes[3]) - require.Equal(t, "library2.h", includes[4]) - require.Equal(t, "library3.h", includes[5]) - require.Equal(t, "library4.h", includes[6]) + require.Equal(t, "library1.h", includes[0]) + require.Equal(t, "library2.h", includes[1]) + require.Equal(t, "library3.h", includes[2]) + require.Equal(t, "library4.h", includes[3]) importedLibraries := context[constants.CTX_IMPORTED_LIBRARIES].([]*types.Library) require.Equal(t, 4, len(importedLibraries)) @@ -175,3 +166,91 @@ func TestIncludesFinderWithGCCSketchWithDependendLibraries(t *testing.T) { require.Equal(t, "library3", importedLibraries[2].Name) require.Equal(t, "library4", importedLibraries[3].Name) } + +func TestIncludesFinderWithGCCSketchWithThatChecksIfSPIHasTransactions(t *testing.T) { + DownloadCoresAndToolsAndLibraries(t) + + context := make(map[string]interface{}) + + buildPath := SetupBuildPath(t, context) + defer os.RemoveAll(buildPath) + + context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} + context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} + context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} + context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"dependent_libraries", "libraries"} + context[constants.CTX_FQBN] = "arduino:avr:leonardo" + context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch_that_checks_if_SPI_has_transactions", "sketch.ino") + context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" + context[constants.CTX_VERBOSE] = true + + commands := []types.Command{ + &builder.SetupHumanLoggerIfMissing{}, + + &builder.ContainerSetupHardwareToolsLibsSketchAndProps{}, + + &builder.ContainerMergeCopySketchFiles{}, + + &builder.ContainerFindIncludes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + require.NotNil(t, context[constants.CTX_INCLUDES]) + includes := context[constants.CTX_INCLUDES].([]string) + require.Equal(t, 1, len(includes)) + require.Equal(t, "SPI.h", includes[0]) + + importedLibraries := context[constants.CTX_IMPORTED_LIBRARIES].([]*types.Library) + require.Equal(t, 1, len(importedLibraries)) + require.Equal(t, "SPI", importedLibraries[0].Name) +} + +func TestIncludesFinderWithGCCSketchWithThatChecksIfSPIHasTransactionsAndIncludesMissingEthernet(t *testing.T) { + DownloadCoresAndToolsAndLibraries(t) + + context := make(map[string]interface{}) + + buildPath := SetupBuildPath(t, context) + defer os.RemoveAll(buildPath) + + context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} + context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} + context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} + context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"dependent_libraries", "libraries"} + context[constants.CTX_FQBN] = "arduino:avr:leonardo" + context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch_that_checks_if_SPI_has_transactions_and_includes_missing_Ethernet", "sketch.ino") + context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" + context[constants.CTX_VERBOSE] = true + + commands := []types.Command{ + &builder.SetupHumanLoggerIfMissing{}, + + &builder.ContainerSetupHardwareToolsLibsSketchAndProps{}, + + &builder.ContainerMergeCopySketchFiles{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + command := &builder.ContainerFindIncludes{} + err := command.Run(context) + require.Error(t, err) + + require.NotNil(t, context[constants.CTX_INCLUDES]) + includes := context[constants.CTX_INCLUDES].([]string) + require.Equal(t, 2, len(includes)) + sort.Strings(includes) + require.Equal(t, "Ethernet.h", includes[0]) + require.Equal(t, "SPI.h", includes[1]) + + importedLibraries := context[constants.CTX_IMPORTED_LIBRARIES].([]*types.Library) + require.Equal(t, 1, len(importedLibraries)) + require.Equal(t, "SPI", importedLibraries[0].Name) +} diff --git a/src/arduino.cc/builder/test/includes_finder_with_regexp_test.go b/src/arduino.cc/builder/test/includes_finder_with_regexp_test.go index 46a07d98..d6be6bbc 100644 --- a/src/arduino.cc/builder/test/includes_finder_with_regexp_test.go +++ b/src/arduino.cc/builder/test/includes_finder_with_regexp_test.go @@ -36,10 +36,11 @@ import ( "github.com/stretchr/testify/require" "os" "path/filepath" + "sort" "testing" ) -func TestIncludesFinderWithRegExp(t *testing.T) { +func TestIncludesFinderWithRegExpCoanOutput(t *testing.T) { DownloadCoresAndToolsAndLibraries(t) context := make(map[string]interface{}) @@ -52,7 +53,7 @@ func TestIncludesFinderWithRegExp(t *testing.T) { context[constants.CTX_FQBN] = "arduino:avr:leonardo" context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch2", "SketchWithIfDef.ino") context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -62,6 +63,8 @@ func TestIncludesFinderWithRegExp(t *testing.T) { &builder.ContainerMergeCopySketchFiles{}, &builder.CoanRunner{}, + + &builder.IncludesFinderWithRegExp{ContextField: constants.CTX_SOURCE}, } for _, command := range commands { @@ -69,13 +72,113 @@ func TestIncludesFinderWithRegExp(t *testing.T) { NoError(t, err) } - includesFinder := builder.IncludesFinderWithRegExp{} - err := includesFinder.Run(context) + require.NotNil(t, context[constants.CTX_INCLUDES]) + includes := context[constants.CTX_INCLUDES].([]string) + require.Equal(t, 3, len(includes)) + require.Equal(t, "Arduino.h", includes[0]) + require.Equal(t, "empty_1.h", includes[1]) + require.Equal(t, "empty_2.h", includes[2]) +} + +func TestIncludesFinderWithRegExp(t *testing.T) { + context := make(map[string]interface{}) + + output := "/some/path/sketch.ino:1:17: fatal error: SPI.h: No such file or directory\n" + + "#include \n" + + "^\n" + + "compilation terminated." + context["source"] = output + + parser := builder.IncludesFinderWithRegExp{ContextField: "source"} + err := parser.Run(context) + NoError(t, err) + + require.NotNil(t, context[constants.CTX_INCLUDES]) + includes := context[constants.CTX_INCLUDES].([]string) + require.Equal(t, 1, len(includes)) + require.Equal(t, "SPI.h", includes[0]) +} + +func TestIncludesFinderWithRegExpEmptyOutput(t *testing.T) { + context := make(map[string]interface{}) + + output := "" + + context["source"] = output + + parser := builder.IncludesFinderWithRegExp{ContextField: "source"} + err := parser.Run(context) + NoError(t, err) + + require.NotNil(t, context[constants.CTX_INCLUDES]) + includes := context[constants.CTX_INCLUDES].([]string) + require.Equal(t, 0, len(includes)) +} + +func TestIncludesFinderWithRegExpPreviousIncludes(t *testing.T) { + context := make(map[string]interface{}) + + context[constants.CTX_INCLUDES] = []string{"test.h"} + + output := "/some/path/sketch.ino:1:17: fatal error: SPI.h: No such file or directory\n" + + "#include \n" + + "^\n" + + "compilation terminated." + + context["source"] = output + + parser := builder.IncludesFinderWithRegExp{ContextField: "source"} + err := parser.Run(context) NoError(t, err) require.NotNil(t, context[constants.CTX_INCLUDES]) includes := context[constants.CTX_INCLUDES].([]string) require.Equal(t, 2, len(includes)) - require.Equal(t, "empty_1.h", includes[0]) - require.Equal(t, "empty_2.h", includes[1]) + sort.Strings(includes) + require.Equal(t, "SPI.h", includes[0]) + require.Equal(t, "test.h", includes[1]) +} + +func TestIncludesFinderWithRegExpPaddedIncludes(t *testing.T) { + context := make(map[string]interface{}) + + context[constants.CTX_INCLUDES] = []string{} + + output := "/some/path/sketch.ino:1:33: fatal error: Wire.h: No such file or directory\n" + + " # include \n" + + " ^\n" + + "compilation terminated.\n" + context["source"] = output + + parser := builder.IncludesFinderWithRegExp{ContextField: "source"} + err := parser.Run(context) + NoError(t, err) + + require.NotNil(t, context[constants.CTX_INCLUDES]) + includes := context[constants.CTX_INCLUDES].([]string) + require.Equal(t, 1, len(includes)) + sort.Strings(includes) + require.Equal(t, "Wire.h", includes[0]) +} + +func TestIncludesFinderWithRegExpPaddedIncludes2(t *testing.T) { + context := make(map[string]interface{}) + + context[constants.CTX_INCLUDES] = []string{} + + output := "/some/path/sketch.ino:1:33: fatal error: Wire.h: No such file or directory\n" + + " #\t\t\tinclude \n" + + " ^\n" + + "compilation terminated.\n" + context["source"] = output + + parser := builder.IncludesFinderWithRegExp{ContextField: "source"} + err := parser.Run(context) + NoError(t, err) + + require.NotNil(t, context[constants.CTX_INCLUDES]) + includes := context[constants.CTX_INCLUDES].([]string) + require.Equal(t, 1, len(includes)) + sort.Strings(includes) + require.Equal(t, "Wire.h", includes[0]) } diff --git a/src/arduino.cc/builder/test/includes_to_include_folders_test.go b/src/arduino.cc/builder/test/includes_to_include_folders_test.go index b035221e..8d29018b 100644 --- a/src/arduino.cc/builder/test/includes_to_include_folders_test.go +++ b/src/arduino.cc/builder/test/includes_to_include_folders_test.go @@ -55,7 +55,7 @@ func TestIncludesToIncludeFolders(t *testing.T) { context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -96,7 +96,7 @@ func TestIncludesToIncludeFoldersSketchWithIfDef(t *testing.T) { context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -135,7 +135,7 @@ func TestIncludesToIncludeFoldersIRremoteLibrary(t *testing.T) { context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -179,7 +179,7 @@ func TestIncludesToIncludeFoldersANewLibrary(t *testing.T) { context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -222,7 +222,7 @@ func TestIncludesToIncludeFoldersDuplicateLibs(t *testing.T) { context[constants.CTX_SKETCH_LOCATION] = filepath.Join("user_hardware", "my_avr_platform", "avr", "libraries", "SPI", "examples", "BarometricPressureSensor", "BarometricPressureSensor.ino") context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -265,7 +265,7 @@ func TestIncludesToIncludeFoldersDuplicateLibsWithConflictingLibsOutsideOfPlatfo context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -308,6 +308,7 @@ func TestIncludesToIncludeFoldersDuplicateLibs2(t *testing.T) { context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, diff --git a/src/arduino.cc/builder/test/libraries/wronglib/library.properties b/src/arduino.cc/builder/test/libraries/wronglib/library.properties new file mode 100644 index 00000000..26c53df4 --- /dev/null +++ b/src/arduino.cc/builder/test/libraries/wronglib/library.properties @@ -0,0 +1,8 @@ +name=wronglib +version=1.0 +author=Arduino +maintainer=Arduino +sentence=sentence +paragraph=paragraph +url=url +architectures=* diff --git a/src/arduino.cc/builder/test/libraries/wronglib/src/.gitkeep b/src/arduino.cc/builder/test/libraries/wronglib/src/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/arduino.cc/builder/test/libraries/wronglib/utility/.gitkeep b/src/arduino.cc/builder/test/libraries/wronglib/utility/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/arduino.cc/builder/test/libraries_loader_test.go b/src/arduino.cc/builder/test/libraries_loader_test.go index ea895417..71b7e04a 100644 --- a/src/arduino.cc/builder/test/libraries_loader_test.go +++ b/src/arduino.cc/builder/test/libraries_loader_test.go @@ -69,7 +69,7 @@ func TestLoadLibrariesAVR(t *testing.T) { require.Equal(t, Abs(t, filepath.Join("libraries")), librariesFolders[2]) libraries := context[constants.CTX_LIBRARIES].([]*types.Library) - require.Equal(t, 16, len(libraries)) + require.Equal(t, 18, len(libraries)) sort.Sort(ByLibraryName(libraries)) @@ -109,6 +109,8 @@ func TestLoadLibrariesAVR(t *testing.T) { idx++ require.Equal(t, "FakeAudio", libraries[idx].Name) idx++ + require.Equal(t, "HID", libraries[idx].Name) + idx++ require.Equal(t, "IRremote", libraries[idx].Name) idx++ require.Equal(t, "Robot_IR_Remote", libraries[idx].Name) @@ -173,7 +175,7 @@ func TestLoadLibrariesSAM(t *testing.T) { require.Equal(t, Abs(t, filepath.Join("libraries")), librariesFolders[2]) libraries := context[constants.CTX_LIBRARIES].([]*types.Library) - require.Equal(t, 14, len(libraries)) + require.Equal(t, 16, len(libraries)) sort.Sort(ByLibraryName(libraries)) @@ -192,6 +194,8 @@ func TestLoadLibrariesSAM(t *testing.T) { idx++ require.Equal(t, "FakeAudio", libraries[idx].Name) idx++ + require.Equal(t, "HID", libraries[idx].Name) + idx++ require.Equal(t, "IRremote", libraries[idx].Name) idx++ require.Equal(t, "Robot_IR_Remote", libraries[idx].Name) diff --git a/src/arduino.cc/builder/test/load_previous_build_options_map_test.go b/src/arduino.cc/builder/test/load_previous_build_options_map_test.go index bc94252b..295e6e3c 100644 --- a/src/arduino.cc/builder/test/load_previous_build_options_map_test.go +++ b/src/arduino.cc/builder/test/load_previous_build_options_map_test.go @@ -34,7 +34,6 @@ import ( "arduino.cc/builder/constants" "arduino.cc/builder/utils" "github.com/stretchr/testify/require" - "io/ioutil" "os" "path/filepath" "testing" @@ -46,7 +45,7 @@ func TestLoadPreviousBuildOptionsMap(t *testing.T) { buildPath := SetupBuildPath(t, context) defer os.RemoveAll(buildPath) - err := ioutil.WriteFile(filepath.Join(buildPath, constants.BUILD_OPTIONS_FILE), []byte("test"), os.FileMode(0644)) + err := utils.WriteFile(filepath.Join(buildPath, constants.BUILD_OPTIONS_FILE), "test") NoError(t, err) command := builder.LoadPreviousBuildOptionsMap{} diff --git a/src/arduino.cc/builder/test/merge_sketch_with_bootloader_test.go b/src/arduino.cc/builder/test/merge_sketch_with_bootloader_test.go index 9a3cca27..8bfd4913 100644 --- a/src/arduino.cc/builder/test/merge_sketch_with_bootloader_test.go +++ b/src/arduino.cc/builder/test/merge_sketch_with_bootloader_test.go @@ -33,6 +33,7 @@ import ( "arduino.cc/builder" "arduino.cc/builder/constants" "arduino.cc/builder/types" + "arduino.cc/builder/utils" "github.com/stretchr/testify/require" "io/ioutil" "os" @@ -57,12 +58,12 @@ func TestMergeSketchWithBootloader(t *testing.T) { context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch1", "sketch.ino") context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" - err := os.MkdirAll(filepath.Join(buildPath, "sketch"), os.FileMode(0755)) + err := utils.EnsureFolderExists(filepath.Join(buildPath, "sketch")) NoError(t, err) fakeSketchHex := "row 1\n" + "row 2\n" - err = ioutil.WriteFile(filepath.Join(buildPath, "sketch", "sketch.ino.hex"), []byte(fakeSketchHex), os.FileMode(0644)) + err = utils.WriteFile(filepath.Join(buildPath, "sketch", "sketch.ino.hex"), fakeSketchHex) NoError(t, err) commands := []types.Command{ @@ -100,12 +101,12 @@ func TestMergeSketchWithBootloaderSketchInBuildPath(t *testing.T) { context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch1", "sketch.ino") context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" - err := os.MkdirAll(filepath.Join(buildPath, "sketch"), os.FileMode(0755)) + err := utils.EnsureFolderExists(filepath.Join(buildPath, "sketch")) NoError(t, err) fakeSketchHex := "row 1\n" + "row 2\n" - err = ioutil.WriteFile(filepath.Join(buildPath, "sketch.ino.hex"), []byte(fakeSketchHex), os.FileMode(0644)) + err = utils.WriteFile(filepath.Join(buildPath, "sketch.ino.hex"), fakeSketchHex) NoError(t, err) commands := []types.Command{ @@ -165,3 +166,46 @@ func TestMergeSketchWithBootloaderWhenNoBootloaderAvailable(t *testing.T) { require.Error(t, err) require.True(t, os.IsNotExist(err)) } + +func TestMergeSketchWithBootloaderPathIsParameterized(t *testing.T) { + DownloadCoresAndToolsAndLibraries(t) + + context := make(map[string]interface{}) + + buildPath := SetupBuildPath(t, context) + defer os.RemoveAll(buildPath) + + context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware", "user_hardware"} + context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} + context[constants.CTX_FQBN] = "my_avr_platform:avr:mymega:cpu=atmega2560" + context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} + context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} + context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch1", "sketch.ino") + context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" + + err := utils.EnsureFolderExists(filepath.Join(buildPath, "sketch")) + NoError(t, err) + + fakeSketchHex := "row 1\n" + + "row 2\n" + err = utils.WriteFile(filepath.Join(buildPath, "sketch", "sketch.ino.hex"), fakeSketchHex) + NoError(t, err) + + commands := []types.Command{ + &builder.SetupHumanLoggerIfMissing{}, + &builder.ContainerSetupHardwareToolsLibsSketchAndProps{}, + &builder.MergeSketchWithBootloader{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + bytes, err := ioutil.ReadFile(filepath.Join(buildPath, "sketch", "sketch.ino.with_bootloader.hex")) + NoError(t, err) + mergedSketchHex := string(bytes) + + require.True(t, strings.HasPrefix(mergedSketchHex, "row 1\n:020000023000CC")) + require.True(t, strings.HasSuffix(mergedSketchHex, ":040000033000E000E9\n:00000001FF\n")) +} diff --git a/src/arduino.cc/builder/test/platform_keys_rewrite_loader_test.go b/src/arduino.cc/builder/test/platform_keys_rewrite_loader_test.go index e8b714e5..694d33af 100644 --- a/src/arduino.cc/builder/test/platform_keys_rewrite_loader_test.go +++ b/src/arduino.cc/builder/test/platform_keys_rewrite_loader_test.go @@ -54,7 +54,7 @@ func TestLoadPlatformKeysRewrite(t *testing.T) { platformKeysRewrite := context[constants.CTX_PLATFORM_KEYS_REWRITE].(types.PlatforKeysRewrite) - require.Equal(t, 12, len(platformKeysRewrite.Rewrites)) + require.Equal(t, 13, len(platformKeysRewrite.Rewrites)) require.Equal(t, constants.BUILD_PROPERTIES_COMPILER_PATH, platformKeysRewrite.Rewrites[0].Key) require.Equal(t, "{runtime.ide.path}/hardware/tools/avr/bin/", platformKeysRewrite.Rewrites[0].OldValue) require.Equal(t, "{runtime.tools.avr-gcc.path}/bin/", platformKeysRewrite.Rewrites[0].NewValue) diff --git a/src/arduino.cc/builder/test/prototypes_adder_test.go b/src/arduino.cc/builder/test/prototypes_adder_test.go index 996b5554..0be24def 100644 --- a/src/arduino.cc/builder/test/prototypes_adder_test.go +++ b/src/arduino.cc/builder/test/prototypes_adder_test.go @@ -49,14 +49,18 @@ func TestPrototypesAdderBridgeExample(t *testing.T) { buildPath := SetupBuildPath(t, context) defer os.RemoveAll(buildPath) + sketchLocation := filepath.Join("downloaded_libraries", "Bridge", "examples", "Bridge", "Bridge.ino") + absoluteSketchLocation := strings.Replace(Abs(t, sketchLocation), "\\", "\\\\", -1) + context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} context[constants.CTX_FQBN] = "arduino:avr:leonardo" - context[constants.CTX_SKETCH_LOCATION] = filepath.Join("downloaded_libraries", "Bridge", "examples", "Bridge", "Bridge.ino") + context[constants.CTX_SKETCH_LOCATION] = sketchLocation context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true + context[constants.CTX_DEBUG_LEVEL] = 10 commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -79,7 +83,7 @@ func TestPrototypesAdderBridgeExample(t *testing.T) { } require.Equal(t, "#include \n#line 1\n", context[constants.CTX_INCLUDE_SECTION].(string)) - require.Equal(t, "void setup();\nvoid loop();\nvoid process(BridgeClient client);\nvoid digitalCommand(BridgeClient client);\nvoid analogCommand(BridgeClient client);\nvoid modeCommand(BridgeClient client);\n#line 33\n", context[constants.CTX_PROTOTYPE_SECTION].(string)) + require.Equal(t, "#line 33 \""+absoluteSketchLocation+"\"\nvoid setup();\n#line 46 \""+absoluteSketchLocation+"\"\nvoid loop();\n#line 62 \""+absoluteSketchLocation+"\"\nvoid process(BridgeClient client);\n#line 82 \""+absoluteSketchLocation+"\"\nvoid digitalCommand(BridgeClient client);\n#line 109 \""+absoluteSketchLocation+"\"\nvoid analogCommand(BridgeClient client);\n#line 149 \""+absoluteSketchLocation+"\"\nvoid modeCommand(BridgeClient client);\n#line 33\n", context[constants.CTX_PROTOTYPE_SECTION].(string)) } func TestPrototypesAdderSketchWithIfDef(t *testing.T) { @@ -138,7 +142,7 @@ func TestPrototypesAdderBaladuino(t *testing.T) { context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -179,7 +183,7 @@ func TestPrototypesAdderCharWithEscapedDoubleQuote(t *testing.T) { context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -261,7 +265,7 @@ func TestPrototypesAdderLineContinuations(t *testing.T) { context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -302,7 +306,7 @@ func TestPrototypesAdderStringWithComment(t *testing.T) { context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -343,7 +347,7 @@ func TestPrototypesAdderSketchWithStruct(t *testing.T) { context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -377,14 +381,17 @@ func TestPrototypesAdderSketchWithConfig(t *testing.T) { buildPath := SetupBuildPath(t, context) defer os.RemoveAll(buildPath) + sketchLocation := filepath.Join("sketch_with_config", "sketch_with_config.ino") + absoluteSketchLocation := strings.Replace(Abs(t, sketchLocation), "\\", "\\\\", -1) + context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} context[constants.CTX_FQBN] = "arduino:avr:leonardo" - context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch_with_config", "sketch_with_config.ino") + context[constants.CTX_SKETCH_LOCATION] = sketchLocation context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -407,7 +414,7 @@ func TestPrototypesAdderSketchWithConfig(t *testing.T) { } require.Equal(t, "#include \n#line 1\n", context[constants.CTX_INCLUDE_SECTION].(string)) - require.Equal(t, "void setup();\nvoid loop();\n#line 13\n", context[constants.CTX_PROTOTYPE_SECTION].(string)) + require.Equal(t, "#line 13 \""+absoluteSketchLocation+"\"\nvoid setup();\n#line 17 \""+absoluteSketchLocation+"\"\nvoid loop();\n#line 13\n", context[constants.CTX_PROTOTYPE_SECTION].(string)) preprocessed := LoadAndInterpolate(t, filepath.Join("sketch_with_config", "sketch_with_config.preprocessed.txt"), context) require.Equal(t, preprocessed, strings.Replace(context[constants.CTX_SOURCE].(string), "\r\n", "\n", -1)) @@ -450,7 +457,7 @@ func TestPrototypesAdderSketchNoFunctionsTwoFiles(t *testing.T) { NoError(t, err) } - require.Nil(t, context[constants.CTX_INCLUDE_SECTION]) + require.Equal(t, "#include \n#line 1\n", context[constants.CTX_INCLUDE_SECTION].(string)) require.Nil(t, context[constants.CTX_PROTOTYPE_SECTION]) } @@ -491,7 +498,7 @@ func TestPrototypesAdderSketchNoFunctions(t *testing.T) { NoError(t, err) } - require.Nil(t, context[constants.CTX_INCLUDE_SECTION]) + require.Equal(t, "#include \n#line 1\n", context[constants.CTX_INCLUDE_SECTION].(string)) require.Nil(t, context[constants.CTX_PROTOTYPE_SECTION]) } @@ -503,14 +510,17 @@ func TestPrototypesAdderSketchWithDefaultArgs(t *testing.T) { buildPath := SetupBuildPath(t, context) defer os.RemoveAll(buildPath) + sketchLocation := filepath.Join("sketch_with_default_args", "sketch.ino") + absoluteSketchLocation := strings.Replace(Abs(t, sketchLocation), "\\", "\\\\", -1) + context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} context[constants.CTX_FQBN] = "arduino:avr:leonardo" - context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch_with_default_args", "sketch.ino") + context[constants.CTX_SKETCH_LOCATION] = sketchLocation context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -533,7 +543,7 @@ func TestPrototypesAdderSketchWithDefaultArgs(t *testing.T) { } require.Equal(t, "#include \n#line 1\n", context[constants.CTX_INCLUDE_SECTION].(string)) - require.Equal(t, "void setup();\nvoid loop();\n#line 1\n", context[constants.CTX_PROTOTYPE_SECTION].(string)) + require.Equal(t, "#line 4 \""+absoluteSketchLocation+"\"\nvoid setup();\n#line 7 \""+absoluteSketchLocation+"\"\nvoid loop();\n#line 1\n", context[constants.CTX_PROTOTYPE_SECTION].(string)) } func TestPrototypesAdderSketchWithInlineFunction(t *testing.T) { @@ -544,14 +554,17 @@ func TestPrototypesAdderSketchWithInlineFunction(t *testing.T) { buildPath := SetupBuildPath(t, context) defer os.RemoveAll(buildPath) + sketchLocation := filepath.Join("sketch_with_inline_function", "sketch.ino") + absoluteSketchLocation := strings.Replace(Abs(t, sketchLocation), "\\", "\\\\", -1) + context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} context[constants.CTX_FQBN] = "arduino:avr:leonardo" - context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch_with_inline_function", "sketch.ino") + context[constants.CTX_SKETCH_LOCATION] = sketchLocation context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} - context[constants.CTX_VERBOSE] = false + context[constants.CTX_VERBOSE] = true commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -574,7 +587,7 @@ func TestPrototypesAdderSketchWithInlineFunction(t *testing.T) { } require.Equal(t, "#include \n#line 1\n", context[constants.CTX_INCLUDE_SECTION].(string)) - require.Equal(t, "void setup();\nvoid loop();\nshort unsigned int testInt();\nint8_t testInline();\nuint8_t testAttribute();\n#line 1\n", context[constants.CTX_PROTOTYPE_SECTION].(string)) + require.Equal(t, "#line 1 \""+absoluteSketchLocation+"\"\nvoid setup();\n#line 2 \""+absoluteSketchLocation+"\"\nvoid loop();\n#line 4 \""+absoluteSketchLocation+"\"\nshort unsigned int testInt();\n#line 8 \""+absoluteSketchLocation+"\"\nstatic int8_t testInline();\n#line 12 \""+absoluteSketchLocation+"\"\nuint8_t testAttribute();\n#line 1\n", context[constants.CTX_PROTOTYPE_SECTION].(string)) } func TestPrototypesAdderSketchWithFunctionSignatureInsideIFDEF(t *testing.T) { @@ -585,10 +598,13 @@ func TestPrototypesAdderSketchWithFunctionSignatureInsideIFDEF(t *testing.T) { buildPath := SetupBuildPath(t, context) defer os.RemoveAll(buildPath) + sketchLocation := filepath.Join("sketch_with_function_signature_inside_ifdef", "sketch.ino") + absoluteSketchLocation := strings.Replace(Abs(t, sketchLocation), "\\", "\\\\", -1) + context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} context[constants.CTX_FQBN] = "arduino:avr:leonardo" - context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch_with_function_signature_inside_ifdef", "sketch.ino") + context[constants.CTX_SKETCH_LOCATION] = sketchLocation context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} @@ -615,7 +631,7 @@ func TestPrototypesAdderSketchWithFunctionSignatureInsideIFDEF(t *testing.T) { } require.Equal(t, "#include \n#line 1\n", context[constants.CTX_INCLUDE_SECTION].(string)) - require.Equal(t, "void setup();\nvoid loop();\nint8_t adalight();\n#line 1\n", context[constants.CTX_PROTOTYPE_SECTION].(string)) + require.Equal(t, "#line 1 \""+absoluteSketchLocation+"\"\nvoid setup();\n#line 3 \""+absoluteSketchLocation+"\"\nvoid loop();\n#line 15 \""+absoluteSketchLocation+"\"\nint8_t adalight();\n#line 1\n", context[constants.CTX_PROTOTYPE_SECTION].(string)) } func TestPrototypesAdderSketchWithUSBCON(t *testing.T) { @@ -626,10 +642,194 @@ func TestPrototypesAdderSketchWithUSBCON(t *testing.T) { buildPath := SetupBuildPath(t, context) defer os.RemoveAll(buildPath) + sketchLocation := filepath.Join("sketch_with_usbcon", "sketch.ino") + absoluteSketchLocation := strings.Replace(Abs(t, sketchLocation), "\\", "\\\\", -1) + + context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} + context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} + context[constants.CTX_FQBN] = "arduino:avr:leonardo" + context[constants.CTX_SKETCH_LOCATION] = sketchLocation + context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" + context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} + context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} + context[constants.CTX_VERBOSE] = true + + commands := []types.Command{ + &builder.SetupHumanLoggerIfMissing{}, + + &builder.ContainerSetupHardwareToolsLibsSketchAndProps{}, + + &builder.ContainerMergeCopySketchFiles{}, + + &builder.ContainerFindIncludes{}, + + &builder.PrintUsedLibrariesIfVerbose{}, + &builder.WarnAboutArchIncompatibleLibraries{}, + + &builder.ContainerAddPrototypes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + require.Equal(t, "#include \n#line 1\n", context[constants.CTX_INCLUDE_SECTION].(string)) + require.Equal(t, "#line 5 \""+absoluteSketchLocation+"\"\nvoid ciao();\n#line 10 \""+absoluteSketchLocation+"\"\nvoid setup();\n#line 15 \""+absoluteSketchLocation+"\"\nvoid loop();\n#line 5\n", context[constants.CTX_PROTOTYPE_SECTION].(string)) +} + +func TestPrototypesAdderSketchWithTypename(t *testing.T) { + DownloadCoresAndToolsAndLibraries(t) + + context := make(map[string]interface{}) + + buildPath := SetupBuildPath(t, context) + defer os.RemoveAll(buildPath) + + sketchLocation := filepath.Join("sketch_with_typename", "sketch.ino") + absoluteSketchLocation := strings.Replace(Abs(t, sketchLocation), "\\", "\\\\", -1) + context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} context[constants.CTX_FQBN] = "arduino:avr:leonardo" - context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch_with_usbcon", "sketch.ino") + context[constants.CTX_SKETCH_LOCATION] = sketchLocation + context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" + context[constants.CTX_LIBRARIES_FOLDERS] = []string{"libraries", "downloaded_libraries"} + context[constants.CTX_VERBOSE] = true + + commands := []types.Command{ + &builder.SetupHumanLoggerIfMissing{}, + + &builder.ContainerSetupHardwareToolsLibsSketchAndProps{}, + + &builder.ContainerMergeCopySketchFiles{}, + + &builder.ContainerFindIncludes{}, + + &builder.PrintUsedLibrariesIfVerbose{}, + &builder.WarnAboutArchIncompatibleLibraries{}, + + &builder.ContainerAddPrototypes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + require.Equal(t, "#include \n#line 1\n", context[constants.CTX_INCLUDE_SECTION].(string)) + require.Equal(t, "#line 6 \""+absoluteSketchLocation+"\"\nvoid setup();\n#line 10 \""+absoluteSketchLocation+"\"\nvoid loop();\n#line 6\n", context[constants.CTX_PROTOTYPE_SECTION].(string)) +} + +func TestPrototypesAdderSketchWithIfDef2(t *testing.T) { + DownloadCoresAndToolsAndLibraries(t) + + context := make(map[string]interface{}) + + buildPath := SetupBuildPath(t, context) + defer os.RemoveAll(buildPath) + + sketchLocation := filepath.Join("sketch_with_ifdef", "sketch.ino") + absoluteSketchLocation := strings.Replace(Abs(t, sketchLocation), "\\", "\\\\", -1) + + context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} + context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} + context[constants.CTX_FQBN] = "arduino:avr:yun" + context[constants.CTX_SKETCH_LOCATION] = sketchLocation + context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" + context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} + context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} + context[constants.CTX_VERBOSE] = true + + commands := []types.Command{ + &builder.SetupHumanLoggerIfMissing{}, + + &builder.ContainerSetupHardwareToolsLibsSketchAndProps{}, + + &builder.ContainerMergeCopySketchFiles{}, + + &builder.ContainerFindIncludes{}, + + &builder.PrintUsedLibrariesIfVerbose{}, + &builder.WarnAboutArchIncompatibleLibraries{}, + + &builder.ContainerAddPrototypes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + require.Equal(t, "#include \n#line 1\n", context[constants.CTX_INCLUDE_SECTION].(string)) + require.Equal(t, "#line 5 \""+absoluteSketchLocation+"\"\nvoid elseBranch();\n#line 9 \""+absoluteSketchLocation+"\"\nvoid f1();\n#line 10 \""+absoluteSketchLocation+"\"\nvoid f2();\n#line 12 \""+absoluteSketchLocation+"\"\nvoid setup();\n#line 14 \""+absoluteSketchLocation+"\"\nvoid loop();\n#line 5\n", context[constants.CTX_PROTOTYPE_SECTION].(string)) + + expectedSource := LoadAndInterpolate(t, filepath.Join("sketch_with_ifdef", "sketch.preprocessed.txt"), context) + require.Equal(t, expectedSource, strings.Replace(context[constants.CTX_SOURCE].(string), "\r\n", "\n", -1)) +} + +func TestPrototypesAdderSketchWithIfDef2SAM(t *testing.T) { + DownloadCoresAndToolsAndLibraries(t) + + context := make(map[string]interface{}) + + buildPath := SetupBuildPath(t, context) + defer os.RemoveAll(buildPath) + + sketchLocation := filepath.Join("sketch_with_ifdef", "sketch.ino") + absoluteSketchLocation := strings.Replace(Abs(t, sketchLocation), "\\", "\\\\", -1) + + context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} + context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} + context[constants.CTX_FQBN] = "arduino:sam:arduino_due_x_dbg" + context[constants.CTX_SKETCH_LOCATION] = sketchLocation + context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" + context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} + context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} + context[constants.CTX_VERBOSE] = true + + commands := []types.Command{ + &builder.SetupHumanLoggerIfMissing{}, + + &builder.ContainerSetupHardwareToolsLibsSketchAndProps{}, + + &builder.ContainerMergeCopySketchFiles{}, + + &builder.ContainerFindIncludes{}, + + &builder.PrintUsedLibrariesIfVerbose{}, + &builder.WarnAboutArchIncompatibleLibraries{}, + + &builder.ContainerAddPrototypes{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + require.Equal(t, "#include \n#line 1\n", context[constants.CTX_INCLUDE_SECTION].(string)) + require.Equal(t, "#line 2 \""+absoluteSketchLocation+"\"\nvoid ifBranch();\n#line 9 \""+absoluteSketchLocation+"\"\nvoid f1();\n#line 10 \""+absoluteSketchLocation+"\"\nvoid f2();\n#line 12 \""+absoluteSketchLocation+"\"\nvoid setup();\n#line 14 \""+absoluteSketchLocation+"\"\nvoid loop();\n#line 2\n", context[constants.CTX_PROTOTYPE_SECTION].(string)) + + expectedSource := LoadAndInterpolate(t, filepath.Join("sketch_with_ifdef", "sketch.preprocessed.SAM.txt"), context) + require.Equal(t, expectedSource, strings.Replace(context[constants.CTX_SOURCE].(string), "\r\n", "\n", -1)) +} + +func TestPrototypesAdderSketchWithConst(t *testing.T) { + DownloadCoresAndToolsAndLibraries(t) + + context := make(map[string]interface{}) + + buildPath := SetupBuildPath(t, context) + defer os.RemoveAll(buildPath) + + sketchLocation := filepath.Join("sketch_with_const", "sketch.ino") + absoluteSketchLocation := strings.Replace(Abs(t, sketchLocation), "\\", "\\\\", -1) + + context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} + context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} + context[constants.CTX_FQBN] = "arduino:avr:uno" + context[constants.CTX_SKETCH_LOCATION] = sketchLocation context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} @@ -656,5 +856,5 @@ func TestPrototypesAdderSketchWithUSBCON(t *testing.T) { } require.Equal(t, "#include \n#line 1\n", context[constants.CTX_INCLUDE_SECTION].(string)) - require.Equal(t, "void ciao();\nvoid setup();\nvoid loop();\n#line 3\n", context[constants.CTX_PROTOTYPE_SECTION].(string)) + require.Equal(t, "#line 1 \""+absoluteSketchLocation+"\"\nvoid setup();\n#line 2 \""+absoluteSketchLocation+"\"\nvoid loop();\n#line 4 \""+absoluteSketchLocation+"\"\nconst __FlashStringHelper* test();\n#line 6 \""+absoluteSketchLocation+"\"\nconst int test3();\n#line 8 \""+absoluteSketchLocation+"\"\nvolatile __FlashStringHelper* test2();\n#line 10 \""+absoluteSketchLocation+"\"\nvolatile int test4();\n#line 1\n", context[constants.CTX_PROTOTYPE_SECTION].(string)) } diff --git a/src/arduino.cc/builder/test/read_file_and_store_in_context_test.go b/src/arduino.cc/builder/test/read_file_and_store_in_context_test.go new file mode 100644 index 00000000..2734725a --- /dev/null +++ b/src/arduino.cc/builder/test/read_file_and_store_in_context_test.go @@ -0,0 +1,57 @@ +/* + * This file is part of Arduino Builder. + * + * Arduino Builder is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + */ + +package test + +import ( + "arduino.cc/builder" + "arduino.cc/builder/constants" + "arduino.cc/builder/utils" + "github.com/stretchr/testify/require" + "io/ioutil" + "os" + "testing" +) + +func TestReadFileAndStoreInContext(t *testing.T) { + file, err := ioutil.TempFile("", "test") + NoError(t, err) + defer os.RemoveAll(file.Name()) + + utils.WriteFile(file.Name(), "test test\nciao") + + context := make(map[string]interface{}) + context[constants.CTX_FILE_PATH_TO_READ] = file.Name() + + command := &builder.ReadFileAndStoreInContext{TargetField: constants.CTX_GCC_MINUS_E_SOURCE} + err = command.Run(context) + NoError(t, err) + + require.Equal(t, "test test\nciao", context[constants.CTX_GCC_MINUS_E_SOURCE].(string)) +} diff --git a/src/arduino.cc/builder/test/setup_build_properties_test.go b/src/arduino.cc/builder/test/setup_build_properties_test.go index 16e9bcf6..d63f87ec 100644 --- a/src/arduino.cc/builder/test/setup_build_properties_test.go +++ b/src/arduino.cc/builder/test/setup_build_properties_test.go @@ -87,9 +87,9 @@ func TestSetupBuildProperties(t *testing.T) { require.Equal(t, Abs(t, "./downloaded_tools/arm-none-eabi-gcc/4.8.3-2014q1"), buildProperties["runtime.tools.arm-none-eabi-gcc.path"]) require.Equal(t, Abs(t, "./downloaded_tools/arm-none-eabi-gcc/4.8.3-2014q1"), buildProperties["runtime.tools.arm-none-eabi-gcc-4.8.3-2014q1.path"]) - require.Equal(t, Abs(t, "./downloaded_tools/bossac/1.3a-arduino"), buildProperties["runtime.tools.bossac-1.3a-arduino.path"]) + require.Equal(t, Abs(t, "./downloaded_tools/bossac/1.6.1-arduino"), buildProperties["runtime.tools.bossac-1.6.1-arduino.path"]) require.Equal(t, Abs(t, "./downloaded_tools/bossac/1.5-arduino"), buildProperties["runtime.tools.bossac-1.5-arduino.path"]) - require.True(t, buildProperties["runtime.tools.bossac.path"] == Abs(t, "./downloaded_tools/bossac/1.3a-arduino") || buildProperties["runtime.tools.bossac.path"] == Abs(t, "./downloaded_tools/bossac/1.5-arduino")) + require.True(t, buildProperties["runtime.tools.bossac.path"] == Abs(t, "./downloaded_tools/bossac/1.6.1-arduino") || buildProperties["runtime.tools.bossac.path"] == Abs(t, "./downloaded_tools/bossac/1.5-arduino")) require.Equal(t, Abs(t, "./downloaded_tools/avrdude/6.0.1-arduino5"), buildProperties["runtime.tools.avrdude.path"]) require.Equal(t, Abs(t, "./downloaded_tools/avrdude/6.0.1-arduino5"), buildProperties["runtime.tools.avrdude-6.0.1-arduino5.path"]) require.Equal(t, Abs(t, "./downloaded_tools/avr-gcc/4.8.1-arduino5"), buildProperties["runtime.tools.avr-gcc.path"]) @@ -228,9 +228,9 @@ func TestSetupBuildPropertiesWithMissingPropsFromParentPlatformTxtFiles(t *testi require.Equal(t, Abs(t, "./downloaded_tools/arm-none-eabi-gcc/4.8.3-2014q1"), buildProperties["runtime.tools.arm-none-eabi-gcc.path"]) require.Equal(t, Abs(t, "./downloaded_tools/arm-none-eabi-gcc/4.8.3-2014q1"), buildProperties["runtime.tools.arm-none-eabi-gcc-4.8.3-2014q1.path"]) - require.Equal(t, Abs(t, "./downloaded_tools/bossac/1.3a-arduino"), buildProperties["runtime.tools.bossac-1.3a-arduino.path"]) + require.Equal(t, Abs(t, "./downloaded_tools/bossac/1.6.1-arduino"), buildProperties["runtime.tools.bossac-1.6.1-arduino.path"]) require.Equal(t, Abs(t, "./downloaded_tools/bossac/1.5-arduino"), buildProperties["runtime.tools.bossac-1.5-arduino.path"]) - require.True(t, buildProperties["runtime.tools.bossac.path"] == Abs(t, "./downloaded_tools/bossac/1.3a-arduino") || buildProperties["runtime.tools.bossac.path"] == Abs(t, "./downloaded_tools/bossac/1.5-arduino")) + require.True(t, buildProperties["runtime.tools.bossac.path"] == Abs(t, "./downloaded_tools/bossac/1.6.1-arduino") || buildProperties["runtime.tools.bossac.path"] == Abs(t, "./downloaded_tools/bossac/1.5-arduino")) require.Equal(t, Abs(t, "./downloaded_tools/avrdude/6.0.1-arduino5"), buildProperties["runtime.tools.avrdude.path"]) require.Equal(t, Abs(t, "./downloaded_tools/avrdude/6.0.1-arduino5"), buildProperties["runtime.tools.avrdude-6.0.1-arduino5.path"]) require.Equal(t, Abs(t, "./downloaded_tools/avr-gcc/4.8.1-arduino5"), buildProperties["runtime.tools.avr-gcc.path"]) diff --git a/src/arduino.cc/builder/test/sketch1/merged_sketch.txt b/src/arduino.cc/builder/test/sketch1/merged_sketch.txt index a342aec5..362cfc82 100644 --- a/src/arduino.cc/builder/test/sketch1/merged_sketch.txt +++ b/src/arduino.cc/builder/test/sketch1/merged_sketch.txt @@ -1,3 +1,5 @@ +#include +#line 1 #line 1 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void setup() { diff --git a/src/arduino.cc/builder/test/sketch1/s_file.S b/src/arduino.cc/builder/test/sketch1/s_file.S new file mode 100644 index 00000000..e69de29b diff --git a/src/arduino.cc/builder/test/sketch2/SketchWithIfDef.preprocessed.txt b/src/arduino.cc/builder/test/sketch2/SketchWithIfDef.preprocessed.txt index b7a637d5..cd473ce8 100644 --- a/src/arduino.cc/builder/test/sketch2/SketchWithIfDef.preprocessed.txt +++ b/src/arduino.cc/builder/test/sketch2/SketchWithIfDef.preprocessed.txt @@ -16,10 +16,15 @@ typedef MyType int; #include "empty_2.h" +#line 16 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void setup(); +#line 21 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void loop(); +#line 33 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void debug(); +#line 44 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void disabledIsDefined(); +#line 48 "{{EscapeBackSlashes .sketch.MainFile.Name}}" int useMyType(MyType type); #line 16 void setup() { diff --git a/src/arduino.cc/builder/test/sketch2/SketchWithIfDef.resolved.directives.txt b/src/arduino.cc/builder/test/sketch2/SketchWithIfDef.resolved.directives.txt index 1c964ddf..75f8b730 100644 --- a/src/arduino.cc/builder/test/sketch2/SketchWithIfDef.resolved.directives.txt +++ b/src/arduino.cc/builder/test/sketch2/SketchWithIfDef.resolved.directives.txt @@ -1,3 +1,5 @@ +#include +#line 1 #line 1 "{{EscapeBackSlashes .sketch.MainFile.Name}}" #define DEBUG 1 #define DISABLED 0 diff --git a/src/arduino.cc/builder/test/sketch3/Baladuino.preprocessed.txt b/src/arduino.cc/builder/test/sketch3/Baladuino.preprocessed.txt index 3f8700c5..e11411d8 100644 --- a/src/arduino.cc/builder/test/sketch3/Baladuino.preprocessed.txt +++ b/src/arduino.cc/builder/test/sketch3/Baladuino.preprocessed.txt @@ -88,7 +88,9 @@ WII Wii(&Btd); // The Wii library can communicate with Wiimotes and the Nunchuck // This can also be done using the Android or Processing application #endif +#line 88 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void setup(); +#line 204 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void loop(); #line 88 void setup() { diff --git a/src/arduino.cc/builder/test/sketch4/CharWithEscapedDoubleQuote.preprocessed.txt b/src/arduino.cc/builder/test/sketch4/CharWithEscapedDoubleQuote.preprocessed.txt index 51351faf..caa42958 100644 --- a/src/arduino.cc/builder/test/sketch4/CharWithEscapedDoubleQuote.preprocessed.txt +++ b/src/arduino.cc/builder/test/sketch4/CharWithEscapedDoubleQuote.preprocessed.txt @@ -39,26 +39,47 @@ Code Exclusively for GPRS shield: // Default set of instructions for GPRS Shield power control // +#line 39 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void setPowerStateTo( int newState ); +#line 64 "{{EscapeBackSlashes .sketch.MainFile.Name}}" int getPowerState(); +#line 75 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void powerUpOrDown(); +#line 90 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void clearBufferArray(); +#line 96 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void makeMissedCall( char num[] ); +#line 111 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void sendTextMessage( char number[], char messg[] ); +#line 129 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void analise(byte incoming[], int length); +#line 179 "{{EscapeBackSlashes .sketch.MainFile.Name}}" byte decToBcd( byte b ); +#line 184 "{{EscapeBackSlashes .sketch.MainFile.Name}}" boolean getBit( byte addr, int pos ); +#line 190 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void setBit( byte addr, int pos, boolean newBit ); +#line 204 "{{EscapeBackSlashes .sketch.MainFile.Name}}" byte getByte( byte addr ); +#line 213 "{{EscapeBackSlashes .sketch.MainFile.Name}}" boolean getBytes( byte addr, int amount ); +#line 230 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void setByte( byte addr, byte newByte ); +#line 235 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void setBytes( byte addr, byte newBytes[], int amount ); +#line 244 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void getTime(); +#line 260 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void setTime( byte newTime[ 7 ] ); +#line 267 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void getRTCTemperature(); +#line 277 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void gprsListen(); +#line 294 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void printTime(); +#line 317 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void setup(); +#line 334 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void loop(); #line 39 void setPowerStateTo( int newState ) diff --git a/src/arduino.cc/builder/test/sketch5/IncludeBetweenMultilineComment.preprocessed.txt b/src/arduino.cc/builder/test/sketch5/IncludeBetweenMultilineComment.preprocessed.txt index a7e6a1ca..8dcc3599 100644 --- a/src/arduino.cc/builder/test/sketch5/IncludeBetweenMultilineComment.preprocessed.txt +++ b/src/arduino.cc/builder/test/sketch5/IncludeBetweenMultilineComment.preprocessed.txt @@ -6,7 +6,9 @@ #include */ CapacitiveSensor cs_13_8 = CapacitiveSensor(13,8); +#line 6 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void setup(); +#line 10 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void loop(); #line 6 void setup() diff --git a/src/arduino.cc/builder/test/sketch6/LineContinuations.preprocessed.txt b/src/arduino.cc/builder/test/sketch6/LineContinuations.preprocessed.txt index f1680a19..5742adcc 100644 --- a/src/arduino.cc/builder/test/sketch6/LineContinuations.preprocessed.txt +++ b/src/arduino.cc/builder/test/sketch6/LineContinuations.preprocessed.txt @@ -7,7 +7,9 @@ world\n"; //" delete this comment line and the IDE parser will crash +#line 7 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void setup(); +#line 11 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void loop(); #line 7 void setup() diff --git a/src/arduino.cc/builder/test/sketch7/StringWithComment.preprocessed.txt b/src/arduino.cc/builder/test/sketch7/StringWithComment.preprocessed.txt index de22ef9b..9e6f2bcf 100644 --- a/src/arduino.cc/builder/test/sketch7/StringWithComment.preprocessed.txt +++ b/src/arduino.cc/builder/test/sketch7/StringWithComment.preprocessed.txt @@ -1,7 +1,9 @@ #include #line 1 #line 1 "{{EscapeBackSlashes .sketch.MainFile.Name}}" +#line 1 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void setup(); +#line 10 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void loop(); #line 1 void setup() { diff --git a/src/arduino.cc/builder/test/sketch8/SketchWithStruct.preprocessed.txt b/src/arduino.cc/builder/test/sketch8/SketchWithStruct.preprocessed.txt index 3519359e..8808f91e 100644 --- a/src/arduino.cc/builder/test/sketch8/SketchWithStruct.preprocessed.txt +++ b/src/arduino.cc/builder/test/sketch8/SketchWithStruct.preprocessed.txt @@ -9,8 +9,11 @@ struct A_NEW_TYPE { int c; } foo; +#line 9 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void setup(); +#line 13 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void loop(); +#line 17 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void dostuff(A_NEW_TYPE * bar); #line 9 void setup() { diff --git a/src/arduino.cc/builder/test/sketch_loader_test.go b/src/arduino.cc/builder/test/sketch_loader_test.go index 15db8d2a..120c68f1 100644 --- a/src/arduino.cc/builder/test/sketch_loader_test.go +++ b/src/arduino.cc/builder/test/sketch_loader_test.go @@ -35,7 +35,6 @@ import ( "arduino.cc/builder/types" "github.com/stretchr/testify/require" "path/filepath" - "strings" "testing" ) @@ -90,15 +89,16 @@ func TestLoadSketch(t *testing.T) { sketch := context[constants.CTX_SKETCH].(*types.Sketch) require.NotNil(t, sketch) - require.True(t, strings.Index(sketch.MainFile.Name, "sketch.ino") != -1) + require.Contains(t, sketch.MainFile.Name, "sketch.ino") require.Equal(t, 2, len(sketch.OtherSketchFiles)) - require.True(t, strings.Index(sketch.OtherSketchFiles[0].Name, "old.pde") != -1) - require.True(t, strings.Index(sketch.OtherSketchFiles[1].Name, "other.ino") != -1) + require.Contains(t, sketch.OtherSketchFiles[0].Name, "old.pde") + require.Contains(t, sketch.OtherSketchFiles[1].Name, "other.ino") - require.Equal(t, 2, len(sketch.AdditionalFiles)) - require.True(t, strings.Index(sketch.AdditionalFiles[0].Name, "header.h") != -1) - require.True(t, strings.Index(sketch.AdditionalFiles[1].Name, "helper.h") != -1) + require.Equal(t, 3, len(sketch.AdditionalFiles)) + require.Contains(t, sketch.AdditionalFiles[0].Name, "header.h") + require.Contains(t, sketch.AdditionalFiles[1].Name, "s_file.S") + require.Contains(t, sketch.AdditionalFiles[2].Name, "helper.h") } func TestFailToLoadSketchFromFolder(t *testing.T) { @@ -134,10 +134,13 @@ func TestLoadSketchFromFolder(t *testing.T) { sketch := context[constants.CTX_SKETCH].(*types.Sketch) require.NotNil(t, sketch) - require.True(t, strings.Index(sketch.MainFile.Name, "sketch_with_subfolders.ino") != -1) + require.Contains(t, sketch.MainFile.Name, "sketch_with_subfolders.ino") + + require.Equal(t, 0, len(sketch.OtherSketchFiles)) - require.Equal(t, 1, len(sketch.AdditionalFiles)) - require.True(t, strings.Index(sketch.AdditionalFiles[0].Name, "other.cpp") != -1) + require.Equal(t, 2, len(sketch.AdditionalFiles)) + require.Contains(t, sketch.AdditionalFiles[0].Name, "other.cpp") + require.Contains(t, sketch.AdditionalFiles[1].Name, "other.h") } func TestLoadSketchWithBackup(t *testing.T) { @@ -157,7 +160,30 @@ func TestLoadSketchWithBackup(t *testing.T) { sketch := context[constants.CTX_SKETCH].(*types.Sketch) require.NotNil(t, sketch) - require.True(t, strings.Index(sketch.MainFile.Name, "sketch.ino") != -1) + require.Contains(t, sketch.MainFile.Name, "sketch.ino") + + require.Equal(t, 0, len(sketch.AdditionalFiles)) + require.Equal(t, 0, len(sketch.OtherSketchFiles)) +} + +func TestLoadSketchWithMacOSXGarbage(t *testing.T) { + context := make(map[string]interface{}) + context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch_with_macosx_garbage", "sketch.ino") + + commands := []types.Command{ + &builder.SetupHumanLoggerIfMissing{}, + &builder.SketchLoader{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + sketch := context[constants.CTX_SKETCH].(*types.Sketch) + require.NotNil(t, sketch) + + require.Contains(t, sketch.MainFile.Name, "sketch.ino") require.Equal(t, 0, len(sketch.AdditionalFiles)) require.Equal(t, 0, len(sketch.OtherSketchFiles)) diff --git a/src/arduino.cc/builder/test/sketch_that_checks_if_SPI_has_transactions/sketch.ino b/src/arduino.cc/builder/test/sketch_that_checks_if_SPI_has_transactions/sketch.ino new file mode 100644 index 00000000..106c39f2 --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_that_checks_if_SPI_has_transactions/sketch.ino @@ -0,0 +1,8 @@ +#include + +#if !defined(SPI_HAS_TRANSACTION) || !SPI_HAS_TRANSACTION +#error "Where is my SPI_HAS_TRANSACTION!?!?" +#endif + +void setup() {} +void loop() {} diff --git a/src/arduino.cc/builder/test/sketch_that_checks_if_SPI_has_transactions_and_includes_missing_Ethernet/sketch.ino b/src/arduino.cc/builder/test/sketch_that_checks_if_SPI_has_transactions_and_includes_missing_Ethernet/sketch.ino new file mode 100644 index 00000000..1a2f81c1 --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_that_checks_if_SPI_has_transactions_and_includes_missing_Ethernet/sketch.ino @@ -0,0 +1,9 @@ +#include +#include + +#if !defined(SPI_HAS_TRANSACTION) || !SPI_HAS_TRANSACTION +#error "Where is my SPI_HAS_TRANSACTION!?!?" +#endif + +void setup() {} +void loop() {} diff --git a/src/arduino.cc/builder/test/sketch_with_config/sketch_with_config.preprocessed.txt b/src/arduino.cc/builder/test/sketch_with_config/sketch_with_config.preprocessed.txt index f8e85df5..f706e579 100644 --- a/src/arduino.cc/builder/test/sketch_with_config/sketch_with_config.preprocessed.txt +++ b/src/arduino.cc/builder/test/sketch_with_config/sketch_with_config.preprocessed.txt @@ -13,7 +13,9 @@ #include +#line 13 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void setup(); +#line 17 "{{EscapeBackSlashes .sketch.MainFile.Name}}" void loop(); #line 13 void setup() { diff --git a/src/arduino.cc/builder/test/sketch_with_const/sketch.ino b/src/arduino.cc/builder/test/sketch_with_const/sketch.ino new file mode 100644 index 00000000..f4f52ca0 --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_with_const/sketch.ino @@ -0,0 +1,10 @@ +void setup() {} +void loop() {} + +const __FlashStringHelper* test() {} + +const int test3() {} + +volatile __FlashStringHelper* test2() {} + +volatile int test4() {} diff --git a/src/arduino.cc/builder/test/sketch_with_function_pointer/sketch.ino b/src/arduino.cc/builder/test/sketch_with_function_pointer/sketch.ino new file mode 100644 index 00000000..a758f4e2 --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_with_function_pointer/sketch.ino @@ -0,0 +1,4 @@ +Task t1(&t1Callback); +void t1Callback() {} +void setup() {} +void loop() {} \ No newline at end of file diff --git a/src/arduino.cc/builder/test/sketch_with_ifdef/sketch.ino b/src/arduino.cc/builder/test/sketch_with_ifdef/sketch.ino new file mode 100644 index 00000000..3d3e2f49 --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_with_ifdef/sketch.ino @@ -0,0 +1,15 @@ +#if __SAM3X8E__ +void ifBranch() { +} +#else +void elseBranch() { +} +#endif + +void f1(){ f2(); } +void f2(){;} + +void setup() { +} +void loop() { +} \ No newline at end of file diff --git a/src/arduino.cc/builder/test/sketch_with_ifdef/sketch.preprocessed.SAM.txt b/src/arduino.cc/builder/test/sketch_with_ifdef/sketch.preprocessed.SAM.txt new file mode 100644 index 00000000..c483fd33 --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_with_ifdef/sketch.preprocessed.SAM.txt @@ -0,0 +1,29 @@ +#include +#line 1 +#line 1 "{{EscapeBackSlashes .sketch.MainFile.Name}}" +#if __SAM3X8E__ +#line 2 "{{EscapeBackSlashes .sketch.MainFile.Name}}" +void ifBranch(); +#line 9 "{{EscapeBackSlashes .sketch.MainFile.Name}}" +void f1(); +#line 10 "{{EscapeBackSlashes .sketch.MainFile.Name}}" +void f2(); +#line 12 "{{EscapeBackSlashes .sketch.MainFile.Name}}" +void setup(); +#line 14 "{{EscapeBackSlashes .sketch.MainFile.Name}}" +void loop(); +#line 2 +void ifBranch() { +} +#else +void elseBranch() { +} +#endif + +void f1(){ f2(); } +void f2(){;} + +void setup() { +} +void loop() { +} diff --git a/src/arduino.cc/builder/test/sketch_with_ifdef/sketch.preprocessed.txt b/src/arduino.cc/builder/test/sketch_with_ifdef/sketch.preprocessed.txt new file mode 100644 index 00000000..9482b870 --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_with_ifdef/sketch.preprocessed.txt @@ -0,0 +1,29 @@ +#include +#line 1 +#line 1 "{{EscapeBackSlashes .sketch.MainFile.Name}}" +#if __SAM3X8E__ +void ifBranch() { +} +#else +#line 5 "{{EscapeBackSlashes .sketch.MainFile.Name}}" +void elseBranch(); +#line 9 "{{EscapeBackSlashes .sketch.MainFile.Name}}" +void f1(); +#line 10 "{{EscapeBackSlashes .sketch.MainFile.Name}}" +void f2(); +#line 12 "{{EscapeBackSlashes .sketch.MainFile.Name}}" +void setup(); +#line 14 "{{EscapeBackSlashes .sketch.MainFile.Name}}" +void loop(); +#line 5 +void elseBranch() { +} +#endif + +void f1(){ f2(); } +void f2(){;} + +void setup() { +} +void loop() { +} diff --git a/src/arduino.cc/builder/test/sketch_with_macosx_garbage/.#sketch.ino b/src/arduino.cc/builder/test/sketch_with_macosx_garbage/.#sketch.ino new file mode 100644 index 00000000..71048175 --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_with_macosx_garbage/.#sketch.ino @@ -0,0 +1,2 @@ +void setup() +void loop) } \ No newline at end of file diff --git a/src/arduino.cc/builder/test/sketch_with_macosx_garbage/sketch.ino b/src/arduino.cc/builder/test/sketch_with_macosx_garbage/sketch.ino new file mode 100644 index 00000000..4f069e3b --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_with_macosx_garbage/sketch.ino @@ -0,0 +1,2 @@ +void setup() {} +void loop() {} \ No newline at end of file diff --git a/src/arduino.cc/builder/test/sketch_with_namespace/sketch.ino b/src/arduino.cc/builder/test/sketch_with_namespace/sketch.ino new file mode 100644 index 00000000..178ba312 --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_with_namespace/sketch.ino @@ -0,0 +1,8 @@ +namespace Test { + int value() { + return 42; + } + int ciao = 24; +} +void setup() {} +void loop() {} diff --git a/src/arduino.cc/builder/test/sketch_with_subfolders/sketch_with_subfolders.ino b/src/arduino.cc/builder/test/sketch_with_subfolders/sketch_with_subfolders.ino index e69de29b..738378f1 100644 --- a/src/arduino.cc/builder/test/sketch_with_subfolders/sketch_with_subfolders.ino +++ b/src/arduino.cc/builder/test/sketch_with_subfolders/sketch_with_subfolders.ino @@ -0,0 +1,10 @@ +#include "subfolder/other.h" + +MyClass myClass; + +void setup() { + myClass.init ( &Serial ); +} + +void loop() { +} \ No newline at end of file diff --git a/src/arduino.cc/builder/test/sketch_with_subfolders/subfolder/dont_load_me.ino b/src/arduino.cc/builder/test/sketch_with_subfolders/subfolder/dont_load_me.ino new file mode 100644 index 00000000..1d32675e --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_with_subfolders/subfolder/dont_load_me.ino @@ -0,0 +1 @@ +#error "Whattya looking at?" diff --git a/src/arduino.cc/builder/test/sketch_with_subfolders/subfolder/other.cpp b/src/arduino.cc/builder/test/sketch_with_subfolders/subfolder/other.cpp index e69de29b..21a3a249 100644 --- a/src/arduino.cc/builder/test/sketch_with_subfolders/subfolder/other.cpp +++ b/src/arduino.cc/builder/test/sketch_with_subfolders/subfolder/other.cpp @@ -0,0 +1,10 @@ +#include // Arduino 1.0 + +#include "other.h" + +MyClass::MyClass() { +} + +void MyClass::init ( Stream *stream ) { + controllerStream = stream; +} diff --git a/src/arduino.cc/builder/test/sketch_with_subfolders/subfolder/other.h b/src/arduino.cc/builder/test/sketch_with_subfolders/subfolder/other.h new file mode 100644 index 00000000..9312702c --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_with_subfolders/subfolder/other.h @@ -0,0 +1,12 @@ +#ifndef other__h +#define other__h + +class MyClass { + public: + MyClass(); + void init ( Stream *controllerStream ); + + private: + Stream *controllerStream; +}; +#endif \ No newline at end of file diff --git a/src/arduino.cc/builder/test/sketch_with_usbcon/sketch.ino b/src/arduino.cc/builder/test/sketch_with_usbcon/sketch.ino index 350c9c3f..1fa15390 100644 --- a/src/arduino.cc/builder/test/sketch_with_usbcon/sketch.ino +++ b/src/arduino.cc/builder/test/sketch_with_usbcon/sketch.ino @@ -1,4 +1,6 @@ -#include +#if !defined(USBCON) +#error "Where's my USBCON?" +#endif #if defined(USBCON) void ciao() { diff --git a/src/arduino.cc/builder/test/target_board_resolver_test.go b/src/arduino.cc/builder/test/target_board_resolver_test.go index 1836346e..19268b26 100644 --- a/src/arduino.cc/builder/test/target_board_resolver_test.go +++ b/src/arduino.cc/builder/test/target_board_resolver_test.go @@ -165,3 +165,29 @@ func TestTargetBoardResolverCustomYun(t *testing.T) { require.Equal(t, "atmega32u4", targetBoard.Properties[constants.BUILD_PROPERTIES_BUILD_MCU]) require.Equal(t, "AVR_YUN", targetBoard.Properties[constants.BUILD_PROPERTIES_BUILD_BOARD]) } + +func TestTargetBoardResolverCustomCore(t *testing.T) { + context := make(map[string]interface{}) + context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware", "user_hardware"} + context[constants.CTX_FQBN] = "watterott:avr:attiny841:core=spencekonde,info=info" + + commands := []types.Command{ + &builder.SetupHumanLoggerIfMissing{}, + &builder.HardwareLoader{}, + &builder.TargetBoardResolver{}, + } + + for _, command := range commands { + err := command.Run(context) + NoError(t, err) + } + + targetPackage := context[constants.CTX_TARGET_PACKAGE].(*types.Package) + require.Equal(t, "watterott", targetPackage.PackageId) + targetPlatform := context[constants.CTX_TARGET_PLATFORM].(*types.Platform) + require.Equal(t, "avr", targetPlatform.PlatformId) + targetBoard := context[constants.CTX_TARGET_BOARD].(*types.Board) + require.Equal(t, "attiny841", targetBoard.BoardId) + require.Equal(t, "tiny841", context[constants.CTX_BUILD_CORE].(string)) + require.Equal(t, "tiny14", targetBoard.Properties[constants.BUILD_PROPERTIES_BUILD_VARIANT]) +} diff --git a/src/arduino.cc/builder/test/tools_loader_test.go b/src/arduino.cc/builder/test/tools_loader_test.go index 1b03437e..07965598 100644 --- a/src/arduino.cc/builder/test/tools_loader_test.go +++ b/src/arduino.cc/builder/test/tools_loader_test.go @@ -68,21 +68,26 @@ func TestLoadTools(t *testing.T) { sort.Sort(ByToolIDAndVersion(tools)) - require.Equal(t, "arm-none-eabi-gcc", tools[0].Name) - require.Equal(t, "4.8.3-2014q1", tools[0].Version) - require.Equal(t, Abs(t, "./downloaded_tools/arm-none-eabi-gcc/4.8.3-2014q1"), tools[0].Folder) - require.Equal(t, "avr-gcc", tools[1].Name) - require.Equal(t, "4.8.1-arduino5", tools[1].Version) - require.Equal(t, Abs(t, "./downloaded_tools/avr-gcc/4.8.1-arduino5"), tools[1].Folder) - require.Equal(t, "avrdude", tools[2].Name) - require.Equal(t, "6.0.1-arduino5", tools[2].Version) - require.Equal(t, Abs(t, "./downloaded_tools/avrdude/6.0.1-arduino5"), tools[2].Folder) - require.Equal(t, "bossac", tools[3].Name) - require.Equal(t, "1.3a-arduino", tools[3].Version) - require.Equal(t, Abs(t, "./downloaded_tools/bossac/1.3a-arduino"), tools[3].Folder) - require.Equal(t, "bossac", tools[4].Name) - require.Equal(t, "1.5-arduino", tools[4].Version) - require.Equal(t, Abs(t, "./downloaded_tools/bossac/1.5-arduino"), tools[4].Folder) + idx := 0 + require.Equal(t, "arm-none-eabi-gcc", tools[idx].Name) + require.Equal(t, "4.8.3-2014q1", tools[idx].Version) + require.Equal(t, Abs(t, "./downloaded_tools/arm-none-eabi-gcc/4.8.3-2014q1"), tools[idx].Folder) + idx++ + require.Equal(t, "avr-gcc", tools[idx].Name) + require.Equal(t, "4.8.1-arduino5", tools[idx].Version) + require.Equal(t, Abs(t, "./downloaded_tools/avr-gcc/4.8.1-arduino5"), tools[idx].Folder) + idx++ + require.Equal(t, "avrdude", tools[idx].Name) + require.Equal(t, "6.0.1-arduino5", tools[idx].Version) + require.Equal(t, Abs(t, "./downloaded_tools/avrdude/6.0.1-arduino5"), tools[idx].Folder) + idx++ + require.Equal(t, "bossac", tools[idx].Name) + require.Equal(t, "1.5-arduino", tools[idx].Version) + require.Equal(t, Abs(t, "./downloaded_tools/bossac/1.5-arduino"), tools[idx].Folder) + idx++ + require.Equal(t, "bossac", tools[idx].Name) + require.Equal(t, "1.6.1-arduino", tools[idx].Version) + require.Equal(t, Abs(t, "./downloaded_tools/bossac/1.6.1-arduino"), tools[idx].Folder) } func TestLoadToolsWithBoardManagerFolderStructure(t *testing.T) { @@ -96,17 +101,18 @@ func TestLoadToolsWithBoardManagerFolderStructure(t *testing.T) { NoError(t, err) tools := context[constants.CTX_TOOLS].([]*types.Tool) - require.Equal(t, 2, len(tools)) + require.Equal(t, 3, len(tools)) sort.Sort(ByToolIDAndVersion(tools)) - require.Equal(t, "arm-none-eabi-gcc", tools[0].Name) - require.Equal(t, "4.8.3-2014q1", tools[0].Version) - require.Equal(t, Abs(t, "./downloaded_board_manager_stuff/RFduino/tools/arm-none-eabi-gcc/4.8.3-2014q1"), tools[0].Folder) + require.Equal(t, "CMSIS", tools[0].Name) + require.Equal(t, "arm-none-eabi-gcc", tools[1].Name) + require.Equal(t, "4.8.3-2014q1", tools[1].Version) + require.Equal(t, Abs(t, "./downloaded_board_manager_stuff/RFduino/tools/arm-none-eabi-gcc/4.8.3-2014q1"), tools[1].Folder) - require.Equal(t, "openocd", tools[1].Name) - require.Equal(t, "0.9.0-arduino", tools[1].Version) - require.Equal(t, Abs(t, "./downloaded_board_manager_stuff/arduino/tools/openocd/0.9.0-arduino"), tools[1].Folder) + require.Equal(t, "openocd", tools[2].Name) + require.Equal(t, "0.9.0-arduino", tools[2].Version) + require.Equal(t, Abs(t, "./downloaded_board_manager_stuff/arduino/tools/openocd/0.9.0-arduino"), tools[2].Folder) } func TestLoadLotsOfTools(t *testing.T) { @@ -120,12 +126,13 @@ func TestLoadLotsOfTools(t *testing.T) { NoError(t, err) tools := context[constants.CTX_TOOLS].([]*types.Tool) - require.Equal(t, 8, len(tools)) + require.Equal(t, 9, len(tools)) require.Equal(t, "arm-none-eabi-gcc", tools[0].Name) require.Equal(t, "4.8.3-2014q1", tools[0].Version) - require.Equal(t, "openocd", tools[7].Name) - require.Equal(t, "0.9.0-arduino", tools[7].Version) - require.Equal(t, Abs(t, "./downloaded_board_manager_stuff/arduino/tools/openocd/0.9.0-arduino"), tools[7].Folder) + require.Equal(t, "CMSIS", tools[7].Name) + require.Equal(t, "openocd", tools[8].Name) + require.Equal(t, "0.9.0-arduino", tools[8].Version) + require.Equal(t, Abs(t, "./downloaded_board_manager_stuff/arduino/tools/openocd/0.9.0-arduino"), tools[8].Folder) } diff --git a/src/arduino.cc/builder/test/unused_compiled_libraries_remover_test.go b/src/arduino.cc/builder/test/unused_compiled_libraries_remover_test.go new file mode 100644 index 00000000..d82af8c0 --- /dev/null +++ b/src/arduino.cc/builder/test/unused_compiled_libraries_remover_test.go @@ -0,0 +1,104 @@ +/* + * This file is part of Arduino Builder. + * + * Arduino Builder is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + */ + +package test + +import ( + "arduino.cc/builder" + "arduino.cc/builder/constants" + "arduino.cc/builder/types" + "github.com/stretchr/testify/require" + "io/ioutil" + "os" + "path/filepath" + "testing" +) + +func TestUnusedCompiledLibrariesRemover(t *testing.T) { + temp, err := ioutil.TempDir("", "test") + NoError(t, err) + defer os.RemoveAll(temp) + + NoError(t, os.MkdirAll(filepath.Join(temp, "SPI"), os.FileMode(0755))) + NoError(t, os.MkdirAll(filepath.Join(temp, "Bridge"), os.FileMode(0755))) + NoError(t, ioutil.WriteFile(filepath.Join(temp, "dummy_file"), []byte{}, os.FileMode(0644))) + + context := make(map[string]interface{}) + context[constants.CTX_LIBRARIES_BUILD_PATH] = temp + context[constants.CTX_IMPORTED_LIBRARIES] = []*types.Library{&types.Library{Name: "Bridge"}} + + cmd := builder.UnusedCompiledLibrariesRemover{} + err = cmd.Run(context) + NoError(t, err) + + _, err = os.Stat(filepath.Join(temp, "SPI")) + require.Error(t, err) + require.True(t, os.IsNotExist(err)) + _, err = os.Stat(filepath.Join(temp, "Bridge")) + NoError(t, err) + _, err = os.Stat(filepath.Join(temp, "dummy_file")) + NoError(t, err) +} + +func TestUnusedCompiledLibrariesRemoverLibDoesNotExist(t *testing.T) { + context := make(map[string]interface{}) + context[constants.CTX_LIBRARIES_BUILD_PATH] = filepath.Join(os.TempDir(), "test") + context[constants.CTX_IMPORTED_LIBRARIES] = []*types.Library{&types.Library{Name: "Bridge"}} + + cmd := builder.UnusedCompiledLibrariesRemover{} + err := cmd.Run(context) + NoError(t, err) +} + +func TestUnusedCompiledLibrariesRemoverNoUsedLibraries(t *testing.T) { + temp, err := ioutil.TempDir("", "test") + NoError(t, err) + defer os.RemoveAll(temp) + + NoError(t, os.MkdirAll(filepath.Join(temp, "SPI"), os.FileMode(0755))) + NoError(t, os.MkdirAll(filepath.Join(temp, "Bridge"), os.FileMode(0755))) + NoError(t, ioutil.WriteFile(filepath.Join(temp, "dummy_file"), []byte{}, os.FileMode(0644))) + + context := make(map[string]interface{}) + context[constants.CTX_LIBRARIES_BUILD_PATH] = temp + context[constants.CTX_IMPORTED_LIBRARIES] = []*types.Library{} + + cmd := builder.UnusedCompiledLibrariesRemover{} + err = cmd.Run(context) + NoError(t, err) + + _, err = os.Stat(filepath.Join(temp, "SPI")) + require.Error(t, err) + require.True(t, os.IsNotExist(err)) + _, err = os.Stat(filepath.Join(temp, "Bridge")) + require.Error(t, err) + require.True(t, os.IsNotExist(err)) + _, err = os.Stat(filepath.Join(temp, "dummy_file")) + NoError(t, err) +} diff --git a/src/arduino.cc/builder/test/user_hardware/my_avr_platform/avr/boards.txt b/src/arduino.cc/builder/test/user_hardware/my_avr_platform/avr/boards.txt index 92a60d27..6b98abf5 100644 --- a/src/arduino.cc/builder/test/user_hardware/my_avr_platform/avr/boards.txt +++ b/src/arduino.cc/builder/test/user_hardware/my_avr_platform/avr/boards.txt @@ -30,7 +30,7 @@ custom_yun.build.vid=0x2341 custom_yun.build.pid=0x8041 custom_yun.build.usb_product="Arduino My" custom_yun.build.board=AVR_YUN -custom_yun.build.variant=yun +custom_yun.build.variant=arduino:yun custom_yun.build.extra_flags={build.usb_flags} mymega.name=Arduino Mega or Mega 2560 @@ -62,9 +62,10 @@ mymega.menu.cpu.atmega2560.upload.protocol=wiring mymega.menu.cpu.atmega2560.upload.maximum_size=253952 mymega.menu.cpu.atmega2560.upload.speed=115200 +mymega.menu.cpu.atmega2560.bootloader._folder=stk500v2 mymega.menu.cpu.atmega2560.bootloader.high_fuses=0xD8 mymega.menu.cpu.atmega2560.bootloader.extended_fuses=0xFD -mymega.menu.cpu.atmega2560.bootloader.file=stk500v2/stk500boot_v2_mega2560.hex +mymega.menu.cpu.atmega2560.bootloader.file={bootloader._folder}/stk500boot_v2_mega2560.hex mymega.menu.cpu.atmega2560.build.mcu=atmega2560 mymega.menu.cpu.atmega2560.build.board=AVR_MEGA2560 @@ -75,9 +76,10 @@ mymega.menu.cpu.atmega1280.upload.protocol=arduino mymega.menu.cpu.atmega1280.upload.maximum_size=126976 mymega.menu.cpu.atmega1280.upload.speed=57600 +mymega.menu.cpu.atmega1280.bootloader._folder=atmega mymega.menu.cpu.atmega1280.bootloader.high_fuses=0xDA mymega.menu.cpu.atmega1280.bootloader.extended_fuses=0xF5 -mymega.menu.cpu.atmega1280.bootloader.file=atmega/ATmegaBOOT_168_atmega1280.hex +mymega.menu.cpu.atmega1280.bootloader.file={bootloader._folder}/ATmegaBOOT_168_atmega1280.hex mymega.menu.cpu.atmega1280.build.mcu=atmega1280 mymega.menu.cpu.atmega1280.build.board=AVR_MEGA diff --git a/src/arduino.cc/builder/test/user_hardware/my_avr_platform/avr/bootloaders/stk500v2/stk500boot_v2_mega2560.hex b/src/arduino.cc/builder/test/user_hardware/my_avr_platform/avr/bootloaders/stk500v2/stk500boot_v2_mega2560.hex new file mode 100644 index 00000000..c52e690a --- /dev/null +++ b/src/arduino.cc/builder/test/user_hardware/my_avr_platform/avr/bootloaders/stk500v2/stk500boot_v2_mega2560.hex @@ -0,0 +1,469 @@ +:020000023000CC +:10E000000D9489F10D94B2F10D94B2F10D94B2F129 +:10E010000D94B2F10D94B2F10D94B2F10D94B2F1F0 +:10E020000D94B2F10D94B2F10D94B2F10D94B2F1E0 +:10E030000D94B2F10D94B2F10D94B2F10D94B2F1D0 +:10E040000D94B2F10D94B2F10D94B2F10D94B2F1C0 +:10E050000D94B2F10D94B2F10D94B2F10D94B2F1B0 +:10E060000D94B2F10D94B2F10D94B2F10D94B2F1A0 +:10E070000D94B2F10D94B2F10D94B2F10D94B2F190 +:10E080000D94B2F10D94B2F10D94B2F10D94B2F180 +:10E090000D94B2F10D94B2F10D94B2F10D94B2F170 +:10E0A0000D94B2F10D94B2F10D94B2F10D94B2F160 +:10E0B0000D94B2F10D94B2F10D94B2F10D94B2F150 +:10E0C0000D94B2F10D94B2F10D94B2F10D94B2F140 +:10E0D0000D94B2F10D94B2F10D94B2F10D94B2F130 +:10E0E0000D94B2F141546D656761323536300041AF +:10E0F000726475696E6F206578706C6F72657220DE +:10E1000073746B3530305632206279204D4C530099 +:10E11000426F6F746C6F616465723E004875683F52 +:10E1200000436F6D70696C6564206F6E203D200048 +:10E130004350552054797065202020203D20005FF9 +:10E140005F4156525F415243485F5F3D2000415658 +:10E1500052204C696243205665723D20004743437C +:10E160002056657273696F6E203D20004350552024 +:10E1700049442020202020203D20004C6F7720663D +:10E18000757365202020203D20004869676820665F +:10E190007573652020203D200045787420667573D6 +:10E1A00065202020203D20004C6F636B2066757336 +:10E1B000652020203D20004D617220203720323024 +:10E1C000313300312E362E3800342E332E350056A2 +:10E1D00023202020414444522020206F7020636F70 +:10E1E00064652020202020696E73747275637469E1 +:10E1F0006F6E2061646472202020496E74657272B3 +:10E20000757074006E6F20766563746F7200726A49 +:10E210006D702020006A6D70200057686174207056 +:10E220006F72743A00506F7274206E6F7420737541 +:10E2300070706F72746564004D7573742062652030 +:10E2400061206C6574746572002000577269747483 +:10E25000696E672045450052656164696E672045B7 +:10E26000450045452065727220636E743D00504F35 +:10E27000525400303D5A65726F2061646472003FF1 +:10E280003D43505520737461747300403D454550C3 +:10E29000524F4D207465737400423D426C696E6B41 +:10E2A000204C454400453D44756D70204545505215 +:10E2B0004F4D00463D44756D7020464C415348001B +:10E2C000483D48656C70004C3D4C69737420492F83 +:10E2D0004F20506F72747300513D51756974005234 +:10E2E0003D44756D702052414D00563D73686F7707 +:10E2F00020696E7465727275707420566563746FF0 +:10E30000727300593D506F727420626C696E6B00BD +:10E310002A0011241FBECFEFD1E2DEBFCDBF01E046 +:10E320000CBF12E0A0E0B2E0EEE1FDEF03E00BBFB6 +:10E3300002C007900D92A030B107D9F712E0A0E01B +:10E34000B2E001C01D92AE30B107E1F70F9460F367 +:10E350000D948DFE01E20EBF0FEF0DBF11241FBE05 +:10E360000D9460F30D9400F020E030E040ED57E0B4 +:10E3700005C0FA013197F1F72F5F3F4F2817390792 +:10E38000C0F308959C01260F311DC901A0E0B0E043 +:10E390002F5F3F4FABBFFC018791882361F08093D3 +:10E3A000C6008091C00086FFFCCF8091C0008064D1 +:10E3B0008093C000EACF08958DE08093C6008091DD +:10E3C000C00086FFFCCF8091C00080648093C000B5 +:10E3D0008AE08093C6008091C00086FFFCCF8091C8 +:10E3E000C00080648093C00008950F94C2F10F9420 +:10E3F000DCF10895FC019081992359F09093C600B7 +:10E400008091C00086FFFCCF8091C0008064809323 +:10E41000C0003196992379F70895282F982F929567 +:10E420009F70892F805D8A3308F0895F8093C600D2 +:10E430008091C00086FFFCCF8091C00080648093F3 +:10E44000C000822F8F70982F905D9A3308F0995FEB +:10E450009093C6008091C00086FFFCCF8091C000E1 +:10E4600080648093C00008959C01FB01853691056E +:10E470001CF46330710594F0C90164E670E00F94F8 +:10E480002EFE605D7F4F6093C6008091C00086FFC6 +:10E49000FCCF8091C00080648093C0002B30310598 +:10E4A00014F43297B4F0C90164E670E00F942EFEC4 +:10E4B0006AE070E00F942EFE605D7F4F6093C600AF +:10E4C0008091C00086FFFCCF8091C0008064809363 +:10E4D000C000C9016AE070E00F942EFEC0968093E0 +:10E4E000C6008091C00086FFFCCF8091C000806490 +:10E4F0008093C00008951F93182F8EE692EE60E07F +:10E500000F94C2F11093C6008091C00086FFFCCF2B +:10E510008091C00080648093C0000F94DCF11F9153 +:10E5200008952F923F924F925F926F927F928F92B7 +:10E530009F92AF92BF92CF92DF92EF92FF920F9392 +:10E540001F93DF93CF93CDB7DEB762970FB6F894E2 +:10E55000DEBF0FBECDBF382E622ECA01DB015C01CB +:10E560006D01772420E2222E2E010894411C511CBB +:10E570008BC081E0A81680E0B80681E0C80680E084 +:10E58000D80628F0C601AA27BB270F940DF2BB2797 +:10E59000AD2D9C2D8B2D0F940DF28A2D0F940DF225 +:10E5A0002092C6008091C00086FFFCCF8091C00001 +:10E5B00080648093C0009DE29093C6008091C0006B +:10E5C00086FFFCCF8091C00080648093C0002092C1 +:10E5D000C6008091C00086FFFCCF8091C00080649F +:10E5E0008093C00019828601750188249924A1E0D6 +:10E5F0003A1651F03A1620F0B2E03B1661F409C029 +:10E600000BBFF701779007C0C7010F9477FE782EF4 +:10E6100002C0F7017080872D0F940DF22092C60082 +:10E620008091C00086FFFCCF8091C0008064809301 +:10E63000C000872D8052F401EF70F0708F3520F408 +:10E64000E40DF51D708204C0E40DF51D8EE280839B +:10E650000894E11CF11C011D111D0894811C911CE2 +:10E6600090E18916910409F0C2CF80E190E0A0E02A +:10E67000B0E0A80EB91ECA1EDB1E198AC2010F9493 +:10E68000FAF10F94DCF16A94662009F072CF629679 +:10E690000FB6F894DEBF0FBECDBFCF91DF911F91B3 +:10E6A0000F91FF90EF90DF90CF90BF90AF909F9031 +:10E6B0008F907F906F905F904F903F902F90089534 +:10E6C0002F923F924F925F926F927F928F929F9282 +:10E6D000AF92BF92CF92DF92EF92FF920F931F9370 +:10E6E000DF93CF93CDB7DEB7CD53D1400FB6F894BB +:10E6F000DEBF0FBECDBF01E20EBF0FEF0DBF94B75F +:10E70000F894A89514BE80916000886180936000A1 +:10E7100010926000789493FF05C0E0910002F091A0 +:10E7200001021995279A2F9A8091C00082608093E8 +:10E73000C00080E18093C40088E18093C1000000A4 +:10E74000EE24FF24870144E0A42EB12CCC24DD2448 +:10E7500024C0C5010197F1F70894E11CF11C011DCB +:10E76000111D21E2E2162EE4F20620E0020720E06D +:10E77000120718F031E0C32ED12CC801B70127ECE5 +:10E780003BE140E050E00F9441FE611571058105C9 +:10E79000910519F485B1805885B98091C00087FD35 +:10E7A00003C0C114D104A9F2A6014F5F5F4FC25E3E +:10E7B000DE4F59834883CE51D140C25EDE4F8881FF +:10E7C0009981CE51D140019711F00D9410FEC05D9A +:10E7D000DE4F19821882C053D14060E0C15DDE4F28 +:10E7E0001882CF52D14088249924C35DDE4F19820C +:10E7F0001882CD52D140C05EDE4F188219821A8233 +:10E800001B82C052D140CE5CDE4F188219821A8220 +:10E810001B82C253D140EE24FF2487010BBFF701B6 +:10E8200007911691C45CDE4F19830883CC53D14005 +:10E830000D940BFEC25EDE4F28813981CE51D1404E +:10E840002130310509F52091C600C25EDE4F1982E4 +:10E850001882CE51D14022C02F5F3F4F4F4F5F4FA4 +:10E86000213082E138078AE7480780E0580780F0C6 +:10E87000C45CDE4FE881F981CC53D140EF5FFF4F9C +:10E8800019F0EE27FF27099420E030E040E050E047 +:10E890008091C00087FFE0CF2091C600C35DDE4FAE +:10E8A00048815981CD52D1404F5F5F4FC35DDE4FEC +:10E8B00059834883CD52D140213209F063C64A3092 +:10E8C000510508F05FC60894811C911C53E0851621 +:10E8D000910409F059C600E010E018C081E280936D +:10E8E000C6008091C00086FFFCCF8091C00080648C +:10E8F0008093C0002F5F3F4F2931310579F70F9486 +:10E90000DCF10F5F1F4F0530110519F020E030E0FA +:10E91000E5CF10920A0210920B0210920C02109294 +:10E920000D02109206021092070210920802109235 +:10E930000902109202021092030210920402109235 +:10E9400005028FEE90EE60E00F94F5F180E191EE1C +:10E9500060E00F94C2F18091C00087FFFCCF9091DE +:10E96000C600903608F09F759032B8F09093C600BC +:10E970008091C00086FFFCCF8091C00080648093AE +:10E98000C000A0E2A093C6008091C00086FFFCCF2B +:10E990008091C00080648093C000983409F4D7C18E +:10E9A0009934B8F4923409F459C1933458F490333B +:10E9B00019F1903308F4E3C59F33A1F1903409F0C5 +:10E9C000DEC5BDC0953409F470C1963409F0D7C5D1 +:10E9D00098C1923509F42BC2933538F49C3409F46C +:10E9E000F5C1913509F0CBC518C2963509F445C279 +:10E9F000993509F0C4C567C483E792EE62E00F94CD +:10EA0000F5F110920602109207021092080210927D +:10EA1000090210920A0210920B0210920C0210923C +:10EA20000D0213C18FE792EE62E00F94F5F18FEEC5 +:10EA300090EE60E00F94F5F181E291EE60E00F94CA +:10EA4000C2F187EB91EE60E00F94F5F180E391EE77 +:10EA500060E00F94C2F184EE90EE60E00F94F5F167 +:10EA60008FE391EE60E00F94C2F186E090E061E008 +:10EA700070E00F9434F20F94DCF18DE591EE60E0DC +:10EA80000F94C2F189EC91EE60E00F94F5F18EE401 +:10EA900091EE60E00F94C2F183EC91EE60E00F9490 +:10EAA000F5F18CE691EE60E00F94C2F18EE10F94E7 +:10EAB0000DF288E90F940DF281E00F940DF20F949E +:10EAC000DCF18BE791EE60E00F94C2F119E0E0E039 +:10EAD000F0E010935700E4918E2F0F940DF20F94F5 +:10EAE000DCF18AE891EE60E00F94C2F1E3E0F0E03F +:10EAF00010935700E4918E2F0F940DF20F94DCF1D8 +:10EB000089E991EE60E00F94C2F1E2E0F0E0109349 +:10EB10005700E4918E2F0F940DF20F94DCF188EAE8 +:10EB200091EE60E00F94C2F1E1E0F0E01093570045 +:10EB30001491812F0F940DF20F94DCF107CF8BE825 +:10EB400092EE62E00F94F5F18BE492EE60E00F94A8 +:10EB5000F5F10F94DCF100E010E019C0C8016F2D51 +:10EB60000F947FFEFF2031F489E492EE60E00F9471 +:10EB7000C2F10BC0F092C6008091C00086FFFCCFAE +:10EB80008091C00080648093C0000F5F1F4FC80158 +:10EB900081519F41A0E0B0E0ABBFFC01F790BAE229 +:10EBA000FB1621F0E2E000301E07C1F60F94DCF105 +:10EBB0000F94DCF187E592EE60E00F94F5F10F948D +:10EBC000DCF1CC24DD2400E010E01EC0C8010F946D +:10EBD00077FEF82E882331F489E492EE60E00F94FA +:10EBE000C2F10BC08093C6008091C00086FFFCCFAD +:10EBF0008091C00080648093C000FE1419F00894D6 +:10EC0000C11CD11C0F5F1F4FC80181519F41A0E063 +:10EC1000B0E0ABBFFC01E790FAE2EF1621F022E092 +:10EC20000030120799F60F94DCF10F94DCF182E6C4 +:10EC300092EE60E00F94C2F1C60161E070E00F94C3 +:10EC400034F20F94DCF10F94DCF110920202109276 +:10EC50000302109204021092050278CE89E992EE26 +:10EC600062E00F94F5F1279A2F9A16C02F9880E052 +:10EC700090E0E0EDF7E03197F1F7019684369105E9 +:10EC8000C1F72F9A80E090E0E0EDF7E03197F1F7DF +:10EC9000019684369105C1F78091C00087FFE6CFC9 +:10ECA0008091C00087FFFCCF64C485EA92EE62E0E9 +:10ECB0000F94F5F140910202509103026091040219 +:10ECC0007091050281E020E10F9491F2809102029F +:10ECD00090910302A0910402B091050280509F4FD1 +:10ECE000AF4FBF4F8093020290930302A0930402A0 +:10ECF000B093050280509041A040B04008F426CE69 +:10ED0000A4CF83EB92EE62E00F94F5F140910602FE +:10ED100050910702609108027091090280E020E1A1 +:10ED20000F9491F28091060290910702A09108023F +:10ED3000B091090280509F4FAF4FBF4F80930602A2 +:10ED400090930702A0930802B0930902FFCD80ECD4 +:10ED500092EE62E00F94F5F183E792EE60E00F949B +:10ED6000F5F18FE792EE60E00F94F5F18BE892EE0B +:10ED700060E00F94F5F189E992EE60E00F94F5F10F +:10ED800085EA92EE60E00F94F5F183EB92EE60E09D +:10ED90000F94F5F180EC92EE60E00F94F5F187ECC2 +:10EDA00092EE60E00F94F5F188ED92EE60E00F9442 +:10EDB000F5F18FED92EE60E00F94F5F18AEE92EEB0 +:10EDC00060E00F94F5F183E093EEBDCD87EC92EE19 +:10EDD00062E00F94F5F181E40F947BF282E40F94EA +:10EDE0007BF283E40F947BF284E40F947BF285E45E +:10EDF0000F947BF286E40F947BF287E40F947BF20E +:10EE000088E40F947BF28AE40F947BF28BE40F94F6 +:10EE10007BF28CE40F947BF299CD88ED92EE62E068 +:10EE20000F94F5F1772473948824992409C48FED05 +:10EE300092EE62E00F94F5F140910A0250910B02BC +:10EE400060910C0270910D0282E020E10F9491F22A +:10EE500080910A0290910B02A0910C02B0910D02D8 +:10EE600080509F4FAF4FBF4F80930A0290930B0289 +:10EE7000A0930C02B0930D0269CD8AEE92EE62E08F +:10EE80000F94F5F184EE90EE60E00F94F5F18FECC5 +:10EE900091EE60E00F94F5F1662477244301CC5D98 +:10EEA000DE4F19821882C452D140D401C301B695F5 +:10EEB000A79597958795CA5DDE4F88839983AA8326 +:10EEC000BB83C652D140CC5DDE4FA881B981C4520C +:10EED000D1401196CC5DDE4FB983A883C452D14096 +:10EEE000CD0162E070E00F9434F2B0E2B093C6005E +:10EEF0008091C00086FFFCCF8091C0008064809329 +:10EF0000C000EDE2E093C6008091C00086FFFCCF18 +:10EF10008091C00080648093C000F0E2F093C6004E +:10EF20008091C00086FFFCCF8091C00080648093F8 +:10EF3000C000CA5DDE4FE880F9800A811B81C6529D +:10EF4000D140BB27A12F902F8F2D0F940DF2CA5DBA +:10EF5000DE4F8881C652D1400F940DF2B0E2FB2EF5 +:10EF6000F092C6008091C00086FFFCCF8091C00067 +:10EF700080648093C0000DE30093C6008091C000C0 +:10EF800086FFFCCF8091C00080648093C00010E2B7 +:10EF90001093C6008091C00086FFFCCF8091C00016 +:10EFA00080648093C0008BBEF3012791C65DDE4F65 +:10EFB0002883CA52D140A22EBB24CC24DD2408943D +:10EFC000611C711C811C911C8BBEF3018791282E42 +:10EFD0003324442455240894611C711C811C911C09 +:10EFE0008BBEF3013791C55DDE4F3883CB52D140E4 +:10EFF0000894611C711C811C911C8BBEF30147910C +:10F00000C45DDE4F4883CC52D140ADEFEA2EAFEF66 +:10F01000FA2EAFEF0A2FAFEF1A2F6E0C7F1C801E57 +:10F02000911E142D032DF22CEE24EA0CFB1C0C1D5A +:10F030001D1D0F940DF220E22093C6008091C000A8 +:10F0400086FFFCCF8091C00080648093C000C65DC5 +:10F05000DE4F8881CA52D1400F940DF230E23093D6 +:10F06000C6008091C00086FFFCCF8091C000806404 +:10F070008093C000C45DDE4F8881CC52D1400F9494 +:10F080000DF240E24093C6008091C00086FFFCCFA5 +:10F090008091C00080648093C000C55DDE4F888190 +:10F0A000CB52D1400F940DF250E25093C6008091A4 +:10F0B000C00086FFFCCF8091C00080648093C000B8 +:10F0C0008FEFE8168FEFF80680E0080780E018075A +:10F0D00031F484E092EE60E00F94C2F1DFC0D80119 +:10F0E000C7018070907CA070B0708050904CA040A0 +:10F0F000B040D1F52FEF3FE340E050E0E222F322B1 +:10F1000004231523CA5DDE4FA880B980CA80DB8046 +:10F11000C652D140AE0CBF1CC01ED11EAA0CBB1CD7 +:10F12000CC1CDD1C8EE092EE60E00F94C2F1BB2798 +:10F13000A12F902F8F2D0F940DF28E2D0F940DF285 +:10F1400030E23093C6008091C00086FFFCCF8091F2 +:10F15000C00080648093C0004EE34093C60080915D +:10F16000C00086FFFCCF87C08EE09EEFA0E0B0E03D +:10F17000E822F9220A231B239CE0E91694E9F90608 +:10F1800090E0090790E0190709F088C0C45DDE4FE0 +:10F19000A881CC52D140EA2EFF2400E010E0102FCD +:10F1A0000F2DFE2CEE24C55DDE4FB881CB52D14031 +:10F1B000EB0EF11C011D111DD601C501817090706F +:10F1C000A070B070DC0199278827E80EF91E0A1F8D +:10F1D0001B1F20EF30E040E050E0A222B322C42207 +:10F1E000D52241E1AA0CBB1CCC1CDD1C4A95D1F7F1 +:10F1F000EA0CFB1C0C1D1D1D81E090E0A0E0B0E0BE +:10F20000282239224A225B2235E1220C331C441C7D +:10F21000551C3A95D1F7E20CF31C041D151D57013E +:10F220006801AA0CBB1CCC1CDD1C85E192EE60E0E1 +:10F230000F94C2F1C801AA27BB270F940DF2BB2778 +:10F24000A12F902F8F2D0F940DF28E2D0F940DF274 +:10F2500090E29093C6008091C00086FFFCCF809121 +:10F26000C00080648093C000AEE3A093C60080918C +:10F27000C00086FFFCCF8091C00080648093C000F6 +:10F28000C601AA27BB270F940DF2BB27AD2D9C2DDD +:10F290008B2D0F940DF28A2D0F940DF20F94DCF14B +:10F2A000CC5DDE4FE881F981C452D140F99709F471 +:10F2B0004DCBF4E0EF2EF12C012D112D6E0C7F1CA7 +:10F2C000801E911EF2CD83E093EE62E00F94F5F183 +:10F2D0008AE192EE60E00F94C2F18091C00087FF56 +:10F2E000FCCF1091C6001F751093C6008091C0001E +:10F2F00086FFFCCF8091C00080648093C0000F9493 +:10F30000DCF1812F81548A3108F036C1163409F4BA +:10F3100095C0173490F4133409F44EC0143430F40B +:10F320001134F1F0123409F01DC130C0143409F465 +:10F3300059C0153409F016C16BC01A3409F4C4C0A1 +:10F340001B3438F4173409F48FC0183409F00AC19B +:10F35000A1C01B3409F4D2C01C3409F003C1E8C0B9 +:10F360008FEF81B90DC082B1809582B980E090E0C5 +:10F37000E0EDF7E03197F1F70196883C9105C1F790 +:10F380008091C00087FFEFCF12B8EFC08FEF84B934 +:10F390000DC085B1809585B980E090E0E0EDF7E0A3 +:10F3A0003197F1F70196883C9105C1F78091C00033 +:10F3B00087FFEFCF15B8D9C08FEF87B90DC088B1DF +:10F3C000809588B980E090E0E0EDF7E03197F1F7C3 +:10F3D0000196883C9105C1F78091C00087FFEFCF6F +:10F3E00018B8C3C08FEF8AB90DC08BB180958BB9A7 +:10F3F00080E090E0E0EDF7E03197F1F70196883C8E +:10F400009105C1F78091C00087FFEFCF1BB8ADC059 +:10F410008FEF8DB90DC08EB180958EB980E090E0F0 +:10F42000E0EDF7E03197F1F70196883C9105C1F7DF +:10F430008091C00087FFEFCF1EB897C08FEF80BBD1 +:10F440000DC081B3809581BB80E090E0E0EDF7E0F6 +:10F450003197F1F70196883C9105C1F78091C00082 +:10F4600087FFEFCF11BA81C08FEF83BB0DC084B38C +:10F47000809584BB80E090E0E0EDF7E03197F1F714 +:10F480000196883C9105C1F78091C00087FFEFCFBE +:10F4900014BA6BC08FEF809301010FC080910201FD +:10F4A00080958093020180E090E0E0EDF7E03197F5 +:10F4B000F1F70196883C9105C1F78091C00087FF64 +:10F4C000EDCF1092020151C08FEF809304010FC065 +:10F4D0008091050180958093050180E090E0E0ED4A +:10F4E000F7E03197F1F70196883C9105C1F78091DB +:10F4F000C00087FFEDCF1092050137C08FEF8093DA +:10F5000007010FC08091080180958093080180E079 +:10F5100090E0E0EDF7E03197F1F70196883C910536 +:10F52000C1F78091C00087FFEDCF109208011DC088 +:10F530008FEF80930A010FC080910B01809580931B +:10F540000B0180E090E0E0EDF7E03197F1F70196F4 +:10F55000883C9105C1F78091C00087FFEDCF1092E4 +:10F560000B0103C085E292EEEEC98091C00087FFD7 +:10F57000FCCF8091C600EAC988E392EEE4C98CE131 +:10F5800091EEE1C988249924933011F1943028F444 +:10F59000913089F09230B8F408C0953061F195301F +:10F5A000F0F0963009F048C043C02B3109F042C951 +:10F5B00091E06BE13FC96227C15DDE4F2883CF52E6 +:10F5C000D14092E037C9B22FA0E0622793E032C960 +:10F5D000822F90E0A82BB92B622794E02BC92E3004 +:10F5E00009F039C3622795E0C05DDE4F19821882A9 +:10F5F000C053D1401FC9E1E0F0E0EC0FFD1FC05D3A +:10F60000DE4F08811981C053D140E00FF11F2083E4 +:10F610000F5F1F4FC05DDE4F19830883C053D14079 +:10F6200062270A171B0709F005C9D80196E002C92D +:10F63000261709F010C303C0973009F0FBC87724E0 +:10F640009981933109F412C19431C8F4963009F4C8 +:10F65000D8C0973050F4923009F406C1933009F4C1 +:10F660006DC0913009F059C253C0913109F477C08F +:10F67000923108F0BBC0903109F04FC2F5C098310B +:10F6800009F487C0993150F4953109F4EFC09531F0 +:10F6900008F4C6C1963109F040C2C2C19A3109F4DA +:10F6A0006CC09A3108F491C09B3109F45BC09D3164 +:10F6B00009F033C29D81903359F48F81882311F46E +:10F6C0009EE11CC0813011F091E018C098E916C08D +:10F6D000892F807591F0903539F4E0E0F0E089E011 +:10F6E0008093570094910AC0983539F4E3E0F0E034 +:10F6F00089E080935700949101C090E01A821B82A8 +:10F700008D818C831D829E831F8227E030E009C299 +:10F710001A8288E08B8381E48C8386E58D8382E581 +:10F720008E8389E48F8383E5888780E589878FE5E9 +:10F730008A8782E38B872BE030E0F3C18A818139AD +:10F7400041F0823941F0803911F48FE005C080E04A +:10F7500003C082E001C08AE01A828B8344C0772410 +:10F76000739482C08D81882311F48EE12CC0813086 +:10F7700011F081E028C088E926C01A82E1E0F0E0BB +:10F7800089E08093570084918B831C8224E030E0D1 +:10F79000C8C18B81803589F48C81883039F4E2E0EE +:10F7A000F0E089E08093570084910DC0E0E0F0E044 +:10F7B00089E080935700849106C0E3E0F0E089E09F +:10F7C0008093570084911A82DFCF8D81836C99E0FA +:10F7D000E1E0F0E0082E90935700E89507B600FCB2 +:10F7E000FDCF1A821B8223E030E09BC180EC8A832C +:10F7F000CE5CDE4F188219821A821B82C253D1401E +:10F800008EC18A8190E0A0E0B0E0582F44273327D2 +:10F8100022278B8190E0A0E0B0E0DC0199278827C7 +:10F82000282B392B4A2B5B2B8D8190E0A0E0B0E098 +:10F83000282B392B4A2B5B2B8C8190E0A0E0B0E089 +:10F84000BA2FA92F982F8827282B392B4A2B5B2BCF +:10F85000220F331F441F551FC05EDE4F288339839C +:10F860004A835B83C052D1401A8259C13A81C95C34 +:10F87000DE4F3883C753D140CA5CDE4F1882C6536F +:10F88000D1408B81C82EDD24CA5CDE4F488159816E +:10F89000C653D140C42AD52A933109F082C0CE5C28 +:10F8A000DE4F88819981AA81BB81C253D1408050AB +:10F8B000904CA340B04030F583E0CE5CDE4FE88052 +:10F8C000F9800A811B81C253D140F70100935B008C +:10F8D00080935700E89507B600FCFDCFCE5CDE4F65 +:10F8E000088119812A813B81C253D14000501F4FAA +:10F8F0002F4F3F4FCE5CDE4F088319832A833B8313 +:10F90000C253D140C05EDE4F488159816A817B81FC +:10F91000C052D140DE011B9631E08C9111962C91A2 +:10F9200011971296C75CDE4F2883C953D140C85C3B +:10F93000DE4F1882C853D14090E0C85CDE4FE881AA +:10F94000F981C853D1408E2B9F2B0C01FA01609393 +:10F950005B0030935700E89511244E5F5F4F6F4F67 +:10F960007F4F0EEFE02E0FEFF02ECE0CDF1CC114F8 +:10F97000D10499F685E0C05EDE4F088119812A81A5 +:10F980003B81C052D140F80120935B008093570027 +:10F99000E89507B600FCFDCF81E180935700E8951C +:10F9A00035C0C05EDE4F88819981AA81BB81C0527B +:10F9B000D140B695A795979587957C018601ABE0D8 +:10F9C000AA2EB12CAC0EBD1E0BC0D5016D915D01F0 +:10F9D000C7010F947FFE0894E11CF11C01501040F8 +:10F9E0000115110591F7A60160E070E0440F551F65 +:10F9F000661F771FC05EDE4FE880F9800A811B8199 +:10FA0000C052D1404E0D5F1D601F711F1A82C05E33 +:10FA1000DE4F488359836A837B83C052D1407FC0C5 +:10FA2000FA80C55CDE4FF882CB53D140C65CDE4F16 +:10FA30001882CA53D1408B81C82EDD24C65CDE4FAC +:10FA400008811981CA53D140C02AD12A1A828981DA +:10FA5000BE016D5F7F4F843121F59601C05EDE4FA0 +:10FA6000E880F9800A811B81C052D1400BBFF701A9 +:10FA700087919691DB018C9311969C936E5F7F4FDB +:10FA8000D801C7010296A11DB11DC05EDE4F88835B +:10FA90009983AA83BB83C052D14022503040F1F6F3 +:10FAA00036C0C05EDE4F288139814A815B81C052F9 +:10FAB000D1400894C108D108760100E010E0089414 +:10FAC000C11CD11C0894E11CF11C011D111DE20E8A +:10FAD000F31E041F151F21BDBB27A52F942F832FB5 +:10FAE00082BD2F5F3F4F4F4F5F4FF89A80B5DB01CC +:10FAF0008D93BD012E153F054007510761F7C05E8C +:10FB0000DE4F288339834A835B83C052D1409601FC +:10FB10002D5F3F4FFB01108204C080EC8A8322E0FE +:10FB200030E08BE18093C6008091C00086FFFCCF5F +:10FB30008091C00080648093C000C15DDE4FF88179 +:10FB4000CF52D140F093C6008091C00086FFFCCF19 +:10FB50008091C00080648093C000432F3093C60022 +:10FB60008091C00086FFFCCF8091C00080648093AC +:10FB7000C000922F2093C6008091C00086FFFCCF6A +:10FB80008091C00080648093C0008EE08093C600A6 +:10FB90008091C00086FFFCCF8091C000806480937C +:10FBA000C00065E1C15DDE4FE880CF52D1406E25D7 +:10FBB00069276427FE01319610C090819093C6009A +:10FBC0008091C00086FFFCCF31968091C000806498 +:10FBD0008093C0006927215030402115310569F715 +:10FBE0006093C6008091C00086FFFCCF8091C0006A +:10FBF00080648093C00085B1805885B9772081F4F6 +:10FC0000C15DDE4F0881CF52D1400F5FC15DDE4F35 +:10FC10000883CF52D14090E0A0E0B0E00D941AF4F8 +:10FC200027982F9880E090E020ED37E0F901319798 +:10FC3000F1F7019684369105C9F700008091C00064 +:10FC40008D7F8093C00081E180935700E895EE2777 +:10FC5000FF270994FFCF90E00D941AF497FB092E2B +:10FC600007260AD077FD04D02ED006D000201AF443 +:10FC7000709561957F4F0895F6F7909581959F4F08 +:10FC80000895A1E21A2EAA1BBB1BFD010DC0AA1FDD +:10FC9000BB1FEE1FFF1FA217B307E407F50720F0F5 +:10FCA000A21BB30BE40BF50B661F771F881F991F70 +:10FCB0001A9469F760957095809590959B01AC01B9 +:10FCC000BD01CF010895AA1BBB1B51E107C0AA1FAC +:10FCD000BB1FA617B70710F0A61BB70B881F991FED +:10FCE0005A95A9F780959095BC01CD010895F99991 +:10FCF000FECF92BD81BDF89A992780B50895262F31 +:10FD0000F999FECF1FBA92BD81BD20BD0FB6F89400 +:0EFD1000FA9AF99A0FBE01960895F894FFCF63 +:040000033000E000E9 +:00000001FF diff --git a/src/arduino.cc/builder/test/wipeout_build_path_if_build_options_changed_test.go b/src/arduino.cc/builder/test/wipeout_build_path_if_build_options_changed_test.go index 7ef728ec..d72b05b2 100644 --- a/src/arduino.cc/builder/test/wipeout_build_path_if_build_options_changed_test.go +++ b/src/arduino.cc/builder/test/wipeout_build_path_if_build_options_changed_test.go @@ -34,8 +34,8 @@ import ( "arduino.cc/builder/constants" "arduino.cc/builder/gohasissues" "arduino.cc/builder/types" + "arduino.cc/builder/utils" "github.com/stretchr/testify/require" - "io/ioutil" "os" "path/filepath" "testing" @@ -50,7 +50,7 @@ func TestWipeoutBuildPathIfBuildOptionsChanged(t *testing.T) { context[constants.CTX_BUILD_OPTIONS_PREVIOUS_JSON] = "old" context[constants.CTX_BUILD_OPTIONS_JSON] = "new" - ioutil.WriteFile(filepath.Join(buildPath, "should_be_deleted.txt"), []byte{}, os.FileMode(0644)) + utils.TouchFile(filepath.Join(buildPath, "should_be_deleted.txt")) commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -81,7 +81,7 @@ func TestWipeoutBuildPathIfBuildOptionsChangedNoPreviousBuildOptions(t *testing. context[constants.CTX_BUILD_OPTIONS_JSON] = "new" - ioutil.WriteFile(filepath.Join(buildPath, "should_not_be_deleted.txt"), []byte{}, os.FileMode(0644)) + utils.TouchFile(filepath.Join(buildPath, "should_not_be_deleted.txt")) commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, @@ -113,7 +113,7 @@ func TestWipeoutBuildPathIfBuildOptionsChangedBuildOptionsMatch(t *testing.T) { context[constants.CTX_BUILD_OPTIONS_PREVIOUS_JSON] = "options" context[constants.CTX_BUILD_OPTIONS_JSON] = "options" - ioutil.WriteFile(filepath.Join(buildPath, "should_not_be_deleted.txt"), []byte{}, os.FileMode(0644)) + utils.TouchFile(filepath.Join(buildPath, "should_not_be_deleted.txt")) commands := []types.Command{ &builder.SetupHumanLoggerIfMissing{}, diff --git a/src/arduino.cc/builder/types/accessories.go b/src/arduino.cc/builder/types/accessories.go index f37004fa..1d7b7fc2 100644 --- a/src/arduino.cc/builder/types/accessories.go +++ b/src/arduino.cc/builder/types/accessories.go @@ -74,9 +74,3 @@ func (queue *UniqueSourceFolderQueue) Pop() interface{} { func (queue *UniqueSourceFolderQueue) Empty() bool { return queue.Len() == 0 } - -type LibraryResolutionResult struct { - Library *Library - IsLibraryFromPlatform bool - NotUsedLibraries []*Library -} diff --git a/src/arduino.cc/builder/types/types.go b/src/arduino.cc/builder/types/types.go index 22cf2693..57da8897 100644 --- a/src/arduino.cc/builder/types/types.go +++ b/src/arduino.cc/builder/types/types.go @@ -31,6 +31,7 @@ package types import ( "arduino.cc/builder/constants" + "strconv" ) type SketchFile struct { @@ -112,6 +113,7 @@ type Library struct { URL string Category string License string + Properties map[string]string } func (library *Library) String() string { @@ -153,11 +155,42 @@ type Command interface { type Prototype struct { FunctionName string + File string Prototype string - Fields map[string]string + Modifiers string + Line int +} + +func (proto *Prototype) String() string { + return proto.Modifiers + " " + proto.Prototype + " @ " + strconv.Itoa(proto.Line) } type SourceFolder struct { Folder string Recurse bool } + +type LibraryResolutionResult struct { + Library *Library + IsLibraryFromPlatform bool + NotUsedLibraries []*Library +} + +type CTag struct { + FunctionName string + Kind string + Line int + Signature string + Returntype string + Code string + Class string + Struct string + Namespace string + Filename string + Typeref string + SkipMe bool + + Prototype string + Function string + PrototypeModifiers string +} diff --git a/src/arduino.cc/builder/unused_compiled_libraries_remover.go b/src/arduino.cc/builder/unused_compiled_libraries_remover.go new file mode 100644 index 00000000..cd743b04 --- /dev/null +++ b/src/arduino.cc/builder/unused_compiled_libraries_remover.go @@ -0,0 +1,78 @@ +/* + * This file is part of Arduino Builder. + * + * Arduino Builder is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + */ + +package builder + +import ( + "arduino.cc/builder/constants" + "arduino.cc/builder/types" + "arduino.cc/builder/utils" + "io/ioutil" + "os" + "path/filepath" +) + +type UnusedCompiledLibrariesRemover struct{} + +func (s *UnusedCompiledLibrariesRemover) Run(context map[string]interface{}) error { + librariesBuildPath := context[constants.CTX_LIBRARIES_BUILD_PATH].(string) + libraries := context[constants.CTX_IMPORTED_LIBRARIES].([]*types.Library) + + _, err := os.Stat(librariesBuildPath) + if err != nil && os.IsNotExist(err) { + return nil + } + + libraryNames := toLibraryNames(libraries) + + files, err := ioutil.ReadDir(librariesBuildPath) + if err != nil { + return utils.WrapError(err) + } + for _, file := range files { + if file.IsDir() { + if !utils.SliceContains(libraryNames, file.Name()) { + err := os.RemoveAll(filepath.Join(librariesBuildPath, file.Name())) + if err != nil { + return utils.WrapError(err) + } + } + } + } + + return nil +} + +func toLibraryNames(libraries []*types.Library) []string { + libraryNames := []string{} + for _, library := range libraries { + libraryNames = append(libraryNames, library.Name) + } + return libraryNames +} diff --git a/src/arduino.cc/builder/utils/utils.go b/src/arduino.cc/builder/utils/utils.go index 592819ee..100598d3 100644 --- a/src/arduino.cc/builder/utils/utils.go +++ b/src/arduino.cc/builder/utils/utils.go @@ -34,6 +34,8 @@ import ( "arduino.cc/builder/gohasissues" "arduino.cc/builder/i18n" "arduino.cc/builder/types" + "crypto/md5" + "encoding/hex" "github.com/go-errors/errors" "io/ioutil" "os" @@ -184,11 +186,22 @@ func FilterFilesWithExtension(extension string) filterFiles { var SOURCE_CONTROL_FOLDERS = map[string]bool{"CVS": true, "RCS": true, ".git": true, ".svn": true, ".hg": true, ".bzr": true} func IsSCCSOrHiddenFile(file os.FileInfo) bool { + return IsSCCSFile(file) || IsHiddenFile(file) +} + +func IsHiddenFile(file os.FileInfo) bool { name := filepath.Base(file.Name()) if name[0] == '.' { return true } + + return false +} + +func IsSCCSFile(file os.FileInfo) bool { + name := filepath.Base(file.Name()) + if SOURCE_CONTROL_FOLDERS[name] { return true } @@ -205,15 +218,6 @@ func SliceContains(slice []string, target string) bool { return false } -func SliceContainsPrototype(slice []*types.Prototype, target *types.Prototype) bool { - for _, value := range slice { - if value.FunctionName == target.FunctionName { - return true - } - } - return false -} - type mapFunc func(string) string func Map(slice []string, fn mapFunc) []string { @@ -292,7 +296,7 @@ func Errorf(context map[string]interface{}, format string, a ...interface{}) *er func ErrorfWithLogger(log i18n.Logger, format string, a ...interface{}) *errors.Error { if log.Name() == "machine" { - log.Fprintln(os.Stderr, format, a...) + log.Fprintln(os.Stderr, constants.LOG_LEVEL_ERROR, format, a...) return errors.Errorf(constants.EMPTY_STRING) } return errors.Errorf(i18n.Format(format, a...)) @@ -380,9 +384,9 @@ func FilterOutFoldersByNames(folders []os.FileInfo, names ...string) []os.FileIn return filtered } -type CheckFileExtensionFunc func(ext string) bool +type CheckFilePathFunc func(filePath string) bool -func CollectAllReadableFiles(collector *[]string, test CheckFileExtensionFunc) filepath.WalkFunc { +func CollectAllReadableFiles(collector *[]string, test CheckFilePathFunc) filepath.WalkFunc { walkFunc := func(currentPath string, info os.FileInfo, err error) error { if err != nil { return err @@ -391,8 +395,7 @@ func CollectAllReadableFiles(collector *[]string, test CheckFileExtensionFunc) f if info.IsDir() { return nil } - ext := strings.ToLower(filepath.Ext(currentPath)) - if !test(ext) { + if !test(currentPath) { return nil } currentFile, err := os.Open(currentPath) @@ -426,3 +429,40 @@ func LibraryToSourceFolder(library *types.Library) []types.SourceFolder { } return sourceFolders } + +func AddStringsToStringsSet(accumulator []string, stringsToAdd []string) []string { + previousStringsSet := SliceToMapStringBool(accumulator, true) + stringsSetToAdd := SliceToMapStringBool(stringsToAdd, true) + + newStringsSet := MergeMapsOfStringBool(previousStringsSet, stringsSetToAdd) + + return KeysOfMapOfStringBool(newStringsSet) +} + +func EnsureFolderExists(folder string) error { + return os.MkdirAll(folder, os.FileMode(0755)) +} + +func WriteFileBytes(targetFilePath string, data []byte) error { + return ioutil.WriteFile(targetFilePath, data, os.FileMode(0644)) +} + +func WriteFile(targetFilePath string, data string) error { + return WriteFileBytes(targetFilePath, []byte(data)) +} + +func TouchFile(targetFilePath string) error { + return WriteFileBytes(targetFilePath, []byte{}) +} + +func NULLFile() string { + if runtime.GOOS == "windows" { + return "nul" + } + return "/dev/null" +} + +func MD5Sum(data []byte) string { + md5sumBytes := md5.Sum(data) + return hex.EncodeToString(md5sumBytes[:]) +} diff --git a/src/arduino.cc/builder/warn_about_arch_incompatible_libraries.go b/src/arduino.cc/builder/warn_about_arch_incompatible_libraries.go index 20de4642..4cad2db7 100644 --- a/src/arduino.cc/builder/warn_about_arch_incompatible_libraries.go +++ b/src/arduino.cc/builder/warn_about_arch_incompatible_libraries.go @@ -62,7 +62,7 @@ func (s *WarnAboutArchIncompatibleLibraries) Run(context map[string]interface{}) importedLibraries := context[constants.CTX_IMPORTED_LIBRARIES].([]*types.Library) for _, importedLibrary := range importedLibraries { if !importedLibrary.SupportsArchitectures(archs) { - logger.Fprintln(os.Stderr, constants.MSG_LIBRARY_INCOMPATIBLE_ARCH, importedLibrary.Name, importedLibrary.Archs, archs) + logger.Fprintln(os.Stdout, constants.LOG_LEVEL_WARN, constants.MSG_LIBRARY_INCOMPATIBLE_ARCH, importedLibrary.Name, importedLibrary.Archs, archs) } } diff --git a/src/arduino.cc/builder/warn_about_platform_rewrites.go b/src/arduino.cc/builder/warn_about_platform_rewrites.go new file mode 100644 index 00000000..a6be00ab --- /dev/null +++ b/src/arduino.cc/builder/warn_about_platform_rewrites.go @@ -0,0 +1,67 @@ +/* + * This file is part of Arduino Builder. + * + * Arduino Builder is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + */ + +package builder + +import ( + "arduino.cc/builder/constants" + "arduino.cc/builder/i18n" + "arduino.cc/builder/types" + "arduino.cc/builder/utils" + "os" +) + +type WarnAboutPlatformRewrites struct{} + +func (s *WarnAboutPlatformRewrites) Run(context map[string]interface{}) error { + warn := utils.DebugLevel(context) > 0 + if !warn { + return nil + } + + logger := context[constants.CTX_LOGGER].(i18n.Logger) + hardwareRewriteResults := context[constants.CTX_HARDWARE_REWRITE_RESULTS].(map[*types.Platform][]types.PlatforKeyRewrite) + targetPlatform := context[constants.CTX_TARGET_PLATFORM].(*types.Platform) + actualPlatform := context[constants.CTX_ACTUAL_PLATFORM].(*types.Platform) + + platforms := []*types.Platform{targetPlatform} + if actualPlatform != targetPlatform { + platforms = append(platforms, actualPlatform) + } + + for _, platform := range platforms { + if hardwareRewriteResults[platform] != nil { + for _, rewrite := range hardwareRewriteResults[platform] { + logger.Fprintln(os.Stdout, constants.LOG_LEVEL_WARN, constants.MSG_WARNING_PLATFORM_OLD_VALUES, platform.Properties[constants.PLATFORM_NAME], rewrite.Key+"="+rewrite.OldValue, rewrite.Key+"="+rewrite.NewValue) + } + } + } + + return nil +} diff --git a/src/arduino.cc/builder/wipeout_build_path_if_build_options_changed.go b/src/arduino.cc/builder/wipeout_build_path_if_build_options_changed.go index 762f2660..71a30e01 100644 --- a/src/arduino.cc/builder/wipeout_build_path_if_build_options_changed.go +++ b/src/arduino.cc/builder/wipeout_build_path_if_build_options_changed.go @@ -53,7 +53,7 @@ func (s *WipeoutBuildPathIfBuildOptionsChanged) Run(context map[string]interface return nil } - logger.Println(constants.MSG_BUILD_OPTIONS_CHANGED) + logger.Println(constants.LOG_LEVEL_INFO, constants.MSG_BUILD_OPTIONS_CHANGED) buildPath := context[constants.CTX_BUILD_PATH].(string) files, err := gohasissues.ReadDir(buildPath)