@@ -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