public ToolFlags CopyAndBuildFlags(BSPBuilder bsp, List <string> projectFiles, string subdir, ref PropertyList configurableProperties, ReverseFileConditionBuilder.Handle reverseConditions)
        {
            List <ParsedCondition> conditions         = null;
            List <ConditionRecord> allConditions      = new List <ConditionRecord>();
            List <string>          preprocessorMacros = new List <string>();

            if (SimpleFileConditions != null)
            {
                allConditions.AddRange(SimpleFileConditions.Select(c => new ConditionRecord(c, null)));
                reverseConditions?.FlagIncomplete(ReverseFileConditionWarning.HasRegularConditions);
            }

            if (!string.IsNullOrEmpty(PreprocessorMacros))
            {
                preprocessorMacros.AddRange(PreprocessorMacros.Split(';'));
                foreach (var macro in preprocessorMacros)
                {
                    reverseConditions?.AttachPreprocessorMacro(macro, null);
                }
            }

            if (SmartFileConditions != null || SmartPreprocessorMacros != null)
            {
                PropertyGroup grp;
                if (configurableProperties == null)
                {
                    configurableProperties = new PropertyList {
                        PropertyGroups = new List <PropertyGroup>()
                    }
                }
                ;
                if (!string.IsNullOrEmpty(SmartPropertyGroup))
                {
                    string[] elements = SmartPropertyGroup.Split('|');
                    configurableProperties.PropertyGroups.Add(grp = new PropertyGroup {
                        Name = elements[1], UniqueID = elements[0]
                    });
                }
                else
                {
                    grp = configurableProperties.PropertyGroups.FirstOrDefault();
                    if (grp == null)
                    {
                        configurableProperties.PropertyGroups.Insert(0, grp = new PropertyGroup {
                        });
                    }
                }

                foreach (var str in SmartFileConditions ?? new string[0])
                {
                    var def = SmartPropertyDefinition.Parse(str, grp.UniqueID);

                    if (def.Items.Length == 1)
                    {
                        var item = def.Items[0];
                        allConditions.Add(new ConditionRecord($"{item.Key}: $${def.IDWithPrefix}$$ == {item.Value.ID}", reverseConditions?.CreateSimpleCondition(def.IDWithPrefix, item.Value.ID)));

                        reverseConditions?.AttachMinimalConfigurationValue(def.IDWithPrefix, "");

                        grp.Properties.Add(new PropertyEntry.Boolean
                        {
                            ValueForTrue = item.Value.ID,
                            Name         = def.Name,
                            UniqueID     = def.IDWithoutPrefix,
                            DefaultValue = def.IsDefaultOn != false
                        });
                    }
                    else
                    {
                        List <PropertyEntry.Enumerated.Suggestion> suggestions = new List <PropertyEntry.Enumerated.Suggestion>();
                        int?emptyIndex = null;

                        foreach (var item in def.Items)
                        {
                            if (item.Key == "")
                            {
                                // 'None' value. No conditions will trigger when this is selected.
                                emptyIndex = suggestions.Count;
                            }
                            else
                            {
                                allConditions.Add(new ConditionRecord($"{item.Key}: $${def.IDWithPrefix}$$ == {item.Value.ID}", reverseConditions?.CreateSimpleCondition(def.IDWithPrefix, item.Value.ID)));
                            }

                            suggestions.Add(new PropertyEntry.Enumerated.Suggestion {
                                InternalValue = item.Value.ID, UserFriendlyName = item.Value.Name
                            });
                        }

                        reverseConditions?.AttachMinimalConfigurationValue(def.IDWithPrefix, suggestions[emptyIndex ?? def.DefaultItemIndex].InternalValue);

                        grp.Properties.Add(new PropertyEntry.Enumerated
                        {
                            Name              = def.Name,
                            UniqueID          = def.IDWithoutPrefix,
                            SuggestionList    = suggestions.ToArray(),
                            DefaultEntryIndex = def.DefaultItemIndex
                        });
                    }
                }

                foreach (var str in SmartPreprocessorMacros ?? new string[0])
                {
                    var def = SmartPropertyDefinition.Parse(str, grp.UniqueID, 1);
                    preprocessorMacros.Add(string.Format(def.ExtraArguments[0], "$$" + def.IDWithPrefix + "$$"));

                    if (def.Items.Length == 1)
                    {
                        var item = def.Items[0];

                        if (item.Key.StartsWith("@"))
                        {
                            var prop = new PropertyEntry.String
                            {
                                Name         = def.Name,
                                UniqueID     = def.IDWithoutPrefix,
                                DefaultValue = item.Key.TrimStart('@'),
                            };

                            grp.Properties.Add(prop);

                            reverseConditions?.AttachFreeformPreprocessorMacro(def.ExtraArguments[0], def.IDWithPrefix);
                            reverseConditions?.AttachMinimalConfigurationValue(def.IDWithPrefix, prop.DefaultValue);
                        }
                        else
                        {
                            grp.Properties.Add(new PropertyEntry.Boolean
                            {
                                Name         = def.Name,
                                UniqueID     = def.IDWithoutPrefix,
                                ValueForTrue = item.Key,
                                DefaultValue = def.IsDefaultOn ?? true,
                            });

                            string expandedMacro = string.Format(def.ExtraArguments[0], item.Key);
                            reverseConditions?.AttachPreprocessorMacro(expandedMacro, reverseConditions?.CreateSimpleCondition(def.IDWithPrefix, item.Key));
                            reverseConditions?.AttachMinimalConfigurationValue(def.IDWithPrefix, "");
                        }
                    }
                    else
                    {
                        List <PropertyEntry.Enumerated.Suggestion> suggestions = new List <PropertyEntry.Enumerated.Suggestion>();

                        foreach (var item in def.Items)
                        {
                            suggestions.Add(new PropertyEntry.Enumerated.Suggestion {
                                InternalValue = item.Key, UserFriendlyName = item.Value.Name
                            });

                            string expandedMacro = string.Format(def.ExtraArguments[0], item.Key);
                            reverseConditions?.AttachPreprocessorMacro(expandedMacro, reverseConditions?.CreateSimpleCondition(def.IDWithPrefix, item.Key));
                        }

                        reverseConditions?.AttachMinimalConfigurationValue(def.IDWithPrefix, suggestions[def.DefaultItemIndex].InternalValue);

                        grp.Properties.Add(new PropertyEntry.Enumerated
                        {
                            Name              = def.Name,
                            UniqueID          = def.IDWithoutPrefix,
                            SuggestionList    = suggestions.ToArray(),
                            DefaultEntryIndex = def.DefaultItemIndex
                        });
                    }
                }
            }

            if (allConditions.Count > 0)
            {
                conditions = new List <ParsedCondition>();
                foreach (var cond in allConditions)
                {
                    int idx = cond.Condition.IndexOf(':');
                    if (idx == -1)
                    {
                        throw new Exception("Invalid simple condition format");
                    }

                    Regex     rgFile     = new Regex(cond.Condition.Substring(0, idx), RegexOptions.IgnoreCase);
                    string    rawCond    = cond.Condition.Substring(idx + 1).Trim();
                    Condition parsedCond = ParseCondition(rawCond);
                    conditions.Add(new ParsedCondition {
                        Regex = rgFile, Condition = parsedCond, ReverseConditionHandle = cond.Handle
                    });
                }
            }

            string expandedSourceFolder = SourceFolder;

            bsp.ExpandVariables(ref expandedSourceFolder);

            if (TargetFolder == null)
            {
                TargetFolder = Path.GetFileName(expandedSourceFolder);
            }
            TargetFolder = TargetFolder.Replace('\\', '/');
            if (subdir == null)
            {
                subdir = "";
            }
            string absTarget = Path.Combine(bsp.BSPRoot, subdir, TargetFolder);

            Directory.CreateDirectory(absTarget);

            string folderInsideBSPPrefix = TargetFolder;

            if (!string.IsNullOrEmpty(subdir))
            {
                folderInsideBSPPrefix = subdir + "/" + TargetFolder;
            }
            folderInsideBSPPrefix = folderInsideBSPPrefix.Replace('\\', '/');
            if (folderInsideBSPPrefix == "/")
            {
                folderInsideBSPPrefix = "";
            }
            else if (folderInsideBSPPrefix != "" && !folderInsideBSPPrefix.StartsWith("/"))
            {
                folderInsideBSPPrefix = "/" + folderInsideBSPPrefix;
            }

            var copyMasks         = new CopyFilters(FilesToCopy);
            var autoIncludes      = new CopyFilters(AutoIncludeMask);
            var potentialSymlinks = new CopyFilters(SymlinkResolutionMask);
            var projectContents   = new CopyFilters(ProjectInclusionMask);

            var filesToCopy = Directory.GetFiles(expandedSourceFolder, "*", SearchOption.AllDirectories)
                              .Where(f => !bsp.SkipHiddenFiles || (File.GetAttributes(f) & FileAttributes.Hidden) != FileAttributes.Hidden)
                              .Select(f => f.Substring(expandedSourceFolder.Length + 1))
                              .Where(f => copyMasks.IsMatch(f))
                              .ToArray();

            foreach (var dir in filesToCopy.Select(f => Path.Combine(absTarget, Path.GetDirectoryName(f))).Distinct())
            {
                Directory.CreateDirectory(dir);
            }

            List <IRenameRule> rules = new List <IRenameRule>();

            foreach (var r in (RenameRules ?? "").Split(';').Select(s => s.Trim()).Where(s => s != ""))
            {
                int idx = r.IndexOf("=>");
                rules.Add(new RenameRule {
                    OldName = r.Substring(0, idx), NewName = r.Substring(idx + 2)
                });
            }
            foreach (var r in (AdvancedRenameRules ?? "").Split(';').Where(s => s != ""))
            {
                int idx = r.IndexOf("=>");
                rules.Add(new AdvancedRenamingRule {
                    OldName = new Regex(r.Substring(0, idx), RegexOptions.IgnoreCase), NewNameFormat = r.Substring(idx + 2)
                });
            }

            var includeDirs = filesToCopy.Where(f => autoIncludes.IsMatch(f)).Select(f => Path.GetDirectoryName(f).Replace('\\', '/')).Distinct().Select(d => "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + (string.IsNullOrEmpty(d) ? "" : ("/" + d))).ToList();

            foreach (var f in filesToCopy)
            {
                string renamedRelativePath = f;
                string pathInsidePackage   = Path.Combine(subdir, TargetFolder, f);
                if (pathInsidePackage.Length > 170)
                {
                    if (!bsp.OnFilePathTooLong(pathInsidePackage))
                    {
                        continue;
                    }
                }

                string targetFile = Path.Combine(absTarget, f);
                string newName    = rules?.FirstOrDefault(r => r.Matches(f))?.Apply(targetFile);

                if (newName == null)
                {
                    if (bsp.RenamedFileTable.TryGetValue(targetFile, out newName) || bsp.RenamedFileTable.TryGetValue(targetFile.Replace('/', '\\'), out newName))
                    {
                    }
                }

                if (newName != null)
                {
                    var oldTargetFile = targetFile;
                    targetFile          = Path.Combine(Path.GetDirectoryName(targetFile), newName);
                    renamedRelativePath = Path.Combine(Path.GetDirectoryName(renamedRelativePath), newName);
                    bsp.RenamedFileTable[oldTargetFile] = newName;
                }

                if (AlreadyCopied)
                {
                    if (!File.Exists(targetFile))
                    {
                        throw new Exception(targetFile + " required by a copy job marked as 'Already Copied' does not exist");
                    }
                }
                else
                {
                    bool resolved      = false;
                    var  absSourcePath = Path.Combine(expandedSourceFolder, f);
                    if (potentialSymlinks.IsMatch(f))
                    {
                        for (; ;)
                        {
                            var contents = File.ReadAllLines(absSourcePath);
                            if (contents.Length == 1 && File.Exists(Path.Combine(Path.GetDirectoryName(absSourcePath), contents[0])))
                            {
                                absSourcePath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(absSourcePath), contents[0]));
                            }
                            else
                            {
                                break;
                            }
                        }
                    }

                    if (!resolved)
                    {
                        File.Copy(absSourcePath, targetFile, true);
                    }
                }

                File.SetAttributes(targetFile, File.GetAttributes(targetFile) & ~FileAttributes.ReadOnly);
                string encodedPath = "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + "/" + renamedRelativePath.Replace('\\', '/');

                bool includedInProject = projectContents.IsMatch(f);
                if (includedInProject)
                {
                    projectFiles.Add(encodedPath.Replace('\\', '/'));
                }

                bool foundCondition = false;

                if (conditions != null)
                {
                    foreach (var cond in conditions)
                    {
                        if (cond.Regex.IsMatch(f))
                        {
                            bsp.MatchedFileConditions.Add(new FileCondition {
                                ConditionToInclude = cond.Condition, FilePath = encodedPath
                            });
                            cond.UseCount++;

                            if (includedInProject)
                            {
                                cond.ReverseConditionHandle?.AttachFile(encodedPath);
                            }

                            foundCondition = true;
                            break;
                        }
                    }
                }

                if (!foundCondition && includedInProject)
                {
                    reverseConditions?.AttachFile(encodedPath);
                }
            }

            if (AdditionalProjectFiles != null)
            {
                foreach (var spec in AdditionalProjectFiles.Split(';'))
                {
                    string encodedPath = "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + "/" + spec;
                    projectFiles.Add(encodedPath);
                }
            }

            var unusedConditions = conditions?.Where(c => c.UseCount == 0)?.ToArray();

            if ((unusedConditions?.Length ?? 0) != 0)
            {
                throw new Exception(string.Format("Found {0} unused conditions. Please recheck your rules.", unusedConditions.Length));
            }

            if (Patches != null)
            {
                foreach (var p in Patches)
                {
                    foreach (var fn in p.FilePath.Split(';'))
                    {
                        List <string> allLines = File.ReadAllLines(Path.Combine(absTarget, fn)).ToList();
                        p.Apply(allLines);

                        string targetPath = p.TargetPath;
                        if (targetPath == null)
                        {
                            targetPath = fn;
                        }
                        Directory.CreateDirectory(Path.GetDirectoryName(Path.Combine(absTarget, targetPath)));
                        File.WriteAllLines(Path.Combine(absTarget, targetPath), allLines);
                    }
                }
            }

            if (GuardedFiles != null)
            {
                foreach (var gf in GuardedFiles)
                {
                    int    idx    = gf.IndexOf("=>");
                    Regex  rgFile = new Regex(gf.Substring(0, idx));
                    string macro  = gf.Substring(idx + 2);
                    var    fn     = Path.Combine(absTarget, filesToCopy.First(f => rgFile.IsMatch(f)));

                    List <string> lines = new List <string>(File.ReadAllLines(fn));
                    int           i     = 0;
                    //1. Find first #include
                    for (i = 0; i < lines.Count; i++)
                    {
                        if (lines[i].Trim().StartsWith("#include"))
                        {
                            break;
                        }
                    }

                    //2. Find first non-preprocessor line
                    for (; i < lines.Count; i++)
                    {
                        if (!string.IsNullOrWhiteSpace(lines[i]) && !lines[i].Trim().StartsWith("#include"))
                        {
                            break;
                        }
                    }

                    if (i == lines.Count)
                    {
                        throw new Exception("Cannot find a place to insert guard in " + fn);
                    }

                    lines.Insert(i, string.Format("#if defined({0}) && {0}", macro));
                    lines.Add("#endif //" + macro);
                    File.WriteAllLines(fn, lines);
                }
            }

            if (AdditionalIncludeDirs != null)
            {
                foreach (var dir in AdditionalIncludeDirs.Split(';'))
                {
                    var mappedDir = MapIncludeDir(absTarget, subdir, dir);
                    reverseConditions?.AttachIncludeDir(mappedDir);
                    includeDirs.Add(mappedDir);
                }
            }

            return(new ToolFlags
            {
                PreprocessorMacros = (preprocessorMacros.Count == 0) ? null : preprocessorMacros.ToArray(),
                IncludeDirectories = includeDirs.ToArray()
            });
        }
Exemple #2
0
        public ToolFlags CopyAndBuildFlags(BSPBuilder bsp, List <string> projectFiles, string subdir, ref PropertyList configurableProperties)
        {
            List <ParsedCondition> conditions    = null;
            List <string>          allConditions = new List <string>();

            if (SimpleFileConditions != null)
            {
                allConditions.AddRange(SimpleFileConditions);
            }
            if (SmartFileConditions != null)
            {
                foreach (var str in SmartFileConditions)
                {
                    int      idx    = str.IndexOf('|');
                    string   name   = str.Substring(0, idx);
                    string   id     = "com.sysprogs.bspoptions." + name.Replace(' ', '_');
                    string[] values = str.Substring(idx + 1).Split(';');

                    PropertyEntry entry;
                    if (values.Length == 1)
                    {
                        var    val = values[0];
                        string regex, value;
                        idx = val.IndexOf("=>");
                        if (idx == -1)
                        {
                            regex = val;
                            value = "1";
                        }
                        else
                        {
                            regex = val.Substring(0, idx);
                            value = val.Substring(idx + 2);
                        }

                        allConditions.Add($"{regex}: $${id}$$ == {value}");

                        entry = new PropertyEntry.Boolean {
                            ValueForTrue = value, Name = name, UniqueID = id, DefaultValue = true
                        };
                    }
                    else
                    {
                        List <PropertyEntry.Enumerated.Suggestion> suggestions = new List <PropertyEntry.Enumerated.Suggestion>();

                        foreach (var val in values)
                        {
                            idx = val.IndexOf("=>");
                            string regex = val.Substring(0, idx);
                            string value = val.Substring(idx + 2);
                            allConditions.Add($"{regex}: $${id}$$ == {value}");
                            suggestions.Add(new PropertyEntry.Enumerated.Suggestion {
                                InternalValue = value
                            });
                        }

                        entry = new PropertyEntry.Enumerated {
                            Name = name, UniqueID = id, SuggestionList = suggestions.ToArray()
                        };
                    }

                    if (configurableProperties?.PropertyGroups == null)
                    {
                        configurableProperties = new PropertyList {
                            PropertyGroups = new List <PropertyGroup>()
                        }
                    }
                    ;

                    var grp = configurableProperties.PropertyGroups.FirstOrDefault(g => g.Name == null && g.UniqueID == null);
                    if (grp == null)
                    {
                        configurableProperties.PropertyGroups.Insert(0, grp = new PropertyGroup());
                    }

                    grp.Properties.Add(entry);
                }
            }

            if (allConditions.Count > 0)
            {
                conditions = new List <ParsedCondition>();
                foreach (var cond in allConditions)
                {
                    int idx = cond.IndexOf(':');
                    if (idx == -1)
                    {
                        throw new Exception("Invalid simple condition format");
                    }

                    Regex     rgFile     = new Regex(cond.Substring(0, idx), RegexOptions.IgnoreCase);
                    string    rawCond    = cond.Substring(idx + 1).Trim();
                    Condition parsedCond = ParseCondition(rawCond);
                    conditions.Add(new ParsedCondition {
                        Regex = rgFile, Condition = parsedCond
                    });
                }
            }

            string expandedSourceFolder = SourceFolder;

            bsp.ExpandVariables(ref expandedSourceFolder);

            if (TargetFolder == null)
            {
                TargetFolder = Path.GetFileName(expandedSourceFolder);
            }
            TargetFolder = TargetFolder.Replace('\\', '/');
            if (subdir == null)
            {
                subdir = "";
            }
            string absTarget = Path.Combine(bsp.BSPRoot, subdir, TargetFolder);

            Directory.CreateDirectory(absTarget);

            string folderInsideBSPPrefix = TargetFolder;

            if (!string.IsNullOrEmpty(subdir))
            {
                folderInsideBSPPrefix = subdir + "/" + TargetFolder;
            }
            folderInsideBSPPrefix = folderInsideBSPPrefix.Replace('\\', '/');
            if (folderInsideBSPPrefix == "/")
            {
                folderInsideBSPPrefix = "";
            }
            else if (folderInsideBSPPrefix != "" && !folderInsideBSPPrefix.StartsWith("/"))
            {
                folderInsideBSPPrefix = "/" + folderInsideBSPPrefix;
            }

            var copyMasks         = new CopyFilters(FilesToCopy);
            var autoIncludes      = new CopyFilters(AutoIncludeMask);
            var potentialSymlinks = new CopyFilters(SymlinkResolutionMask);
            var projectContents   = new CopyFilters(ProjectInclusionMask);
            var filesToCopy       = Directory.GetFiles(expandedSourceFolder, "*", SearchOption.AllDirectories).Select(f => f.Substring(expandedSourceFolder.Length + 1)).Where(f => copyMasks.IsMatch(f)).ToArray();

            foreach (var dir in filesToCopy.Select(f => Path.Combine(absTarget, Path.GetDirectoryName(f))).Distinct())
            {
                Directory.CreateDirectory(dir);
            }

            List <IRenameRule> rules = new List <IRenameRule>();

            foreach (var r in (RenameRules ?? "").Split(';').Where(s => s != ""))
            {
                int idx = r.IndexOf("=>");
                rules.Add(new RenameRule {
                    OldName = r.Substring(0, idx), NewName = r.Substring(idx + 2)
                });
            }
            foreach (var r in (AdvancedRenameRules ?? "").Split(';').Where(s => s != ""))
            {
                int idx = r.IndexOf("=>");
                rules.Add(new AdvancedRenamingRule {
                    OldName = new Regex(r.Substring(0, idx), RegexOptions.IgnoreCase), NewNameFormat = r.Substring(idx + 2)
                });
            }

            var includeDirs = filesToCopy.Where(f => autoIncludes.IsMatch(f)).Select(f => Path.GetDirectoryName(f).Replace('\\', '/')).Distinct().Select(d => "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + (string.IsNullOrEmpty(d) ? "" : ("/" + d))).ToList();

            foreach (var f in filesToCopy)
            {
                string renamedRelativePath = f;
                string pathInsidePackage   = Path.Combine(subdir, TargetFolder, f);
                if (pathInsidePackage.Length > 120)
                {
                    if (!bsp.OnFilePathTooLong(pathInsidePackage))
                    {
                        continue;
                    }
                }

                string targetFile = Path.Combine(absTarget, f);
                string newName    = rules?.FirstOrDefault(r => r.Matches(f))?.Apply(targetFile);

                if (newName == null)
                {
                    if (bsp.RenamedFileTable.TryGetValue(targetFile, out newName) || bsp.RenamedFileTable.TryGetValue(targetFile.Replace('/', '\\'), out newName))
                    {
                    }
                }

                if (newName != null)
                {
                    var oldTargetFile = targetFile;
                    targetFile          = Path.Combine(Path.GetDirectoryName(targetFile), newName);
                    renamedRelativePath = Path.Combine(Path.GetDirectoryName(renamedRelativePath), newName);
                    bsp.RenamedFileTable[oldTargetFile] = newName;
                }

                if (AlreadyCopied)
                {
                    if (!File.Exists(targetFile))
                    {
                        throw new Exception(targetFile + " required by a copy job marked as 'Already Copied' does not exist");
                    }
                }
                else
                {
                    bool resolved      = false;
                    var  absSourcePath = Path.Combine(expandedSourceFolder, f);
                    if (potentialSymlinks.IsMatch(f))
                    {
                        for (; ;)
                        {
                            var contents = File.ReadAllLines(absSourcePath);
                            if (contents.Length == 1 && File.Exists(Path.Combine(Path.GetDirectoryName(absSourcePath), contents[0])))
                            {
                                absSourcePath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(absSourcePath), contents[0]));
                            }
                            else
                            {
                                break;
                            }
                        }
                    }

                    if (!resolved)
                    {
                        File.Copy(absSourcePath, targetFile, true);
                    }
                }

                File.SetAttributes(targetFile, File.GetAttributes(targetFile) & ~FileAttributes.ReadOnly);
                string encodedPath = "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + "/" + renamedRelativePath.Replace('\\', '/');

                if (projectContents.IsMatch(f))
                {
                    projectFiles.Add(encodedPath.Replace('\\', '/'));
                }

                if (conditions != null)
                {
                    foreach (var cond in conditions)
                    {
                        if (cond.Regex.IsMatch(f))
                        {
                            bsp.MatchedFileConditions.Add(new FileCondition {
                                ConditionToInclude = cond.Condition, FilePath = encodedPath
                            });
                            cond.UseCount++;
                            break;
                        }
                    }
                }
            }

            if (AdditionalProjectFiles != null)
            {
                foreach (var spec in AdditionalProjectFiles.Split(';'))
                {
                    string encodedPath = "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + "/" + spec;
                    projectFiles.Add(encodedPath);
                }
            }

            var unusedConditions = conditions?.Where(c => c.UseCount == 0)?.ToArray();

            if ((unusedConditions?.Length ?? 0) != 0)
            {
                throw new Exception(string.Format("Found {0} unused conditions. Please recheck your rules.", unusedConditions.Length));
            }

            if (Patches != null)
            {
                foreach (var p in Patches)
                {
                    foreach (var fn in p.FilePath.Split(';'))
                    {
                        List <string> allLines = File.ReadAllLines(Path.Combine(absTarget, fn)).ToList();
                        p.Apply(allLines);

                        string targetPath = p.TargetPath;
                        if (targetPath == null)
                        {
                            targetPath = fn;
                        }
                        Directory.CreateDirectory(Path.GetDirectoryName(Path.Combine(absTarget, targetPath)));
                        File.WriteAllLines(Path.Combine(absTarget, targetPath), allLines);
                    }
                }
            }

            if (GuardedFiles != null)
            {
                foreach (var gf in GuardedFiles)
                {
                    int    idx    = gf.IndexOf("=>");
                    Regex  rgFile = new Regex(gf.Substring(0, idx));
                    string macro  = gf.Substring(idx + 2);
                    var    fn     = Path.Combine(absTarget, filesToCopy.First(f => rgFile.IsMatch(f)));

                    List <string> lines = new List <string>(File.ReadAllLines(fn));
                    int           i     = 0;
                    //1. Find first #include
                    for (i = 0; i < lines.Count; i++)
                    {
                        if (lines[i].Trim().StartsWith("#include"))
                        {
                            break;
                        }
                    }

                    //2. Find first non-preprocessor line
                    for (; i < lines.Count; i++)
                    {
                        if (!string.IsNullOrWhiteSpace(lines[i]) && !lines[i].Trim().StartsWith("#include"))
                        {
                            break;
                        }
                    }

                    if (i == lines.Count)
                    {
                        throw new Exception("Cannot find a place to insert guard in " + fn);
                    }

                    lines.Insert(i, string.Format("#if defined({0}) && {0}", macro));
                    lines.Add("#endif //" + macro);
                    File.WriteAllLines(fn, lines);
                }
            }

            if (AdditionalIncludeDirs != null)
            {
                includeDirs.AddRange(AdditionalIncludeDirs.Split(';').Select(d => MapIncludeDir(absTarget, d)));
            }

            return(new ToolFlags
            {
                PreprocessorMacros = (PreprocessorMacros == null) ? null : PreprocessorMacros.Split(';'),
                IncludeDirectories = includeDirs.ToArray()
            });
        }
Exemple #3
0
        public IEnumerable <CopiedSample> CopySamples(IEnumerable <EmbeddedFramework> allFrameworks = null, IEnumerable <SysVarEntry> extraVariablesToValidateSamples = null)
        {
            if (Definition.SmartSamples != null)
            {
                foreach (var sample in Definition.SmartSamples)
                {
                    string destFolder = Path.Combine(BSP.BSPRoot, sample.DestinationFolder);
                    string sourceDir  = sample.SourceFolder;
                    BSP.ExpandVariables(ref sourceDir);

                    if (sample.CopyFilters == null)
                    {
                        PathTools.CopyDirectoryRecursive(sourceDir, destFolder);
                    }
                    else
                    {
                        var filters = new CopyFilters(sample.CopyFilters);
                        foreach (var fn in Directory.GetFiles(sourceDir, "*.*", SearchOption.AllDirectories))
                        {
                            string relPath = fn.Substring(sourceDir.Length).TrimStart('\\');
                            if (filters.IsMatch(relPath))
                            {
                                string targetPath = Path.Combine(destFolder, relPath);
                                Directory.CreateDirectory(Path.GetDirectoryName(targetPath));
                                File.Copy(fn, targetPath);
                            }
                        }
                    }

                    var sampleObj = sample.EmbeddedSample ?? XmlTools.LoadObject <EmbeddedProjectSample>(Path.Combine(destFolder, "sample.xml"));
                    if (sampleObj.RequiredFrameworks == null && allFrameworks != null)
                    {
                        sampleObj.RequiredFrameworks = allFrameworks.Where(fw => fw.DefaultEnabled).Select(fw => fw.ClassID ?? fw.ID)?.ToArray();
                    }

                    if (sample.AdditionalSources != null)
                    {
                        sampleObj.AdditionalSourcesToCopy = sample.AdditionalSources.Select(f =>
                        {
                            int idx = f.IndexOf("=>");
                            if (idx == -1)
                            {
                                return new AdditionalSourceFile {
                                    SourcePath = f
                                }
                            }
                            ;
                            else
                            {
                                return new AdditionalSourceFile {
                                    SourcePath = f.Substring(0, idx).Trim(), TargetFileName = f.Substring(idx + 2).Trim()
                                }
                            };
                        }).ToArray();

                        foreach (var f in sampleObj.AdditionalSourcesToCopy)
                        {
                            string path = f.SourcePath.Replace("$$SYS:BSP_ROOT$$", BSP.Directories.OutputDir);
                            if (!File.Exists(path))
                            {
                                if (extraVariablesToValidateSamples != null)
                                {
                                    foreach (var v in extraVariablesToValidateSamples)
                                    {
                                        path = path.Replace("$$" + v.Key + "$$", v.Value);
                                    }
                                }

                                if (!File.Exists(path))
                                {
                                    Console.WriteLine("Missing sample file: " + f.SourcePath);
                                }
                            }
                        }
                    }

                    if (sampleObj.MCUFilterRegex == null & allFrameworks != null && sampleObj.RequiredFrameworks != null)
                    {
                        string[] devices = null;

                        foreach (var fw in allFrameworks)
                        {
                            if (fw.MCUFilterRegex == null)
                            {
                                continue;
                            }

                            if (sampleObj.RequiredFrameworks.Contains(fw.ID) || sampleObj.RequiredFrameworks.Contains(fw.ClassID))
                            {
                                if (devices == null)
                                {
                                    devices = fw.MCUFilterRegex.Split('|');
                                }
                                else
                                {
                                    devices = devices.Intersect(fw.MCUFilterRegex.Split('|')).ToArray();
                                }
                            }
                        }

                        if (devices != null)
                        {
                            sampleObj.MCUFilterRegex = string.Join("|", devices);
                        }
                    }

                    if (sampleObj.MCUFilterRegex == null && sample.MCUFilterRegex != null)
                    {
                        sampleObj.MCUFilterRegex = sample.MCUFilterRegex;
                    }

                    XmlTools.SaveObject(sampleObj, Path.Combine(destFolder, "sample.xml"));
                    yield return(new CopiedSample {
                        RelativePath = sample.DestinationFolder, IsTestProjectSample = sample.IsTestProjectSample
                    });
                }
            }
        }
Exemple #4
0
        public IEnumerable <CopiedSample> CopySamples(IEnumerable <EmbeddedFramework> allFrameworks = null, IEnumerable <SysVarEntry> extraVariablesToValidateSamples = null)
        {
            if (Definition.SmartSamples != null)
            {
                foreach (var sample in Definition.SmartSamples)
                {
                    string destFolder = Path.Combine(BSP.BSPRoot, sample.DestinationFolder);
                    string sourceDir  = sample.SourceFolder;
                    BSP.ExpandVariables(ref sourceDir);

                    if (sample.CopyFilters == null)
                    {
                        PathTools.CopyDirectoryRecursive(sourceDir, destFolder);
                    }
                    else
                    {
                        var filters = new CopyFilters(sample.CopyFilters);
                        foreach (var fn in Directory.GetFiles(sourceDir, "*.*", SearchOption.AllDirectories))
                        {
                            string relPath = fn.Substring(sourceDir.Length).TrimStart('\\');
                            if (filters.IsMatch(relPath))
                            {
                                string targetPath = Path.Combine(destFolder, relPath);
                                Directory.CreateDirectory(Path.GetDirectoryName(targetPath));
                                File.Copy(fn, targetPath);
                            }
                        }
                    }

                    if (sample.AdditionalBuildTimeSources != null)
                    {
                        foreach (var src in sample.AdditionalBuildTimeSources)
                        {
                            string source = src;
                            BSP.ExpandVariables(ref source);
                            string targetPath = Path.Combine(destFolder, Path.GetFileName(source));
                            File.Copy(source, targetPath);
                        }
                    }

                    if (sample.Patches != null)
                    {
                        foreach (var p in sample.Patches)
                        {
                            foreach (var fn in p.FilePath.Split(';'))
                            {
                                List <string> allLines = File.ReadAllLines(Path.Combine(destFolder, fn)).ToList();
                                p.Apply(allLines);
                                File.WriteAllLines(Path.Combine(destFolder, fn), allLines);
                            }
                        }
                    }

                    var sampleObj = sample.EmbeddedSample ?? XmlTools.LoadObject <EmbeddedProjectSample>(Path.Combine(destFolder, "sample.xml"));
                    if (sampleObj.RequiredFrameworks == null && allFrameworks != null)
                    {
                        sampleObj.RequiredFrameworks = allFrameworks.Where(fw => fw.DefaultEnabled).Select(fw => fw.ClassID ?? fw.ID)?.ToArray();
                    }

                    if (sample.AdditionalSources != null)
                    {
                        sampleObj.AdditionalSourcesToCopy = sample.AdditionalSources.Select(f =>
                        {
                            int idx = f.IndexOf("=>");
                            if (idx == -1)
                            {
                                return new AdditionalSourceFile {
                                    SourcePath = f
                                }
                            }
                            ;
                            else
                            {
                                return new AdditionalSourceFile {
                                    SourcePath = f.Substring(0, idx).Trim(), TargetFileName = f.Substring(idx + 2).Trim()
                                }
                            };
                        }).ToArray();


                        for (int i = 0; i < sampleObj.AdditionalSourcesToCopy.Length; i++)
                        {
                            string path = sampleObj.AdditionalSourcesToCopy[i].SourcePath.Replace("$$SYS:BSP_ROOT$$", BSP.Directories.OutputDir);
                            if (!File.Exists(path))
                            {
                                if (extraVariablesToValidateSamples != null)
                                {
                                    foreach (var v in extraVariablesToValidateSamples)
                                    {
                                        path = path.Replace("$$" + v.Key + "$$", v.Value);
                                    }
                                }

                                if (!File.Exists(path))
                                {
                                    var args = new MissingSampleFileArgs {
                                        UnexpandedPath = sampleObj.AdditionalSourcesToCopy[i].SourcePath, ExpandedPath = path
                                    };

                                    OnMissingSampleFile(args);
                                    if (args.SubstitutePath != null)
                                    {
                                        if (args.SubstitutePath.StartsWith(BSP.BSPRoot))
                                        {
                                            args.SubstitutePath = "$$SYS:BSP_ROOT$$" + args.SubstitutePath.Substring(BSP.BSPRoot.Length).Replace('\\', '/');
                                        }
                                        else if (args.SubstitutePath.StartsWith("$$"))
                                        {
                                            //Already encoded
                                        }
                                        else
                                        {
                                            throw new Exception("Invalid substitute path: " + args.SubstitutePath);
                                        }

                                        sampleObj.AdditionalSourcesToCopy[i].SourcePath = args.SubstitutePath;
                                    }
                                }
                            }
                        }
                    }

                    if (sampleObj.MCUFilterRegex == null & allFrameworks != null && sampleObj.RequiredFrameworks != null)
                    {
                        string[] devices = null;

                        foreach (var fw in allFrameworks)
                        {
                            if (fw.MCUFilterRegex == null)
                            {
                                continue;
                            }

                            if (sampleObj.RequiredFrameworks.Contains(fw.ID) || sampleObj.RequiredFrameworks.Contains(fw.ClassID))
                            {
                                if (devices == null)
                                {
                                    devices = fw.MCUFilterRegex.Split('|');
                                }
                                else
                                {
                                    devices = devices.Intersect(fw.MCUFilterRegex.Split('|')).ToArray();
                                }
                            }
                        }

                        if (devices != null)
                        {
                            sampleObj.MCUFilterRegex = string.Join("|", devices);
                        }
                    }

                    if (sampleObj.MCUFilterRegex == null && sample.MCUFilterRegex != null)
                    {
                        sampleObj.MCUFilterRegex = sample.MCUFilterRegex;
                    }

                    XmlTools.SaveObject(sampleObj, Path.Combine(destFolder, "sample.xml"));
                    yield return(new CopiedSample {
                        RelativePath = sample.DestinationFolder, IsTestProjectSample = sample.IsTestProjectSample
                    });
                }
            }
        }
        public ToolFlags CopyAndBuildFlags(BSPBuilder bsp, List <string> projectFiles, string subdir)
        {
            List <ParsedCondition> conditions = null;

            if (SimpleFileConditions != null)
            {
                conditions = new List <ParsedCondition>();
                foreach (var cond in SimpleFileConditions)
                {
                    int idx = cond.IndexOf(':');
                    if (idx == -1)
                    {
                        throw new Exception("Invalid simple condition format");
                    }

                    Regex     rgFile     = new Regex(cond.Substring(0, idx), RegexOptions.IgnoreCase);
                    string    rawCond    = cond.Substring(idx + 1).Trim();
                    Condition parsedCond = ParseCondition(rawCond);
                    conditions.Add(new ParsedCondition {
                        Regex = rgFile, Condition = parsedCond
                    });
                }
            }

            string expandedSourceFolder = SourceFolder;

            bsp.ExpandVariables(ref expandedSourceFolder);

            if (TargetFolder == null)
            {
                TargetFolder = Path.GetFileName(expandedSourceFolder);
            }
            TargetFolder = TargetFolder.Replace('\\', '/');
            if (subdir == null)
            {
                subdir = "";
            }
            string absTarget = Path.Combine(bsp.BSPRoot, subdir, TargetFolder);

            Directory.CreateDirectory(absTarget);

            string folderInsideBSPPrefix = TargetFolder;

            if (!string.IsNullOrEmpty(subdir))
            {
                folderInsideBSPPrefix = subdir + "/" + TargetFolder;
            }
            folderInsideBSPPrefix = folderInsideBSPPrefix.Replace('\\', '/');
            if (folderInsideBSPPrefix == "/")
            {
                folderInsideBSPPrefix = "";
            }
            else if (folderInsideBSPPrefix != "" && !folderInsideBSPPrefix.StartsWith("/"))
            {
                folderInsideBSPPrefix = "/" + folderInsideBSPPrefix;
            }

            var copyMasks       = new CopyFilters(FilesToCopy);
            var autoIncludes    = new CopyFilters(AutoIncludeMask);
            var projectContents = new CopyFilters(ProjectInclusionMask);
            var filesToCopy     = Directory.GetFiles(expandedSourceFolder, "*", SearchOption.AllDirectories).Select(f => f.Substring(expandedSourceFolder.Length + 1)).Where(f => copyMasks.IsMatch(f)).ToArray();

            foreach (var dir in filesToCopy.Select(f => Path.Combine(absTarget, Path.GetDirectoryName(f))).Distinct())
            {
                Directory.CreateDirectory(dir);
            }

            RenameRule[] rules = null;
            if (RenameRules != null)
            {
                rules = RenameRules.Split(';').Select(r =>
                {
                    int idx = r.IndexOf("=>");
                    return(new RenameRule {
                        OldName = r.Substring(0, idx), NewName = r.Substring(idx + 2)
                    });
                }).ToArray();
            }

            var includeDirs = filesToCopy.Where(f => autoIncludes.IsMatch(f)).Select(f => Path.GetDirectoryName(f).Replace('\\', '/')).Distinct().Select(d => "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + (string.IsNullOrEmpty(d) ? "" : ("/" + d))).ToList();

            foreach (var f in filesToCopy)
            {
                string renamedRelativePath = f;
                string pathInsidePackage   = Path.Combine(subdir, TargetFolder, f);
                if (pathInsidePackage.Length > 120)
                {
                    if (!bsp.OnFilePathTooLong(pathInsidePackage))
                    {
                        continue;
                    }
                }

                string targetFile = Path.Combine(absTarget, f);
                var    rule       = rules?.FirstOrDefault(r => r.Matches(f));
                if (rule != null)
                {
                    targetFile          = Path.Combine(Path.GetDirectoryName(targetFile), rule.NewName);
                    renamedRelativePath = Path.Combine(Path.GetDirectoryName(renamedRelativePath), rule.NewName);
                }

                if (AlreadyCopied)
                {
                    if (!File.Exists(targetFile))
                    {
                        throw new Exception(targetFile + " required by a copy job marked as 'Already Copied' does not exist");
                    }
                }
                else
                {
                    File.Copy(Path.Combine(expandedSourceFolder, f), targetFile, true);
                }

                File.SetAttributes(targetFile, File.GetAttributes(targetFile) & ~FileAttributes.ReadOnly);
                string encodedPath = "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + "/" + renamedRelativePath.Replace('\\', '/');

                if (projectContents.IsMatch(f))
                {
                    projectFiles.Add(encodedPath.Replace('\\', '/'));
                }

                if (conditions != null)
                {
                    foreach (var cond in conditions)
                    {
                        if (cond.Regex.IsMatch(f))
                        {
                            bsp.MatchedFileConditions.Add(new FileCondition {
                                ConditionToInclude = cond.Condition, FilePath = encodedPath
                            });
                            cond.UseCount++;
                            break;
                        }
                    }
                }
            }

            if (AdditionalProjectFiles != null)
            {
                foreach (var spec in AdditionalProjectFiles.Split(';'))
                {
                    string encodedPath = "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + "/" + spec;
                    projectFiles.Add(encodedPath);
                }
            }

            var unusedConditions = conditions?.Where(c => c.UseCount == 0)?.ToArray();

            if ((unusedConditions?.Length ?? 0) != 0)
            {
                throw new Exception(string.Format("Found {0} unused conditions. Please recheck your rules.", unusedConditions.Length));
            }

            if (Patches != null)
            {
                foreach (var p in Patches)
                {
                    foreach (var fn in p.FilePath.Split(';'))
                    {
                        List <string> allLines = File.ReadAllLines(Path.Combine(absTarget, fn)).ToList();
                        p.Apply(allLines);

                        string targetPath = p.TargetPath;
                        if (targetPath == null)
                        {
                            targetPath = fn;
                        }
                        Directory.CreateDirectory(Path.GetDirectoryName(Path.Combine(absTarget, targetPath)));
                        File.WriteAllLines(Path.Combine(absTarget, targetPath), allLines);
                    }
                }
            }

            if (GuardedFiles != null)
            {
                foreach (var gf in GuardedFiles)
                {
                    int    idx    = gf.IndexOf("=>");
                    Regex  rgFile = new Regex(gf.Substring(0, idx));
                    string macro  = gf.Substring(idx + 2);
                    var    fn     = Path.Combine(absTarget, filesToCopy.First(f => rgFile.IsMatch(f)));

                    List <string> lines = new List <string>(File.ReadAllLines(fn));
                    int           i     = 0;
                    //1. Find first #include
                    for (i = 0; i < lines.Count; i++)
                    {
                        if (lines[i].Trim().StartsWith("#include"))
                        {
                            break;
                        }
                    }

                    //2. Find first non-preprocessor line
                    for (; i < lines.Count; i++)
                    {
                        if (!string.IsNullOrWhiteSpace(lines[i]) && !lines[i].Trim().StartsWith("#include"))
                        {
                            break;
                        }
                    }

                    if (i == lines.Count)
                    {
                        throw new Exception("Cannot find a place to insert guard in " + fn);
                    }

                    lines.Insert(i, string.Format("#if defined({0}) && {0}", macro));
                    lines.Add("#endif //" + macro);
                    File.WriteAllLines(fn, lines);
                }
            }

            if (AdditionalIncludeDirs != null)
            {
                includeDirs.AddRange(AdditionalIncludeDirs.Split(';'));
            }

            return(new ToolFlags
            {
                PreprocessorMacros = (PreprocessorMacros == null) ? null : PreprocessorMacros.Split(';'),
                IncludeDirectories = includeDirs.ToArray()
            });
        }
Exemple #6
0
        public string TargetFolder; //if null, defaults to (BSP)\(name of source folder), otherwise specifies relative path within the family subdirectory

        #endregion Fields

        #region Methods

        public ToolFlags CopyAndBuildFlags(BSPBuilder bsp, List<string> projectFiles, string subdir)
        {
            List<ParsedCondition> conditions = null;
            if (SimpleFileConditions != null)
            {
                conditions = new List<ParsedCondition>();
                foreach (var cond in SimpleFileConditions)
                {
                    int idx = cond.IndexOf(':');
                    if (idx == -1)
                        throw new Exception("Invalid simple condition format");

                    Regex rgFile = new Regex(cond.Substring(0, idx), RegexOptions.IgnoreCase);
                    string rawCond = cond.Substring(idx + 1).Trim();
                    Condition parsedCond = ParseCondition(rawCond);
                    conditions.Add(new ParsedCondition { Regex = rgFile, Condition = parsedCond });
                }
            }

            string expandedSourceFolder = SourceFolder;
            bsp.ExpandVariables(ref expandedSourceFolder);

            if (TargetFolder == null)
                TargetFolder = Path.GetFileName(expandedSourceFolder);
            TargetFolder = TargetFolder.Replace('\\', '/');
            if (subdir == null)
                subdir = "";
            string absTarget = Path.Combine(bsp.BSPRoot, subdir, TargetFolder);
            Directory.CreateDirectory(absTarget);

            string folderInsideBSPPrefix = TargetFolder;
            if (!string.IsNullOrEmpty(subdir))
                folderInsideBSPPrefix = subdir + "/" + TargetFolder;
            folderInsideBSPPrefix = folderInsideBSPPrefix.Replace('\\', '/');
            if (folderInsideBSPPrefix == "/")
                folderInsideBSPPrefix = "";
            else if (folderInsideBSPPrefix != "" && !folderInsideBSPPrefix.StartsWith("/"))
                folderInsideBSPPrefix = "/" + folderInsideBSPPrefix;

            var copyMasks = new CopyFilters(FilesToCopy);
            var autoIncludes = new CopyFilters(AutoIncludeMask);
            var projectContents = new CopyFilters(ProjectInclusionMask);
            var filesToCopy = Directory.GetFiles(expandedSourceFolder, "*", SearchOption.AllDirectories).Select(f => f.Substring(expandedSourceFolder.Length + 1)).Where(f => copyMasks.IsMatch(f)).ToArray();
            foreach (var dir in filesToCopy.Select(f => Path.Combine(absTarget, Path.GetDirectoryName(f))).Distinct())
                Directory.CreateDirectory(dir);

            RenameRule[] rules = null;
            if (RenameRules != null)
                rules = RenameRules.Split(';').Select(r =>
                {
                    int idx = r.IndexOf("=>");
                    return new RenameRule { OldName = r.Substring(0, idx), NewName = r.Substring(idx + 2) };
                }).ToArray();

            var includeDirs = filesToCopy.Where(f => autoIncludes.IsMatch(f)).Select(f => Path.GetDirectoryName(f).Replace('\\', '/')).Distinct().Select(d => "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + (string.IsNullOrEmpty(d) ? "" : ("/" + d))).ToList();
            foreach (var f in filesToCopy)
            {
                string renamedRelativePath = f;
                string pathInsidePackage = Path.Combine(subdir, TargetFolder, f);
                if (pathInsidePackage.Length > 120)
                {
                    if (!bsp.OnFilePathTooLong(pathInsidePackage))
                        continue;
                }

                string targetFile = Path.Combine(absTarget, f);
                var rule = rules?.FirstOrDefault(r => r.Matches(f));
                if (rule != null)
                {
                    targetFile = Path.Combine(Path.GetDirectoryName(targetFile), rule.NewName);
                    renamedRelativePath = Path.Combine(Path.GetDirectoryName(renamedRelativePath), rule.NewName);
                }

                if (AlreadyCopied)
                {
                    if (!File.Exists(targetFile))
                        throw new Exception(targetFile + " required by a copy job marked as 'Already Copied' does not exist");
                }
                else
                    File.Copy(Path.Combine(expandedSourceFolder, f), targetFile, true);

                File.SetAttributes(targetFile, File.GetAttributes(targetFile) & ~FileAttributes.ReadOnly);
                string encodedPath = "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + "/" + renamedRelativePath.Replace('\\', '/');

                if (projectContents.IsMatch(f))
                    projectFiles.Add(encodedPath.Replace('\\', '/'));

                if (conditions != null)
                {
                    foreach (var cond in conditions)
                        if (cond.Regex.IsMatch(f))
                        {
                            bsp.MatchedFileConditions.Add(new FileCondition { ConditionToInclude = cond.Condition, FilePath = encodedPath });
                            cond.UseCount++;
                            break;
                        }
                }
            }

            var unusedConditions = conditions?.Where(c => c.UseCount == 0)?.ToArray();
            if ((unusedConditions?.Length ?? 0) != 0)
                throw new Exception(string.Format("Found {0} unused conditions. Please recheck your rules.", unusedConditions.Length));

            if (Patches != null)
                foreach(var p in Patches)
                {
                    List<string> allLines = File.ReadAllLines(Path.Combine(absTarget, p.FilePath)).ToList();
                    p.Apply(allLines);

                    string targetPath = p.TargetPath;
                    if (targetPath == null)
                        targetPath = p.FilePath;
                    Directory.CreateDirectory(Path.GetDirectoryName(Path.Combine(absTarget, targetPath)));
                    File.WriteAllLines(Path.Combine(absTarget, targetPath), allLines);
                }

            if (GuardedFiles != null)
                foreach (var gf in GuardedFiles)
                {
                    int idx = gf.IndexOf("=>");
                    Regex rgFile = new Regex(gf.Substring(0, idx));
                    string macro = gf.Substring(idx + 2);
                    var fn = Path.Combine(absTarget, filesToCopy.First(f => rgFile.IsMatch(f)));

                    List<string> lines = new List<string>(File.ReadAllLines(fn));
                    int i = 0;
                    //1. Find first #include
                    for (i = 0; i < lines.Count; i++)
                        if (lines[i].Trim().StartsWith("#include"))
                            break;

                    //2. Find first non-preprocessor line
                    for (; i < lines.Count; i++)
                        if (!string.IsNullOrWhiteSpace(lines[i]) && !lines[i].Trim().StartsWith("#include"))
                            break;

                    if (i == lines.Count)
                        throw new Exception("Cannot find a place to insert guard in " + fn);

                    lines.Insert(i, string.Format("#if defined({0}) && {0}", macro));
                    lines.Add("#endif //" + macro);
                    File.WriteAllLines(fn, lines);
                }

            if (AdditionalIncludeDirs != null)
                includeDirs.AddRange(AdditionalIncludeDirs.Split(';'));

            return new ToolFlags
            {
                PreprocessorMacros = (PreprocessorMacros == null) ? null : PreprocessorMacros.Split(';'),
                IncludeDirectories = includeDirs.ToArray()
            };
        }