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