1# Copyright (c) 2016, 2017 Arm Limited. 2# 3# SPDX-License-Identifier: MIT 4# 5# Permission is hereby granted, free of charge, to any person obtaining a copy 6# of this software and associated documentation files (the "Software"), to 7# deal in the Software without restriction, including without limitation the 8# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9# sell copies of the Software, and to permit persons to whom the Software is 10# furnished to do so, subject to the following conditions: 11# 12# The above copyright notice and this permission notice shall be included in all 13# copies or substantial portions of the Software. 14# 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21# SOFTWARE. 22import collections 23import os.path 24import re 25import subprocess 26 27VERSION = "v20.11" 28LIBRARY_VERSION_MAJOR = 21 29LIBRARY_VERSION_MINOR = 0 30LIBRARY_VERSION_PATCH = 0 31SONAME_VERSION = str(LIBRARY_VERSION_MAJOR) + "." + str(LIBRARY_VERSION_MINOR) + "." + str(LIBRARY_VERSION_PATCH) 32 33Import('env') 34Import('vars') 35Import('install_lib') 36 37def build_bootcode_objs(sources): 38 39 arm_compute_env.Append(ASFLAGS = "-I bootcode/") 40 obj = arm_compute_env.Object(sources) 41 obj = install_lib(obj) 42 Default(obj) 43 return obj 44 45def build_library(name, sources, static=False, libs=[]): 46 if static: 47 obj = arm_compute_env.StaticLibrary(name, source=sources, LIBS = arm_compute_env["LIBS"] + libs) 48 else: 49 if env['set_soname']: 50 obj = arm_compute_env.SharedLibrary(name, source=sources, SHLIBVERSION = SONAME_VERSION, LIBS = arm_compute_env["LIBS"] + libs) 51 else: 52 obj = arm_compute_env.SharedLibrary(name, source=sources, LIBS = arm_compute_env["LIBS"] + libs) 53 54 obj = install_lib(obj) 55 Default(obj) 56 return obj 57 58def resolve_includes(target, source, env): 59 # File collection 60 FileEntry = collections.namedtuple('FileEntry', 'target_name file_contents') 61 62 # Include pattern 63 pattern = re.compile("#include \"(.*)\"") 64 65 # Get file contents 66 files = [] 67 for i in range(len(source)): 68 src = source[i] 69 dst = target[i] 70 contents = src.get_contents().decode('utf-8').splitlines() 71 entry = FileEntry(target_name=dst, file_contents=contents) 72 files.append((os.path.basename(src.get_path()),entry)) 73 74 # Create dictionary of tupled list 75 files_dict = dict(files) 76 77 # Check for includes (can only be files in the same folder) 78 final_files = [] 79 for file in files: 80 done = False 81 tmp_file = file[1].file_contents 82 while not done: 83 file_count = 0 84 updated_file = [] 85 for line in tmp_file: 86 found = pattern.search(line) 87 if found: 88 include_file = found.group(1) 89 data = files_dict[include_file].file_contents 90 updated_file.extend(data) 91 else: 92 updated_file.append(line) 93 file_count += 1 94 95 # Check if all include are replaced. 96 if file_count == len(tmp_file): 97 done = True 98 99 # Update temp file 100 tmp_file = updated_file 101 102 # Append and prepend string literal identifiers and add expanded file to final list 103 tmp_file.insert(0, "R\"(\n") 104 tmp_file.append("\n)\"") 105 entry = FileEntry(target_name=file[1].target_name, file_contents=tmp_file) 106 final_files.append((file[0], entry)) 107 108 # Write output files 109 for file in final_files: 110 with open(file[1].target_name.get_path(), 'w+') as out_file: 111 out_file.write( "\n".join( file[1].file_contents )) 112 113def create_version_file(target, source, env): 114# Generate string with build options library version to embed in the library: 115 try: 116 git_hash = subprocess.check_output(["git", "rev-parse", "HEAD"]) 117 except (OSError, subprocess.CalledProcessError): 118 git_hash="unknown" 119 120 build_info = "\"arm_compute_version=%s Build options: %s Git hash=%s\"" % (VERSION, vars.args, git_hash.strip()) 121 with open(target[0].get_path(), "w") as fd: 122 fd.write(build_info) 123 124arm_compute_env = env.Clone() 125version_file = arm_compute_env.Command("src/core/arm_compute_version.embed", "", action=create_version_file) 126arm_compute_env.AlwaysBuild(version_file) 127 128# Generate embed files 129generate_embed = [ version_file ] 130if env['opencl'] and env['embed_kernels']: 131 cl_files = Glob('src/core/CL/cl_kernels/*.cl') 132 cl_files += Glob('src/core/CL/cl_kernels/*.h') 133 134 embed_files = [ f.get_path()+"embed" for f in cl_files ] 135 arm_compute_env.Append(CPPPATH =[Dir("./src/core/CL/").path] ) 136 137 generate_embed.append(arm_compute_env.Command(embed_files, cl_files, action=resolve_includes)) 138 139if env['gles_compute'] and env['embed_kernels']: 140 cs_files = Glob('src/core/GLES_COMPUTE/cs_shaders/*.cs') 141 cs_files += Glob('src/core/GLES_COMPUTE/cs_shaders/*.h') 142 143 embed_files = [ f.get_path()+"embed" for f in cs_files ] 144 arm_compute_env.Append(CPPPATH =[Dir("./src/core/GLES_COMPUTE/").path] ) 145 146 generate_embed.append(arm_compute_env.Command(embed_files, cs_files, action=resolve_includes)) 147 148Default(generate_embed) 149if env["build"] == "embed_only": 150 Return() 151 152# Append version defines for semantic versioning 153arm_compute_env.Append(CPPDEFINES = [('ARM_COMPUTE_VERSION_MAJOR', LIBRARY_VERSION_MAJOR), 154 ('ARM_COMPUTE_VERSION_MINOR', LIBRARY_VERSION_MINOR), 155 ('ARM_COMPUTE_VERSION_PATCH', LIBRARY_VERSION_PATCH)]) 156 157 158# Don't allow undefined references in the libraries: 159arm_compute_env.Append(LINKFLAGS=['-Wl,--no-undefined']) 160arm_compute_env.Append(CPPPATH =[Dir("./src/core/").path] ) 161 162arm_compute_env.Append(LIBS = ['dl']) 163 164core_files = Glob('src/core/*.cpp') 165core_files += Glob('src/core/CPP/*.cpp') 166core_files += Glob('src/core/CPP/kernels/*.cpp') 167core_files += Glob('src/core/helpers/*.cpp') 168core_files += Glob('src/core/utils/*.cpp') 169core_files += Glob('src/core/utils/helpers/*.cpp') 170core_files += Glob('src/core/utils/io/*.cpp') 171core_files += Glob('src/core/utils/quantization/*.cpp') 172core_files += Glob('src/core/utils/misc/*.cpp') 173if env["logging"]: 174 core_files += Glob('src/core/utils/logging/*.cpp') 175 176runtime_files = Glob('src/runtime/*.cpp') 177runtime_files += Glob('src/runtime/CPP/ICPPSimpleFunction.cpp') 178runtime_files += Glob('src/runtime/CPP/functions/*.cpp') 179 180# CLHarrisCorners uses the Scheduler to run CPP kernels 181runtime_files += Glob('src/runtime/CPP/SingleThreadScheduler.cpp') 182 183graph_files = Glob('src/graph/*.cpp') 184graph_files += Glob('src/graph/*/*.cpp') 185 186if env['cppthreads']: 187 runtime_files += Glob('src/runtime/CPP/CPPScheduler.cpp') 188 189if env['openmp']: 190 runtime_files += Glob('src/runtime/OMP/OMPScheduler.cpp') 191 192if env['opencl']: 193 core_files += Glob('src/core/CL/*.cpp') 194 core_files += Glob('src/core/CL/kernels/*.cpp') 195 core_files += Glob('src/core/CL/gemm/*.cpp') 196 core_files += Glob('src/core/CL/gemm/native/*.cpp') 197 core_files += Glob('src/core/CL/gemm/reshaped/*.cpp') 198 core_files += Glob('src/core/CL/gemm/reshaped_only_rhs/*.cpp') 199 200 runtime_files += Glob('src/runtime/CL/*.cpp') 201 runtime_files += Glob('src/runtime/CL/functions/*.cpp') 202 runtime_files += Glob('src/runtime/CL/gemm/*.cpp') 203 runtime_files += Glob('src/runtime/CL/tuners/*.cpp') 204 205 graph_files += Glob('src/graph/backends/CL/*.cpp') 206 207 208if env['neon']: 209 core_files += Glob('src/core/NEON/*.cpp') 210 core_files += Glob('src/core/NEON/kernels/*.cpp') 211 core_files += Glob('src/core/NEON/kernels/assembly/*.cpp') 212 213 core_files += Glob('src/core/NEON/kernels/arm_gemm/*.cpp') 214 215 # build winograd/depthwise sources for either v7a / v8a 216 core_files += Glob('src/core/NEON/kernels/convolution/*/*.cpp') 217 core_files += Glob('src/core/NEON/kernels/convolution/winograd/*/*.cpp') 218 arm_compute_env.Append(CPPPATH = ["src/core/NEON/kernels/convolution/common/", 219 "src/core/NEON/kernels/convolution/winograd/", 220 "src/core/NEON/kernels/convolution/depthwise/", 221 "src/core/NEON/kernels/assembly/", 222 "arm_compute/core/NEON/kernels/assembly/"]) 223 224 graph_files += Glob('src/graph/backends/NEON/*.cpp') 225 226 if env['estate'] == '32': 227 core_files += Glob('src/core/NEON/kernels/arm_gemm/kernels/a32_*/*.cpp') 228 229 if env['estate'] == '64': 230 core_files += Glob('src/core/NEON/kernels/arm_gemm/kernels/a64_*/*.cpp') 231 if "sve" in env['arch']: 232 core_files += Glob('src/core/NEON/kernels/arm_gemm/kernels/sve_*/*.cpp') 233 234 if any(i in env['data_type_support'] for i in ['all', 'fp16']): 235 core_files += Glob('src/core/NEON/kernels/*/impl/fp16_*.cpp') 236 if any(i in env['data_type_support'] for i in ['all', 'fp32']): 237 core_files += Glob('src/core/NEON/kernels/*/impl/fp32_*.cpp') 238 if any(i in env['data_type_support'] for i in ['all', 'qasymm8']): 239 core_files += Glob('src/core/NEON/kernels/*/impl/qasymm8_neon*.cpp') 240 if any(i in env['data_type_support'] for i in ['all', 'qasymm8_signed']): 241 core_files += Glob('src/core/NEON/kernels/*/impl/qasymm8_signed_*.cpp') 242 if any(i in env['data_type_support'] for i in ['all', 'qsymm16']): 243 core_files += Glob('src/core/NEON/kernels/*/impl/qsymm16_*.cpp') 244 245 runtime_files += Glob('src/runtime/NEON/*.cpp') 246 runtime_files += Glob('src/runtime/NEON/functions/*.cpp') 247 runtime_files += Glob('src/runtime/NEON/functions/assembly/*.cpp') 248 249if env['gles_compute']: 250 if env['os'] != 'android': 251 arm_compute_env.Append(CPPPATH = ["#opengles-3.1/include", "#opengles-3.1/mali_include"]) 252 253 core_files += Glob('src/core/GLES_COMPUTE/*.cpp') 254 core_files += Glob('src/core/GLES_COMPUTE/kernels/*.cpp') 255 256 runtime_files += Glob('src/runtime/GLES_COMPUTE/*.cpp') 257 runtime_files += Glob('src/runtime/GLES_COMPUTE/functions/*.cpp') 258 259 graph_files += Glob('src/graph/backends/GLES/*.cpp') 260if env['tracing']: 261 arm_compute_env.Append(CPPDEFINES = ['ARM_COMPUTE_TRACING_ENABLED']) 262else: 263 # Remove TracePoint files if tracing is disabled: 264 core_files = [ f for f in core_files if not "TracePoint" in str(f)] 265 runtime_files = [ f for f in runtime_files if not "TracePoint" in str(f)] 266 267bootcode_o = [] 268if env['os'] == 'bare_metal': 269 bootcode_files = Glob('bootcode/*.s') 270 bootcode_o = build_bootcode_objs(bootcode_files) 271Export('bootcode_o') 272 273arm_compute_core_a = build_library('arm_compute_core-static', core_files, static=True) 274Export('arm_compute_core_a') 275 276if env['os'] != 'bare_metal' and not env['standalone']: 277 arm_compute_core_so = build_library('arm_compute_core', core_files, static=False) 278 Export('arm_compute_core_so') 279 280arm_compute_a = build_library('arm_compute-static', runtime_files, static=True, libs = [ arm_compute_core_a ]) 281Export('arm_compute_a') 282 283if env['os'] != 'bare_metal' and not env['standalone']: 284 arm_compute_so = build_library('arm_compute', runtime_files, static=False, libs = [ "arm_compute_core" ]) 285 Depends(arm_compute_so, arm_compute_core_so) 286 Export('arm_compute_so') 287 288arm_compute_graph_a = build_library('arm_compute_graph-static', graph_files, static=True, libs = [ arm_compute_a]) 289Export('arm_compute_graph_a') 290 291if env['os'] != 'bare_metal' and not env['standalone']: 292 arm_compute_graph_so = build_library('arm_compute_graph', graph_files, static=False, libs = [ "arm_compute" , "arm_compute_core"]) 293 Depends(arm_compute_graph_so, arm_compute_so) 294 Export('arm_compute_graph_so') 295 296if env['standalone']: 297 alias = arm_compute_env.Alias("arm_compute", [arm_compute_a]) 298else: 299 alias = arm_compute_env.Alias("arm_compute", [arm_compute_a, arm_compute_so]) 300 301Default(alias) 302 303if env['standalone']: 304 Depends([alias,arm_compute_core_a], generate_embed) 305else: 306 Depends([alias,arm_compute_core_so, arm_compute_core_a], generate_embed) 307