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