/// <summary> /// Attempts to get the SSH private key from the standard locations /// </summary> /// <param name="OutPrivateKey">If successful, receives the location of the private key that was found</param> /// <returns>True if a private key was found, false otherwise</returns> private bool TryGetSshPrivateKey(out FileReference OutPrivateKey) { // Build a list of all the places to look for a private key List <DirectoryReference> Locations = new List <DirectoryReference>(); Locations.Add(DirectoryReference.Combine(DirectoryReference.GetSpecialFolder(Environment.SpecialFolder.ApplicationData), "Unreal Engine", "UnrealBuildTool")); Locations.Add(DirectoryReference.Combine(DirectoryReference.GetSpecialFolder(Environment.SpecialFolder.Personal), "Unreal Engine", "UnrealBuildTool")); if (ProjectFile != null) { Locations.Add(DirectoryReference.Combine(ProjectFile.Directory, "Build", "NotForLicensees")); Locations.Add(DirectoryReference.Combine(ProjectFile.Directory, "Build", "NoRedist")); Locations.Add(DirectoryReference.Combine(ProjectFile.Directory, "Build")); } Locations.Add(DirectoryReference.Combine(UnrealBuildTool.EngineDirectory, "Build", "NotForLicensees")); Locations.Add(DirectoryReference.Combine(UnrealBuildTool.EngineDirectory, "Build", "NoRedist")); Locations.Add(DirectoryReference.Combine(UnrealBuildTool.EngineDirectory, "Build")); // Find the first that exists foreach (DirectoryReference Location in Locations) { FileReference KeyFile = FileReference.Combine(Location, "SSHKeys", ServerName, UserName, "RemoteToolChainPrivate.key"); if (FileReference.Exists(KeyFile)) { OutPrivateKey = KeyFile; return(true); } } // Nothing found OutPrivateKey = null; return(false); }
/// <summary> /// Gets the path to the linker. /// </summary> static FileReference GetLinkerToolPath(UnrealTargetPlatform Platform, WindowsCompiler Compiler, DirectoryReference DefaultLinkerDir) { // If we were asked to use Clang, then we'll redirect the path to the compiler to the LLVM installation directory if (Compiler == WindowsCompiler.Clang && WindowsPlatform.bAllowClangLinker) { FileReference LinkerPath = FileReference.Combine(DirectoryReference.GetSpecialFolder(Environment.SpecialFolder.ProgramFiles), "LLVM", "bin", "lld.exe"); if (FileReference.Exists(LinkerPath)) { return(LinkerPath); } FileReference LinkerPathX86 = FileReference.Combine(DirectoryReference.GetSpecialFolder(Environment.SpecialFolder.ProgramFilesX86), "LLVM", "bin", "lld.exe"); if (FileReference.Exists(LinkerPathX86)) { return(LinkerPathX86); } throw new BuildException("Clang was selected as the Windows compiler, but {0} and {1} were not found.", LinkerPath, LinkerPathX86); } else if (Compiler == WindowsCompiler.Intel && WindowsPlatform.bAllowICLLinker) { FileReference LinkerPath = FileReference.Combine(DirectoryReference.GetSpecialFolder(Environment.SpecialFolder.ProgramFilesX86), "IntelSWTools", "compilers_and_libraries", "windows", "bin", (Platform == UnrealTargetPlatform.Win32)? "ia32" : "intel64", "xilink.exe"); if (FileReference.Exists(LinkerPath)) { return(LinkerPath); } throw new BuildException("ICL was selected as the Windows compiler, but {0} was not found.", LinkerPath); } else { return(FileReference.Combine(DefaultLinkerDir, "link.exe")); } }
/// <summary> /// Gets the path to the library linker. /// </summary> static FileReference GetLibraryLinkerToolPath(UnrealTargetPlatform Platform, WindowsCompiler Compiler, DirectoryReference DefaultLinkerDir) { // Regardless of the target, if we're linking on a 64 bit machine, we want to use the 64 bit linker (it's faster than the 32 bit linker) if (Compiler == WindowsCompiler.Intel && WindowsPlatform.bAllowICLLinker) { FileReference LibPath = FileReference.Combine(DirectoryReference.GetSpecialFolder(Environment.SpecialFolder.ProgramFilesX86), "IntelSWTools", "compilers_and_libraries", "windows", "bin", Platform == UnrealTargetPlatform.Win32 ? "ia32" : "intel64", "xilib.exe"); if (FileReference.Exists(LibPath)) { return(LibPath); } throw new BuildException("ICL was selected as the Windows compiler, but does not appear to be installed. Could not find: " + LibPath); } else { return(FileReference.Combine(DefaultLinkerDir, "lib.exe")); } }
/// <summary> /// Constructor /// </summary> /// <param name="ProjectFile">Project to read settings from</param> public RemoteMac(FileReference ProjectFile) { this.RsyncExe = FileReference.Combine(UnrealBuildTool.EngineDirectory, "Extras", "ThirdPartyNotUE", "DeltaCopy", "Binaries", "Rsync.exe"); this.SshExe = FileReference.Combine(UnrealBuildTool.EngineDirectory, "Extras", "ThirdPartyNotUE", "DeltaCopy", "Binaries", "Ssh.exe"); this.ProjectFile = ProjectFile; this.ProjectDirectory = DirectoryReference.FromFile(ProjectFile); // Apply settings from the XML file XmlConfig.ApplyTo(this); // Get the project config file path DirectoryReference EngineIniPath = ProjectFile != null ? ProjectFile.Directory : null; if (EngineIniPath == null && UnrealBuildTool.GetRemoteIniPath() != null) { EngineIniPath = new DirectoryReference(UnrealBuildTool.GetRemoteIniPath()); } ConfigHierarchy Ini = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, EngineIniPath, UnrealTargetPlatform.IOS); // Read the project settings if we don't have anything in the build configuration settings if (String.IsNullOrEmpty(ServerName)) { // Read the server name string IniServerName; if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "RemoteServerName", out IniServerName) && !String.IsNullOrEmpty(IniServerName)) { this.ServerName = IniServerName; } else { throw new BuildException("Remote compiling requires a server name. Use the editor (Project Settings > IOS) to set up your remote compilation settings."); } // Parse the username string IniUserName; if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "RSyncUsername", out IniUserName) && !String.IsNullOrEmpty(IniUserName)) { this.UserName = IniUserName; } } // Split port out from the server name int PortIdx = ServerName.LastIndexOf(':'); if (PortIdx != -1) { string Port = ServerName.Substring(PortIdx + 1); if (!int.TryParse(Port, out ServerPort)) { throw new BuildException("Unable to parse port number from '{0}'", ServerName); } ServerName = ServerName.Substring(0, PortIdx); } // If a user name is not set, use the current user if (String.IsNullOrEmpty(UserName)) { UserName = Environment.UserName; } // Print out the server info Log.TraceInformation("[Remote] Using remote server '{0}' on port {1} (user '{2}')", ServerName, ServerPort, UserName); // Get the path to the SSH private key string OverrideSshPrivateKeyPath; if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "SSHPrivateKeyOverridePath", out OverrideSshPrivateKeyPath) && !String.IsNullOrEmpty(OverrideSshPrivateKeyPath)) { SshPrivateKey = new FileReference(OverrideSshPrivateKeyPath); if (!FileReference.Exists(SshPrivateKey)) { throw new BuildException("SSH private key specified in config file ({0}) does not exist.", SshPrivateKey); } } // If it's not set, look in the standard locations. If that fails, spawn the batch file to generate one. if (SshPrivateKey == null && !TryGetSshPrivateKey(out SshPrivateKey)) { Log.TraceWarning("No SSH private key found for {0}@{1}. Launching SSH to generate one.", UserName, ServerName); StringBuilder CommandLine = new StringBuilder(); CommandLine.AppendFormat("/C \"\"{0}\"", FileReference.Combine(UnrealBuildTool.EngineDirectory, "Build", "BatchFiles", "MakeAndInstallSSHKey.bat")); CommandLine.AppendFormat(" \"{0}\"", SshExe); CommandLine.AppendFormat(" \"{0}\"", ServerPort); CommandLine.AppendFormat(" \"{0}\"", RsyncExe); CommandLine.AppendFormat(" \"{0}\"", UserName); CommandLine.AppendFormat(" \"{0}\"", ServerName); CommandLine.AppendFormat(" \"{0}\"", DirectoryReference.GetSpecialFolder(Environment.SpecialFolder.MyDocuments)); CommandLine.AppendFormat(" \"{0}\"", GetLocalCygwinPath(DirectoryReference.GetSpecialFolder(Environment.SpecialFolder.MyDocuments))); CommandLine.AppendFormat(" \"{0}\"", UnrealBuildTool.EngineDirectory); CommandLine.Append("\""); using (Process ChildProcess = Process.Start("C:\\Windows\\System32\\Cmd.exe", CommandLine.ToString())) { ChildProcess.WaitForExit(); } if (!TryGetSshPrivateKey(out SshPrivateKey)) { throw new BuildException("Failed to generate SSH private key for {0}@{1}.", UserName, ServerName); } } // resolve the rest of the strings RsyncAuthentication = ExpandVariables(RsyncAuthentication); SshAuthentication = ExpandVariables(SshAuthentication); // Get the remote base directory RemoteBaseDir = String.Format("/Users/{0}/UE4/Builds/{1}", UserName, Environment.MachineName); // Build the list of directory mappings between the local and remote machines Mappings = new List <RemoteMapping>(); Mappings.Add(new RemoteMapping(UnrealBuildTool.EngineDirectory, GetRemotePath(UnrealBuildTool.EngineDirectory))); if (ProjectFile != null && !ProjectFile.IsUnderDirectory(UnrealBuildTool.EngineDirectory)) { Mappings.Add(new RemoteMapping(ProjectFile.Directory, GetRemotePath(ProjectFile.Directory))); } // Build a list of arguments for SSH CommonSshArguments = new List <string>(); CommonSshArguments.Add("-o BatchMode=yes"); CommonSshArguments.Add(SshAuthentication); CommonSshArguments.Add(String.Format("-p {0}", ServerPort)); CommonSshArguments.Add(String.Format("\"{0}@{1}\"", UserName, ServerName)); // Build a list of arguments for Rsync CommonRsyncArguments = new List <string>(); CommonRsyncArguments.Add("--compress"); CommonRsyncArguments.Add("--recursive"); CommonRsyncArguments.Add("--delete"); // Delete anything not in the source directory CommonRsyncArguments.Add("--delete-excluded"); // Delete anything not in the source directory CommonRsyncArguments.Add("--times"); // Preserve modification times CommonRsyncArguments.Add("--verbose"); CommonRsyncArguments.Add("-m"); CommonRsyncArguments.Add("--chmod=ug=rwX,o=rxX"); CommonRsyncArguments.Add(String.Format("--rsh=\"{0} -p {1}\"", RsyncAuthentication, ServerPort)); }
protected IOSProvisioningData(IOSProjectSettings ProjectSettings, bool bIsTVOS, bool bForDistribtion) { SigningCertificate = ProjectSettings.SigningCertificate; string MobileProvision = ProjectSettings.MobileProvision; FileReference ProjectFile = ProjectSettings.ProjectFile; if (!string.IsNullOrEmpty(SigningCertificate)) { // verify the certificate Process IPPProcess = new Process(); if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac) { string IPPCmd = "\"" + UnrealBuildTool.EngineDirectory + "/Binaries/DotNET/IOS/IPhonePackager.exe\" certificates " + ((ProjectFile != null) ? ("\"" + ProjectFile.ToString() + "\"") : "Engine") + " -bundlename " + ProjectSettings.BundleIdentifier + (bForDistribtion ? " -distribution" : ""); IPPProcess.StartInfo.WorkingDirectory = UnrealBuildTool.EngineDirectory.ToString(); IPPProcess.StartInfo.FileName = UnrealBuildTool.EngineDirectory + "/Build/BatchFiles/Mac/RunMono.sh"; IPPProcess.StartInfo.Arguments = IPPCmd; IPPProcess.OutputDataReceived += new DataReceivedEventHandler(IPPDataReceivedHandler); IPPProcess.ErrorDataReceived += new DataReceivedEventHandler(IPPDataReceivedHandler); } else { string IPPCmd = "certificates " + ((ProjectFile != null) ? ("\"" + ProjectFile.ToString() + "\"") : "Engine") + " -bundlename " + ProjectSettings.BundleIdentifier + (bForDistribtion ? " -distribution" : ""); IPPProcess.StartInfo.WorkingDirectory = UnrealBuildTool.EngineDirectory.ToString(); IPPProcess.StartInfo.FileName = UnrealBuildTool.EngineDirectory + "\\Binaries\\DotNET\\IOS\\IPhonePackager.exe"; IPPProcess.StartInfo.Arguments = IPPCmd; IPPProcess.OutputDataReceived += new DataReceivedEventHandler(IPPDataReceivedHandler); IPPProcess.ErrorDataReceived += new DataReceivedEventHandler(IPPDataReceivedHandler); } Utils.RunLocalProcess(IPPProcess); } else { SigningCertificate = bForDistribtion ? "iPhone Distribution" : "iPhone Developer"; bHaveCertificate = true; } if (!string.IsNullOrEmpty(MobileProvision)) { DirectoryReference MobileProvisionDir; if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac) { MobileProvisionDir = DirectoryReference.Combine(new DirectoryReference(Environment.GetEnvironmentVariable("HOME")), "Library", "MobileDevice", "Provisioning Profiles"); } else { MobileProvisionDir = DirectoryReference.Combine(DirectoryReference.GetSpecialFolder(Environment.SpecialFolder.LocalApplicationData), "Apple Computer", "MobileDevice", "Provisioning Profiles"); } FileReference PossibleMobileProvisionFile = FileReference.Combine(MobileProvisionDir, MobileProvision); if (FileReference.Exists(PossibleMobileProvisionFile)) { MobileProvisionFile = PossibleMobileProvisionFile; } } if (MobileProvisionFile == null || !bHaveCertificate) { SigningCertificate = ""; MobileProvision = ""; MobileProvisionFile = null; Log.TraceLog("Provision not specified or not found for " + ((ProjectFile != null) ? ProjectFile.GetFileNameWithoutAnyExtensions() : "UE4Game") + ", searching for compatible match..."); Process IPPProcess = new Process(); if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac) { string IPPCmd = "\"" + UnrealBuildTool.EngineDirectory + "/Binaries/DotNET/IOS/IPhonePackager.exe\" signing_match " + ((ProjectFile != null) ? ("\"" + ProjectFile.ToString() + "\"") : "Engine") + " -bundlename " + ProjectSettings.BundleIdentifier + (bIsTVOS ? " -tvos" : "") + (bForDistribtion ? " -distribution" : ""); IPPProcess.StartInfo.WorkingDirectory = UnrealBuildTool.EngineDirectory.ToString(); IPPProcess.StartInfo.FileName = UnrealBuildTool.EngineDirectory + "/Build/BatchFiles/Mac/RunMono.sh"; IPPProcess.StartInfo.Arguments = IPPCmd; IPPProcess.OutputDataReceived += new DataReceivedEventHandler(IPPDataReceivedHandler); IPPProcess.ErrorDataReceived += new DataReceivedEventHandler(IPPDataReceivedHandler); } else { string IPPCmd = "signing_match " + ((ProjectFile != null) ? ("\"" + ProjectFile.ToString() + "\"") : "Engine") + " -bundlename " + ProjectSettings.BundleIdentifier + (bIsTVOS ? " -tvos" : "") + (bForDistribtion ? " -distribution" : ""); IPPProcess.StartInfo.WorkingDirectory = UnrealBuildTool.EngineDirectory.ToString(); IPPProcess.StartInfo.FileName = UnrealBuildTool.EngineDirectory + "\\Binaries\\DotNET\\IOS\\IPhonePackager.exe"; IPPProcess.StartInfo.Arguments = IPPCmd; IPPProcess.OutputDataReceived += new DataReceivedEventHandler(IPPDataReceivedHandler); IPPProcess.ErrorDataReceived += new DataReceivedEventHandler(IPPDataReceivedHandler); } Utils.RunLocalProcess(IPPProcess); if (MobileProvisionFile != null) { Log.TraceLog("Provision found for " + ((ProjectFile != null) ? ProjectFile.GetFileNameWithoutAnyExtensions() : "UE4Game") + ", Provision: " + MobileProvisionFile + " Certificate: " + SigningCertificate); } } // add to the dictionary SigningCertificate = SigningCertificate.Replace("\"", ""); // read the provision to get the UUID if (MobileProvisionFile == null) { Log.TraceLog("No matching provision file was discovered for {0}. Please ensure you have a compatible provision installed.", ProjectFile); } else if (!FileReference.Exists(MobileProvisionFile)) { Log.TraceLog("Selected mobile provision for {0} ({1}) was not found. Please ensure you have a compatible provision installed.", ProjectFile, MobileProvisionFile); } else { byte[] AllBytes = FileReference.ReadAllBytes(MobileProvisionFile); uint StartIndex = (uint)AllBytes.Length; uint EndIndex = (uint)AllBytes.Length; for (uint i = 0; i + 4 < AllBytes.Length; i++) { if (AllBytes[i] == '<' && AllBytes[i + 1] == '?' && AllBytes[i + 2] == 'x' && AllBytes[i + 3] == 'm' && AllBytes[i + 4] == 'l') { StartIndex = i; break; } } if (StartIndex < AllBytes.Length) { for (uint i = StartIndex; i + 7 < AllBytes.Length; i++) { if (AllBytes[i] == '<' && AllBytes[i + 1] == '/' && AllBytes[i + 2] == 'p' && AllBytes[i + 3] == 'l' && AllBytes[i + 4] == 'i' && AllBytes[i + 5] == 's' && AllBytes[i + 6] == 't' && AllBytes[i + 7] == '>') { EndIndex = i + 7; break; } } } if (StartIndex < AllBytes.Length && EndIndex < AllBytes.Length) { byte[] TextBytes = new byte[EndIndex - StartIndex]; Buffer.BlockCopy(AllBytes, (int)StartIndex, TextBytes, 0, (int)(EndIndex - StartIndex)); string AllText = Encoding.UTF8.GetString(TextBytes); int idx = AllText.IndexOf("<key>UUID</key>"); if (idx > 0) { idx = AllText.IndexOf("<string>", idx); if (idx > 0) { idx += "<string>".Length; MobileProvisionUUID = AllText.Substring(idx, AllText.IndexOf("</string>", idx) - idx); } } idx = AllText.IndexOf("<key>com.apple.developer.team-identifier</key>"); if (idx > 0) { idx = AllText.IndexOf("<string>", idx); if (idx > 0) { idx += "<string>".Length; TeamUUID = AllText.Substring(idx, AllText.IndexOf("</string>", idx) - idx); } } idx = AllText.IndexOf("<key>Name</key>"); if (idx > 0) { idx = AllText.IndexOf("<string>", idx); if (idx > 0) { idx += "<string>".Length; MobileProvisionName = AllText.Substring(idx, AllText.IndexOf("</string>", idx) - idx); } } } if (string.IsNullOrEmpty(MobileProvisionUUID) || string.IsNullOrEmpty(TeamUUID)) { MobileProvision = null; SigningCertificate = null; Log.TraceLog("Failed to parse the mobile provisioning profile."); } } }