如何通过solc编译solidity编写的以太坊智能合约?

solc是solidity的命令行编译器,solidity编写的以太坊智能合约可通过带参数的命令行工具solc进行编译,成为以太坊虚拟机中的代码。最终部署到链上形成我们所见到的各种智能合约。

作为solidity语言开发中的重要编译工具,我们来看看官网上怎么说。

solidity编译器solc的命令介绍

solc --help ,solc–help命令显示所有的solc命令选项。编译器可以生成各种输出,比如最终的二进制合约文件、语法树的汇编或者需要预计的要花费的gas等。 solc --bin sourceFile.sol ,可以编译后输出一个名为sourceFile.sol的智能合约文件。如果你想从 solc 获得更丰富的一些输出变量,你可以使用 solc -o outputDirectory --bin --ast --asm sourceFile.sol

你在部署以太坊智能合约之前可以用 solc --optimize --bin sourceFile.sol 优化一下。默认情况下solc编译器会帮你优化200次。你也可以设置 --runs=1 ,这样就按照最小化的方式进行编译,如果你希望多次交易不太在乎成本,那你可以设置成你想要的次数:)。

命令行编译器会自动读取需要导入的文件,也可以通过使用 prefix = path 来指定路径,例如:

solc github.com/ethereum/dapp-bin/=/usr/local/lib/dapp-bin/ =/usr/local/lib/fallback file.sol

这样编译器就会从指定目录 github.com/ethereum/dapp-bin/ 下的 /usr/local/lib/dapp-bin/ 目录开始搜索,如果没有找到文件,它将查看 /usr/local/lib/fallback 。solc将只读取你指定的这两个路径的,因此像 import "/etc/passwd"; 必须要通过 /= 重新映射才起作用。如果有多个匹配,则选择具有最长公共前缀的进行匹配。

出于安全上的考虑,编译器限制了它可以访问的一些目录。在命令行中指定的源文件的路径(及其子目录)和命令行指定的路径外其他所有内容都会被拒绝。 --allow-paths /sample/path,/another/sample/path 来切换。

如果智能合约使用了libraries,你会注意到字节码包含了 __LibraryName______ 的子字符串。您可以使用solc作为链接器,这意味着它将在这些点为您插入库地址。

可以通过添加库 --libraries "Math:0x12345678901234567890 Heap:0xabcdef0123456" 到您的命令,以提供每个库的地址,或者使用文件中的说明字符串(每行一个库),并使用 --libraries fileName 运行solc。

如果用选项 --link 调用Solc,则所有输入文件都被解释为未链接的二进制文件(HEX编码),在上面给出的 __LibraryName____ 格式中,将其链接到适当地址(如果从stdin读取输入,则将其写入stdout)。在这种情况下,除了库外,所有选项都被忽略(包括 -o )。

如果用 --standard-json 调用SOLC,它就将标准的JSON输入(如下所述),并返回JSON输出。

solc编译器输入输出JSON描述

这些JSON格式通过编译器API使用,可以通过SOLC获得。内容都是可以修改的,一些对象是可选的(如前所述),其目的是向后兼容。

编译器的API需要一个JSON格式的输入,然后以JSON格式输出编译结果。

注意不允许注释。下面示例中的注释,是官网为了学习者更好的理解标注的。

  • 输入格式说明:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
{
// Required: Source code language, such as "Solidity", "serpent", "lll", "assembly", etc.
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.
"urls":
[
"bzzr://56ab...",
"ipfs://Qma...",
"file:///tmp/path/to/file.sol"
]
},
"mortal":
{
// Optional: keccak256 hash of the source file
"keccak256": "0x234...",
// Required (unless "urls" is used): literal contents of the source file
"content": "contract mortal is owned { function kill() { if (msg.sender == owner) selfdestruct(owner); } }"
}
},
// Optional
settings:
{
// Optional: Sorted list of remappings
remappings: [ ":g/dir" ],
// Optional: Optimizer settings
optimizer: {
// disabled by default
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
},
evmVersion: "byzantium", // Version of the EVM to compile for. Affects type checking and code generation. Can be homestead, tangerineWhistle, spuriousDragon, byzantium or constantinople
// Metadata settings (optional)
metadata: {
// Use only literal content and not URLs (false by default)
useLiteralContent: true
},
// 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 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.
// 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 is the contract name, where empty contract name refers to the file itself,
// while the star refers to all of the contracts.
//
// The available output types are as follows:
// abi - ABI
// ast - AST of all source files
// legacyAST - legacy AST of all source files
// devdoc - Developer documentation (natspec)
// userdoc - User documentation (natspec)
// metadata - Metadata
// ir - New assembly format before desugaring
// evm.assembly - New assembly format after desugaring
// evm.legacyAssembly - Old-style assembly format in JSON
// 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.deployedBytecode* - Deployed bytecode (has the same options as evm.bytecode)
// evm.methodIdentifiers - The list of function hashes
// evm.gasEstimates - Function gas estimates
// ewasm.wast - eWASM S-expressions format (not supported atm)
// ewasm.wasm - eWASM binary format (not supported atm)
//
// Note that using a using `evm`, `evm.bytecode`, `ewasm`, etc. will select every
// target part of that output. Additionally, `*` can be used as a wildcard to request everything.
//
outputSelection: {
// Enable the metadata and bytecode outputs of every single contract.
"*": {
"*": [ "metadata", "evm.bytecode" ]
},
// Enable the abi and opcodes output of MyContract defined in file def.
"def": {
"MyContract": [ "abi", "evm.bytecode.opcodes" ]
},
// Enable the source map output of every single contract.
"*": {
"*": [ "evm.bytecode.sourceMap" ]
},
// Enable the legacy AST output of every single file.
"*": {
"": [ "legacyAST" ]
}
}
}
}
  • 输出格式说明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

{
// Optional: not present if no errors/warnings were encountered
errors: [
{
// Optional: Location within the source file.
sourceLocation: {
file: "sourceFile.sol",
start: 0,
end: 100
],
// 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", "ewasm", etc.
component: "general",
// Mandatory ("error" or "warning")
severity: "error",
// Mandatory
message: "Invalid keyword"
// Optional: the message formatted with source location
formattedMessage: "sourceFile.sol:100: Invalid keyword"
}
],
// This contains the file-level outputs. In can be limited/filtered by the outputSelection settings.
sources: {
"sourceFile.sol": {
// Identifier (used in source maps)
id: 1,
// The AST object
ast: {},
// The legacy AST object
legacyAST: {}
}
},
// 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://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
abi: [],
// See the Metadata Output documentation (serialised JSON string)
metadata: "{...}",
// User documentation (natspec)
userdoc: {},
// Developer documentation (natspec)
devdoc: {},
// Intermediate representation (string)
ir: "",
// EVM-related outputs
evm: {
// Assembly (string)
assembly: "",
// Old-style assembly (object)
legacyAssembly: {},
// Bytecode and related details.
bytecode: {
// The bytecode as a hex string.
object: "00fe",
// Opcodes list (string)
opcodes: "",
// The source mapping as a string. See the source mapping definition.
sourceMap: "",
// 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 }
]
}
}
},
// The same layout as above.
deployedBytecode: { },
// 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"
}
}
},
// eWASM related outputs
ewasm: {
// S-expressions format
wast: "",
// Binary format (hex string)
wasm: ""
}
}
}
}
}
  • 错误类型说明:
  1. JSONError:JSON错误,JSON输入不符合要求的格式,例如输入不是JSON对象,不支持语言,等等。
  2. IOError:IO错误,IO和导入处理错误,如提供的源中的不可解析URL或hash不匹配。
  3. ParserError:语法f分析错误,源代码不符合语言规则。
  4. DocstringParsingError:文档解析错误,无法解析注释块中的NATSPEC标记。
  5. SytRealError:语法错误,如continuefor循环之外使用。
  6. DeclarationError:声明错误,无效、不可解析或冲突的标识符名称。例如未找到标识符
  7. TypeError:类型错误,如无效类型转换、无效赋值等。
  8. UnimplementedFeatureError:编译器不支持该特性,但希望在将来的版本中得到支持。
  9. InternalCompilerError:编译器中触发内部错误,这应该作为一个问题来反馈。
  10. Exception:例外,编译过程中未知的故障,这应该作为一个问题反馈。
  11. CompilerError:编译错误,编译器堆栈的使用无效,这应该作为一个问题来反馈。
  12. FatalError:致命错误,这应该作为一个问题来反馈。
  13. Warning:警告并没有停止编译,但如果可能的话,应该加以处理。

如果你希望马上开始学习以太坊DApp开发,可以访问我们的在线互动课程:

  • 以太坊教程,主要介绍智能合约与dapp应用开发,适合入门。
  • 以太坊开发,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。

汇智网原创翻译,转载请标明出处,solc官网原文