static void FillFlatFileCollectionRecursively(ImportedExternalProject.ConstructedVirtualDirectory dir, List <FlatFileReference> fileList) { foreach (var file in dir.Files ?? new List <ImportedExternalProject.ImportedFile>()) { fileList.Add(new FlatFileReference { Directory = dir, File = file }); } foreach (var subdir in (dir.Subdirectories ?? new List <ImportedExternalProject.VirtualDirectory>()).OfType <ImportedExternalProject.ConstructedVirtualDirectory>()) { FillFlatFileCollectionRecursively(subdir, fileList); } }
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); } } } }
//STM32CubeMX v5.3.0 does not reference some of the FreeRTOS-specific files and references an incorrect system file. //The method below detects and fixes this condition. static void ApplyFreeRTOSFixes(ImportedExternalProject.ConstructedVirtualDirectory dir, ref string[] includeDirs, ref PropertyDictionary2 mcuConfiguration) { List <FlatFileReference> allFiles = new List <FlatFileReference>(); FillFlatFileCollectionRecursively(dir, allFiles); var fileListsByName = allFiles.GroupBy(f => Path.GetFileName(f.File.FullPath), StringComparer.InvariantCultureIgnoreCase).ToDictionary(g => g.Key, StringComparer.InvariantCultureIgnoreCase); if (!fileListsByName.TryGetValue("queue.c", out var queueFiles) || queueFiles.Count() == 0) { return; //Could not find the FreeRTOS base directory } var queueCFile = queueFiles.First(); string baseDir = Path.GetFullPath(Path.GetDirectoryName(queueCFile.File.FullPath)); string portFile = FindAndAddFileIfMissing(fileListsByName, "port.c", Path.Combine(baseDir, "portable"), queueCFile.Directory, ref includeDirs); FindAndAddFileIfMissing(fileListsByName, "cmsis_os.c", baseDir, queueCFile.Directory, ref includeDirs); foreach (var file in fileListsByName.SelectMany(g => g.Value)) { if (Path.GetFileName(file.File.FullPath).StartsWith("system_stm32", StringComparison.InvariantCultureIgnoreCase) && !File.Exists(file.File.FullPath)) { //Found an incorrectly referenced system file (typically Source\Templates\system_stm32f7xx.c). Replace it with the real path. string foundReplacement = null; foreach (var f2 in fileListsByName.SelectMany(g => g.Value)) { string candidatePath = Path.Combine(Path.GetDirectoryName(f2.File.FullPath), Path.GetFileName(file.File.FullPath)); if (File.Exists(candidatePath)) { foundReplacement = candidatePath; break; } } if (foundReplacement != null) { file.File.FullPath = foundReplacement; } } } if (portFile != null) { string relPath = portFile.Substring(baseDir.Length); if (relPath.Contains("ARM_CM7") || relPath.Contains("ARM_CM4F")) { if (mcuConfiguration == null) { mcuConfiguration = new PropertyDictionary2(); } if (mcuConfiguration.Entries == null) { mcuConfiguration.Entries = new PropertyDictionary2.KeyValue[0]; } mcuConfiguration.Entries = mcuConfiguration.Entries.Concat(new[] { new PropertyDictionary2.KeyValue { Key = "com.sysprogs.bspoptions.arm.floatmode", Value = "-mfloat-abi=hard" } }).ToArray(); } } }
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() } } } }); }
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); }
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] }); }
ParsedCubeProject ParseProjectFile(string projectFile, bool importingReconfigurableProject) { XmlDocument xml = new XmlDocument(); xml.Load(projectFile); ParsedCubeProject result = new ParsedCubeProject { RootDirectory = new ImportedExternalProject.ConstructedVirtualDirectory() }; result.DeviceName = result.InternalDeviceName = (xml.SelectSingleNode("package/generators/generator/select/@Dname") as XmlAttribute)?.Value; if (result.DeviceName == null) { throw new Exception("Failed to extract the device name from " + projectFile); } result.DeviceName = result.DeviceName.TrimEnd('x'); result.DeviceName = result.DeviceName.Substring(0, result.DeviceName.Length - 1); HashSet <string> allHeaderDirs = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase); string baseDir = Path.GetDirectoryName(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)); } result.RootDirectory.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) && !importingReconfigurableProject) { 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)) { result.RootDirectory.ProvideSudirectory(path).AddFile(fn, category == "header"); } } } else { result.RootDirectory.ProvideSudirectory(path).AddFile(Path.Combine(baseDir, relativePath), category == "header"); } } } if (importingReconfigurableProject) { result.PreprocessorMacros = new HashSet <string>(); } else { result.PreprocessorMacros = new HashSet <string> { "$$com.sysprogs.bspoptions.primary_memory$$_layout", "$$com.sysprogs.stm32.hal_device_family$$" } }; result.IncludeDirectories = new HashSet <string>(); foreach (var dir in allHeaderDirs) { result.IncludeDirectories.Add(Path.GetFullPath(Path.Combine(baseDir, dir))); } if (hasFreeRTOS) { result.PreprocessorMacros.Add("USE_FREERTOS"); ApplyFreeRTOSFixes(result.RootDirectory, result.IncludeDirectories, ref result.MCUConfiguration); } Dictionary <string, string> temporaryExistingFileCollection = null; FixInvalidPathsRecursively(result.RootDirectory, baseDir, ref temporaryExistingFileCollection); result.AllFiles = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase); foreach (var f in result.RootDirectory.AllFilesRecursively) { result.AllFiles.Add(Path.GetFullPath(f.FullPath)); } if (importingReconfigurableProject) { string makefile = Path.Combine(Path.GetDirectoryName(projectFile), "Makefile"); if (File.Exists(makefile)) { AdjustImportedProjectFromMakefile(ref result, makefile); } } return(result); } bool ExpandValues(ref string[] inputs, Dictionary <string, string[]> dict) { List <string> result = new List <string>(); int expanded = 0; foreach (var t in inputs) { if (t.StartsWith("$(") && t.EndsWith(")")) { expanded++; if (dict.TryGetValue(t.Substring(2, t.Length - 3), out var foundValues)) { result.AddRange(foundValues); } } else { result.Add(t); } } inputs = result.ToArray(); return(expanded > 0); } void AdjustImportedProjectFromMakefile(ref ParsedCubeProject parsedProject, string makefile) { var baseDir = Path.GetDirectoryName(makefile); Dictionary <string, string[]> listsByKey = ExtractListsFromSTM32CubeMXMakefile(makefile); if (listsByKey.TryGetValue("C_DEFS", out var values)) { foreach (var v in values) { if (v.StartsWith("-D")) { parsedProject.PreprocessorMacros.Add(v.Substring(2)); } } } if (listsByKey.TryGetValue("C_INCLUDES", out values)) { foreach (var v in values) { if (v.StartsWith("-I")) { parsedProject.IncludeDirectories.Add(Path.GetFullPath(Path.Combine(baseDir, v.Substring(2)))); } } } if (listsByKey.TryGetValue("LDSCRIPT", out values) && values.Length == 1) { parsedProject.LinkerScript = Path.GetFullPath(Path.Combine(baseDir, values[0])); } if (listsByKey.TryGetValue("MCU", out values)) { for (int i = 0; i < 10; i++) { if (!ExpandValues(ref values, listsByKey)) { break; } } parsedProject.CFLAGS = string.Join(" ", values); } if (listsByKey.TryGetValue("C_SOURCES", out values)) { //GPDSC files generated by STM32CubeMX are often inaccurate and buggy, so we take the data from the Makefile instead parsedProject.AllFiles.RemoveWhere(f => f.EndsWith(".c", StringComparison.InvariantCultureIgnoreCase)); foreach (var src in values) { parsedProject.AllFiles.Add(Path.GetFullPath(Path.Combine(baseDir, src))); } } if (listsByKey.TryGetValue("ASM_SOURCES", out values)) { parsedProject.AllFiles.RemoveWhere(f => f.EndsWith(".s", StringComparison.InvariantCultureIgnoreCase)); foreach (var src in values) { parsedProject.AllFiles.Add(Path.GetFullPath(Path.Combine(baseDir, src))); } } }
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, }, } } }); }
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, } } } }); }
public ImportedExternalProject ImportProject(ProjectImportParameters parameters, IProjectImportService service) { XmlDocument xml = new XmlDocument(); xml.Load(parameters.ProjectFile); var target = xml.SelectSingleNode("Project/Targets/Target") as XmlElement; if (target == null) { throw new Exception("Failed to locate the target node in " + parameters.ProjectFile); } string deviceName = (target.SelectSingleNode("TargetOption/TargetCommonOption/Device") as XmlElement)?.InnerText; if (deviceName == null) { throw new Exception("Failed to extract the device name from " + parameters.ProjectFile); } if (deviceName.EndsWith("x")) { deviceName = deviceName.TrimEnd('x'); deviceName = deviceName.Substring(0, deviceName.Length - 1); } string baseDir = Path.GetDirectoryName(parameters.ProjectFile); ImportedExternalProject.ConstructedVirtualDirectory rootDir = new ImportedExternalProject.ConstructedVirtualDirectory(); foreach (var group in target.SelectNodes("Groups/Group").OfType <XmlElement>()) { string virtualPath = group.SelectSingleNode("GroupName")?.InnerText; if (string.IsNullOrEmpty(virtualPath)) { continue; } var subdir = rootDir.ProvideSudirectory(virtualPath); foreach (var file in group.SelectNodes("Files/File").OfType <XmlElement>()) { string path = file.SelectSingleNode("FilePath")?.InnerText; string type = file.SelectSingleNode("FileType")?.InnerText; if (type == "2") { //This is an assembly file. Keil uses a different assembly syntax than GCC, so we cannot include this file into the project. //The end user will need to include a GCC-specific replacement manually (unless this is the startup file, in which case VisualGDB //automatically includes a GCC-compatible replacement). continue; } if (string.IsNullOrEmpty(path)) { continue; } var adjustedPath = TryAdjustPath(baseDir, path, service); subdir.AddFile(adjustedPath, type == "5"); } } List <string> macros = new List <string> { "$$com.sysprogs.bspoptions.primary_memory$$_layout" }; List <string> includeDirs = new List <string>(); var optionsNode = target.SelectSingleNode("TargetOption/TargetArmAds/Cads/VariousControls"); if (optionsNode != null) { macros.AddRange((optionsNode.SelectSingleNode("Define")?.InnerText ?? "").Split(',').Select(m => m.Trim())); includeDirs.AddRange((optionsNode.SelectSingleNode("IncludePath")?.InnerText ?? "") .Split(';') .Select(p => TryAdjustPath(baseDir, p.Trim(), service)) .Where(p => p != null)); } 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. Configurations = new[] { new ImportedExternalProject.ImportedConfiguration { Settings = new ImportedExternalProject.InvariantProjectBuildSettings { IncludeDirectories = includeDirs.ToArray(), PreprocessorMacros = macros.ToArray() } } } }); }