Skip to content

Decentralize portable lib cmake build file #150

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
96 changes: 4 additions & 92 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -174,102 +174,14 @@ target_include_directories(executorch PUBLIC ${_common_include_directories})
target_compile_options(executorch PUBLIC ${_common_compile_options})

#
# portable_kernels: Pure-C++ kernel library for ATen ops
#
# Focused on portability and understandability rather than speed.
#

add_library(portable_kernels ${_portable_kernels__srcs})
target_link_libraries(portable_kernels PRIVATE executorch)
target_compile_options(portable_kernels PUBLIC ${_common_compile_options})

#
# portable_kernels_bindings: Bindings and registration for all ops defined in
# kernels/portable/functions.yaml
# portable_ops_lib: A library to register core ATen ops using portable kernels,
# see kernels/portable/CMakeLists.txt.
#
# Real integrations should supply their own YAML file that only lists the
# operators necessary for the models that will run.
#
# TODO(dbort): Make it possible to provide a custom YAML file. It will be easier
# once we stop using buck2 for this step.
#

set(_portable_kernels_bindings__generated_files
# Although the codegen tool generates more files, these are the only ones we
# need for non-custom kernels.
NativeFunctions.h RegisterCodegenUnboxedKernelsEverything.cpp)

set(_portable_kernels_bindings__output_dir
"${CMAKE_CURRENT_BINARY_DIR}/portable_kernels_bindings")

# Paths to files generated by the codegen step.
set(_portable_kernels_bindings__outputs)
foreach(gen ${_portable_kernels_bindings__generated_files})
list(APPEND _portable_kernels_bindings__outputs
"${_portable_kernels_bindings__output_dir}/${gen}")
endforeach()

set(_portable_kernels_bindings__cpp_files
${_portable_kernels_bindings__outputs})
list(FILTER _portable_kernels_bindings__cpp_files INCLUDE REGEX "[.]cpp$")

# Build the generated files.
#
# NOTE: This will only happen once during cmake setup, so it will not re-run if
# the functions.yaml file changes. TODO(dbort): Stop using buck2 to do this. Use
# add_custom_command() to run the codegen tool directly.
message(STATUS "portable_kernels_bindings: Generating bindings")
execute_process(
COMMAND ${BUCK2} build //kernels/portable:generated_lib_combined --show-output
OUTPUT_VARIABLE buck_output
ERROR_VARIABLE buck_error
RESULT_VARIABLE buck_exit_code
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
if(buck_exit_code EQUAL 0)
# The output will look like
# ~~~
# root//kernels/portable:generated_lib_combined buck-out/<path-we-want>
# ~~~
# Extract the second field while avoiding trailing whitespace.
string(REGEX MATCH "buck-out/[^ \t\r\n]*" srcdir ${buck_output})

# Assemble the list of source files, which live under the buck output dir.
set(_srcfiles)
foreach(gen ${_portable_kernels_bindings__generated_files})
list(APPEND _srcfiles "${CMAKE_CURRENT_SOURCE_DIR}/${srcdir}/${gen}")
endforeach()

file(MAKE_DIRECTORY ${_portable_kernels_bindings__output_dir})
file(COPY ${_srcfiles} DESTINATION ${_portable_kernels_bindings__output_dir})
message(STATUS "portable_kernels_bindings: "
"Copied files to ${_portable_kernels_bindings__output_dir}")
else()
message(
"Error occurred while executing buck2 command. Exit code: ${buck_exit_code}"
)
message("Buck2 Output:\n${buck_output}")
message("Buck2 Error:\n${buck_error}")
message(FATAL_ERROR "portable_kernels_bindings: codegen failed")
endif()

add_library(portable_kernels_bindings)
target_sources(portable_kernels_bindings
PRIVATE ${_portable_kernels_bindings__cpp_files})
target_link_libraries(portable_kernels_bindings PRIVATE executorch)
target_link_libraries(portable_kernels_bindings INTERFACE portable_kernels)

# Ensure that the load-time constructor functions run. By default, the linker
# would remove them since there are no other references to them.
if(APPLE)
macos_kernel_link_options(portable_kernels_bindings)
else()
kernel_link_options(portable_kernels_bindings)
endif()

#
# executor_runner: A simple commandline tool that loads and runs a program file.
#
set(_libs executorch portable_kernels_bindings gflags)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/kernels/portable)
set(_libs executorch portable_ops_lib gflags)

# Generate custom_ops_lib based on REGISTER_EXAMPLE_CUSTOM_OP
if(REGISTER_EXAMPLE_CUSTOM_OP EQUAL 1 OR REGISTER_EXAMPLE_CUSTOM_OP EQUAL 2)
Expand Down
35 changes: 12 additions & 23 deletions build/Codegen.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -101,31 +101,20 @@ function(gen_custom_ops_aot_lib lib_name kernel_sources)

include(${EXECUTORCH_ROOT}/build/Utils.cmake)

# Ensure that the load-time constructor functions run. By default, the linker
# would remove them since there are no other references to them.
if(APPLE)
macos_kernel_link_options(${lib_name})
else()
kernel_link_options(${lib_name})
endif()
target_link_options_shared_lib(${lib_name})
endfunction()

# Generate a runtime lib for registering operators in Executorch
function(gen_operators_lib lib_name kernel_sources)
add_library(
${lib_name} SHARED
${CMAKE_CURRENT_BINARY_DIR}/RegisterCodegenUnboxedKernelsEverything.cpp
${CMAKE_CURRENT_BINARY_DIR}/Functions.h
${CMAKE_CURRENT_BINARY_DIR}/NativeFunctions.h ${kernel_sources})
target_link_libraries(${lib_name} PRIVATE executorch)

include(${EXECUTORCH_ROOT}/build/Utils.cmake)
function(gen_operators_lib lib_name kernel_lib deps)
add_library(${lib_name})
target_sources(
${lib_name}
PRIVATE
${CMAKE_CURRENT_BINARY_DIR}/RegisterCodegenUnboxedKernelsEverything.cpp
${CMAKE_CURRENT_BINARY_DIR}/Functions.h
${CMAKE_CURRENT_BINARY_DIR}/NativeFunctions.h)
target_link_libraries(${lib_name} PRIVATE ${deps})
target_link_libraries(${lib_name} INTERFACE ${kernel_lib})

# Ensure that the load-time constructor functions run. By default, the linker
# would remove them since there are no other references to them.
if(APPLE)
macos_kernel_link_options(${lib_name})
else()
kernel_link_options(${lib_name})
endif()
target_link_options_shared_lib(${lib_name})
endfunction()
89 changes: 62 additions & 27 deletions build/Utils.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,74 @@
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.

# This file is intended to have helper functions to keep the CMakeLists.txt concise. If there are any helper function can be re-used, it's recommented to add them here.
# This file is intended to have helper functions to keep the CMakeLists.txt
# concise. If there are any helper function can be re-used, it's recommented to
# add them here.


# Public function to print summary for all configurations. For new variable, it's recommended to add them here.
# Public function to print summary for all configurations. For new variable,
# it's recommended to add them here.
function(executorch_print_configuration_summary)
message(STATUS "")
message(STATUS "******** Summary ********")
message(STATUS " BUCK : ${BUCK2}")
message(STATUS " CMAKE_CXX_STANDARD : ${CMAKE_CXX_STANDARD}")
message(STATUS " CMAKE_CXX_COMPILER_ID : ${CMAKE_CXX_COMPILER_ID}")
message(STATUS " CMAKE_TOOLCHAIN_FILE : ${CMAKE_TOOLCHAIN_FILE}")
message(STATUS " FLATBUFFERS_BUILD_FLATC : ${FLATBUFFERS_BUILD_FLATC}")
message(STATUS " FLATBUFFERS_BUILD_FLATHASH : ${FLATBUFFERS_BUILD_FLATHASH}")
message(STATUS " FLATBUFFERS_BUILD_FLATLIB : ${FLATBUFFERS_BUILD_FLATLIB}")
message(STATUS " FLATBUFFERS_BUILD_TESTS : ${FLATBUFFERS_BUILD_TESTS}")
message(STATUS " REGISTER_EXAMPLE_CUSTOM_OPS : ${REGISTER_EXAMPLE_CUSTOM_OPS}")
message(STATUS "")
message(STATUS "******** Summary ********")
message(STATUS " BUCK : ${BUCK2}")
message(STATUS " CMAKE_CXX_STANDARD : ${CMAKE_CXX_STANDARD}")
message(STATUS " CMAKE_CXX_COMPILER_ID : ${CMAKE_CXX_COMPILER_ID}")
message(STATUS " CMAKE_TOOLCHAIN_FILE : ${CMAKE_TOOLCHAIN_FILE}")
message(STATUS " FLATBUFFERS_BUILD_FLATC : ${FLATBUFFERS_BUILD_FLATC}")
message(
STATUS " FLATBUFFERS_BUILD_FLATHASH : ${FLATBUFFERS_BUILD_FLATHASH}")
message(
STATUS " FLATBUFFERS_BUILD_FLATLIB : ${FLATBUFFERS_BUILD_FLATLIB}")
message(STATUS " FLATBUFFERS_BUILD_TESTS : ${FLATBUFFERS_BUILD_TESTS}")
message(
STATUS " REGISTER_EXAMPLE_CUSTOM_OPS : ${REGISTER_EXAMPLE_CUSTOM_OPS}")
endfunction()

# This is the funtion to use -Wl, --whole-archive to link static library
# This is the funtion to use -Wl, --whole-archive to link static library NB:
# target_link_options is broken for this case, it only append the interface link
# options of the first library.
function(kernel_link_options target_name)
target_link_options(${target_name}
INTERFACE
# TODO(dbort): This will cause the .a to show up on the link line twice
-Wl,--whole-archive
$<TARGET_FILE:${target_name}>
-Wl,--no-whole-archive
)
# target_link_options(${target_name} INTERFACE
# "$<LINK_LIBRARY:WHOLE_ARCHIVE,target_name>")
target_link_options(
${target_name}
INTERFACE
"SHELL:LINKER:--whole-archive $<TARGET_FILE:${target_name}> LINKER:--no-whole-archive"
)
endfunction()

function(macos_kernel_link_options target_name)
target_link_options(${target_name}
INTERFACE
# Same as kernel_link_options but it's for MacOS linker
-Wl,-force_load,$<TARGET_FILE:${target_name}>
)
target_link_options(
${target_name} INTERFACE
# Same as kernel_link_options but it's for MacOS linker
"SHELL:LINKER:-force_load,$<TARGET_FILE:${target_name}>")
endfunction()

function(target_link_options_shared_lib target_name)
# Ensure that the load-time constructor functions run. By default, the linker
# would remove them since there are no other references to them.
if(APPLE)
macos_kernel_link_options(${target_name})
else()
kernel_link_options(${target_name})
endif()
endfunction()

# Extract source files based on toml config. This is useful to keep buck2 and
# cmake aligned.
function(extract_sources sources_file)
execute_process(
COMMAND ${PYTHON_EXECUTABLE} build/extract_sources.py --buck2=${BUCK2}
--config=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()
endfunction()
7 changes: 6 additions & 1 deletion examples/custom_ops/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,9 @@ if(REGISTER_EXAMPLE_CUSTOM_OP EQUAL 1)
elseif(REGISTER_EXAMPLE_CUSTOM_OP EQUAL 2)
set(kernel_sources ${CMAKE_CURRENT_LIST_DIR}/custom_ops_2_out.cpp)
endif()
gen_operators_lib("custom_ops_lib" "${kernel_sources}")

add_library(custom_kernels ${kernel_sources})
target_link_libraries(custom_kernels PRIVATE executorch)
target_compile_options(custom_kernels PUBLIC ${_common_compile_options})

gen_operators_lib("custom_ops_lib" custom_kernels executorch)
60 changes: 60 additions & 0 deletions kernels/portable/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# 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.

# Kernel library for portable kernels. Please this file formatted by running:
# ~~~
# cmake-format --first-comment-is-literal=True CMakeLists.txt
# ~~~

cmake_minimum_required(VERSION 3.19)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
endif()

if(NOT PYTHON_EXECUTABLE)
set(PYTHON_EXECUTABLE python3)
endif()
# Source root directory for executorch.
if(NOT EXECUTORCH_ROOT)
set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..)
endif()
# Source root directory for pytorch.
if(NOT TORCH_ROOT)
set(TORCH_ROOT ${EXECUTORCH_ROOT}/third-party/pytorch)
endif()

set(_common_compile_options -Wno-deprecated-declarations)

include(${EXECUTORCH_ROOT}/build/Utils.cmake)
include(${EXECUTORCH_ROOT}/build/Codegen.cmake)
# Portable kernel sources TODO(larryliu0820): use buck2 to gather the sources
file(GLOB_RECURSE _portable_kernels__srcs
"${CMAKE_CURRENT_SOURCE_DIR}/cpu/*.cpp")
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
gen_selected_ops("${CMAKE_CURRENT_LIST_DIR}/functions.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}")

#
# portable_kernels: Pure-C++ kernel library for ATen ops
#
# Focused on portability and understandability rather than speed.
#
add_library(portable_kernels ${_portable_kernels__srcs})
target_link_libraries(portable_kernels PRIVATE executorch)
target_compile_options(portable_kernels PUBLIC ${_common_compile_options})

# Build a library for _portable_kernels__srcs
#
# portable_ops_lib: Register portable_ops_lib ops kernels into Executorch
# runtime
gen_operators_lib("portable_ops_lib" portable_kernels executorch)
5 changes: 4 additions & 1 deletion kernels/quantized/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ set(_quantized_sources
)
gen_custom_ops_aot_lib("quantized_ops_aot_lib" "${_quantized_sources}")

add_library(quantized_kernels ${_quantized_kernels__srcs})
target_link_libraries(quantized_kernels PRIVATE executorch)
target_compile_options(quantized_kernels PUBLIC ${_common_compile_options})
# Build a library for _quantized_kernels_srcs
#
# quantized_ops_lib: Register quantized ops kernels into Executorch runtime
gen_operators_lib("quantized_ops_lib" "${_quantized_kernels__srcs}")
gen_operators_lib("quantized_ops_lib" quantized_kernels executorch)