Skip to content

Commit b5de01c

Browse files
authored
Merge pull request travitch#58 from SRI-CSL/master
--emit-llvm, bitcode store, and minor bug fixes.
2 parents b5cbb65 + 2c345e1 commit b5de01c

File tree

8 files changed

+109
-77
lines changed

8 files changed

+109
-77
lines changed

README.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ As of August 2016 WLLVM is now a pip package. You can just do:
4040

4141
pip install wllvm
4242

43-
or
43+
or
4444

4545
sudo pip install wllvm
4646

@@ -222,8 +222,19 @@ Building a bitcode archive then extracting the bitcode
222222
llvm-ar x libjansson.bca
223223
ls -la
224224

225-
226225

226+
Preserving bitcode files in a store
227+
--------------------------------
228+
229+
Sometimes it can be useful to preserve the bitcode files produced in a
230+
build, either to prevent deletion or to retrieve it later. If the
231+
environment variable `WLLVM_BC_STORE` is set to the absolute path of
232+
an existing directory,
233+
then WLLVM will copy the produced bitcode file into that directory.
234+
The name of the copied bitcode file is the hash of the path to the
235+
original bitcode file. For convenience, when using both the manifest
236+
feature of `extract-bc` and the store, the manifest will contain both
237+
the original path, and the store path.
227238

228239

229240
Debugging

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
description='Whole Program LLVM',
2121
long_description=long_description,
2222
url='https://github.com/SRI-CSL/whole-program-llvm',
23-
author='Ian A. Mason, Tristan Ravitch, Dan Liew, Bruno Dutertre, Benjamin Schubert, Berkeley Churchill, Marko Dimjasevic, Will Dietz, Fabian Mager, Ben Liblit, Andrew Santosa.',
23+
author='Ian A. Mason, Tristan Ravitch, Dan Liew, Bruno Dutertre, Benjamin Schubert, Berkeley Churchill, Marko Dimjasevic, Will Dietz, Fabian Mager, Ben Liblit, Andrew Santosa, Tomas Kalibera, Loic Gelle.',
2424
author_email='iam@csl.sri.com',
2525

2626

test/test_files/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#iam: please leave this Makefile; it is useful for debugging when things break.
22

3+
all: one archive
34

45
zero:
56
${CXX} hello.cc -o hello

wllvm/arglistfilter.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ def __init__(self, inputList, exactMatches={}, patternMatches={}):
264264
self._inputArgs = collections.deque(inputList)
265265

266266
#iam: parse the cmd line, bailing if we discover that there will be no second phase.
267-
while (len(self._inputArgs) > 0 and
267+
while (self._inputArgs and
268268
not (self.isAssembly or
269269
self.isAssembleOnly or
270270
self.isPreprocessOnly)):
@@ -397,8 +397,7 @@ def getOutputFilename(self):
397397
(_, base) = os.path.split(self.inputFiles[0])
398398
(root, _) = os.path.splitext(base)
399399
return '{0}.o'.format(root)
400-
else:
401-
return 'a.out'
400+
return 'a.out'
402401

403402
# iam: returns a pair [objectFilename, bitcodeFilename] i.e .o and .bc.
404403
# the hidden flag determines whether the objectFile is hidden like the

wllvm/checker.py

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import subprocess as sp
1414
import errno
1515

16+
from .version import wllvm_version
1617

1718
explain_LLVM_COMPILER = """
1819
@@ -90,6 +91,7 @@ def check(self):
9091
1. Check that the OS is supported.
9192
2. Checks that the compiler settings make sense.
9293
3. Checks that the needed LLVM utilities exists.
94+
4. Check that the store, if set, exists.
9395
"""
9496

9597
if not self.checkOS():
@@ -100,6 +102,7 @@ def check(self):
100102

101103
if success:
102104
self.checkAuxiliaries()
105+
self.checkStore()
103106

104107
return 0 if success else 1
105108

@@ -115,12 +118,12 @@ def checkOS(self):
115118
def checkSwitch(self):
116119
"""Checks the correctness of the LLVM_COMPILER env var."""
117120
compiler_type = os.getenv('LLVM_COMPILER')
121+
vmsg = 'We are wllvm version {0} and'.format(wllvm_version)
118122
if compiler_type == 'clang':
119-
return (1, '\nGood, we are using clang.\n')
123+
return (1, '\n{0} we are using clang.\n'.format(vmsg))
120124
elif compiler_type == 'dragonegg':
121-
return (2, '\nOK, we are using dragonegg.\n')
122-
else:
123-
return (0, explain_LLVM_COMPILER)
125+
return (2, '\n{0} we are using dragonegg.\n'.format(vmsg))
126+
return (0, explain_LLVM_COMPILER)
124127

125128

126129
def checkClang(self):
@@ -182,9 +185,8 @@ def checkCompiler(self):
182185
elif code == 2:
183186
print(comment)
184187
return self.checkDragonegg()
185-
else:
186-
print('Insane')
187-
return False
188+
print('Insane')
189+
return False
188190

189191

190192

@@ -196,12 +198,12 @@ def checkCompilers(self, cc, cxx):
196198
if not ccOk:
197199
print('The C compiler {0} was not found or not executable.\nBetter not try using wllvm!\n'.format(cc))
198200
else:
199-
print('The C compiler {0} is:\n\n{1}\n'.format(cc, extractLine(ccVersion, 0)))
201+
print('The C compiler {0} is:\n\n\t{1}\n'.format(cc, extractLine(ccVersion, 0)))
200202

201203
if not cxxOk:
202204
print('The CXX compiler {0} was not found or not executable.\nBetter not try using wllvm++!\n'.format(cxx))
203205
else:
204-
print('The C++ compiler {0} is:\n\n{1}\n'.format(cxx, extractLine(cxxVersion, 0)))
206+
print('The C++ compiler {0} is:\n\n\t{1}\n'.format(cxx, extractLine(cxxVersion, 0)))
205207

206208
if not ccOk or not cxxOk:
207209
print(explain_LLVM_COMPILER_PATH)
@@ -227,8 +229,7 @@ def checkExecutable(self, exe, version_switch='-v'):
227229
return (False, '{0} not executable'.format(exe))
228230
elif e.errno == errno.ENOENT:
229231
return (False, '{0} not found'.format(exe))
230-
else:
231-
return (False, '{0} not sure why, errno is {1}'.format(exe, e.errno))
232+
return (False, '{0} not sure why, errno is {1}'.format(exe, e.errno))
232233
else:
233234
return (True, compilerOutput)
234235

@@ -256,21 +257,30 @@ def checkAuxiliaries(self):
256257
print('The bitcode linker {0} was not found or not executable.\nBetter not try using extract-bc!\n'.format(link))
257258
print(explain_LLVM_LINK_NAME)
258259
else:
259-
print('The bitcode linker {0} is:\n\n{1}\n'.format(link, extractLine(linkVersion, 1)))
260+
print('The bitcode linker {0} is:\n\n\t{1}\n'.format(link, extractLine(linkVersion, 1)))
260261

261262
if not arOk:
262263
print('The bitcode archiver {0} was not found or not executable.\nBetter not try using extract-bc!\n'.format(ar))
263264
print(explain_LLVM_AR_NAME)
264265
else:
265-
print('The bitcode archiver {0} is:\n\n{1}\n'.format(ar, extractLine(arVersion, 1)))
266+
print('The bitcode archiver {0} is:\n\n\t{1}\n'.format(ar, extractLine(arVersion, 1)))
266267

267268

269+
def checkStore(self):
270+
"""Checks that the bitcode store, if set, makes sense."""
271+
store_dir = os.getenv('WLLVM_BC_STORE')
272+
if store_dir:
273+
if os.path.exists(store_dir) and os.path.isdir(store_dir) and os.path.isabs(store_dir):
274+
print('Using the bitcode store:\n\n\t{0}\n\n'.format(store_dir))
275+
else:
276+
print('The bitcode store:\n\n\t{0}\n\nis either not absolute, does not exist, or is not a directory.\n\n'.format(store_dir))
277+
else:
278+
print('Not using a bitcode store.\n\n')
279+
268280

269281
def extractLine(version, n):
270282
if not version:
271283
return version
272284
lines = version.split('\n')
273-
if n < len(lines):
274-
return lines[n]
275-
else:
276-
return lines[-1]
285+
line = lines[n] if n < len(lines) else lines[-1]
286+
return line.strip() if line else line

wllvm/compilers.py

Lines changed: 16 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import os
66
import sys
77
import tempfile
8+
import hashlib
89

10+
from shutil import copyfile
911
from .filetype import FileType
1012
from .popenwrapper import Popen
1113
from .arglistfilter import ArgumentListFilter
@@ -120,6 +122,13 @@ def attachBitcodePathToObject(bcPath, outFileName):
120122
_logger.error('objcopy failed with %s', orc)
121123
sys.exit(-1)
122124

125+
# loicg: If the environment variable WLLVM_BC_STORE is set, copy the bitcode
126+
# file to that location, using a hash of the original bitcode path as a name
127+
storeEnv = os.getenv('WLLVM_BC_STORE')
128+
if storeEnv:
129+
hashName = hashlib.sha256(absBcPath).hexdigest()
130+
copyfile(absBcPath, os.path.join(storeEnv, hashName))
131+
123132
class BuilderBase(object):
124133
def __init__(self, cmd, isCxx, prefixPath=None):
125134
self.cmd = cmd
@@ -140,16 +149,7 @@ def __init__(self, cmd, isCxx, prefixPath=None):
140149
else:
141150
self.prefixPath = ''
142151

143-
#clang and dragonegg share the same taste in bitcode filenames.
144-
def getBitcodeFileName(self, argFilter):
145-
(dirs, baseFile) = os.path.split(argFilter.getOutputFilename())
146-
bcfilename = os.path.join(dirs, '.{0}.bc'.format(baseFile))
147-
return bcfilename
148-
149152
class ClangBuilder(BuilderBase):
150-
def __init__(self, cmd, isCxx, prefixPath=None):
151-
super(ClangBuilder, self).__init__(cmd, isCxx, prefixPath)
152-
153153
def getBitcodeCompiler(self):
154154
cc = self.getCompiler()
155155
return cc + ['-emit-llvm']
@@ -159,31 +159,16 @@ def getCompiler(self):
159159
cxx = os.getenv('LLVM_CXX_NAME')
160160
if cxx:
161161
return ['{0}{1}'.format(self.prefixPath, cxx)]
162-
else:
163-
return ['{0}clang++'.format(self.prefixPath)]
164-
else:
165-
cc = os.getenv('LLVM_CC_NAME')
166-
if cc:
167-
return ['{0}{1}'.format(self.prefixPath, cc)]
168-
else:
169-
return ['{0}clang'.format(self.prefixPath)]
162+
return ['{0}clang++'.format(self.prefixPath)]
163+
cc = os.getenv('LLVM_CC_NAME')
164+
if cc:
165+
return ['{0}{1}'.format(self.prefixPath, cc)]
166+
return ['{0}clang'.format(self.prefixPath)]
170167

171168
def getBitcodeArglistFilter(self):
172169
return ClangBitcodeArgumentListFilter(self.cmd)
173170

174-
def extraBitcodeArgs(self, argFilter):
175-
bcPath = self.getBitcodeFileName(argFilter)
176-
return ['-o', bcPath]
177-
178-
def attachBitcode(self, argFilter):
179-
bcname = self.getBitcodeFileName(argFilter)
180-
outFile = argFilter.getOutputFilename()
181-
attachBitcodePathToObject(bcname, outFile)
182-
183171
class DragoneggBuilder(BuilderBase):
184-
def __init__(self, cmd, isCxx, prefixPath=None):
185-
super(DragoneggBuilder, self).__init__(cmd, isCxx, prefixPath)
186-
187172
def getBitcodeCompiler(self):
188173
pth = os.getenv('LLVM_DRAGONEGG_PLUGIN')
189174
cc = self.getCompiler()
@@ -201,21 +186,11 @@ def getCompiler(self):
201186

202187
if self.isCxx:
203188
return ['{0}{1}g++'.format(self.prefixPath, pfx)]
204-
else:
205-
return ['{0}{1}gcc'.format(self.prefixPath, pfx)]
189+
return ['{0}{1}gcc'.format(self.prefixPath, pfx)]
206190

207191
def getBitcodeArglistFilter(self):
208192
return ArgumentListFilter(self.cmd)
209193

210-
# Don't need to do anything since the -B flag in the bitcode
211-
# compiler and the assembly stub handles it
212-
def attachBitcode(self, argFilter):
213-
pass
214-
215-
def extraBitcodeArgs(self, _):
216-
return []
217-
218-
219194
def getBuilder(cmd, isCxx):
220195
compilerEnv = 'LLVM_COMPILER'
221196
cstring = os.getenv(compilerEnv)
@@ -251,7 +226,7 @@ def buildAndAttachBitcode(builder):
251226

252227
af = builder.getBitcodeArglistFilter()
253228

254-
if len(af.inputFiles) == 0 or af.isEmitLLVM or af.isAssembly or af.isAssembleOnly or (af.isDependencyOnly and not af.isCompileOnly) or af.isPreprocessOnly:
229+
if not af.inputFiles or af.isEmitLLVM or af.isAssembly or af.isAssembleOnly or (af.isDependencyOnly and not af.isCompileOnly) or af.isPreprocessOnly:
255230
_logger.debug('No work to do')
256231
_logger.debug(af.__dict__)
257232
return
@@ -271,9 +246,6 @@ def buildAndAttachBitcode(builder):
271246
# maybe python-magic is in our future ...
272247
srcFile = af.inputFiles[0]
273248
(objFile, bcFile) = af.getArtifactNames(srcFile, hidden)
274-
if af.outputFilename is not None:
275-
objFile = af.outputFilename
276-
bcFile = builder.getBitcodeFileName(af)
277249
buildBitcodeFile(builder, srcFile, bcFile)
278250
attachBitcodePathToObject(bcFile, objFile)
279251

wllvm/extraction.py

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import tempfile
99
import shutil
1010
import argparse
11+
import hashlib
1112

1213
from .popenwrapper import Popen
1314

@@ -149,11 +150,38 @@ def extract_section_linux(inputFile):
149150
return contents
150151

151152

153+
def getStorePath(bcPath):
154+
storeEnv = os.getenv('WLLVM_BC_STORE')
155+
if storeEnv:
156+
hashName = hashlib.sha256(bcPath).hexdigest()
157+
hashPath = os.path.join(storeEnv, hashName)
158+
if os.path.isfile(hashPath):
159+
return hashPath
160+
return None
161+
162+
163+
def getBitcodePath(bcPath):
164+
"""Tries to resolve the whereabouts of the bitcode.
165+
166+
First, ihecks if the given path points to an existing bitcode file.
167+
If it does not, it tries to look for the bitcode file in the store directory given
168+
by the environment variable WLLVM_BC_STORE.
169+
"""
170+
171+
if not bcPath or os.path.isfile(bcPath):
172+
return bcPath
173+
174+
storePath = getStorePath(bcPath)
175+
if storePath:
176+
return storePath
177+
return bcPath
178+
152179
def linkFiles(pArgs, fileNames):
153180
linkCmd = [pArgs.llvmLinker, '-v'] if pArgs.verboseFlag else [pArgs.llvmLinker]
154181

155-
linkCmd.extend(['-o', pArgs.outputFile])
182+
linkCmd.append('-o={0}'.format(pArgs.outputFile))
156183

184+
fileNames = map(getBitcodePath, fileNames)
157185
linkCmd.extend([x for x in fileNames if x != ''])
158186
_logger.info('Writing output to %s', pArgs.outputFile)
159187
try:
@@ -216,10 +244,7 @@ def handleExecutable(pArgs):
216244
return 1
217245

218246
if pArgs.manifestFlag:
219-
manifestFile = '{0}.llvm.manifest'.format(pArgs.inputFile)
220-
with open(manifestFile, 'w') as output:
221-
for f in fileNames:
222-
output.write('{0}\n'.format(f))
247+
writeManifest('{0}.llvm.manifest'.format(pArgs.inputFile), fileNames)
223248

224249
if pArgs.outputFile is None:
225250
pArgs.outputFile = pArgs.inputFile + '.' + moduleExtension
@@ -289,10 +314,7 @@ def handleArchive(pArgs):
289314

290315
#write the manifest file if asked for
291316
if pArgs.manifestFlag:
292-
manifestFile = '{0}.llvm.manifest'.format(pArgs.inputFile)
293-
with open(manifestFile, 'w') as output:
294-
for f in bitCodeFiles:
295-
output.write('{0}\n'.format(f))
317+
writeManifest('{0}.llvm.manifest'.format(pArgs.inputFile), bitCodeFiles)
296318

297319
# Build bitcode archive
298320
os.chdir(originalDir)
@@ -326,6 +348,16 @@ def buildArchive(pArgs, bitCodeFiles):
326348
return archiveFiles(pArgs, bitCodeFiles)
327349

328350

351+
def writeManifest(manifestFile, bitCodeFiles):
352+
with open(manifestFile, 'w') as output:
353+
for f in bitCodeFiles:
354+
output.write('{0}\n'.format(f))
355+
sf = getStorePath(f)
356+
if sf:
357+
output.write('{0}\n'.format(sf))
358+
359+
360+
329361
class ExtractedArgs(object):
330362

331363
def __init__(self):

0 commit comments

Comments
 (0)