link_lib.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. from __future__ import print_function
  2. import sys
  3. import subprocess
  4. import tempfile
  5. import os
  6. import shutil
  7. import argparse
  8. class Opts(object):
  9. def __init__(self, args):
  10. kvs = args.index('--')
  11. kve = args.index('--', kvs + 1)
  12. kv = args[kvs + 1:kve]
  13. args = args[:kvs] + args[kve + 1:]
  14. parser = argparse.ArgumentParser()
  15. parser.add_argument('--plugin')
  16. kvargs = parser.parse_args(kv)
  17. self.ar_plugin = kvargs.plugin
  18. self.archiver = args[0]
  19. self.arch_type = args[1]
  20. self.llvm_ar_format = args[2]
  21. self.build_root = args[3]
  22. self.plugin = args[4]
  23. self.output = args[5]
  24. auto_input = args[6:]
  25. self.need_modify = False
  26. self.extra_args = []
  27. if self.arch_type.endswith('_AR'):
  28. if self.arch_type == 'GNU_AR':
  29. self.create_flags = ['rcs']
  30. self.modify_flags = ['-M']
  31. elif self.arch_type == 'LLVM_AR':
  32. self.create_flags = ['rcs', '--format=%s' % self.llvm_ar_format]
  33. self.modify_flags = ['-M']
  34. self.need_modify = any(item.endswith('.a') for item in auto_input)
  35. if self.need_modify:
  36. self.objs = list(filter(lambda x: x.endswith('.o'), auto_input))
  37. self.libs = list(filter(lambda x: x.endswith('.a'), auto_input))
  38. else:
  39. self.objs = auto_input
  40. self.libs = []
  41. self.output_opts = [self.output]
  42. elif self.arch_type == 'LIBTOOL':
  43. self.create_flags = ['-static']
  44. self.objs = auto_input
  45. self.libs = []
  46. self.output_opts = ['-o', self.output]
  47. elif self.arch_type == 'LIB':
  48. self.create_flags = []
  49. self.extra_args = list(filter(lambda x: x.startswith('/'), auto_input))
  50. self.objs = list(filter(lambda x: not x.startswith('/'), auto_input))
  51. self.libs = []
  52. self.output_opts = ['/OUT:' + self.output]
  53. self.plugin_flags = ['--plugin', self.plugin] if self.plugin != 'None' else []
  54. def get_opts(args):
  55. return Opts(args)
  56. if __name__ == "__main__":
  57. opts = get_opts(sys.argv[1:])
  58. # There is a bug in llvm-ar. Some files with size slightly greater 2^32
  59. # still have GNU format instead of GNU64 and cause link problems.
  60. # Workaround just lowers llvm-ar's GNU64 threshold to 2^31.
  61. if opts.arch_type == 'LLVM_AR':
  62. os.environ['SYM64_THRESHOLD'] = '31'
  63. def call():
  64. try:
  65. p = subprocess.Popen(cmd, stdin=stdin, cwd=opts.build_root)
  66. rc = p.wait()
  67. return rc
  68. except OSError as e:
  69. raise Exception('while running %s: %s' % (' '.join(cmd), e))
  70. try:
  71. os.unlink(opts.output)
  72. except OSError:
  73. pass
  74. if not opts.need_modify:
  75. cmd = [opts.archiver] + opts.create_flags + opts.plugin_flags + opts.extra_args + opts.output_opts + opts.objs
  76. stdin = None
  77. exit_code = call()
  78. elif len(opts.objs) == 0 and len(opts.libs) == 1:
  79. shutil.copy(opts.libs[0], opts.output)
  80. exit_code = 0
  81. else:
  82. temp = tempfile.NamedTemporaryFile(dir=os.path.dirname(opts.output), delete=False)
  83. with open(temp.name, 'w') as tmp:
  84. tmp.write('CREATE {0}\n'.format(opts.output))
  85. for lib in opts.libs:
  86. tmp.write('ADDLIB {0}\n'.format(lib))
  87. for obj in opts.objs:
  88. tmp.write('ADDMOD {0}\n'.format(obj))
  89. tmp.write('SAVE\n')
  90. tmp.write('END\n')
  91. cmd = [opts.archiver] + opts.modify_flags + opts.plugin_flags
  92. stdin = open(temp.name)
  93. exit_code = call()
  94. os.remove(temp.name)
  95. if exit_code != 0:
  96. raise Exception('{0} returned non-zero exit code {1}. Stop.'.format(' '.join(cmd), exit_code))
  97. if opts.ar_plugin:
  98. subprocess.check_call([sys.executable, opts.ar_plugin, opts.output, '--'] + sys.argv[1:])