public static void Generate(IProgressMonitor monitor, BuildResult result, MonobjcProject project, ConfigurationSelector configuration, String outputDirectory, bool native) { // Infer application name from configuration String applicationName = project.GetApplicationName(configuration); LoggingService.LogInfo("Generate => applicationName='" + applicationName + "'"); LoggingService.LogInfo("Generate => outputDirectory='" + outputDirectory + "'"); // Create the bundle maker BundleMaker maker = new BundleMaker(applicationName, outputDirectory); // Compile the XIB files BuildHelper.CompileXIBFiles(monitor, project, maker, result); if (result.ErrorCount > 0) { monitor.ReportError(GettextCatalog.GetString("Failed to compile XIB files"), null); return; } // Copy the output and dependencies BuildHelper.CopyOutputFiles(monitor, project, configuration, maker); // Copy the content files BuildHelper.CopyContentFiles(monitor, project, configuration, maker); // Create the Info.plist BuildHelper.CreateInfoPList(monitor, project, configuration, maker); if (native) { GenerateNative(monitor, result, project, configuration, maker); } else { // Copy the Monobjc assemblies BuildHelper.CopyMonobjcAssemblies(monitor, project, configuration, maker); // Write the native runtime monitor.BeginTask(GettextCatalog.GetString("Copying native launcher..."), 0); maker.WriteRuntime(project.TargetOSVersion); monitor.EndTask(); } BuildHelper.CombineArtwork(monitor, project, maker); BuildHelper.EncryptContentFiles(monitor, project, configuration, maker); // Perform the signing BuildHelper.SignBundle(monitor, project, maker); BuildHelper.SignNativeBinaries(monitor, project, maker); }
public static void Archive(IProgressMonitor monitor, BuildResult result, MonobjcProject project, ConfigurationSelector configuration, String outputDirectory) { monitor.BeginTask(GettextCatalog.GetString("Archiving..."), 0); // Infer application name from configuration String applicationName = project.GetApplicationName(configuration); // Create the bundle maker BundleMaker maker = new BundleMaker(applicationName, outputDirectory); // Archive the application BuildHelper.ArchiveBundle(monitor, project, maker); monitor.EndTask(); }
/// <summary> /// Combines the artwork. /// </summary> public static void CombineArtwork(IProgressMonitor monitor, MonobjcProject project, BundleMaker maker) { if (!project.CombineArtwork) { return; } monitor.BeginTask (GettextCatalog.GetString ("Combining artwork..."), 0); using (StringWriter outputWriter = new StringWriter()) { using (StringWriter errorWriter = new StringWriter()) { ArtworkCombiner combiner = new ArtworkCombiner(); combiner.Combine(maker.ResourcesFolder, outputWriter, errorWriter); LoggingService.LogInfo ("Combiner returns: " + outputWriter.ToString ()); } } monitor.EndTask (); }
/// <summary> /// Archive the application bundle. /// </summary> /// <param name = 'monitor'>The progress monitor.</param> /// <param name = 'project'>The project.</param> /// <param name = 'maker'>The bundle maker.</param> public static void ArchiveBundle(IProgressMonitor monitor, MonobjcProject project, BundleMaker maker) { if (project.Archive && project.ArchiveIdentity != null) { FilePath definitionFile = project.BaseDirectory.Combine ("Definition.plist"); String definitionFilename = File.Exists (definitionFile) ? definitionFile.ToString () : null; monitor.BeginTask (GettextCatalog.GetString ("Signing archive..."), 0); using (StringWriter outputWriter = new StringWriter()) { using (StringWriter errorWriter = new StringWriter()) { ProductBuild.ArchiveApplication (maker.ApplicationDirectory, project.ArchiveIdentity, definitionFilename, outputWriter, errorWriter); LoggingService.LogInfo ("ProductBuild returns: " + outputWriter.ToString ()); } } monitor.EndTask (); } }
/// <summary> /// Compiles the XIB files. /// </summary> /// <param name = 'monitor'>The progress monitor.</param> /// <param name = 'project'>The project.</param> /// <param name = 'maker'>The bundle maker.</param> /// <param name = 'result'>The build result.</param> public static void CompileXIBFiles(IProgressMonitor monitor, MonobjcProject project, BundleMaker maker, BuildResult result) { XibCompiler xibCompiler = new XibCompiler (); IEnumerable<FilePair> files = project.GetIBFiles (Constants.InterfaceDefinition, maker.ResourcesFolder); if (files == null || files.Count() == 0) { return; } List<FilePair> pairs = new List<FilePair> (files); monitor.BeginTask (GettextCatalog.GetString ("Compiling XIB files..."), files.Count ()); foreach (FilePair pair in pairs) { monitor.Log.WriteLine (GettextCatalog.GetString ("Compiling {0}", pair.Source.ToRelative (project.BaseDirectory))); xibCompiler.Logger = new BuildLogger (pair.Source, monitor, result); xibCompiler.Compile (pair.Source, pair.DestinationDir); monitor.Step (1); } monitor.EndTask (); }
/// <summary> /// Sign the native libraries inside the bundle. /// </summary> /// <param name = 'monitor'>The progress monitor.</param> /// <param name = 'project'>The project.</param> /// <param name = 'maker'>The bundle maker.</param> public static void SignNativeBinaries(IProgressMonitor monitor, MonobjcProject project, BundleMaker maker) { if (project.Signing && !String.IsNullOrEmpty(project.SigningIdentity)) { String[] files = Directory.GetFiles (maker.MacOSDirectory, "*.dylib"); if (files == null || files.Count() == 0) { return; } monitor.BeginTask (GettextCatalog.GetString ("Signing native libraries..."), files.Length); foreach (String file in files) { using (StringWriter outputWriter = new StringWriter()) { using (StringWriter errorWriter = new StringWriter()) { CodeSign.PerformSigning (file, project.SigningIdentity, outputWriter, errorWriter); LoggingService.LogInfo ("CodeSign returns: " + outputWriter.ToString ()); } } monitor.Step (1); } monitor.EndTask (); } }
/// <summary> /// Sign the application bundle. /// </summary> /// <param name = 'monitor'>The progress monitor.</param> /// <param name = 'project'>The project.</param> /// <param name = 'maker'>The bundle maker.</param> public static void SignBundle(IProgressMonitor monitor, MonobjcProject project, BundleMaker maker) { if (project.Signing && !String.IsNullOrEmpty(project.SigningIdentity)) { monitor.BeginTask (GettextCatalog.GetString ("Signing bundle..."), 0); using (StringWriter outputWriter = new StringWriter()) { using (StringWriter errorWriter = new StringWriter()) { FilePath file = project.BaseDirectory.Combine(Constants.APP_ENTITLEMENTS); if (project.UseEntitlements && File.Exists(file)) { monitor.Log.WriteLine (GettextCatalog.GetString ("Signing with identity '{0}' and entitlements '{1}'", project.SigningIdentity, file.FileName)); CodeSign.PerformSigning (maker.ApplicationDirectory, project.SigningIdentity, file, outputWriter, errorWriter); } else { monitor.Log.WriteLine (GettextCatalog.GetString ("Signing with identity='{0}'", project.SigningIdentity)); CodeSign.PerformSigning (maker.ApplicationDirectory, project.SigningIdentity, outputWriter, errorWriter); } LoggingService.LogInfo ("CodeSign returns: " + outputWriter.ToString ()); } } monitor.EndTask (); } }
/// <summary> /// Combines the artwork. /// </summary> public static void EncryptContentFiles(IProgressMonitor monitor, MonobjcProject project, ConfigurationSelector configuration, BundleMaker maker) { IEnumerable<FilePair> files = project.GetEncryptedContentFiles (configuration, maker.ResourcesFolder); if (files == null || files.Count() == 0) { return; } Aes provider = FileEncrypter.GetProvider (project.EncryptionSeed); monitor.BeginTask (GettextCatalog.GetString ("Encrypting content files..."), files.Count ()); foreach (FilePair pair in files) { monitor.Log.WriteLine (GettextCatalog.GetString ("Encrypting {0}", pair.Source.ToRelative (project.BaseDirectory))); pair.Encrypt(provider); monitor.Step (1); } monitor.EndTask (); }
/// <summary> /// Creates the Info.plist file. /// </summary> /// <param name = 'monitor'>The progress monitor.</param> /// <param name = 'project'>The project.</param> /// <param name = 'configuration'>The configuration.</param> /// <param name = 'maker'>The bundle maker.</param> public static void CreateInfoPList(IProgressMonitor monitor, MonobjcProject project, ConfigurationSelector configuration, BundleMaker maker) { monitor.BeginTask (GettextCatalog.GetString ("Generating the Info.plist..."), 0); InfoPListGenerator pListGenerator = new InfoPListGenerator (); // If an Info.plist exists in the project then use it FilePath infoPListFile = project.BaseDirectory.Combine (Constants.INFO_PLIST); if (File.Exists (infoPListFile)) { pListGenerator.Content = File.ReadAllText (infoPListFile); } String mainAssembly = project.GetOutputFileName (configuration); Assembly assembly = Assembly.ReflectionOnlyLoadFrom (mainAssembly); AssemblyName assemblyName = assembly.GetName (); // TODO: Review to use new parameters pListGenerator.DevelopmentRegion = project.DevelopmentRegion; pListGenerator.ApplicationName = assemblyName.Name; pListGenerator.Identifier = project.BundleId; pListGenerator.Version = project.BundleVersion; pListGenerator.Icon = project.BundleIcon.IsNullOrEmpty ? null : project.BundleIcon.FileNameWithoutExtension; pListGenerator.MainNibFile = project.MainNibFile.IsNullOrEmpty ? null : project.MainNibFile.FileNameWithoutExtension; pListGenerator.TargetOSVersion = project.TargetOSVersion; pListGenerator.PrincipalClass = "NSApplication"; pListGenerator.WriteTo (Path.Combine (maker.ContentsDirectory, Constants.INFO_PLIST)); monitor.EndTask (); }
/// <summary> /// Copies the content files. /// </summary> /// <param name = 'monitor'>The progress monitor.</param> /// <param name = 'project'>The project.</param> /// <param name = 'configuration'>The configuration.</param> /// <param name = 'maker'>The bundle maker.</param> public static void CopyOutputFiles(IProgressMonitor monitor, MonobjcProject project, ConfigurationSelector configuration, BundleMaker maker) { IEnumerable<FilePair> files = project.GetOutputFiles (configuration, maker.ResourcesFolder); if (files == null || files.Count() == 0) { return; } monitor.BeginTask (GettextCatalog.GetString ("Copying output files..."), files.Count ()); foreach (FilePair pair in files) { monitor.Log.WriteLine (GettextCatalog.GetString ("Copying {0}", pair.Source.ToRelative (project.BaseDirectory))); pair.Copy (false); monitor.Step (1); } monitor.EndTask (); }
/// <summary> /// Copies the Monobjc assemblies. /// </summary> /// <param name="monitor">The monitor.</param> /// <param name="project">The project.</param> /// <param name="configuration">The configuration.</param> /// <param name="maker">The maker.</param> public static void CopyMonobjcAssemblies(IProgressMonitor monitor, MonobjcProject project, ConfigurationSelector configuration, BundleMaker maker) { IEnumerable<String> assemblies = project.ProjectMonobjcAssemblies.Select (a => a.GetReferencedFileNames (configuration) [0]); monitor.BeginTask (GettextCatalog.GetString ("Copying Monobjc assemblies..."), assemblies.Count ()); foreach (String assembly in assemblies) { String filename = Path.GetFileName (assembly); monitor.Log.WriteLine (GettextCatalog.GetString ("Copying {0}", filename)); File.Copy (assembly, Path.Combine (maker.ResourcesFolder, filename), true); monitor.Step (1); } monitor.EndTask (); }
/// <summary> /// Creates the execution command. /// </summary> /// <param name = "configSel">The configuration selector.</param> /// <param name = "configuration">The configuration.</param> /// <returns>The execution command.</returns> protected override ExecutionCommand CreateExecutionCommand (ConfigurationSelector configSel, DotNetProjectConfiguration configuration) { if (this.CompileTarget != CompileTarget.Exe) { return base.CreateExecutionCommand (configSel, configuration); } if (this.projectType == MonobjcProjectType.None) { return base.CreateExecutionCommand (configSel, configuration); } // Infer application name from configuration MonobjcProjectConfiguration conf = (MonobjcProjectConfiguration)configuration; String applicationName = this.GetApplicationName (configSel); conf.ApplicationName = applicationName; switch (this.ApplicationType) { case MonobjcProjectType.CocoaApplication: { // Create the bundle maker to get the path to the runtime BundleMaker maker = new BundleMaker (applicationName, conf.OutputDirectory); conf.Runtime = maker.Runtime; } break; case MonobjcProjectType.ConsoleApplication: { // Build the command line conf.Runtime = FileProvider.GetPath (this.TargetOSVersion, "runtime"); conf.CommandLineParameters = this.GetOutputFileName (configSel); } break; default: throw new NotSupportedException ("Unsupported application type " + this.ApplicationType); } // Create the command MonobjcExecutionCommand command = new MonobjcExecutionCommand (conf); command.UserAssemblyPaths = this.GetUserAssemblyPaths (configSel); return command; }
private static void GenerateNative(IProgressMonitor monitor, BuildResult result, MonobjcProject project, ConfigurationSelector configuration, BundleMaker maker) { // Create a directory for generation String tempDir = Path.Combine(project.GetOutputFileName(configuration).ParentDirectory, ".native"); Directory.CreateDirectory(tempDir); // Build a list of all folders to visit when collecting managed references String mainAssembly = project.GetOutputFileName(configuration); String configurationDir = Path.GetDirectoryName(mainAssembly); List<String> searchDirs = new List<String>(); searchDirs.Add(configurationDir); // For each reference, add its base dir foreach (ProjectReference reference in project.References) { String[] files = reference.GetReferencedFileNames(configuration); foreach (string file in files) { String dir = Path.GetDirectoryName(file); searchDirs.Add(dir); } } // Remove redundant entries searchDirs = searchDirs.Distinct().ToList(); // Collect all the assemblies monitor.BeginTask(GettextCatalog.GetString("Collecting assemblies..."), 0); ManagedReferenceCollector collector = new ManagedReferenceCollector(); collector.Logger = new BuildLogger(monitor, result); collector.SearchDirectories = searchDirs; monitor.EndTask(); // Collect the main assembly references List<String> assemblies = new List<String>(); assemblies.AddRange(collector.Collect(mainAssembly)); // Remove redundant entries assemblies = assemblies.Distinct().ToList(); // Generate the embedded executable monitor.BeginTask(GettextCatalog.GetString("Generating native code..."), 0); NativeCodeGenerator codeGenerator = new NativeCodeGenerator(); codeGenerator.Logger = new BuildLogger(monitor, result); codeGenerator.Assemblies = assemblies; codeGenerator.DeveloperToolsFolder = DeveloperToolsDesktopApplication.DeveloperToolsFolder; codeGenerator.TargetOSVersion = project.TargetOSVersion; codeGenerator.TargetArchitecture = project.TargetOSArch; // We embed the machine.config file; it depends on the target framework int version = (int) project.TargetFramework.ClrVersion; switch (version) { case 2: // ClrVersion.Net_2_0: codeGenerator.MachineConfiguration = "/Library/Frameworks/Mono.framework/Home/etc/mono/2.0/machine.config"; break; case 4: // ClrVersion.Net_4_0: codeGenerator.MachineConfiguration = "/Library/Frameworks/Mono.framework/Home/etc/mono/4.0/machine.config"; break; case 5: // ClrVersion.Net_4_5: codeGenerator.MachineConfiguration = "/Library/Frameworks/Mono.framework/Home/etc/mono/4.5/machine.config"; break; } // Launch the generation String executableFile = codeGenerator.Generate(tempDir); String libraryFile = Path.Combine(tempDir, "libmonobjc.dylib"); monitor.EndTask(); // Copy the native parts into the bundle monitor.BeginTask(GettextCatalog.GetString("Copying native code..."), 0); maker.CopyTo(executableFile, maker.MacOSDirectory); maker.CopyTo(libraryFile, maker.MacOSDirectory); monitor.EndTask(); // Change the paths executableFile = maker.Combine(maker.MacOSDirectory, executableFile); libraryFile = maker.Combine(maker.MacOSDirectory, libraryFile); // Relocate the libraries monitor.BeginTask(GettextCatalog.GetString("Relocating native code..."), 0); NativeCodeRelocator relocator = new NativeCodeRelocator(); relocator.Logger = new BuildLogger(monitor, result); relocator.DependencyPattern = new List<string> {"Mono.framework"}; relocator.Relocate(executableFile, maker.MacOSDirectory); relocator.Relocate(libraryFile, maker.MacOSDirectory); monitor.EndTask(); }
/// <summary> /// Cleans the specified solution item. /// </summary> /// <param name = "monitor">The monitor.</param> /// <param name = "item">The item.</param> /// <param name = "configuration">The configuration.</param> protected override void Clean(IProgressMonitor monitor, SolutionEntityItem item, ConfigurationSelector configuration) { // Call base implementation base.Clean (monitor, item, configuration); // Balk if the project is not a Monobjc one MonobjcProject project = item as MonobjcProject; if (project == null) { return; } // Call specific implementation switch (project.ApplicationType) { case MonobjcProjectType.CocoaApplication: { MonobjcProjectConfiguration conf = (MonobjcProjectConfiguration)project.GetConfiguration (configuration); // Infer application name from configuration string applicationName = project.GetApplicationName (configuration); // Create the bundle maker BundleMaker maker = new BundleMaker (applicationName, conf.OutputDirectory); // Remove the application bundle Directory.Delete (maker.ApplicationDirectory, true); } break; case MonobjcProjectType.ConsoleApplication: { // Do nothing } break; case MonobjcProjectType.CocoaLibrary: { // Do nothing } break; default: throw new NotSupportedException ("Unsupported application type " + project.ApplicationType); } }
/// <summary> /// Checks if the solution items needs building. /// </summary> /// <param name = "item">The item.</param> /// <param name = "configuration">The configuration.</param> /// <returns></returns> protected override bool GetNeedsBuilding(SolutionEntityItem item, ConfigurationSelector configuration) { // Call base implementation bool result = base.GetNeedsBuilding (item, configuration); // Balk if the project is not a Monobjc one MonobjcProject project = item as MonobjcProject; if (result || project == null) { return result; } // Call specific implementation switch (project.ApplicationType) { case MonobjcProjectType.CocoaApplication: { MonobjcProjectConfiguration conf = (MonobjcProjectConfiguration)project.GetConfiguration (configuration); // Infer application name from configuration string applicationName = project.GetApplicationName (configuration); // Create the bundle maker BundleMaker maker = new BundleMaker (applicationName, conf.OutputDirectory); // Info.plist if (!File.Exists (Path.Combine (maker.ContentsDirectory, Constants.INFO_PLIST))) { return true; } // Runtime executable if (!File.Exists (maker.Runtime)) { return true; } // The IB files if (project.GetIBFiles (Constants.InterfaceDefinition, maker.ResourcesFolder).Where (p => p.NeedsBuilding).Any ()) { return true; } // The IB files if (project.GetIBFiles (Constants.EmbeddedInterfaceDefinition, null).Where (p => p.NeedsBuilding).Any ()) { return true; } // The output files (output assembly and references) if (project.GetOutputFiles (configuration, maker.ResourcesFolder).Where (p => p.NeedsBuilding).Any ()) { return true; } // The content files (file marked as content) if (project.GetContentFiles (configuration, maker.ResourcesFolder).Where (p => p.NeedsBuilding).Any ()) { return true; } } break; case MonobjcProjectType.ConsoleApplication: { // Do nothing } break; case MonobjcProjectType.CocoaLibrary: { // The IB files if (project.GetIBFiles (Constants.EmbeddedInterfaceDefinition, null).Where (p => p.NeedsBuilding).Any ()) { return true; } } break; default: throw new NotSupportedException ("Unsupported application type " + project.ApplicationType); } return false; }