diff --git a/.gitignore b/.gitignore index 83fa3abba..c9779a32d 100644 --- a/.gitignore +++ b/.gitignore @@ -39,4 +39,6 @@ session_manager.mu # See maya_tools.mu.in maya_tools.mu # See rvnuke_mode.mu.in -rvnuke_mode.mu \ No newline at end of file +rvnuke_mode.mu +# see generate_about_rv.py +about_rv.cpp \ No newline at end of file diff --git a/cmake/dependencies/glew.cmake b/cmake/dependencies/glew.cmake index 97fef1f2a..32ea4b134 100644 --- a/cmake/dependencies/glew.cmake +++ b/cmake/dependencies/glew.cmake @@ -52,19 +52,12 @@ EXTERNALPROJECT_ADD( URL_MD5 ${_download_hash} DOWNLOAD_NAME ${_target}_${_version}.zip DOWNLOAD_DIR ${RV_DEPS_DOWNLOAD_DIR} - # Patch to fix the build issue with OpenGL-Registry - # Pinning the OpenGL-Registry version to a specific commit - # https://github.com/nigels-com/glew/issues/449 + # Patch to fix the build issue with OpenGL-Registry Pinning the OpenGL-Registry version to a specific commit https://github.com/nigels-com/glew/issues/449 # Also clone the required glfixes repository - PATCH_COMMAND - cd auto && - git clone https://github.com/KhronosGroup/OpenGL-Registry.git || true && - cd OpenGL-Registry && - git checkout a77f5b6ffd0b0b74904f755ae977fa278eac4e95 && - cd .. && - git clone --depth=1 --branch glew https://github.com/nigels-com/glfixes glfixes || true && - touch OpenGL-Registry/.dummy && - cd .. + PATCH_COMMAND + cd auto && git clone https://github.com/KhronosGroup/OpenGL-Registry.git || true && cd OpenGL-Registry && git checkout + a77f5b6ffd0b0b74904f755ae977fa278eac4e95 && cd .. && git clone --depth=1 --branch glew https://github.com/nigels-com/glfixes glfixes || true && touch + OpenGL-Registry/.dummy && cd .. CONFIGURE_COMMAND cd auto && ${_make_command} && cd .. && ${_make_command} BUILD_COMMAND ${_make_command} -j${_cpu_count} GLEW_DEST=${_install_dir} INSTALL_COMMAND ${_make_command} install LIBDIR=${_lib_dir} GLEW_DEST=${_install_dir} diff --git a/cmake/dependencies/imgui.cmake b/cmake/dependencies/imgui.cmake index fd55d2777..a97fd8d20 100644 --- a/cmake/dependencies/imgui.cmake +++ b/cmake/dependencies/imgui.cmake @@ -42,7 +42,7 @@ ENDIF() IF(RV_TARGET_WINDOWS) SET(_libpath - ${_bin_dir}/${_libname} + ${_bin_dir}/${_libname} ) ELSE() SET(_libpath @@ -103,20 +103,19 @@ EXTERNALPROJECT_ADD( USES_TERMINAL_DOWNLOAD TRUE ) -SET(_qt_location - ${RV_DEPS_QT_LOCATION} +SET(_qt_location + ${RV_DEPS_QT_LOCATION} ) -SET(_find_qt_version - "Qt${RV_DEPS_QT_MAJOR}" +SET(_find_qt_version + "Qt${RV_DEPS_QT_MAJOR}" ) IF(NOT _qt_location) - SET(_qt_major - ${RV_DEPS_QT_MAJOR} + SET(_qt_major + ${RV_DEPS_QT_MAJOR} ) MESSAGE(FATAL_ERROR "Qt is not found in path \"${_qt_location}\". Please provide -DRV_DEPS_QT_LOCATION= to CMake.") ENDIF() - SET(_patch_command_for_imgui patch -p1 < ${CMAKE_CURRENT_SOURCE_DIR}/patch/imgui_cpp_h.patch ) @@ -133,8 +132,8 @@ EXTERNALPROJECT_ADD( ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/imgui/CMakeLists.txt ${CMAKE_BINARY_DIR}/${_target}/src/CMakeLists.txt && ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/${_target}/deps/implot ${CMAKE_BINARY_DIR}/${_target}/src/implot && ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/${_target}/deps/imgui-backend-qt/backends ${CMAKE_BINARY_DIR}/${_target}/src/backends && ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_BINARY_DIR}/${_target}/deps/imgui-node-editor ${CMAKE_BINARY_DIR}/${_target}/src/imgui-node-editor - && ${_patch_command_for_imgui_backend_qt} && ${_patch_command_for_imgui} + ${CMAKE_BINARY_DIR}/${_target}/deps/imgui-node-editor ${CMAKE_BINARY_DIR}/${_target}/src/imgui-node-editor && ${_patch_command_for_imgui_backend_qt} && + ${_patch_command_for_imgui} CONFIGURE_COMMAND ${CMAKE_COMMAND} ${_configure_options} -DFIND_QT_VERSION=${_find_qt_version} -DCMAKE_PREFIX_PATH=${_qt_location}/lib/cmake BUILD_COMMAND ${_cmake_build_command} INSTALL_COMMAND ${_cmake_install_command} @@ -174,3 +173,9 @@ TARGET_INCLUDE_DIRECTORIES( ) LIST(APPEND RV_DEPS_LIST imgui::imgui) + +# Set version for about dialog +SET(RV_DEPS_IMGUI_VERSION + ${_version} + CACHE INTERNAL "" FORCE +) diff --git a/cmake/dependencies/python3.cmake b/cmake/dependencies/python3.cmake index f3cb2e3c1..3c04c2b08 100644 --- a/cmake/dependencies/python3.cmake +++ b/cmake/dependencies/python3.cmake @@ -13,34 +13,32 @@ SET(_opentimelineio_target ) SET(_pyside_target - "${RV_DEPS_PYSIDE_TARGET}" + "${RV_DEPS_PYSIDE_TARGET}" ) SET(_python3_version "${RV_DEPS_PYTHON_VERSION}" ) -string(REPLACE "." ";" _python_version_list "${_python3_version}") - -list(GET _python_version_list 0 PYTHON_VERSION_MAJOR) -list(GET _python_version_list 1 PYTHON_VERSION_MINOR) -list(GET _python_version_list 2 PYTHON_VERSION_PATCH) +STRING(REPLACE "." ";" _python_version_list "${_python3_version}") +LIST(GET _python_version_list 0 PYTHON_VERSION_MAJOR) +LIST(GET _python_version_list 1 PYTHON_VERSION_MINOR) +LIST(GET _python_version_list 2 PYTHON_VERSION_PATCH) SET(RV_DEPS_PYTHON_VERSION_SHORT "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}" ) -# This version is used for generating src/build/requirements.txt from requirements.txt.in template -# All platforms install OpenTimelineIO from git to ensure consistent source builds. +# This version is used for generating src/build/requirements.txt from requirements.txt.in template All platforms install OpenTimelineIO from git to ensure +# consistent source builds. SET(_opentimelineio_version "${RV_DEPS_OTIO_VERSION}" ) -SET(_pyside_version +SET(_pyside_version "${RV_DEPS_PYSIDE_VERSION}" ) -# Construct the full git URL for pip to use in requirements.txt -# Using this avoids @ symbol conflicts in CONFIGURE_FILE +# Construct the full git URL for pip to use in requirements.txt Using this avoids @ symbol conflicts in CONFIGURE_FILE SET(_opentimelineio_pip_url "git+https://github.com/AcademySoftwareFoundation/OpenTimelineIO@v${_opentimelineio_version}#egg=OpenTimelineIO" ) @@ -49,7 +47,7 @@ SET(_python3_download_url "https://github.com/python/cpython/archive/refs/tags/v${_python3_version}.zip" ) -SET(_python3_download_hash +SET(_python3_download_hash "${RV_DEPS_PYTHON_DOWNLOAD_HASH}" ) @@ -62,11 +60,11 @@ SET(_opentimelineio_git_tag ) SET(_pyside_archive_url - "${RV_DEPS_PYSIDE_ARCHIVE_URL}" + "${RV_DEPS_PYSIDE_ARCHIVE_URL}" ) -SET(_pyside_download_hash - "${RV_DEPS_PYSIDE_DOWNLOAD_HASH}" +SET(_pyside_download_hash + "${RV_DEPS_PYSIDE_DOWNLOAD_HASH}" ) SET(_install_dir @@ -79,8 +77,8 @@ SET(_build_dir ${RV_DEPS_BASE_DIR}/${_python3_target}/build ) -# Note: OpenTimelineIO is now installed via requirements.txt from git URL for all platforms. -# This ensures consistent source builds across Windows, Mac, and Linux. +# Note: OpenTimelineIO is now installed via requirements.txt from git URL for all platforms. This ensures consistent source builds across Windows, Mac, and +# Linux. FETCHCONTENT_DECLARE( ${_pyside_target} @@ -109,7 +107,6 @@ LIST(APPEND _python3_make_command ${_build_dir}) LIST(APPEND _python3_make_command "--vfx_platform") LIST(APPEND _python3_make_command ${RV_VFX_CY_YEAR}) - IF(DEFINED RV_DEPS_OPENSSL_INSTALL_DIR) LIST(APPEND _python3_make_command "--openssl-dir") LIST(APPEND _python3_make_command ${RV_DEPS_OPENSSL_INSTALL_DIR}) @@ -260,11 +257,7 @@ SET(_requirements_output_file "${CMAKE_BINARY_DIR}/requirements.txt" ) -CONFIGURE_FILE( - ${_requirements_input_file} - ${_requirements_output_file} - @ONLY -) +CONFIGURE_FILE(${_requirements_input_file} ${_requirements_output_file} @ONLY) # OpenTimelineIO needs to be built from source with CMAKE_ARGS to ensure it uses # the correct custom-built Python libraries. This is required for both old and new @@ -298,8 +291,18 @@ IF(RV_TARGET_WINDOWS) patch -p1 < ${CMAKE_CURRENT_SOURCE_DIR}/patch/python-${RV_DEPS_PYTHON_VERSION}/python.${RV_DEPS_PYTHON_VERSION}.get_externals.bat.patch" ) - #TODO: Above patches are for Python 3.11.9, need to add other versions. - RV_VFX_SET_VARIABLE(_patch_command CY2023 "" CY2024 "${_patch_python_command}" CY2025 "${_patch_python_command}" CY2026 "") + # TODO: Above patches are for Python 3.11.9, need to add other versions. + RV_VFX_SET_VARIABLE( + _patch_command + CY2023 + "" + CY2024 + "${_patch_python_command}" + CY2025 + "${_patch_python_command}" + CY2026 + "" + ) # Split the command into a semi-colon separated list. SEPARATE_ARGUMENTS(_patch_command) STRING( @@ -339,10 +342,8 @@ IF(APPLE patch -p1 < ${CMAKE_CURRENT_SOURCE_DIR}/patch/pyopengl-accelerate.patch ) - # TODO: pyopengl is now at 3.1.10. - # Need to check if this is an improvement - # Still need the patch https://github.com/mcfletch/pyopengl/blob/master/accelerate/src/vbo.pyx - # https://github.com/mcfletch/pyopengl/compare/release-3.1.8...3.1.10 + # TODO: pyopengl is now at 3.1.10. Need to check if this is an improvement Still need the patch + # https://github.com/mcfletch/pyopengl/blob/master/accelerate/src/vbo.pyx https://github.com/mcfletch/pyopengl/compare/release-3.1.8...3.1.10 EXTERNALPROJECT_ADD( pyopengl_accelerate URL "https://github.com/mcfletch/pyopengl/archive/refs/tags/release-3.1.8.tar.gz" @@ -387,7 +388,8 @@ IF(RV_TARGET_WINDOWS POST_BUILD COMMENT "Copying Debug Python lib as a unversionned file for Debug" COMMAND cmake -E copy_if_different ${_python3_implib} ${_python_release_libpath} - COMMAND cmake -E copy_if_different ${_python3_implib} ${_python_release_in_bin_libpath} DEPENDS ${_python3_target} ${_requirements_output_file} ${_requirements_input_file} + COMMAND cmake -E copy_if_different ${_python3_implib} ${_python_release_in_bin_libpath} DEPENDS ${_python3_target} ${_requirements_output_file} + ${_requirements_input_file} ) ENDIF() diff --git a/src/lib/app/RvCommon/CMakeLists.txt b/src/lib/app/RvCommon/CMakeLists.txt index 1ba4ce232..d3362ce3e 100644 --- a/src/lib/app/RvCommon/CMakeLists.txt +++ b/src/lib/app/RvCommon/CMakeLists.txt @@ -191,11 +191,163 @@ FOREACH( LIST(APPEND _sources ${outfile}) ENDFOREACH() +# +# Generate about_rv.cpp with build information +# +SET(_about_rv_cpp + ${CMAKE_CURRENT_SOURCE_DIR}/${_target}/generated/about_rv.cpp +) + +# Get compiler name +IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + SET(_compiler_name + "GCC ${CMAKE_CXX_COMPILER_VERSION}" + ) +ELSEIF(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + IF(CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") + SET(_compiler_name + "Clang-cl ${CMAKE_CXX_COMPILER_VERSION}" + ) + ELSE() + SET(_compiler_name + "Clang ${CMAKE_CXX_COMPILER_VERSION}" + ) + ENDIF() +ELSEIF(MSVC) + SET(_compiler_name + "MSVC ${CMAKE_CXX_COMPILER_VERSION}" + ) +ELSE() + SET(_compiler_name + "${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}" + ) +ENDIF() + +# Get VFX platform +IF(RV_VFX_PLATFORM) + SET(_vfx_platform_str + ${RV_VFX_PLATFORM} + ) +ELSE() + SET(_vfx_platform_str + "N/A" + ) +ENDIF() + +# Get platform and arch +IF(RV_TARGET_DARWIN) + SET(_platform_name + "macOS" + ) +ELSEIF(RV_TARGET_LINUX) + SET(_platform_name + "Linux" + ) +ELSEIF(RV_TARGET_WINDOWS) + SET(_platform_name + "Windows" + ) +ELSE() + SET(_platform_name + ${CMAKE_SYSTEM_NAME} + ) +ENDIF() + +SET(_arch_name + ${CMAKE_SYSTEM_PROCESSOR} +) + +# Create a JSON-like string with versions (using semicolon as separator for CMake list) +SET(_versions_list + "Qt:${RV_DEPS_QT_VERSION}" + "CMake:${CMAKE_VERSION}" + "Python:${RV_DEPS_PYTHON3_VERSION}" + "PySide:${RV_DEPS_PYSIDE_VERSION}" + "Boost:${RV_DEPS_BOOST_VERSION}" + "Imath:${RV_DEPS_IMATH_VERSION}" + "OpenEXR:${RV_DEPS_OPENEXR_VERSION}" + "OpenImageIO:${RV_DEPS_OIIO_VERSION}" + "OpenColorIO:${RV_DEPS_OCIO_VERSION}" + "FFmpeg:${RV_DEPS_FFMPEG_VERSION}" + "OpenSSL:${RV_DEPS_OPENSSL_VERSION}" + "GLEW:${RV_DEPS_GLEW_VERSION_LIB}" + "spdlog:${RV_DEPS_SPDLOG_VERSION}" + "yaml-cpp:${RV_DEPS_YAML_CPP_VERSION}" + "zlib:${RV_DEPS_ZLIB_VERSION}" + "dav1d:${RV_DEPS_DAV1D_VERSION}" + "jpegturbo:${RV_DEPS_JPEGTURBO_VERSION}" + "png:${RV_DEPS_PNG_VERSION}" + "tiff:${RV_DEPS_TIFF_VERSION}" + "webp:${RV_DEPS_WEBP_VERSION}" + "openjpeg:${RV_DEPS_OPENJPEG_VERSION}" + "openjph:${RV_DEPS_OPENJPH_VERSION}" + "raw:${RV_DEPS_RAW_VERSION}" + "gc:${RV_DEPS_GC_VERSION}" + "aja:${RV_DEPS_AJA_VERSION}" + "bmd:${RV_DEPS_BMD_VERSION}" + "imgui:${RV_DEPS_IMGUI_VERSION}" + "numpy:$ENV{RV_DEPS_NUMPY_VERSION}" + "otio:${RV_DEPS_OTIO_VERSION}" + "expat:${RV_DEPS_EXPAT_VERSION}" + "nanobind:${RV_DEPS_NANOBIND_VERSION}" + "pcre2:${RV_DEPS_PCRE2_VERSION}" +) + +# Add commercial RV-specific SDK versions if they exist +IF(DEFINED RV_DEPS_PRORES_VERSION + AND RV_DEPS_PRORES_VERSION +) + LIST(APPEND _versions_list "prores:${RV_DEPS_PRORES_VERSION}") +ENDIF() +IF(DEFINED RV_DEPS_R3DSDK_VERSION + AND RV_DEPS_R3DSDK_VERSION +) + LIST(APPEND _versions_list "r3dsdk:${RV_DEPS_R3DSDK_VERSION}") +ENDIF() +IF(DEFINED RV_DEPS_ARRIRAW_VERSION + AND RV_DEPS_ARRIRAW_VERSION +) + LIST(APPEND _versions_list "arriraw:${RV_DEPS_ARRIRAW_VERSION}") +ENDIF() +IF(DEFINED RV_DEPS_X264_VERSION + AND RV_DEPS_X264_VERSION +) + LIST(APPEND _versions_list "x264:${RV_DEPS_X264_VERSION}") +ENDIF() +IF(DEFINED RV_DEPS_NDI_VERSION + AND RV_DEPS_NDI_VERSION +) + LIST(APPEND _versions_list "ndi:${RV_DEPS_NDI_VERSION}") +ENDIF() + +STRING(REPLACE ";" "," _versions_str "${_versions_list}") + +ADD_CUSTOM_COMMAND( + OUTPUT ${_about_rv_cpp} + COMMAND + python3 ${CMAKE_CURRENT_SOURCE_DIR}/generate_about_rv.py ${_about_rv_cpp} "${_compiler_name}" + "${_vfx_platform_str}" "${_platform_name}" "${_arch_name}" "${RV_UI_APPLICATION_NAME}" "${_versions_str}" "${RV_GIT_COMMIT_SHORT_HASH}" + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/generate_about_rv.py + COMMENT "Generating about_rv.cpp with build information" + VERBATIM +) + +# Create explicit target to ensure about_rv.cpp is generated before RvCommon builds +ADD_CUSTOM_TARGET( + generate_about_rv_cpp + DEPENDS ${_about_rv_cpp} +) + +LIST(APPEND _sources ${_about_rv_cpp}) + ADD_LIBRARY( ${_target} STATIC ${_sources} qrc/RvCommon.qrc ) +# Ensure about_rv.cpp is generated before building RvCommon +ADD_DEPENDENCIES(${_target} generate_about_rv_cpp) + # Need that with Qt6 since the code for this target does not support unicode correctly. IF(RV_TARGET_WINDOWS AND RV_VFX_PLATFORM STRGREATER_EQUAL CY2024 diff --git a/src/lib/app/RvCommon/RvApplication.cpp b/src/lib/app/RvCommon/RvApplication.cpp index 149333ead..4b7bc6da4 100644 --- a/src/lib/app/RvCommon/RvApplication.cpp +++ b/src/lib/app/RvCommon/RvApplication.cpp @@ -59,6 +59,9 @@ extern char** environ; #endif +// Generated by generate_about_rv.py +extern const char* about_RV; + #ifdef PLATFORM_DARWIN extern void (*sessionFromUrlPointer)(std::string); extern void (*putUrlOnMacPasteboardPointer)(std::string, std::string); @@ -619,7 +622,15 @@ namespace Rv msgBox->setIconPixmap(icon.pixmap(size)); msgBox->setStandardButtons(QMessageBox::Close); + // Add a text box with detailed build and dependency information + QTextEdit* textBox = new QTextEdit(); + textBox->setHtml(about_RV); + textBox->setReadOnly(true); + textBox->setMinimumHeight(250); + textBox->setMinimumWidth(500); + QGridLayout* grid = static_cast(msgBox->layout()); + grid->addWidget(textBox, grid->rowCount() - 1, 0, 1, -1); QDialogButtonBox* buttonBox = msgBox->findChild(); grid->removeWidget(buttonBox); diff --git a/src/lib/app/RvCommon/generate_about_rv.py b/src/lib/app/RvCommon/generate_about_rv.py new file mode 100755 index 000000000..efd58dcb1 --- /dev/null +++ b/src/lib/app/RvCommon/generate_about_rv.py @@ -0,0 +1,293 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2025 Autodesk, Inc. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Generate about_rv.cpp with build and dependency information + +import argparse +import sys +from datetime import datetime +from pathlib import Path + + +def get_git_info(git_hash_from_cmake=""): + """Get git commit hash from CMake""" + return git_hash_from_cmake if git_hash_from_cmake else "unknown" + + +def parse_versions(versions_str): + """Parse the versions string into a dictionary""" + versions = {} + if versions_str: + for item in versions_str.split(","): + if ":" in item: + key, value = item.split(":", 1) + versions[key] = value + return versions + + +def get_dependencies_info(versions, app_name, platform=""): + """Generate dependency information using detected versions""" + + def get_version(key, default="Unknown"): + version = versions.get(key, default) + # Strip FFmpeg's 'n' prefix (e.g., n6.1.2 -> 6.1.2) + if key == "FFmpeg" and version.startswith("n"): + version = version[1:] + return version + + # OpenRV uses LGPL, commercial RV uses Qt Commercial + is_commercial_rv = app_name == "RV" + qt_license = "Qt Commercial" if is_commercial_rv else "LGPL v3" + pyside_license = "Qt Commercial" if is_commercial_rv else "LGPL v3" + + is_macos = "darwin" in platform.lower() or "macos" in platform.lower() + + vfx_deps = [ + ("Boost", get_version("Boost"), "Boost Software License"), + ("CMake", get_version("CMake"), "BSD 3-Clause"), + ("Imath", get_version("Imath"), "BSD 3-Clause"), + ("NumPy", get_version("numpy", "1.24+"), "BSD 3-Clause"), + ("OpenColorIO", get_version("OpenColorIO"), "BSD 3-Clause"), + ("OpenEXR", get_version("OpenEXR"), "BSD 3-Clause"), + ("OpenImageIO", get_version("OpenImageIO"), "Apache 2.0"), + ("OpenTimelineIO", get_version("otio"), "Apache 2.0"), + ("PySide", get_version("PySide"), pyside_license), + ("Python", get_version("Python"), "PSF License"), + ("Qt Framework", get_version("Qt"), qt_license), + ] + + # RV-specific proprietary components (only for commercial RV, alphabetical order) + rv_specific_deps = [] + if is_commercial_rv: + # Apple ProRes is only available on macOS (and not on ARM64 currently) + if is_macos: + prores_ver = get_version("prores", "Not Used") + rv_specific_deps.append(("Apple ProRes", prores_ver, "Apple Proprietary")) + + # Always add these for commercial RV (version will show "Not Used" if not available) + rv_specific_deps.extend( + [ + ("ARRI SDK", get_version("arriraw", "Not Used"), "ARRI Proprietary"), + ("NDI SDK", get_version("ndi", "Not Used"), "NDI Proprietary"), + ("RED R3D SDK", get_version("r3dsdk", "Not Used"), "RED Proprietary"), + ("x264", get_version("x264", "Not Used"), "x264 Commercial License"), + ] + ) + + # Other third-party components (alphabetical order) + other_deps = [ + ("AJA NTV2 SDK", get_version("aja"), "MIT License"), + ("Blackmagic DeckLink SDK", get_version("bmd"), "Proprietary"), + ("Boehm GC", get_version("gc"), "MIT-style"), + ("dav1d", get_version("dav1d"), "BSD 2-Clause"), + ("Dear ImGui", get_version("imgui"), "MIT License"), + ("Expat", get_version("expat"), "MIT License"), + ("FFmpeg", get_version("FFmpeg"), "LGPL v2.1+"), + ("GLEW", get_version("GLEW"), "Modified BSD / MIT"), + ("libjpeg-turbo", get_version("jpegturbo"), "BSD-style"), + ("libpng", get_version("png"), "libpng License"), + ("LibRaw", get_version("raw"), "LGPL v2.1 / CDDL"), + ("libtiff", get_version("tiff"), "libtiff License"), + ("libwebp", get_version("webp"), "BSD 3-Clause"), + ("nanobind", get_version("nanobind"), "BSD 3-Clause"), + ("OpenJPEG", get_version("openjpeg"), "BSD 2-Clause"), + ("OpenJPH", get_version("openjph"), "BSD 2-Clause"), + ("OpenSSL", get_version("OpenSSL"), "Apache License 2.0"), + ("PCRE2", get_version("pcre2"), "BSD License"), + ("spdlog", get_version("spdlog"), "MIT License"), + ("yaml-cpp", get_version("yaml-cpp"), "MIT License"), + ("zlib", get_version("zlib"), "zlib License"), + ] + + return vfx_deps, other_deps, rv_specific_deps + + +def generate_about_cpp( + output_file, + compiler, + vfx_platform, + platform, + arch, + app_name, + versions_str="", + git_hash="", +): + """Generate the about_rv.cpp file""" + + git_commit = get_git_info(git_hash) + versions = parse_versions(versions_str) + vfx_deps, other_deps, rv_specific_deps = get_dependencies_info(versions, app_name, platform) + build_date = datetime.now().strftime("%B %d, %Y") + + # Build the HTML content + html_content = [] + html_content.append("

") + html_content.append(f"{platform} {arch}") + html_content.append("

") + html_content.append("

") + html_content.append(f"Compiled using {compiler}") + html_content.append("

") + html_content.append("

") + html_content.append(f"Build identifier: {app_name}, HEAD={git_commit}") + html_content.append("

") + html_content.append("

") + html_content.append(f"Built on: {build_date}") + html_content.append("

") + + # Single table with both sections + html_content.append("


") + html_content.append("

") + html_content.append('') + + # VFX Platform header row + if vfx_platform: + # Extract year from platform (e.g., "CY2024" -> "2024") + vfx_year = vfx_platform.replace("CY", "") if vfx_platform.startswith("CY") else vfx_platform + html_content.append("") + html_content.append(f'') + html_content.append("") + + # Column headers + html_content.append("") + html_content.append("") + html_content.append("") + html_content.append("") + html_content.append("") + + # VFX Platform dependencies + for desc, version, license in vfx_deps: + html_content.append("") + html_content.append(f"") + html_content.append(f"") + html_content.append(f"") + html_content.append("") + + # Empty row separator + html_content.append('') + + # Other Dependencies header row + html_content.append("") + html_content.append('') + html_content.append("") + + # Column headers for other dependencies + html_content.append("") + html_content.append("") + html_content.append("") + html_content.append("") + html_content.append("") + + # Other dependencies + for desc, version, license in other_deps: + html_content.append("") + html_content.append(f"") + html_content.append(f"") + html_content.append(f"") + html_content.append("") + + # RV-Specific Components section (only for commercial RV) + if rv_specific_deps: + # Empty row separator + html_content.append('') + + # RV Components header row + html_content.append("") + html_content.append('') + html_content.append("") + + # Column headers + html_content.append("") + html_content.append("") + html_content.append("") + html_content.append("") + html_content.append("") + + # RV-specific components + for desc, version, license in rv_specific_deps: + html_content.append("") + html_content.append(f"") + html_content.append(f"") + html_content.append(f"") + html_content.append("") + + html_content.append("
VFX Reference Platform {vfx_year}
DescriptionVersionLicense
{desc}{version}{license}
 
Other Dependencies
DescriptionVersionLicense
{desc}{version}{license}
 
RV-Specific Components
DescriptionVersionLicense
{desc}{version}{license}
") + html_content.append("

") + html_content.append("


") + html_content.append("

") + html_content.append("For detailed license information, please see the THIRD-PARTY.md file ") + html_content.append("included with this distribution or visit the Open RV GitHub repository.") + html_content.append("

") + + # Join without newlines - HTML doesn't need them + html_str = "".join(html_content) + + # Escape quotes for C++ + html_str = html_str.replace('"', '\\"') + + # Generate the C++ file + cpp_content = f'''// +// Copyright (C) 2025 Autodesk, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// +// This file is auto-generated by generate_about_rv.py +// DO NOT EDIT MANUALLY + +const char* about_RV = "{html_str}"; +''' + + # Ensure the output directory exists + try: + output_path = Path(output_file) + print(f"Creating directory: {output_path.parent}") + output_path.parent.mkdir(parents=True, exist_ok=True) + + print(f"Writing to: {output_path}") + with open(output_file, "w", encoding="utf-8", newline="\n") as f: + f.write(cpp_content) + + # Verify the file was written + if not output_path.exists(): + print(f"ERROR: File was not created: {output_file}", file=sys.stderr) + sys.exit(1) + + file_size = output_path.stat().st_size + print(f"Generated {output_file} ({file_size} bytes)") + + except Exception as e: + print(f"ERROR generating {output_file}: {e}", file=sys.stderr) + import traceback + + traceback.print_exc() + sys.exit(1) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Generate about_rv.cpp with build and dependency information" + ) + parser.add_argument("output_file", help="Path to the output C++ file") + parser.add_argument("compiler", help="Compiler name and version") + parser.add_argument("vfx_platform", help="VFX Platform version (e.g., CY2024)") + parser.add_argument("platform", help="Target platform (e.g., macOS, Linux, Windows)") + parser.add_argument("arch", help="Target architecture (e.g., x86_64, arm64)") + parser.add_argument("app_name", nargs="?", default="Open RV", help="Application name") + parser.add_argument("versions", nargs="?", default="", help="Comma-separated dependency versions") + parser.add_argument("git_hash", nargs="?", default="", help="Git commit hash") + + args = parser.parse_args() + + print(f"=== generate_about_rv.py: generating {args.output_file} ===", flush=True) + generate_about_cpp( + args.output_file, + args.compiler, + args.vfx_platform, + args.platform, + args.arch, + args.app_name, + args.versions, + args.git_hash, + )