xref: /aosp_15_r20/external/executorch/build/Utils.cmake (revision 523fa7a60841cd1ecfb9cc4201f1ca8b03ed023a)
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