date:20170728
使用命令行編譯器
Solidity代碼庫(kù)的構(gòu)建對(duì)象之一是solc,Solidity的命令行編譯器。使用solc --help可以解釋所有參數(shù)。編譯器可以生成不同的輸出,范圍從簡(jiǎn)單的二進(jìn)制和匯編一個(gè)抽象語(yǔ)法樹(shù)(解析樹(shù))到預(yù)估gas的用量。如果你只想要編譯單個(gè)文件,你只是想編譯單個(gè)文件,使用命令solc --bin sourceFile.sol可以生成二進(jìn)制。在你發(fā)布代碼之前,如果想要在編譯的時(shí)候使用優(yōu)化器,可以使用命令solc --optimize --bin sourceFile.sol。如果你想要獲取solc的一些更加高級(jí)的輸出變量,你可以讓它輸出所有的信息到一個(gè)單獨(dú)的文件中,使用命令solc -o outputDirectory --bin --ast --asm sourceFile.sol。
命令行編譯器會(huì)自動(dòng)的從文件系統(tǒng)中導(dǎo)入文件,但是可能通過(guò)如下的方式,使用prefix=path來(lái)重定向:
solc github.com/ethereum/dapp-bin/=/usr/local/lib/dapp-bin/ =/usr/local/lib/fallback file.sol
這條代碼本質(zhì)上是讓編譯器在/usr/local/lib/dapp-bin中查找所有github.com/ethereum/dapp-bin/開(kāi)頭的文件。如果沒(méi)有找到文件,會(huì)在/usr/lcoal/lib/fallback目錄里查找(空白的前綴總是會(huì)匹配)。solc不會(huì)在除了制定路徑外的其他路徑中查找文件,所以像import "/etc/passwd";只會(huì)在你添加了=/映射之后才會(huì)有效。
如果由于映射,會(huì)有多個(gè)匹配,那么會(huì)選擇最多匹配的前綴。
由于安全問(wèn)題,編譯器會(huì)限制可訪問(wèn)的路徑。源碼的路徑(和子路徑)在命令行中指定,并且重定向定義的路徑允許聲明導(dǎo)入。但是其他會(huì)被拒絕。另外的路徑(和子路徑)可以通過(guò)--allow-paths /sample/path,/another/sample/path來(lái)切換。
如果你的合約使用到了庫(kù),你會(huì)發(fā)現(xiàn)字節(jié)碼中包含__LibraryName______形式的字符串。你可以使用solc作為連接器,會(huì)在這些地方插入庫(kù)的地址。
或者在命令行中添加--libraries "Math:0x12345678901234567890 Heap:0xabcdef0123456"參數(shù)來(lái)為每個(gè)庫(kù)提供地址或者把他們保存在一個(gè)文件(一個(gè)庫(kù)一行)里,然后運(yùn)行solc,使用--libraries fileName參數(shù)。
如果solc命令中有--link參數(shù),所有的輸入文件都會(huì)當(dāng)做是沒(méi)有連接的庫(kù)(十六進(jìn)制編碼),在以上述的__LibraryName____處連接(如果輸入從stdin讀取,它會(huì)寫到stdout中)。這種情況下,所有參數(shù),除了--libraries都會(huì)被忽略(包含-o)。
如果solc命令中有--standard-json,它會(huì)在標(biāo)準(zhǔn)輸入中接收J(rèn)SON輸入(會(huì)在下文敘述),并且在標(biāo)準(zhǔn)輸出中返回JSON輸出。
編譯輸入和輸出的JSON描述
這些JSON格式會(huì)被用作編譯器的api,也可以通過(guò)solc使用。這些可能會(huì)有更改,有些字段是可選的(已經(jīng)說(shuō)過(guò)了)。但是只會(huì)做一些后向兼容的更改。
編譯器API期望JSON格式的輸入并輸出JSON格式的編譯結(jié)果。
當(dāng)然,注釋是不允許的,這里只是為了說(shuō)明情況。
輸入描述
{
// 必須字段:源碼語(yǔ)言,可以是"Solidity", "serpent", "lll", "assembly", 等等
language: "Solidity",
// 必須字段
sources:
{
// 鍵是源文件的“全局”名稱。
// imports可以使用其他重定向的文件(看下文)
"myFile.sol":
{
// 可選的參數(shù): 源文件的keccak256 hash值
// 如果它被導(dǎo)入,它會(huì)被用來(lái)驗(yàn)證獲得的內(nèi)容。
"keccak256": "0x123...",
// 必須字段(除非使用了“content”字段,看下文): 源文件的URL(s)
// URL(s) 應(yīng)該按順序?qū)?,并且結(jié)果要進(jìn)行keccak256驗(yàn)證。如果hash值不匹配,或者不能正確加載URL(s),就會(huì)產(chǎn)生一個(gè)錯(cuò)誤。
"urls":
[
"bzzr://56ab...",
"ipfs://Qma...",
"file:///tmp/path/to/file.sol"
]
},
"mortal":
{
// 可選字段:源文件的keccak256 hash值
Optional: keccak256 hash of the source file
"keccak256": "0x234...",
// 必須字段(除非“urls”字段被使用): 源文件的字面量信息
"content": "contract mortal is owned { function kill() { if (msg.sender == owner) selfdestruct(owner); } }"
}
},
// 可選字段
settings:
{
// 可選字段: 排過(guò)序的重定向
remappings: [ ":g/dir" ],
// 可選字段: 優(yōu)化器設(shè)置(enabled默認(rèn)為false)
optimizer: {
enabled: true,
runs: 500
},
// 元數(shù)據(jù)設(shè)置 (可選的)
metadata: {
// 只能使用字面量?jī)?nèi)容,并且不能有URLs(默認(rèn)不支持)。
useLiteralContent: true
},
// 庫(kù)的地址。如果這里沒(méi)有給出所有的庫(kù),這會(huì)導(dǎo)致生成沒(méi)有連接的對(duì)象,這些對(duì)象的輸出是不同的。
libraries: {
// 最上層的鍵是所需庫(kù)的源文件的名稱。
// 如果使用了重定向,這些源文件會(huì)在映射作用之后匹配全局路徑。
// 如果鍵是空字符串,他會(huì)被引用到全局層級(jí)。
"myFile.sol": {
"MyLib": "0x123123..."
}
}
// 下面的參數(shù)可以用來(lái)指定期望的輸出。
// 如果沒(méi)有這個(gè)字段,編譯器會(huì)載入并做類型檢測(cè),但是不會(huì)生成其他輸出。除非出現(xiàn)錯(cuò)誤。
// 第一層的鍵是文件的名稱,第二層是合約的名稱,如果合約的名稱為空,會(huì)引用文件的名稱。
// 星號(hào)代表著所有合約
//
// 有效的輸出類型如下所示:
// abi - ABI
// ast - 所有源文件的AST
// legacyAST - 所有源文件的legacy AST
// devdoc - 開(kāi)發(fā)文檔 (natspec)
// userdoc - 用戶手冊(cè) (natspec)
// metadata - 元素?fù)?jù)
// ir - 在去語(yǔ)法糖之前的新匯編形式
// evm.assembly - 在去語(yǔ)法糖之后的新匯編形式
// evm.legacyAssembly - JSON格式的舊類型的匯編形式
// evm.bytecode.object - 字節(jié)碼對(duì)象
// evm.bytecode.opcodes - 操作碼列表
// evm.bytecode.sourceMap - 源碼映射(調(diào)試很有用)
// evm.bytecode.linkReferences - 引用連接 (如果是沒(méi)有連接的對(duì)象)
// evm.deployedBytecode* - 發(fā)布字節(jié)碼 (和evm.bytecode有相同的選項(xiàng))
// evm.methodIdentifiers - 函數(shù)列表的hash
// evm.gasEstimates - gas估計(jì)函數(shù)
// ewasm.wast - eWASM S-表達(dá)式 格式 (不支持 atm)
// ewasm.wasm - eWASM 二進(jìn)制格式 (不支持 atm)
//
// 注意使用 `evm`, `evm.bytecode`, `ewasm`, 等. 會(huì)選擇輸出的每個(gè)目標(biāo)部分
//
outputSelection: {
// 使能每個(gè)簡(jiǎn)單合約的元數(shù)據(jù)和字節(jié)碼
"*": {
"*": [ "metadata", "evm.bytecode" ]
},
// 對(duì)文件def,使能 MyContract合約的abi和操作碼輸出。
"def": {
"MyContract": [ "abi", "evm.opcodes" ]
},
// 使能每個(gè)合約的源映射
"*": {
"*": [ "evm.sourceMap" ]
},
// 使能每個(gè)文件的legacyAST輸出
"*": {
"": [ "legacyAST" ]
}
}
}
}
輸出描述
{
// 可選字段:如果沒(méi)有錯(cuò)誤或者警告,就不會(huì)生成這個(gè)字段。
errors: [
{
// 可選字段:源文件的位置
sourceLocation: {
file: "sourceFile.sol",
start: 0,
end: 100
],
// 強(qiáng)制的: 錯(cuò)誤類型,如"TypeError", "InternalCompilerError", "Exception", 等
type: "TypeError",
// 強(qiáng)制的: 發(fā)生錯(cuò)誤的組件,如"general", "ewasm", 等
component: "general",
// 強(qiáng)制的 ("error" 或者 "warning")
severity: "error",
// 強(qiáng)制的
message: "Invalid keyword"
// 可選的: 格式化的信息,說(shuō)明出錯(cuò)的源碼位置。
formattedMessage: "sourceFile.sol:100: Invalid keyword"
}
],
// 這包含文件層級(jí)的輸出,它通過(guò) outputSelection 設(shè)置來(lái)限制或者過(guò)濾。
sources: {
"sourceFile.sol": {
// 標(biāo)識(shí)符 (用于源碼映射)
id: 1,
// AST 對(duì)象
ast: {},
// legacy AST 對(duì)象
legacyAST: {}
}
},
// 這里包含合約層級(jí)的輸出??梢酝ㄟ^(guò) outputSelection 設(shè)置來(lái)限制或者過(guò)濾.
contracts: {
"sourceFile.sol": {
// 如果語(yǔ)言沒(méi)有合約名稱,這個(gè)字段像是空字段。
"ContractName": {
// 以太坊合約 ABI. 如果為空,會(huì)呈現(xiàn)為空數(shù)組。
// 詳情查看 https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
abi: [],
// 查看輸出文檔的元數(shù)據(jù) (JSON 字符串連載)
metadata: "{...}",
// 用戶手冊(cè) (natspec)
userdoc: {},
// 開(kāi)發(fā)文檔 (natspec)
devdoc: {},
// 中間件(字符串)
ir: "",
// EVM-相關(guān)輸出
evm: {
// 匯編 (字符串)
assembly: "",
// 舊格式匯編 (對(duì)象)
legacyAssembly: {},
// 字節(jié)碼和相關(guān)詳情
bytecode: {
// 十六進(jìn)制字符串的字節(jié)碼
object: "00fe",
// 操作碼列表 (字符串)
opcodes: "",
// 字符串形式的源碼映射。查看源碼映射定義。
sourceMap: "",
// 如果給定這個(gè)字段,這是未連接的對(duì)象
linkReferences: {
"libraryFile.sol": {
// 字節(jié)碼偏移。連接會(huì)在指定位置替換20字節(jié)
Byte offsets into the bytecode. Linking replaces the 20 bytes located there.
"Library1": [
{ start: 0, length: 20 },
{ start: 200, length: 20 }
]
}
}
},
// 和上面字段結(jié)構(gòu)相同
deployedBytecode: { },
// 函數(shù)列表的哈希
methodIdentifiers: {
"delegate(address)": "5c19a95c"
},
// 函數(shù) gas 估計(jì)
gasEstimates: {
creation: {
codeDepositCost: "420000",
executionCost: "infinite",
totalCost: "infinite"
},
external: {
"delegate(address)": "25000"
},
internal: {
"heavyLifting()": "infinite"
}
}
},
// eWASM 相關(guān)的輸出
ewasm: {
// S-表達(dá)式 格式
wast: "",
// 二進(jìn)制格式 (十六進(jìn)制字符串)
wasm: ""
}
}
}
}
}