使用编译器
使用命令行编译器
注意
本节不适用于 solcjs,即使它在命令行模式下使用。
基本用法
Solidity 存储库的构建目标之一是 solc,即 Solidity 命令行编译器。使用 solc --help 可以了解所有选项的说明。编译器可以生成各种输出,从简单的二进制文件和汇编到抽象语法树(解析树)以及对燃气费用的估计。如果只需要编译单个文件,可以运行 solc --bin sourceFile.sol,它将打印二进制文件。如果需要获取 solc 的一些更高级的输出变体,最好告诉它使用 solc -o outputDirectory --bin --ast-compact-json --asm sourceFile.sol 将所有内容输出到单独的文件中。
优化器选项
在部署合约之前,请在编译时使用 solc --optimize --bin sourceFile.sol 激活优化器。默认情况下,优化器会优化合约,假设它在其生命周期内被调用 200 次(更确切地说,假设每个操作码大约执行 200 次)。如果希望初始合约部署更便宜,而后续函数执行更昂贵,请将其设置为 --optimize-runs=1。如果预计有许多交易,并且不关心更高的部署成本和输出大小,请将 --optimize-runs 设置为一个较大的数字。此参数会影响以下内容(这在将来可能会发生变化):
函数调度例程中二进制搜索的大小
大型数字或字符串等常量存储的方式
基本路径和导入重映射
命令行编译器会自动从文件系统中读取导入的文件,但也可以使用 路径重定向,方法是在以下方式中使用 prefix=path
solc github.com/ethereum/dapp-bin/=/usr/local/lib/dapp-bin/ file.sol
这实际上指示编译器在 /usr/local/lib/dapp-bin 下搜索所有以 github.com/ethereum/dapp-bin/ 开头的内容。
在访问文件系统以搜索导入文件时,不以 ./ 或 ../ 开头的路径 被视为相对于使用 --base-path 和 --include-path 选项指定的目录(如果未指定基本路径,则为当前工作目录)。此外,通过这些选项添加的路径部分不会出现在合约元数据中。
出于安全原因,编译器对 它可以访问哪些目录 施加了限制。在命令行上指定的源文件目录和重映射的目标路径会自动被允许文件读取器访问,但默认情况下会拒绝其他所有内容。可以使用 --allow-paths /sample/path,/another/sample/path 开关允许访问其他路径(及其子目录)。通过 --base-path 指定的路径内的所有内容始终被允许。
以上只是编译器如何处理导入路径的简化说明。有关详细说明、示例以及对特殊情况的讨论,请参阅有关 路径解析 的部分。
库链接
如果合约使用了 库,你会注意到字节码包含形如 __$53aea86b7d70b31448b230b20ae141a537$__ 的子字符串。这些是实际库地址的占位符。占位符是完全限定库名称的 keccak256 哈希值的十六进制编码的 34 个字符前缀。字节码文件还将在末尾包含形如 // <placeholder> -> <fq library name> 的行,以帮助识别占位符代表哪些库。请注意,完全限定库名称是其源文件的路径和库名称,用 : 分隔。可以使用 solc 作为链接器,这意味着它会为你将这些库地址插入这些位置。
可以将 --libraries "file.sol:Math=0x1234567890123456789012345678901234567890 file.sol:Heap=0xabCD567890123456789012345678901234567890" 添加到命令中,为每个库提供一个地址(使用逗号或空格作为分隔符),或者将字符串存储在一个文件中(每行一个库),并使用 --libraries fileName 运行 solc。
注意
从 Solidity 0.8.1 开始,库和地址之间的分隔符接受 =,而使用 : 作为分隔符已弃用。它将在未来被移除。目前 --libraries "file.sol:Math:0x1234567890123456789012345678901234567890 file.sol:Heap:0xabCD567890123456789012345678901234567890" 仍然有效。
如果使用选项 --standard-json 调用 solc,它将期望从标准输入中读取 JSON 输入(如下所述),并在标准输出中返回 JSON 输出。这是在更复杂的情况下(尤其是在自动化的情况下)推荐使用的接口。该过程始终在“成功”状态下终止,并通过 JSON 输出报告任何错误。选项 --base-path 也会在标准 JSON 模式下处理。
如果使用选项 --link 调用 solc,所有输入文件都将被解释为上面给出的 __$53aea86b7d70b31448b230b20ae141a537$__ 格式的未链接二进制文件(十六进制编码),并将被就地链接(如果输入是从 stdin 读取的,则写入 stdout)。在这种情况下,将忽略所有选项(包括 -o),除了 --libraries。
警告
不建议在生成的字节码上手动链接库,因为它不会更新合约元数据。由于元数据包含编译时指定的库列表,而字节码包含元数据哈希值,因此根据链接执行的时间,你会获得不同的二进制文件。
应要求编译器在编译合约时链接库,方法是使用 solc 的 --libraries 选项,或者如果使用标准 JSON 接口调用编译器,则使用 libraries 键。
注意
库占位符曾经是库本身的完全限定名称,而不是其哈希值。这种格式仍然被 solc --link 支持,但编译器不再输出它。此更改是为了降低库之间发生冲突的可能性,因为只能使用完全限定库名称的前 36 个字符。
设置目标 EVM 版本
编译合约代码时,可以指定要编译的目标以太坊虚拟机版本,以避免特定的功能或行为。
警告
针对错误的 EVM 版本进行编译会导致错误、奇怪和失败的行为。请确保(尤其是在运行私有链时)使用匹配的 EVM 版本。
在命令行上,可以按如下方式选择 EVM 版本:
solc --evm-version <VERSION> contract.sol
在 标准 JSON 接口 中,在 "settings" 字段中使用 "evmVersion" 键
{
"sources": {/* ... */},
"settings": {
"optimizer": {/* ... */},
"evmVersion": "<VERSION>"
}
}
目标选项
以下是目标 EVM 版本列表,以及每个版本引入的与编译器相关的更改。在每个版本之间不保证向后兼容性。
homestead(支持已弃用)(最早版本)
tangerineWhistle(支持已弃用)访问其他帐户的燃气成本增加,与燃气估算和优化器相关。
默认情况下,所有发送到外部调用的燃气都会被使用,之前必须保留一定量的燃气。
spuriousDragon(支持已弃用)exp操作码的燃气成本增加,与燃气估算和优化器相关。
byzantium(支持已弃用)操作码
returndatacopy、returndatasize和staticcall在汇编中可用。staticcall操作码用于调用非库视图或纯函数,这将阻止函数在 EVM 级修改状态,即即使你使用无效的类型转换也是如此。可以访问从函数调用返回的动态数据。
revert操作码引入,这意味着revert()不会浪费燃气。
君士坦丁堡操作码
create2、extcodehash、shl、shr和sar在汇编中可用。移位运算符使用移位操作码,因此需要的燃气更少。
圣彼得堡编译器行为与君士坦丁堡相同。
伊斯坦布尔操作码
chainid和selfbalance在汇编中可用。
柏林SLOAD、*CALL、BALANCE、EXT*和SELFDESTRUCT的燃气成本增加。编译器假设这些操作的冷燃气成本。这与燃气估算和优化器相关。
巴黎引入
prevrandao()和block.prevrandao,并更改了现已弃用的block.difficulty的语义,禁止在内联汇编中使用difficulty()(参见 EIP-4399)。
上海由于引入了
push0,代码大小更小,燃气节省更多(参见 EIP-3855)。
编译器输入和输出 JSON 描述
与 Solidity 编译器交互,尤其是对于更复杂和自动化的设置,推荐使用所谓的 JSON 输入输出接口。编译器的所有发行版都提供了相同的接口。
这些字段通常会发生变化,有些是可选的(如所述),但我们尽量只进行向后兼容的更改。
编译器 API 预期一个 JSON 格式的输入,并将编译结果输出到 JSON 格式的输出。标准错误输出不使用,进程将始终在“成功”状态下终止,即使有错误。错误始终作为 JSON 输出的一部分进行报告。
以下小节通过一个例子来描述格式。当然不允许使用注释,这里只用于解释目的。
输入描述
{
// Required: Source code language. Currently supported are "Solidity", "Yul", "SolidityAST" (experimental), "EVMAssembly" (experimental).
"language": "Solidity",
// Required
"sources":
{
// The keys here are the "global" names of the source files,
// imports can use other files via remappings (see below).
"myFile.sol":
{
// Optional: keccak256 hash of the source file
// It is used to verify the retrieved content if imported via URLs.
"keccak256": "0x123...",
// Required (unless "content" is used, see below): URL(s) to the source file.
// URL(s) should be imported in this order and the result checked against the
// keccak256 hash (if available). If the hash doesn't match or none of the
// URL(s) result in success, an error should be raised.
// Using the commandline interface only filesystem paths are supported.
// With the JavaScript interface the URL will be passed to the user-supplied
// read callback, so any URL supported by the callback can be used.
"urls":
[
"bzzr://56ab...",
"ipfs://Qma...",
"/tmp/path/to/file.sol"
// If files are used, their directories should be added to the command-line via
// `--allow-paths <path>`.
]
},
"settable":
{
// Optional: keccak256 hash of the source file
"keccak256": "0x234...",
// Required (unless "urls" is used): literal contents of the source file
"content": "contract settable is owned { uint256 private x = 0; function set(uint256 _x) public { if (msg.sender == owner) x = _x; } }"
},
"myFile.sol_json.ast":
{
// If language is set to "SolidityAST", an AST needs to be supplied under the "ast" key
// and there can be only one source file present.
// The format is the same as used by the `ast` output.
// Note that importing ASTs is experimental and in particular that:
// - importing invalid ASTs can produce undefined results and
// - no proper error reporting is available on invalid ASTs.
// Furthermore, note that the AST import only consumes the fields of the AST as
// produced by the compiler in "stopAfter": "parsing" mode and then re-performs
// analysis, so any analysis-based annotations of the AST are ignored upon import.
"ast": { ... }
},
"myFile_evm.json":
{
// If language is set to "EVMAssembly", an EVM Assembly JSON object needs to be supplied
// under the "assemblyJson" key and there can be only one source file present.
// The format is the same as used by the `evm.legacyAssembly` output or `--asm-json`
// output on the command line.
// Note that importing EVM assembly is experimental.
"assemblyJson":
{
".code": [ ... ],
".data": { ... }, // optional
"sourceList": [ ... ] // optional (if no `source` node was defined in any `.code` object)
}
}
},
// Optional
"settings":
{
// Optional: Stop compilation after the given stage. Currently only "parsing" is valid here
"stopAfter": "parsing",
// Optional: Sorted list of remappings
"remappings": [ ":g=/dir" ],
// Optional: Optimizer settings
"optimizer": {
// Disabled by default.
// NOTE: enabled=false still leaves some optimizations on. See comments below.
// WARNING: Before version 0.8.6 omitting the 'enabled' key was not equivalent to setting
// it to false and would actually disable all the optimizations.
"enabled": true,
// Optimize for how many times you intend to run the code.
// Lower values will optimize more for initial deployment cost, higher
// values will optimize more for high-frequency usage.
"runs": 200,
// Switch optimizer components on or off in detail.
// The "enabled" switch above provides two defaults which can be
// tweaked here. If "details" is given, "enabled" can be omitted.
"details": {
// The peephole optimizer is always on if no details are given,
// use details to switch it off.
"peephole": true,
// The inliner is always off if no details are given,
// use details to switch it on.
"inliner": false,
// The unused jumpdest remover is always on if no details are given,
// use details to switch it off.
"jumpdestRemover": true,
// Sometimes re-orders literals in commutative operations.
"orderLiterals": false,
// Removes duplicate code blocks
"deduplicate": false,
// Common subexpression elimination, this is the most complicated step but
// can also provide the largest gain.
"cse": false,
// Optimize representation of literal numbers and strings in code.
"constantOptimizer": false,
// Use unchecked arithmetic when incrementing the counter of for loops
// under certain circumstances. It is always on if no details are given.
"simpleCounterForLoopUncheckedIncrement": true,
// The new Yul optimizer. Mostly operates on the code of ABI coder v2
// and inline assembly.
// It is activated together with the global optimizer setting
// and can be deactivated here.
// Before Solidity 0.6.0 it had to be activated through this switch.
"yul": false,
// Tuning options for the Yul optimizer.
"yulDetails": {
// Improve allocation of stack slots for variables, can free up stack slots early.
// Activated by default if the Yul optimizer is activated.
"stackAllocation": true,
// Select optimization steps to be applied. It is also possible to modify both the
// optimization sequence and the clean-up sequence. Instructions for each sequence
// are separated with the ":" delimiter and the values are provided in the form of
// optimization-sequence:clean-up-sequence. For more information see
// "The Optimizer > Selecting Optimizations".
// This field is optional, and if not provided, the default sequences for both
// optimization and clean-up are used. If only one of the sequences is provided
// the other will not be run.
// If only the delimiter ":" is provided then neither the optimization nor the clean-up
// sequence will be run.
// If set to an empty value, only the default clean-up sequence is used and
// no optimization steps are applied.
"optimizerSteps": "dhfoDgvulfnTUtnIf..."
}
}
},
// Version of the EVM to compile for.
// Affects type checking and code generation. Can be homestead,
// tangerineWhistle, spuriousDragon, byzantium, constantinople,
// petersburg, istanbul, berlin, london, paris, shanghai or cancun (default)
"evmVersion": "cancun",
// Optional: Change compilation pipeline to go through the Yul intermediate representation.
// This is false by default.
"viaIR": true,
// Optional: Debugging settings
"debug": {
// How to treat revert (and require) reason strings. Settings are
// "default", "strip", "debug" and "verboseDebug".
// "default" does not inject compiler-generated revert strings and keeps user-supplied ones.
// "strip" removes all revert strings (if possible, i.e. if literals are used) keeping side-effects
// "debug" injects strings for compiler-generated internal reverts, implemented for ABI encoders V1 and V2 for now.
// "verboseDebug" even appends further information to user-supplied revert strings (not yet implemented)
"revertStrings": "default",
// Optional: How much extra debug information to include in comments in the produced EVM
// assembly and Yul code. Available components are:
// - `location`: Annotations of the form `@src <index>:<start>:<end>` indicating the
// location of the corresponding element in the original Solidity file, where:
// - `<index>` is the file index matching the `@use-src` annotation,
// - `<start>` is the index of the first byte at that location,
// - `<end>` is the index of the first byte after that location.
// - `snippet`: A single-line code snippet from the location indicated by `@src`.
// The snippet is quoted and follows the corresponding `@src` annotation.
// - `*`: Wildcard value that can be used to request everything.
"debugInfo": ["location", "snippet"]
},
// Metadata settings (optional)
"metadata": {
// The CBOR metadata is appended at the end of the bytecode by default.
// Setting this to false omits the metadata from the runtime and deploy time code.
"appendCBOR": true,
// Use only literal content and not URLs (false by default)
"useLiteralContent": true,
// Use the given hash method for the metadata hash that is appended to the bytecode.
// The metadata hash can be removed from the bytecode via option "none".
// The other options are "ipfs" and "bzzr1".
// If the option is omitted, "ipfs" is used by default.
"bytecodeHash": "ipfs"
},
// Addresses of the libraries. If not all libraries are given here,
// it can result in unlinked objects whose output data is different.
"libraries": {
// The top level key is the name of the source file where the library is used.
// If remappings are used, this source file should match the global path
// after remappings were applied.
// If this key is an empty string, that refers to a global level.
"myFile.sol": {
"MyLib": "0x123123..."
}
},
// The following can be used to select desired outputs based
// on file and contract names.
// If this field is omitted, then the compiler loads and does type checking,
// but will not generate any outputs apart from errors.
// The first level key is the file name and the second level key is the contract name.
// An empty contract name is used for outputs that are not tied to a contract
// but to the whole source file like the AST.
// A star as contract name refers to all contracts in the file.
// Similarly, a star as a file name matches all files.
// To select all outputs the compiler can possibly generate, use
// "outputSelection: { "*": { "*": [ "*" ], "": [ "*" ] } }"
// but note that this might slow down the compilation process needlessly.
//
// The available output types are as follows:
//
// File level (needs empty string as contract name):
// ast - AST of all source files
//
// Contract level (needs the contract name or "*"):
// abi - ABI
// devdoc - Developer documentation (natspec)
// userdoc - User documentation (natspec)
// metadata - Metadata
// ir - Yul intermediate representation of the code before optimization
// irAst - AST of Yul intermediate representation of the code before optimization
// irOptimized - Intermediate representation after optimization
// irOptimizedAst - AST of intermediate representation after optimization
// storageLayout - Slots, offsets and types of the contract's state variables.
// evm.assembly - New assembly format
// evm.legacyAssembly - Old-style assembly format in JSON
// evm.bytecode.functionDebugData - Debugging information at function level
// evm.bytecode.object - Bytecode object
// evm.bytecode.opcodes - Opcodes list
// evm.bytecode.sourceMap - Source mapping (useful for debugging)
// evm.bytecode.linkReferences - Link references (if unlinked object)
// evm.bytecode.generatedSources - Sources generated by the compiler
// evm.deployedBytecode* - Deployed bytecode (has all the options that evm.bytecode has)
// evm.deployedBytecode.immutableReferences - Map from AST ids to bytecode ranges that reference immutables
// evm.methodIdentifiers - The list of function hashes
// evm.gasEstimates - Function gas estimates
//
// Note that using `evm`, `evm.bytecode`, etc. will select every
// target part of that output. Additionally, `*` can be used as a wildcard to request everything.
//
"outputSelection": {
"*": {
"*": [
"metadata", "evm.bytecode" // Enable the metadata and bytecode outputs of every single contract.
, "evm.bytecode.sourceMap" // Enable the source map output of every single contract.
],
"": [
"ast" // Enable the AST output of every single file.
]
},
// Enable the abi and opcodes output of MyContract defined in file def.
"def": {
"MyContract": [ "abi", "evm.bytecode.opcodes" ]
}
},
// The modelChecker object is experimental and subject to changes.
"modelChecker":
{
// Chose which contracts should be analyzed as the deployed one.
"contracts":
{
"source1.sol": ["contract1"],
"source2.sol": ["contract2", "contract3"]
},
// Choose how division and modulo operations should be encoded.
// When using `false` they are replaced by multiplication with slack
// variables. This is the default.
// Using `true` here is recommended if you are using the CHC engine
// and not using Spacer as the Horn solver (using Eldarica, for example).
// See the Formal Verification section for a more detailed explanation of this option.
"divModNoSlacks": false,
// Choose which model checker engine to use: all (default), bmc, chc, none.
"engine": "chc",
// Choose whether external calls should be considered trusted in case the
// code of the called function is available at compile-time.
// For details see the SMTChecker section.
"extCalls": "trusted",
// Choose which types of invariants should be reported to the user: contract, reentrancy.
"invariants": ["contract", "reentrancy"],
// Choose whether to output all proved targets. The default is `false`.
"showProved": true,
// Choose whether to output all unproved targets. The default is `false`.
"showUnproved": true,
// Choose whether to output all unsupported language features. The default is `false`.
"showUnsupported": true,
// Choose which solvers should be used, if available.
// See the Formal Verification section for the solvers description.
"solvers": ["cvc4", "smtlib2", "z3"],
// Choose which targets should be checked: constantCondition,
// underflow, overflow, divByZero, balance, assert, popEmptyArray, outOfBounds.
// If the option is not given all targets are checked by default,
// except underflow/overflow for Solidity >=0.8.7.
// See the Formal Verification section for the targets description.
"targets": ["underflow", "overflow", "assert"],
// Timeout for each SMT query in milliseconds.
// If this option is not given, the SMTChecker will use a deterministic
// resource limit by default.
// A given timeout of 0 means no resource/time restrictions for any query.
"timeout": 20000
}
}
}
输出描述
{
// Optional: not present if no errors/warnings/infos were encountered
"errors": [
{
// Optional: Location within the source file.
"sourceLocation": {
"file": "sourceFile.sol",
"start": 0,
"end": 100
},
// Optional: Further locations (e.g. places of conflicting declarations)
"secondarySourceLocations": [
{
"file": "sourceFile.sol",
"start": 64,
"end": 92,
"message": "Other declaration is here:"
}
],
// Mandatory: Error type, such as "TypeError", "InternalCompilerError", "Exception", etc.
// See below for complete list of types.
"type": "TypeError",
// Mandatory: Component where the error originated, such as "general" etc.
"component": "general",
// Mandatory ("error", "warning" or "info", but please note that this may be extended in the future)
"severity": "error",
// Optional: unique code for the cause of the error
"errorCode": "3141",
// Mandatory
"message": "Invalid keyword",
// Optional: the message formatted with source location
"formattedMessage": "sourceFile.sol:100: Invalid keyword"
}
],
// This contains the file-level outputs.
// It can be limited/filtered by the outputSelection settings.
"sources": {
"sourceFile.sol": {
// Identifier of the source (used in source maps)
"id": 1,
// The AST object
"ast": {}
}
},
// This contains the contract-level outputs.
// It can be limited/filtered by the outputSelection settings.
"contracts": {
"sourceFile.sol": {
// If the language used has no contract names, this field should equal to an empty string.
"ContractName": {
// The Ethereum Contract ABI. If empty, it is represented as an empty array.
// See https://docs.solidity.lang.ac.cn/en/develop/abi-spec.html
"abi": [],
// See the Metadata Output documentation (serialised JSON string)
"metadata": "{/* ... */}",
// User documentation (natspec)
"userdoc": {},
// Developer documentation (natspec)
"devdoc": {},
// Intermediate representation before optimization (string)
"ir": "",
// AST of intermediate representation before optimization
"irAst": {/* ... */},
// Intermediate representation after optimization (string)
"irOptimized": "",
// AST of intermediate representation after optimization
"irOptimizedAst": {/* ... */},
// See the Storage Layout documentation.
"storageLayout": {"storage": [/* ... */], "types": {/* ... */} },
// EVM-related outputs
"evm": {
// Assembly (string)
"assembly": "",
// Old-style assembly (object)
"legacyAssembly": {},
// Bytecode and related details.
"bytecode": {
// Debugging data at the level of functions.
"functionDebugData": {
// Now follows a set of functions including compiler-internal and
// user-defined function. The set does not have to be complete.
"@mint_13": { // Internal name of the function
"entryPoint": 128, // Byte offset into the bytecode where the function starts (optional)
"id": 13, // AST ID of the function definition or null for compiler-internal functions (optional)
"parameterSlots": 2, // Number of EVM stack slots for the function parameters (optional)
"returnSlots": 1 // Number of EVM stack slots for the return values (optional)
}
},
// The bytecode as a hex string.
"object": "00fe",
// Opcodes list (string)
"opcodes": "",
// The source mapping as a string. See the source mapping definition.
"sourceMap": "",
// Array of sources generated by the compiler. Currently only
// contains a single Yul file.
"generatedSources": [{
// Yul AST
"ast": {/* ... */},
// Source file in its text form (may contain comments)
"contents":"{ function abi_decode(start, end) -> data { data := calldataload(start) } }",
// Source file ID, used for source references, same "namespace" as the Solidity source files
"id": 2,
"language": "Yul",
"name": "#utility.yul"
}],
// If given, this is an unlinked object.
"linkReferences": {
"libraryFile.sol": {
// Byte offsets into the bytecode.
// Linking replaces the 20 bytes located there.
"Library1": [
{ "start": 0, "length": 20 },
{ "start": 200, "length": 20 }
]
}
}
},
"deployedBytecode": {
/* ..., */ // The same layout as above.
"immutableReferences": {
// There are two references to the immutable with AST ID 3, both 32 bytes long. One is
// at bytecode offset 42, the other at bytecode offset 80.
"3": [{ "start": 42, "length": 32 }, { "start": 80, "length": 32 }]
}
},
// The list of function hashes
"methodIdentifiers": {
"delegate(address)": "5c19a95c"
},
// Function gas estimates
"gasEstimates": {
"creation": {
"codeDepositCost": "420000",
"executionCost": "infinite",
"totalCost": "infinite"
},
"external": {
"delegate(address)": "25000"
},
"internal": {
"heavyLifting()": "infinite"
}
}
}
}
}
}
}
错误类型
JSONError: JSON 输入不符合要求的格式,例如输入不是 JSON 对象,语言不受支持,等等。IOError: IO 和导入处理错误,例如无法解析的 URL 或提供的源中的哈希不匹配。ParserError: 源代码不符合语言规则。DocstringParsingError: 注释块中的 NatSpec 标签无法解析。SyntaxError: 语法错误,例如continue在for循环之外使用。DeclarationError: 无效、无法解析或冲突的标识符名称。例如Identifier not foundTypeError: 类型系统中的错误,例如无效的类型转换、无效的赋值等等。UnimplementedFeatureError: 编译器不支持此功能,但预计将在未来版本中支持。InternalCompilerError: 编译器中触发了内部错误 - 应将其报告为问题。Exception: 编译期间发生的未知错误 - 应将其报告为问题。CompilerError: 无效的编译器堆栈使用 - 应将其报告为问题。FatalError: 未正确处理的致命错误 - 应将其报告为问题。YulException: Yul 代码生成期间发生的错误 - 应将其报告为问题。Warning: 警告,没有阻止编译,但应尽量解决。Info: 编译器认为用户可能发现有用的信息,但并不危险,也不一定需要解决。