@@ -220,37 +220,50 @@ def src_path(self, installer: "InstallerBuildExt") -> Path:
220
220
"""
221
221
# Share the cmake-out location with CustomBuild.
222
222
build_cmd = installer .get_finalized_command ("build" )
223
- if hasattr (build_cmd , "cmake_cache_dir" ):
224
- cmake_cache_dir = Path (build_cmd .cmake_cache_dir )
223
+ if "%CMAKE_CACHE_DIR%" in self .src :
224
+ if not hasattr (build_cmd , "cmake_cache_dir" ):
225
+ raise RuntimeError (
226
+ f"Extension { self .name } has a src { self .src } that contains"
227
+ " %CMAKE_CACHE_DIR% but CMake does not run in the `build` "
228
+ "command. Please double check if the command is correct."
229
+ )
230
+ else :
231
+ build_dir = Path (build_cmd .cmake_cache_dir )
225
232
else :
226
- # If we're in editable mode, use a default or fallback value for cmake_cache_dir
227
- # This could be a hardcoded path, or a path derived from the current working directory
228
- cmake_cache_dir = Path ("." )
233
+ # If the src path doesn't contain %CMAKE_CACHE_DIR% placeholder,
234
+ # try to find it under the current directory.
235
+ build_dir = Path ("." )
236
+
237
+ src_path = self .src .replace ("%CMAKE_CACHE_DIR%/" , "" )
238
+
229
239
cfg = get_build_type (installer .debug )
230
240
231
241
if os .name == "nt" :
232
242
# Replace %BUILD_TYPE% with the current build type.
233
- self . src = self . src .replace ("%BUILD_TYPE%" , cfg )
243
+ src_path = src_path .replace ("%BUILD_TYPE%" , cfg )
234
244
else :
235
245
# Remove %BUILD_TYPE% from the path.
236
- self . src = self . src .replace ("/%BUILD_TYPE%" , "" )
246
+ src_path = src_path .replace ("/%BUILD_TYPE%" , "" )
237
247
238
248
# Construct the full source path, resolving globs. If there are no glob
239
249
# pattern characters, this will just ensure that the source file exists.
240
- srcs = tuple (cmake_cache_dir .glob (self . src ))
250
+ srcs = tuple (build_dir .glob (src_path ))
241
251
if len (srcs ) != 1 :
242
252
raise ValueError (
243
- f"""Expected exactly one file matching '{ self .src } ' in { cmake_cache_dir } ; found { repr (srcs )} .
244
-
245
- If that file is a CMake-built extension module file, and we are installing in editable mode, please disable the corresponding build option since it's not supported yet.
246
-
247
- Try:
248
-
249
- EXECUTORCH_BUILD_FLATC=OFF EXECUTORCH_BUILD_KERNELS_CUSTOM_AOT=OFF pip install -e .
250
- """
253
+ f"Expecting exactly 1 file matching { self .src } in { build_dir } , "
254
+ f"found { repr (srcs )} . Resolved src pattern: { src_path } ."
251
255
)
252
256
return srcs [0 ]
253
257
258
+ def inplace_dir (self , installer : "InstallerBuildExt" ) -> Path :
259
+ """Returns the path of this file to be installed to, under inplace mode.
260
+
261
+ It will be a relative path to the project root directory. For more info
262
+ related to inplace/editable mode, please checkout this doc:
263
+ https://setuptools.pypa.io/en/latest/userguide/development_mode.html
264
+ """
265
+ raise NotImplementedError ()
266
+
254
267
255
268
class BuiltFile (_BaseExtension ):
256
269
"""An extension that installs a single file that was built by cmake.
@@ -316,6 +329,18 @@ def dst_path(self, installer: "InstallerBuildExt") -> Path:
316
329
# Destination looks like a file.
317
330
return dst_root / Path (self .dst )
318
331
332
+ def inplace_dir (self , installer : "InstallerBuildExt" ) -> Path :
333
+ """For a `BuiltFile`, we use self.dst as its inplace directory path.
334
+ Need to handle directory vs file.
335
+ """
336
+ # HACK: get rid of the leading "executorch" in ext.dst.
337
+ # This is because we don't have a root level "executorch" module.
338
+ package_dir = self .dst .removeprefix ("executorch/" )
339
+ # If dst is a file, use it's directory
340
+ if not package_dir .endswith ("/" ):
341
+ package_dir = os .path .dirname (package_dir )
342
+ return Path (package_dir )
343
+
319
344
320
345
class BuiltExtension (_BaseExtension ):
321
346
"""An extension that installs a python extension that was built by cmake."""
@@ -369,6 +394,15 @@ def dst_path(self, installer: "InstallerBuildExt") -> Path:
369
394
# path: that's the file we're creating.
370
395
return Path (installer .get_ext_fullpath (self .dst ))
371
396
397
+ def inplace_dir (self , installer : "InstallerBuildExt" ) -> Path :
398
+ """For BuiltExtension, deduce inplace dir path from extension name."""
399
+ build_py = installer .get_finalized_command ("build_py" )
400
+ modpath = self .name .split ("." )
401
+ package = "." .join (modpath [:- 1 ])
402
+ package_dir = os .path .abspath (build_py .get_package_dir (package ))
403
+
404
+ return Path (package_dir )
405
+
372
406
373
407
class InstallerBuildExt (build_ext ):
374
408
"""Installs files that were built by cmake."""
@@ -399,23 +433,15 @@ def copy_extensions_to_source(self) -> None:
399
433
400
434
Returns:
401
435
"""
402
- build_py = self .get_finalized_command ("build_py" )
403
436
for ext in self .extensions :
404
- if isinstance (ext , BuiltExtension ):
405
- modpath = ext .name .split ("." )
406
- package = "." .join (modpath [:- 1 ])
407
- package_dir = os .path .abspath (build_py .get_package_dir (package ))
408
- else :
409
- # HACK: get rid of the leading "executorch" in ext.dst.
410
- # This is because we don't have a root level "executorch" module.
411
- package_dir = ext .dst .removeprefix ("executorch/" )
437
+ package_dir = ext .inplace_dir (self )
412
438
413
439
# Ensure that the destination directory exists.
414
440
self .mkpath (os .fspath (package_dir ))
415
441
416
442
regular_file = ext .src_path (self )
417
443
inplace_file = os .path .join (
418
- package_dir , os .path .basename (ext .src_path (self ))
444
+ package_dir , os .path .basename (ext .dst_path (self ))
419
445
)
420
446
421
447
# Always copy, even if source is older than destination, to ensure
@@ -724,20 +750,6 @@ def run(self):
724
750
# Build the system.
725
751
self .spawn (["cmake" , "--build" , cmake_cache_dir , * build_args ])
726
752
727
- # Non-python files should live under this data directory.
728
- data_root = os .path .join (self .build_lib , "executorch" , "data" )
729
-
730
- # Directories like bin/ and lib/ live under data/.
731
- bin_dir = os .path .join (data_root , "bin" )
732
-
733
- # Copy the bin wrapper so that users can run any executables under
734
- # data/bin, as long as they are listed in the [project.scripts] section
735
- # of pyproject.toml.
736
- self .mkpath (bin_dir )
737
- self .copy_file (
738
- "build/pip_data_bin_init.py.in" ,
739
- os .path .join (bin_dir , "__init__.py" ),
740
- )
741
753
# Share the cmake-out location with _BaseExtension.
742
754
self .cmake_cache_dir = cmake_cache_dir
743
755
@@ -749,13 +761,20 @@ def get_ext_modules() -> List[Extension]:
749
761
"""Returns the set of extension modules to build."""
750
762
ext_modules = []
751
763
if ShouldBuild .flatc ():
752
- ext_modules .append (
753
- BuiltFile (
754
- src_dir = "third-party/flatbuffers/%BUILD_TYPE%/" ,
755
- src_name = "flatc" ,
756
- dst = "executorch/data/bin/" ,
757
- is_executable = True ,
758
- )
764
+ ext_modules .extend (
765
+ [
766
+ BuiltFile (
767
+ src_dir = "%CMAKE_CACHE_DIR%/third-party/flatbuffers/%BUILD_TYPE%/" ,
768
+ src_name = "flatc" ,
769
+ dst = "executorch/data/bin/" ,
770
+ is_executable = True ,
771
+ ),
772
+ BuiltFile (
773
+ src_dir = "build/" ,
774
+ src_name = "pip_data_bin_init.py.in" ,
775
+ dst = "executorch/data/bin/__init__.py" ,
776
+ ),
777
+ ]
759
778
)
760
779
761
780
if ShouldBuild .pybindings ():
@@ -778,16 +797,16 @@ def get_ext_modules() -> List[Extension]:
778
797
if ShouldBuild .llama_custom_ops ():
779
798
ext_modules .append (
780
799
BuiltFile (
781
- src_dir = "extension/llm/custom_ops/%BUILD_TYPE%/" ,
800
+ src_dir = "%CMAKE_CACHE_DIR%/ extension/llm/custom_ops/%BUILD_TYPE%/" ,
782
801
src_name = "custom_ops_aot_lib" ,
783
- dst = "executorch/extension/llm/custom_ops" ,
802
+ dst = "executorch/extension/llm/custom_ops/ " ,
784
803
is_dynamic_lib = True ,
785
804
)
786
805
)
787
806
ext_modules .append (
788
807
# Install the prebuilt library for quantized ops required by custom ops.
789
808
BuiltFile (
790
- src_dir = "kernels/quantized/%BUILD_TYPE%/" ,
809
+ src_dir = "%CMAKE_CACHE_DIR%/ kernels/quantized/%BUILD_TYPE%/" ,
791
810
src_name = "quantized_ops_aot_lib" ,
792
811
dst = "executorch/kernels/quantized/" ,
793
812
is_dynamic_lib = True ,
0 commit comments