-
Notifications
You must be signed in to change notification settings - Fork 536
[Build] fix build issues for native Windows. #4681
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -17,7 +17,11 @@ | |||||||||
#include <fcntl.h> | ||||||||||
#include <sys/stat.h> | ||||||||||
#include <sys/types.h> | ||||||||||
#ifndef _WIN32 | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I really want to avoid _WIN32 checks in any of the code, but this is reasonable for now. The best solution would be to avoid using POSIX concepts and to just use the standard C APIs.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Heads up that #4760 merged recently, which changes this class to use There would be a lot of duplicated code, though. If we needed to split into a windows-specific data loader, it might make sense to have an AbstractFileDataLoader with one pure-virtual protected method to do the actual read. |
||||||||||
#include <unistd.h> | ||||||||||
#else | ||||||||||
#include <io.h> | ||||||||||
#endif | ||||||||||
|
||||||||||
#include <executorch/runtime/core/error.h> | ||||||||||
#include <executorch/runtime/core/result.h> | ||||||||||
|
@@ -55,8 +59,10 @@ FileDataLoader::~FileDataLoader() { | |||||||||
// file_name_ can be nullptr if this instance was moved from, but freeing a | ||||||||||
// null pointer is safe. | ||||||||||
std::free(const_cast<char*>(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). | ||||||||||
// fd_ can be -1 if this instance was moved from. | ||||||||||
if (fd_ == -1) { | ||||||||||
return; | ||||||||||
} | ||||||||||
::close(fd_); | ||||||||||
} | ||||||||||
|
||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
@ECHO OFF | ||
|
||
rem Copyright (c) Meta Platforms, Inc. and affiliates. | ||
rem All rights reserved. | ||
|
||
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 | ||
) | ||
) | ||
|
||
"%PYTHON_EXECUTABLE%" install_requirements.py %* | ||
|
||
exit /b %ERRORLEVEL% |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -83,6 +83,10 @@ def python_is_compatible(): | |
print(f"Error: Unknown option {arg}") | ||
sys.exit(1) | ||
|
||
# Use ClangCL on Windows. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment repeats what the code does, and doesn't provide extra value. Either remove it, or (ideally) add a comment explaining why this logic is necessary. It'd also be helpful to explain what ClangCL is, since non-windows devs will not be familiar with it. |
||
if os.name == "nt": | ||
CMAKE_ARGS += " -T ClangCL" | ||
|
||
# Since ExecuTorch often uses main-branch features of pytorch, only the nightly | ||
# pip versions will have the required features. | ||
# | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -133,6 +133,13 @@ | |||||||||||||||||||||||||||
#endif | ||||||||||||||||||||||||||||
#endif // ifndef | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
#ifndef _WIN32 | ||||||||||||||||||||||||||||
#include <sys/types.h> // TODO(T126923429): Include size_t, ssize_t | ||||||||||||||||||||||||||||
#else | ||||||||||||||||||||||||||||
#include <stddef.h> | ||||||||||||||||||||||||||||
using ssize_t = ptrdiff_t; | ||||||||||||||||||||||||||||
#endif | ||||||||||||||||||||||||||||
Comment on lines
+136
to
+141
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your PR actually fixes the TODO, so we can remove it.
Suggested change
|
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
// DEPRECATED: Use the non-underscore-prefixed versions instead. | ||||||||||||||||||||||||||||
// TODO(T199005537): Remove these once all users have stopped using them. | ||||||||||||||||||||||||||||
#define __ET_DEPRECATED ET_DEPRECATED | ||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -48,6 +48,7 @@ | |||||||||||||
|
||||||||||||||
import contextlib | ||||||||||||||
import os | ||||||||||||||
import platform | ||||||||||||||
import re | ||||||||||||||
import sys | ||||||||||||||
|
||||||||||||||
|
@@ -162,6 +163,31 @@ def write_to_python_file(cls, path: str) -> None: | |||||||||||||
fp.write("\n".join(lines) + "\n") | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
# The build type is determined by the DEBUG environment variable. If DEBUG is | ||||||||||||||
# set to a non-empty value, the build type is Debug. Otherwise, the build type | ||||||||||||||
# is Release. | ||||||||||||||
def get_build_type(is_debug=None) -> str: | ||||||||||||||
debug = int(os.environ.get("DEBUG", 0)) if is_debug is None else is_debug | ||||||||||||||
cfg = "Debug" if debug else "Release" | ||||||||||||||
return cfg | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
def get_dynamic_lib_name(name: str) -> str: | ||||||||||||||
if platform.system() == "Windows": | ||||||||||||||
return name + ".dll" | ||||||||||||||
elif platform.system() == "Darwin": | ||||||||||||||
return "lib" + name + ".dylib" | ||||||||||||||
else: | ||||||||||||||
return "lib" + name + ".so" | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
def get_executable_name(name: str) -> str: | ||||||||||||||
if platform.system() == "Windows": | ||||||||||||||
return name + ".exe" | ||||||||||||||
else: | ||||||||||||||
return name | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
class _BaseExtension(Extension): | ||||||||||||||
"""A base class that maps an abstract source to an abstract destination.""" | ||||||||||||||
|
||||||||||||||
|
@@ -189,9 +215,17 @@ 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. | ||||||||||||||
cmake_cache_dir = Path(installer.get_finalized_command("build").cmake_cache_dir) | ||||||||||||||
|
||||||||||||||
cfg = get_build_type(installer.debug) | ||||||||||||||
|
||||||||||||||
if os.name == "nt": | ||||||||||||||
# Replace %BUILD_TYPE% with the current build type. | ||||||||||||||
self.src = self.src.replace("%BUILD_TYPE%", cfg) | ||||||||||||||
else: | ||||||||||||||
# Remove %BUILD_TYPE% from the path. | ||||||||||||||
self.src = self.src.replace("/%BUILD_TYPE%", "") | ||||||||||||||
|
||||||||||||||
# Construct the full source path, resolving globs. If there are no glob | ||||||||||||||
# pattern characters, this will just ensure that the source file exists. | ||||||||||||||
|
@@ -212,17 +246,35 @@ class BuiltFile(_BaseExtension): | |||||||||||||
`ext_modules`. | ||||||||||||||
""" | ||||||||||||||
|
||||||||||||||
def __init__(self, src: str, dst: str): | ||||||||||||||
def __init__( | ||||||||||||||
self, | ||||||||||||||
src_path: str, | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please call this |
||||||||||||||
src_name: str, | ||||||||||||||
dst: str, | ||||||||||||||
is_executable: bool = False, | ||||||||||||||
is_dynamic_lib: bool = False, | ||||||||||||||
): | ||||||||||||||
"""Initializes a BuiltFile. | ||||||||||||||
|
||||||||||||||
Args: | ||||||||||||||
src: The path to the file to install, relative to the cmake-out | ||||||||||||||
directory. May be an fnmatch-style glob that matches exactly one | ||||||||||||||
file. | ||||||||||||||
src_path: The path to the file to install without name, relative to the cmake-out | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please mention |
||||||||||||||
directory. | ||||||||||||||
src_name: The name of the file to install | ||||||||||||||
dst: The path to install to, relative to the root of the pip | ||||||||||||||
package. If dst ends in "/", it is treated as a directory. | ||||||||||||||
Otherwise it is treated as a filename. | ||||||||||||||
is_executable: If True, the file is an executable. This is used to | ||||||||||||||
determine the destination filename for executable. | ||||||||||||||
is_dynamic_lib: If True, the file is a dynamic library. This is used | ||||||||||||||
to determine the destination filename for dynamic library. | ||||||||||||||
""" | ||||||||||||||
if is_executable and is_dynamic_lib: | ||||||||||||||
raise ValueError("is_executable and is_dynamic_lib cannot be both True.") | ||||||||||||||
if is_executable: | ||||||||||||||
src_name = get_executable_name(src_name) | ||||||||||||||
elif is_dynamic_lib: | ||||||||||||||
src_name = get_dynamic_lib_name(src_name) | ||||||||||||||
src = os.path.join(src_path, src_name) | ||||||||||||||
# This is not a real extension, so use a unique name that doesn't look | ||||||||||||||
# like a module path. Some of setuptools's autodiscovery will look for | ||||||||||||||
# extension names with prefixes that match certain module paths. | ||||||||||||||
|
@@ -397,7 +449,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 | ||||||||||||||
|
@@ -432,8 +484,7 @@ def initialize_options(self): | |||||||||||||
def run(self): | ||||||||||||||
self.dump_options() | ||||||||||||||
|
||||||||||||||
debug = int(os.environ.get("DEBUG", 0)) if self.debug is None else self.debug | ||||||||||||||
cfg = "Debug" if debug else "Release" | ||||||||||||||
cfg = get_build_type(self.debug) | ||||||||||||||
|
||||||||||||||
# get_python_lib() typically returns the path to site-packages, where | ||||||||||||||
# all pip packages in the environment are installed. | ||||||||||||||
|
@@ -508,6 +559,8 @@ def run(self): | |||||||||||||
item for item in os.environ["CMAKE_BUILD_ARGS"].split(" ") if item | ||||||||||||||
] | ||||||||||||||
|
||||||||||||||
build_args += ["--config", cfg] | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add a comment explaining why this is necessary. |
||||||||||||||
|
||||||||||||||
# Put the cmake cache under the temp directory, like | ||||||||||||||
# "pip-out/temp.<plat>/cmake-out". | ||||||||||||||
cmake_cache_dir = os.path.join(repo_root, self.build_temp, "cmake-out") | ||||||||||||||
|
@@ -545,18 +598,24 @@ 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) | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
def get_ext_modules() -> List[Extension]: | ||||||||||||||
"""Returns the set of extension modules to build.""" | ||||||||||||||
|
||||||||||||||
ext_modules = [] | ||||||||||||||
if ShouldBuild.flatc(): | ||||||||||||||
ext_modules.append( | ||||||||||||||
BuiltFile("third-party/flatbuffers/flatc", "executorch/data/bin/") | ||||||||||||||
BuiltFile( | ||||||||||||||
"third-party/flatbuffers/%BUILD_TYPE%/", | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will It's ok as-is for now, though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is, but it does not have access to the installer in the constructor of BuiltFile. |
||||||||||||||
"flatc", | ||||||||||||||
"executorch/data/bin/", | ||||||||||||||
Comment on lines
+614
to
+616
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that there are more than two params, please use kwargs for all params. Same for other BuiltFile uses below.
Suggested change
|
||||||||||||||
is_executable=True, | ||||||||||||||
) | ||||||||||||||
) | ||||||||||||||
|
||||||||||||||
if ShouldBuild.pybindings(): | ||||||||||||||
|
@@ -570,17 +629,20 @@ 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/", | ||||||||||||||
"extension/llm/custom_ops/%BUILD_TYPE%/", | ||||||||||||||
"custom_ops_aot_lib", | ||||||||||||||
"executorch/extension/llm/custom_ops", | ||||||||||||||
is_dynamic_lib=True, | ||||||||||||||
) | ||||||||||||||
) | ||||||||||||||
ext_modules.append( | ||||||||||||||
# Install the prebuilt library for quantized ops required by custom ops. | ||||||||||||||
BuiltFile( | ||||||||||||||
"kernels/quantized/libquantized_ops_aot_lib.*", | ||||||||||||||
"kernels/quantized/%BUILD_TYPE%/", | ||||||||||||||
"quantized_ops_aot_lib", | ||||||||||||||
"executorch/kernels/quantized/", | ||||||||||||||
is_dynamic_lib=True, | ||||||||||||||
) | ||||||||||||||
) | ||||||||||||||
|
||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comments should begin with a capital letter. And I suggest making this a little more general.