Skip to content

Commit ca6936b

Browse files
authored
support editable install (#76511)
1 parent 1def310 commit ca6936b

File tree

1 file changed

+47
-4
lines changed

1 file changed

+47
-4
lines changed

python/paddle/utils/cpp_extension/cpp_extension.py

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -863,17 +863,19 @@ def _generate_python_api_file(self) -> None:
863863
write_stub mechanism that is no longer triggered in setuptools >= 80.
864864
"""
865865
try:
866-
outputs = self.get_outputs()
867-
if not outputs:
866+
if not self.extensions:
868867
return
868+
869869
# We only support a single extension per setup()
870-
so_path = os.path.abspath(outputs[0])
870+
ext = self.extensions[0]
871+
# Use get_ext_fullpath to handle both standard and inplace builds correctly
872+
so_path = os.path.abspath(self.get_ext_fullpath(ext.name))
871873
so_name = os.path.basename(so_path)
872874
build_dir = os.path.dirname(so_path)
873875

874876
# Get the extension name from the extension module, not the distribution name
875877
# This ensures we use the correct package name from setup.py
876-
ext_name = self.extensions[0].name
878+
ext_name = ext.name
877879

878880
# Extract the last part of the extension name for the Python file
879881
# For example, from "custom_setup_ops.my_ops.custom_relu" we get "custom_relu"
@@ -887,12 +889,53 @@ def _generate_python_api_file(self) -> None:
887889
f"Failed to generate python api file: {e}"
888890
) from e
889891

892+
def _rename_inplace_shared_library(self) -> None:
893+
"""
894+
Rename the shared library to *_pd_.so if it is an inplace build.
895+
This is necessary for editable installs to work correctly with the python stub.
896+
"""
897+
# We only support a single extension per setup()
898+
if not self.extensions:
899+
return
900+
901+
ext = self.extensions[0]
902+
fullpath = self.get_ext_fullpath(ext.name)
903+
904+
filename = os.path.basename(fullpath)
905+
dirname = os.path.dirname(fullpath)
906+
name, ext_suffix = os.path.splitext(filename)
907+
908+
will_rename = False
909+
if OS_NAME.startswith('linux') and ext_suffix == '.so':
910+
will_rename = True
911+
elif OS_NAME.startswith('darwin') and (
912+
ext_suffix == '.dylib' or ext_suffix == '.so'
913+
):
914+
will_rename = True
915+
elif IS_WINDOWS and ext_suffix == '.pyd':
916+
will_rename = True
917+
918+
if will_rename:
919+
new_name = f"{name}_pd_{ext_suffix}"
920+
new_path = os.path.join(dirname, new_name)
921+
922+
if os.path.exists(fullpath):
923+
if os.path.exists(new_path):
924+
os.remove(new_path)
925+
os.rename(fullpath, new_path)
926+
print(
927+
f"Renaming {fullpath} to {new_path} for editable install compatibility"
928+
)
929+
890930
def run(self):
891931
super().run()
892932

893933
# Compatible with wheel installation via `pip install .`
894934
self._generate_python_api_file()
895935

936+
if self.inplace:
937+
self._rename_inplace_shared_library()
938+
896939
self._clean_intermediate_files()
897940

898941

0 commit comments

Comments
 (0)