From 8100665d1d6d07804a64900d9fd59fe8b959894f Mon Sep 17 00:00:00 2001 From: "T.J. Alumbaugh" Date: Sat, 19 Sep 2026 21:47:09 +0000 Subject: [PATCH 1/3] Ship libtensilelite-host.so in its own tensilelite-host package libtensilelite-host.so was installed into hipblaslt's runtime component, so the only way for hipSPARSELt to obtain it at run time is to depend on the whole hipblaslt package. Measured on a 7.0.2 drop build that package is 1600.6 MB, of which 466.5 MB is Tensile kernel data hipSPARSELt never uses, to supply one 6.5 MB shared library. Move the LIBRARY/RUNTIME artefacts of tensilelite-host into a new "tensilelite" CPack component, named tensilelite-host via LIBRARY_NAME + PACKAGE_NAME. The static archive and the public headers stay in devel: they are build-time only and hipsparselt-devel already depends on hipblaslt-devel. The component is declared only when tensilelite-host is actually a shared library. The check reads the target TYPE property rather than BUILD_SHARED_LIBS, because that variable is assigned later in this file (~line 805) and is therefore not reliable at the packaging scope. Refs AIHPBLAS-4434, AIHPBLAS-3522. Co-Authored-By: Claude --- projects/hipblaslt/CMakeLists.txt | 19 +++++++++++++++++++ projects/hipblaslt/tasks.py | 13 +++++++++---- projects/hipblaslt/tensilelite/CMakeLists.txt | 11 +++++++++-- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/projects/hipblaslt/CMakeLists.txt b/projects/hipblaslt/CMakeLists.txt index cd93a106ce0a..c69e1d516b8b 100644 --- a/projects/hipblaslt/CMakeLists.txt +++ b/projects/hipblaslt/CMakeLists.txt @@ -899,6 +899,25 @@ if(HIPBLASLT_ENABLE_CLIENT AND HIPBLASLT_ENABLE_SAMPLES) rocm_package_setup_client_component(samples) endif() +# libtensilelite-host.so ships as its own package (tensilelite-host) instead of +# inside hipblaslt's runtime component, so hipSPARSELt can depend on the one +# ~6.5 MB shared library without pulling hipblaslt's ~1.6 GB of Tensile kernel +# binaries. See AIHPBLAS-4434. +# +# Guard on the target TYPE rather than BUILD_SHARED_LIBS: that variable is not +# reliably set at this scope (it is assigned further down, near line 805), so +# testing it here would silently skip the component in a shared build. +if(TARGET tensilelite-host) + get_target_property(_tensilelite_host_type tensilelite-host TYPE) + if(_tensilelite_host_type STREQUAL "SHARED_LIBRARY") + rocm_package_setup_component(tensilelite + LIBRARY_NAME tensilelite + PACKAGE_NAME host + ) + endif() + unset(_tensilelite_host_type) +endif() + if(ROCM_LIBS_SUPERBUILD OR NOT HIPBLASLT_IS_SUBPROJECT) set(HIPBLASLT_CONFIG_DIR "\${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" CACHE PATH "Path placed into ldconfig file") rocm_create_package( diff --git a/projects/hipblaslt/tasks.py b/projects/hipblaslt/tasks.py index c0ab95ba8029..7b86205b4000 100644 --- a/projects/hipblaslt/tasks.py +++ b/projects/hipblaslt/tasks.py @@ -863,14 +863,19 @@ def _normalized(p: str) -> str: if install_pkg: with c.cd(str(build_subdir)): c.run("make package") + # hipBLASLt does not only produce hipblaslt-* packages: libtensilelite-host.so + # ships as tensilelite-host (see CMakeLists.txt, rocm_package_setup_component). + # Globbing hipblaslt-* alone leaves the .so uninstalled, and a downstream + # find_package(hipblaslt) then fails on the imported roc::tensilelite-host + # target pointing at a file that was never installed. if distro == "ubuntu": - _elevate(c, f"dpkg -i {build_subdir}/hipblaslt[-_]*.deb") + _elevate(c, f"dpkg -i {build_subdir}/hipblaslt[-_]*.deb {build_subdir}/tensilelite-host[-_]*.deb") elif distro in ("centos", "rhel", "almalinux"): - _elevate(c, f"rpm --nodeps -U {build_subdir}/hipblaslt-*.rpm") + _elevate(c, f"rpm --nodeps -U {build_subdir}/hipblaslt-*.rpm {build_subdir}/tensilelite-host-*.rpm") elif distro == "fedora": - _elevate(c, f"dnf install {build_subdir}/hipblaslt-*.rpm") + _elevate(c, f"dnf install {build_subdir}/hipblaslt-*.rpm {build_subdir}/tensilelite-host-*.rpm") elif distro in ("sles", "opensuse-leap"): - _elevate(c, f"zypper -n --no-gpg-checks install {build_subdir}/hipblaslt-*.rpm") + _elevate(c, f"zypper -n --no-gpg-checks install {build_subdir}/hipblaslt-*.rpm {build_subdir}/tensilelite-host-*.rpm") # --------------------------------------------------------------------------- diff --git a/projects/hipblaslt/tensilelite/CMakeLists.txt b/projects/hipblaslt/tensilelite/CMakeLists.txt index a061589af760..f1ae40b65625 100644 --- a/projects/hipblaslt/tensilelite/CMakeLists.txt +++ b/projects/hipblaslt/tensilelite/CMakeLists.txt @@ -192,10 +192,17 @@ if(TENSILELITE_ENABLE_HOST) add_subdirectory(src) add_subdirectory(include) + # The shared library ships in its own "tensilelite" component (package + # tensilelite-host) rather than hipblaslt's runtime component. hipSPARSELt + # needs this one ~6.5 MB .so; bundling it in hipblaslt's runtime package + # would force every hipSPARSELt install to pull ~1.6 GB of Tensile kernel + # binaries it does not use. See AIHPBLAS-4434. + # The static archive and headers stay in devel: they are build-time only, + # and hipsparselt-devel already depends on hipblaslt-devel. install(TARGETS tensilelite-host EXPORT hipblaslt-targets - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT runtime - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT runtime + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT tensilelite + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT tensilelite ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT devel FILE_SET tensilelite_public_headers DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" COMPONENT devel From 91ba6b0fa1fcf058f095f7fed2d85e00ba34fa54 Mon Sep 17 00:00:00 2001 From: "T.J. Alumbaugh" Date: Mon, 21 Sep 2026 15:10:06 +0000 Subject: [PATCH 2/3] Declare hipblaslt's dependency on the tensilelite-host package libhipblaslt.so carries DT_NEEDED on libtensilelite-host.so.1, so the hipblaslt runtime package must say so now that the library ships separately. Three things are needed together; splitting them leaves the package in a state that is worse than before. 1. Publish the soname. rocm-cmake's packaging defaults set CPACK_RPM_PACKAGE_AUTOREQPROV to Off for every ROCm library, so rpmbuild's ELF scanning never runs and nothing Provides or Requires a soname today. AIHPBLAS-4434 assumed re-enabling it would be a repo-wide change; CPack in fact supports per-component overrides (CPackRPM.cmake:1098-1106 falls back from CPACK_RPM__PACKAGE_ to the global tag), so it can be scoped to the tensilelite component alone. tensilelite-host then Provides libtensilelite-host.so.1()(64bit), derived from the binary rather than hand-written, so the capability tracks SOVERSION automatically. 2. Pin the version. hipblaslt, hipsparselt and tensilelite-host are intended to move together within one ROCm release, so the dependency is an exact version rather than the >= floor used for hipblas-common. CPACK_PACKAGE_VERSION is computed inside rocm_create_package (ROCMCreatePackage.cmake:281,296) from PROJECT_VERSION_* plus ROCM_LIBPATCH_VERSION, and rocm_package_add_*_dependencies must be called before rocm_create_package, so the same value is recomputed here. 3. Preserve the global dependency list. CPack uses CPACK_RPM__PACKAGE_REQUIRES *instead of* the global CPACK_RPM_PACKAGE_REQUIRES once the component variable exists, so adding any runtime-scoped dependency silently drops the global ones. Without this the hipblaslt package loses "roctracer >= 1.0.0" and "rocm-core"; measured on a gfx942 build its runtime Requires became just /bin/sh plus the soname. rocm-core is added explicitly because rocm_package_add_rocm_core_dependency appends it from inside rocm_create_package, after this point. Resulting hipblaslt runtime Requires: libtensilelite-host.so.1()(64bit) rocm-core roctracer >= 1.0.0 tensilelite-host = 1.5.0.70002 The pin is on VERSION, not VERSION-RELEASE: two builds from different commits share a VERSION and differ only in RELEASE, so this gives release lockstep, not ABI safety. Only SOVERSION discipline (AIHPBLAS-3522 decision D7) gives the latter. Refs AIHPBLAS-4434. Co-Authored-By: Claude --- projects/hipblaslt/CMakeLists.txt | 82 +++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/projects/hipblaslt/CMakeLists.txt b/projects/hipblaslt/CMakeLists.txt index c69e1d516b8b..f02a8dd36631 100644 --- a/projects/hipblaslt/CMakeLists.txt +++ b/projects/hipblaslt/CMakeLists.txt @@ -914,6 +914,88 @@ if(TARGET tensilelite-host) LIBRARY_NAME tensilelite PACKAGE_NAME host ) + + # rocm-cmake's packaging defaults set CPACK_RPM_PACKAGE_AUTOREQPROV to + # Off for every ROCm library, so no package currently Provides or + # Requires a soname. Re-enable rpmbuild's ELF scanning for this one + # component: tensilelite-host then Provides + # libtensilelite-host.so.1()(64bit), derived from the binary rather + # than hand-written, so the capability tracks SOVERSION automatically. + # This is scoped to the component and does not change any other + # package's dependency surface. + set(CPACK_RPM_TENSILELITE_PACKAGE_AUTOREQPROV "ON") + + # CPack uses CPACK_RPM__PACKAGE_REQUIRES *instead of* the + # global CPACK_RPM_PACKAGE_REQUIRES when the component-scoped variable + # is defined (CPackRPM.cmake:1098-1106). Defining a runtime-scoped + # dependency therefore drops every global one -- hipblaslt's runtime + # package silently lost "roctracer >= 1.0.0" and "rocm-core". + # + # Carry the global list into the component before adding anything, and + # add rocm-core explicitly because rocm_package_add_rocm_core_dependency + # appends it to the global list from inside rocm_create_package, which + # runs after this point. + if(CPACK_RPM_PACKAGE_REQUIRES) + rocm_package_add_rpm_dependencies(COMPONENT runtime + DEPENDS "${CPACK_RPM_PACKAGE_REQUIRES}") + endif() + if(ROCM_DEP_ROCMCORE) + if(ENABLE_ASAN_PACKAGING) + rocm_package_add_rpm_dependencies(COMPONENT runtime DEPENDS "rocm-core-asan") + else() + rocm_package_add_rpm_dependencies(COMPONENT runtime DEPENDS "rocm-core") + endif() + endif() + + # hipBLASLt's own libhipblaslt.so carries DT_NEEDED on this soname, so + # the runtime package must require it. Stated as the soname capability + # rather than a package name: the dynamic linker enforces the same + # string, and a SOVERSION bump updates both sides together. + rocm_package_add_rpm_dependencies(COMPONENT runtime + DEPENDS "libtensilelite-host.so.1()(64bit)") + + # Lockstep pin. The soname capability above is the correctness + # mechanism; this is the release policy on top of it: hipblaslt, + # hipsparselt and tensilelite-host are intended to move together + # within one ROCm release, so the dependency is an exact version + # rather than a floor. + # + # CPACK_PACKAGE_VERSION is only computed inside rocm_create_package + # (ROCMCreatePackage.cmake:281 and :296), which runs after this point, + # so recompute the same value from the same inputs. + # + # Note this pins VERSION only, not VERSION-RELEASE. Two builds from + # different commits share a VERSION and differ only in RELEASE (the + # git tag from rocm_get_git_commit_tag), so this does not detect + # commit-level ABI drift. Only a SOVERSION bump does -- see D7. + rocm_get_patch_version(_tensilelite_rocm_patch) + set(_tensilelite_pkg_version + "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") + if(_tensilelite_rocm_patch) + set(_tensilelite_pkg_version + "${_tensilelite_pkg_version}.${_tensilelite_rocm_patch}") + endif() + + # Same component-shadows-global rule applies on the Debian side. + if(CPACK_DEBIAN_PACKAGE_DEPENDS) + rocm_package_add_deb_dependencies(COMPONENT runtime + DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}") + endif() + if(ROCM_DEP_ROCMCORE) + if(ENABLE_ASAN_PACKAGING) + rocm_package_add_deb_dependencies(COMPONENT runtime DEPENDS "rocm-core-asan") + else() + rocm_package_add_deb_dependencies(COMPONENT runtime DEPENDS "rocm-core") + endif() + endif() + + rocm_package_add_rpm_dependencies(COMPONENT runtime + DEPENDS "tensilelite-host = ${_tensilelite_pkg_version}") + rocm_package_add_deb_dependencies(COMPONENT runtime + DEPENDS "tensilelite-host (= ${_tensilelite_pkg_version})") + + unset(_tensilelite_rocm_patch) + unset(_tensilelite_pkg_version) endif() unset(_tensilelite_host_type) endif() From f8652d7c272c3bd0bdb46db272fbcc28c0ca5c23 Mon Sep 17 00:00:00 2001 From: David Dixon <165835255+davidd-amd@users.noreply.github.com> Date: Wed, 30 Sep 2026 07:56:26 -0600 Subject: [PATCH 3/3] build(hipblaslt): remove tensilelite-host version constraint (#12600) Drop the tensilelite-host version pin; mark devel placement as interim hipblaslt's runtime package pinned tensilelite-host to hipBLASLt's exact package version. That records "tensilelite version equals hipBLASLt version" in package metadata, which a standalone tensilelite package would have to undo. It also rebuilt CPACK_PACKAGE_VERSION by hand because the real value is computed later inside rocm_create_package, so a change to rocm-cmake's formula would break the pin silently. Remove the pin and the version recomputation. RPM keeps the soname dependency libtensilelite-host.so.1()(64bit). DEB gets no soname dependency, so it now depends on tensilelite-host with no version. Reword the install comment so the archive, headers and imported target living in hipblaslt-devel read as interim, not as the intended layout. Fix the TYPE-guard comment: BUILD_SHARED_LIBS at that point holds HIPBLASLT_BUILD_SHARED_LIBS, which is independent of TENSILELITE_BUILD_SHARED_LIBS. Co-Authored-By: Claude Opus 5.5 Co-authored-by: Claude Opus 5.5 --- projects/hipblaslt/CMakeLists.txt | 41 +++++-------------- projects/hipblaslt/tensilelite/CMakeLists.txt | 6 ++- 2 files changed, 14 insertions(+), 33 deletions(-) diff --git a/projects/hipblaslt/CMakeLists.txt b/projects/hipblaslt/CMakeLists.txt index f02a8dd36631..6921c063851b 100644 --- a/projects/hipblaslt/CMakeLists.txt +++ b/projects/hipblaslt/CMakeLists.txt @@ -904,9 +904,11 @@ endif() # ~6.5 MB shared library without pulling hipblaslt's ~1.6 GB of Tensile kernel # binaries. See AIHPBLAS-4434. # -# Guard on the target TYPE rather than BUILD_SHARED_LIBS: that variable is not -# reliably set at this scope (it is assigned further down, near line 805), so -# testing it here would silently skip the component in a shared build. +# Guard on the target TYPE rather than BUILD_SHARED_LIBS: at this scope +# BUILD_SHARED_LIBS holds HIPBLASLT_BUILD_SHARED_LIBS, which describes +# libhipblaslt, not tensilelite-host. The two are set independently +# (TENSILELITE_BUILD_SHARED_LIBS vs HIPBLASLT_BUILD_SHARED_LIBS), so only the +# target's own TYPE says whether there is a .so to package. if(TARGET tensilelite-host) get_target_property(_tensilelite_host_type tensilelite-host TYPE) if(_tensilelite_host_type STREQUAL "SHARED_LIBRARY") @@ -954,28 +956,6 @@ if(TARGET tensilelite-host) rocm_package_add_rpm_dependencies(COMPONENT runtime DEPENDS "libtensilelite-host.so.1()(64bit)") - # Lockstep pin. The soname capability above is the correctness - # mechanism; this is the release policy on top of it: hipblaslt, - # hipsparselt and tensilelite-host are intended to move together - # within one ROCm release, so the dependency is an exact version - # rather than a floor. - # - # CPACK_PACKAGE_VERSION is only computed inside rocm_create_package - # (ROCMCreatePackage.cmake:281 and :296), which runs after this point, - # so recompute the same value from the same inputs. - # - # Note this pins VERSION only, not VERSION-RELEASE. Two builds from - # different commits share a VERSION and differ only in RELEASE (the - # git tag from rocm_get_git_commit_tag), so this does not detect - # commit-level ABI drift. Only a SOVERSION bump does -- see D7. - rocm_get_patch_version(_tensilelite_rocm_patch) - set(_tensilelite_pkg_version - "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") - if(_tensilelite_rocm_patch) - set(_tensilelite_pkg_version - "${_tensilelite_pkg_version}.${_tensilelite_rocm_patch}") - endif() - # Same component-shadows-global rule applies on the Debian side. if(CPACK_DEBIAN_PACKAGE_DEPENDS) rocm_package_add_deb_dependencies(COMPONENT runtime @@ -989,13 +969,12 @@ if(TARGET tensilelite-host) endif() endif() - rocm_package_add_rpm_dependencies(COMPONENT runtime - DEPENDS "tensilelite-host = ${_tensilelite_pkg_version}") + # Debian gets no soname dependency here, so name the package. No + # version constraint: tensilelite-host is versioned with hipBLASLt only + # until it has a version of its own, and an exact pin would record that + # coupling in package metadata. The SOVERSION is the ABI contract. rocm_package_add_deb_dependencies(COMPONENT runtime - DEPENDS "tensilelite-host (= ${_tensilelite_pkg_version})") - - unset(_tensilelite_rocm_patch) - unset(_tensilelite_pkg_version) + DEPENDS "tensilelite-host") endif() unset(_tensilelite_host_type) endif() diff --git a/projects/hipblaslt/tensilelite/CMakeLists.txt b/projects/hipblaslt/tensilelite/CMakeLists.txt index f1ae40b65625..bf758a8b8809 100644 --- a/projects/hipblaslt/tensilelite/CMakeLists.txt +++ b/projects/hipblaslt/tensilelite/CMakeLists.txt @@ -197,8 +197,10 @@ if(TENSILELITE_ENABLE_HOST) # needs this one ~6.5 MB .so; bundling it in hipblaslt's runtime package # would force every hipSPARSELt install to pull ~1.6 GB of Tensile kernel # binaries it does not use. See AIHPBLAS-4434. - # The static archive and headers stay in devel: they are build-time only, - # and hipsparselt-devel already depends on hipblaslt-devel. + # Interim: the static archive, headers and the roc::tensilelite-host + # imported target still ship through hipblaslt-devel and the + # hipblaslt-targets export set. A standalone tensilelite package moves + # them to its own export set, config file and devel package. install(TARGETS tensilelite-host EXPORT hipblaslt-targets RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT tensilelite