// Copyright (c) 2016, Compiler Explorer Authors // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. import path from 'path'; import _ from 'underscore'; import {BaseCompiler} from '../base-compiler'; import {BuildEnvDownloadInfo} from '../buildenvsetup/buildenv.interfaces'; import {logger} from '../logger'; import {parseRustOutput} from '../utils'; import {RustParser} from './argument-parsers'; export class RustCompiler extends BaseCompiler { linker: string; static get key() { return 'rust'; } constructor(info, env) { super(info, env); this.compiler.supportsIntel = true; this.compiler.supportsIrView = true; this.compiler.supportsLLVMOptPipelineView = true; this.compiler.supportsRustMirView = true; const isNightly = info.name === 'nightly' || info.semver === 'nightly'; // Macro expansion (-Zunpretty=expanded) and HIR (-Zunpretty=hir-tree) // are only available for Nightly this.compiler.supportsRustMacroExpView = isNightly; this.compiler.supportsRustHirView = isNightly; this.compiler.irArg = ['--emit', 'llvm-ir']; this.compiler.llvmOptArg = ['-C', 'llvm-args=-print-after-all -print-before-all']; this.compiler.llvmOptModuleScopeArg = ['-C', 'llvm-args=-print-module-scope']; this.compiler.llvmOptNoDiscardValueNamesArg = isNightly ? ['-Z', 'fewer-names=no'] : []; this.linker = this.compilerProps('linker'); } override getSharedLibraryPathsAsArguments(libraries, libDownloadPath) { return []; } override getSharedLibraryLinks(libraries): string[] { return []; } override getIncludeArguments(libraries) { const includeFlag = '--extern'; return _.flatten( _.map(libraries, selectedLib => { const foundVersion = this.findLibVersion(selectedLib); if (!foundVersion) return false; if (!foundVersion.name) return false; const list: string[] = []; const lowercaseLibName = foundVersion.name.replaceAll('-', '_'); for (const rlib of foundVersion.path) { list.push( includeFlag, `${lowercaseLibName}=${foundVersion.name}/build/debug/${rlib}`, '-L', `dependency=${foundVersion.name}/build/debug/deps`, ); } return list; }), ); } override orderArguments( options, inputFilename, libIncludes, libOptions, libPaths, libLinks, userOptions, staticLibLinks, ) { return options.concat(userOptions, libIncludes, libOptions, libPaths, libLinks, staticLibLinks, [ this.filename(inputFilename), ]); } override async setupBuildEnvironment(key, dirPath): Promise { if (this.buildenvsetup) { const libraryDetails = await this.getRequiredLibraryVersions(key.libraries); return this.buildenvsetup.setup(key, dirPath, libraryDetails); } else { return []; } } override optionsForBackend(backendOptions, outputFilename) { // The super class handles the GCC dump files that may be needed by // rustc-cg-gcc subclass. const opts = super.optionsForBackend(backendOptions, outputFilename); if (backendOptions.produceRustMir && this.compiler.supportsRustMirView) { const of = this.getRustMirOutputFilename(outputFilename); opts.push('--emit', `mir=${of}`); } return opts; } override optionsForFilter(filters, outputFilename, userOptions) { let options = ['-C', 'debuginfo=1', '-o', this.filename(outputFilename)]; const userRequestedEmit = _.any(userOptions, opt => opt.includes('--emit')); if (filters.binary) { options = options.concat(['--crate-type', 'bin']); if (this.linker) { options = options.concat(`-Clinker=${this.linker}`); } } else if (!filters.binary) { if (!userRequestedEmit) { options = options.concat('--emit', 'asm'); } if (filters.intel) options = options.concat('-Cllvm-args=--x86-asm-syntax=intel'); options = options.concat(['--crate-type', 'rlib']); } return options; } // Override the IR file name method for rustc because the output file is different from clang. override getIrOutputFilename(inputFilename) { return this.getOutputFilename(path.dirname(inputFilename), this.outputFilebase).replace('.s', '.ll'); } override getArgumentParser() { return RustParser; } override isCfgCompiler(/*compilerVersion*/) { return true; } override parseCompilationOutput(result, inputFilename) { result.stdout = parseRustOutput(result.stdout, inputFilename); result.stderr = parseRustOutput(result.stderr, inputFilename); } }