• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2020 The TensorFlow Authors. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ==============================================================================
15"""Simple script to convert binary file to C++ source code for embedding."""
16
17# This is a version of //tensorflow/lite/python/convert_file_to_c_source.py
18# with minimal dependencies to reduce build times. See b/158254039.
19
20import argparse
21import datetime
22import sys
23
24
25# Cribbed from //tensorflow/lite/python/util.py
26# Changed:
27# - Alignment from 4 to 16 for generality (16 can be required for SIMD)
28# - Added 'extern' to source for building on C++ target platforms
29# - Changed comments to refer to this script, and C++ rather than C
30def _convert_bytes_to_cc_source(data,
31                                array_name,
32                                max_line_width=80,
33                                include_guard=None,
34                                include_path=None,
35                                use_tensorflow_license=False):
36  """Returns strings representing a C++ constant array containing `data`.
37
38  Args:
39    data: Byte array that will be converted into a C++ constant.
40    array_name: String to use as the variable name for the constant array.
41    max_line_width: The longest line length, for formatting purposes.
42    include_guard: Name to use for the include guard macro definition.
43    include_path: Optional path to include in the source file.
44    use_tensorflow_license: Whether to include the standard TensorFlow Apache2
45      license in the generated files.
46
47  Returns:
48    Text that can be compiled as a C++ source file to link in the data as a
49    literal array of values.
50    Text that can be used as a C++ header file to reference the literal array.
51  """
52
53  starting_pad = "   "
54  array_lines = []
55  array_line = starting_pad
56  for value in bytearray(data):
57    if (len(array_line) + 4) > max_line_width:
58      array_lines.append(array_line + "\n")
59      array_line = starting_pad
60    array_line += " 0x%02x," % value
61  if len(array_line) > len(starting_pad):
62    array_lines.append(array_line + "\n")
63  array_values = "".join(array_lines)
64
65  if include_guard is None:
66    include_guard = "TENSORFLOW_LITE_UTIL_" + array_name.upper() + "_DATA_H_"
67
68  if include_path is not None:
69    include_line = "#include \"{include_path}\"\n".format(
70        include_path=include_path)
71  else:
72    include_line = ""
73
74  if use_tensorflow_license:
75    license_text = """
76/* Copyright {year} The TensorFlow Authors. All Rights Reserved.
77
78Licensed under the Apache License, Version 2.0 (the "License");
79you may not use this file except in compliance with the License.
80You may obtain a copy of the License at
81
82    http://www.apache.org/licenses/LICENSE-2.0
83
84Unless required by applicable law or agreed to in writing, software
85distributed under the License is distributed on an "AS IS" BASIS,
86WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
87See the License for the specific language governing permissions and
88limitations under the License.
89==============================================================================*/
90""".format(year=datetime.date.today().year)
91  else:
92    license_text = ""
93
94  source_template = """{license_text}
95// This is a binary file that has been converted into a C++ data array using the
96// //tensorflow/lite/experimental/acceleration/compatibility/convert_binary_to_cc_source.py
97// script. This form is useful for compiling into a binary to simplify
98// deployment on mobile devices
99
100{include_line}
101// We need to keep the data array aligned on some architectures.
102#ifdef __has_attribute
103#define HAVE_ATTRIBUTE(x) __has_attribute(x)
104#else
105#define HAVE_ATTRIBUTE(x) 0
106#endif
107#if HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__))
108#define DATA_ALIGN_ATTRIBUTE __attribute__((aligned(16)))
109#else
110#define DATA_ALIGN_ATTRIBUTE
111#endif
112
113extern const unsigned char {array_name}[] DATA_ALIGN_ATTRIBUTE = {{
114{array_values}}};
115extern const int {array_name}_len = {array_length};
116"""
117
118  source_text = source_template.format(
119      array_name=array_name,
120      array_length=len(data),
121      array_values=array_values,
122      license_text=license_text,
123      include_line=include_line)
124
125  header_template = """
126{license_text}
127
128// This is a binary file that has been converted into a C++ data array using the
129// //tensorflow/lite/experimental/acceleration/compatibility/convert_binary_to_cc_source.py
130// script. This form is useful for compiling into a binary to simplify
131// deployment on mobile devices
132
133#ifndef {include_guard}
134#define {include_guard}
135
136extern const unsigned char {array_name}[];
137extern const int {array_name}_len;
138
139#endif  // {include_guard}
140"""
141
142  header_text = header_template.format(
143      array_name=array_name,
144      include_guard=include_guard,
145      license_text=license_text)
146
147  return source_text, header_text
148
149
150def main():
151  parser = argparse.ArgumentParser(
152      description=("Binary to C++ source converter"))
153  parser.add_argument(
154      "--input_binary_file",
155      type=str,
156      help="Full filepath of input binary.",
157      required=True)
158  parser.add_argument(
159      "--output_header_file",
160      type=str,
161      help="Full filepath of output header.",
162      required=True)
163  parser.add_argument(
164      "--array_variable_name",
165      type=str,
166      help="Full filepath of output source.",
167      required=True)
168  parser.add_argument(
169      "--output_source_file",
170      type=str,
171      help="Name of global variable that will contain the binary data.",
172      required=True)
173  flags, _ = parser.parse_known_args(args=sys.argv[1:])
174  with open(flags.input_binary_file, "rb") as input_handle:
175    input_data = input_handle.read()
176
177  source, header = _convert_bytes_to_cc_source(
178      data=input_data,
179      array_name=flags.array_variable_name,
180      use_tensorflow_license=True)
181
182  with open(flags.output_source_file, "w") as source_handle:
183    source_handle.write(source)
184
185  with open(flags.output_header_file, "w") as header_handle:
186    header_handle.write(header)
187
188
189if __name__ == "__main__":
190  main()
191