Пример #1
0
        private ToolChainSelection SelectToolChain()
        {
            // See if user requested a specific toolchain via -toolchain= or output file extension
            ToolChainSelection requestedToolChainType = new ToolChainSelection();

            if (_requestedToolChain != null)
            {
                if (!ToolChain.TryGetToolchain(_requestedToolChain, out Type requestedType))
                {
                    throw Diagnostics.ThrowError(
                              $"{_requestedToolChain} is not a supported toolchain",
                              writer => {
                        writer.WriteLine("Accepted toolchains:");
                        ToolChain.WriteOutToolChains(writer);
                    });
                }

                requestedToolChainType = new ToolChainSelection(_requestedToolChain, requestedType);
            }

            // When an explicit toolchain is not selected, build a closed set of incompatible toolchains
            HashSet <string> closedToolChains = new HashSet <string>(ToolChain.ToolChains.Length);

            void CheckFileToolChainCompatibilty(FileInfo fileInfo)
            {
                if (requestedToolChainType.Value != null)
                {
                    // Ensure file is compatible with user-requested toolchain
                    if (!fileInfo.IsCompatibleWithToolchainType(requestedToolChainType.Value))
                    {
                        Diagnostics.Report(Diagnostics.Severity.Error,
                                           $"{fileInfo.OriginalPath} is not compatible with {requestedToolChainType.Key}");
                    }
                }
                else
                {
                    // Add incompatible toolchains to closed set
                    foreach (var pair in ToolChain.ToolChains)
                    {
                        if (!fileInfo.IsCompatibleWithToolchainType(pair.Value))
                        {
                            closedToolChains.Add(pair.Key);
                        }
                    }
                }
            }

            // If specified, eliminate incompatible toolchains based on output file extension
            if (_outputFile != null && _outputFile.Kind != FileType.Kind.UNCLASSIFIED)
            {
                CheckFileToolChainCompatibilty(_outputFile);
            }

            // Ensure each input file requires a consistent toolchain
            foreach (FileInfo inputFile in _inputFiles)
            {
                CheckFileToolChainCompatibilty(inputFile);
            }

            Diagnostics.ThrowIfErrors();

            // Toolchain set as user request
            if (requestedToolChainType.Value != null)
            {
                return(requestedToolChainType);
            }

            // Otherwise take first non-closed toolchain
            foreach (var pair in ToolChain.ToolChains)
            {
                if (closedToolChains.Contains(pair.Key))
                {
                    continue;
                }

                return(pair);
            }

            throw Diagnostics.ThrowError("unable to select a mutually compatible toolchain with provided files");
        }
Пример #2
0
        public Job(CommandLine commandLine)
        {
            commandLine.ApplyTo(this);

            // Build input file list
            _inputFiles = new List <FileInfo>(commandLine.PositionalArguments.Count + (_interactive ? 1 : 0));
            foreach (string filePath in commandLine.PositionalArguments)
            {
                FileInfo tmpFile = new FileInfo(filePath);
                if (!tmpFile.Exists)
                {
                    Diagnostics.Report(Diagnostics.Severity.Error, $"{filePath} does not exist");
                }
                else if (tmpFile.Kind == FileType.Kind.UNCLASSIFIED)
                {
                    Diagnostics.Report(Diagnostics.Severity.Error, $"{filePath} is of unknown type");
                }
                else if (tmpFile.Kind == FileType.Kind.TARGET_ASSEMBLY ||
                         tmpFile.Kind == FileType.Kind.TARGET_OBJECT)
                {
                    Diagnostics.Report(Diagnostics.Severity.Error,
                                       "MonC cannot load target assembly or object files. External tools must be used for these.");
                }
                else
                {
                    _inputFiles.Add(tmpFile);
                }
            }

            // Additional interactive input file if requested
            if (_interactive)
            {
                _inputFiles.Add(FileInfo.Interactive);
            }

            Diagnostics.ThrowIfErrors();

            // Skip run is implied when output path is provided
            if (_outputPath != null)
            {
                _skipRun = true;
            }

            // VM is implied for debugger
            if (_debugger)
            {
                _skipRun = false;
            }

            if (_asm)
            {
                // Relocatable processing is implied for assembly output
                _reloc = true;
            }

            // Relocatable output always skips VM and may only accept one input file
            if (_reloc)
            {
                _skipRun = true;
                if (_inputFiles.Count > 1)
                {
                    throw Diagnostics.ThrowError("-c or -S flag may only be set for one input file");
                }
            }

            // Set output file if provided and not using VM
            _outputFile = _outputPath != null ? new FileInfo(_outputPath) : null;

            // Assembly output defaults to stdout if not specified
            if (_asm && _outputFile == null)
            {
                _outputFile = FileInfo.StdIo;
            }

            // Select toolchain by user request or input files / output file
            _toolChainSelection = SelectToolChain();

            // Construct toolchain
            _toolChain = (ToolChain)Activator.CreateInstance(_toolChainSelection.Value);
            commandLine.ApplyTo(_toolChain);

            // Determine target phase based on output file (if provided) and command line flags
            _targetPhase = SelectTargetPhase();

            if (_reloc && _inputFiles.Count > 1)
            {
                throw Diagnostics.ThrowError("relocatable output only works with one input file");
            }

            // Initialize module phase open set with pre-link phases up to target
            PhaseSet modulePhaseOpenSet =
                _toolChain.FilterPhases(
                    PhaseSet.AllPhasesTo((Phase)Math.Min((int)_targetPhase, (int)Phase.Link - 1)));

            // Visit JobActions for each file; building a chain of tools
            _moduleFileTools = new List <IModuleTool>(_inputFiles.Count);
            foreach (FileInfo inputFile in _inputFiles)
            {
                if (inputFile.IsLinkerInput)
                {
                    _moduleFileTools.Add(_toolChain.BuildLinkerInputFileTool(this, inputFile));
                    continue;
                }

                ITool tool = null;
                foreach (Phase phase in inputFile.PossiblePhases& modulePhaseOpenSet)
                {
                    tool = IJobAction.FromPhase(phase)
                           .Accept(_toolChain, this, tool != null ? (IInput)tool : inputFile);
                    commandLine.ApplyTo(tool);
                }

                if (tool is IModuleTool moduleTool)
                {
                    _moduleFileTools.Add(moduleTool);
                }
                else
                {
                    throw new InvalidOperationException("toolchain did not produce a module input file tool");
                }
            }

            // Set up link and subsequent tools
            if (_targetPhase >= Phase.Link)
            {
                PhaseSet linkPhaseOpenSet =
                    _toolChain.FilterPhases(PhaseSet.AllPhasesTo(_targetPhase) & PhaseSet.AllPhasesFrom(Phase.Link));

                ITool tool = null;
                foreach (Phase phase in linkPhaseOpenSet)
                {
                    tool = IJobAction.FromPhase(phase)
                           .Accept(_toolChain, this, tool != null ? (IInput)tool : this);
                    commandLine.ApplyTo(tool);
                }

                if (tool is IExecutableTool executableTool)
                {
                    _executableTool = executableTool;
                }
                else
                {
                    throw new InvalidOperationException("toolchain did not produce an executable tool");
                }
            }
        }