Esempio n. 1
0
func loadBoards(boards map[string]*types.Board, packageId string, platformId string, folder string, logger i18n.Logger) error {
	properties, err := props.Load(filepath.Join(folder, constants.FILE_BOARDS_TXT), logger)
	if err != nil {
		return utils.WrapError(err)
	}

	localProperties, err := props.SafeLoad(filepath.Join(folder, constants.FILE_BOARDS_LOCAL_TXT), logger)
	if err != nil {
		return utils.WrapError(err)
	}

	properties = utils.MergeMapsOfStrings(properties, localProperties)

	propertiesByBoardId := props.FirstLevelOf(properties)
	delete(propertiesByBoardId, constants.BOARD_PROPERTIES_MENU)

	for boardId, properties := range propertiesByBoardId {
		properties[constants.ID] = boardId
		board := getOrCreateBoard(boards, boardId)
		board.Properties = utils.MergeMapsOfStrings(board.Properties, properties)
		boards[boardId] = board
	}

	return nil
}
Esempio n. 2
0
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)
	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

	pattern := properties[constants.BUILD_PROPERTIES_PATTERN]
	if pattern == constants.EMPTY_STRING {
		return utils.Errorf(context, constants.MSG_PATTERN_MISSING, constants.CTAGS)
	}

	commandLine := props.ExpandPropsInString(properties, pattern)
	command, err := utils.PrepareCommand(commandLine, logger)
	if err != nil {
		return utils.WrapError(err)
	}

	verbose := context[constants.CTX_VERBOSE].(bool)
	if verbose {
		fmt.Println(commandLine)
	}

	sourceBytes, err := command.Output()
	if err != nil {
		return utils.WrapError(err)
	}

	context[constants.CTX_CTAGS_OUTPUT] = string(sourceBytes)

	return nil
}
Esempio n. 3
0
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)
	}

	buildProperties := utils.GetMapStringStringOrDefault(context, constants.CTX_BUILD_PROPERTIES)
	verbose := context[constants.CTX_VERBOSE].(bool)

	recipes := findRecipes(buildProperties, s.Prefix, s.Suffix)

	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)
		}
		_, err := builder_utils.ExecRecipe(properties, recipe, false, verbose, verbose, logger)
		if err != nil {
			return utils.WrapError(err)
		}
	}

	return nil

}
func (s *IncludesFinderWithGCC) Run(context map[string]interface{}) error {
	buildProperties := utils.GetMapStringStringOrDefault(context, constants.CTX_BUILD_PROPERTIES)
	verbose := context[constants.CTX_VERBOSE].(bool)
	logger := context[constants.CTX_LOGGER].(i18n.Logger)

	includesParams := constants.EMPTY_STRING
	if utils.MapHas(context, constants.CTX_INCLUDE_FOLDERS) {
		includes := context[constants.CTX_INCLUDE_FOLDERS].([]string)
		includes = utils.Map(includes, utils.WrapWithHyphenI)
		includesParams = strings.Join(includes, " ")
	}

	properties := utils.MergeMapsOfStrings(make(map[string]string), buildProperties)
	properties[constants.BUILD_PROPERTIES_SOURCE_FILE] = s.SourceFile
	properties[constants.BUILD_PROPERTIES_INCLUDES] = includesParams
	builder_utils.RemoveHyphenMDDFlagFromGCCCommandLine(properties)

	output, err := builder_utils.ExecRecipe(properties, constants.RECIPE_PREPROC_INCLUDES, true, verbose, false, logger)
	if err != nil {
		return utils.WrapError(err)
	}

	context[constants.CTX_GCC_MINUS_M_OUTPUT] = string(output)

	return nil
}
Esempio n. 5
0
func compileFileWithRecipe(sourcePath string, source string, buildPath string, buildProperties map[string]string, includes []string, recipe string, verbose bool, warningsLevel string, logger i18n.Logger) (string, error) {
	properties := utils.MergeMapsOfStrings(make(map[string]string), buildProperties)
	properties[constants.BUILD_PROPERTIES_COMPILER_WARNING_FLAGS] = properties[constants.BUILD_PROPERTIES_COMPILER_WARNING_FLAGS+"."+warningsLevel]
	properties[constants.BUILD_PROPERTIES_INCLUDES] = strings.Join(includes, constants.SPACE)
	properties[constants.BUILD_PROPERTIES_SOURCE_FILE] = source
	relativeSource, err := filepath.Rel(sourcePath, source)
	if err != nil {
		return "", utils.WrapError(err)
	}
	properties[constants.BUILD_PROPERTIES_OBJECT_FILE] = filepath.Join(buildPath, relativeSource+".o")

	err = utils.EnsureFolderExists(filepath.Dir(properties[constants.BUILD_PROPERTIES_OBJECT_FILE]))
	if err != nil {
		return "", utils.WrapError(err)
	}

	objIsUpToDate, err := ObjFileIsUpToDate(properties[constants.BUILD_PROPERTIES_SOURCE_FILE], properties[constants.BUILD_PROPERTIES_OBJECT_FILE], filepath.Join(buildPath, relativeSource+".d"))
	if err != nil {
		return "", utils.WrapError(err)
	}

	if !objIsUpToDate {
		_, err = ExecRecipe(properties, recipe, false, verbose, verbose, logger)
		if err != nil {
			return "", utils.WrapError(err)
		}
	} else if verbose {
		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
}
func (s *LoadVIDPIDSpecificProperties) Run(context map[string]interface{}) error {
	if !utils.MapHas(context, constants.CTX_VIDPID) {
		return nil
	}

	vidPid := context[constants.CTX_VIDPID].(string)
	vidPid = strings.ToLower(vidPid)
	vidPidParts := strings.Split(vidPid, "_")
	vid := vidPidParts[0]
	pid := vidPidParts[1]

	buildProperties := context[constants.CTX_BUILD_PROPERTIES].(map[string]string)
	VIDPIDIndex, err := findVIDPIDIndex(buildProperties, vid, pid)
	if err != nil {
		return utils.WrapError(err)
	}
	if VIDPIDIndex < 0 {
		return nil
	}

	vidPidSpecificProperties := props.SubTree(props.SubTree(buildProperties, constants.BUILD_PROPERTIES_VID), strconv.Itoa(VIDPIDIndex))
	utils.MergeMapsOfStrings(buildProperties, vidPidSpecificProperties)

	return nil
}
Esempio n. 7
0
func (s *HardwareLoader) Run(context map[string]interface{}) error {
	mainHardwarePlatformTxt := make(map[string]string)

	packages := make(map[string]*types.Package)

	folders := context[constants.CTX_HARDWARE_FOLDERS].([]string)
	folders, err := utils.AbsolutizePaths(folders)
	if err != nil {
		return utils.WrapError(err)
	}

	for _, folder := range folders {
		stat, err := os.Stat(folder)
		if err != nil {
			return utils.WrapError(err)
		}
		if !stat.IsDir() {
			return utils.Errorf(context, constants.MSG_MUST_BE_A_FOLDER, folder)
		}

		if len(mainHardwarePlatformTxt) == 0 {
			mainHardwarePlatformTxt, err = props.SafeLoad(filepath.Join(folder, constants.FILE_PLATFORM_TXT))
			if err != nil {
				return utils.WrapError(err)
			}
		}
		hardwarePlatformTxt, err := props.SafeLoad(filepath.Join(folder, constants.FILE_PLATFORM_TXT))
		if err != nil {
			return utils.WrapError(err)
		}
		hardwarePlatformTxt = utils.MergeMapsOfStrings(make(map[string]string), mainHardwarePlatformTxt, hardwarePlatformTxt)

		subfolders, err := utils.ReadDirFiltered(folder, utils.FilterDirs)
		if err != nil {
			return utils.WrapError(err)
		}
		subfolders = utils.FilterOutFoldersByNames(subfolders, constants.FOLDER_TOOLS)

		for _, subfolder := range subfolders {
			subfolderPath := filepath.Join(folder, subfolder.Name())
			packageId := subfolder.Name()

			if _, err := os.Stat(filepath.Join(subfolderPath, constants.FOLDER_HARDWARE)); err == nil {
				subfolderPath = filepath.Join(subfolderPath, constants.FOLDER_HARDWARE)
			}

			targetPackage := getOrCreatePackage(packages, packageId)
			err = loadPackage(targetPackage, subfolderPath, hardwarePlatformTxt)
			if err != nil {
				return utils.WrapError(err)
			}
			packages[packageId] = targetPackage
		}
	}

	context[constants.CTX_HARDWARE] = packages

	return nil
}
func (s *AddMissingBuildPropertiesFromParentPlatformTxtFiles) Run(context map[string]interface{}) error {
	packages := context[constants.CTX_HARDWARE].(*types.Packages)
	targetPackage := context[constants.CTX_TARGET_PACKAGE].(*types.Package)
	buildProperties := context[constants.CTX_BUILD_PROPERTIES].(map[string]string)

	buildProperties = utils.MergeMapsOfStrings(make(map[string]string), packages.Properties, targetPackage.Properties, buildProperties)

	context[constants.CTX_BUILD_PROPERTIES] = buildProperties

	return nil
}
Esempio n. 9
0
func compileCore(buildPath string, buildProperties map[string]string, verbose bool, warningsLevel string, logger i18n.Logger) ([]string, error) {
	var objectFiles []string
	coreFolder := buildProperties[constants.BUILD_PROPERTIES_BUILD_CORE_PATH]
	variantFolder := buildProperties[constants.BUILD_PROPERTIES_BUILD_VARIANT_PATH]

	var includes []string
	includes = append(includes, coreFolder)
	if variantFolder != constants.EMPTY_STRING {
		includes = append(includes, variantFolder)
	}
	includes = utils.Map(includes, utils.WrapWithHyphenI)

	var err error

	if variantFolder != constants.EMPTY_STRING {
		objectFiles, err = builder_utils.CompileFiles(objectFiles, variantFolder, true, buildPath, buildProperties, includes, verbose, warningsLevel, logger)
		if err != nil {
			return nil, utils.WrapError(err)
		}
	}

	coreObjectFiles, err := builder_utils.CompileFiles([]string{}, coreFolder, true, buildPath, buildProperties, includes, verbose, warningsLevel, logger)
	if err != nil {
		return nil, utils.WrapError(err)
	}

	coreArchiveFilePath := filepath.Join(buildPath, "core.a")
	if _, err := os.Stat(coreArchiveFilePath); err == nil {
		err = os.Remove(coreArchiveFilePath)
		if err != nil {
			return nil, utils.WrapError(err)
		}
	}

	for _, coreObjectFile := range coreObjectFiles {
		properties := utils.MergeMapsOfStrings(make(map[string]string), buildProperties)
		properties[constants.BUILD_PROPERTIES_INCLUDES] = strings.Join(includes, constants.SPACE)
		properties[constants.BUILD_PROPERTIES_ARCHIVE_FILE] = filepath.Base(coreArchiveFilePath)
		properties[constants.BUILD_PROPERTIES_OBJECT_FILE] = coreObjectFile

		_, err := builder_utils.ExecRecipe(properties, "recipe.ar.pattern", false, verbose, verbose, logger)
		if err != nil {
			return nil, utils.WrapError(err)
		}
	}

	return objectFiles, nil
}
Esempio n. 10
0
func link(objectFiles []string, coreDotARelPath string, coreArchiveFilePath string, buildProperties map[string]string, verbose bool, warningsLevel string, logger i18n.Logger) error {
	optRelax := addRelaxTrickIfATMEGA2560(buildProperties)

	objectFiles = utils.Map(objectFiles, wrapWithDoubleQuotes)
	objectFileList := strings.Join(objectFiles, constants.SPACE)

	properties := utils.MergeMapsOfStrings(make(map[string]string), buildProperties)
	properties[constants.BUILD_PROPERTIES_COMPILER_C_ELF_FLAGS] = properties[constants.BUILD_PROPERTIES_COMPILER_C_ELF_FLAGS] + optRelax
	properties[constants.BUILD_PROPERTIES_COMPILER_WARNING_FLAGS] = properties[constants.BUILD_PROPERTIES_COMPILER_WARNING_FLAGS+"."+warningsLevel]
	properties[constants.BUILD_PROPERTIES_ARCHIVE_FILE] = coreDotARelPath
	properties[constants.BUILD_PROPERTIES_ARCHIVE_FILE_PATH] = coreArchiveFilePath
	properties[constants.BUILD_PROPERTIES_OBJECT_FILES] = objectFileList

	_, err := builder_utils.ExecRecipe(properties, constants.RECIPE_C_COMBINE_PATTERN, false, verbose, verbose, logger)
	return err
}
Esempio n. 11
0
func link(objectFiles []string, buildProperties map[string]string, verbose bool, warningsLevel string, logger i18n.Logger) error {
	optRelax := constants.EMPTY_STRING
	if buildProperties[constants.BUILD_PROPERTIES_BUILD_MCU] == "atmega2560" {
		optRelax = ",--relax"
	}

	objectFiles = utils.Map(objectFiles, wrapWithDoubleQuotes)
	objectFileList := strings.Join(objectFiles, constants.SPACE)

	properties := utils.MergeMapsOfStrings(make(map[string]string), buildProperties)
	properties["compiler.c.elf.flags"] = properties["compiler.c.elf.flags"] + optRelax
	properties["compiler.warning_flags"] = properties["compiler.warning_flags."+warningsLevel]
	properties[constants.BUILD_PROPERTIES_ARCHIVE_FILE] = "core.a"
	properties[constants.BUILD_PROPERTIES_OBJECT_FILES] = objectFileList

	_, err := builder_utils.ExecRecipe(properties, "recipe.c.combine.pattern", false, verbose, verbose, logger)
	return err
}
Esempio n. 12
0
func loadPackage(targetPackage *types.Package, folder string, logger i18n.Logger) error {
	packagePlatformTxt, err := props.SafeLoad(filepath.Join(folder, constants.FILE_PLATFORM_TXT), logger)
	if err != nil {
		return utils.WrapError(err)
	}
	targetPackage.Properties = utils.MergeMapsOfStrings(targetPackage.Properties, packagePlatformTxt)

	subfolders, err := utils.ReadDirFiltered(folder, utils.FilterDirs)
	if err != nil {
		return utils.WrapError(err)
	}

	subfolders = utils.FilterOutFoldersByNames(subfolders, constants.FOLDER_TOOLS)

	platforms := targetPackage.Platforms
	for _, subfolder := range subfolders {
		subfolderPath := filepath.Join(folder, subfolder.Name())
		platformId := subfolder.Name()

		_, err := os.Stat(filepath.Join(subfolderPath, constants.FILE_BOARDS_TXT))
		if err != nil && os.IsNotExist(err) {
			theOnlySubfolder, err := utils.TheOnlySubfolderOf(subfolderPath)
			if err != nil {
				return utils.WrapError(err)
			}

			if theOnlySubfolder != constants.EMPTY_STRING {
				subfolderPath = filepath.Join(subfolderPath, theOnlySubfolder)
			}
		}

		platform := getOrCreatePlatform(platforms, platformId)
		err = loadPlatform(platform, targetPackage.PackageId, subfolderPath, logger)
		if err != nil {
			return utils.WrapError(err)
		}
		platforms[platformId] = platform
	}

	return nil
}
func prepareGCCPreprocRecipeProperties(context map[string]interface{}, sourceFilePath string, targetFileName string) (map[string]string, string, error) {
	preprocPath := context[constants.CTX_PREPROC_PATH].(string)
	err := utils.EnsureFolderExists(preprocPath)
	if err != nil {
		return nil, "", utils.WrapError(err)
	}
	targetFilePath := filepath.Join(preprocPath, targetFileName)

	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
}
Esempio n. 14
0
func (s *CoanRunner) Run(context map[string]interface{}) error {
	source := context[constants.CTX_SOURCE].(string)
	source += "\n"
	verbose := context[constants.CTX_VERBOSE].(bool)

	preprocPath := context[constants.CTX_PREPROC_PATH].(string)
	err := utils.EnsureFolderExists(preprocPath)
	if err != nil {
		return utils.WrapError(err)
	}

	coanTargetFileName := filepath.Join(preprocPath, constants.FILE_COAN_TARGET)
	err = utils.WriteFile(coanTargetFileName, source)
	if err != nil {
		return utils.WrapError(err)
	}

	buildProperties := context[constants.CTX_BUILD_PROPERTIES].(map[string]string)
	properties := utils.MergeMapsOfStrings(make(map[string]string), buildProperties, props.SubTree(props.SubTree(buildProperties, constants.BUILD_PROPERTIES_TOOLS_KEY), constants.COAN))
	properties[constants.BUILD_PROPERTIES_SOURCE_FILE] = coanTargetFileName

	pattern := properties[constants.BUILD_PROPERTIES_PATTERN]
	if pattern == constants.EMPTY_STRING {
		return utils.Errorf(context, constants.MSG_PATTERN_MISSING, constants.COAN)
	}

	logger := context[constants.CTX_LOGGER].(i18n.Logger)
	commandLine := props.ExpandPropsInString(properties, pattern)
	command, err := utils.PrepareCommandFilteredArgs(commandLine, filterAllowedArg, logger)

	if verbose {
		fmt.Println(commandLine)
	}

	sourceBytes, _ := command.Output()

	context[constants.CTX_SOURCE] = string(sourceBytes)

	return nil
}
Esempio n. 15
0
func compileWithRecipe(objectFiles []string, sourcePath string, sources []string, buildPath string, buildProperties map[string]string, includes []string, recipe string, verbose bool, warningsLevel string, logger i18n.Logger) ([]string, error) {
	for _, source := range sources {
		properties := utils.MergeMapsOfStrings(make(map[string]string), buildProperties)
		properties[constants.BUILD_PROPERTIES_COMPILER_WARNING_FLAGS] = properties[constants.BUILD_PROPERTIES_COMPILER_WARNING_FLAGS+"."+warningsLevel]
		properties[constants.BUILD_PROPERTIES_INCLUDES] = strings.Join(includes, constants.SPACE)
		properties[constants.BUILD_PROPERTIES_SOURCE_FILE] = source
		relativeSource, err := filepath.Rel(sourcePath, source)
		if err != nil {
			return nil, utils.WrapError(err)
		}
		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))
		if err != nil {
			return nil, utils.WrapError(err)
		}

		sourceFileStat, err := os.Stat(properties[constants.BUILD_PROPERTIES_SOURCE_FILE])
		if err != nil {
			return nil, utils.WrapError(err)
		}

		objectFileStat, err := os.Stat(properties[constants.BUILD_PROPERTIES_OBJECT_FILE])
		if err != nil && !os.IsNotExist(err) {
			return nil, utils.WrapError(err)
		}

		if !objFileIsUpToDateWithSourceFile(sourceFileStat, objectFileStat) {
			_, err = ExecRecipe(properties, recipe, false, verbose, verbose, logger)
			if err != nil {
				return nil, utils.WrapError(err)
			}
		} else if verbose {
			logger.Println(constants.MSG_USING_PREVIOUS_COMPILED_FILE, properties[constants.BUILD_PROPERTIES_OBJECT_FILE])
		}

		objectFiles = append(objectFiles, properties[constants.BUILD_PROPERTIES_OBJECT_FILE])
	}
	return objectFiles, nil
}
Esempio n. 16
0
func loadPlatform(targetPlatform *types.Platform, packageId string, folder string, logger i18n.Logger) error {
	_, err := os.Stat(filepath.Join(folder, constants.FILE_BOARDS_TXT))
	if err != nil && !os.IsNotExist(err) {
		return utils.WrapError(err)
	}

	if os.IsNotExist(err) {
		return nil
	}

	targetPlatform.Folder = folder

	err = loadBoards(targetPlatform.Boards, packageId, targetPlatform.PlatformId, folder, logger)
	if err != nil {
		return utils.WrapError(err)
	}

	assignDefaultBoardToPlatform(targetPlatform)

	platformTxt, err := props.SafeLoad(filepath.Join(folder, constants.FILE_PLATFORM_TXT), logger)
	if err != nil {
		return utils.WrapError(err)
	}

	localPlatformProperties, err := props.SafeLoad(filepath.Join(folder, constants.FILE_PLATFORM_LOCAL_TXT), logger)
	if err != nil {
		return utils.WrapError(err)
	}

	targetPlatform.Properties = utils.MergeMapsOfStrings(make(map[string]string), targetPlatform.Properties, platformTxt, localPlatformProperties)

	programmersProperties, err := props.SafeLoad(filepath.Join(folder, constants.FILE_PROGRAMMERS_TXT), logger)
	if err != nil {
		return utils.WrapError(err)
	}
	targetPlatform.Programmers = utils.MergeMapsOfMapsOfStrings(make(map[string]map[string]string), targetPlatform.Programmers, props.FirstLevelOf(programmersProperties))

	return nil
}
Esempio n. 17
0
func ArchiveCompiledFiles(buildPath string, archiveFile string, objectFiles []string, buildProperties map[string]string, verbose bool, logger i18n.Logger) (string, error) {
	archiveFilePath := filepath.Join(buildPath, archiveFile)
	if _, err := os.Stat(archiveFilePath); err == nil {
		err = os.Remove(archiveFilePath)
		if err != nil {
			return "", utils.WrapError(err)
		}
	}

	for _, objectFile := range objectFiles {
		properties := utils.MergeMapsOfStrings(make(map[string]string), buildProperties)
		properties[constants.BUILD_PROPERTIES_ARCHIVE_FILE] = filepath.Base(archiveFilePath)
		properties[constants.BUILD_PROPERTIES_ARCHIVE_FILE_PATH] = archiveFilePath
		properties[constants.BUILD_PROPERTIES_OBJECT_FILE] = objectFile

		_, err := ExecRecipe(properties, constants.RECIPE_AR_PATTERN, false, verbose, verbose, logger)
		if err != nil {
			return "", utils.WrapError(err)
		}
	}

	return archiveFilePath, nil
}
func addAdditionalPropertiesToTargetBoard(board *types.Board, options string) {
	optionsParts := strings.Split(options, ",")
	optionsParts = utils.Map(optionsParts, utils.TrimSpace)

	for _, optionPart := range optionsParts {
		parts := strings.Split(optionPart, "=")
		parts = utils.Map(parts, utils.TrimSpace)

		key := parts[0]
		value := parts[1]
		if key != constants.EMPTY_STRING && value != constants.EMPTY_STRING {
			menu := props.SubTree(board.Properties, constants.BOARD_PROPERTIES_MENU)
			if len(menu) == 0 {
				return
			}
			propertiesOfKey := props.SubTree(menu, key)
			if len(propertiesOfKey) == 0 {
				return
			}
			propertiesOfKeyValue := props.SubTree(propertiesOfKey, value)
			utils.MergeMapsOfStrings(board.Properties, propertiesOfKeyValue)
		}
	}
}
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")

	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)
	output, err := builder_utils.ExecRecipe(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)

	return nil
}
func (s *SetupBuildProperties) Run(context map[string]interface{}) error {
	packages := context[constants.CTX_HARDWARE].(map[string]*types.Package)

	targetPlatform := context[constants.CTX_TARGET_PLATFORM].(*types.Platform)
	actualPlatform := context[constants.CTX_ACTUAL_PLATFORM].(*types.Platform)
	targetBoard := context[constants.CTX_TARGET_BOARD].(*types.Board)

	buildProperties := make(map[string]string)
	utils.MergeMapsOfStrings(buildProperties, actualPlatform.Properties)
	utils.MergeMapsOfStrings(buildProperties, targetPlatform.Properties)
	utils.MergeMapsOfStrings(buildProperties, targetBoard.Properties)

	if utils.MapHas(context, constants.CTX_BUILD_PATH) {
		buildProperties[constants.BUILD_PROPERTIES_BUILD_PATH] = context[constants.CTX_BUILD_PATH].(string)
	}
	if utils.MapHas(context, constants.CTX_SKETCH) {
		buildProperties[constants.BUILD_PROPERTIES_BUILD_PROJECT_NAME] = filepath.Base(context[constants.CTX_SKETCH].(*types.Sketch).MainFile.Name)
	}
	buildProperties[constants.BUILD_PROPERTIES_BUILD_ARCH] = strings.ToUpper(targetPlatform.PlatformId)

	if buildProperties[constants.BUILD_PROPERTIES_COMPILER_PATH] == constants.EMPTY_STRING {
		return utils.Errorf(context, constants.MSG_MISSING_COMPILER_PATH)
	}

	buildProperties[constants.BUILD_PROPERTIES_BUILD_CORE] = context[constants.CTX_BUILD_CORE].(string)
	buildProperties[constants.BUILD_PROPERTIES_BUILD_CORE_PATH] = filepath.Join(actualPlatform.Folder, constants.FOLDER_CORES, buildProperties[constants.BUILD_PROPERTIES_BUILD_CORE])
	buildProperties[constants.BUILD_PROPERTIES_BUILD_SYSTEM_PATH] = filepath.Join(actualPlatform.Folder, constants.FOLDER_SYSTEM)
	buildProperties[constants.BUILD_PROPERTIES_RUNTIME_PLATFORM_PATH] = actualPlatform.Folder
	buildProperties[constants.BUILD_PROPERTIES_RUNTIME_HARDWARE_PATH] = filepath.Join(actualPlatform.Folder, "..")
	buildProperties[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION].(string)
	buildProperties[constants.IDE_VERSION] = context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION].(string)
	buildProperties[constants.BUILD_PROPERTIES_RUNTIME_OS] = utils.PrettyOSName()

	variant := buildProperties[constants.BUILD_PROPERTIES_BUILD_VARIANT]
	if variant == constants.EMPTY_STRING {
		buildProperties[constants.BUILD_PROPERTIES_BUILD_VARIANT_PATH] = constants.EMPTY_STRING
	} else {
		var variantPlatform *types.Platform
		variantParts := strings.Split(variant, ":")
		if len(variantParts) > 1 {
			variantPlatform = packages[variantParts[0]].Platforms[targetPlatform.PlatformId]
			variant = variantParts[1]
		} else {
			variantPlatform = targetPlatform
		}
		buildProperties[constants.BUILD_PROPERTIES_BUILD_VARIANT_PATH] = filepath.Join(variantPlatform.Folder, constants.FOLDER_VARIANTS, variant)
	}

	tools := context[constants.CTX_TOOLS].([]*types.Tool)
	for _, tool := range tools {
		buildProperties[constants.BUILD_PROPERTIES_RUNTIME_TOOLS_PREFIX+tool.Name+constants.BUILD_PROPERTIES_RUNTIME_TOOLS_SUFFIX] = tool.Folder
		buildProperties[constants.BUILD_PROPERTIES_RUNTIME_TOOLS_PREFIX+tool.Name+"-"+tool.Version+constants.BUILD_PROPERTIES_RUNTIME_TOOLS_SUFFIX] = tool.Folder
	}

	if !utils.MapStringStringHas(buildProperties, constants.BUILD_PROPERTIES_SOFTWARE) {
		buildProperties[constants.BUILD_PROPERTIES_SOFTWARE] = DEFAULT_SOFTWARE
	}

	if utils.MapHas(context, constants.CTX_SKETCH_LOCATION) {
		sourcePath, err := filepath.Abs(context[constants.CTX_SKETCH_LOCATION].(string))
		if err != nil {
			return err
		}
		buildProperties[constants.BUILD_PROPERTIES_SOURCE_PATH] = sourcePath
	}

	context[constants.CTX_BUILD_PROPERTIES] = buildProperties

	return nil
}