diff --git a/CMakeLists.txt b/CMakeLists.txt index 801e6baec8b..0712da48b6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,38 +127,7 @@ add_subdirectory(third-party/gflags) # # program_schema: Generated .h files from schema/*.fbs inputs # - -# The include directory that will contain the generated schema headers. -set(_program_schema__include_dir "${CMAKE_CURRENT_BINARY_DIR}/schema/include") - -# Paths to headers generated from the .fbs files. -set(_program_schema__outputs) -foreach(fbs_file ${_program_schema__srcs}) - string(REGEX REPLACE "[.]fbs$" "_generated.h" generated "${fbs_file}") - list(APPEND _program_schema__outputs - "${_program_schema__include_dir}/executorch/${generated}") -endforeach() - -# Generate the headers from the .fbs files. -add_custom_command( - OUTPUT ${_program_schema__outputs} - COMMAND - flatc --cpp --cpp-std c++11 --gen-mutable --scoped-enums - # Add a subdirectory to the include dir so the files can be included as - # - -o "${_program_schema__include_dir}/executorch/schema" - ${_program_schema__srcs} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS flatc ${_program_schema__srcs} - COMMENT "Generating program_schema headers" - VERBATIM) - -add_library(program_schema INTERFACE ${_program_schema__outputs}) -set_target_properties(program_schema PROPERTIES LINKER_LANGUAGE CXX) -target_include_directories( - program_schema - INTERFACE ${_program_schema__include_dir} - ${CMAKE_CURRENT_SOURCE_DIR}/third-party/flatbuffers/include) +add_subdirectory(schema) # # executorch: Core runtime library @@ -174,102 +143,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/ - # ~~~ - # 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) diff --git a/build/Codegen.cmake b/build/Codegen.cmake index 308fc9e2bbf..61e18b7f103 100644 --- a/build/Codegen.cmake +++ b/build/Codegen.cmake @@ -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() diff --git a/build/Utils.cmake b/build/Utils.cmake index 8ed11fc1efb..aee0e01df38 100644 --- a/build/Utils.cmake +++ b/build/Utils.cmake @@ -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 - $ - -Wl,--no-whole-archive - ) + # target_link_options(${target_name} INTERFACE + # "$") + target_link_options( + ${target_name} + INTERFACE + "SHELL:LINKER:--whole-archive $ 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_link_options( + ${target_name} INTERFACE + # Same as kernel_link_options but it's for MacOS linker + "SHELL:LINKER:-force_load,$") +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() diff --git a/examples/custom_ops/CMakeLists.txt b/examples/custom_ops/CMakeLists.txt index b1dfeed2415..6c65e92892d 100644 --- a/examples/custom_ops/CMakeLists.txt +++ b/examples/custom_ops/CMakeLists.txt @@ -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) diff --git a/kernels/portable/CMakeLists.txt b/kernels/portable/CMakeLists.txt new file mode 100644 index 00000000000..a0f1712b4e3 --- /dev/null +++ b/kernels/portable/CMakeLists.txt @@ -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) diff --git a/kernels/quantized/CMakeLists.txt b/kernels/quantized/CMakeLists.txt index acea70c899d..2a40d6848d8 100644 --- a/kernels/quantized/CMakeLists.txt +++ b/kernels/quantized/CMakeLists.txt @@ -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) diff --git a/schema/CMakeLists.txt b/schema/CMakeLists.txt new file mode 100644 index 00000000000..710a763fc65 --- /dev/null +++ b/schema/CMakeLists.txt @@ -0,0 +1,48 @@ +# 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. + +# Flatbuffer schema header lib. Please this file formatted by running: +# ~~~ +# cmake-format --first-comment-is-literal=True CMakeLists.txt +# ~~~ + +# The include directory that will contain the generated schema headers. +set(_program_schema__include_dir "${CMAKE_CURRENT_BINARY_DIR}/schema/include") + +# Source root directory for executorch. +if(NOT EXECUTORCH_ROOT) + set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/..) +endif() + +# Paths to headers generated from the .fbs files. +set(_program_schema__srcs program.fbs scalar_type.fbs) + +set(_program_schema__outputs) +foreach(fbs_file ${_program_schema__srcs}) + string(REGEX REPLACE "[.]fbs$" "_generated.h" generated "${fbs_file}") + list(APPEND _program_schema__outputs + "${_program_schema__include_dir}/executorch/${generated}") +endforeach() + +# Generate the headers from the .fbs files. +add_custom_command( + OUTPUT ${_program_schema__outputs} + COMMAND + flatc --cpp --cpp-std c++11 --gen-mutable --scoped-enums + # Add a subdirectory to the include dir so the files can be included as + # + -o "${_program_schema__include_dir}/executorch/schema" + ${_program_schema__srcs} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS flatc ${_program_schema__srcs} + COMMENT "Generating program_schema headers" + VERBATIM) + +add_library(program_schema INTERFACE ${_program_schema__outputs}) +set_target_properties(program_schema PROPERTIES LINKER_LANGUAGE CXX) +target_include_directories( + program_schema INTERFACE ${_program_schema__include_dir} + ${EXECUTORCH_ROOT}/third-party/flatbuffers/include)