Skip to content

[cmake] Install libexecutorch.a and libportable_kernels.a #1036

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ endif()
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()
# ------------------------------ OPTIONS -------------------------------------
# WARNING: Please don't add example specific options in this CMakeLists.txt.
# Instead please use `find_package(executorch REQUIRED)` in the example
# directory and add a new executable in the example `CMakeLists.txt`.

# _default_release_disabled_options: default value for options that should be
# disabled in Release mode by default. Users can still manually enable them,
Expand Down Expand Up @@ -111,16 +115,9 @@ option(BUILD_SELECTIVE_BUILD_TEST

option(EXECUTORCH_BUILD_SIZE_TEST "Whether to build size test" OFF)

# Selective build options.
option(EXECUTORCH_SELECT_ALL_OPS
"Whether to register all ops defined in portable kernel library." ON)

# Option to register op list
option(EXECUTORCH_SELECT_OPS_LIST "Register the following list of ops" OFF)

# Option to register ops from yaml file
option(EXECUTORCH_SELECT_OPS_YAML "Register all the ops from a given yaml file"
OFF)
# Do not enable select all ops if any of the other select options is on.
if(EXECUTORCH_SELECT_OPS_LIST OR EXECUTORCH_SELECT_OPS_YAML)
set(EXECUTORCH_SELECT_ALL_OPS OFF)
Expand Down Expand Up @@ -281,6 +278,16 @@ if(EXECUTORCH_BUILD_GFLAGS)
add_subdirectory(third-party/gflags)
endif()


# Install `executorch` library as well as `ExecuTorchConfig.cmake`
# under ${CMAKE_INSTALL_PREFIX}/
install(
TARGETS executorch
DESTINATION lib
INCLUDES DESTINATION ${_common_include_directories}
)
install(FILES build/ExecuTorchConfig.cmake DESTINATION lib/cmake/ExecuTorch)

#
# executor_runner: Host tool that demonstrates program execution.
#
Expand Down
50 changes: 30 additions & 20 deletions build/Utils.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -79,27 +79,37 @@ function(target_link_options_shared_lib target_name)
endfunction()

# Extract source files based on toml config. This is useful to keep buck2 and
# cmake aligned.
# cmake aligned. Do not regenerate if file exists.
function(extract_sources sources_file)
if(EXECUTORCH_ROOT)
set(executorch_root ${EXECUTORCH_ROOT})
if(EXISTS "${sources_file}")
message(STATUS "executorch: Using source file list ${sources_file}")
else()
set(executorch_root ${CMAKE_CURRENT_SOURCE_DIR})
endif()
execute_process(
COMMAND
${PYTHON_EXECUTABLE} ${executorch_root}/build/extract_sources.py
--buck2=${BUCK2} --config=${executorch_root}/build/cmake_deps.toml
--out=${sources_file}
OUTPUT_VARIABLE gen_srcs_output
ERROR_VARIABLE gen_srcs_error
RESULT_VARIABLE gen_srcs_exit_code
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
if(NOT gen_srcs_exit_code EQUAL 0)
message("Error while generating ${sources_file}. "
"Exit code: ${gen_srcs_exit_code}")
message("Output:\n${gen_srcs_output}")
message("Error:\n${gen_srcs_error}")
message(FATAL_ERROR "executorch: source list generation failed")
# A file wasn't generated. Run a script to extract the source lists from the
# buck2 build system and write them to a file we can include.
#
# NOTE: This will only happen once during cmake setup, so it will not re-run
# if the buck2 targets change.
message(STATUS "executorch: Generating source file list ${sources_file}")
if(EXECUTORCH_ROOT)
set(executorch_root ${EXECUTORCH_ROOT})
else()
set(executorch_root ${CMAKE_CURRENT_SOURCE_DIR})
endif()
execute_process(
COMMAND
${PYTHON_EXECUTABLE} ${executorch_root}/build/extract_sources.py
--buck2=${BUCK2} --config=${executorch_root}/build/cmake_deps.toml
--out=${sources_file}
OUTPUT_VARIABLE gen_srcs_output
ERROR_VARIABLE gen_srcs_error
RESULT_VARIABLE gen_srcs_exit_code
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
if(NOT gen_srcs_exit_code EQUAL 0)
message("Error while generating ${sources_file}. "
"Exit code: ${gen_srcs_exit_code}")
message("Output:\n${gen_srcs_output}")
message("Error:\n${gen_srcs_error}")
message(FATAL_ERROR "executorch: source list generation failed")
endif()
endif()
endfunction()
32 changes: 32 additions & 0 deletions build/executorch-config.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.

# Config defining how CMake should find ExecuTorch package. CMake will search
# for this file and find ExecuTorch package if it is installed.
# Typical usage is:
#
# find_package(executorch REQUIRED)

cmake_minimum_required(VERSION 3.19)

set(_root "${CMAKE_CURRENT_LIST_DIR}/../..")
add_library(executorch STATIC IMPORTED)
find_library(
EXECUTORCH_LIBRARY_PATH executorch HINTS "${_root}"
)
set_target_properties(
executorch PROPERTIES IMPORTED_LOCATION "${EXECUTORCH_LIBRARY_PATH}"
)
target_include_directories(executorch INTERFACE ${_root})

add_library(portable_kernels STATIC IMPORTED)
find_library(
PORTABLE_KERNELS_PATH portable_kernels HINTS "${_root}"
)
set_target_properties(
portable_kernels PROPERTIES IMPORTED_LOCATION "${PORTABLE_KERNELS_PATH}"
)
target_include_directories(portable_kernels INTERFACE ${_root})
54 changes: 47 additions & 7 deletions examples/selective_build/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,57 @@
# ~~~
# It should also be cmake-lint clean.
#

cmake_minimum_required(VERSION 3.19)
project(selective_build_example)

if(NOT PYTHON_EXECUTABLE)
set(PYTHON_EXECUTABLE python3)
endif()

set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..)
set(TORCH_ROOT ${EXECUTORCH_ROOT}/third-party/pytorch)
include(${EXECUTORCH_ROOT}/build/Utils.cmake)
include(${EXECUTORCH_ROOT}/build/Codegen.cmake)

set(_common_compile_options -Wno-deprecated-declarations -fPIC)

# Let files say "include <executorch/path/to/header.h>".
set(_common_include_directories ${EXECUTORCH_ROOT}/..)

find_package(executorch CONFIG REQUIRED)
find_package(
gflags REQUIRED PATHS ${CMAKE_CURRENT_BINARY_DIR}/../../third-party
)

target_include_directories(executorch INTERFACE ${_common_include_directories})

# ------------------------------ OPTIONS BEGIN -------------------------------

# Option to register ops from yaml file
option(EXECUTORCH_SELECT_OPS_YAML "Register all the ops from a given yaml file"
OFF)

# Option to register op list
option(EXECUTORCH_SELECT_OPS_LIST "Register a list of ops, separated by comma"
OFF)

# Selective build options.
option(EXECUTORCH_SELECT_ALL_OPS
"Whether to register all ops defined in portable kernel library." OFF)
# ------------------------------- OPTIONS END --------------------------------

#
# The `_<target>_srcs` lists are defined by including ${EXECUTORCH_SRCS_FILE}.
#
set(
EXECUTORCH_SRCS_FILE
"${CMAKE_CURRENT_BINARY_DIR}/../../executorch_srcs.cmake"
)

extract_sources(${EXECUTORCH_SRCS_FILE})

include(${EXECUTORCH_SRCS_FILE})

#
# select_build_lib: C++ library to register selected ops in custom kernel
# library
Expand All @@ -30,7 +74,6 @@ set(_kernel_lib)
if(EXECUTORCH_SELECT_OPS_YAML)
set(_custom_ops_yaml
${EXECUTORCH_ROOT}/examples/portable/custom_ops/custom_ops.yaml)
gen_selected_ops("${_custom_ops_yaml}" "" "")
set(kernel_sources
${EXECUTORCH_ROOT}/examples/portable/custom_ops/custom_ops_1_out.cpp
${EXECUTORCH_ROOT}/examples/portable/custom_ops/custom_ops_2_out.cpp)
Expand All @@ -55,16 +98,13 @@ generate_bindings_for_kernels(${EXECUTORCH_ROOT}/kernels/portable/functions.yaml
"${_custom_ops_yaml}")
gen_operators_lib("select_build_lib" ${_kernel_lib} executorch)

set(_updated__srcs)
foreach(_src ${_executor_runner__srcs})
list(APPEND _updated__srcs "${EXECUTORCH_ROOT}/${_src}")
endforeach()
list(TRANSFORM _executor_runner__srcs PREPEND "${EXECUTORCH_ROOT}/")

#
# selective_build_test: test binary to allow different operator libraries to
# link to
#
add_executable(selective_build_test ${_updated__srcs})
add_executable(selective_build_test ${_executor_runner__srcs})
if(CMAKE_BUILD_TYPE EQUAL "RELEASE")
target_link_options(selective_build_test PRIVATE "LINKER:--gc-sections")
endif()
Expand Down
75 changes: 46 additions & 29 deletions examples/selective_build/test_selective_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@ set -e
# shellcheck source=/dev/null
source "$(dirname "${BASH_SOURCE[0]}")/../../.ci/scripts/utils.sh"

cmake_install_executorch_lib() {
echo "Installing libexecutorch.a and libportable_kernels.a"
rm -rf cmake-out
retry cmake -DBUCK2="$BUCK" \
-DCMAKE_INSTALL_PREFIX=cmake-out \
-DCMAKE_BUILD_TYPE=Release \
-DPYTHON_EXECUTABLE="$PYTHON_EXECUTABLE" \
-Bcmake-out .
cmake --build cmake-out -j9 --target install --config Release
}

test_buck2_select_all_ops() {
echo "Exporting MobilenetV3"
${PYTHON_EXECUTABLE} -m examples.portable.scripts.export --model_name="mv3"
Expand Down Expand Up @@ -59,20 +70,22 @@ test_cmake_select_all_ops() {
echo "Exporting MobilenetV3"
${PYTHON_EXECUTABLE} -m examples.portable.scripts.export --model_name="mv3"

(rm -rf cmake-out \
&& mkdir cmake-out \
&& cd cmake-out \
&& retry cmake -DBUCK2="$BUCK" \
-DBUILD_SELECTIVE_BUILD_TEST=ON \
local example_dir=examples/selective_build
local build_dir=cmake-out/${example_dir}
rm -rf ${build_dir}
retry cmake -DBUCK2="$BUCK" \
-DCMAKE_BUILD_TYPE=Release \
-DEXECUTORCH_SELECT_ALL_OPS=ON \
-DPYTHON_EXECUTABLE="$PYTHON_EXECUTABLE" ..)
-DCMAKE_INSTALL_PREFIX=cmake-out \
-DPYTHON_EXECUTABLE="$PYTHON_EXECUTABLE" \
-B${build_dir} \
${example_dir}

echo "Build selective build test"
cmake --build cmake-out -j9 --config Release
echo "Building ${example_dir}"
cmake --build ${build_dir} -j9 --config Release

echo 'Running selective build test'
cmake-out/examples/selective_build/selective_build_test --model_path="./mv3.pte"
${build_dir}/selective_build_test --model_path="./mv3.pte"

echo "Removing mv3.pte"
rm "./mv3.pte"
Expand All @@ -82,25 +95,27 @@ test_cmake_select_ops_in_list() {
echo "Exporting MobilenetV2"
${PYTHON_EXECUTABLE} -m examples.portable.scripts.export --model_name="mv2"

local example_dir=examples/selective_build
local build_dir=cmake-out/${example_dir}
# set MAX_KERNEL_NUM=17: 14 primops, add, mul
(rm -rf cmake-out \
&& mkdir cmake-out \
&& cd cmake-out \
&& retry cmake -DBUCK2="$BUCK" \
-DMAX_KERNEL_NUM=17 \
-DBUILD_SELECTIVE_BUILD_TEST=ON \
rm -rf ${build_dir}
retry cmake -DBUCK2="$BUCK" \
-DCMAKE_BUILD_TYPE=Release \
-DMAX_KERNEL_NUM=17 \
-DEXECUTORCH_SELECT_OPS_LIST="aten::convolution.out,\
aten::_native_batch_norm_legit_no_training.out,aten::hardtanh.out,aten::add.out,\
aten::mean.out,aten::view_copy.out,aten::permute_copy.out,aten::addmm.out,\
aten,aten::clone.out" \
-DPYTHON_EXECUTABLE="$PYTHON_EXECUTABLE" ..)
-DCMAKE_INSTALL_PREFIX=cmake-out \
-DPYTHON_EXECUTABLE="$PYTHON_EXECUTABLE" \
-B${build_dir} \
${example_dir}

echo "Build selective build test"
cmake --build cmake-out -j9 --config Release
echo "Building ${example_dir}"
cmake --build ${build_dir} -j9 --config Release

echo 'Running selective build test'
cmake-out/examples/selective_build/selective_build_test --model_path="./mv2.pte"
${build_dir}/selective_build_test --model_path="./mv2.pte"

echo "Removing mv2.pte"
rm "./mv2.pte"
Expand All @@ -109,21 +124,22 @@ aten,aten::clone.out" \
test_cmake_select_ops_in_yaml() {
echo "Exporting custom_op_1"
${PYTHON_EXECUTABLE} -m examples.portable.custom_ops.custom_ops_1

(rm -rf cmake-out \
&& mkdir cmake-out \
&& cd cmake-out \
&& retry cmake -DBUCK2="$BUCK" \
-DBUILD_SELECTIVE_BUILD_TEST=ON \
local example_dir=examples/selective_build
local build_dir=cmake-out/${example_dir}
rm -rf ${build_dir}
retry cmake -DBUCK2="$BUCK" \
-DCMAKE_BUILD_TYPE=Release \
-DEXECUTORCH_SELECT_OPS_YAML=ON \
-DPYTHON_EXECUTABLE="$PYTHON_EXECUTABLE" ..)
-DCMAKE_INSTALL_PREFIX=cmake-out \
-DPYTHON_EXECUTABLE="$PYTHON_EXECUTABLE" \
-B${build_dir} \
${example_dir}

echo "Build selective build test"
cmake --build cmake-out -j9 --config Release
echo "Building ${example_dir}"
cmake --build ${build_dir} -j9 --config Release

echo 'Running selective build test'
cmake-out/examples/selective_build/selective_build_test --model_path="./custom_ops_1.pte"
${build_dir}/selective_build_test --model_path="./custom_ops_1.pte"

echo "Removing custom_ops_1.pte"
rm "./custom_ops_1.pte"
Expand All @@ -141,6 +157,7 @@ fi

if [[ $1 == "cmake" ]];
then
cmake_install_executorch_lib
test_cmake_select_all_ops
test_cmake_select_ops_in_list
test_cmake_select_ops_in_yaml
Expand Down
9 changes: 4 additions & 5 deletions kernels/portable/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,8 @@ list(FILTER _portable_kernels__srcs EXCLUDE REGEX "test/*.cpp")
list(FILTER _portable_kernels__srcs EXCLUDE REGEX "codegen")
# Generate C++ bindings to register kernels into both PyTorch (for AOT) and
# Executorch (for runtime). Here select all ops in functions.yaml
if(EXECUTORCH_SELECT_OPS_YAML)
set(_yaml "${CMAKE_CURRENT_LIST_DIR}/functions.yaml")
endif()
gen_selected_ops(
"${_yaml}" "${EXECUTORCH_SELECT_OPS_LIST}" "${EXECUTORCH_SELECT_ALL_OPS}")
set(_yaml "${CMAKE_CURRENT_LIST_DIR}/functions.yaml")
gen_selected_ops("${_yaml}" "" "")
# Expect gen_selected_ops output file to be selected_operators.yaml
generate_bindings_for_kernels(${CMAKE_CURRENT_SOURCE_DIR}/functions.yaml "")
message("Generated files ${gen_command_sources}")
Expand All @@ -62,3 +59,5 @@ target_compile_options(portable_kernels PUBLIC ${_common_compile_options})
# portable_ops_lib: Register portable_ops_lib ops kernels into Executorch
# runtime
gen_operators_lib("portable_ops_lib" portable_kernels executorch)

install(TARGETS portable_kernels DESTINATION lib)