3
3
import re
4
4
import subprocess
5
5
import warnings
6
+ import shlex
6
7
7
8
import yaml
8
9
@@ -22,6 +23,11 @@ def get_compiler_path():
22
23
This funtion will search for the solc binary in the $PATH and return the
23
24
path of the first executable occurence.
24
25
"""
26
+ # If the user provides a specific solc binary let's use that
27
+ given_binary = os .environ .get ('SOLC_BINARY' )
28
+ if given_binary :
29
+ return given_binary
30
+
25
31
for path in os .getenv ('PATH' , '' ).split (os .pathsep ):
26
32
path = path .strip ('"' )
27
33
executable_path = os .path .join (path , BINARY )
@@ -40,16 +46,22 @@ def get_solidity():
40
46
return solc_wrapper
41
47
42
48
43
- def solc_arguments (libraries = None , combined = 'bin,abi' , optimize = True ):
49
+ def solc_arguments (libraries = None , combined = 'bin,abi' , optimize = True , extra_args = None ):
44
50
""" Build the arguments to call the solc binary. """
45
51
args = [
46
52
'--combined-json' , combined ,
47
- '--add-std' ,
53
+ '--add-std'
48
54
]
49
55
50
56
if optimize :
51
57
args .append ('--optimize' )
52
58
59
+ if extra_args :
60
+ try :
61
+ args .extend (shlex .split (extra_args ))
62
+ except : # if not a parseable string then treat it as a list
63
+ args .extend (extra_args )
64
+
53
65
if libraries is not None and len (libraries ):
54
66
addresses = [
55
67
'{name}:{address}' .format (name = name , address = address .decode ('utf8' ))
@@ -65,6 +77,10 @@ def solc_arguments(libraries=None, combined='bin,abi', optimize=True):
65
77
66
78
def solc_parse_output (compiler_output ):
67
79
""" Parses the compiler output. """
80
+ # At the moment some solc output like --hashes or -- gas will not output
81
+ # json at all so if used with those arguments the logic here will break.
82
+ # Perhaps solidity will slowly switch to a json only output and this comment
83
+ # can eventually go away and we will not need to add more logic here at all.
68
84
result = yaml .safe_load (compiler_output )['contracts' ]
69
85
70
86
if 'bin' in tuple (result .values ())[0 ]:
@@ -93,7 +109,7 @@ def solc_parse_output(compiler_output):
93
109
def compiler_version ():
94
110
""" Return the version of the installed solc. """
95
111
version_info = subprocess .check_output (['solc' , '--version' ])
96
- match = re .search ('^Version: ([0-9a-z.-]+)/' , version_info , re .MULTILINE )
112
+ match = re .search (b '^Version: ([0-9a-z.-]+)/' , version_info , re .MULTILINE )
97
113
98
114
if match :
99
115
return match .group (1 )
@@ -185,7 +201,7 @@ def solidity_resolve_address(hex_code, library_symbol, library_address):
185
201
raise ValueError ('Address should not contain the 0x prefix' )
186
202
187
203
try :
188
- _ = decode_hex (library_address )
204
+ decode_hex (library_address )
189
205
except TypeError :
190
206
raise ValueError ('library_address contains invalid characters, it must be hex encoded.' )
191
207
@@ -221,7 +237,7 @@ def solidity_unresolved_symbols(hex_code):
221
237
return set (re .findall (r"_.{39}" , hex_code ))
222
238
223
239
224
- def compile_file (filepath , libraries = None , combined = 'bin,abi' , optimize = True ):
240
+ def compile_file (filepath , libraries = None , combined = 'bin,abi' , optimize = True , extra_args = None ):
225
241
""" Return the compile contract code.
226
242
227
243
Args:
@@ -236,7 +252,7 @@ def compile_file(filepath, libraries=None, combined='bin,abi', optimize=True):
236
252
237
253
workdir , filename = os .path .split (filepath )
238
254
239
- args = solc_arguments (libraries = libraries , combined = combined , optimize = optimize )
255
+ args = solc_arguments (libraries = libraries , combined = combined , optimize = optimize , extra_args = extra_args )
240
256
args .insert (0 , get_compiler_path ())
241
257
args .append (filename )
242
258
@@ -245,18 +261,19 @@ def compile_file(filepath, libraries=None, combined='bin,abi', optimize=True):
245
261
return solc_parse_output (output )
246
262
247
263
248
- def compile_contract (filepath , contract_name , libraries = None , combined = 'bin,abi' , optimize = True ):
264
+ def compile_contract (filepath , contract_name , libraries = None , combined = 'bin,abi' , optimize = True , extra_args = None ):
249
265
all_contracts = compile_file (
250
266
filepath ,
251
267
libraries = libraries ,
252
268
combined = combined ,
253
269
optimize = optimize ,
270
+ extra_args = extra_args
254
271
)
255
272
256
273
return all_contracts [contract_name ]
257
274
258
275
259
- def compile_last_contract (filepath , libraries = None , combined = 'bin,abi' , optimize = True ):
276
+ def compile_last_contract (filepath , libraries = None , combined = 'bin,abi' , optimize = True , extra_args = None ):
260
277
with open (filepath ) as handler :
261
278
all_names = solidity_names (handler .read ())
262
279
@@ -273,11 +290,12 @@ def compile_last_contract(filepath, libraries=None, combined='bin,abi', optimize
273
290
libraries = libraries ,
274
291
combined = combined ,
275
292
optimize = optimize ,
293
+ extra_args = extra_args
276
294
)
277
295
278
296
279
- def compile_code (sourcecode , libraries = None , combined = 'bin,abi' , optimize = True ):
280
- args = solc_arguments (libraries = libraries , combined = combined , optimize = optimize )
297
+ def compile_code (sourcecode , libraries = None , combined = 'bin,abi' , optimize = True , extra_args = None ):
298
+ args = solc_arguments (libraries = libraries , combined = combined , optimize = optimize , extra_args = extra_args )
281
299
args .insert (0 , get_compiler_path ())
282
300
283
301
process = subprocess .Popen (args , stdin = subprocess .PIPE , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
@@ -297,17 +315,17 @@ class Solc(object):
297
315
compiler_version = staticmethod (compiler_version )
298
316
299
317
@staticmethod
300
- def _code_or_path (sourcecode , path , contract_name , libraries , combined ):
318
+ def _code_or_path (sourcecode , path , contract_name , libraries , combined , extra_args ):
301
319
warnings .warn ('solc_wrapper is deprecated, please use the functions compile_file or compile_code' )
302
320
303
321
if sourcecode and path :
304
322
raise ValueError ('sourcecode and path are mutually exclusive.' )
305
323
306
324
if path and contract_name :
307
- return compile_contract (path , contract_name , libraries = libraries , combined = combined )
325
+ return compile_contract (path , contract_name , libraries = libraries , combined = combined , extra_args = extra_args )
308
326
309
327
if path :
310
- return compile_last_contract (path , libraries = libraries , combined = combined )
328
+ return compile_last_contract (path , libraries = libraries , combined = combined , extra_args = extra_args )
311
329
312
330
all_names = solidity_names (sourcecode )
313
331
all_contract_names = [
@@ -316,41 +334,44 @@ def _code_or_path(sourcecode, path, contract_name, libraries, combined):
316
334
]
317
335
last_contract = all_contract_names [- 1 ]
318
336
319
- result = compile_code (sourcecode , libraries = libraries , combined = combined )
337
+ result = compile_code (sourcecode , libraries = libraries , combined = combined , extra_args = extra_args )
320
338
return result [last_contract ]
321
339
322
340
@classmethod
323
- def compile (cls , code , path = None , libraries = None , contract_name = '' ):
341
+ def compile (cls , code , path = None , libraries = None , contract_name = '' , extra_args = None ):
324
342
""" Return the binary of last contract in code. """
325
- result = cls ._code_or_path (code , path , contract_name , libraries , 'bin' )
343
+ result = cls ._code_or_path (code , path , contract_name , libraries , 'bin' , extra_args )
326
344
return result ['bin' ]
327
345
328
346
@classmethod
329
- def mk_full_signature (cls , code , path = None , libraries = None , contract_name = '' ):
347
+ def mk_full_signature (cls , code , path = None , libraries = None , contract_name = '' , extra_args = None ):
330
348
"returns signature of last contract in code"
331
349
332
- result = cls ._code_or_path (code , path , contract_name , libraries , 'abi' )
350
+ result = cls ._code_or_path (code , path , contract_name , libraries , 'abi' , extra_args )
333
351
return result ['abi' ]
334
352
335
353
@classmethod
336
- def combined (cls , code , path = None ):
354
+ def combined (cls , code , path = None , extra_args = None ):
337
355
""" Compile combined-json with abi,bin,devdoc,userdoc.
338
356
339
357
@param code: literal solidity code as a string.
340
- @param path: absolute path to solidity-file. Note: code & path are exclusive!
358
+ @param path: absolute path to solidity-file. Note: code & path are
359
+ mutually exclusive!
360
+ @param extra_args: Either a space separated string or a list of extra
361
+ arguments to be passed to the solidity compiler.
341
362
"""
342
363
343
364
if code and path :
344
365
raise ValueError ('sourcecode and path are mutually exclusive.' )
345
366
346
367
if path :
347
- contracts = compile_file (path )
368
+ contracts = compile_file (path , extra_args = extra_args )
348
369
349
370
with open (path ) as handler :
350
371
code = handler .read ()
351
372
352
373
elif code :
353
- contracts = compile_code (code )
374
+ contracts = compile_code (code , extra_args = extra_args )
354
375
355
376
else :
356
377
raise ValueError ('either code or path needs to be supplied.' )
@@ -361,7 +382,7 @@ def combined(cls, code, path=None):
361
382
return sorted_contracts
362
383
363
384
@classmethod
364
- def compile_rich (cls , code , path = None ):
385
+ def compile_rich (cls , code , path = None , extra_args = None ):
365
386
"""full format as returned by jsonrpc"""
366
387
367
388
return {
@@ -378,7 +399,7 @@ def compile_rich(cls, code, path=None):
378
399
},
379
400
}
380
401
for contract_name , contract
381
- in cls .combined (code , path = path )
402
+ in cls .combined (code , path = path , extra_args = extra_args )
382
403
}
383
404
384
405
0 commit comments