public void RelativizeTest1() { AbsoluteCrosspath xIncludeDirectory = AbsoluteCrosspath.FromString("/local/store/bin-src/qemu"); AbsoluteCrosspath xFile = AbsoluteCrosspath.FromString("/local/store/bin-src/qemu/hw/mips/serial.c"); RelativeCrosspath relPath = xFile.Relativized(xIncludeDirectory); Assert.AreEqual("hw/mips/serial.c", relPath.ToString()); }
public void AppendedTest() { AbsoluteCrosspath xLocalIncludeDirectory = AbsoluteCrosspath.GetCurrentDirectory(); RelativeCrosspath xRelPath = RelativeCrosspath.FromString("lzcintrin.h"); AbsoluteCrosspath xPath = xLocalIncludeDirectory.Appended(xRelPath); Assert.AreEqual(xPath.ToString(), xLocalIncludeDirectory + @"\" + xRelPath); }
public void RelativizeTestWin1() { AbsoluteCrosspath xIncludeDirectory = AbsoluteCrosspath.FromString(@"C:\Windows\system32\config"); AbsoluteCrosspath xFile = AbsoluteCrosspath.FromString(@"C:\Program Files (x86)\Common Files\Microsoft"); RelativeCrosspath relPath = xFile.Relativized(xIncludeDirectory); Assert.AreEqual(@"..\..\..\Program Files (x86)\Common Files\Microsoft", relPath.ToString()); }
public void RelativizeTest2() { AbsoluteCrosspath xIncludeDirectory = AbsoluteCrosspath.FromString("/local/store/bin-src/qemu"); AbsoluteCrosspath xFile = AbsoluteCrosspath.FromString("/local/store/fast/bin-src/ccache/ccache.c"); RelativeCrosspath relPath = xFile.Relativized(xIncludeDirectory); Assert.AreEqual("../../fast/bin-src/ccache/ccache.c", relPath.ToString()); }
public String GetLocalProjectPath(AbsoluteCrosspath solutionDir) { if (autoDownloaded) { return($@"$(SolutionDir)\{this.Relativized(solutionDir, true)}"); } return(this.ToString()); }
public void RebaseFromUnixToWindowsTestFull() { Crosspath xpath = Crosspath.FromString("/local/store/bin-src/qemu"); AbsoluteCrosspath before = Crosspath.FromString("/local/store/bin-src/qemu") as AbsoluteCrosspath; AbsoluteCrosspath after = Crosspath.FromString(@"D:\Workspace\Source\qemu") as AbsoluteCrosspath; AbsoluteCrosspath apath = ((AbsoluteCrosspath)xpath).Rebase(before, after); Assert.AreEqual(CrosspathFlavor.Windows, apath.Flavor); Assert.AreEqual('D', apath.WindowsRootDrive); Assert.AreEqual(@"D:\Workspace\Source\qemu", apath.ToString()); Assert.AreEqual(@"D:\Workspace\Source\qemu", apath.ToAbsolutizedString()); }
public void RelativizeTest3() { AbsoluteCrosspath xIncludeDirectory = AbsoluteCrosspath.FromString("/local/store/bin-src/qemu"); AbsoluteCrosspath xFile = AbsoluteCrosspath.FromString("/local/store/fast/bin-src/ccache/ccache.c"); try { RelativeCrosspath unused = xFile.Relativized(xIncludeDirectory, true); Assert.Fail("should fail"); } catch (CrosspathLibException) { } }
public void RelativizeTestWin2() { AbsoluteCrosspath xIncludeDirectory = AbsoluteCrosspath.FromString(@"C:\Windows\system32\config"); AbsoluteCrosspath xFile = AbsoluteCrosspath.FromString(@"D:\Games\Call of Duty 2"); try { RelativeCrosspath unused = xFile.Relativized(xIncludeDirectory); Assert.Fail("should fail"); } catch { // ignored } }
public void TestMethod3() { Crosspath cpath = Crosspath.FromString(@"/local/store/qemu"); Assert.IsInstanceOfType(cpath, typeof(AbsoluteCrosspath)); Assert.AreEqual(CrosspathFlavor.Unix, cpath.Flavor); Assert.AreEqual(CrosspathOrigin.Absolute, cpath.Origin); Assert.AreEqual(@"/local/store/qemu", ((AbsoluteCrosspath)cpath).ToString()); // DONE: substitute (rebase) absolute paths Assert.AreEqual(@"D:\Projects\local\store\qemu" , ((AbsoluteCrosspath)cpath).Rebase(AbsoluteCrosspath.FromString("/") , AbsoluteCrosspath.FromString(@"D:\Projects")).ToString()); }
public ProjectFile(Solution sln, AbsoluteCrosspath filePath, CompilerInstance compilerInstance) { CompilerOfFile = compilerInstance; IncludeDirectories = new IncludeDirectoryList(); DoNotUseStandardIncludeDirectories = false; Defines = new Dictionary <String, Define>(); SetOfDefines = new HashSet <Define>(DefineExactComparer.Instance); ForceIncludes = new HashSet <AbsoluteCrosspath>(); FilePath = filePath; OwnerSolution = sln; if (sln.config.BaseDir != null) { ProjectFolder = RelativeCrosspath.CreateRelativePath(filePath, sln.config.BaseDir, true).ToContainingDirectory() as RelativeCrosspath; } }
public void HashDiversedEquality() { HashSet <Crosspath> hs = new HashSet <Crosspath> { Crosspath.FromString("/tmp/VCXProjWriter") , AbsoluteCrosspath.FromString("/tmp/VCXProjWriter1") , RelativeCrosspath.FromString("tmp/VCXProjWriter") }; RelativeCrosspath relativeCrosspath = RelativeCrosspath.FromString("VCXProjWriter"); relativeCrosspath.SetWorkingDirectory(AbsoluteCrosspath.FromString("/tmp")); Boolean has_added = hs.Add(relativeCrosspath); Assert.AreEqual(false, has_added); Assert.AreEqual(3, hs.Count); }
public void DownloadStandardIncludeDirectories(RemoteHost remote) { if (Skip) { return; } // use sftp, or, when not possible, ssh cat AbsoluteCrosspath xpwd = AbsoluteCrosspath.GetCurrentDirectory(); AbsoluteCrosspath xCompilerDir = xpwd.Appended(RelativeCrosspath.FromString($@"compilers\{ShortName}")); Directory.CreateDirectory(xCompilerDir.ToString()); foreach (IncludeDirectory includeDirectory in IncludeDirectories) { includeDirectory.RebaseToLocal(remote, xCompilerDir); } }
/// <summary> /// Writes compiler_${ShortName}.props and compiler_$(ShortName}_compat.h /// </summary> public void WriteToFile(AbsoluteCrosspath solutionDir) { if (Skip) { return; } AbsoluteCrosspath compilerDir = RelativeCrosspath.FromString(PropsFileName).Absolutized(AbsoluteCrosspath.GetCurrentDirectory()).ToContainingDirectory(); Directory.CreateDirectory(compilerDir.ToString()); foreach (CompilerInstance compilerInstance in Instances) { compilerInstance.WriteToFile(solutionDir); } XmlDocument doc = new XmlDocument(); doc.AppendChild(doc.CreateXmlDeclaration("1.0", "utf-8", null)); XmlElement projectNode = doc.CreateElement("Project"); projectNode.SetAttribute("DefaultTargets", "Build"); projectNode.SetAttribute("ToolsVersion", "Current"); projectNode.SetAttribute("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003"); XmlElement projectImportProps = doc.CreateElement("Import"); projectImportProps.SetAttribute("Project", @"$(SolutionDir)\Solution.props"); projectNode.AppendChild(projectImportProps); XmlElement projectPropertyGroupCompiler = doc.CreateElement("PropertyGroup"); XmlElement projectCompilerExeName = doc.CreateElement("RemoteCCompileToolExe"); projectCompilerExeName.InnerText = ExePath.ToString(); projectPropertyGroupCompiler.AppendChild(projectCompilerExeName); XmlElement projectCompilerCppExeName = doc.CreateElement("RemoteCppCompileToolExe"); projectCompilerCppExeName.InnerText = ExePath.ToString(); projectPropertyGroupCompiler.AppendChild(projectCompilerCppExeName); projectNode.AppendChild(projectPropertyGroupCompiler); doc.AppendChild(projectNode); doc.Save(PropsFileName); }
public Boolean AddEntry(AbsoluteCrosspath path) { NTree <String> fs = (NTree <String>) this; foreach (String pathEntry in path) { if (fs.children[pathEntry] == null) { fs.children[pathEntry] = new NTree <String>(fs, pathEntry); } else { fs = fs.children[pathEntry]; } } return(false); }
/// <summary> /// Can be called multiple times. /// </summary> /// <param name="before">Old base (e.g. Unix path where compiled)</param> /// <param name="after">New base (e.g. Windows path where edited)</param> public void Rebase(AbsoluteCrosspath before, AbsoluteCrosspath after) { // move project files to another location foreach (ProjectFile projectFile in solutionFiles) { projectFile.FilePath.Rebase(before, after); } // move include directories to another location foreach (KeyValuePair <String, IncludeDirectory> includeDirPair in solutionIncludeDirectories) { includeDirPair.Value.Rebase(before, after); } if (this.config.BaseDir != null) { this.config.BaseDir.Rebase(before, after); } }
internal IncludeDirectory TrackIncludeDirectory(AbsoluteCrosspath includeDirPath, IncludeDirectoryType idt) { String includeDirStrReconstructed = includeDirPath.ToString(); IncludeDirectory includeDir; if (!solutionIncludeDirectories.ContainsKey(includeDirStrReconstructed)) { includeDir = new IncludeDirectory(includeDirPath, idt); solutionIncludeDirectories.Add(includeDirStrReconstructed, includeDir); Logger.WriteLine(LogLevel.Debug, $"New include directory '{includeDirStrReconstructed}'"); } else { // if this include directory is already known, then drop current object and get old reference includeDir = solutionIncludeDirectories[includeDirStrReconstructed]; Logger.WriteLine(LogLevel.Trace, $"Reusing include directory '{includeDirStrReconstructed}'"); } return(includeDir); }
public void IncludeDirsOrder() { IncludeDirectoryList includeDirs = new IncludeDirectoryList(); IncludeDirectory[] expected = { new IncludeDirectory(AbsoluteCrosspath.FromString("/opt/qemu-5.3/inc/private"), IncludeDirectoryType.Quote) , new IncludeDirectory(AbsoluteCrosspath.FromString("/opt/qemu-5.3/hw/mips/include"), IncludeDirectoryType.Generic) , new IncludeDirectory(AbsoluteCrosspath.FromString("/opt/qemu-5.3/hw/mips"), IncludeDirectoryType.Generic) , new IncludeDirectory(AbsoluteCrosspath.FromString("/opt/qemu-5.3/inc"), IncludeDirectoryType.System) , new IncludeDirectory(AbsoluteCrosspath.FromString("/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include"), IncludeDirectoryType.System) , new IncludeDirectory(AbsoluteCrosspath.FromString("/usr/local/include"), IncludeDirectoryType.System) , new IncludeDirectory(AbsoluteCrosspath.FromString("/usr/include"), IncludeDirectoryType.System) , new IncludeDirectory(AbsoluteCrosspath.FromString("/opt/qemu-5.3-helper/if-a-compiler-didnt-handle/include"), IncludeDirectoryType.DirAfter) }; // a tricky project includeDirs.AddIncludeDirectory(expected[3]); /* /opt/qemu-5.3/inc */ includeDirs.AddIncludeDirectory(expected[0]); /* /opt/qemu-5.3/inc/private */ includeDirs.AddIncludeDirectory(expected[0]); /* /opt/qemu-5.3/inc/private */ // intentional duplicate includeDirs.AddIncludeDirectory(expected[7]); /* /opt/qemu-5.3-helper/if-a-compiler-didnt-handle/include */ includeDirs.AddIncludeDirectory(expected[1]); /* /opt/qemu-5.3/hw/mips/include */ includeDirs.AddIncludeDirectory(expected[2]); /* /opt/qemu-5.3/hw/mips */ // compiler should go after the project includeDirs.AddIncludeDirectory(expected[4]); /* /usr/lib/gcc/x86_64-redhat-linux/4.8.5/include */ includeDirs.AddIncludeDirectory(expected[5]); /* /usr/local/include */ includeDirs.AddIncludeDirectory(expected[6]); /* /usr/include */ int idx = 0; foreach (IncludeDirectory includeDirectory in includeDirs) { Assert.AreEqual(expected[idx], includeDirectory); ++idx; } }
private static void ProcessArgs(String[] args) { for (int idx = 0; idx < args.Length; idx++) { switch (args[idx]) { case "-s": case "--substitute-path": String[] subst = TakeArg(args, ref idx).Split(new[] { '=' }, 2); if (subst.Length != 2) { throw new ApplicationException("--substitute-path requires next arg to be like '/path/before=/path/after'"); } AbsoluteCrosspath[] pair = new AbsoluteCrosspath[2]; for (int i = 0; i < 2; ++i) { try { pair[i] = Crosspath.FromString(subst[i]) as AbsoluteCrosspath; } catch (Exception e) { throw new PolymorphismException($"{e.GetType()}: '{subst[i]}' is not a valid absolute path"); } } config.Substitutions.Add(new Tuple <AbsoluteCrosspath, AbsoluteCrosspath>(pair[0], pair[1])); break; case "-b": case "--base-dir": config.BaseDir = AbsoluteCrosspath.FromString(TakeArg(args, ref idx)); break; #if PATH_BASED_FILTERING case "--include": config.IncludeFilesFrom.Add(Crosspath.FromString(TakeArg(args, ref idx))); break; case "--exclude": config.ExcludeFilesFrom.Add(Crosspath.FromString(TakeArg(args, ref idx))); break; #endif case "-o": case "--output-dir": config.Outdir = TakeArg(args, ref idx); break; case "-f": case "--file": config.InputFile = TakeArg(args, ref idx); break; case "-r": case "--remote": RemoteHost remote = RemoteHost.Parse(TakeArg(args, ref idx)); config.AssignRemote(remote); break; case "-D": case "--define": config.OverrideDefines.Add(new Define(TakeArg(args, ref idx))); break; case "--exclude-compiler": config.ExcludeCompilers.Add(Crosspath.FromString(TakeArg(args, ref idx))); break; case "--relax-include-dirs-order": config.RelaxIncludeDirsOrder = true; break; case "--randomize-outdir": config.Outdir = Path.Combine(config.Outdir, new Random().Next().ToString("x8")); break; case "--open-now": config.OpenSolution = true; break; case "--debug": Logger.Level = LogLevel.Debug; break; case "--help": ShowHelp(); return; default: throw new Exception($"Unknown command line parameter '{args[idx]}"); } } }
private static void Main(String[] args) { #if !DEBUG try { #endif ProcessArgs(args); if (config.InputFile == null) { ShowHelp(); } Stopwatch sw = new Stopwatch(); sw.Start(); Solution sln = new Solution(config); sln.ParseCompileDB(config.InputFile); sw.Stop(); Int64 parseAndGroup = sw.ElapsedMilliseconds; sw.Reset(); sw.Start(); if (config.Remote != null) { sln.RetrieveExtraInfoFromRemote(config.Remote); } sw.Stop(); Int64 remoteInfo = sw.ElapsedMilliseconds; sln.FilterOutEntries(); sw.Reset(); sw.Start(); foreach (Tuple <AbsoluteCrosspath, AbsoluteCrosspath> substitution in config.Substitutions) { sln.Rebase(substitution.Item1, substitution.Item2); } sw.Stop(); Int64 rebase = sw.ElapsedMilliseconds; // DONE: also check for: // - project file accessibility // - include dirs accessibility List <IncludeDirectory> remoteNotRebased = new List <IncludeDirectory>(); sln.CheckForTotalRebase(ref remoteNotRebased); try { Directory.Delete(config.Outdir, true); } catch { // ignored } if (config.Remote != null) { sln.DownloadCompilerIncludeDirectoriesFromRemote(config.Remote, config.Outdir); foreach (IncludeDirectory includeDirectory in remoteNotRebased) { Crosspath outdir = Crosspath.FromString(config.Outdir); if (outdir is RelativeCrosspath relativeCrosspath) { outdir = relativeCrosspath.Absolutized(AbsoluteCrosspath.GetCurrentDirectory()); } includeDirectory.RebaseToLocal(config.Remote , ((AbsoluteCrosspath)outdir).Append( RelativeCrosspath.FromString(String.Format(SolutionStructure.RemoteIncludePath , config.Remote.Host)))); } } sw.Reset(); sw.Start(); sln.WriteToDirectory(config.Outdir); sw.Stop(); Int64 write = sw.ElapsedMilliseconds; Console.WriteLine(); Console.WriteLine($"Elapsed time: parseAndGroup = {parseAndGroup} ms, remoteInfo = {remoteInfo} ms" + $", rebase = {rebase} ms, write = {write} ms."); if (config.OpenSolution) { Process.Start(new ProcessStartInfo(Path.Combine(config.Outdir, SolutionStructure.SolutionFilename)) { UseShellExecute = true }); } #if !DEBUG } catch (Exception e) { Console.WriteLine($"[x] {e.Message}"); Console.WriteLine(); Console.WriteLine("Stack trace for debugging purposes:"); Console.WriteLine($"{e.StackTrace}"); Console.WriteLine("Press Enter to continue..."); Console.ReadLine(); } #endif }
public void WriteToFile(AbsoluteCrosspath solutionDir) { String inheritFrom; if (Skip || CompilerInstance.BaseCompiler.Skip) { return; } // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression if (CompilerInstance.HaveAdditionalInfo) { inheritFrom = $@"$(SolutionDir)\{CompilerInstance.PropsFileName}"; } else { inheritFrom = @"$(SolutionDir)\Solution.props"; } Directory.CreateDirectory(Path.GetDirectoryName(this.Filename) ?? Directory.GetCurrentDirectory()); // compatibility files // DONE: add compatibility files directly to the project node String compatPrefix = SolutionStructure.SeparateProjectsFromEachOther ? "" : $"{Name}."; String compatLocal = String.Format(SolutionStructure.ForcedIncludes.LocalCompat, compatPrefix); String compatLocalPost = String.Format(SolutionStructure.ForcedIncludes.LocalPostCompat, compatPrefix); File.WriteAllText($@"{Path.GetDirectoryName(Filename)}\{compatLocal}", @""); File.WriteAllText($@"{Path.GetDirectoryName(Filename)}\{compatLocalPost}", @""); // create with XML API XmlDocument doc = new XmlDocument(); doc.AppendChild(doc.CreateXmlDeclaration("1.0", "utf-8", null)); XmlElement projectNode = doc.CreateElement("Project"); projectNode.SetAttribute("DefaultTargets", "Build"); projectNode.SetAttribute("ToolsVersion", "Current"); projectNode.SetAttribute("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003"); XmlElement projectImportProps = doc.CreateElement("Import"); projectImportProps.SetAttribute("Project", inheritFrom); projectNode.AppendChild(projectImportProps); XmlElement projectPropertyGroupGlobals = doc.CreateElement("PropertyGroup"); projectPropertyGroupGlobals.SetAttribute("Label", "Globals"); XmlElement projectGuid = doc.CreateElement("ProjectGuid"); projectGuid.InnerText = $"{{{Guid}}}"; projectPropertyGroupGlobals.AppendChild(projectGuid); projectNode.AppendChild(projectPropertyGroupGlobals); XmlElement projectPropertyGroupIDU = doc.CreateElement("PropertyGroup"); // maybe someday this will be helpful, but now it can be inherited from Solution.props XmlElement projectForcedIncludes = doc.CreateElement("NMakeForcedIncludes"); // TODO: add compiler compat header to forced includes projectForcedIncludes.InnerText = $@"$(ProjectDir)\{compatLocal};$(SolutionPreCompilerCompat);$(CompilerCompat);$(SolutionPostCompilerCompat);$(ProjectDir)\{compatLocalPost}"; projectPropertyGroupIDU.AppendChild(projectForcedIncludes); projectNode.AppendChild(projectPropertyGroupIDU); // source file list XmlElement projectItemGroupCompiles = doc.CreateElement("ItemGroup"); projectItemGroupCompiles.SetAttribute("Label", "Source Files"); foreach (ProjectFile projectFile in this.ProjectFiles) { // exclusion list comes here! // TODO: we need to access path before rebase occured... XmlElement projectFileXmlElement = doc.CreateElement("ClCompile"); projectFileXmlElement.SetAttribute("Include", projectFile.FilePath.ToString()); // IDU settings XmlElement pfIncludePaths = doc.CreateElement("AdditionalIncludeDirectories"); // DONE?: intermix project include directories with compiler include directories // in the project file foreach (IncludeDirectory includePath in projectFile.IncludeDirectories) { // append -idirafter to the very end, below compiler dirs if (includePath.Type == IncludeDirectoryType.DirAfter) { continue; } pfIncludePaths.InnerText += includePath.GetLocalProjectPath(solutionDir) + ";"; } pfIncludePaths.InnerText += "%(AdditionalIncludeDirectories)"; foreach (IncludeDirectory includePath in projectFile.IncludeDirectories) { // append -idirafter to the very end, below compiler dirs if (includePath.Type == IncludeDirectoryType.DirAfter) { pfIncludePaths.InnerText += ";" + includePath.GetLocalProjectPath(solutionDir); } } projectFileXmlElement.AppendChild(pfIncludePaths); // maybe someday this will be helpful, but now it can be inherited from Solution.props XmlElement pfForcedIncludes = doc.CreateElement("ForcedIncludeFiles"); foreach (AbsoluteCrosspath projectForcedInclude in projectFile.ForceIncludes) { pfForcedIncludes.InnerText += $"{projectForcedInclude};"; } pfForcedIncludes.InnerText += $"%(ForcedIncludeFiles)"; projectFileXmlElement.AppendChild(pfForcedIncludes); XmlElement pfDefines = doc.CreateElement("PreprocessorDefinitions"); foreach (Define define in projectFile.Defines.Values) { pfDefines.InnerText += define + ";"; } pfDefines.InnerText += "$(PreprocessorDefinitions)"; projectFileXmlElement.AppendChild(pfDefines); projectItemGroupCompiles.AppendChild(projectFileXmlElement); } // add local_compat.h and local_post_compiler_compat.h XmlElement projectFileLocalCompatXmlElement = doc.CreateElement("ClCompile"); projectFileLocalCompatXmlElement.SetAttribute("Include", "local_compat.h"); projectItemGroupCompiles.AppendChild(projectFileLocalCompatXmlElement); XmlElement projectFileLocalPostCompatXmlElement = doc.CreateElement("ClCompile"); projectFileLocalPostCompatXmlElement.SetAttribute("Include", "local_post_compiler_compat.h"); projectItemGroupCompiles.AppendChild(projectFileLocalPostCompatXmlElement); projectNode.AppendChild(projectItemGroupCompiles); // TODO: add headers somehow... XmlElement projectItemGroupIncludes = doc.CreateElement("ItemGroup"); projectItemGroupIncludes.SetAttribute("Label", "Header Files"); /* * foreach (ProjectFile projectFile in this.ProjectDepends.Values) { * XmlElement projectFileXmlElement = doc.CreateElement("ClInclude"); * projectFileXmlElement.SetAttribute("Include", projectFile.FilePath); * projectItemGroupIncludes.AppendChild(projectFileXmlElement); * } */ projectNode.AppendChild(projectItemGroupIncludes); doc.AppendChild(projectNode); doc.Save(this.Filename); WriteStructureToFile(); }
/// <summary> /// Call RemoteHost.ExtractInfoFromCompiler() instead. /// Requires these utilities on the remote system: pwd, echo, which, touch, sort, pushd, popd, zip /// </summary> /// <param name="remote">Remote host where compiler installed</param> public void ExtractAdditionalInfo(RemoteHost remote) { String remoteTempFile = String.Format(Compiler.RemoteTempFile, BaseCompiler.ShortName, instanceGuid.ToString()); if (remote.Execute("pwd || echo $PWD", out String pwd) != RemoteHost.Success) { throw new ApplicationException("could not get current directory name"); } pwd = pwd.TrimEnd(RemoteHost.LineEndingChars); if (remote.Execute($"which {BaseCompiler.ExePath}", out String absExePath) != RemoteHost.Success) { throw new ApplicationException("could not get absolute compiler path"); } absExePath = absExePath.TrimEnd(RemoteHost.LineEndingChars); if (remote.Execute($"{BaseCompiler.ExePath} -dumpversion", out String version) != RemoteHost.Success) { throw new ApplicationException("could not extract version from compiler"); } Version = version.TrimEnd(RemoteHost.LineEndingChars); // create temporary .c file for auto-distinguishment between C and C++ if (remote.Execute($"touch {remoteTempFile} || echo > {remoteTempFile}", out String _) != RemoteHost.Success) { throw new ApplicationException("could not create temporary file"); } if (remote.Execute($"{BaseCompiler.ExePath} {this} -E -dM {remoteTempFile} | sort", out String defines) != RemoteHost.Success) { throw new ApplicationException("could not extract defines from compiler"); } if (remote.Execute($"{BaseCompiler.ExePath} {this} -E -Wp,-v {remoteTempFile} 2>&1 1> /dev/null", out String includeDirs) != RemoteHost.Success) { throw new ApplicationException("could not extract include dirs from compiler"); } AbsoluteCrosspath xpwd = AbsoluteCrosspath.FromString(pwd); AbsoluteCrosspath xcompiler = AbsoluteCrosspath.FromString(absExePath); if (!xcompiler.ToString().Equals(BaseCompiler.ExePath.ToString())) { AbsoluteCrosspath compilerLocatedIn = new AbsoluteCrosspath(xcompiler); ((RelativeCrosspath)BaseCompiler.ExePath).SetWorkingDirectory(xcompiler.ToContainingDirectory()); Logger.WriteLine(LogLevel.Info, $"compiler '{BaseCompiler.ExePath}' actually located at '{xcompiler}'"); } Defines.Clear(); Platform fallbackPlatform = Platform.x64; foreach (String macro in defines.Split(RemoteHost.LineEndings, StringSplitOptions.RemoveEmptyEntries)) { // assuming standard format '#define MACRO some thing probably with spaces' String[] defArray = macro.Split(new[] { ' ' }, 3); // try to auto-detect the platform if (VSPlatform == Platform.Unknown) { switch (defArray[1]) { case "__x86_64__": VSPlatform = Platform.x64; break; case "__i386__": VSPlatform = Platform.x86; break; case "__arm__": VSPlatform = Platform.ARM; break; case "__aarch64__": VSPlatform = Platform.ARM64; break; case "__mips__": VSPlatform = Platform.MIPS; break; case "__WORDSIZE__": /* this seems to be standard */ case "__INTPTR_WIDTH__": /* this not, but use as fallback */ if (Int32.Parse(defArray[2]) == 32) { fallbackPlatform = Platform.x86; } break; } } Defines.Add(new Define(defArray[1], defArray[2])); } if (VSPlatform == Platform.Unknown) { VSPlatform = fallbackPlatform; } IncludeDirectories.Clear(); IncludeDirectoryType incDirType = IncludeDirectoryType.Null; foreach (String cppLine in includeDirs.Split(RemoteHost.LineEndings, StringSplitOptions.RemoveEmptyEntries)) { // sample output: /* * ignoring nonexistent directory "/opt/gcc-4.1.2-glibc-2.5-binutils-2.17-kernel-2.6.18/arm-v5te-linux-gnueabi/include" #include "..." search starts here: #include <...> search starts here: * /opt/gcc-4.1.2-glibc-2.5-binutils-2.17-kernel-2.6.18/bin/../lib/gcc/arm-v5te-linux-gnueabi/4.1.2/include * /opt/gcc-4.1.2-glibc-2.5-binutils-2.17-kernel-2.6.18/bin/../sysroot-arm-v5te-linux-gnueabi/usr/include * End of search list. */ // regarding priority: // -iquote has the highest priority affecting #include "..." not only #include <...> // -I has lower priority than -iquote // -isystem has lower priority but yet higher priority than system-wide headers // then follows the priority of system-wide-headers // -idirafter has the lowest priority possible // example (gcc 9): /* * $ gcc -x c -c -Wp,-v -iquote /proc/1 -I /proc/10 -isystem /proc/12 -I /proc/14 -idirafter /proc/1204 - < /dev/null * ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu" * ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/include-fixed" * ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/../../../../x86_64-linux-gnu/include" #include "..." search starts here: * /proc/1 #include <...> search starts here: * /proc/10 * /proc/14 * /proc/12 * /usr/lib/gcc/x86_64-linux-gnu/9/include * /usr/local/include * /usr/include/x86_64-linux-gnu * /usr/include * /proc/1204 * End of search list. */ // usually gcc does not have any include directories in the #include "..." section. // so the reason for parsing this section is when using some compiler wrapper that puts some paths to -iquote. if (cppLine == "#include \"...\" search starts here:") { incDirType = IncludeDirectoryType.Quote; continue; } if (cppLine == "#include <...> search starts here:") { incDirType = IncludeDirectoryType.System; continue; } if (cppLine.Length > 0 && cppLine[0] == ' ') { Crosspath xpath = Crosspath.FromString(cppLine.Substring(1)); if (xpath is RelativeCrosspath relPath) { relPath.SetWorkingDirectory(xpwd); xpath = relPath.Absolutized(); } IncludeDirectory incDir = new IncludeDirectory(xpath as AbsoluteCrosspath, incDirType); IncludeDirectory incDirCached = BaseCompiler.TrackIncludeDir(incDir); if (incDirCached != null) { incDir = incDirCached; } IncludeDirectories.Add(incDir); continue; } if (cppLine == "End of search list.") { break; } } HaveAdditionalInfo = true; Logger.WriteLine(LogLevel.Info, $"{absExePath} {this} is {VSPlatform} compiler"); }
public void WriteToDirectory(String directory) { Directory.CreateDirectory(directory); String pwd = Directory.GetCurrentDirectory(); Directory.SetCurrentDirectory(directory); AbsoluteCrosspath solutionDir = AbsoluteCrosspath.GetCurrentDirectory(); foreach (Compiler compiler in solutionCompilers) { compiler.WriteToFile(solutionDir); } foreach (Project projectKvp in projects.Values) { // remember there will also be .vcxproj.filters projectKvp.WriteToFile(solutionDir); } // TODO: add them as "Solution Items" File.WriteAllText(SolutionStructure.ForcedIncludes.SolutionCompat, @"#pragma once"); File.WriteAllText(SolutionStructure.ForcedIncludes.SolutionPostCompat, templates.SolutionCompat); // regarding compiler_compat.h: // generate one file per compiler and reference them from projects // see Compiler.WriteToFile() instead File.WriteAllBytes(SolutionStructure.SolutionPropsFilename, templates.SolutionProps); // write .sln itself // using simple text generator using (StreamWriter sw = new StreamWriter(SolutionStructure.SolutionFilename, false, Encoding.UTF8)) { sw.WriteLine(""); sw.WriteLine("Microsoft Visual Studio Solution File, Format Version 12.00"); sw.WriteLine("# Visual Studio Version 16"); sw.WriteLine("VisualStudioVersion = 16.0.31613.86"); sw.WriteLine("MinimumVisualStudioVersion = 10.0.40219.1"); foreach (Project project in projects.Values) { if (project.Skip || project.CompilerInstance.BaseCompiler.Skip) { continue; } // this magic GUID is "Windows (Visual C++)" project type sw.WriteLine($"Project(\"{{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}}\") = \"{project.Name}\", \"{project.Filename}\", \"{{{project.Guid.ToString().ToUpper()}}}\""); sw.WriteLine("EndProject"); } // this magic GUID is "Solution Folder" sw.WriteLine($"Project(\"{{2150E333-8FDC-42A3-9474-1A3956D46DE8}}\") = \"Compat files\", \"Compat files\", \"{{{AllocateGuid()}}}\""); sw.WriteLine("\tProjectSection(SolutionItems) = preProject"); sw.WriteLine("\t\tsolution_compat.h = solution_compat.h"); sw.WriteLine("\t\tsolution_post_compiler_compat.h = solution_post_compiler_compat.h"); sw.WriteLine("\tEndProjectSection"); sw.WriteLine("EndProject"); sw.WriteLine("Global"); sw.WriteLine("GlobalSection(SolutionConfigurationPlatforms) = preSolution"); foreach (String cfg in SolutionStructure.SolutionConfigurations) { sw.WriteLine($"\t\t{cfg}|{SolutionStructure.SolutionPlatformName} = {cfg}|{SolutionStructure.SolutionPlatformName}"); } sw.WriteLine("EndGlobalSection"); sw.WriteLine("GlobalSection(ProjectConfigurationPlatforms) = postSolution"); String[] cfgStages = { "ActiveCfg", "Build.0", "Deploy.0" }; foreach (Project project in projects.Values) { if (project.Skip || project.CompilerInstance.BaseCompiler.Skip) { continue; } foreach (String cfg in SolutionStructure.SolutionConfigurations) { foreach (String cfgStage in cfgStages) { sw.WriteLine($"\t\t{{{project.Guid.ToString().ToUpper()}}}.{cfg}|{SolutionStructure.SolutionPlatformName}.{cfgStage} = {cfg}|{project.CompilerInstance.VSPlatform}"); } } } sw.WriteLine("\tEndGlobalSection"); sw.WriteLine("\tGlobalSection(SolutionProperties) = preSolution"); sw.WriteLine("\t\tHideSolutionNode = FALSE"); sw.WriteLine("\tEndGlobalSection"); sw.WriteLine("\tGlobalSection(ExtensibilityGlobals) = postSolution"); sw.WriteLine($"\t\tSolutionGuid = {{{selfGuid}}}"); sw.WriteLine("\tEndGlobalSection"); sw.WriteLine("EndGlobal"); sw.Close(); } Directory.SetCurrentDirectory(pwd); }
/// <summary> /// Writes compiler_${ShortName}.props and compiler_$(ShortName}_compat.h /// </summary> public void WriteToFile(AbsoluteCrosspath solutionDir) { if (BaseCompiler.Skip) { return; } AbsoluteCrosspath xpath = solutionDir.Appended(RelativeCrosspath.FromString(CompilerInstanceCompatHeaderPath)).ToContainingDirectory(); Directory.CreateDirectory(xpath.ToString()); using (StreamWriter sw = new StreamWriter(CompilerInstanceCompatHeaderPath, false, Encoding.UTF8)) { sw.WriteLine(@"#pragma once"); sw.WriteLine($"/* This is generated from compiler instance {BaseCompiler} {this} */"); foreach (Define compilerInternalDefine in Defines) { sw.WriteLine($"#define {compilerInternalDefine.Name} {compilerInternalDefine.Value}"); } } XmlDocument doc = new XmlDocument(); doc.AppendChild(doc.CreateXmlDeclaration("1.0", "utf-8", null)); XmlElement projectNode = doc.CreateElement("Project"); projectNode.SetAttribute("DefaultTargets", "Build"); projectNode.SetAttribute("ToolsVersion", "Current"); projectNode.SetAttribute("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003"); XmlElement projectImportProps = doc.CreateElement("Import"); projectImportProps.SetAttribute("Project", $@"$(SolutionDir)\{BaseCompiler.PropsFileName}"); projectNode.AppendChild(projectImportProps); // Platform settings /* * <ItemGroup Label="ProjectConfigurations"> * <ProjectConfiguration Include="Debug|x64"> * <Configuration>Debug</Configuration> * <Platform>x64</Platform> * </ProjectConfiguration> * <ProjectConfiguration Include="Release|x64"> * <Configuration>Release</Configuration> * <Platform>x64</Platform> * </ProjectConfiguration> * </ItemGroup> */ XmlElement projectItemGroupPlatform = doc.CreateElement("ItemGroup"); projectItemGroupPlatform.SetAttribute("Label", "ProjectConfigurations"); foreach (String buildConfiguration in SolutionStructure.SolutionConfigurations) { XmlElement projectPlatformConfiguration = doc.CreateElement("ProjectConfiguration"); projectPlatformConfiguration.SetAttribute("Include", $"{buildConfiguration}|{VSPlatform}"); XmlElement projectPlatformConfiguration_Configuration = doc.CreateElement("Configuration"); projectPlatformConfiguration_Configuration.InnerText = buildConfiguration; projectPlatformConfiguration.AppendChild(projectPlatformConfiguration_Configuration); XmlElement projectPlatformConfiguration_Platform = doc.CreateElement("Platform"); projectPlatformConfiguration_Platform.InnerText = VSPlatform.ToString(); projectPlatformConfiguration.AppendChild(projectPlatformConfiguration_Platform); projectItemGroupPlatform.AppendChild(projectPlatformConfiguration); } projectNode.AppendChild(projectItemGroupPlatform); // IDU settings XmlElement projectPropertyGroupIDU = doc.CreateElement("PropertyGroup"); XmlElement projectIncludePaths = doc.CreateElement("NMakeIncludeSearchPath"); // DONE: intermix project include directories with compiler include directories foreach (IncludeDirectory includePath in IncludeDirectories) { projectIncludePaths.InnerText += includePath.GetLocalProjectPath(solutionDir) + ";"; } projectIncludePaths.InnerText += "$(CompilerIncludeDirAfter);$(NMakeIncludeSearchPath)"; projectPropertyGroupIDU.AppendChild(projectIncludePaths); // maybe someday this will be helpful, but now it can be inherited from Solution.props XmlElement projectForcedIncludes = doc.CreateElement("NMakeForcedIncludes"); // DONE: add compiler compat header to forced includes projectForcedIncludes.InnerText = $@"$(SolutionDir)\solution_compat.h;$(SolutionDir)\{CompilerInstanceCompatHeaderPath};$(SolutionDir)\solution_post_compiler_compat.h"; projectPropertyGroupIDU.AppendChild(projectForcedIncludes); XmlElement compilerForcedIncludes = doc.CreateElement("CompilerCompat"); // DONE: add compiler compat header to forced includes compilerForcedIncludes.InnerText = $@"$(SolutionDir)\{CompilerInstanceCompatHeaderPath}"; projectPropertyGroupIDU.AppendChild(compilerForcedIncludes); projectNode.AppendChild(projectPropertyGroupIDU); doc.AppendChild(projectNode); doc.Save(PropsFileName); }
public IncludeDirectory(AbsoluteCrosspath path, IncludeDirectoryType type) : base(path) { Type = type; ShortName = $"{serial:D4}"; ++serial; }
public void AddInfoFromCommandLine(AbsoluteCrosspath workingDir, List <String> args) { // parse arguments to obtain all -I, -D, -U // start from 1 to skip compiler name for (Int32 i = 1; i < args.Count; i++) { // includes: // -I // -iquote // -isystem // -idirafter // ..., see https://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html // TODO: also process -nostdinc to control whether system include dirs should be added or not. // TODO: preserve priority between -I, -iquote and other include dir types IncludeDirectoryType idt = IncludeDirectoryType.Null; String includeDirStr = String.Empty; foreach (IncludeDirectoryType idk in IncludeDirectory.IncludeParam.Keys) { if (TakeParamValue(args, ref i, IncludeDirectory.IncludeParam[idk], out includeDirStr)) { idt = idk; break; } } if (idt != IncludeDirectoryType.Null) { // DONE: determine more accurately which include is local and which is remote // this is done with the use of Solution.Rebase() so we customly point to local files AbsoluteCrosspath includeDirPath = AbsoluteCrosspath.FromString(includeDirStr, workingDir); IncludeDirectory includeDir = OwnerSolution.TrackIncludeDirectory(includeDirPath, idt); // relax if we're adding the same include directory twice // TODO: rewrite this using PriorityQueue to preserver order this.AddIncludeDir(includeDir); continue; } // defines: // -D if (TakeParamValue(args, ref i, "-D", out String defineString)) { this.SetCppDefine(defineString); Logger.WriteLine(LogLevel.Trace, $"[i] Added -D{defineString}"); continue; } // undefines: // -U if (TakeParamValue(args, ref i, "-U", out String undefineString)) { this.UnsetCppDefine(undefineString); Logger.WriteLine(LogLevel.Trace, $"[i] Added -U{undefineString}"); continue; } if (TakeParamValue(args, ref i, "-include", out String forceInclude)) { AbsoluteCrosspath forceIncludePath = AbsoluteCrosspath.FromString(forceInclude, workingDir); ProjectFile forceIncludeProjectFile = this.OwnerSolution.TrackFile(new ProjectFile(OwnerSolution, forceIncludePath, this.CompilerOfFile), true); this.ForceIncludes.Add(forceIncludeProjectFile.FilePath); // ReSharper disable once RedundantJumpStatement continue; } } }
public void Rebase(AbsoluteCrosspath before, AbsoluteCrosspath after) { xpath.Rebase(before, after); }
public void Polymorphism() { Crosspath cpath = Crosspath.FromString(@"/"); AbsoluteCrosspath unused = cpath as AbsoluteCrosspath; RelativeCrosspath unused1 = cpath as RelativeCrosspath; }
/// <summary> /// /// </summary> /// <param name="remote">Remote host to download from</param> /// <param name="localXpath">Local directory for remote include directories, e.g. D:\Project1\remote\192.168.0.1.</param> public void RebaseToLocal(RemoteHost remote, AbsoluteCrosspath localXpath) { if (this.Flavor == CrosspathFlavor.Windows) { return; } int xtractBufSize = 65536; Byte[] zipExtractBuf = new Byte[xtractBufSize]; String remoteFilename = $"/tmp/{ShortName}.zip"; String localDirectoryPattern = $@"include\{ShortName}"; String localFilenamePattern = $"{ShortName}.zip"; AbsoluteCrosspath xLocalIncludeDirectory = localXpath.Appended(RelativeCrosspath.FromString(localDirectoryPattern)); String localIncludeDirectory = xLocalIncludeDirectory.ToString(); String localFilename = localXpath.Appended(RelativeCrosspath.FromString(localFilenamePattern)).ToString(); Logger.WriteLine(LogLevel.Info, $"Rolling {this} into {localFilenamePattern}..."); Directory.CreateDirectory(localIncludeDirectory); if (remote.Execute($"pushd {this} && zip -1 -r -q {remoteFilename} . && popd", out String result) != RemoteHost.Success) { Logger.WriteLine(LogLevel.Error, result); // FIXME, hack this.Rebase(this, xLocalIncludeDirectory); autoDownloaded = true; return; } remote.DownloadFile(remoteFilename, localFilename); File.WriteAllText(xLocalIncludeDirectory.Appended(RelativeCrosspath.FromString($@"..\{ShortName}_origin.txt")).ToString(), this.ToString()); // not working bcz of NTFS case & special names restrictions. extract manually. //ZipFile.ExtractToDirectory(localFilename, localDirectory, Encoding.UTF8); using (FileStream fs = new FileStream(localFilename, FileMode.Open)) { ZipArchive za = new ZipArchive(fs, ZipArchiveMode.Read); foreach (ZipArchiveEntry zaEntry in za.Entries) { RelativeCrosspath xRelPath = RelativeCrosspath.FromString(zaEntry.FullName); AbsoluteCrosspath xPath = xLocalIncludeDirectory.Appended(xRelPath); if (zaEntry.FullName.EndsWith("/")) { // packed directory continue; } String path = xPath.ToString(); if (File.Exists(path)) { Logger.WriteLine(LogLevel.Warning, $"file '{zaEntry.FullName}' already exists as '{path}' - case problems?"); continue; } // hax, remove leading / from path if (xRelPath.ToString() == Compiler.RemoteTempFile.Substring(1)) { continue; } String dirname = new AbsoluteCrosspath(xPath).ToContainingDirectory().ToString(); try { Directory.CreateDirectory(dirname); // packed file using (FileStream xfs = new FileStream(path, FileMode.CreateNew)) { using (Stream zas = zaEntry.Open()) { while (true) { int len = zas.Read(zipExtractBuf, 0, xtractBufSize); if (len == 0) { // EOF break; } xfs.Write(zipExtractBuf, 0, len); } zas.Close(); } } } catch (Exception e) { Logger.WriteLine(LogLevel.Error, $"Could not extract '${zaEntry.FullName}': ${e.Message}"); } } } // if extraction went ok, we can remove files remote.Execute($"rm {remoteFilename}", out String _); File.Delete(localFilename); // since we definitely have a local copy of include directory, rebase on it this.Rebase(this, xLocalIncludeDirectory); autoDownloaded = true; }
public void ParseCompileDB(String filename) { // hope compiledb is not so large to eat all the memory String compiledbRaw = File.ReadAllText(filename); List <CompileDBEntry> entries = JsonConvert.DeserializeObject <List <CompileDBEntry> >(compiledbRaw); foreach (CompileDBEntry entry in entries) { // get full file path AbsoluteCrosspath workingDir = AbsoluteCrosspath.FromString(entry.directory); AbsoluteCrosspath xpath = AbsoluteCrosspath.FromString(entry.file, workingDir); // TODO: filter out entries by include and exclude lists // get compiler path // it can be absolute or relative Crosspath compilerPath = Crosspath.FromString(entry.arguments[0]); // TODO: filter out compilers by include and exclude lists Compiler compiler = null; foreach (Compiler solutionCompiler in solutionCompilers) { if (solutionCompiler.ExePath.ToString().Equals(compilerPath.ToString())) { // already registered compiler = solutionCompiler; break; } } if (compiler == null) { compiler = new Compiler(compilerPath); if (solutionCompilers.Add(compiler)) { Logger.WriteLine(LogLevel.Info, $"New compiler '{compiler.ExePath}'"); } } CompilerInstance compilerInstance = null; CompilerInstance compilerInstanceTmp = new CompilerInstance(compiler, entry.arguments); foreach (CompilerInstance compilerInstanceInUse in compiler.Instances) { if (compilerInstanceInUse.Equals(compilerInstanceTmp)) { compilerInstance = compilerInstanceInUse; break; } } if (compilerInstance == null) { compilerInstance = compilerInstanceTmp; compiler.Instances.Add(compilerInstanceTmp); Logger.WriteLine(LogLevel.Info, $"New compiler instance '{compilerInstanceTmp.BaseCompiler.ExePath} {compilerInstanceTmp}'"); } ProjectFile pf = new ProjectFile(this, xpath, compilerInstance); Logger.WriteLine(LogLevel.Trace, $"===== file {xpath} ====="); pf.AddInfoFromCommandLine(workingDir, entry.arguments); // put global override defines silently // TODO: write them to solution-wide props foreach (Define define in config.OverrideDefines) { pf.UnsetCppDefine(define.Name); pf.SetCppDefine(define.ToString()); } // add to project files now? //pf.DumpData(); Int64 projectHash = pf.HashProjectID(); if (!projects.ContainsKey(projectHash)) { projects.Add(projectHash, new Project(AllocateGuid(), projectHash, this, compilerInstance, pf.IncludeDirectories, pf.SetOfDefines, pf.ForceIncludes)); } // add file to project if (!projects[projectHash].TestWhetherProjectFileBelongs(pf)) { throw new ApplicationException( $"[x] Could not add '{pf.FilePath}' to project '{projectHash}' - hash function error"); } if (!projects[projectHash].AddProjectFile(pf)) { //throw new ApplicationException( // $"[x] Could not add '{pf.FilePath}' to project '{projectHash}' - already exists"); Logger.WriteLine(LogLevel.Error, $"[x] Could not add '{pf}' to project '{projectHash}' - already exists"); } TrackFile(pf); } Logger.WriteLine(LogLevel.Info, $"[i] Created a solution of {projects.Count} projects from {solutionFiles.Count} files"); if (Logger.Level == LogLevel.Trace) { foreach (var projectKvp in projects) { Logger.WriteLine(LogLevel.Trace, $"# Project ID {projectKvp.Key}"); foreach (var file in projectKvp.Value.ProjectFiles) { Logger.WriteLine(LogLevel.Trace, $"# > {file.FilePath}"); } using (var enumerator = projectKvp.Value.ProjectFiles.GetEnumerator()) { if (!enumerator.MoveNext()) { break; } if (enumerator.Current != null) { enumerator.Current.DumpData(); } } Logger.WriteLine(LogLevel.Trace, "============================================"); } } }