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 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 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); }
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); }
/// <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; }
/// <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); }
/// <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"); }