static int Main(string[] args) { CommandLineApplication app = new CommandLineApplication(); app.HelpOption("-? | -h | --help"); app.ThrowOnUnexpectedArgument = false; // Required arguments CommandOption OutputFileOption = app.Option( "-f | --file <OUTPUT_FILE>", "The output file to write to.", CommandOptionType.SingleValue ).IsRequired(); // Compilation-related arguments CommandOption <Compiler.DotNetVersion> DotNetVersionOption = app.Option <Compiler.DotNetVersion>( "-d | --dotnet | --dotnet-framework <DOTNET_VERSION>", "The Dotnet Framework version to target (net35 or net40).", CommandOptionType.SingleValue ); DotNetVersionOption.Validators.Add(new MustBeDotNetVersionValidator()); CommandOption OutputKindOption = app.Option( "-o | --output-kind <OUTPUT_KIND>", "The OutputKind to use (dll or console).", CommandOptionType.SingleValue ); OutputKindOption.Validators.Add(new MustBeOutputKindValidator()); CommandOption PlatformOption = app.Option( "-p | --platform <PLATFORM>", "The Platform to use (AnyCpy, x86, or x64).", CommandOptionType.SingleValue ); PlatformOption.Validators.Add(new MustBePlatformValidator()); CommandOption NoOptimizationOption = app.Option( "-n | --no-optimization", "Don't use source code optimization.", CommandOptionType.NoValue ); CommandOption AssemblyNameOption = app.Option( "-a | --assembly-name <ASSEMBLY_NAME>", "The name of the assembly to be generated.", CommandOptionType.SingleValue ); AssemblyNameOption.Validators.Add(new MustBeIdentifierValidator()); // Source-related arguments CommandOption SourceFileOption = app.Option( "-s | --source-file <SOURCE_FILE>", "The source code to compile.", CommandOptionType.SingleValue ).Accepts(v => v.ExistingFile()); CommandOption ClassNameOption = app.Option( "-c | --class-name <CLASS_NAME>", "The name of the class to be generated.", CommandOptionType.SingleValue ); ClassNameOption.Validators.Add(new MustBeIdentifierValidator()); CommandOption ConfuseOption = app.Option( "--confuse <CONFUSEREX_PROJECT_FILE>", "The ConfuserEx ProjectFile configuration.", CommandOptionType.SingleValue ).Accepts(v => v.ExistingFile()); app.OnExecute(() => { Compiler.CompilationRequest request = new Compiler.CompilationRequest(); // Compilation options if (!SetRequestDirectories(ref request)) { SharpGenConsole.PrintFormattedErrorLine("Unable to specify CompilationRequest directories"); app.ShowHelp(); return(-1); } if (!SetRequestDotNetVersion(DotNetVersionOption, ref request)) { SharpGenConsole.PrintFormattedErrorLine("Invalid DotNetVersion specified."); app.ShowHelp(); return(-2); } if (!SetRequestOutputKind(OutputKindOption, OutputFileOption, ref request)) { SharpGenConsole.PrintFormattedErrorLine("Invalid OutputKind specified."); app.ShowHelp(); return(-3); } if (!SetRequestPlatform(PlatformOption, ref request)) { SharpGenConsole.PrintFormattedErrorLine("Invalid Platform specified."); app.ShowHelp(); return(-4); } if (!SetRequestOptimization(NoOptimizationOption, ref request)) { SharpGenConsole.PrintFormattedErrorLine("Invalid NoOptimization specified."); app.ShowHelp(); return(-5); } if (!SetRequestAssemblyName(AssemblyNameOption, ref request)) { SharpGenConsole.PrintFormattedErrorLine("Invalid AssemblyName specified."); app.ShowHelp(); return(-6); } if (!SetRequestReferences(ref request)) { SharpGenConsole.PrintFormattedErrorLine("Unable to set CompilationRequest references."); app.ShowHelp(); return(-7); } if (!SetRequestEmbeddedResources(ref request)) { SharpGenConsole.PrintFormattedErrorLine("Unable to set CompilationRequest resources."); app.ShowHelp(); return(-8); } // Source options if (!SetRequestSource(SourceFileOption, ClassNameOption, app.RemainingArguments, ref request)) { SharpGenConsole.PrintFormattedErrorLine("Unable to create source code for request."); app.ShowHelp(); return(-9); } // Compile SharpGenConsole.PrintFormattedProgressLine("Compiling source: "); SharpGenConsole.PrintInfoLine(request.Source); try { byte[] compiled = Compiler.Compile(request); // Write to file string path = Path.Combine(Common.SharpGenOutputDirectory, OutputFileOption.Value()); File.WriteAllBytes(path, compiled); if (ConfuseOption.HasValue()) { ConfuserProject project = new ConfuserProject(); System.Xml.XmlDocument doc = new System.Xml.XmlDocument(); string ProjectFile = String.Format( File.ReadAllText(ConfuseOption.Value()), Common.SharpGenOutputDirectory, Common.SharpGenOutputDirectory, OutputFileOption.Value() ); doc.Load(new StringReader(ProjectFile)); project.Load(doc); project.ProbePaths.Add(Common.Net35Directory); project.ProbePaths.Add(Common.Net40Directory); SharpGenConsole.PrintFormattedProgressLine("Confusing assembly..."); ConfuserParameters parameters = new ConfuserParameters(); parameters.Project = project; parameters.Logger = new ConfuserConsoleLogger(); Directory.SetCurrentDirectory(Common.SharpGenRefsDirectory); ConfuserEngine.Run(parameters).Wait(); } SharpGenConsole.PrintFormattedHighlightLine("Compiled assembly written to: " + path); } catch (CompilerException e) { SharpGenConsole.PrintFormattedErrorLine(e.Message); return(-10); } catch (ConfuserException e) { SharpGenConsole.PrintFormattedErrorLine("Confuser Exception: " + e.Message); return(-11); } return(0); }); return(app.Execute(args)); }
public static byte[] Compile(CompilationRequest request) { // Gather SyntaxTrees for compilation List <SourceSyntaxTree> sourceSyntaxTrees = Directory.GetFiles(request.SourceDirectory, "*.cs", SearchOption.AllDirectories) .Select(F => new SourceSyntaxTree { FileName = F, SyntaxTree = CSharpSyntaxTree.ParseText(File.ReadAllText(F), new CSharpParseOptions()) }) .ToList(); List <SyntaxTree> compilationTrees = sourceSyntaxTrees.Select(S => S.SyntaxTree).ToList(); SyntaxTree sourceTree = CSharpSyntaxTree.ParseText(request.Source, new CSharpParseOptions()); compilationTrees.Add(sourceTree); // Use specified OutputKind and Platform CSharpCompilationOptions options = new CSharpCompilationOptions(outputKind: request.OutputKind, optimizationLevel: OptimizationLevel.Release, platform: request.Platform); // Compile to obtain SemanticModel CSharpCompilation compilation = CSharpCompilation.Create( request.AssemblyName == null ? Path.GetRandomFileName() : request.AssemblyName, compilationTrees, request.References.Where(R => R.Framework == request.TargetDotNetVersion).Where(R => R.Enabled).Select(R => { string folder = (request.TargetDotNetVersion == DotNetVersion.Net35 ? request.ReferenceDirectory + "net35" + Path.DirectorySeparatorChar : request.ReferenceDirectory + "net40" + Path.DirectorySeparatorChar); return(MetadataReference.CreateFromFile(folder + R.File)); }).ToList(), options ); // Perform source code optimization, removing unused types if (request.Optimize) { // Find all Types used by the generated compilation List <INamedTypeSymbol> usedTypes = new List <INamedTypeSymbol>(); GetUsedTypesRecursively(compilation, sourceTree, ref usedTypes, ref sourceSyntaxTrees); usedTypes = usedTypes.Distinct().ToList(); List <string> usedTypeNames = usedTypes.Select(T => GetFullyQualifiedTypeName(T)).ToList(); // SharpGenConsole.PrintInfoLine("usedTypes: " + String.Join(",", usedTypeNames)); // Filter SyntaxTrees to trees that define a used Type, otherwise the tree is not needed in this compilation compilationTrees = sourceSyntaxTrees.Where(SST => SyntaxTreeDefinesUsedType(compilation, SST.SyntaxTree, usedTypeNames)) .Select(SST => SST.SyntaxTree) .ToList(); // Removed unused Using statements from the additional entrypoint source List <string> usedNamespaceNames = GetUsedTypes(compilation, sourceTree) .Select(T => GetFullyQualifiedContainingNamespaceName(T)).Distinct().ToList(); // SharpGenConsole.PrintInfoLine("usedNamespaces: " + String.Join(",", usedNamespaceNames)); List <SyntaxNode> unusedUsingDirectives = sourceTree.GetRoot().DescendantNodes().Where(N => { return(N.Kind() == SyntaxKind.UsingDirective && !usedNamespaceNames.Contains(((UsingDirectiveSyntax)N).Name.ToFullString())); }).ToList(); sourceTree = sourceTree.GetRoot().RemoveNodes(unusedUsingDirectives, SyntaxRemoveOptions.KeepNoTrivia).SyntaxTree; // Compile again, with unused SyntaxTrees and unused using statements removed SharpGenConsole.PrintFormattedProgressLine("Compiling optimized source: "); SharpGenConsole.PrintInfoLine(sourceTree.ToString()); compilationTrees.Add(sourceTree); compilation = CSharpCompilation.Create( request.AssemblyName == null ? Path.GetRandomFileName() : request.AssemblyName, compilationTrees, request.References.Where(R => R.Framework == request.TargetDotNetVersion).Where(R => R.Enabled).Select(R => { string folder = (request.TargetDotNetVersion == DotNetVersion.Net35 ? request.ReferenceDirectory + "net35" + Path.DirectorySeparatorChar : request.ReferenceDirectory + "net40" + Path.DirectorySeparatorChar); return(MetadataReference.CreateFromFile(folder + R.File)); }).ToList(), options ); } // Emit compilation EmitResult emitResult; byte[] ILbytes = null; using (var ms = new MemoryStream()) { emitResult = compilation.Emit( ms, manifestResources: request.EmbeddedResources.Where(ER => { return(request.Platform == Platform.AnyCpu || ER.Platform == Platform.AnyCpu || ER.Platform == request.Platform); }).Where(ER => ER.Enabled).Select(ER => { return(new ResourceDescription(ER.Name, () => File.OpenRead(request.ResourceDirectory + ER.File), true)); }).ToList() ); if (emitResult.Success) { ms.Flush(); ms.Seek(0, SeekOrigin.Begin); ILbytes = ms.ToArray(); } else { StringBuilder sb = new StringBuilder(); foreach (Diagnostic d in emitResult.Diagnostics) { sb.AppendLine(d.ToString()); } throw new CompilerException("CompilationErrors: " + Environment.NewLine + sb); } } return(ILbytes); }