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
Add option for cpp_extensions to compile standalone executable #47862
Conversation
[ghstack-poisoned]
💊 CI failures summary and remediationsAs of commit e778589 (more details on the Dr. CI page): ✅ None of the CI failures appear to be your fault 💚
🚧 1 fixed upstream failure:These were probably caused by upstream breakages that were already fixed.
Please rebase on the
|
torch/utils/cpp_extension.py
Outdated
@@ -23,6 +23,13 @@ | |||
|
|||
|
|||
IS_WINDOWS = sys.platform == 'win32' | |||
LIB_EXT = 'pyd' if IS_WINDOWS else 'so' | |||
EXEC_EXT = 'exe' if IS_WINDOWS else 'o' |
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.
exec extension is o on linux? Really?
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.
I wound up just omitting it altogether. (Which I guess is the most UNIX-y thing to do.)
torch/utils/cpp_extension.py
Outdated
if IS_WINDOWS: | ||
if is_standalone: | ||
ldflags = extra_ldflags | ||
elif IS_WINDOWS: |
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.
nittiest of nits: it would feel better if it was:
if is_standalone:
...
else:
if IS_WINDOWS:
...
else:
...
as this communicates better that there aren't three cases, there are two cases, and a subdivision in the second case.
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.
Fair point, though my cyclomatic complexity alarm went off for the double nest. I wound up defining SHARED_FLAG
since platform is import constant, and then just did ldflags = ([] if is_standalone else [SHARED_FLAG]) + extra_ldflags
. A cynic might argue that I'm being too cute / python-y, but hopefully that conveys the intent of "either it's standalone, or slap a --plays_well_with_others
stamp on it.)
torch/utils/cpp_extension.py
Outdated
def _import_module_from_library(module_name, path, is_python_module): | ||
def _import_module_from_library(module_name, path, is_python_module, is_standalone): | ||
if is_standalone: | ||
if IS_WINDOWS and TORCH_LIB_PATH not in os.getenv('PATH', ''): |
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.
Technically this is wrong, because if I have f'{TORCH_LIB_PATH}/blah/blah
in PATH it will incorrectly detect that the PATH is present when it actually isn't. I also get a bit nervous about forward slash and backward slash confusion here.
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.
Good point. I added .split(';')
so now it should actually do the right thing. There shouldn't be any forward-backward slash shenaniganry since I use os.path.blah
for everything. (Right?)
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.
It will be strictly safe if you use os.path.samefile
, which automatically handles cases and slashes. e.g.
>>> os.path.samefile('C:\\Windows', 'c:/windows')
True
But it requires the existence of the paths. So maybe you'll need to use it like os.path.exists(a) and os.path.exists(b) and os.path.samefile(a, b)
.
extra_ldflags.append(f'/LIBPATH:{TORCH_LIB_PATH}') | ||
if not is_standalone: | ||
extra_ldflags.append('torch_python.lib') | ||
extra_ldflags.append(f'/LIBPATH:{python_lib_path}') |
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.
By the way, one could conceivable want a standalone executable that still has the Python interpreter. This use case would be when the top level runner is a C++ program, but then calls into the Python runtime. Pretty obscure, but it's a valid configuration. (No action needed.)
stdout=subprocess.PIPE, | ||
) | ||
self.assertEqual(r.returncode, 0) | ||
self.assertEqual( |
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.
expect test?
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.
In this case no, because:
expecttest
doesn't handle the loop properly. (Tries to double update.)- The replacement is completely dedented.
I tried it (factoring the run bits so there were two literal tests) and it was just ugly and awkward. If there were more test cases or the output was less trivial, yeah I'd convert it to an expect test.
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.
just nits
…able" [ghstack-poisoned]
…able" [ghstack-poisoned]
…able" [ghstack-poisoned]
…able" [ghstack-poisoned]
…able" Differential Revision: [D25199265](https://our.internmc.facebook.com/intern/diff/D25199265) [ghstack-poisoned]
…able" Differential Revision: [D25199265](https://our.internmc.facebook.com/intern/diff/D25199265) [ghstack-poisoned]
…able" Differential Revision: [D25199265](https://our.internmc.facebook.com/intern/diff/D25199265) [ghstack-poisoned]
…able" Differential Revision: [D25199265](https://our.internmc.facebook.com/intern/diff/D25199265) [ghstack-poisoned]
Stack from ghstack:
Differential Revision: D25199265