|
24 | 24 | from pathlib import Path # isort: skip
|
25 | 25 | from pkg_resources import get_build_platform # isort: skip
|
26 | 26 | from distutils.command.clean import clean as CleanCommand # isort: skip
|
| 27 | +from distutils.dep_util import newer_group |
27 | 28 |
|
28 | 29 |
|
29 | 30 | try:
|
@@ -312,6 +313,8 @@ def run(self):
|
312 | 313 |
|
313 | 314 |
|
314 | 315 | class CMakeBuild(build_ext):
|
| 316 | + INCREMENTAL = os.getenv("DD_CMAKE_INCREMENTAL_BUILD", "0").lower() in ("1", "yes", "on", "true") |
| 317 | + |
315 | 318 | @staticmethod
|
316 | 319 | def try_strip_symbols(so_file):
|
317 | 320 | if CURRENT_OS == "Linux" and shutil.which("strip") is not None:
|
@@ -350,6 +353,35 @@ def build_extension(self, ext):
|
350 | 353 | print(f"WARNING: An error occurred while building the extension: {e}")
|
351 | 354 |
|
352 | 355 | def build_extension_cmake(self, ext):
|
| 356 | + if IS_EDITABLE and self.INCREMENTAL: |
| 357 | + # DEV: Rudimentary incremental build support. We copy the logic from |
| 358 | + # setuptools' build_ext command, best effort. |
| 359 | + full_path = Path(self.get_ext_fullpath(ext.name)) |
| 360 | + ext_path = Path(ext.source_dir, full_path.name) |
| 361 | + |
| 362 | + # Collect all the source files within the source directory. We exclude |
| 363 | + # Python sources and anything that does not have a suffix (most likely |
| 364 | + # a binary file), or that has the same name as the extension binary. |
| 365 | + sources = ( |
| 366 | + [ |
| 367 | + _ |
| 368 | + for _ in Path(ext.source_dir).rglob("**") |
| 369 | + if _.is_file() and _.name != full_path.name and _.suffix and _.suffix not in (".py", ".pyc", ".pyi") |
| 370 | + ] |
| 371 | + if ext.source_dir |
| 372 | + else [] |
| 373 | + ) |
| 374 | + if not (self.force or newer_group([str(_.resolve()) for _ in sources], str(ext_path.resolve()), "newer")): |
| 375 | + print(f"skipping '{ext.name}' CMake extension (up-to-date)") |
| 376 | + |
| 377 | + # We need to copy the binary where setuptools expects it |
| 378 | + full_path.parent.mkdir(parents=True, exist_ok=True) |
| 379 | + shutil.copy(ext_path, full_path) |
| 380 | + |
| 381 | + return |
| 382 | + else: |
| 383 | + print(f"building '{ext.name}' CMake extension") |
| 384 | + |
353 | 385 | # Define the build and output directories
|
354 | 386 | output_dir = Path(self.get_ext_fullpath(ext.name)).parent.resolve()
|
355 | 387 | extension_basename = Path(self.get_ext_fullpath(ext.name)).name
|
@@ -459,11 +491,15 @@ def dump_metadata(cls):
|
459 | 491 | with open(cls.metadata_file, "w") as f:
|
460 | 492 | f.write(f"Total time: {total_s:0.2f}s\n")
|
461 | 493 | f.write("Environment:\n")
|
462 |
| - f.write(f"\tCARGO_BUILD_JOBS: {os.getenv('CARGO_BUILD_JOBS', 'unset')}\n") |
463 |
| - f.write(f"\tCMAKE_BUILD_PARALLEL_LEVEL: {os.getenv('CMAKE_BUILD_PARALLEL_LEVEL', 'unset')}\n") |
464 |
| - f.write(f"\tDD_COMPILE_MODE: {COMPILE_MODE}\n") |
465 |
| - f.write(f"\tDD_USE_SCCACHE: {SCCACHE_COMPILE}\n") |
466 |
| - f.write(f"\tDD_FAST_BUILD: {FAST_BUILD}\n") |
| 494 | + for n, v in [ |
| 495 | + ("CARGO_BUILD_JOBS", os.getenv("CARGO_BUILD_JOBS", "unset")), |
| 496 | + ("CMAKE_BUILD_PARALLEL_LEVEL", os.getenv("CMAKE_BUILD_PARALLEL_LEVEL", "unset")), |
| 497 | + ("DD_COMPILE_MODE", COMPILE_MODE), |
| 498 | + ("DD_USE_SCCACHE", SCCACHE_COMPILE), |
| 499 | + ("DD_FAST_BUILD", FAST_BUILD), |
| 500 | + ("DD_CMAKE_INCREMENTAL_BUILD", CMakeBuild.INCREMENTAL), |
| 501 | + ]: |
| 502 | + print(f"\t{n}: {v}", file=f) |
467 | 503 | f.write("Extension build times:\n")
|
468 | 504 | f.write(f"\tTotal: {build_total_s:0.2f}s ({build_percent:0.2f}%)\n")
|
469 | 505 | for ext, elapsed_ns in sorted(cls.build_times.items(), key=lambda x: x[1], reverse=True):
|
|
0 commit comments