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# Example CMakeLists.txt for registering custom ops into ExecuTorch. In this 8# example we have custom ops `my_ops::mul3.out` implemented in C++ in 9# `examples/portable/custom_ops/custom_ops_1.cpp`. We also have it registered 10# into EXIR in `examples/portable/custom_ops/custom_ops_1.py`. This 11# CMakeLists.txt runs a script to generate wrapper code based on the operator 12# kernel binding defined in `examples/portable/custom_ops/custom_ops.yaml`. Then 13# creates a library that contains both binding wrapper and the implementation 14# source file. This library can be linked into ExecuTorch binary 15# (`executor_runner` in this example) and it is ready to run models containing 16# that custom op. 17cmake_minimum_required(VERSION 3.19) 18project(custom_ops_example) 19 20set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 21if(NOT CMAKE_CXX_STANDARD) 22 set(CMAKE_CXX_STANDARD 17) 23endif() 24 25# Source root directory for executorch. 26if(NOT EXECUTORCH_ROOT) 27 set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../..) 28endif() 29 30include(${EXECUTORCH_ROOT}/build/Utils.cmake) 31include(${EXECUTORCH_ROOT}/build/Codegen.cmake) 32 33if(NOT PYTHON_EXECUTABLE) 34 resolve_python_executable() 35endif() 36 37set(_common_compile_options -Wno-deprecated-declarations -fPIC) 38 39# Let files say "include <executorch/path/to/header.h>". 40set(_common_include_directories ${EXECUTORCH_ROOT}/..) 41 42find_package(executorch CONFIG REQUIRED) 43find_package( 44 gflags REQUIRED PATHS ${CMAKE_CURRENT_BINARY_DIR}/../../../third-party 45) 46 47target_include_directories(executorch INTERFACE ${_common_include_directories}) 48 49# ------------------------------ OPTIONS BEGIN ------------------------------- 50# Option to register custom operator `my_ops::mul3` or `my_ops::mul4` or no 51# custom ops at all. Custom ops are defined in 52# `examples/portable/custom_ops/custom_ops_1.py` and 53# `examples/portable/custom_ops/custom_ops_2.cpp`. 54option( 55 REGISTER_EXAMPLE_CUSTOM_OP 56 "Register whether custom op 1 (my_ops::mul3) or custom op 2 (my_ops::mul4) \ 57 or no custom op at all." OFF 58) 59# ------------------------------- OPTIONS END -------------------------------- 60 61# 62# The `_<target>_srcs` lists are defined by including ${EXECUTORCH_SRCS_FILE}. 63# 64set(EXECUTORCH_SRCS_FILE 65 "${CMAKE_CURRENT_BINARY_DIR}/../../../executorch_srcs.cmake" 66) 67 68extract_sources(${EXECUTORCH_SRCS_FILE}) 69 70include(${EXECUTORCH_SRCS_FILE}) 71 72# Generate C++ bindings to register kernels into both PyTorch (for AOT) and 73# Executorch (for runtime). 74if(REGISTER_EXAMPLE_CUSTOM_OP EQUAL 1) 75 gen_selected_ops(LIB_NAME "custom_ops_lib" ROOT_OPS "my_ops::mul3.out") 76elseif(REGISTER_EXAMPLE_CUSTOM_OP EQUAL 2) 77 gen_selected_ops(LIB_NAME "custom_ops_lib" ROOT_OPS "my_ops::mul4.out") 78endif() 79# Expect gen_selected_ops output file to be selected_operators.yaml 80generate_bindings_for_kernels( 81 LIB_NAME "custom_ops_lib" CUSTOM_OPS_YAML 82 ${CMAKE_CURRENT_LIST_DIR}/custom_ops.yaml 83) 84message("Generated files ${gen_command_sources}") 85 86# Prepare for C++ libraries. 87 88# C++ library to register custom ops into PyTorch. 89if(REGISTER_EXAMPLE_CUSTOM_OP EQUAL 2) 90 gen_selected_ops(LIB_NAME "custom_ops_aot_lib" ROOT_OPS "my_ops::mul4.out") 91 generate_bindings_for_kernels( 92 LIB_NAME "custom_ops_aot_lib" CUSTOM_OPS_YAML 93 ${CMAKE_CURRENT_LIST_DIR}/custom_ops.yaml 94 ) 95 set(custom_ops_kernel_sources 96 ${CMAKE_CURRENT_LIST_DIR}/custom_ops_2.cpp # register my_ops::mul4 97 ${CMAKE_CURRENT_LIST_DIR}/custom_ops_2_out.cpp # register my_ops::mul4.out 98 ) 99 gen_custom_ops_aot_lib( 100 LIB_NAME "custom_ops_aot_lib" KERNEL_SOURCES "${custom_ops_kernel_sources}" 101 ) 102 target_include_directories( 103 custom_ops_aot_lib PUBLIC ${_common_include_directories} 104 ) 105endif() 106 107# C++ library to register custom ops into Executorch runtime. 108if(REGISTER_EXAMPLE_CUSTOM_OP EQUAL 1) 109 set(kernel_sources ${CMAKE_CURRENT_LIST_DIR}/custom_ops_1_out.cpp) 110elseif(REGISTER_EXAMPLE_CUSTOM_OP EQUAL 2) 111 set(kernel_sources ${CMAKE_CURRENT_LIST_DIR}/custom_ops_2_out.cpp) 112endif() 113 114add_library(custom_kernels ${kernel_sources}) 115target_link_libraries(custom_kernels PRIVATE executorch) 116target_compile_options(custom_kernels PUBLIC ${_common_compile_options}) 117 118gen_operators_lib( 119 LIB_NAME "custom_ops_lib" KERNEL_LIBS custom_kernels DEPS executorch 120) 121 122list(TRANSFORM _executor_runner__srcs PREPEND "${EXECUTORCH_ROOT}/") 123 124add_executable(custom_ops_executor_runner ${_executor_runner__srcs}) 125target_link_libraries( 126 custom_ops_executor_runner custom_ops_lib executorch gflags 127) 128target_compile_options( 129 custom_ops_executor_runner PUBLIC ${_common_compile_options} 130) 131