syms.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #! /usr/bin/env python
  2. # encoding: utf-8
  3. """
  4. This tool supports the export_symbols_regex to export the symbols in a shared library.
  5. by default, all symbols are exported by gcc, and nothing by msvc.
  6. to use the tool, do something like:
  7. def build(ctx):
  8. ctx(features='c cshlib syms', source='a.c b.c', export_symbols_regex='mylib_.*', target='testlib')
  9. only the symbols starting with 'mylib_' will be exported.
  10. """
  11. import re
  12. from waflib.Context import STDOUT
  13. from waflib.Task import Task
  14. from waflib.Errors import WafError
  15. from waflib.TaskGen import feature, after_method
  16. class gen_sym(Task):
  17. def run(self):
  18. obj = self.inputs[0]
  19. kw = {}
  20. reg = getattr(self.generator, 'export_symbols_regex', '.+?')
  21. if 'msvc' in (self.env.CC_NAME, self.env.CXX_NAME):
  22. re_nm = re.compile(r'External\s+\|\s+_(?P<symbol>%s)\b' % reg)
  23. cmd = (self.env.DUMPBIN or ['dumpbin']) + ['/symbols', obj.abspath()]
  24. else:
  25. if self.env.DEST_BINFMT == 'pe': #gcc uses nm, and has a preceding _ on windows
  26. re_nm = re.compile(r'(T|D)\s+_(?P<symbol>%s)\b' % reg)
  27. elif self.env.DEST_BINFMT=='mac-o':
  28. re_nm=re.compile(r'(T|D)\s+(?P<symbol>_?%s)\b' % reg)
  29. else:
  30. re_nm = re.compile(r'(T|D)\s+(?P<symbol>%s)\b' % reg)
  31. cmd = (self.env.NM or ['nm']) + ['-g', obj.abspath()]
  32. syms = [m.group('symbol') for m in re_nm.finditer(self.generator.bld.cmd_and_log(cmd, quiet=STDOUT, **kw))]
  33. self.outputs[0].write('%r' % syms)
  34. class compile_sym(Task):
  35. def run(self):
  36. syms = {}
  37. for x in self.inputs:
  38. slist = eval(x.read())
  39. for s in slist:
  40. syms[s] = 1
  41. lsyms = list(syms.keys())
  42. lsyms.sort()
  43. if self.env.DEST_BINFMT == 'pe':
  44. self.outputs[0].write('EXPORTS\n' + '\n'.join(lsyms))
  45. elif self.env.DEST_BINFMT == 'elf':
  46. self.outputs[0].write('{ global:\n' + ';\n'.join(lsyms) + ";\nlocal: *; };\n")
  47. elif self.env.DEST_BINFMT=='mac-o':
  48. self.outputs[0].write('\n'.join(lsyms) + '\n')
  49. else:
  50. raise WafError('NotImplemented')
  51. @feature('syms')
  52. @after_method('process_source', 'process_use', 'apply_link', 'process_uselib_local', 'propagate_uselib_vars')
  53. def do_the_symbol_stuff(self):
  54. def_node = self.path.find_or_declare(getattr(self, 'sym_file', self.target + '.def'))
  55. compiled_tasks = getattr(self, 'compiled_tasks', None)
  56. if compiled_tasks:
  57. ins = [x.outputs[0] for x in compiled_tasks]
  58. self.gen_sym_tasks = [self.create_task('gen_sym', x, x.change_ext('.%d.sym' % self.idx)) for x in ins]
  59. self.create_task('compile_sym', [x.outputs[0] for x in self.gen_sym_tasks], def_node)
  60. link_task = getattr(self, 'link_task', None)
  61. if link_task:
  62. self.link_task.dep_nodes.append(def_node)
  63. if 'msvc' in (self.env.CC_NAME, self.env.CXX_NAME):
  64. self.link_task.env.append_value('LINKFLAGS', ['/def:' + def_node.bldpath()])
  65. elif self.env.DEST_BINFMT == 'pe':
  66. # gcc on windows takes *.def as an additional input
  67. self.link_task.inputs.append(def_node)
  68. elif self.env.DEST_BINFMT == 'elf':
  69. self.link_task.env.append_value('LINKFLAGS', ['-Wl,-version-script', '-Wl,' + def_node.bldpath()])
  70. elif self.env.DEST_BINFMT=='mac-o':
  71. self.link_task.env.append_value('LINKFLAGS',['-Wl,-exported_symbols_list,' + def_node.bldpath()])
  72. else:
  73. raise WafError('NotImplemented')