diff --git a/main.go b/main.go index 3eba1ed8..f01abf2a 100644 --- a/main.go +++ b/main.go @@ -293,6 +293,15 @@ func main() { context[constants.CTX_LOGGER] = i18n.HumanLogger{} } + sketchBuildOptions, err := builder.GetSketchBuildProperties(context) + if err != nil { + printError(err, printStackTrace) + defer os.Exit(1) + return + } + context[constants.CTX_SKETCH_BUILD_PROPERTIES] = sketchBuildOptions + + if compile { err = builder.RunBuilder(context) } else if dumpPrefs { diff --git a/src/arduino.cc/builder/constants/constants.go b/src/arduino.cc/builder/constants/constants.go index 9925d0cd..02a88406 100644 --- a/src/arduino.cc/builder/constants/constants.go +++ b/src/arduino.cc/builder/constants/constants.go @@ -114,6 +114,7 @@ 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_BUILD_PROPERTIES = "sketchBuildProperties" const CTX_SKETCH_LOCATION = "sketchLocation" const CTX_SKETCH = "sketch" const CTX_SOURCE = "source" @@ -245,6 +246,7 @@ const RECIPE_PREPROC_MACROS = "recipe.preproc.macros" const RECIPE_S_PATTERN = "recipe.S.o.pattern" const REWRITING_DISABLED = "disabled" const REWRITING = "rewriting" +const SKETCH_BUILD_OPTIONS_TXT = "build_props.txt" const SPACE = " " const TOOL_NAME = "name" const TOOL_URL = "url" diff --git a/src/arduino.cc/builder/container_setup.go b/src/arduino.cc/builder/container_setup.go index 9c702b1d..daf7d0ae 100644 --- a/src/arduino.cc/builder/container_setup.go +++ b/src/arduino.cc/builder/container_setup.go @@ -50,6 +50,7 @@ func (s *ContainerSetupHardwareToolsLibsSketchAndProps) Run(context map[string]i &SketchLoader{}, &SetupBuildProperties{}, &LoadVIDPIDSpecificProperties{}, + &SetSketchBuildProperties{}, &SetCustomBuildProperties{}, &AddMissingBuildPropertiesFromParentPlatformTxtFiles{}, } diff --git a/src/arduino.cc/builder/create_build_options_map.go b/src/arduino.cc/builder/create_build_options_map.go index 835c90e0..600317c6 100644 --- a/src/arduino.cc/builder/create_build_options_map.go +++ b/src/arduino.cc/builder/create_build_options_map.go @@ -40,8 +40,7 @@ import ( type CreateBuildOptionsMap struct{} func (s *CreateBuildOptionsMap) Run(context map[string]interface{}) error { - buildOptions := make(map[string]string) - + buildOptions := make(map[string]interface{}) buildOptionsMapKeys := []string{ constants.CTX_HARDWARE_FOLDERS, constants.CTX_TOOLS_FOLDERS, @@ -49,23 +48,23 @@ func (s *CreateBuildOptionsMap) Run(context map[string]interface{}) error { constants.CTX_FQBN, constants.CTX_SKETCH_LOCATION, constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION, + constants.CTX_SKETCH_BUILD_PROPERTIES, constants.CTX_CUSTOM_BUILD_PROPERTIES, } for _, key := range buildOptionsMapKeys { if utils.MapHas(context, key) { originalValue := context[key] - value := constants.EMPTY_STRING kindOfValue := reflect.TypeOf(originalValue).Kind() if kindOfValue == reflect.Slice { - value = strings.Join(originalValue.([]string), ",") + buildOptions[key] = strings.Join(originalValue.([]string), ",") } else if kindOfValue == reflect.String { - value = originalValue.(string) + buildOptions[key] = originalValue.(string) + } else if kindOfValue == reflect.TypeOf(make(map[string]string)).Kind() { + buildOptions[key] = originalValue } else { return utils.Errorf(context, constants.MSG_UNHANDLED_TYPE_IN_CONTEXT, kindOfValue.String(), key) } - - buildOptions[key] = value } } diff --git a/src/arduino.cc/builder/get_sketch_build_properties.go b/src/arduino.cc/builder/get_sketch_build_properties.go new file mode 100644 index 00000000..c90b94b8 --- /dev/null +++ b/src/arduino.cc/builder/get_sketch_build_properties.go @@ -0,0 +1,62 @@ +/* + * 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 Steve Marple + */ + +package builder + +import ( + "arduino.cc/builder/constants" + "arduino.cc/builder/props" + "github.com/go-errors/errors" + "os" + "path/filepath" +) + +func GetSketchBuildPropertiesFilename(context map[string]interface{}) (string, error) { + sketchLocation, ok := context[constants.CTX_SKETCH_LOCATION].(string) + if !ok { + return "", errors.New("Unknown sketch location") + } + + filename := filepath.Join(filepath.Dir(sketchLocation), constants.SKETCH_BUILD_OPTIONS_TXT) + return filename, nil +} + + +func GetSketchBuildProperties(context map[string]interface{}) (map[string]string, error) { + filename, err := GetSketchBuildPropertiesFilename(context) + if err != nil { + return nil, err + } + _, err = os.Stat(filename) + if err == nil { + return props.SafeLoad(filename) + } + return make(map[string]string), nil +} + diff --git a/src/arduino.cc/builder/set_sketch_build_properties.go b/src/arduino.cc/builder/set_sketch_build_properties.go new file mode 100644 index 00000000..5d0e1dbc --- /dev/null +++ b/src/arduino.cc/builder/set_sketch_build_properties.go @@ -0,0 +1,52 @@ +/* + * 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 Steve Marple + */ + +package builder + +import ( + "arduino.cc/builder/constants" + "arduino.cc/builder/utils" +) + +type SetSketchBuildProperties struct{} + +func (s *SetSketchBuildProperties) Run(context map[string]interface{}) error { + if !utils.MapHas(context, constants.CTX_SKETCH_BUILD_PROPERTIES) { + return nil + } + + buildProperties := context[constants.CTX_BUILD_PROPERTIES].(map[string]string) + + sketchBuildProperties := context[constants.CTX_SKETCH_BUILD_PROPERTIES].(map[string]string) + for key, value := range sketchBuildProperties { + buildProperties[key] = value + } + + return nil +} diff --git a/src/arduino.cc/builder/test/create_build_options_map_test.go b/src/arduino.cc/builder/test/create_build_options_map_test.go index 02b08100..fc5aeae2 100644 --- a/src/arduino.cc/builder/test/create_build_options_map_test.go +++ b/src/arduino.cc/builder/test/create_build_options_map_test.go @@ -48,14 +48,18 @@ func TestCreateBuildOptionsMap(t *testing.T) { context[constants.CTX_SKETCH_LOCATION] = "sketchLocation" context[constants.CTX_VERBOSE] = true context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "ideVersion" + context[constants.CTX_SKETCH_BUILD_PROPERTIES] = map[string]string{ + "compiler.c.extra_flags": "-D NDEBUG", + "compiler.cpp.extra_flags": "-D HOSTNAME=\"www.example.com\"", + } context[constants.CTX_DEBUG_LEVEL] = 5 create := builder.CreateBuildOptionsMap{} err := create.Run(context) NoError(t, err) - buildOptions := context[constants.CTX_BUILD_OPTIONS].(map[string]string) - require.Equal(t, 6, len(utils.KeysOfMapOfString(buildOptions))) + buildOptions := context[constants.CTX_BUILD_OPTIONS].(map[string]interface{}) + require.Equal(t, 7, len(utils.KeysOfMapOfStringInterface(buildOptions))) require.Equal(t, "hardware,hardware2", buildOptions[constants.CTX_HARDWARE_FOLDERS]) require.Equal(t, "tools", buildOptions[constants.CTX_TOOLS_FOLDERS]) require.Equal(t, "libraries", buildOptions[constants.CTX_LIBRARIES_FOLDERS]) @@ -63,11 +67,21 @@ func TestCreateBuildOptionsMap(t *testing.T) { require.Equal(t, "sketchLocation", buildOptions[constants.CTX_SKETCH_LOCATION]) require.Equal(t, "ideVersion", buildOptions[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION]) + sketchBuildProps := map[string]string{ + "compiler.c.extra_flags": "-D NDEBUG", + "compiler.cpp.extra_flags": "-D HOSTNAME=\"www.example.com\"", + } + require.Equal(t, sketchBuildProps, buildOptions[constants.CTX_SKETCH_BUILD_PROPERTIES]) + require.Equal(t, "{\n"+ " \"fqbn\": \"fqbn\",\n"+ " \"hardwareFolders\": \"hardware,hardware2\",\n"+ " \"librariesFolders\": \"libraries\",\n"+ " \"runtime.ide.version\": \"ideVersion\",\n"+ + " \"sketchBuildProperties\": {\n" + + " \"compiler.c.extra_flags\": \"-D NDEBUG\",\n"+ + " \"compiler.cpp.extra_flags\": \"-D HOSTNAME=\\\"www.example.com\\\"\"\n"+ + " },\n"+ " \"sketchLocation\": \"sketchLocation\",\n"+ " \"toolsFolders\": \"tools\"\n"+ "}", context[constants.CTX_BUILD_OPTIONS_JSON].(string)) diff --git a/src/arduino.cc/builder/test/sketch_build_properties_test.go b/src/arduino.cc/builder/test/sketch_build_properties_test.go new file mode 100644 index 00000000..4e5c7b14 --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_build_properties_test.go @@ -0,0 +1,96 @@ +/* + * 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 Steve Marple + */ + +package test + +import ( + "arduino.cc/builder" + "arduino.cc/builder/constants" + "github.com/stretchr/testify/require" + "path/filepath" + "testing" +) + +func TestSketchWithNoBuildProps(t *testing.T) { + var err error + context := make(map[string]interface{}) + + context[constants.CTX_BUILD_PATH] = "buildPath" + context[constants.CTX_HARDWARE_FOLDERS] = []string{"hardware"} + context[constants.CTX_TOOLS_FOLDERS] = []string{"tools"} + context[constants.CTX_LIBRARIES_FOLDERS] = []string{"libraries"} + context[constants.CTX_FQBN] = "fqbn" + context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch_no_props", "sketch.ino") + + context[constants.CTX_VERBOSE] = true + context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "ideVersion" + context[constants.CTX_SKETCH_BUILD_PROPERTIES], err = builder.GetSketchBuildProperties(context) + NoError(t, err) + + context[constants.CTX_DEBUG_LEVEL] = 5 + + create := builder.CreateBuildOptionsMap{} + err = create.Run(context) + NoError(t, err) + + buildOptions := context[constants.CTX_BUILD_OPTIONS].(map[string]interface{}) + sketchBuildProps := make(map[string]string) + require.Equal(t, sketchBuildProps, buildOptions[constants.CTX_SKETCH_BUILD_PROPERTIES]) +} + +func TestSketchWithBuildProps(t *testing.T) { + var err error + context := make(map[string]interface{}) + + context[constants.CTX_BUILD_PATH] = "buildPath" + context[constants.CTX_HARDWARE_FOLDERS] = []string{"hardware"} + context[constants.CTX_TOOLS_FOLDERS] = []string{"tools"} + context[constants.CTX_LIBRARIES_FOLDERS] = []string{"libraries"} + context[constants.CTX_FQBN] = "fqbn" + context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch_with_props", "sketch.ino") + + context[constants.CTX_VERBOSE] = true + context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "ideVersion" + context[constants.CTX_SKETCH_BUILD_PROPERTIES], err = builder.GetSketchBuildProperties(context) + NoError(t, err) + + context[constants.CTX_DEBUG_LEVEL] = 5 + + create := builder.CreateBuildOptionsMap{} + err = create.Run(context) + NoError(t, err) + + buildOptions := context[constants.CTX_BUILD_OPTIONS].(map[string]interface{}) + sketchBuildProps := make(map[string]string) + sketchBuildProps["compiler.c.extra_flags"] = "-D NDEBUG" + sketchBuildProps["compiler.cpp.extra_flags"] = "-D NDEBUG -D TESTLIBRARY_BUFSIZE=100 -D ARDUINO_URL=\"https://www.arduino.cc/\"" + + require.Equal(t, sketchBuildProps, buildOptions[constants.CTX_SKETCH_BUILD_PROPERTIES]) + +} diff --git a/src/arduino.cc/builder/test/sketch_no_props/sketch.ino b/src/arduino.cc/builder/test/sketch_no_props/sketch.ino new file mode 100644 index 00000000..32f56baa --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_no_props/sketch.ino @@ -0,0 +1,7 @@ +void setup() { + +} + +void loop() { + +} diff --git a/src/arduino.cc/builder/test/sketch_with_props/build_props.txt b/src/arduino.cc/builder/test/sketch_with_props/build_props.txt new file mode 100644 index 00000000..469e2848 --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_with_props/build_props.txt @@ -0,0 +1,3 @@ +compiler.c.extra_flags=-D NDEBUG +compiler.cpp.extra_flags=-D NDEBUG -D TESTLIBRARY_BUFSIZE=100 -D ARDUINO_URL="https://www.arduino.cc/" + diff --git a/src/arduino.cc/builder/test/sketch_with_props/sketch.ino b/src/arduino.cc/builder/test/sketch_with_props/sketch.ino new file mode 100644 index 00000000..32f56baa --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_with_props/sketch.ino @@ -0,0 +1,7 @@ +void setup() { + +} + +void loop() { + +} diff --git a/src/arduino.cc/builder/utils/utils.go b/src/arduino.cc/builder/utils/utils.go index 643f26da..4bdd89cd 100644 --- a/src/arduino.cc/builder/utils/utils.go +++ b/src/arduino.cc/builder/utils/utils.go @@ -60,6 +60,14 @@ func KeysOfMapOfStringBool(input map[string]bool) []string { return keys } +func KeysOfMapOfStringInterface(input map[string]interface{}) []string { + var keys []string + for key, _ := range input { + keys = append(keys, key) + } + return keys +} + func MergeMapsOfStrings(target map[string]string, sources ...map[string]string) map[string]string { for _, source := range sources { for key, value := range source {