예제 #1
0
        private static string FindAndAddFileIfMissing(Dictionary <string, IGrouping <string, FlatFileReference> > fileListsByName, string fileName, string baseDir, ImportedExternalProject.ConstructedVirtualDirectory directoryToAddFile, ref string[] includeDirs)
        {
            if (fileListsByName.TryGetValue(fileName, out var group))
            {
                return(group.FirstOrDefault().File?.FullPath);
            }

            if (!Directory.Exists(baseDir))
            {
                return(null);
            }

            string foundFile = Directory.GetFiles(baseDir, fileName, SearchOption.AllDirectories).FirstOrDefault();

            if (foundFile != null)
            {
                directoryToAddFile.AddFile(foundFile, false);
                includeDirs = includeDirs.Concat(new[] { Path.GetDirectoryName(foundFile) }).ToArray();
            }

            return(foundFile);
        }
예제 #2
0
        private void ImportProjectFolderRecursively(XmlElement projectOrFolder,
                                                    ImportedExternalProject.ConstructedVirtualDirectory constructedDir,
                                                    ProjectImportParameters parameters,
                                                    IVariableExpander expander,
                                                    IProjectImportService service)
        {
            foreach (var el in projectOrFolder.ChildNodes.OfType <XmlElement>())
            {
                if (el.Name == "file")
                {
                    string relPath = ExpandVariables(el.GetAttribute("file_name"), expander, service);
                    if (!string.IsNullOrEmpty(relPath) && !relPath.EndsWith(".vec"))
                    {
                        string fullPath = Path.Combine(Path.GetDirectoryName(parameters.ProjectFile), relPath);
                        constructedDir.AddFile(fullPath, relPath.EndsWith(".h", StringComparison.InvariantCultureIgnoreCase));
                    }
                }
                else if (el.Name == "folder")
                {
                    string name = el.GetAttribute("Name");
                    if (string.IsNullOrEmpty(name))
                    {
                        name = "Subfolder";
                    }

                    if (name == "Source Files" || name == "Header Files")
                    {
                        //Visual Studio already provides filters for source/header files, so we don't need to specify them explicitly
                        ImportProjectFolderRecursively(el, constructedDir, parameters, expander, service);
                    }
                    else
                    {
                        ImportProjectFolderRecursively(el, constructedDir.ProvideSudirectory(name), parameters, expander, service);
                    }
                }
            }
        }
예제 #3
0
        public ImportedExternalProject ImportProject(ProjectImportParameters parameters, IProjectImportService service)
        {
            XmlDocument xml = new XmlDocument();

            xml.Load(parameters.ProjectFile);

            string deviceName = (xml.SelectSingleNode("package/generators/generator/select/@Dname") as XmlAttribute)?.Value;

            if (deviceName == null)
            {
                throw new Exception("Failed to extract the device name from " + deviceName);
            }

            HashSet <string> allHeaderDirs = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase);
            string           baseDir       = Path.GetDirectoryName(parameters.ProjectFile);

            ImportedExternalProject.ConstructedVirtualDirectory rootDir = new ImportedExternalProject.ConstructedVirtualDirectory();

            foreach (var file in xml.SelectNodes("package/generators/generator/project_files/file").OfType <XmlElement>())
            {
                string category = file.GetAttribute("category");
                string name     = file.GetAttribute("name");

                if (category == "header")
                {
                    allHeaderDirs.Add(Path.GetDirectoryName(name));
                }

                rootDir.AddFile(Path.Combine(baseDir, name), category == "header");
            }

            bool hasFreeRTOS = false;

            foreach (var component in xml.SelectNodes("package/components/component").OfType <XmlElement>())
            {
                string group    = component.GetAttribute("Cgroup");
                string subGroup = component.GetAttribute("Csub");
                if (subGroup == "FREERTOS")
                {
                    hasFreeRTOS = true;
                }
                foreach (var file in component.SelectNodes("files/file").OfType <XmlElement>())
                {
                    string category     = file.GetAttribute("category");
                    string relativePath = file.GetAttribute("name");

                    string condition = file.GetAttribute("condition");
                    if (!string.IsNullOrEmpty(condition))
                    {
                        if (condition == "FreeRTOS")
                        {
                            if (!hasFreeRTOS)
                            {
                                continue;
                            }
                        }
                        else if (condition != "GCC Toolchain")
                        {
                            continue;   //This is a IAR-only or Keil-only file
                        }
                    }

                    int    idx = relativePath.LastIndexOfAny(new[] { '\\', '/' });
                    string name, dir;
                    if (idx == -1)
                    {
                        name = relativePath;
                        dir  = "";
                    }
                    else
                    {
                        name = relativePath.Substring(idx + 1);
                        dir  = relativePath.Substring(0, idx);
                    }

                    if (category == "sourceAsm" && name.StartsWith("startup_", StringComparison.InvariantCultureIgnoreCase))
                    {
                        continue;   //VisualGDB provides its own startup files for STM32 devices that are compatible with STM32CubeMX-generated files
                    }
                    if (category == "header" && dir != "")
                    {
                        allHeaderDirs.Add(dir);
                    }

                    string path = group;
                    if (!string.IsNullOrEmpty(subGroup))
                    {
                        path += "/" + subGroup;
                    }

                    if (relativePath.Contains("*"))
                    {
                        string physicalDir = Path.Combine(baseDir, dir);
                        if (Directory.Exists(physicalDir))
                        {
                            foreach (var fn in Directory.GetFiles(physicalDir, name))
                            {
                                rootDir.ProvideSudirectory(path).AddFile(fn, category == "header");
                            }
                        }
                    }
                    else
                    {
                        rootDir.ProvideSudirectory(path).AddFile(Path.Combine(baseDir, relativePath), category == "header");
                    }
                }
            }

            List <string> macros = new List <string> {
                "$$com.sysprogs.bspoptions.primary_memory$$_layout", "$$com.sysprogs.stm32.hal_device_family$$"
            };

            string[] includeDirs = allHeaderDirs.Select(d => Path.Combine(baseDir, d)).ToArray();

            PropertyDictionary2 mcuConfiguration = null;

            if (hasFreeRTOS)
            {
                macros.Add("USE_FREERTOS");
                ApplyFreeRTOSFixes(rootDir, ref includeDirs, ref mcuConfiguration);
            }

            Dictionary <string, string> temporaryExistingFileCollection = null;

            FixInvalidPathsRecursively(rootDir, baseDir, ref temporaryExistingFileCollection);

            deviceName = deviceName.TrimEnd('x');
            deviceName = deviceName.Substring(0, deviceName.Length - 1);

            return(new ImportedExternalProject
            {
                DeviceNameMask = new Regex(deviceName.Replace("x", ".*") + ".*"),
                OriginalProjectFile = parameters.ProjectFile,
                RootDirectory = rootDir,
                GNUTargetID = "arm-eabi",
                ReferencedFrameworks = new string[0],   //Unless this is explicitly specified, VisualGDB will try to reference the default frameworks (STM32 HAL) that will conflict with the STM32CubeMX-generated files.

                MCUConfiguration = mcuConfiguration,

                Configurations = new[]
                {
                    new ImportedExternalProject.ImportedConfiguration
                    {
                        Settings = new ImportedExternalProject.InvariantProjectBuildSettings
                        {
                            IncludeDirectories = includeDirs,
                            PreprocessorMacros = macros.ToArray()
                        }
                    }
                }
            });
        }
예제 #4
0
        public ImportedExternalProject ImportProject(ProjectImportParameters parameters, IProjectImportService service)
        {
            Regex  rgLine      = new Regex("(PROJECT|OBJECTS|INCLUDE_PATHS|LIBRARY_PATHS|LIBRARIES|LINKER_SCRIPT|C_FLAGS|CXX_FLAGS|ASM_FLAGS|LD_FLAGS|LD_SYS_LIBS|CC)[ \t]*(:=|\\+=|=|\\?=|=)[ \t]*(.*)$");
            string projectName = null;
            string baseDir     = Path.GetDirectoryName(parameters.ProjectFile);

            ConstructedVirtualDirectory     rootDir  = new ConstructedVirtualDirectory();
            ConstructedProjectBuildSettings settings = new ConstructedProjectBuildSettings();


            foreach (var line in File.ReadAllLines(parameters.ProjectFile))
            {
                var m = rgLine.Match(line);
                if (!m.Success)
                {
                    continue;
                }

                string value = m.Groups[3].Value.Trim();
                if (value == "")
                {
                    continue;
                }


                switch (m.Groups[1].Value)
                {
                case "PROJECT":
                    projectName = value;
                    break;

                case "OBJECTS":
                    string relPath = value;
                    if (relPath.StartsWith("./"))
                    {
                        relPath = relPath.Substring(2);
                    }
                    string fullPath = Path.GetFullPath(Path.Combine(baseDir, relPath));
                    foreach (var extension in new[] { ".c", ".cpp", ".s" })
                    {
                        string source = Path.ChangeExtension(fullPath, extension);
                        if (File.Exists(source))
                        {
                            ImportedExternalProject.ConstructedVirtualDirectory subdir = rootDir;
                            if (relPath.Contains('/'))
                            {
                                subdir = rootDir.ProvideSudirectory(Path.GetDirectoryName(relPath));
                            }
                            subdir.AddFile(source, false).ObjectFilePath = relPath;
                        }
                    }
                    break;

                case "INCLUDE_PATHS":
                    ProcessPath(service, settings.IncludeDirectories, "-I../", "include path", value, baseDir);
                    break;

                case "LIBRARY_PATHS":
                    ProcessPath(service, settings.LibraryDirectories, "-L../", "library path", value, baseDir);
                    break;

                case "LIBRARIES":
                    settings.ExtraLDFLAGS.Add(value);
                    break;

                case "LINKER_SCRIPT":
                    if (!value.StartsWith("../"))
                    {
                        service.Logger.LogLine("Warning: unsupported linker script: " + value);
                    }
                    else
                    {
                        settings.LinkerScript = Path.GetFullPath(Path.Combine(baseDir, value.Substring(3)));
                    }
                    break;

                case "C_FLAGS":
                    if (value.StartsWith("-std="))
                    {
                        settings.CStandard = value.Substring(5);
                    }
                    break;

                case "CXX_FLAGS":
                    if (value.StartsWith("-std="))
                    {
                        settings.CXXStandard = value.Substring(5);
                    }
                    else if (value == "-fno-rtti" || value == "-fno-exceptions")
                    {
                        continue;
                    }
                    else if (value.StartsWith("-D"))
                    {
                        settings.PreprocessorMacros.Add(value.Substring(2));
                    }
                    else
                    {
                        settings.ExtraCFLAGS.Add(value);
                    }
                    break;

                case "LD_FLAGS":
                    settings.ExtraLDFLAGS.Add(value);
                    break;

                case "LD_SYS_LIBS":
                    foreach (var lib in value.Split(' '))
                    {
                        if (lib.StartsWith("-l"))
                        {
                            settings.LibraryNames.Add(lib.Substring(2));
                        }
                    }
                    break;

                case "CC":
                    int skip = 0;
                    foreach (var flag in value.Split(' ').Select(f => f.Trim('\'')).Skip(1))
                    {
                        if (skip > 0)
                        {
                            skip--;
                            continue;
                        }
                        if (flag.StartsWith("-std") || flag.StartsWith("-g") || flag.StartsWith("-O"))
                        {
                            continue;
                        }

                        switch (flag)
                        {
                        case "-c":
                        case "-ffunction-sections":
                        case "-fdata-sections":
                            continue;
                        }

                        settings.ExtraCFLAGS.Add(flag);
                    }
                    break;
                }
            }

            return(new ImportedExternalProject
            {
                OriginalProjectFile = parameters.ProjectFile,
                ProjectName = projectName,
                GNUTargetID = "arm-eabi",
                Configurations = new []
                {
                    new ImportedConfiguration
                    {
                        Settings = settings.ToProjectBuildSettings()
                    }
                },
                RootDirectory = rootDir,
                ReferencedFrameworks = new string[0]
            });
        }
예제 #5
0
        public ImportedExternalProject ImportProject(ProjectImportParameters parameters, IProjectImportService service)
        {
            Dictionary <string, string> systemDirectories = new Dictionary <string, string>();

            var key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Rowley Associates Limited\CrossWorks for ARM\Installer");

            service.Logger.LogLine("Detecting CrossWorks directory...");
            string crossWorksDir = null;

            if (key != null)
            {
                foreach (var kn in key.GetSubKeyNames().OrderByDescending(k => k))
                {
                    service.Logger.LogLine($"Checking {kn}...");

                    using (var subkey = key.OpenSubKey(kn + @"\OrganizationDefaults"))
                    {
                        var destDir = subkey?.GetValue("DestDir") as string;
                        if (destDir != null && Directory.Exists(destDir))
                        {
                            service.Logger.LogLine($"Found {destDir}");
                            systemDirectories["StudioDir"] = crossWorksDir = destDir;
                            break;
                        }
                    }
                }
            }

            service.Logger.LogLine("Detecting CrossWorks AppData directory...");

            var appDataDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Rowley Associates Limited\CrossWorks for ARM");

            foreach (var subdir in Directory.GetDirectories(appDataDir).OrderByDescending(d => d))
            {
                string packagesDir = Path.Combine(subdir, "packages");
                service.Logger.LogLine($"Trying {subdir}...");
                if (Directory.Exists(packagesDir))
                {
                    service.Logger.LogLine($"Found {packagesDir}");
                    systemDirectories["TargetsDir"]  = packagesDir + @"\targets";
                    systemDirectories["PackagesDir"] = packagesDir;
                    break;
                }
            }

            systemDirectories["ProjectDir"] = Path.GetDirectoryName(parameters.ProjectFile);
            systemDirectories["LibExt"]     = "";

            XmlDocument xml = new XmlDocument();

            xml.Load(parameters.ProjectFile);

            var project      = xml.DocumentElement.SelectSingleNode("project") as XmlElement ?? throw new Exception("Could not find the project element");
            var commonConfig = project.SelectSingleNode("configuration[@Name='Common']") as XmlElement ?? throw new Exception("Could not find the common configuration element");

            string deviceName = commonConfig.GetAttribute("Target");

            if (string.IsNullOrEmpty(deviceName))
            {
                throw new Exception("Target name is unspecified");
            }

            string[] internalMacros = commonConfig.GetAttribute("macros")?.Split(';');
            string   vectorFile     = null;

            foreach (var im in internalMacros ?? new string[0])
            {
                int idx = im.IndexOf('=');
                if (idx != -1)
                {
                    string mk = im.Substring(0, idx).Trim();
                    string mv = im.Substring(idx + 1).Trim();
                    systemDirectories[mk] = mv;
                    if (mk == "DeviceVectorsFile")
                    {
                        vectorFile = mv;
                    }
                }
            }

            string[] macros      = commonConfig.GetAttribute("c_preprocessor_definitions")?.Split(';');
            string[] includeDirs = (commonConfig.GetAttribute("c_system_include_directories") + ";" + commonConfig.GetAttribute("c_user_include_directories"))?.Split(';');
            if (crossWorksDir != null)
            {
                includeDirs = includeDirs.Concat(new[] { crossWorksDir + "/include" }).ToArray();
            }

            string[] additionalLinkerInputs = commonConfig.GetAttribute("linker_additional_files")?.Split(';');

            macros = macros.Concat(new[] { "__CROSSWORKS_ARM", "STARTUP_FROM_RESET" }).ToArray();
            if (vectorFile != null)
            {
                macros = macros.Concat(new[] { $"__VECTORS=\"{vectorFile}\"" }).ToArray();
            }

            string frequency = commonConfig.GetAttribute("oscillator_frequency");

            if (frequency?.EndsWith("MHz") == true && int.TryParse(frequency.Substring(0, frequency.Length - 3), out int frequencyInMhz))
            {
                macros = macros.Concat(new[] { "OSCILLATOR_CLOCK_FREQUENCY=" + (frequencyInMhz * 1000000) }).ToArray();
            }

            ImportedExternalProject.ConstructedVirtualDirectory rootDir = new ImportedExternalProject.ConstructedVirtualDirectory();

            var expander = service.CreateVariableExpander(systemDirectories, VariableExpansionSyntax.Makefile);

            SettingsFromBuiltProject extraSettings = RetrieveSettingsFromBuiltProject(parameters, service);

            if (extraSettings.AdditionalInputs != null)
            {
                foreach (var input in extraSettings.AdditionalInputs)
                {
                    rootDir.AddFile(input, false);
                }
            }

            foreach (var lib in additionalLinkerInputs)
            {
                var mappedPath = ExpandVariables(lib, expander, service);
                if (!string.IsNullOrEmpty(mappedPath))
                {
                    rootDir.AddFile(mappedPath, false);
                }
            }

            ImportProjectFolderRecursively(project, rootDir, parameters, expander, service);

            return(new ImportedExternalProject
            {
                DeviceNameMask = new Regex(deviceName.Replace("x", ".*") + ".*"),
                OriginalProjectFile = parameters.ProjectFile,
                RootDirectory = rootDir,
                GNUTargetID = "arm-eabi",
                ReferencedFrameworks = new string[0],   //Unless this is explicitly specified, VisualGDB will try to reference the default frameworks (STM32 HAL) that will conflict with the STM32CubeMX-generated files.
                MCUConfiguration = new PropertyDictionary2 {
                    Entries = new[] { new PropertyDictionary2.KeyValue {
                                          Key = "com.sysprogs.mcuoptions.ignore_startup_file", Value = "1"
                                      } }
                },

                Configurations = new[]
                {
                    new ImportedExternalProject.ImportedConfiguration
                    {
                        Settings = new ImportedExternalProject.InvariantProjectBuildSettings
                        {
                            IncludeDirectories = includeDirs?.Select(d => ExpandVariables(d, expander, service))?.Where(d => !string.IsNullOrEmpty(d))?.ToArray(),
                            PreprocessorMacros = macros,
                            ExtraLDFLAGS = new[] { "-nostdlib -Wl,-u_vectors -Wl,-ereset_handler " },
                            LinkerScript = extraSettings.LinkerScript,
                        },
                    }
                }
            });
        }
예제 #6
0
        public ImportedExternalProject ImportProject(ProjectImportParameters parameters, IProjectImportService service)
        {
            var parser = new ParserImpl();
            List <VendorSample> result = new List <VendorSample>();

            parser.ParseSingleProject(null, parameters.ProjectFile, null, null, null, SW4STM32ProjectParserBase.ProjectSubtype.Auto, result);
            if (result.Count == 0)
            {
                throw new Exception("Failed to parse the project file");
            }

            ImportedExternalProject.ConstructedVirtualDirectory rootDir = new ImportedExternalProject.ConstructedVirtualDirectory();

            Dictionary <string, string> physicalDirToVirtualPaths = new Dictionary <string, string>(StringComparer.InvariantCultureIgnoreCase);

            var sample = result[0];

            if (parser.OptionDictionary.TryGetValue(sample, out var opts) && opts.SourceFiles != null)
            {
                foreach (var sf in opts.SourceFiles)
                {
                    string virtualDir = Path.GetDirectoryName(sf.VirtualPath);
                    physicalDirToVirtualPaths[Path.GetDirectoryName(sf.FullPath)] = virtualDir;
                    rootDir.ProvideSudirectory(virtualDir).AddFile(sf.FullPath, false);
                }
            }
            else
            {
                foreach (var src in sample.SourceFiles ?? new string[0])
                {
                    rootDir.AddFile(src, false);
                }
            }

            foreach (var src in sample.HeaderFiles ?? new string[0])
            {
                if (physicalDirToVirtualPaths.TryGetValue(Path.GetDirectoryName(src), out string virtualDir))
                {
                    rootDir.ProvideSudirectory(virtualDir).AddFile(src, true);
                }
                else if (physicalDirToVirtualPaths.TryGetValue(Path.GetDirectoryName(src).Replace(@"\Inc", @"\Src"), out virtualDir))
                {
                    rootDir.ProvideSudirectory(virtualDir).AddFile(src, true);
                }
                else
                {
                    rootDir.AddFile(src, true);
                }
            }

            return(new ImportedExternalProject
            {
                DeviceNameMask = new Regex(sample.DeviceID),
                OriginalProjectFile = parameters.ProjectFile,
                RootDirectory = rootDir,
                GNUTargetID = "arm-eabi",
                ReferencedFrameworks = new string[0],

                MCUConfiguration = sample.Configuration.MCUConfiguration,

                Configurations = new[]
                {
                    new ImportedExternalProject.ImportedConfiguration
                    {
                        Settings = new ImportedExternalProject.InvariantProjectBuildSettings
                        {
                            IncludeDirectories = sample.IncludeDirectories,
                            PreprocessorMacros = sample.PreprocessorMacros,
                            LinkerScript = sample.LinkerScript,
                        }
                    }
                }
            });
        }