public CompileResult Build(CompileOptions options)
        {
            var settings = new GenerationSettings(
                partialsFolder: Path.Combine(SharedData.GeneratedFolder, assemblyNameNoExtension),
                macrosFolder: Path.Combine(SharedData.GeneratedFolder, "_macros"),
                txtForPartials: null,
                baseDirectory: ".");

            if (_cache == null ||
                _cache._options.WorkDirectory != options.WorkDirectory ||
                _cache._options.AssemblyName != options.AssemblyName ||
                _cache._options.Output != options.Output ||
                _cache._options.NoWarnings.SequenceEqual(options.NoWarnings) == false ||
                _cache._options.Defines.SequenceEqual(options.Defines) == false ||
                _cache._options.DebugSymbolFile != options.DebugSymbolFile ||
                _cache._options.IsUnityPackage != options.IsUnityPackage)
            {
                (previousResult, _cache) = BuildFull(options, settings);
                return(previousResult);
            }
            else
            {
                _cache._options = options;
                return(BuildIncremental(options, settings, _cache, previousResult !));
            }
        }
        public CompileResult Build(string projectPath, CompileOptions options)
        {
            _logger.Info("Build(projectPath={0}, output={1})", projectPath, options.Output);

            if (string.IsNullOrEmpty(_projectPath) || _projectPath != projectPath)
            {
                // create new one
                _compilerMap = new Dictionary <string, Compiler>();
                if (string.IsNullOrEmpty(_projectPath) == false)
                {
                    _logger.Info("Flush old project. (Project={0})", _projectPath);
                }
            }

            _projectPath = projectPath;

            Compiler compiler;

            if (_compilerMap.TryGetValue(options.Output, out compiler) == false)
            {
                compiler = new Compiler();
                _compilerMap.Add(options.Output, compiler);
                _logger.Info("Add new project. (Project={0})", _projectPath);
            }

            try
            {
                return(compiler.Build(options));
            }
            catch (Exception e)
            {
                _logger.Error(e, "Error in build.");
                throw;
            }
        }
        public CompileResult Build(string projectPath, CompileOptions options)
        {
            _logger.Info("Build(projectPath={0}, output={1})", projectPath, options.Output);

            if (string.IsNullOrEmpty(_projectPath) || _projectPath != projectPath)
            {
                // create new one
                _compilerMap = new Dictionary<string, Compiler>();
                if (string.IsNullOrEmpty(_projectPath) == false)
                    _logger.Info("Flush old project. (Project={0})", _projectPath);
            }

            _projectPath = projectPath;

            Compiler compiler;
            if (_compilerMap.TryGetValue(options.Output, out compiler) == false)
            {
                compiler = new Compiler();
                _compilerMap.Add(options.Output, compiler);
                _logger.Info("Add new project. (Project={0})", _projectPath);
            }

            try
            {
                return compiler.Build(options);
            }
            catch (Exception e)
            {
                _logger.Error(e, "Error in build.");
                throw;
            }
        }
        private CompileResult BuildFull(CompileOptions options)
        {
            var result = new CompileResult();

            _logger.Info("BuildFull");
            _options = options;

            _referenceFileList = new FileTimeList();
            _referenceFileList.Update(options.References);

            _sourceFileList = new FileTimeList();
            _sourceFileList.Update(options.Files);

            _referenceMap = options.References.ToDictionary(
               file => file,
               file => CreateReference(file));

            var parseOption = new CSharpParseOptions(LanguageVersion.CSharp6, DocumentationMode.Parse, SourceCodeKind.Regular, options.Defines);
            _sourceMap = options.Files.ToDictionary(
                file => file,
                file => ParseSource(file, parseOption));

            _compilation = CSharpCompilation.Create(
                options.AssemblyName,
                _sourceMap.Values,
                _referenceMap.Values,
                new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

            Emit(result);

            return result;
        }
 public Compiler(CompileOptions options)
 {
     assemblyNameNoExtension = Path.GetFileNameWithoutExtension(options.AssemblyName);
     parseOptions            = new CSharpParseOptions(
         LanguageVersion.CSharp8, DocumentationMode.Parse, SourceCodeKind.Regular, options.Defines
         ).WithFeatures(new [] { new KeyValuePair <string, string>("IOperation", ""), });
 }
        public static CompileResult Request(int parentProcessId, string currentPath, CompileOptions options, bool useCompilationServer)
        {
            if (!useCompilationServer)
            {
                return(new CompilerService().Build(currentPath, options));
            }

            var address = CompilerServiceHelper.BaseAddress + parentProcessId;

            // var client = new IpcServiceClientBuilder<ICompilerService>()
            //     .UseNamedPipe(address)
            //     // or .UseTcp(IPAddress.Loopback, 45684) to invoke using TCP
            //     .Build();

            var client = new NamedPipeIpcServiceClient <ICompilerService>(new DefaultIpcMessageSerializer(),
                                                                          new DefaultValueConverter(), address);

            try
            {
                var result = client.InvokeAsync(cs => cs.Build(currentPath, options)).Result;
                return(result);
            }
            catch (AggregateException e)
            {
                if (e.InnerException != null && e.InnerException is TimeoutException)
                {
                    throw e.InnerException;
                }
                else
                {
                    throw;
                }
            }
        }
Beispiel #7
0
        public CompileResult Build(string projectPath, CompileOptions options)
        {
            _logger.Info("Build(projectPath={0}, output={1})", projectPath, options.Output);

            Compiler compiler;

            if (options.IsUnityPackage)
            {
                // do not cache packages in ram, because they do not change
                compiler = new Compiler(options);
            }
            else
            {
                lock (_lockObj)
                {
                    if (string.IsNullOrEmpty(_projectPath) || _projectPath != projectPath)
                    {
                        // create new one
                        _projectPath = projectPath;
                        _compilerMap = new Dictionary <string, Compiler>();
                        if (string.IsNullOrEmpty(_projectPath) == false)
                        {
                            _logger.Info("Flush old project. (Project={0})", _projectPath);
                        }
                    }


                    if (_compilerMap.TryGetValue(options.Output, out var cachedCompiler))
                    {
                        compiler = cachedCompiler;
                    }
                    else
                    {
                        compiler = new Compiler(options);
                        _compilerMap.Add(options.Output, compiler);
                        _logger.Info("Add new project. (Project={0})", _projectPath);
                    }
                }
            }

            try
            {
                lock (compiler)
                {
                    var result = compiler.Build(options);
                    if (options.IsUnityPackage)
                    {
                        compiler.Dispose();
                    }
                    return(result);
                }
            }
            catch (Exception e)
            {
                _logger.Error(e, "Error in build.");
                throw;
            }
        }
Beispiel #8
0
        public static CompileResult Request(int parentProcessId, string currentPath, CompileOptions options)
        {
            var address = CompilerServiceHelper.BaseAddress + parentProcessId;
            var binding = CompilerServiceHelper.GetBinding();
            var ep      = new EndpointAddress(address);
            var channel = ChannelFactory <ICompilerService> .CreateChannel(binding, ep);

            return(channel.Build(currentPath, options));
        }
 ImmutableArray <DiagnosticAnalyzer> Analyzers(CompileOptions options, List <Diagnostic> diagnostics)
 {
     lock (_lockAnalyzers)
     {
         if (_loadedAnalyzers.HasValue)
         {
             return(_loadedAnalyzers.Value);
         }
         _loadedAnalyzers = AnalyzersInner(options, diagnostics);
         return(_loadedAnalyzers.Value);
     }
 }
        public static CompileResult Request(int parentProcessId, string currentPath, CompileOptions options)
        {
            var address = "net.pipe://localhost/Unity3D.IncrementalCompiler/" + parentProcessId;

            var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
            {
                MaxBufferSize = 1048576,
                MaxReceivedMessageSize = 1048576
            };
            var ep = new EndpointAddress(address);
            var channel = ChannelFactory<ICompilerService>.CreateChannel(binding, ep);
            return channel.Build(currentPath, options);
        }
        public static CompileResult Request(int parentProcessId, string currentPath, CompileOptions options)
        {
            var address = "net.pipe://localhost/Unity3D.IncrementalCompiler/" + parentProcessId;

            var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
            {
                MaxBufferSize          = int.MaxValue,
                MaxReceivedMessageSize = int.MaxValue
            };
            var ep      = new EndpointAddress(address);
            var channel = ChannelFactory <ICompilerService> .CreateChannel(binding, ep);

            return(channel.Build(currentPath, options));
        }
 public CompileResult Build(CompileOptions options)
 {
     if (_compilation == null ||
         _options.WorkDirectory != options.WorkDirectory ||
         _options.AssemblyName != options.AssemblyName ||
         _options.Output != options.Output ||
         _options.Defines.SequenceEqual(options.Defines) == false)
     {
         return BuildFull(options);
     }
     else
     {
         return BuildIncremental(options);
     }
 }
        void CompileAnalyzer(CompileOptions options, string fullPath, string assembliesPath)
        {
            _logger.Info($"Compiling analyzer: {fullPath}");
            var name   = Path.GetFileNameWithoutExtension(Path.GetFileName(fullPath));
            var parsed = ParseSource(options, fullPath, parseOptions);

            var assemblyRefs =
                AppDomain.CurrentDomain.GetAssemblies()
                .Select(a => MetadataReference.CreateFromFile(a.Location))
                .ToArray();

            var c = CSharpCompilation.Create(
                name,
                new[] { parsed },
                assemblyRefs,
                new CSharpCompilationOptions(
                    OutputKind.DynamicallyLinkedLibrary,
                    assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default,
                    sourceReferenceResolver: new SourceFileResolver(ImmutableArray <string> .Empty, options.WorkDirectory)
                    )
                );

            using (var stream = new FileStream(Path.Combine(assembliesPath, name + ".dll"), FileMode.OpenOrCreate))
            {
                var res = c.Emit(stream);
                foreach (var diagnostic in res.Diagnostics)
                {
                    switch (diagnostic.Severity)
                    {
                    case DiagnosticSeverity.Error:
                        _logger.Error(diagnostic.ToString());
                        break;

                    case DiagnosticSeverity.Warning:
                        _logger.Warn(diagnostic.ToString());
                        break;

                    default:
                        _logger.Info(diagnostic.ToString());
                        break;
                    }
                }
                if (!res.Success)
                {
                    throw new Exception($"Could not compile `{fullPath}`");
                }
            }
        }
 public CompilationCache(
     CSharpCompilation compilation,
     CompileOptions options,
     FileTimeList referenceFileList,
     FileTimeList sourceFileList,
     Dictionary <string, MetadataReference> referenceMap,
     Dictionary <string, SyntaxTree> sourceMap, CodeGeneration.GeneratedFilesMapping filesMapping)
 {
     _referenceFileList = referenceFileList;
     _sourceFileList    = sourceFileList;
     _referenceMap      = referenceMap;
     _sourceMap         = sourceMap;
     _filesMapping      = filesMapping;
     _compilation       = compilation;
     _options           = options;
 }
 public CompileResult Build(CompileOptions options)
 {
     if (_compilation == null ||
         _options.WorkDirectory != options.WorkDirectory ||
         _options.AssemblyName != options.AssemblyName ||
         _options.Output != options.Output ||
         _options.NoWarnings.SequenceEqual(options.NoWarnings) == false ||
         _options.Defines.SequenceEqual(options.Defines) == false)
     {
         return(BuildFull(options));
     }
     else
     {
         return(BuildIncremental(options));
     }
 }
        private CompileResult BuildFull(CompileOptions options)
        {
            var result = new CompileResult();

            _logger.Info("BuildFull");
            _options = options;

            _referenceFileList = new FileTimeList();
            _referenceFileList.Update(options.References);

            _sourceFileList = new FileTimeList();
            _sourceFileList.Update(options.Files);

            _referenceMap = options.References.ToDictionary(
                file => file,
                file => CreateReference(file));

            var parseOption = new CSharpParseOptions(LanguageVersion.CSharp6, DocumentationMode.Parse, SourceCodeKind.Regular, options.Defines);

            _sourceMap = options.Files.ToDictionary(
                file => file,
                file => ParseSource(file, parseOption));

            var specificDiagnosticOptions = options.NoWarnings.ToDictionary(x => x, _ => ReportDiagnostic.Suppress);

            _compilation = CSharpCompilation.Create(
                options.AssemblyName,
                _sourceMap.Values,
                _referenceMap.Values,
                new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
                .WithSpecificDiagnosticOptions(specificDiagnosticOptions)
                .WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default)
                .WithAllowUnsafe(options.Options.Contains("-unsafe")));

            Emit(result);

            return(result);
        }
        string CompileAnalyzers(CompileOptions options)
        {
            var analyzers  = "compiled-analyzers-" + assemblyNameNoExtension;
            var outputPath = Directory.Exists("Temp") ? Path.Combine("Temp", analyzers) : analyzers;

            if (Directory.Exists(outputPath))
            {
                Directory.Delete(outputPath, true);
            }
            Directory.CreateDirectory(outputPath);
            var analyzerSources =
                Directory
                .GetFiles(analyzersPath)
                .Where(x => x.EndsWith(".cs", StringComparison.OrdinalIgnoreCase))
                .ToArray();

            foreach (var cs in analyzerSources)
            {
                CompileAnalyzer(options, cs, outputPath);
            }

            return(outputPath);
        }
        private CompileResult BuildFull(CompileOptions options)
        {
            var result = new CompileResult();

            _logger.Info("BuildFull");
            _options = options;

            _referenceFileList = new FileTimeList();
            _referenceFileList.Update(options.References);

            _sourceFileList = new FileTimeList();
            _sourceFileList.Update(options.Files);

            _referenceMap = options.References.ToDictionary(
               file => file,
               file => CreateReference(file));

            var parseOption = new CSharpParseOptions(LanguageVersion.CSharp6, DocumentationMode.Parse, SourceCodeKind.Regular, options.Defines);
            _sourceMap = options.Files.ToDictionary(
                file => file,
                file => ParseSource(file, parseOption));

            var specificDiagnosticOptions = options.NoWarnings.ToDictionary(x => x, _ => ReportDiagnostic.Suppress);
            _compilation = CSharpCompilation.Create(
                options.AssemblyName,
                _sourceMap.Values,
                _referenceMap.Values,
                new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
                    .WithSpecificDiagnosticOptions(specificDiagnosticOptions)
                    .WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default)
                    .WithAllowUnsafe(options.Options.Contains("-unsafe")));

            Emit(result);

            return result;
        }
        /// <summary>
        /// analyzers can only use dependencies that are already in this project
        /// dependency versions must match those of project dependencies
        /// </summary>
        /// <param name="diagnostics"></param>
        ImmutableArray <DiagnosticAnalyzer> AnalyzersInner(CompileOptions options, List <Diagnostic> diagnostics)
        {
            // if Location.None is used instead, unity doesnt print the error to console.
            var defaultPos = Location.Create(
                "/Analyzers", TextSpan.FromBounds(0, 0), new LinePositionSpan()
                );

            try {
                if (PlatformHelper.CurrentPlatform == Platform.Mac)
                {
                    return(ImmutableArray <DiagnosticAnalyzer> .Empty);
                }

                if (!Directory.Exists(analyzersPath))
                {
                    Directory.CreateDirectory(analyzersPath);
                    File.WriteAllText(
                        analyzersPath + "/readme.txt",
                        "Add Roslyn Analyzers here\r\nAdd analyzer dependencies in sub-folders"
                        );
                    return(ImmutableArray <DiagnosticAnalyzer> .Empty);
                }

                var loader = new AL();

                var additionalPath = CompileAnalyzers(options);

                var analyzerNames =
                    Directory.GetFiles(analyzersPath).Concat(Directory.GetFiles(additionalPath))
                    .Where(x => x.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
                    .ToArray();

                var analyzerDependencies =
                    Directory.GetDirectories(analyzersPath).SelectMany(Directory.GetFiles).ToArray();

                foreach (var analyzerDependency in analyzerDependencies)
                {
                    _logger.Info("Analyzer dependency: " + analyzerDependency);
                    loader.LoadFromPath(analyzerDependency);
                }

                _logger.Info("Analyzers:");
                var analyzers =
                    analyzerNames
                    .Select(dll => {
                    _logger.Info("Analyzer dll: " + dll);
                    var _ref = new AnalyzerFileReference(dll, loader);
                    _ref.AnalyzerLoadFailed += (_, e) => {
                        _logger.Error("failed to load analyzer: " + e.TypeName + "; " + e.Message);
                        diagnostics.Add(Diagnostic.Create(new DiagnosticDescriptor(
                                                              "A01",
                                                              "Error",
                                                              "Compiler couldn't load provided code analyzer: " + e.TypeName +
                                                              ". Please fix or remove from /Analyzers directory. More info in compiler log.",
                                                              "Error",
                                                              DiagnosticSeverity.Error,
                                                              true
                                                              ), defaultPos));
                    };

                    return(_ref.GetAnalyzers(LanguageNames.CSharp));
                })
                    .Aggregate(new List <DiagnosticAnalyzer>(), (list, a) => {
                    a.ForEach(_logger.Info);
                    list.AddRange(a);
                    return(list);
                })
                    .ToImmutableArray();

                return(analyzers);
            } catch (Exception e) {
                _logger.Error(e);
                diagnostics.Add(Diagnostic.Create(new DiagnosticDescriptor(
                                                      "A02",
                                                      "Warning",
                                                      "Exception was thrown when loading analyzers: " + e.Message,
                                                      "Warning",
                                                      DiagnosticSeverity.Warning,
                                                      true
                                                      ), defaultPos));
                return(ImmutableArray <DiagnosticAnalyzer> .Empty);
            }
        }
        static int RunAsClient(string[] args)
        {
            SetupLogger("IncrementalCompiler.log", false);

            var logger = LogManager.GetLogger("Client");
            logger.Info("Started");

            Settings settings;
            try
            {
                settings = Settings.Load() ?? Settings.Default;
            }
            catch (Exception e)
            {
                logger.Error(e, "Failed in loading settings.");
                return 1;
            }

            var currentPath = Directory.GetCurrentDirectory();
            var options = new CompileOptions();
            options.ParseArgument(args);
            options.WorkDirectory = currentPath;
            options.References = options.References.Distinct().ToList();
            options.Files = options.Files.Distinct().ToList();
            options.DebugSymbolFile = settings.DebugSymbolFile;
            options.PrebuiltOutputReuse = settings.PrebuiltOutputReuse;

            logger.Info("CurrentDir: {0}", Directory.GetCurrentDirectory());
            logger.Info("Output: {0}", options.Output);

            if (string.IsNullOrEmpty(options.Output))
            {
                logger.Error("No output");
                return 1;
            }

            // Get unity process ID

            var parentProcessId = 0;
            var pd = options.Defines.FirstOrDefault(d => d.StartsWith("__UNITY_PROCESSID__"));
            if (pd != null)
            {
                int.TryParse(pd.Substring(19), out parentProcessId);
            }
            else
            {
                var parentProcess = Process.GetProcessesByName("Unity").FirstOrDefault();
                if (parentProcess != null)
                    parentProcessId = parentProcess.Id;
            }

            if (parentProcessId == 0)
            {
                logger.Error("No parent process");
                return 1;
            }

            logger.Info("Parent process ID: {0}", parentProcessId);

            // Run

            Process serverProcess = null;
            while (true)
            {
                try
                {
                    var w = new Stopwatch();
                    w.Start();
                    logger.Info("Request to server");
                    var result = CompilerServiceClient.Request(parentProcessId, currentPath, options);
                    w.Stop();
                    logger.Info("Done: Succeeded={0}. Duration={1}sec.", result.Succeeded, w.Elapsed.TotalSeconds);
                    Console.WriteLine("Compile {0}. (Duration={1}sec)", result.Succeeded ? "succeeded" : "failed",
                                                                        w.Elapsed.TotalSeconds);
                    foreach (var warning in result.Warnings)
                    {
                        logger.Info(warning);
                        Console.Error.WriteLine(warning);
                    }
                    foreach (var error in result.Errors)
                    {
                        logger.Info(error);
                        Console.Error.WriteLine(error);
                    }
                    return result.Succeeded ? 0 : 1;
                }
                catch (EndpointNotFoundException)
                {
                    if (serverProcess == null)
                    {
                        logger.Info("Spawn server");
                        serverProcess = Process.Start(
                            new ProcessStartInfo
                            {
                                FileName = Assembly.GetEntryAssembly().Location,
                                Arguments = "-server " + parentProcessId,
                                WindowStyle = ProcessWindowStyle.Hidden
                            });
                        Thread.Sleep(100);
                    }
                    else
                    {
                        if (serverProcess.HasExited == false)
                            Thread.Sleep(100);
                        else
                            return 1;
                    }
                }
                catch (Exception e)
                {
                    logger.Error(e, "Error in request");
                    Console.Error.WriteLine("Internal error: " + e);
                    return 1;
                }
            }
        }
        private static int RunAsDev(string[] args)
        {
            SetupLogger("IncrementalCompiler.log", true);

            var workDirectory = args[1];
            var reponseFile   = args[2];
            var settings      = Settings.Load() ?? Settings.Default;

            var logger = LogManager.GetLogger("Dev");

            logger.Info("Started");

            Directory.SetCurrentDirectory(workDirectory);
            var curPath = Directory.GetCurrentDirectory();

            var options = new CompileOptions();

            options.ParseArgument(new string[]
            {
                "-nostdlib+",
                "-noconfig",
                // Unity5
//                "-r:" + @"C:/Software/Unity-2018/Editor/Data/Mono/lib/mono/2.0/mscorlib.dll",
//                "-r:" + @"C:/Software/Unity-2018/Editor/Data/Mono/lib/mono/2.0/System.dll",
//                "-r:" + @"C:/Software/Unity-2018/Editor/Data/Mono/lib/mono/2.0/System.Core.dll",
//                "-r:" + @"C:/Software/Unity-2018/Editor/Data/Mono/lib/mono/2.0/System.Xml.dll",
                "@Temp/" + reponseFile,
            });

            options.WorkDirectory       = curPath;
            options.References          = options.References.Distinct().ToList();
            options.Files               = options.Files.Distinct().ToList();
            options.PrebuiltOutputReuse = settings.PrebuiltOutputReuse;

            var parentProcessId = Process.GetCurrentProcess().Id;

            Process?serverProcess = null;

            // new Thread(() => CompilerServiceServer.Run(logger, parentProcessId)).Start();

            while (true)
            {
                try
                {
                    var w = new Stopwatch();
                    w.Start();
                    Console.WriteLine("Run");

                    var result = CompilerServiceClient.Request(parentProcessId, curPath, options, false);

                    w.Stop();

                    Console.WriteLine("Done: Succeeded={0}. Duration={1}sec. ", result.Succeeded,
                                      w.Elapsed.TotalSeconds);
                    foreach (var warning in result.Warnings)
                    {
                        Console.WriteLine(warning);
                    }
                    foreach (var error in result.Errors)
                    {
                        Console.WriteLine(error);
                    }

                    Console.ReadLine();
                }
                catch (TimeoutException)
                {
                    if (serverProcess == null)
                    {
                        var a = new Thread(() => CompilerServiceServer.Run(logger, parentProcessId));
                        a.Start();
                        serverProcess = Process.GetCurrentProcess();

                        // serverProcess = Process.Start(
                        //     new ProcessStartInfo
                        //     {
                        //         FileName = Assembly.GetEntryAssembly().Location,
                        //         Arguments = "-server " + parentProcessId,
                        //         WindowStyle = ProcessWindowStyle.Hidden
                        //     });
                        //
                        Thread.Sleep(100);
                    }
                    else
                    {
                        if (serverProcess.HasExited == false)
                        {
                            Thread.Sleep(100);
                        }
                        else
                        {
                            serverProcess = null;
                        }
                    }
                }
            }
        }
        private CompileResult BuildIncremental(CompileOptions options)
        {
            var result = new CompileResult();

            _logger.Info("BuildIncremental");
            _options = options;

            // update reference files

            var referenceChanges = _referenceFileList.Update(options.References);
            foreach (var file in referenceChanges.Added)
            {
                _logger.Info("+ {0}", file);
                var reference = CreateReference(file);
                _compilation = _compilation.AddReferences(reference);
                _referenceMap.Add(file, reference);
            }
            foreach (var file in referenceChanges.Changed)
            {
                _logger.Info("* {0}", file);
                var reference = CreateReference(file);
                _compilation = _compilation.RemoveReferences(_referenceMap[file])
                                           .AddReferences(reference);
                _referenceMap[file] = reference;
            }
            foreach (var file in referenceChanges.Removed)
            {
                _logger.Info("- {0}", file);
                _compilation = _compilation.RemoveReferences(_referenceMap[file]);
                _referenceMap.Remove(file);
            }

            // update source files

            var sourceChanges = _sourceFileList.Update(options.Files);
            var parseOption = new CSharpParseOptions(LanguageVersion.CSharp6, DocumentationMode.Parse, SourceCodeKind.Regular, options.Defines);
            foreach (var file in sourceChanges.Added)
            {
                _logger.Info("+ {0}", file);
                var syntaxTree = ParseSource(file, parseOption);
                _compilation = _compilation.AddSyntaxTrees(syntaxTree);
                _sourceMap.Add(file, syntaxTree);
            }
            foreach (var file in sourceChanges.Changed)
            {
                _logger.Info("* {0}", file);
                var syntaxTree = ParseSource(file, parseOption);
                _compilation = _compilation.RemoveSyntaxTrees(_sourceMap[file])
                                           .AddSyntaxTrees(syntaxTree);
                _sourceMap[file] = syntaxTree;
            }
            foreach (var file in sourceChanges.Removed)
            {
                _logger.Info("- {0}", file);
                _compilation = _compilation.RemoveSyntaxTrees(_sourceMap[file]);
                _sourceMap.Remove(file);
            }

            // emit or reuse prebuilt output

            var reusePrebuilt = _outputDllStream != null && (
                (_options.PrebuiltOutputReuse == PrebuiltOutputReuseType.WhenNoChange &&
                 sourceChanges.Empty && referenceChanges.Empty) ||
                (_options.PrebuiltOutputReuse == PrebuiltOutputReuseType.WhenNoSourceChange &&
                 sourceChanges.Empty && referenceChanges.Added.Count == 0 && referenceChanges.Removed.Count == 0));

            if (reusePrebuilt)
            {
                _logger.Info("Reuse prebuilt output");

                // write dll

                var dllFile = Path.Combine(_options.WorkDirectory, _options.Output);
                using (var dllStream = new FileStream(dllFile, FileMode.Create))
                {
                    _outputDllStream.Seek(0L, SeekOrigin.Begin);
                    _outputDllStream.CopyTo(dllStream);
                }

                // write pdb or mdb

                switch (_options.DebugSymbolFile)
                {
                    case DebugSymbolFileType.Pdb:
                        var pdbFile = Path.Combine(_options.WorkDirectory, Path.ChangeExtension(_options.Output, ".pdb"));
                        using (var debugSymbolStream = new FileStream(pdbFile, FileMode.Create))
                        {
                            _outputDebugSymbolStream.Seek(0L, SeekOrigin.Begin);
                            _outputDebugSymbolStream.CopyTo(debugSymbolStream);
                        }
                        break;

                    case DebugSymbolFileType.PdbToMdb:
                    case DebugSymbolFileType.Mdb:
                        var mdbFile = Path.Combine(_options.WorkDirectory, _options.Output + ".mdb");
                        using (var debugSymbolStream = new FileStream(mdbFile, FileMode.Create))
                        {
                            _outputDebugSymbolStream.Seek(0L, SeekOrigin.Begin);
                            _outputDebugSymbolStream.CopyTo(debugSymbolStream);
                        }
                        break;
                }

                result.Succeeded = true;
            }
            else
            {
                _logger.Info("Emit");

                Emit(result);
            }

            return result;
        }
        private CompileResult BuildIncremental(CompileOptions options)
        {
            var result = new CompileResult();

            _logger.Info("BuildIncremental");
            _options = options;

            // update reference files

            var referenceChanges = _referenceFileList.Update(options.References);

            foreach (var file in referenceChanges.Added)
            {
                _logger.Info("+ {0}", file);
                var reference = CreateReference(file);
                _compilation = _compilation.AddReferences(reference);
                _referenceMap.Add(file, reference);
            }
            foreach (var file in referenceChanges.Changed)
            {
                _logger.Info("* {0}", file);
                var reference = CreateReference(file);
                _compilation = _compilation.RemoveReferences(_referenceMap[file])
                               .AddReferences(reference);
                _referenceMap[file] = reference;
            }
            foreach (var file in referenceChanges.Removed)
            {
                _logger.Info("- {0}", file);
                _compilation = _compilation.RemoveReferences(_referenceMap[file]);
                _referenceMap.Remove(file);
            }

            // update source files

            var sourceChanges = _sourceFileList.Update(options.Files);
            var parseOption   = new CSharpParseOptions(LanguageVersion.CSharp6, DocumentationMode.Parse, SourceCodeKind.Regular, options.Defines);

            foreach (var file in sourceChanges.Added)
            {
                _logger.Info("+ {0}", file);
                var syntaxTree = ParseSource(file, parseOption);
                _compilation = _compilation.AddSyntaxTrees(syntaxTree);
                _sourceMap.Add(file, syntaxTree);
            }
            foreach (var file in sourceChanges.Changed)
            {
                _logger.Info("* {0}", file);
                var syntaxTree = ParseSource(file, parseOption);
                _compilation = _compilation.RemoveSyntaxTrees(_sourceMap[file])
                               .AddSyntaxTrees(syntaxTree);
                _sourceMap[file] = syntaxTree;
            }
            foreach (var file in sourceChanges.Removed)
            {
                _logger.Info("- {0}", file);
                _compilation = _compilation.RemoveSyntaxTrees(_sourceMap[file]);
                _sourceMap.Remove(file);
            }

            // emit or reuse prebuilt output

            var reusePrebuilt = _outputDllStream != null && (
                (_options.PrebuiltOutputReuse == PrebuiltOutputReuseType.WhenNoChange &&
                 sourceChanges.Empty && referenceChanges.Empty) ||
                (_options.PrebuiltOutputReuse == PrebuiltOutputReuseType.WhenNoSourceChange &&
                 sourceChanges.Empty && referenceChanges.Added.Count == 0 && referenceChanges.Removed.Count == 0));

            if (reusePrebuilt)
            {
                _logger.Info("Reuse prebuilt output");

                // write dll

                var dllFile = Path.Combine(_options.WorkDirectory, _options.Output);
                using (var dllStream = new FileStream(dllFile, FileMode.Create))
                {
                    _outputDllStream.Seek(0L, SeekOrigin.Begin);
                    _outputDllStream.CopyTo(dllStream);
                }

                // write pdb or mdb

                switch (_options.DebugSymbolFile)
                {
                case DebugSymbolFileType.Pdb:
                    var pdbFile = Path.Combine(_options.WorkDirectory, Path.ChangeExtension(_options.Output, ".pdb"));
                    using (var debugSymbolStream = new FileStream(pdbFile, FileMode.Create))
                    {
                        _outputDebugSymbolStream.Seek(0L, SeekOrigin.Begin);
                        _outputDebugSymbolStream.CopyTo(debugSymbolStream);
                    }
                    break;

                case DebugSymbolFileType.PdbToMdb:
                case DebugSymbolFileType.Mdb:
                    var mdbFile = Path.Combine(_options.WorkDirectory, _options.Output + ".mdb");
                    using (var debugSymbolStream = new FileStream(mdbFile, FileMode.Create))
                    {
                        _outputDebugSymbolStream.Seek(0L, SeekOrigin.Begin);
                        _outputDebugSymbolStream.CopyTo(debugSymbolStream);
                    }
                    break;
                }

                result.Succeeded = true;
            }
            else
            {
                _logger.Info("Emit");

                Emit(result);
            }

            return(result);
        }
Beispiel #24
0
        private static int RunAsClient(string[] args)
        {
            SetupLogger("IncrementalCompiler.log", false);

            var logger = LogManager.GetLogger("Client");

            logger.Info("Started");

            Settings settings;

            try
            {
                settings = Settings.Load() ?? Settings.Default;
            }
            catch (Exception e)
            {
                logger.Error(e, "Failed in loading settings.");
                return(1);
            }

            var currentPath = Directory.GetCurrentDirectory();
            var options     = new CompileOptions();

            options.ParseArgument(args);
            options.WorkDirectory       = currentPath;
            options.References          = options.References.Distinct().ToList();
            options.Files               = options.Files.Distinct().ToList();
            options.PrebuiltOutputReuse = settings.PrebuiltOutputReuse;

            logger.Info("CurrentDir: {0}", Directory.GetCurrentDirectory());
            logger.Info("Output: {0}", options.Output);

            if (string.IsNullOrEmpty(options.Output))
            {
                logger.Error("No output");
                return(1);
            }

            // Get unity process ID

            var parentProcessId = 0;
            var pd = options.Defines.FirstOrDefault(d => d.StartsWith("__UNITY_PROCESSID__"));

            if (pd != null)
            {
                int.TryParse(pd.Substring(19), out parentProcessId);
            }
            else
            {
                var parentProcess = Process.GetProcessesByName("Unity").FirstOrDefault();
                if (parentProcess != null)
                {
                    parentProcessId = parentProcess.Id;
                }
            }

            if (parentProcessId == 0)
            {
                logger.Error("No parent process");
                return(1);
            }

            logger.Info("Parent process ID: {0}", parentProcessId);

            // Run

            var useCompilationServer = true;

            // it does not work on mac for some reason
            useCompilationServer &= PlatformHelper.CurrentPlatform == Platform.Windows;

            useCompilationServer = false;

            Process?serverProcess = null;

            while (true)
            {
                try
                {
                    var w = new Stopwatch();
                    w.Start();
                    logger.Info("Request to server");
                    var result = CompilerServiceClient.Request(parentProcessId, currentPath, options, useCompilationServer);
                    w.Stop();
                    logger.Info("Done: Succeeded={0}. Duration={1}sec.", result.Succeeded, w.Elapsed.TotalSeconds);
                    Console.WriteLine("Compile {0}. (Duration={1}sec)", result.Succeeded ? "succeeded" : "failed",
                                      w.Elapsed.TotalSeconds);
                    foreach (var warning in result.Warnings)
                    {
                        logger.Info(warning);
                        Console.Error.WriteLine(warning.Replace("\r\n", " ~~ ").Replace("\n", " ~~ "));
                    }
                    foreach (var error in result.Errors)
                    {
                        logger.Info(error);
                        Console.Error.WriteLine(error.Replace("\r\n", " ~~ ").Replace("\n", " ~~ "));
                    }
                    return(result.Succeeded ? 0 : 1);
                }
                catch (TimeoutException)
                {
                    if (serverProcess == null)
                    {
                        logger.Info("Spawn server");
                        serverProcess = Process.Start(
                            new ProcessStartInfo
                        {
                            FileName    = (Assembly.GetEntryAssembly() ?? typeof(Program).Assembly).Location,
                            Arguments   = "-server " + parentProcessId,
                            WindowStyle = ProcessWindowStyle.Hidden
                        });
                        Thread.Sleep(100);
                    }
                    else
                    {
                        if (serverProcess.HasExited == false)
                        {
                            Thread.Sleep(100);
                        }
                        else
                        {
                            return(1);
                        }
                    }
                }
                catch (Exception e)
                {
                    logger.Error(e, "Error in request");
                    Console.Error.WriteLine("Internal error: " + e);
                    return(1);
                }
            }
        }
        static int RunAsDev(string[] args)
        {
            SetupLogger("IncrementalCompiler.log", true);

            var workDirectory = args[1];
            var reponseFile = args[2];
            var settings = Settings.Load() ?? Settings.Default;

            var logger = LogManager.GetLogger("Dev");
            logger.Info("Started");

            Directory.SetCurrentDirectory(workDirectory);
            var curPath = Directory.GetCurrentDirectory();

            var options = new CompileOptions();
            options.ParseArgument(new string[]
            {
                "-nostdlib+",
                "-noconfig",
                "-r:" + @"C:/Program Files/Unity/Editor/Data\Mono/lib/mono/2.0/mscorlib.dll",
                "-r:" + @"C:/Program Files/Unity/Editor/Data\Mono/lib/mono/2.0/System.dll",
                "-r:" + @"C:/Program Files/Unity/Editor/Data\Mono/lib/mono/2.0/System.Core.dll",
                "-r:" + @"C:/Program Files/Unity/Editor/Data\Mono/lib/mono/2.0/System.Xml.dll",
                "@Temp/" + reponseFile,
            });
            options.WorkDirectory = curPath;
            options.References = options.References.Distinct().ToList();
            options.Files = options.Files.Distinct().ToList();
            options.DebugSymbolFile = settings.DebugSymbolFile;
            options.PrebuiltOutputReuse = settings.PrebuiltOutputReuse;

            var parentProcessId = Process.GetCurrentProcess().Id;

            Process serverProcess = null;

            while (true)
            {
                try
                {
                    var w = new Stopwatch();
                    w.Start();
                    Console.WriteLine("Run");

                    var result = CompilerServiceClient.Request(parentProcessId, curPath, options);

                    w.Stop();

                    Console.WriteLine("Done: Succeeded={0}. Duration={1}sec. ", result.Succeeded, w.Elapsed.TotalSeconds);
                    foreach (var warning in result.Warnings)
                        Console.WriteLine(warning);
                    foreach (var error in result.Errors)
                        Console.WriteLine(error);

                    Console.ReadLine();
                }
                catch (EndpointNotFoundException)
                {
                    if (serverProcess == null)
                    {
                        var a = new Thread(() => CompilerServiceServer.Run(logger, parentProcessId));
                        a.Start();
                        serverProcess = Process.GetCurrentProcess();
                        /*
                        serverProcess = Process.Start(
                            new ProcessStartInfo
                            {
                                FileName = Assembly.GetEntryAssembly().Location,
                                Arguments = "-server " + parentProcessId,
                                WindowStyle = ProcessWindowStyle.Hidden
                            });
                        */
                        Thread.Sleep(100);
                    }
                    else
                    {
                        if (serverProcess.HasExited == false)
                            Thread.Sleep(100);
                        else
                            serverProcess = null;
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    return 1;
                }
            }
        }