file_to_object.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. # Tool to embed file into objects
  4. __author__ = __maintainer__ = "Jérôme Carretero <cJ-waf@zougloub.eu>"
  5. __copyright__ = "Jérôme Carretero, 2014"
  6. """
  7. This tool allows to embed file contents in object files (.o).
  8. It is not exactly portable, and the file contents are reachable
  9. using various non-portable fashions.
  10. The goal here is to provide a functional interface to the embedding
  11. of file data in objects.
  12. See the ``playground/embedded_resources`` example for an example.
  13. Usage::
  14. bld(
  15. name='pipeline',
  16. # ^ Reference this in use="..." for things using the generated code
  17. features='file_to_object',
  18. source='some.file',
  19. # ^ Name of the file to embed in binary section.
  20. )
  21. Known issues:
  22. - Destination is named like source, with extension renamed to .o
  23. eg. some.file -> some.o
  24. """
  25. import os
  26. from waflib import Task, TaskGen, Errors
  27. def filename_c_escape(x):
  28. return x.replace("\\", "\\\\")
  29. class file_to_object_s(Task.Task):
  30. color = 'CYAN'
  31. vars = ['DEST_CPU', 'DEST_BINFMT']
  32. def run(self):
  33. name = []
  34. for i, x in enumerate(self.inputs[0].name):
  35. if x.isalnum():
  36. name.append(x)
  37. else:
  38. name.append('_')
  39. file = self.inputs[0].abspath()
  40. size = os.path.getsize(file)
  41. if self.env.DEST_CPU in ('x86_64', 'ia', 'aarch64'):
  42. unit = 'quad'
  43. align = 8
  44. elif self.env.DEST_CPU in ('x86','arm', 'thumb', 'm68k'):
  45. unit = 'long'
  46. align = 4
  47. else:
  48. raise Errors.WafError("Unsupported DEST_CPU, please report bug!")
  49. file = filename_c_escape(file)
  50. name = "_binary_" + "".join(name)
  51. rodata = ".section .rodata"
  52. if self.env.DEST_BINFMT == "mac-o":
  53. name = "_" + name
  54. rodata = ".section __TEXT,__const"
  55. with open(self.outputs[0].abspath(), 'w') as f:
  56. f.write(\
  57. """
  58. .global %(name)s_start
  59. .global %(name)s_end
  60. .global %(name)s_size
  61. %(rodata)s
  62. %(name)s_start:
  63. .incbin "%(file)s"
  64. %(name)s_end:
  65. .align %(align)d
  66. %(name)s_size:
  67. .%(unit)s 0x%(size)x
  68. """ % locals())
  69. class file_to_object_c(Task.Task):
  70. color = 'CYAN'
  71. def run(self):
  72. name = []
  73. for i, x in enumerate(self.inputs[0].name):
  74. if x.isalnum():
  75. name.append(x)
  76. else:
  77. name.append('_')
  78. file = self.inputs[0].abspath()
  79. size = os.path.getsize(file)
  80. name = "_binary_" + "".join(name)
  81. data = self.inputs[0].read('rb')
  82. lines, line = [], []
  83. for idx_byte, byte in enumerate(data):
  84. line.append(byte)
  85. if len(line) > 15 or idx_byte == size-1:
  86. lines.append(", ".join(("0x%02x" % ord(x)) for x in line))
  87. line = []
  88. data = ",\n ".join(lines)
  89. self.outputs[0].write(\
  90. """
  91. unsigned long %(name)s_size = %(size)dL;
  92. char const %(name)s_start[] = {
  93. %(data)s
  94. };
  95. char const %(name)s_end[] = {};
  96. """ % locals())
  97. @TaskGen.feature('file_to_object')
  98. @TaskGen.before_method('process_source')
  99. def tg_file_to_object(self):
  100. bld = self.bld
  101. sources = self.to_nodes(self.source)
  102. targets = []
  103. for src in sources:
  104. if bld.env.F2O_METHOD == ["asm"]:
  105. tgt = src.parent.find_or_declare(src.name + '.f2o.s')
  106. tsk = self.create_task('file_to_object_s', src, tgt)
  107. tsk.cwd = src.parent.abspath() # verify
  108. else:
  109. tgt = src.parent.find_or_declare(src.name + '.f2o.c')
  110. tsk = self.create_task('file_to_object_c', src, tgt)
  111. tsk.cwd = src.parent.abspath() # verify
  112. targets.append(tgt)
  113. self.source = targets
  114. def configure(conf):
  115. conf.load('gas')
  116. conf.env.F2O_METHOD = ["c"]