link_lib.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import sys
  2. import subprocess
  3. import tempfile
  4. import os
  5. import shutil
  6. class Opts(object):
  7. def __init__(self, args):
  8. self.archiver = args[0]
  9. self.arch_type = args[1]
  10. self.llvm_ar_format = args[2]
  11. self.build_root = args[3]
  12. self.plugin = args[4]
  13. self.output = args[5]
  14. auto_input = args[6:]
  15. self.need_modify = False
  16. self.extra_args = []
  17. if self.arch_type.endswith('_AR'):
  18. if self.arch_type == 'GNU_AR':
  19. self.create_flags = ['rcs']
  20. self.modify_flags = ['-M']
  21. elif self.arch_type == 'LLVM_AR':
  22. self.create_flags = ['rcs', '--format=%s' % self.llvm_ar_format]
  23. self.modify_flags = ['-M']
  24. self.need_modify = any(item.endswith('.a') for item in auto_input)
  25. if self.need_modify:
  26. self.objs = list(filter(lambda x: x.endswith('.o'), auto_input))
  27. self.libs = list(filter(lambda x: x.endswith('.a'), auto_input))
  28. else:
  29. self.objs = auto_input
  30. self.libs = []
  31. self.output_opts = [self.output]
  32. elif self.arch_type == 'LIBTOOL':
  33. self.create_flags = ['-static']
  34. self.objs = auto_input
  35. self.libs = []
  36. self.output_opts = ['-o', self.output]
  37. elif self.arch_type == 'LIB':
  38. self.create_flags = []
  39. self.extra_args = list(filter(lambda x: x.startswith('/'), auto_input))
  40. self.objs = list(filter(lambda x: not x.startswith('/'), auto_input))
  41. self.libs = []
  42. self.output_opts = ['/OUT:' + self.output]
  43. self.plugin_flags = ['--plugin', self.plugin] if self.plugin != 'None' else []
  44. def get_opts(args):
  45. return Opts(args)
  46. def run(*args):
  47. return subprocess.check_output(list(args), shell=False).strip()
  48. def gen_renames_1(d):
  49. for l in d.split('\n'):
  50. l = l.strip()
  51. if ' ' in l:
  52. yield l.split(' ')[-1]
  53. def have_prefix(l, p):
  54. for x in l:
  55. if not x.startswith(p):
  56. return False
  57. return True
  58. def gen_renames_2(p, d):
  59. l = list(gen_renames_1(d))
  60. a = have_prefix(l, '_')
  61. for s in l:
  62. if 'asan_globals' in s:
  63. continue
  64. if s in ['HMAC', 'SHA1', 'SHA256', 'SHA256', 'SHA512', 'RC4', 'MD5', 'SHA384']:
  65. continue
  66. if a and s[1:] in ['HMAC', 'SHA1', 'SHA256', 'SHA256', 'SHA512', 'RC4', 'MD5', 'SHA384']:
  67. continue
  68. if a:
  69. yield s + ' _' + p + s[1:]
  70. else:
  71. yield s + ' ' + p + s
  72. def gen_renames(p, d):
  73. return '\n'.join(gen_renames_2(p, d)).strip() + '\n'
  74. def rename_syms(where, ret):
  75. p = 'v1_'
  76. # find symbols to rename
  77. syms = run(where + 'llvm-nm', '--extern-only', '--defined-only', '-A', ret)
  78. # prepare rename plan
  79. renames = gen_renames(p, syms)
  80. tmp = ret + '.syms'
  81. with open(tmp, 'w') as f:
  82. f.write(renames)
  83. # rename symbols
  84. run(where + 'llvm-objcopy', '--redefine-syms=' + tmp, ret)
  85. os.unlink(tmp)
  86. if __name__ == "__main__":
  87. opts = get_opts(sys.argv[1:])
  88. # There is a bug in llvm-ar. Some files with size slightly greater 2^32
  89. # still have GNU format instead of GNU64 and cause link problems.
  90. # Workaround just lowers llvm-ar's GNU64 threshold to 2^31.
  91. if opts.arch_type == 'LLVM_AR':
  92. os.environ['SYM64_THRESHOLD'] = '31'
  93. def call():
  94. try:
  95. p = subprocess.Popen(cmd, stdin=stdin, cwd=opts.build_root)
  96. rc = p.wait()
  97. return rc
  98. except OSError as e:
  99. raise Exception('while running %s: %s' % (' '.join(cmd), e))
  100. try:
  101. os.unlink(opts.output)
  102. except OSError:
  103. pass
  104. if not opts.need_modify:
  105. cmd = [opts.archiver] + opts.create_flags + opts.plugin_flags + opts.extra_args + opts.output_opts + opts.objs
  106. stdin = None
  107. exit_code = call()
  108. elif len(opts.objs) == 0 and len(opts.libs) == 1:
  109. shutil.copy(opts.libs[0], opts.output)
  110. exit_code = 0
  111. else:
  112. temp = tempfile.NamedTemporaryFile(dir=os.path.dirname(opts.output), delete=False)
  113. with open(temp.name, 'w') as tmp:
  114. tmp.write('CREATE {0}\n'.format(opts.output))
  115. for lib in opts.libs:
  116. tmp.write('ADDLIB {0}\n'.format(lib))
  117. for obj in opts.objs:
  118. tmp.write('ADDMOD {0}\n'.format(obj))
  119. tmp.write('SAVE\n')
  120. tmp.write('END\n')
  121. cmd = [opts.archiver] + opts.modify_flags + opts.plugin_flags
  122. stdin = open(temp.name)
  123. exit_code = call()
  124. os.remove(temp.name)
  125. if exit_code != 0:
  126. raise Exception('{0} returned non-zero exit code {1}. Stop.'.format(' '.join(cmd), exit_code))
  127. if os.path.basename(opts.output) in ['libcontrib-libs-openssl.a', 'liblibs-openssl-crypto.a']:
  128. rename_syms(os.path.dirname(opts.archiver) + '/', opts.output)