1
1
from subprocess import *
2
2
import collections
3
+ import pprint
4
+ import logging
3
5
import errno
4
6
import os
5
7
import re
6
8
import sys
7
9
import tempfile
8
- import subprocess
10
+ from driver . popenwrapper import Popen
9
11
10
12
fullSelfPath = os .path .realpath (__file__ )
11
13
prefix = os .path .dirname (fullSelfPath )
12
14
driverDir = prefix
13
15
16
+ # Environmental variable for path to compiler tools (clang/llvm-link etc..)
17
+ llvmCompilerPathEnv = 'LLVM_COMPILER_PATH'
18
+
19
+ # This is the ELF section name inserted into binaries
20
+ elfSectionName = '.llvm_bc'
21
+
22
+ # Internal logger
23
+ _logger = logging .getLogger (__name__ )
24
+
14
25
# This class applies filters to GCC argument lists. It has a few
15
26
# default arguments that it records, but does not modify the argument
16
27
# list at all. It can be subclassed to change this behavior.
@@ -106,7 +117,7 @@ def __init__(self, inputList, exactMatches={}, patternMatches={}):
106
117
handler (self , currentItem , * flagArgs )
107
118
else :
108
119
matched = False
109
- for pattern , (arity , handler ) in argPatterns .iteritems ():
120
+ for pattern , (arity , handler ) in argPatterns .items ():
110
121
if re .match (pattern , currentItem ):
111
122
flagArgs = self ._shiftArgs (arity )
112
123
handler (self , currentItem , * flagArgs )
@@ -180,6 +191,39 @@ def __init__(self, arglist):
180
191
def outputFileCallback (self , flag , filename ):
181
192
self .outputFilename = filename
182
193
194
+
195
+ # Static class that allows the type of a file to be checked.
196
+ class FileType (object ):
197
+ # Provides int -> str map
198
+ revMap = { }
199
+
200
+ @classmethod
201
+ def getFileType (cls , fileName ):
202
+ # This is a hacky way of determining
203
+ # the type of file we are looking at.
204
+ # Maybe we should use python-magic instead?
205
+
206
+ fileP = Popen (['file' ,fileName ], stdout = PIPE )
207
+ output = fileP .communicate ()[0 ]
208
+ output = output .decode ()
209
+ if 'ELF' in output and 'executable' in output :
210
+ return cls .EXECUTABLE
211
+ elif 'current ar archive' in output :
212
+ return cls .ARCHIVE
213
+ elif 'ELF' in output and 'relocatable' in output :
214
+ return cls .OBJECT
215
+ else :
216
+ return cls .UNKNOWN
217
+
218
+ @classmethod
219
+ def init (cls ):
220
+ for (index , name ) in enumerate (('UNKNOWN' , 'EXECUTABLE' , 'OBJECT' , 'ARCHIVE' )):
221
+ setattr (cls , name , index )
222
+ cls .revMap [index ] = name
223
+
224
+ # Initialise FileType static class
225
+ FileType .init ()
226
+
183
227
def attachBitcodePathToObject (bcPath , outFileName ):
184
228
# Don't try to attach a bitcode path to a binary. Unfortunately
185
229
# that won't work.
@@ -189,9 +233,11 @@ def attachBitcodePathToObject(bcPath, outFileName):
189
233
190
234
# Now just build a temporary text file with the full path to the
191
235
# bitcode file that we'll write into the object file.
192
- f = tempfile .NamedTemporaryFile (mode = 'rw+b' , delete = False )
193
- f .write (os .path .abspath (bcPath ))
194
- f .write ('\n ' )
236
+ f = tempfile .NamedTemporaryFile (mode = 'w+b' , delete = False )
237
+ absBcPath = os .path .abspath (bcPath )
238
+ f .write (absBcPath .encode ())
239
+ f .write ('\n ' .encode ())
240
+ _logger .debug (pprint .pformat ('Wrote "{0}" to file "{1}"' .format (absBcPath , f .name )))
195
241
196
242
# Ensure buffers are flushed so that objcopy doesn't read an empty
197
243
# file
@@ -200,12 +246,12 @@ def attachBitcodePathToObject(bcPath, outFileName):
200
246
f .close ()
201
247
202
248
# Now write our .llvm_bc section
203
- objcopyCmd = ['objcopy' , '--add-section' , '.llvm_bc= {0}' .format (f .name ), outFileName ]
249
+ objcopyCmd = ['objcopy' , '--add-section' , '{0}={1} ' .format (elfSectionName , f .name ), outFileName ]
204
250
orc = 0
205
251
206
252
try :
207
253
if os .path .getsize (outFileName ) > 0 :
208
- objProc = subprocess . Popen (objcopyCmd )
254
+ objProc = Popen (objcopyCmd )
209
255
orc = objProc .wait ()
210
256
except OSError :
211
257
# configure loves to immediately delete things, causing issues for
@@ -216,28 +262,44 @@ def attachBitcodePathToObject(bcPath, outFileName):
216
262
os .remove (f .name )
217
263
218
264
if orc != 0 :
219
- print objcopyCmd
220
- print ('objcopy failed with {0}' .format (orc ))
265
+ _logger .error ('objcopy failed with {0}' .format (orc ))
221
266
sys .exit (- 1 )
222
267
223
268
class BuilderBase (object ):
224
- def __init__ (self , cmd , isCxx ):
269
+ def __init__ (self , cmd , isCxx , prefixPath = None ):
225
270
self .cmd = cmd
226
271
self .isCxx = isCxx
227
272
273
+ # Used as prefix path for compiler
274
+ if prefixPath :
275
+ self .prefixPath = prefixPath
276
+
277
+ # Ensure prefixPath has trailing slash
278
+ if self .prefixPath [- 1 ] != os .path .sep :
279
+ self .prefixPath = self .prefixPath + os .path .sep
280
+
281
+ # Check prefix path exists
282
+ if not os .path .exists (self .prefixPath ):
283
+ errorMsg = 'Path to compiler "{0}" does not exist' .format (self .prefixPath )
284
+ _logger .error (errorMsg )
285
+ raise Exception (errorMsg )
286
+
287
+ else :
288
+ self .prefixPath = ''
289
+
228
290
class ClangBuilder (BuilderBase ):
229
- def __init__ (self , cmd , isCxx ):
230
- super (ClangBuilder , self ).__init__ (cmd , isCxx )
291
+ def __init__ (self , cmd , isCxx , prefixPath = None ):
292
+ super (ClangBuilder , self ).__init__ (cmd , isCxx , prefixPath )
231
293
232
294
def getBitcodeCompiler (self ):
233
295
cc = self .getCompiler ()
234
296
return cc + ['-emit-llvm' ]
235
297
236
298
def getCompiler (self ):
237
299
if self .isCxx :
238
- return ['clang++' ]
300
+ return ['{0} clang++' . format ( self . prefixPath ) ]
239
301
else :
240
- return ['clang' ]
302
+ return ['{0} clang' . format ( self . prefixPath ) ]
241
303
242
304
def getBitcodeArglistFilter (self ):
243
305
return ClangBitcodeArgumentListFilter (self .cmd )
@@ -259,8 +321,8 @@ def attachBitcode(self, argFilter):
259
321
attachBitcodePathToObject (bcname , outFile )
260
322
261
323
class DragoneggBuilder (BuilderBase ):
262
- def __init__ (self , cmd , isCxx ):
263
- super (DragoneggBuilder , self ).__init__ (cmd , isCxx )
324
+ def __init__ (self , cmd , isCxx , prefixPath = None ):
325
+ super (DragoneggBuilder , self ).__init__ (cmd , isCxx , prefixPath )
264
326
265
327
def getBitcodeCompiler (self ):
266
328
pth = os .getenv ('LLVM_DRAGONEGG_PLUGIN' )
@@ -274,9 +336,9 @@ def getCompiler(self):
274
336
pfx = os .getenv ('LLVM_GCC_PREFIX' )
275
337
276
338
if self .isCxx :
277
- return ['{0}g++' .format (pfx )]
339
+ return ['{0}{1} g++' .format (self . prefixPath , pfx )]
278
340
else :
279
- return ['{0}gcc' .format (pfx )]
341
+ return ['{0}{1} gcc' .format (self . prefixPath , pfx )]
280
342
281
343
def getBitcodeArglistFilter (self ):
282
344
return ArgumentListFilter (self .cmd )
@@ -291,13 +353,25 @@ def extraBitcodeArgs(self, argFilter):
291
353
292
354
293
355
def getBuilder (cmd , isCxx ):
294
- cstring = os .getenv ('LLVM_COMPILER' )
356
+ compilerEnv = 'LLVM_COMPILER'
357
+ cstring = os .getenv (compilerEnv )
358
+ pathPrefix = os .getenv (llvmCompilerPathEnv ) # Optional
359
+ _logger .info ('WLLVM compiler using {0}' .format (cstring ))
360
+ if pathPrefix :
361
+ _logger .info ('WLLVM compiler path prefix "{0}"' .format (pathPrefix ))
362
+
295
363
if cstring == 'clang' :
296
- return ClangBuilder (cmd , isCxx )
364
+ return ClangBuilder (cmd , isCxx , pathPrefix )
297
365
elif cstring == 'dragonegg' :
298
- return DragoneggBuilder (cmd , isCxx )
366
+ return DragoneggBuilder (cmd , isCxx , pathPrefix )
367
+ elif cstring == None :
368
+ errorMsg = ' No compiler set. Please set environment variable ' + compilerEnv
369
+ _logger .critical (errorMsg )
370
+ raise Exception (errorMsg )
299
371
else :
300
- raise Exception ('Invalid compiler type: ' + cstring )
372
+ errorMsg = compilerEnv + '=' + str (cstring ) + ' : Invalid compiler type'
373
+ _logger .critical (errorMsg )
374
+ raise Exception (errorMsg )
301
375
302
376
def buildObject (builder ):
303
377
objCompiler = builder .getCompiler ()
@@ -330,3 +404,4 @@ def buildAndAttachBitcode(builder):
330
404
if rc == 0 :
331
405
builder .attachBitcode (af )
332
406
sys .exit (rc )
407
+
0 commit comments