Skip to content

Commit 44b40d6

Browse files
committed
Add licenses, gate build
1 parent 73ec52e commit 44b40d6

3 files changed

Lines changed: 45 additions & 16 deletions

File tree

packaging/repair_wheel.py

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,22 @@ def _find_nvjpeg_libs():
111111
return list(found)
112112

113113

114+
def _find_nvjpeg_license():
115+
# Try to find EULA.txt, fallback to LICENSE
116+
dirs = []
117+
for lib in _find_nvjpeg_libs():
118+
dirs.extend(lib.parents)
119+
for var in ("CUDA_HOME", "CUDA_PATH", "CUDAToolkit_ROOT"):
120+
if v := os.environ.get(var):
121+
dirs.append(Path(v))
122+
for filename in ("EULA.txt", "LICENSE"):
123+
for d in dirs:
124+
candidate = d / filename
125+
if candidate.is_file():
126+
return candidate
127+
return None
128+
129+
114130
def repair_linux(wheels):
115131
run([sys.executable, "-m", "pip", "install", "--upgrade", "auditwheel"])
116132
run(["auditwheel", "--version"])
@@ -274,7 +290,8 @@ def bundle_third_party_licenses():
274290
statically embeds dav1d and libyuv) as binaries inside the wheel. Their
275291
permissive licenses (IJG/BSD/zlib) require reproducing the copyright notice
276292
and license text in binary redistributions, so we ship them next to our own
277-
LICENSE.
293+
LICENSE. CUDA wheels additionally bundle libnvjpeg, redistributed under the
294+
NVIDIA CUDA Toolkit EULA, which we ship as well.
278295
"""
279296

280297
def _resolve_conda_licenses():
@@ -349,9 +366,9 @@ def _resolve_avif_licenses():
349366
return {f.name: f for f in sorted(dirs[0].iterdir()) if f.is_file()}
350367

351368
run([sys.executable, "-m", "pip", "install", "-U", "wheel"])
352-
licenses = {**_resolve_conda_licenses(), **_resolve_avif_licenses()}
369+
base_licenses = {**_resolve_conda_licenses(), **_resolve_avif_licenses()}
353370
print("Third-party license files to bundle:")
354-
for name, src in sorted(licenses.items()):
371+
for name, src in sorted(base_licenses.items()):
355372
print(f" {name} <- {src}")
356373

357374
scratch = Path("dist_licenses")
@@ -360,6 +377,16 @@ def _resolve_avif_licenses():
360377
scratch.mkdir(parents=True)
361378

362379
for wheel in sorted(DIST_DIR.glob("*.whl")):
380+
licenses = dict(base_licenses)
381+
if _is_cuda_wheel(wheel):
382+
if (nvjpeg_license := _find_nvjpeg_license()) is None:
383+
raise RuntimeError(
384+
f"{wheel.name} bundles libnvjpeg but the NVIDIA CUDA EULA "
385+
"could not be located to ship alongside it."
386+
)
387+
licenses["LICENSE.libnvjpeg-NVIDIA-CUDA-EULA.txt"] = nvjpeg_license
388+
print(f" LICENSE.libnvjpeg-NVIDIA-CUDA-EULA.txt <- {nvjpeg_license}")
389+
363390
unpack_dir = scratch / "unpack"
364391
if unpack_dir.is_dir():
365392
shutil.rmtree(unpack_dir)
@@ -550,16 +577,20 @@ def _assert_linux_libjpeg_is_turbo(zf):
550577
"found at build time."
551578
)
552579

553-
def _assert_third_party_licenses(zf):
580+
def _assert_third_party_licenses(zf, is_cuda):
554581
"""Every bundled third-party lib must ship its license text under
555582
.dist-info/licenses/third_party/ (see bundle_third_party_licenses)."""
556583
license_files = [
557584
n
558585
for n in zf.namelist()
559586
if "/licenses/third_party/" in n and not n.endswith("/")
560587
]
561-
# keyword each bundled lib's license file must be identifiable by.
562-
for keyword in ("jpeg", "png", "zlib", "webp", "avif", "dav1d", "yuv"):
588+
# keyword each bundled lib's license file must be identifiable by. CUDA
589+
# wheels also bundle libnvjpeg, whose NVIDIA CUDA EULA must ship too.
590+
keywords = ["jpeg", "png", "zlib", "webp", "avif", "dav1d", "yuv"]
591+
if is_cuda:
592+
keywords.append("nvjpeg")
593+
for keyword in keywords:
563594
if not any(keyword in n.lower() for n in license_files):
564595
raise RuntimeError(
565596
f"No third-party license file matching '{keyword}' found in "
@@ -569,7 +600,7 @@ def _assert_third_party_licenses(zf):
569600
for wheel in DIST_DIR.glob("*.whl"):
570601
print(f"Checking bundled libraries in {wheel.name}")
571602
with zipfile.ZipFile(wheel) as zf:
572-
_assert_third_party_licenses(zf)
603+
_assert_third_party_licenses(zf, _is_cuda_wheel(wheel))
573604
names = zf.namelist()
574605
libs = sorted({n.rsplit("/", 1)[-1] for n in names if _is_shared_lib(n)})
575606
if unexpected := [lib for lib in libs if not _is_allowed(lib)]:

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ TORCHCODEC_BUILD_PNG = {env = "TORCHCODEC_BUILD_PNG", default = "AUTO"}
6363
TORCHCODEC_BUILD_WEBP = {env = "TORCHCODEC_BUILD_WEBP", default = "AUTO"}
6464
TORCHCODEC_BUILD_AVIF = {env = "TORCHCODEC_BUILD_AVIF", default = "AUTO"}
6565
TORCHCODEC_BUILD_GIF = {env = "TORCHCODEC_BUILD_GIF", default = "AUTO"}
66+
TORCHCODEC_BUILD_NVJPEG = {env = "TORCHCODEC_BUILD_NVJPEG", default = "AUTO"}
6667

6768
[project.optional-dependencies]
6869
dev = [

src/torchcodec/_core/CMakeLists.txt

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ endif()
4343
if(NOT DEFINED TORCHCODEC_BUILD_IMAGE)
4444
set(TORCHCODEC_BUILD_IMAGE "ON")
4545
endif()
46-
foreach(_codec JPEG PNG WEBP AVIF GIF)
46+
foreach(_codec JPEG PNG WEBP AVIF GIF NVJPEG)
4747
if(NOT DEFINED TORCHCODEC_BUILD_${_codec})
4848
set(TORCHCODEC_BUILD_${_codec} "AUTO")
4949
endif()
@@ -551,17 +551,14 @@ function(make_torchcodec_image_library)
551551
"${TORCH_LIBRARIES}"
552552
)
553553

554-
# The nvJPEG GPU JPEG decoder is a plain C++ translation unit (nvJPEG is a
555-
# host-side API with no CUDA kernels), so the image library needs no
556-
# enable_language(CUDA) -- just nvjpeg/cudart headers and libs from the CUDA
557-
# toolkit, found via CUDAToolkit.
558-
if(ENABLE_CUDA)
554+
resolve_image_codec("${TORCHCODEC_BUILD_NVJPEG}" want_nvjpeg)
555+
if(ENABLE_CUDA AND want_nvjpeg)
559556
find_package(CUDAToolkit REQUIRED)
560557
target_link_libraries(${image_library_name} PRIVATE CUDA::nvjpeg CUDA::cudart)
561-
# TORCHCODEC_ENABLE_NVJPEG unlocks the real nvJPEG decoder (otherwise
562-
# decode_jpegs_cuda is a stub that raises). USE_CUDA is needed for the
563-
# torch stable-ABI CUDA shim (torch_get_cuda_stream_from_pool).
564558
target_compile_definitions(${image_library_name} PRIVATE TORCHCODEC_ENABLE_NVJPEG=1 USE_CUDA)
559+
message(STATUS "Building torchcodec with nvJPEG GPU JPEG decoding support.")
560+
elseif(ENABLE_CUDA)
561+
message(STATUS "Not building torchcodec with nvJPEG support (disabled via TORCHCODEC_BUILD_NVJPEG/TORCHCODEC_BUILD_IMAGE): decode_jpeg(device='cuda') will raise at runtime.")
565562
endif()
566563

567564
if(want_jpeg)

0 commit comments

Comments
 (0)