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