From 86e4837b69c0d8ffb1878358edc57b7fab026053 Mon Sep 17 00:00:00 2001 From: Stephen Jia Date: Fri, 14 Mar 2025 17:24:38 -0400 Subject: [PATCH] [Windows] misc fixes to enable Windows build Summary: ## Context Implement some small miscellaneous fixes to enable installing ExecuTorch on Windows. Currently, the optimized kernels cannot be built successfully but the installation works in custom ops are not built. ## Installation ```powershell cd executorch # Need to disable building custom kernels; there are a bunch of build errors $env:EXECUTORCH_BUILD_KERNELS_CUSTOM_AOT=0 # For some reason need to explicitly enable tensor extension otherwise I see a linker error $env:CMAKE_ARGS="-DEXECUTORCH_BUILD_EXTENSION_TENSOR=ON" python install_executorch.py # Unset if you want Remove-Item Env:\EXECUTORCH_BUILD_KERNELS_CUSTOM_AOT Remove-Item Env:\CMAKE_ARGS ``` ## Testing I am able to follow the [Getting Started tutorial](https://pytorch.org/executorch/stable/getting-started-setup.html#run-your-program) successfully. ## Outstanding Build Issues Currently, with CMake I can successfully build with the following settings: ``` del -Recurse -Force cmake-out; ` cmake . ` -DCMAKE_INSTALL_PREFIX=cmake-out ` -DPYTHON_EXECUTABLE=C:\\Users\\ssjia\\AppData\\Local\\miniconda3\\python.exe ` -DCMAKE_PREFIX_PATH=C:\\Users\\ssjia\\AppData\\Local\\miniconda3\\Lib\\site-packages ` -DCMAKE_BUILD_TYPE=Release ` -DEXECUTORCH_BUILD_EXTENSION_TENSOR=ON ` -DEXECUTORCH_BUILD_PYBIND=ON ` -DEXECUTORCH_BUILD_XNNPACK=ON ` -DEXECUTORCH_BUILD_KERNELS_QUANTIZED_AOT=ON ` -DEXECUTORCH_BUILD_KERNELS_CUSTOM_AOT=ON ` -DEXECUTORCH_BUILD_KERNELS_CUSTOM=OFF ` -T ClangCL ` -Bcmake-out; ` cmake --build cmake-out -j64 --target install ``` If I switch `EXECUTORCH_BUILD_KERNELS_CUSTOM` to `ON`, then the build fails. The primary offenders appear to be the `gelu`. The implementation includes a header from ATen which is causing the majority of the errors. --- CMakeLists.txt | 9 +++++++-- backends/xnnpack/CMakeLists.txt | 14 ++++++++++--- extension/llm/custom_ops/CMakeLists.txt | 2 +- install_executorch.bat | 10 ++------- setup.py | 27 ++++++++++++++++++------- 5 files changed, 41 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 511597a7440..dfbc3425fed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -506,13 +506,18 @@ if(EXECUTORCH_BUILD_FLATC) -DFLATBUFFERS_BUILD_FLATLIB=${FLATBUFFERS_BUILD_FLATLIB} -DFLATBUFFERS_BUILD_TESTS=${FLATBUFFERS_BUILD_TESTS} -DFLATBUFFERS_INSTALL=${FLATBUFFERS_INSTALL} - -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-DFLATBUFFERS_MAX_ALIGNMENT=${FLATBUFFERS_MAX_ALIGNMENT}" INSTALL_COMMAND "" BUILD_BYPRODUCTS /flatc ) ExternalProject_Get_Property(flatbuffers BINARY_DIR) - set(FLATC_EXECUTABLE ${BINARY_DIR}/flatc) + if(WIN32) + # flatbuffers does not use CMAKE_BUILD_TYPE. Internally, the build forces Release + # config, but from CMake's perspective the build type is always Debug. + set(FLATC_EXECUTABLE ${BINARY_DIR}/$/flatc.exe) + else() + set(FLATC_EXECUTABLE ${BINARY_DIR}/flatc) + endif() set(FLATC_EXECUTABLE_BUILT_FROM_SOURCE YES) endif() diff --git a/backends/xnnpack/CMakeLists.txt b/backends/xnnpack/CMakeLists.txt index 8b3bf3d91c1..686610c45b4 100644 --- a/backends/xnnpack/CMakeLists.txt +++ b/backends/xnnpack/CMakeLists.txt @@ -69,6 +69,12 @@ foreach(fbs_file ${_xnnpack_schema__srcs}) ) endforeach() +if(WIN32) + set(MV_COMMAND powershell -Command "Move-Item -Path ${_xnnpack_flatbuffer__outputs} -Destination ${_xnnpack_schema__outputs}") +else() + set(MV_COMMAND mv ${_xnnpack_flatbuffer__outputs} ${_xnnpack_schema__outputs}) +endif() + # Generate the headers from the .fbs files. add_custom_command( OUTPUT ${_xnnpack_schema__outputs} @@ -76,13 +82,15 @@ add_custom_command( ${FLATC_EXECUTABLE} --cpp --cpp-std c++11 --scoped-enums -o "${_xnnpack_schema__include_dir}/executorch/backends/xnnpack/serialization" ${_xnnpack_schema__srcs} - COMMAND mv ${_xnnpack_flatbuffer__outputs} ${_xnnpack_schema__outputs} + COMMAND ${MV_COMMAND} WORKING_DIRECTORY ${EXECUTORCH_ROOT} DEPENDS flatc COMMENT "Generating xnnpack_schema headers" VERBATIM ) +unset(MV_COMMAND) + add_library(xnnpack_schema INTERFACE ${_xnnpack_schema__outputs}) set_target_properties(xnnpack_schema PROPERTIES LINKER_LANGUAGE CXX) target_include_directories( @@ -90,14 +98,14 @@ target_include_directories( ${EXECUTORCH_ROOT}/third-party/flatbuffers/include ) -set(xnnpack_third_party pthreadpool cpuinfo) +set(xnnpack_third_party pthreadpool extension_threadpool cpuinfo) include(cmake/Dependencies.cmake) list(TRANSFORM _xnnpack_backend__srcs PREPEND "${EXECUTORCH_ROOT}/") add_library(xnnpack_backend STATIC ${_xnnpack_backend__srcs}) target_link_libraries( - xnnpack_backend PRIVATE ${xnnpack_third_party} executorch_core xnnpack_schema + xnnpack_backend PUBLIC ${xnnpack_third_party} executorch_core xnnpack_schema ) target_include_directories( diff --git a/extension/llm/custom_ops/CMakeLists.txt b/extension/llm/custom_ops/CMakeLists.txt index 6dec5d136ea..4584d077b3d 100644 --- a/extension/llm/custom_ops/CMakeLists.txt +++ b/extension/llm/custom_ops/CMakeLists.txt @@ -49,7 +49,7 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|armv7)$") list(APPEND _custom_ops__srcs "extension/llm/custom_ops/spinquant/third-party/FFHT/fht_neon.c" ) -elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64)") list(APPEND _custom_ops__srcs "extension/llm/custom_ops/spinquant/third-party/FFHT/fht_avx.c" ) diff --git a/install_executorch.bat b/install_executorch.bat index 863ade7bdbb..e6d5c5db363 100644 --- a/install_executorch.bat +++ b/install_executorch.bat @@ -7,14 +7,8 @@ rem This batch file provides a basic functionality similar to the bash script. cd /d "%~dp0" -rem Find the names of the python tools to use (replace with your actual python installation) -if "%PYTHON_EXECUTABLE%"=="" ( - if "%CONDA_DEFAULT_ENV%"=="" OR "%CONDA_DEFAULT_ENV%"=="base" OR NOT EXIST "python" ( - set PYTHON_EXECUTABLE=python3 - ) else ( - set PYTHON_EXECUTABLE=python - ) -) +rem Under windows, it's always python +set PYTHON_EXECUTABLE=python "%PYTHON_EXECUTABLE%" install_executorch.py %* diff --git a/setup.py b/setup.py index 32ec94708af..e779ac73662 100644 --- a/setup.py +++ b/setup.py @@ -345,22 +345,30 @@ def inplace_dir(self, installer: "InstallerBuildExt") -> Path: class BuiltExtension(_BaseExtension): """An extension that installs a python extension that was built by cmake.""" - def __init__(self, src: str, modpath: str): + def __init__(self, src: str, modpath: str, src_dir: Optional[str] = None): """Initializes a BuiltExtension. Args: - src: The path to the file to install (typically a shared library), - relative to the cmake-out directory. May be an fnmatch-style - glob that matches exactly one file. If the path ends in `.so`, - this class will also look for similarly-named `.dylib` files. + src_dir: The directory of the file to install, relative to the cmake-out + directory. A placeholder %BUILD_TYPE% will be replaced with the build + type for multi-config generators (like Visual Studio) where the build + output is in a subdirectory named after the build type. For single- + config generators (like Makefile Generators or Ninja), this placeholder + will be removed. + src_name: The name of the file to install. If the path ends in `.so`, modpath: The dotted path of the python module that maps to the extension. """ assert ( "/" not in modpath ), f"modpath must be a dotted python module path: saw '{modpath}'" + full_src = src + if src_dir is None and platform.system() == "Windows": + src_dir = "%BUILD_TYPE%/" + if src_dir is not None: + full_src = os.path.join(src_dir, src) # This is a real extension, so use the modpath as the name. - super().__init__(src=f"%CMAKE_CACHE_DIR%/{src}", dst=modpath, name=modpath) + super().__init__(src=f"%CMAKE_CACHE_DIR%/{full_src}", dst=modpath, name=modpath) def src_path(self, installer: "InstallerBuildExt") -> Path: """Returns the path to the source file, resolving globs. @@ -780,7 +788,12 @@ def get_ext_modules() -> List[Extension]: # portable kernels, and a selection of backends. This lets users # load and execute .pte files from python. BuiltExtension( - "_portable_lib.*", "executorch.extension.pybindings._portable_lib" + ( + "_portable_lib.cp*" + if platform.system() == "Windows" + else "_portable_lib.*" + ), + "executorch.extension.pybindings._portable_lib", ) ) if ShouldBuild.training():