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); }
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); } } } }
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() } } } }); }
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] }); }
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, } } } }); }