1# Copyright (c) Meta Platforms, Inc. and affiliates. 2# All rights reserved. 3# 4# This source code is licensed under the BSD-style license found in the 5# LICENSE file in the root directory of this source tree. 6 7# 8# This file is intended to have helper functions to keep the CMakeLists.txt 9# concise. If there are any helper function can be re-used, it's recommented to 10# add them here. 11# 12# ### Editing this file ### 13# 14# This file should be formatted with 15# ~~~ 16# cmake-format -i Utils.cmake 17# ~~~ 18# It should also be cmake-lint clean. 19# 20 21# Public function to print summary for all configurations. For new variables, 22# it's recommended to add them here. 23function(executorch_print_configuration_summary) 24 message(STATUS "") 25 message(STATUS "******** Summary ********") 26 message(STATUS " CMAKE_BUILD_TYPE : ${CMAKE_BUILD_TYPE}") 27 message(STATUS " CMAKE_CXX_STANDARD : ${CMAKE_CXX_STANDARD}") 28 message(STATUS " CMAKE_CXX_COMPILER_ID : ${CMAKE_CXX_COMPILER_ID}") 29 message(STATUS " CMAKE_TOOLCHAIN_FILE : ${CMAKE_TOOLCHAIN_FILE}") 30 message(STATUS " BUCK2 : ${BUCK2}") 31 message(STATUS " PYTHON_EXECUTABLE : ${PYTHON_EXECUTABLE}") 32 message(STATUS " FLATC_EXECUTABLE : ${FLATC_EXECUTABLE}") 33 message( 34 STATUS 35 " EXECUTORCH_ENABLE_LOGGING : ${EXECUTORCH_ENABLE_LOGGING}" 36 ) 37 message(STATUS " EXECUTORCH_ENABLE_PROGRAM_VERIFICATION : " 38 "${EXECUTORCH_ENABLE_PROGRAM_VERIFICATION}" 39 ) 40 message( 41 STATUS " EXECUTORCH_LOG_LEVEL : ${EXECUTORCH_LOG_LEVEL}" 42 ) 43 message(STATUS " EXECUTORCH_BUILD_ANDROID_JNI : " 44 "${EXECUTORCH_BUILD_ANDROID_JNI}" 45 ) 46 message(STATUS " EXECUTORCH_BUILD_ARM_BAREMETAL : " 47 "${EXECUTORCH_BUILD_ARM_BAREMETAL}" 48 ) 49 message( 50 STATUS 51 " EXECUTORCH_BUILD_COREML : ${EXECUTORCH_BUILD_COREML}" 52 ) 53 message(STATUS " EXECUTORCH_BUILD_KERNELS_CUSTOM : " 54 "${EXECUTORCH_BUILD_KERNELS_CUSTOM}" 55 ) 56 message(STATUS " EXECUTORCH_BUILD_EXECUTOR_RUNNER : " 57 "${EXECUTORCH_BUILD_EXECUTOR_RUNNER}" 58 ) 59 message(STATUS " EXECUTORCH_BUILD_EXTENSION_DATA_LOADER : " 60 "${EXECUTORCH_BUILD_EXTENSION_DATA_LOADER}" 61 ) 62 message(STATUS " EXECUTORCH_BUILD_EXTENSION_MODULE : " 63 "${EXECUTORCH_BUILD_EXTENSION_MODULE}" 64 ) 65 message(STATUS " EXECUTORCH_BUILD_EXTENSION_RUNNER_UTIL : " 66 "${EXECUTORCH_BUILD_EXTENSION_RUNNER_UTIL}" 67 ) 68 message(STATUS " EXECUTORCH_BUILD_EXTENSION_TENSOR : " 69 "${EXECUTORCH_BUILD_EXTENSION_TENSOR}" 70 ) 71 message(STATUS " EXECUTORCH_BUILD_EXTENSION_TRAINING : " 72 "${EXECUTORCH_BUILD_EXTENSION_TRAINING}" 73 ) 74 message( 75 STATUS 76 " EXECUTORCH_BUILD_FLATC : ${EXECUTORCH_BUILD_FLATC}" 77 ) 78 message( 79 STATUS 80 " EXECUTORCH_BUILD_GFLAGS : ${EXECUTORCH_BUILD_GFLAGS}" 81 ) 82 message( 83 STATUS 84 " EXECUTORCH_BUILD_GTESTS : ${EXECUTORCH_BUILD_GTESTS}" 85 ) 86 message(STATUS " EXECUTORCH_BUILD_HOST_TARGETS : " 87 "${EXECUTORCH_BUILD_HOST_TARGETS}" 88 ) 89 message( 90 STATUS " EXECUTORCH_BUILD_MPS : ${EXECUTORCH_BUILD_MPS}" 91 ) 92 message( 93 STATUS 94 " EXECUTORCH_BUILD_PYBIND : ${EXECUTORCH_BUILD_PYBIND}" 95 ) 96 message( 97 STATUS " EXECUTORCH_BUILD_QNN : ${EXECUTORCH_BUILD_QNN}" 98 ) 99 message(STATUS " EXECUTORCH_BUILD_KERNELS_OPTIMIZED : " 100 "${EXECUTORCH_BUILD_KERNELS_OPTIMIZED}" 101 ) 102 message(STATUS " EXECUTORCH_BUILD_KERNELS_QUANTIZED : " 103 "${EXECUTORCH_BUILD_KERNELS_QUANTIZED}" 104 ) 105 message( 106 STATUS " EXECUTORCH_BUILD_DEVTOOLS : ${EXECUTORCH_BUILD_DEVTOOLS}" 107 ) 108 message( 109 STATUS 110 " EXECUTORCH_BUILD_SIZE_TEST : ${EXECUTORCH_BUILD_SIZE_TEST}" 111 ) 112 message( 113 STATUS 114 " EXECUTORCH_BUILD_XNNPACK : ${EXECUTORCH_BUILD_XNNPACK}" 115 ) 116 message( 117 STATUS 118 " EXECUTORCH_BUILD_VULKAN : ${EXECUTORCH_BUILD_VULKAN}" 119 ) 120 message( 121 STATUS 122 " EXECUTORCH_BUILD_PTHREADPOOL : ${EXECUTORCH_BUILD_PTHREADPOOL}" 123 ) 124 message( 125 STATUS 126 " EXECUTORCH_BUILD_CPUINFO : ${EXECUTORCH_BUILD_CPUINFO}" 127 ) 128 129endfunction() 130 131# This is the funtion to use -Wl, --whole-archive to link static library NB: 132# target_link_options is broken for this case, it only append the interface link 133# options of the first library. 134function(kernel_link_options target_name) 135 # target_link_options(${target_name} INTERFACE 136 # "$<LINK_LIBRARY:WHOLE_ARCHIVE,target_name>") 137 target_link_options( 138 ${target_name} INTERFACE "SHELL:LINKER:--whole-archive \ 139 $<TARGET_FILE:${target_name}> \ 140 LINKER:--no-whole-archive" 141 ) 142endfunction() 143 144# Same as kernel_link_options but it's for MacOS linker 145function(macos_kernel_link_options target_name) 146 target_link_options( 147 ${target_name} INTERFACE 148 "SHELL:LINKER:-force_load,$<TARGET_FILE:${target_name}>" 149 ) 150endfunction() 151 152# Same as kernel_link_options but it's for MSVC linker 153function(msvc_kernel_link_options target_name) 154 target_link_options( 155 ${target_name} INTERFACE 156 "SHELL:LINKER:/WHOLEARCHIVE:$<TARGET_FILE:${target_name}>" 157 ) 158endfunction() 159 160# Ensure that the load-time constructor functions run. By default, the linker 161# would remove them since there are no other references to them. 162function(target_link_options_shared_lib target_name) 163 if(APPLE) 164 macos_kernel_link_options(${target_name}) 165 elseif(MSVC) 166 msvc_kernel_link_options(${target_name}) 167 else() 168 kernel_link_options(${target_name}) 169 endif() 170endfunction() 171 172# Extract source files based on toml config. This is useful to keep buck2 and 173# cmake aligned. Do not regenerate if file exists. 174function(extract_sources sources_file) 175 if(EXISTS "${sources_file}") 176 message(STATUS "executorch: Using source file list ${sources_file}") 177 else() 178 # A file wasn't generated. Run a script to extract the source lists from the 179 # buck2 build system and write them to a file we can include. 180 # 181 # NOTE: This will only happen once during cmake setup, so it will not re-run 182 # if the buck2 targets change. 183 message(STATUS "executorch: Generating source file list ${sources_file}") 184 if(EXECUTORCH_ROOT) 185 set(executorch_root ${EXECUTORCH_ROOT}) 186 else() 187 set(executorch_root ${CMAKE_CURRENT_SOURCE_DIR}) 188 endif() 189 190 if(ANDROID_ABI) 191 if("${ANDROID_ABI}" STREQUAL "arm64-v8a") 192 set(target_platforms_arg "--target-platforms=shim//:android-arm64") 193 elseif("${ANDROID_ABI}" STREQUAL "x86_64") 194 set(target_platforms_arg "--target-platforms=shim//:android-x86_64") 195 else() 196 message(FATAL_ERROR "Unsupported ANDROID_ABI setting ${ANDROID_ABI}. Please add it here!") 197 endif() 198 endif() 199 execute_process( 200 COMMAND 201 ${PYTHON_EXECUTABLE} ${executorch_root}/build/extract_sources.py 202 --config=${executorch_root}/build/cmake_deps.toml --out=${sources_file} 203 --buck2=${BUCK2} ${target_platforms_arg} 204 OUTPUT_VARIABLE gen_srcs_output 205 ERROR_VARIABLE gen_srcs_error 206 RESULT_VARIABLE gen_srcs_exit_code 207 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 208 ) 209 210 if(NOT gen_srcs_exit_code EQUAL 0) 211 message("Error while generating ${sources_file}. " 212 "Exit code: ${gen_srcs_exit_code}" 213 ) 214 message("Output:\n${gen_srcs_output}") 215 message("Error:\n${gen_srcs_error}") 216 message(FATAL_ERROR "executorch: source list generation failed") 217 endif() 218 endif() 219endfunction() 220 221# Sets the value of the BUCK2 variable by searching for a buck2 binary with the 222# correct version. 223# 224# The resolve_buck.py script uses the following logic to find buck2: 1) If BUCK2 225# argument is set explicitly, use it. Warn if the version is incorrect. 2) Look 226# for a binary named buck2 on the system path. Take it if it is the correct 227# version. 3) Check for a previously downloaded buck2 binary (from step 4). 4) 228# Download and cache correct version of buck2. 229function(resolve_buck2) 230 if(EXECUTORCH_ROOT) 231 set(executorch_root ${EXECUTORCH_ROOT}) 232 else() 233 set(executorch_root ${CMAKE_CURRENT_SOURCE_DIR}) 234 endif() 235 236 set(resolve_buck2_command 237 ${PYTHON_EXECUTABLE} ${executorch_root}/build/resolve_buck.py 238 --cache_dir=${CMAKE_CURRENT_BINARY_DIR}/buck2-bin 239 ) 240 241 if(NOT ${BUCK2} STREQUAL "") 242 list(APPEND resolve_buck2_command --buck2=${BUCK2}) 243 endif() 244 245 execute_process( 246 COMMAND ${resolve_buck2_command} 247 OUTPUT_VARIABLE resolve_buck2_output 248 ERROR_VARIABLE resolve_buck2_error 249 RESULT_VARIABLE resolve_buck2_exit_code 250 WORKING_DIRECTORY ${executorch_root} 251 OUTPUT_STRIP_TRAILING_WHITESPACE 252 ) 253 254 # $BUCK2 is a copy of the var from the parent scope. This block will set 255 # $buck2 to the value we want to return. 256 if(resolve_buck2_exit_code EQUAL 0) 257 set(buck2 ${resolve_buck2_output}) 258 message(STATUS "Resolved buck2 as ${resolve_buck2_output}.") 259 elseif(resolve_buck2_exit_code EQUAL 2) 260 # Wrong buck version used. Stop here to ensure that the user sees the error. 261 message(FATAL_ERROR "Failed to resolve buck2.\n${resolve_buck2_error}") 262 else() 263 # Unexpected failure of the script. Warn. 264 message(WARNING "Failed to resolve buck2.") 265 message(WARNING "${resolve_buck2_error}") 266 267 if("${BUCK2}" STREQUAL "") 268 set(buck2 "buck2") 269 endif() 270 endif() 271 272 # Update the var in the parent scope. Note that this does not modify our 273 # local $BUCK2 value. 274 set(BUCK2 "${buck2}" PARENT_SCOPE) 275 276 # The buck2 daemon can get stuck. Killing it can help. 277 message(STATUS "Killing buck2 daemon") 278 execute_process( 279 # Note that we need to use the local buck2 variable. BUCK2 is only set in 280 # the parent scope, and can still be empty in this scope. 281 COMMAND "${buck2} kill" 282 WORKING_DIRECTORY ${executorch_root} 283 COMMAND_ECHO STDOUT 284 ) 285endfunction() 286 287# Sets the value of the PYTHON_EXECUTABLE variable to 'python' if in an active 288# (non-base) conda environment, and 'python3' otherwise. This maintains 289# backwards compatibility for non-conda users and avoids conda users needing to 290# explicitly set PYTHON_EXECUTABLE=python. 291function(resolve_python_executable) 292 # Counter-intuitively, CONDA_DEFAULT_ENV contains the name of the active 293 # environment. 294 if(DEFINED ENV{CONDA_DEFAULT_ENV} AND NOT $ENV{CONDA_DEFAULT_ENV} STREQUAL 295 "base" 296 ) 297 set(PYTHON_EXECUTABLE 298 python 299 PARENT_SCOPE 300 ) 301 else() 302 set(PYTHON_EXECUTABLE 303 python3 304 PARENT_SCOPE 305 ) 306 endif() 307endfunction() 308