-
Notifications
You must be signed in to change notification settings - Fork 154
DRAFT: CLI: Add "tar.gz" packaging support and exercise with Holoscan GStreamer #1604
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
7f2c9b9
fded9c7
d7538f6
eaeb342
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| # holohub_configure_tgz(NAME <name> VERSION <version> | ||
| # [EXPORT_NAME <export>] | ||
| # [COMPONENTS <comp> ...]) | ||
| # | ||
| # Generates a CPack TGZ configuration file at | ||
| # ${CMAKE_BINARY_DIR}/pkg/CPackConfig-<name>-TGZ.cmake | ||
| # | ||
| # The resulting tarball follows the KitMaker multi-variant naming convention: | ||
| # <name_underscored>-<os>-<arch>-<version>.tar.gz | ||
| # with archive root <name_underscored>/ and library variant subdirectory | ||
| # lib/<cuda_major>/ (e.g. lib/13/) per the multi-variant layout. | ||
| # | ||
| # EXPORT_NAME: when provided, generates and installs cmake config/version files | ||
| # for the named export target, mirroring holohub_configure_deb behaviour. | ||
| # | ||
| # COMPONENTS: when provided, only those cmake install components (plus the | ||
| # cmake export component, if EXPORT_NAME is set) are included in the archive. | ||
| # When omitted, CMAKE_INSTALL_DEFAULT_COMPONENT_NAME is used instead. | ||
| function(holohub_configure_tgz) | ||
| set(requiredArgs NAME VERSION) | ||
| set(oneValueArgs NAME VERSION EXPORT_NAME) | ||
| set(multiValueArgs COMPONENTS) | ||
| cmake_parse_arguments(ARG "" "${oneValueArgs}" "${multiValueArgs}" ${ARGV}) | ||
|
|
||
| # KitMaker multi-variant layout requires libraries under lib/<cuda_major>/. | ||
| # Override CMAKE_INSTALL_LIBDIR in the cache so operator install() rules — | ||
| # processed after modules in HoloHub's build order — use the versioned path. | ||
| # Only active when the CLI sets HOLOHUB_PKG_TGZ=ON (i.e. --pkg-generator TGZ); | ||
| # all other builds (normal installs, DEB, wheel) keep the default lib/ path. | ||
| if(HOLOHUB_PKG_TGZ) | ||
| find_package(CUDAToolkit QUIET) | ||
| if(CUDAToolkit_FOUND) | ||
| set(CMAKE_INSTALL_LIBDIR "lib/${CUDAToolkit_VERSION_MAJOR}" | ||
| CACHE STRING "Library install directory (KitMaker multi-variant layout)" FORCE) | ||
| endif() | ||
| endif() | ||
|
|
||
| foreach(arg ${requiredArgs}) | ||
| if(NOT ARG_${arg}) | ||
| list(APPEND _missing ${arg}) | ||
| endif() | ||
| endforeach() | ||
| if(_missing) | ||
| message(FATAL_ERROR "holohub_configure_tgz: missing required arguments: ${_missing}") | ||
| endif() | ||
|
|
||
| if(ARG_EXPORT_NAME) | ||
| set(config_install_dir "lib/cmake/${ARG_NAME}") | ||
| set(export_component ${ARG_NAME}-cmake) | ||
| install( | ||
| EXPORT ${ARG_EXPORT_NAME} | ||
| DESTINATION ${config_install_dir} | ||
| NAMESPACE holoscan:: | ||
| COMPONENT ${export_component} | ||
| ) | ||
| include(CMakePackageConfigHelpers) | ||
| configure_package_config_file("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Config.cmake.in" | ||
| "${CMAKE_CURRENT_BINARY_DIR}/${ARG_NAME}Config.cmake" | ||
| INSTALL_DESTINATION ${config_install_dir} | ||
| NO_SET_AND_CHECK_MACRO | ||
| NO_CHECK_REQUIRED_COMPONENTS_MACRO | ||
| ) | ||
| write_basic_package_version_file( | ||
| "${CMAKE_CURRENT_BINARY_DIR}/${ARG_NAME}ConfigVersion.cmake" | ||
| VERSION "${ARG_VERSION}" | ||
| COMPATIBILITY AnyNewerVersion | ||
| ) | ||
| install(FILES | ||
| ${CMAKE_CURRENT_BINARY_DIR}/${ARG_NAME}Config.cmake | ||
| ${CMAKE_CURRENT_BINARY_DIR}/${ARG_NAME}ConfigVersion.cmake | ||
| DESTINATION ${config_install_dir} | ||
| COMPONENT ${export_component} | ||
| ) | ||
| endif() | ||
|
Comment on lines
+68
to
+89
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When |
||
|
|
||
| if(ARG_COMPONENTS) | ||
| set(_components "${ARG_COMPONENTS}") | ||
| else() | ||
| # Fall back to the cmake default component name. The caller is responsible | ||
| # for setting CMAKE_INSTALL_DEFAULT_COMPONENT_NAME before any install() | ||
| # rules so that unqualified installs land in the intended component. | ||
| set(_components "${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}") | ||
| endif() | ||
| if(ARG_EXPORT_NAME) | ||
| list(APPEND _components "${export_component}") | ||
| endif() | ||
|
|
||
| # Filter to only the desired components by enumerating them in | ||
| # CPACK_INSTALL_CMAKE_PROJECTS. CPack.cmake only sets this variable when it | ||
| # is unset, so our value is preserved through include(CPack). This approach | ||
| # avoids CPACK_ARCHIVE_COMPONENT_INSTALL, which strips the root directory | ||
| # from the archive when used with the TGZ generator. | ||
| set(_install_projects "") | ||
| foreach(_comp IN LISTS _components) | ||
| list(APPEND _install_projects | ||
| "${CMAKE_BINARY_DIR}" "${PROJECT_NAME}" "${_comp}" "/") | ||
| endforeach() | ||
| set(CPACK_INSTALL_CMAKE_PROJECTS "${_install_projects}") | ||
|
|
||
| # KitMaker requires underscores in the component name (no hyphens). | ||
| string(REPLACE "-" "_" _name_us "${ARG_NAME}") | ||
|
|
||
| # KitMaker requires lowercase OS token. | ||
| string(TOLOWER "${CMAKE_SYSTEM_NAME}" _os) | ||
|
|
||
| # Arch token comes from CMAKE_SYSTEM_PROCESSOR (x86_64, aarch64, sbsa, etc.). | ||
| set(_arch "${CMAKE_SYSTEM_PROCESSOR}") | ||
|
|
||
| # KitMaker naming: <name>-<os>-<arch>-<version> | ||
| set(CPACK_PACKAGE_FILE_NAME "${_name_us}-${_os}-${_arch}-${ARG_VERSION}") | ||
|
|
||
| # The archive root directory is the component name alone (KitMaker multi-variant | ||
| # convention). Inject it as the install prefix so files land at | ||
| # <component_name>/lib/..., <component_name>/include/..., etc. | ||
| # CPACK_INCLUDE_TOPLEVEL_DIRECTORY is disabled so CPack does not also prepend | ||
| # the full package-file-name stem, which would double-nest the root directory. | ||
| set(CPACK_PACKAGING_INSTALL_PREFIX "/${_name_us}") | ||
| set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF) | ||
|
|
||
| set(CPACK_GENERATOR "TGZ") | ||
| set(CPACK_STRIP_FILES TRUE) | ||
|
|
||
| set(CPACK_OUTPUT_CONFIG_FILE | ||
| "${CMAKE_BINARY_DIR}/pkg/CPackConfig-${ARG_NAME}-TGZ.cmake") | ||
| set(CPACK_SOURCE_OUTPUT_CONFIG_FILE | ||
| "${CMAKE_BINARY_DIR}/pkg/CPackSourceConfig-${ARG_NAME}-TGZ.cmake") | ||
|
|
||
| include(CPack) | ||
| endfunction() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -483,7 +483,7 @@ def _create_parser(self) -> argparse.ArgumentParser: | |
| type=str, | ||
| default="DEB", | ||
| dest="pkg_generator", | ||
| help="Comma-separated package generators: DEB, WHEEL (default: DEB)", | ||
| help="Comma-separated package generators: DEB, TGZ, WHEEL (default: DEB)", | ||
| ) | ||
| package.add_argument("--language", choices=["cpp", "python"], default=None) | ||
| package.add_argument("--verbose", action="store_true") | ||
|
|
@@ -2284,6 +2284,8 @@ def handle_package(self, args: argparse.Namespace) -> None: | |
| f"-DMODULE_{pkg_slug}=ON", | ||
| f"-DPKG_{pkg_slug}=ON", | ||
| ] | ||
| if "TGZ" in cpack_generators: | ||
| cmake_args.append("-DHOLOHUB_PKG_TGZ=ON") | ||
|
Comment on lines
+2287
to
+2288
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Comment on lines
+2287
to
+2288
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Split TGZ and non-TGZ configure paths to avoid mutating DEB layout Line 2287 enables Suggested fix direction- if "TGZ" in cpack_generators:
- cmake_args.append("-DHOLOHUB_PKG_TGZ=ON")
- holohub_cli_util.run_command(cmake_args, ...)
- holohub_cli_util.run_command(build_cmd, ...)
- # then cpack for all generators
+ # configure/build per generator class to isolate install layout
+ # (e.g., one build dir with HOLOHUB_PKG_TGZ=ON for TGZ, another without it for DEB/RPM/ZIP)
+ # then run cpack against each generator’s corresponding config set🤖 Prompt for AI Agents |
||
| if shutil.which("ninja"): | ||
| cmake_args.extend(["-G", "Ninja"]) | ||
| holohub_cli_util.run_command(cmake_args, dry_run=dryrun, env=build_env) | ||
|
|
@@ -2300,18 +2302,51 @@ def handle_package(self, args: argparse.Namespace) -> None: | |
| holohub_cli_util.run_command(build_cmd, dry_run=dryrun, env=build_env) | ||
|
|
||
| pkg_config_dir = build_dir / "pkg" | ||
| cpack_configs = ( | ||
| all_cpack_configs = ( | ||
| list(pkg_config_dir.glob("CPackConfig-*.cmake")) | ||
| if pkg_config_dir.exists() | ||
| else [] | ||
| ) | ||
| if not cpack_configs and dryrun: | ||
| if not all_cpack_configs and dryrun: | ||
| bare = project_name.replace("_", "-") | ||
| if bare.startswith("holoscan-"): | ||
| bare = bare[len("holoscan-") :] | ||
| cpack_configs = [pkg_config_dir / f"CPackConfig-holoscan-{bare}.cmake"] | ||
| for cpack_config in cpack_configs: | ||
| for gen in cpack_generators: | ||
| base_name = f"CPackConfig-holoscan-{bare}" | ||
| all_cpack_configs = [pkg_config_dir / f"{base_name}.cmake"] | ||
| # Also synthesize generator-specific configs so dry-run routing matches reality. | ||
| all_cpack_configs += [ | ||
| pkg_config_dir / f"{base_name}-{g}.cmake" for g in cpack_generators | ||
| ] | ||
| elif not all_cpack_configs: | ||
| holohub_cli_util.fatal( | ||
| f"No CPack config files were generated in {pkg_config_dir}. " | ||
| "Check module packaging configuration." | ||
| ) | ||
|
|
||
| # Separate generator-specific configs (e.g. CPackConfig-*-TGZ.cmake) | ||
| # from the base config so each generator uses the right one. | ||
| _KNOWN_GEN_SUFFIXES = ("TGZ", "DEB", "RPM", "ZIP") | ||
| gen_specific_configs: dict = {} | ||
| base_configs = [] | ||
| for c in all_cpack_configs: | ||
| stem_upper = c.stem.upper() | ||
| matched = next( | ||
| (g for g in _KNOWN_GEN_SUFFIXES if stem_upper.endswith(f"-{g}")), None | ||
| ) | ||
| if matched: | ||
| gen_specific_configs.setdefault(matched, []).append(c) | ||
| else: | ||
| base_configs.append(c) | ||
|
|
||
| for gen in cpack_generators: | ||
| configs_for_gen = gen_specific_configs.get(gen) or base_configs | ||
| if not configs_for_gen: | ||
| available = ", ".join(sorted(gen_specific_configs.keys())) or "none" | ||
| holohub_cli_util.fatal( | ||
| f"No CPack config found for generator '{gen}' in {pkg_config_dir}. " | ||
| f"Available generator-specific configs: {available}." | ||
| ) | ||
| for cpack_config in configs_for_gen: | ||
| holohub_cli_util.run_command( | ||
| ["cpack", "--config", str(cpack_config), "-G", gen], | ||
| dry_run=dryrun, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
CMAKE_INSTALL_LIBDIRcache override withFORCEexecutes unconditionally (whenHOLOHUB_PKG_TGZis set) before the required-argument check that follows. If a caller omitsNAMEorVERSION, the global cache is already mutated beforemessage(FATAL_ERROR)fires. While FATAL_ERROR prevents the build from proceeding, a partially modified cache can cause surprising behavior on the next reconfigure attempt. Consider moving argument validation before any side-effecting cache writes.