diff --git a/build/Utils.cmake b/build/Utils.cmake index 56fc1e104b0..55f5892a55e 100644 --- a/build/Utils.cmake +++ b/build/Utils.cmake @@ -143,11 +143,21 @@ function(macos_kernel_link_options target_name) ) endfunction() +# Same as kernel_link_options but it's for MSVC linker +function(msvc_kernel_link_options target_name) + target_link_options( + ${target_name} INTERFACE + "SHELL:LINKER:/WHOLEARCHIVE:$" + ) +endfunction() + # Ensure that the load-time constructor functions run. By default, the linker # would remove them since there are no other references to them. function(target_link_options_shared_lib target_name) if(APPLE) macos_kernel_link_options(${target_name}) + elseif(MSVC) + msvc_kernel_link_options(${target_name}) else() kernel_link_options(${target_name}) endif() diff --git a/build/pip_data_bin_init.py.in b/build/pip_data_bin_init.py.in index 9644c5621df..92998bfa41c 100644 --- a/build/pip_data_bin_init.py.in +++ b/build/pip_data_bin_init.py.in @@ -21,7 +21,9 @@ def _find_executable_files_under(dir): for filename in os.listdir(dir): filepath = os.path.join(dir, filename) if os.path.isfile(filepath) and os.access(filepath, os.X_OK): - bin_names.append(filename) + # avoid def flat.exe() on windows. + filename_without_ext = os.path.splitext(filename)[0] + bin_names.append(filename_without_ext) return bin_names # The list of binaries to create wrapper functions for. diff --git a/build/resolve_buck.py b/build/resolve_buck.py index d70fe94b415..804ab22a033 100644 --- a/build/resolve_buck.py +++ b/build/resolve_buck.py @@ -11,7 +11,6 @@ import platform import stat import sys -import tempfile import urllib.request from dataclasses import dataclass @@ -85,6 +84,12 @@ class BuckInfo: archive_name="buck2-x86_64-apple-darwin.zst", target_versions=["3eb1ae97ea963086866b4d2d9ffa966d"], ), + ("windows", "x86_64"): BuckInfo( + archive_name="buck2-x86_64-pc-windows-msvc.exe.zst", + target_versions=[ + "bf1685c4c4ddd9de4592b5a955cb7326fd01e6c4d5f561643422bed961a17401" + ], + ), } @@ -135,6 +140,8 @@ def resolve_buck2(args: argparse.Namespace) -> Union[str, int]: os_family = "linux" elif sys.platform.startswith("darwin"): os_family = "darwin" + elif sys.platform.startswith("win"): + os_family = "windows" platform_key = (os_family, arch) if platform_key not in BUCK_PLATFORM_MAP: @@ -193,12 +200,12 @@ def resolve_buck2(args: argparse.Namespace) -> Union[str, int]: buck2_archive_url = f"https://github.com/facebook/buck2/releases/download/{target_buck_version}/{buck_info.archive_name}" - with tempfile.NamedTemporaryFile() as archive_file: + try: print(f"Downloading buck2 from {buck2_archive_url}...", file=sys.stderr) - urllib.request.urlretrieve(buck2_archive_url, archive_file.name) + archive_file, _ = urllib.request.urlretrieve(buck2_archive_url) # Extract and chmod. - with open(archive_file.name, "rb") as f: + with open(archive_file, "rb") as f: data = f.read() decompressed_bytes = zstd.decompress(data) @@ -207,6 +214,8 @@ def resolve_buck2(args: argparse.Namespace) -> Union[str, int]: file_stat = os.stat(buck2_local_path) os.chmod(buck2_local_path, file_stat.st_mode | stat.S_IEXEC) + finally: + os.remove(archive_file) return buck2_local_path diff --git a/extension/data_loader/file_data_loader.cpp b/extension/data_loader/file_data_loader.cpp index 7b041fef002..e1d28c3ced0 100644 --- a/extension/data_loader/file_data_loader.cpp +++ b/extension/data_loader/file_data_loader.cpp @@ -17,7 +17,16 @@ #include #include #include +#ifndef _WIN32 #include +#else +#include +#endif + +#ifdef _WIN32 +#include +using ssize_t = ptrdiff_t; +#endif #include #include @@ -58,6 +67,10 @@ FileDataLoader::~FileDataLoader() { std::free(const_cast(file_name_)); // fd_ can be -1 if this instance was moved from, but closing a negative fd is // safe (though it will return an error). +#ifdef _WIN32 + if (fd_ == -1) + return; +#endif ::close(fd_); } diff --git a/extension/llm/custom_ops/CMakeLists.txt b/extension/llm/custom_ops/CMakeLists.txt index 3f242e3d7d7..32c10a17d1c 100644 --- a/extension/llm/custom_ops/CMakeLists.txt +++ b/extension/llm/custom_ops/CMakeLists.txt @@ -101,6 +101,9 @@ if(EXECUTORCH_BUILD_KERNELS_CUSTOM_AOT) endif() target_link_libraries(custom_ops_aot_lib PUBLIC cpublas torch) + if(WIN32) + target_link_libraries(custom_ops_aot_lib PUBLIC pthreadpool cpuinfo) + endif() target_compile_options( custom_ops_aot_lib PUBLIC -Wno-deprecated-declarations -fPIC -frtti -fexceptions diff --git a/runtime/core/exec_aten/util/tensor_util.h b/runtime/core/exec_aten/util/tensor_util.h index 5a6f53213a4..3bc8606c6cd 100644 --- a/runtime/core/exec_aten/util/tensor_util.h +++ b/runtime/core/exec_aten/util/tensor_util.h @@ -15,6 +15,11 @@ #include // size_t #include +#ifdef _WIN32 +#include +using ssize_t = ptrdiff_t; +#endif + #include #include #include diff --git a/runtime/core/portable_type/tensor_impl.h b/runtime/core/portable_type/tensor_impl.h index 49b32afe320..9214423ac35 100644 --- a/runtime/core/portable_type/tensor_impl.h +++ b/runtime/core/portable_type/tensor_impl.h @@ -8,7 +8,12 @@ #pragma once +#ifndef _WIN32 #include // TODO(T126923429): Include size_t, ssize_t +#else +#include +using ssize_t = ptrdiff_t; +#endif #include #include diff --git a/setup.py b/setup.py index 58a9973c9f9..5eab8167a3c 100644 --- a/setup.py +++ b/setup.py @@ -189,9 +189,9 @@ def src_path(self, installer: "InstallerBuildExt") -> Path: installer: The InstallerBuildExt instance that is installing the file. """ - # TODO(dbort): share the cmake-out location with CustomBuild. Can get a - # handle with installer.get_finalized_command('build') - cmake_cache_dir: Path = Path().cwd() / installer.build_temp / "cmake-out" + # share the cmake-out location with CustomBuild. + # Get a handle with installer.get_finalized_command('build') + cmake_cache_dir = Path(installer.get_finalized_command("build").cmake_cache_dir) # Construct the full source path, resolving globs. If there are no glob # pattern characters, this will just ensure that the source file exists. @@ -397,7 +397,7 @@ def __init__(self): self.saved_env = {} def __enter__(self): - if os.geteuid() == 0 and "HOME" in os.environ: + if os.name != "nt" and os.geteuid() == 0 and "HOME" in os.environ: log.info("temporarily unsetting HOME while running as root") self.saved_env["HOME"] = os.environ.pop("HOME") return self @@ -508,6 +508,9 @@ def run(self): item for item in os.environ["CMAKE_BUILD_ARGS"].split(" ") if item ] + if os.name == "nt": + build_args += ["--config", cfg] + # Put the cmake cache under the temp directory, like # "pip-out/temp./cmake-out". cmake_cache_dir = os.path.join(repo_root, self.build_temp, "cmake-out") @@ -545,6 +548,8 @@ def run(self): "build/pip_data_bin_init.py.in", os.path.join(bin_dir, "__init__.py"), ) + # share the cmake-out location with _BaseExtension. + self.cmake_cache_dir = cmake_cache_dir # Finally, run the underlying subcommands like build_py, build_ext. build.run(self) @@ -553,11 +558,21 @@ def run(self): def get_ext_modules() -> List[Extension]: """Returns the set of extension modules to build.""" + debug = os.environ.get("DEBUG", 0) + cfg = "Debug" if debug else "Release" + ext_modules = [] if ShouldBuild.flatc(): - ext_modules.append( - BuiltFile("third-party/flatbuffers/flatc", "executorch/data/bin/") - ) + if os.name == "nt": + ext_modules.append( + BuiltFile( + f"third-party/flatbuffers/{cfg}/flatc.exe", "executorch/data/bin/" + ) + ) + else: + ext_modules.append( + BuiltFile("third-party/flatbuffers/flatc", "executorch/data/bin/") + ) if ShouldBuild.pybindings(): ext_modules.append( @@ -569,20 +584,35 @@ def get_ext_modules() -> List[Extension]: ) ) if ShouldBuild.llama_custom_ops(): - ext_modules.append( - # Install the prebuilt library for custom ops used in llama. - BuiltFile( - "extension/llm/custom_ops/libcustom_ops_aot_lib.*", - "executorch/extension/llm/custom_ops/", + if os.name == "nt": + ext_modules.append( + BuiltFile( + f"extension/llm/custom_ops/{cfg}/custom_ops_aot_lib.dll", + "executorch/extension/llm/custom_ops", + ) ) - ) - ext_modules.append( - # Install the prebuilt library for quantized ops required by custom ops. - BuiltFile( - "kernels/quantized/libquantized_ops_aot_lib.*", - "executorch/kernels/quantized/", + ext_modules.append( + # Install the prebuilt library for quantized ops required by custom ops. + BuiltFile( + f"kernels/quantized/{cfg}/quantized_ops_aot_lib.dll", + "executorch/kernels/quantized/", + ) + ) + else: + ext_modules.append( + # Install the prebuilt library for custom ops used in llama. + BuiltFile( + "extension/llm/custom_ops/libcustom_ops_aot_lib.*", + "executorch/extension/llm/custom_ops/", + ) + ) + ext_modules.append( + # Install the prebuilt library for quantized ops required by custom ops. + BuiltFile( + "kernels/quantized/libquantized_ops_aot_lib.*", + "executorch/kernels/quantized/", + ) ) - ) # Note that setuptools uses the presence of ext_modules as the main signal # that a wheel is platform-specific. If we install any platform-specific