summaryrefslogtreecommitdiff
path: root/third_party/waf/waflib/extras/file_to_object.py
blob: a295998e9e6db9e0184fd4d1a96e244bdfbe8bfb (plain)
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
#! /usr/bin/env python
# encoding: utf-8
# WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file

#!/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
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)

		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" % ord(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"]