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