private VendorSample ParseSingleConfiguration(XmlDocument cproject, XmlDocument project, XmlElement cconfiguration, string optionalProjectRootForLocatingHeaders, string cprojectFileDir, string boardName, MultiConfigurationContext multiConfigurationContext, ProjectSubtype subtype) { VendorSample result = new VendorSample { UserFriendlyName = (project.SelectSingleNode("projectDescription/name") as XmlElement)?.InnerText ?? throw new Exception("Failed to determine sample name"), NoImplicitCopy = true, }; if (optionalProjectRootForLocatingHeaders == null) { optionalProjectRootForLocatingHeaders = cprojectFileDir; } CommonConfigurationOptions opts; if (subtype == ProjectSubtype.Auto) { var toolchainConfigNode = cconfiguration.SelectSingleNode(ToolchainConfigKey) as XmlNode ?? throw new Exception("Failed to locate the configuration node"); if (toolchainConfigNode.SelectSingleNode("tool[starts-with(@id, 'fr.ac6.managedbuild.tool.gnu.cross.c.compiler')]") != null) { subtype = ProjectSubtype.SW4STM32; } else if (toolchainConfigNode.SelectSingleNode("tool[@superClass = 'com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler']") != null) { subtype = ProjectSubtype.STM32CubeIDE; } else { throw new Exception("Failed to detect the project type"); } } if (subtype == ProjectSubtype.SW4STM32) { opts = ExtractSW4STM32Options(cproject, project, cconfiguration, cprojectFileDir); } else { opts = ExtractSTM32CubeIDEOptions(cproject, project, cconfiguration, cprojectFileDir); } var mcu = opts.MCU; if (mcu.EndsWith("x")) { if (mcu.StartsWith("STM32MP1")) { mcu = mcu.Substring(0, mcu.Length - 3) + "_M4"; } else { mcu = mcu.Remove(mcu.Length - 2, 2); } } else if (mcu.EndsWith("xP")) { mcu = mcu.Remove(mcu.Length - 3, 3); } AdjustMCUName(ref mcu); if (multiConfigurationContext is MultiConfigurationContext.MultiCore mc) { mcu += mc.DeviceSuffix; result.InternalUniqueID += mc.DeviceSuffix; result.UserFriendlyName += mc.UserFriendlyNameSuffix; } ValidateFinalMCUName(mcu); result.DeviceID = mcu; result.SourceFiles = opts.SourceFiles.Select(f => f.FullPath).Concat(opts.Libraries).Distinct().ToArray(); result.IncludeDirectories = opts.IncludeDirectories; result.PreprocessorMacros = opts.PreprocessorMacros; result.BoardName = boardName ?? opts.BoardName; result.LinkerScript = opts.LinkerScript; OnVendorSampleParsed(result, opts); List <PropertyDictionary2.KeyValue> mcuConfig = new List <PropertyDictionary2.KeyValue>(); if (opts.LDFLAGS?.Contains("rdimon.specs") == true) { mcuConfig.Add(new PropertyDictionary2.KeyValue { Key = "com.sysprogs.toolchainoptions.arm.libctype", Value = "--specs=rdimon.specs" }); } try { if (result.SourceFiles.Select(f => Path.GetFileName(f)).FirstOrDefault(f => f.StartsWith("startup_", StringComparison.InvariantCultureIgnoreCase) && f.EndsWith(".s", StringComparison.InvariantCultureIgnoreCase)) != null) { mcuConfig.Add(new PropertyDictionary2.KeyValue { Key = "com.sysprogs.mcuoptions.ignore_startup_file", Value = "1" }); } } catch { } if (mcuConfig.Count > 0) { result.Configuration.MCUConfiguration = new PropertyDictionary2 { Entries = mcuConfig.ToArray() }; } result.Path = Path.GetDirectoryName(optionalProjectRootForLocatingHeaders); HashSet <string> possibleIncludeDirs = new HashSet <string>(); foreach (var src in result.SourceFiles) { int idx = src.IndexOf(@"\Src\", StringComparison.InvariantCultureIgnoreCase); if (idx == -1) { continue; } string possibleInc = src.Substring(0, idx) + @"\Inc"; possibleIncludeDirs.Add(possibleInc); } string possibleRoot = optionalProjectRootForLocatingHeaders; for (; ;) { string possibleIncDir = Path.Combine(possibleRoot, "Inc"); if (Directory.Exists(possibleIncDir)) { possibleIncludeDirs.Add(possibleIncDir); break; } var baseDir = Path.GetDirectoryName(possibleRoot); if (string.IsNullOrEmpty(baseDir) || baseDir == possibleRoot) { break; } possibleRoot = baseDir; } List <string> headers = new List <string>(); foreach (var possibleIncDir in possibleIncludeDirs) { if (Directory.Exists(possibleIncDir)) { headers.AddRange(Directory.GetFiles(possibleIncDir, "*.h", SearchOption.AllDirectories)); } } result.HeaderFiles = headers.ToArray(); return(result); }
ConfigurationWithContext[] DetectConfigurationContexts(XmlDocument cproject, string projectFile) { var cconfigurationNodes = cproject.SelectNodes("cproject/storageModule[@moduleId='org.eclipse.cdt.core.settings']/cconfiguration").OfType <XmlElement>().ToArray(); if (cconfigurationNodes.Length == 0) { throw new Exception("No 'cconfiguration' nodes found"); } if (cconfigurationNodes.Length > 1) { var nonReleaseNodes = cconfigurationNodes.Where(n => !n.GetAttribute("id").Contains(".release.")).ToArray(); if (nonReleaseNodes.Length > 0) { cconfigurationNodes = nonReleaseNodes; } } List <ConfigurationWithContext> result = new List <ConfigurationWithContext>(); foreach (var cconfiguration in cconfigurationNodes) { MultiConfigurationContext mctx = null; if (cconfigurationNodes.Length > 1) { if (cconfigurationNodes.Length != 2) { throw new Exception("Unexpected configuration count for " + projectFile); } string artifactName = cconfiguration.SelectSingleNode("storageModule[@moduleId='cdtBuildSystem']/configuration/@artifactName")?.Value; if (artifactName.EndsWith("_CM4")) { mctx = new MultiConfigurationContext.MultiCore { DeviceSuffix = "_M4", UserFriendlyNameSuffix = " (Cortex-M4 Core)" } } ; else if (artifactName.EndsWith("_CM7")) { mctx = new MultiConfigurationContext.MultiCore { DeviceSuffix = "", UserFriendlyNameSuffix = " (Cortex-M7 Core)" } } ; else { throw new Exception("Don't know how to interpret the difference between multiple configurations for a project. Please review it manually."); } } result.Add(new ConfigurationWithContext { CConfiguration = cconfiguration, Context = mctx }); } if (result.Select(c => c.Context?.IDSuffix ?? "").Distinct().Count() != result.Count) { OnMultipleConfigurationsFound(projectFile); result = result.Take(1).ToList(); } return(result.ToArray()); }