From 4805a7c909b32821b22d8f02ce45c579822688f2 Mon Sep 17 00:00:00 2001
From: Sean Donnelly <23455376+seando-adsk@users.noreply.github.com>
Date: Wed, 19 Jul 2023 16:43:58 -0400
Subject: [PATCH 1/4] EMSUSD-282 - MayaUsd: build with Qt directly from Maya
devkit/runtime
* New logic in build.py (during configure stage) to "setup Maya Qt"
by looking for Qt headers in Maya devkit. If not found, extract
either just the header from "qt*-include.zip" for Qt5 or the entire
zipfile for Qt6.
* Deprecated the "--qt-location" flag from build.py.
* New cmake module "FindMaya_Qt" used for Qt5.
* Use versionless Qt targets.
---
CMakeLists.txt | 38 ++++-
build.py | 116 ++++++++++++-
cmake/modules/FindMaya_Qt.cmake | 190 +++++++++++++++++++++
lib/mayaUsd/CMakeLists.txt | 2 +-
lib/usd/CMakeLists.txt | 2 +-
lib/usd/ui/CMakeLists.txt | 12 +-
lib/usd/ui/importDialogDemo/CMakeLists.txt | 6 +-
plugin/adsk/plugin/CMakeLists.txt | 4 +-
8 files changed, 338 insertions(+), 32 deletions(-)
create mode 100644 cmake/modules/FindMaya_Qt.cmake
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e8c4833953..aecaf3e913 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -156,7 +156,7 @@ endif()
if(DEFINED QT_LOCATION)
if(NOT DEFINED QT_VERSION)
- if(BUILD_WITH_QT_6)
+ if(BUILD_WITH_QT_6)
set(QT_VERSION "6.5")
else() # Maya 2022, 2023, 2024
set(QT_VERSION "5.15")
@@ -164,19 +164,41 @@ if(DEFINED QT_LOCATION)
message(STATUS "Setting Qt version to Qt ${QT_VERSION}")
endif()
set(CMAKE_PREFIX_PATH "${QT_LOCATION}")
+
if(BUILD_WITH_QT_6)
find_package(Qt6 ${QT_VERSION} COMPONENTS Core Gui Widgets REQUIRED)
- if(Qt6_FOUND)
- message(STATUS "Building with Qt ${QT_VERSION} features enabled.")
- endif()
else()
find_package(Qt5 ${QT_VERSION} COMPONENTS Core Gui Widgets REQUIRED)
- if(Qt5_FOUND)
- message(STATUS "Building with Qt ${QT_VERSION} features enabled.")
- endif()
endif()
+ if(Qt5_FOUND OR Qt6_FOUND)
+ message(STATUS "Found Qt in custom location, building with Qt ${QT_VERSION} features enabled.")
+ set(Qt_FOUND TRUE)
+ else()
+ message(WARNING "Could not find Qt in custom location: ${QT_LOCATION}. Building with Qt features will be disabled.")
+ endif()
else()
- message(STATUS "QT_LOCATION not set. Building Qt features will be disabled.")
+ # First look for Qt6 in the Maya devkit.
+ # The Qt6 archive in the Maya devkit contains everything needed for the normal cmake find_package.
+ set(CMAKE_PREFIX_PATH "${MAYA_DEVKIT_LOCATION}/Qt")
+ find_package(Qt6 6.5 COMPONENTS Core Gui Widgets QUIET)
+ if (Qt6_FOUND)
+ message(STATUS "Found Qt6 in Maya devkit, building with Qt ${Qt6_VERSION} features enabled.")
+ set(BUILD_WITH_QT_6 ON)
+ set(Qt_FOUND TRUE)
+ else()
+ # If we didn't find Qt6 in Maya devkit, search again, but for Qt5 this time.
+ # Minimum version required is 5.15 (Maya 2022/2023/2024).
+ # This will find Qt in the Maya devkit using a custom find package.
+ # So the version will match Maya we are building for.
+ find_package(Maya_Qt 5.15 COMPONENTS Core Gui Widgets QUIET)
+ if (Maya_Qt_FOUND)
+ message(STATUS "Found Qt5 in Maya devkit, building with Qt ${MAYA_QT_VERSION} features enabled.")
+ set(BUILD_WITH_QT_6 OFF)
+ set(Qt_FOUND TRUE)
+ else()
+ message(WARNING "Could not find Qt in Maya devkit directory: ${MAYA_DEVKIT_LOCATION}. Building with Qt features will be disabled.")
+ endif()
+ endif()
endif()
#------------------------------------------------------------------------------
diff --git a/build.py b/build.py
index ad76699b12..459620653e 100755
--- a/build.py
+++ b/build.py
@@ -2,6 +2,7 @@
from __future__ import print_function
from distutils.spawn import find_executable
+from glob import glob
import argparse
import contextlib
@@ -18,6 +19,8 @@
import sys
import distutils.util
import time
+import zipfile
+import tarfile
############################################################
# Helpers for printing output
@@ -359,6 +362,99 @@ def RunMakeZipArchive(context):
PrintError("Failed to write to directory {pkgDir} : {exp}".format(pkgDir=pkgDir,exp=exp))
sys.exit(1)
+def SetupMayaQt(context):
+ def haveQtHeaders(rootPath):
+ if os.path.exists(rootPath):
+ # MayaUsd uses these components from Qt (so at a minimum we must find them).
+ qtComponentsToFind = ['QtCore', 'QtGui', 'QtWidgets']
+ # Qt6 includes the entire Qt in a single zip file, which when extracted ends in folder 'Qt'.
+ startDir = os.path.join(rootPath, 'Qt', 'include') if os.path.exists(os.path.join(rootPath, 'Qt')) else os.path.join(rootPath, 'include')
+ for root,dirs,files in os.walk(startDir):
+ if 'qt' not in root.lower() or not files:
+ continue
+ if not any(root.endswith(qtComp) for qtComp in qtComponentsToFind):
+ # Skip any folders that aren't the components we are looking for.
+ continue
+
+ for qtComp in qtComponentsToFind[:]: # Loop over slice copy as we remove items
+ if qtComp in root and '{comp}version.h'.format(comp=qtComp.lower()) in files:
+ qtComponentsToFind.remove(qtComp)
+ PrintInfo('Found {comp} in {dir}'.format(comp=qtComp, dir=root))
+ break # Once we've found (and removed) a component, move to the next os.walk
+
+ if not qtComponentsToFind: # Once we've found them all, we are done.
+ return True
+
+ # The list of directories (in order) that we'll search. This list matches the one
+ # in FindMayaQt.cmake.
+ dirsToSearch = [context.devkitLocation]
+ if 'MAYA_DEVKIT_LOCATION' in os.environ:
+ dirsToSearch.append(os.path.expandvars('$MAYA_DEVKIT_LOCATION'))
+ dirsToSearch.append(context.mayaLocation)
+ if 'MAYA_LOCATION' in os.environ:
+ dirsToSearch.append(os.path.expandvars('$MAYA_LOCATION'))
+
+ # Check if the Qt zip file has been extracted (we need the Qt headers).
+ for dirToSearch in dirsToSearch:
+ if haveQtHeaders(dirToSearch):
+ PrintStatus('Found Maya Qt headers in: {dir}'.format(dir=dirToSearch))
+ return
+
+ # Qt5
+ # Didn't find Qt headers, so try and extract qt_5.x-include.zip (the first one we find).
+ qtIncludeArchiveName = 'qt_5*-include.zip' if Windows() else 'qt_5*-include.tar.gz'
+ for dirToSearch in dirsToSearch:
+ qtZipFiles = glob(os.path.join(dirToSearch, 'include', qtIncludeArchiveName))
+ if qtZipFiles:
+ qtZipFile = qtZipFiles[0]
+ baseDir = os.path.dirname(qtZipFile)
+ if os.access(baseDir, os.W_OK):
+ qtZipDirName = os.path.basename(qtZipFile)
+ qtZipDirName = qtZipDirName.replace('.zip', '').replace('.tar.gz', '')
+ qtZipDirFolder = os.path.join(baseDir, qtZipDirName)
+ PrintStatus("Could not find Maya Qt headers.")
+ PrintStatus(" Extracting '{zip}' to '{dir}'".format(zip=qtZipFile, dir=qtZipDirFolder))
+ if not os.path.exists(qtZipDirFolder):
+ os.makedirs(os.path.join(baseDir, qtZipDirFolder))
+ try:
+ # We only need certain Qt components so we only extract the headers for those.
+ if Windows():
+ archive = zipfile.ZipFile(qtZipFile, mode='r')
+ files = [n for n in archive.namelist()
+ if (n.startswith('QtCore/') or n.startswith('QtGui/') or n.startswith('QtWidgets/'))]
+ else:
+ archive = tarfile.open(qtZipFile, mode='r')
+ files = [n for n in archive.getmembers()
+ if (n.name.startswith('./QtCore/') or n.name.startswith('./QtGui/') or n.name.startswith('./QtWidgets/'))]
+ archive.extractall(qtZipDirFolder, files)
+ archive.close()
+ except zipfile.BadZipfile as error:
+ PrintError(str(error))
+ except tarfile.TarError as error:
+ PrintError(str(error))
+
+ # We found and extracted the Qt5 include zip - we are done.
+ return
+
+ # Qt6
+ # The entire Qt is in a single zip file, which we extract to 'Qt'.
+ # Then we can simply use find_package(Qt6) on it.
+ for dirToSearch in dirsToSearch:
+ # Qt archive has same name on all platforms.
+ qtArchive = os.path.join(dirToSearch, 'Qt.tar.gz')
+ if os.path.exists(qtArchive):
+ qtZipDirFolder = os.path.dirname(qtArchive)
+ if os.access(qtZipDirFolder, os.W_OK):
+ PrintStatus("Could not find Maya Qt6.")
+ PrintStatus(" Extracting '{zip}' to '{dir}'".format(zip=qtArchive, dir=qtZipDirFolder))
+ try:
+ archive = tarfile.open(qtArchive, mode='r')
+ archive.extractall(qtZipDirFolder)
+ archive.close()
+ except tarfile.TarError as error:
+ PrintError(str(error))
+ return
+
def BuildAndInstall(context, buildArgs, stages):
with CurrentWorkingDirectory(context.mayaUsdSrcDir):
extraArgs = []
@@ -389,10 +485,6 @@ def BuildAndInstall(context, buildArgs, stages):
else:
extraArgs.append('-DMAYAUSD_DEFINE_BOOST_DEBUG_PYTHON_FLAG=OFF')
- if context.qtLocation:
- extraArgs.append('-DQT_LOCATION="{qtLocation}"'
- .format(qtLocation=context.qtLocation))
-
extraArgs += buildArgs
stagesArgs += stages
@@ -477,7 +569,7 @@ def Package(context):
help="Define Boost Python Debug if your Python library comes with Debugging symbols (default: %(default)s).")
parser.add_argument("--qt-location", type=str,
- help="Directory where Qt is installed.")
+ help="DEPRECATED: Qt is found automatically in Maya devkit.")
parser.add_argument("--build-args", type=str, nargs="*", default=[],
help=("Comma-separated list of arguments passed into CMake when building libraries"))
@@ -486,7 +578,7 @@ def Package(context):
help=("Comma-separated list of arguments passed into CTest.(e.g -VV, --output-on-failure)"))
parser.add_argument("--stages", type=str, nargs="*", default=['clean','configure','build','install'],
- help=("Comma-separated list of stages to execute.(possible stages: clean, configure, build, install, test, package)"))
+ help=("Comma-separated list of stages to execute. Possible stages: clean, configure, build, install, test, package."))
parser.add_argument("-j", "--jobs", type=int, default=GetCPUCount(),
help=("Number of build jobs to run in parallel. "
@@ -550,9 +642,11 @@ def __init__(self, args):
self.devkitLocation = (os.path.abspath(args.devkit_location)
if args.devkit_location else None)
- # Qt Location
- self.qtLocation = (os.path.abspath(args.qt_location)
- if args.qt_location else None)
+ # DEPRECATED: Qt Location
+ if args.qt_location:
+ PrintError("--qt-location flag is deprecated as Qt is found automatically in Maya devkit.")
+ PrintError("If you want to use custom Qt, use flag: --build-args=-DQT_LOCATION=
")
+ sys.exit(1)
# MaterialX
self.materialxEnabled = args.build_materialx
@@ -632,6 +726,10 @@ def __init__(self, args):
Print(summaryMsg)
+ # Make sure Qt from Maya devkit is ready.
+ if 'configure' in context.stagesArgs:
+ SetupMayaQt(context)
+
# BuildAndInstall
if any(stage in ['clean', 'configure', 'build', 'install'] for stage in context.stagesArgs):
StartBuild()
diff --git a/cmake/modules/FindMaya_Qt.cmake b/cmake/modules/FindMaya_Qt.cmake
new file mode 100644
index 0000000000..5d9ca405fb
--- /dev/null
+++ b/cmake/modules/FindMaya_Qt.cmake
@@ -0,0 +1,190 @@
+# Module to find Qt in Maya devkit.
+#
+# This module searches for the necessary Qt files in the Maya devkit.
+#
+# It relies on Maya being found first: find_package(Maya)
+# as it uses variables set there.
+#
+# Variables that will be defined:
+# Maya_Qt_FOUND Defined if Qt has been found
+# Qt{$QT_MAJOR_VERSION}_FOUND Defined if Qt has been found
+# MAYA_QT_INC_DIR The include folder where Qt header files can be found
+# QT_MOC_EXECUTABLE Path to Qt moc executable
+# QT_UIC_EXECUTABLE Path to Qt uic executable
+# QT_RCC_EXECUTABLE Path to Qt rcc executable
+# MAYA_QT_VERSION The version of Qt in the Maya devkit
+#
+
+# List of directories to search for Maya Qt headers/libraries/executables.
+set(MAYA_DIRS_TO_SEARCH
+ ${MAYA_DEVKIT_LOCATION}
+ $ENV{MAYA_DEVKIT_LOCATION}
+ ${MAYA_LOCATION}
+ $ENV{MAYA_LOCATION}
+)
+
+# Find the directory paths to the Qt headers (using the input components list).
+foreach(MAYA_DIR_TO_SEARCH ${MAYA_DIRS_TO_SEARCH})
+ file(TO_CMAKE_PATH ${MAYA_DIR_TO_SEARCH} qt_root_dir)
+
+ # Make sure we can find the header files for each Qt component.
+ set(Maya_Qt_Headers_FOUND TRUE) # Assume we will find them all.
+ foreach(Maya_Qt_Component ${Maya_Qt_FIND_COMPONENTS})
+ string(TOUPPER ${Maya_Qt_Component} MAYA_QT_COMPONENT)
+ string(TOLOWER ${Maya_Qt_Component} maya_qt_component)
+ unset(MAYA_QT_VERSION_FILE)
+ file(GLOB_RECURSE MAYA_QT_VERSION_FILE "${qt_root_dir}/include/*/qt${maya_qt_component}version.h")
+ if (NOT MAYA_QT_VERSION_FILE)
+ set(Maya_Qt_Headers_FOUND FALSE)
+ break() # We could not find the headers in this search path (try the next).
+ endif()
+ # Get the include directory for this component.
+ get_filename_component(MAYA_QT_${MAYA_QT_COMPONENT}_DIR ${MAYA_QT_VERSION_FILE} DIRECTORY)
+ endforeach()
+
+ if (Maya_Qt_Headers_FOUND AND MAYA_QT_${MAYA_QT_COMPONENT}_DIR)
+ # Get the base Qt include path (we can simply use the last component found as they are
+ # all in the same base path).
+ get_filename_component(MAYA_QT_INC_DIR ${MAYA_QT_${MAYA_QT_COMPONENT}_DIR} DIRECTORY)
+ break() # We found all the headers in this search path.
+ endif()
+endforeach()
+
+# Find Qt utilities.
+set(Maya_Qt_Utilities "moc;uic;rcc")
+foreach(Maya_Qt_Utility ${Maya_Qt_Utilities})
+ string(TOUPPER ${Maya_Qt_Utility} MAYA_QT_UTILITY)
+ find_program(QT_${MAYA_QT_UTILITY}_EXECUTABLE
+ NAMES
+ ${Maya_Qt_Utility}
+ PATHS
+ ${MAYA_DEVKIT_LOCATION}
+ $ENV{MAYA_DEVKIT_LOCATION}
+ ${MAYA_LOCATION}
+ $ENV{MAYA_LOCATION}
+ ${MAYA_BASE_DIR}
+ PATH_SUFFIXES
+ devkit/bin
+ bin
+ NO_DEFAULT_PATH
+ DOC
+ "Maya Qt utility"
+ )
+endforeach()
+
+if (QT_UIC_EXECUTABLE)
+ # Get the Qt version based on UIC
+ execute_process(COMMAND ${QT_UIC_EXECUTABLE} "--version" OUTPUT_VARIABLE QT_UIC_VERSION)
+ STRING(REPLACE "." " " QT_UIC_VERSION ${QT_UIC_VERSION})
+ STRING(REPLACE " " ";" QT_UIC_VERSION ${QT_UIC_VERSION})
+ LIST(GET QT_UIC_VERSION 1 QT_VERSION_MAJOR)
+ LIST(GET QT_UIC_VERSION 2 QT_VERSION_MINOR)
+ LIST(GET QT_UIC_VERSION 3 QT_PATCH_LEVEL)
+ set(MAYA_QT_VERSION ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}.${QT_PATCH_LEVEL})
+ add_executable(Qt${QT_VERSION_MAJOR}::uic IMPORTED GLOBAL)
+ set_target_properties(Qt${QT_VERSION_MAJOR}::uic PROPERTIES IMPORTED_LOCATION ${QT_UIC_EXECUTABLE})
+endif()
+
+if (QT_MOC_EXECUTABLE)
+ add_executable(Qt${QT_VERSION_MAJOR}::moc IMPORTED GLOBAL)
+ set_target_properties(Qt${QT_VERSION_MAJOR}::moc PROPERTIES IMPORTED_LOCATION ${QT_MOC_EXECUTABLE})
+endif()
+
+if (QT_RCC_EXECUTABLE)
+ add_executable(Qt${QT_VERSION_MAJOR}::rcc IMPORTED GLOBAL)
+ set_target_properties(Qt${QT_VERSION_MAJOR}::rcc PROPERTIES IMPORTED_LOCATION ${QT_RCC_EXECUTABLE})
+endif()
+
+# Find the Maya Qt libraries (using the input components list).
+foreach(Maya_Qt_LIB ${Maya_Qt_FIND_COMPONENTS})
+ string(TOUPPER ${Maya_Qt_LIB} MAYA_QT_LIB)
+ set(QT_NAME_TO_FIND "Qt${QT_VERSION_MAJOR}${Maya_Qt_LIB}")
+ if (CMAKE_BUILD_TYPE MATCHES "Debug")
+ # When in debug we sometimes need to modify the names.
+ if (IS_WINDOWS)
+ string(APPEND QT_NAME_TO_FIND "d") # extra 'd' at end
+ elseif (IS_MACOSX)
+ string(APPEND QT_NAME_TO_FIND "_debug") # extra '_debug' at end
+ endif()
+ endif()
+ find_library(MAYA_QT${MAYA_QT_LIB}_LIBRARY
+ NAMES
+ ${QT_NAME_TO_FIND}
+ PATHS
+ ${MAYA_LIBRARY_DIR}
+ NO_DEFAULT_PATH
+ DOC
+ "Maya Qt library"
+ )
+ if (MAYA_QT${MAYA_QT_LIB}_LIBRARY)
+ # Add each Qt library and set the target properties.
+ set(__target_name "Qt${QT_VERSION_MAJOR}::${Maya_Qt_LIB}")
+ add_library(${__target_name} SHARED IMPORTED GLOBAL)
+ set_target_properties(${__target_name} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${MAYA_QT_${MAYA_QT_LIB}_DIR};${MAYA_QT_INC_DIR}")
+ set_target_properties(${__target_name} PROPERTIES IMPORTED_CONFIGURATIONS RELEASE) # RELEASE?
+ set_target_properties(${__target_name} PROPERTIES IMPORTED_LOCATION "${MAYA_QT${MAYA_QT_LIB}_LIBRARY}")
+ if(IS_WINDOWS)
+ set_target_properties(${__target_name} PROPERTIES IMPORTED_IMPLIB "${MAYA_QT${MAYA_QT_LIB}_LIBRARY}")
+ set_target_properties(${__target_name} PROPERTIES INTERFACE_LINK_LIBRARIES "${__target_name}")
+ endif()
+ if(${QT_VERSION_MAJOR} VERSION_EQUAL 6)
+ # Add extra compile options required for Qt6.
+ set_target_properties(${__target_name} PROPERTIES
+ INTERFACE_COMPILE_FEATURES "cxx_std_17") # Comes from Qt6::Platform
+ if (IS_WINDOWS)
+ # Comes from Qt6::Platform
+ set_target_properties(${__target_name} PROPERTIES
+ INTERFACE_COMPILE_OPTIONS "\$<\$:/Zc:__cplusplus;/permissive->")
+ endif()
+ endif()
+
+ # Add a versionless target.
+ set(__versionless_target_name "Qt::${Maya_Qt_LIB}")
+ if (TARGET ${__target_name} AND NOT TARGET ${__versionless_target_name})
+ add_library(${__versionless_target_name} INTERFACE IMPORTED)
+ set_target_properties(${__versionless_target_name} PROPERTIES INTERFACE_LINK_LIBRARIES ${__target_name})
+ endif()
+ endif()
+endforeach()
+
+# Set the Qt library dependencies (special cases we know about).
+if (IS_LINUX AND TARGET Qt${QT_VERSION_MAJOR}::Core)
+ set_property(TARGET Qt${QT_VERSION_MAJOR}::Core APPEND PROPERTY INTERFACE_COMPILE_OPTIONS -fPIC)
+ set_property(TARGET Qt${QT_VERSION_MAJOR}::Core PROPERTY INTERFACE_COMPILE_FEATURES cxx_decltype)
+endif()
+if (TARGET Qt${QT_VERSION_MAJOR}::Widgets)
+ set_target_properties(Qt${QT_VERSION_MAJOR}::Widgets PROPERTIES INTERFACE_LINK_LIBRARIES "Qt${QT_VERSION_MAJOR}::Gui;Qt${QT_VERSION_MAJOR}::Core")
+endif()
+if (TARGET Qt${QT_VERSION_MAJOR}::Gui)
+ set_target_properties(Qt${QT_VERSION_MAJOR}::Gui PROPERTIES INTERFACE_LINK_LIBRARIES "Qt${QT_VERSION_MAJOR}::Core")
+endif()
+
+# Handle the QUIETLY and REQUIRED arguments and set UFE_FOUND to TRUE if
+# all listed variables are TRUE.
+include(FindPackageHandleStandardArgs)
+
+list(APPEND Maya_QtRequiredVars "MAYA_QT_INC_DIR" "QT_MOC_EXECUTABLE" "QT_UIC_EXECUTABLE" "QT_RCC_EXECUTABLE")
+foreach(Maya_Qt_LIB ${Maya_Qt_FIND_COMPONENTS})
+ string(TOUPPER ${Maya_Qt_LIB} MAYA_QT_LIB)
+ list(APPEND Maya_QtRequiredVars "MAYA_QT${MAYA_QT_LIB}_LIBRARY")
+endforeach()
+
+find_package_handle_standard_args(Maya_Qt
+ REQUIRED_VARS
+ ${Maya_QtRequiredVars}
+ VERSION_VAR
+ MAYA_QT_VERSION
+)
+
+if (Maya_Qt_FOUND)
+ set(Qt${QT_VERSION_MAJOR}_FOUND TRUE)
+ message(STATUS "Using Maya Qt version ${MAYA_QT_VERSION}")
+ message(STATUS " Qt include path : ${MAYA_QT_INC_DIR}")
+ message(STATUS " moc executable : ${QT_MOC_EXECUTABLE}")
+ message(STATUS " uic executable : ${QT_UIC_EXECUTABLE}")
+ message(STATUS " rcc executable : ${QT_RCC_EXECUTABLE}")
+ foreach(Maya_Qt_LIB ${Maya_Qt_FIND_COMPONENTS})
+ string(TOUPPER ${Maya_Qt_LIB} MAYA_QT_LIB)
+ message(STATUS " Qt ${Maya_Qt_LIB} library: ${MAYA_QT${MAYA_QT_LIB}_LIBRARY}")
+ endforeach()
+endif()
diff --git a/lib/mayaUsd/CMakeLists.txt b/lib/mayaUsd/CMakeLists.txt
index 4da2c1ad2d..89528eae3b 100644
--- a/lib/mayaUsd/CMakeLists.txt
+++ b/lib/mayaUsd/CMakeLists.txt
@@ -49,7 +49,7 @@ target_compile_definitions(${PROJECT_NAME}
$<$:GL_GLEXT_PROTOTYPES>
$<$:GLX_GLXEXT_PROTOTYPES>
$<$:WANT_MATERIALX_BUILD>
- $<$,$>:WANT_QT_BUILD>
+ $<$:WANT_QT_BUILD>
$<$:BUILD_HDMAYA>
# this flag is needed when building maya-usd in Maya
diff --git a/lib/usd/CMakeLists.txt b/lib/usd/CMakeLists.txt
index e87bbbf200..6d1234f993 100644
--- a/lib/usd/CMakeLists.txt
+++ b/lib/usd/CMakeLists.txt
@@ -23,7 +23,7 @@ add_subdirectory(schemas)
add_subdirectory(utils)
-if(Qt5_FOUND OR Qt6_FOUND)
+if(Qt_FOUND)
add_subdirectory(ui)
endif()
diff --git a/lib/usd/ui/CMakeLists.txt b/lib/usd/ui/CMakeLists.txt
index cd38e09381..302a4be6b3 100644
--- a/lib/usd/ui/CMakeLists.txt
+++ b/lib/usd/ui/CMakeLists.txt
@@ -47,11 +47,7 @@ target_compile_definitions(${PROJECT_NAME}
# QT_NO_KEYWORDS prevents Qt from defining the foreach, signals, slots and emit macros.
# this avoids overlap between Qt macros and boost, and enforces using Q_ macros.
-if (Qt6_FOUND)
- set_target_properties(Qt6::Core PROPERTIES INTERFACE_COMPILE_DEFINITIONS QT_NO_KEYWORDS)
-else()
- set_target_properties(Qt5::Core PROPERTIES INTERFACE_COMPILE_DEFINITIONS QT_NO_KEYWORDS)
-endif()
+set_target_properties(Qt::Core PROPERTIES INTERFACE_COMPILE_DEFINITIONS QT_NO_KEYWORDS)
mayaUsd_compile_config(${PROJECT_NAME})
@@ -62,9 +58,9 @@ target_link_libraries(${PROJECT_NAME}
PUBLIC
mayaUsd
PRIVATE
- $,Qt6::Core,Qt5::Core>
- $,Qt6::Gui,Qt5::Gui>
- $,Qt6::Widgets,Qt5::Widgets>
+ Qt::Core
+ Qt::Gui
+ Qt::Widgets
)
# -----------------------------------------------------------------------------
diff --git a/lib/usd/ui/importDialogDemo/CMakeLists.txt b/lib/usd/ui/importDialogDemo/CMakeLists.txt
index b0fef08452..302fb16698 100644
--- a/lib/usd/ui/importDialogDemo/CMakeLists.txt
+++ b/lib/usd/ui/importDialogDemo/CMakeLists.txt
@@ -40,9 +40,9 @@ mayaUsd_compile_config(${PROJECT_NAME})
target_link_libraries(${PROJECT_NAME}
PRIVATE
mayaUsdUI
- $,Qt6::Core,Qt5::Core>
- $,Qt6::Gui,Qt5::Gui>
- $,Qt6::Widgets,Qt5::Widgets>
+ Qt::Core
+ Qt::Gui
+ Qt::Widgets
)
if (IS_LINUX)
diff --git a/plugin/adsk/plugin/CMakeLists.txt b/plugin/adsk/plugin/CMakeLists.txt
index 657a9ccbf9..86c3c55dfe 100644
--- a/plugin/adsk/plugin/CMakeLists.txt
+++ b/plugin/adsk/plugin/CMakeLists.txt
@@ -48,7 +48,7 @@ endif()
target_compile_definitions(${TARGET_NAME}
PRIVATE
MAYAUSD_PLUGIN_EXPORT
- $<$,$>:WANT_QT_BUILD>
+ $<$:WANT_QT_BUILD>
)
if(DEFINED MAYAUSD_VERSION)
@@ -77,7 +77,7 @@ target_link_libraries(${TARGET_NAME}
basePxrUsdPreviewSurface
)
-if (Qt5_FOUND OR Qt6_FOUND)
+if (Qt_FOUND)
target_link_libraries(${TARGET_NAME}
PRIVATE
mayaUsdUI
From 22f81d4ae886dcff79c4a766afd11400bcf3b24b Mon Sep 17 00:00:00 2001
From: Sean Donnelly <23455376+seando-adsk@users.noreply.github.com>
Date: Mon, 28 Aug 2023 10:38:49 -0400
Subject: [PATCH 2/4] EMSUSD-282 - MayaUsd: build with Qt directly from Maya
devkit/runtime
* Fix for security/bandit B202: tarfile_unsafe_members
---
build.py | 42 +++++++++++++++++++++++++++++++++++-------
1 file changed, 35 insertions(+), 7 deletions(-)
diff --git a/build.py b/build.py
index 459620653e..6921114ed9 100755
--- a/build.py
+++ b/build.py
@@ -385,6 +385,32 @@ def haveQtHeaders(rootPath):
if not qtComponentsToFind: # Once we've found them all, we are done.
return True
+ def safeTarfileExtract(members):
+ """Use a function to look for bad paths in the tarfile archive to fix
+ security/bandit B202: tarfile_unsafe_members."""
+
+ def isBadPath(path, base):
+ return not os.path.realpath(os.path.abspath(os.path.join(base, path))).startswith(base)
+ def isBadLink(info, base):
+ # Links are interpreted relative to the directory containing the link.
+ tip = os.path.realpath(os.path.abspath(os.path.join(base, dirname(info.name))))
+ return _badpath(info.linkname, base=tip)
+
+ base = os.path.realpath(os.path.abspath('.'))
+ result = []
+ for finfo in members:
+ # If any bad paths for links are found in the tarfile, print an error
+ # and don't extract anything from tarfile.
+ if isBadPath(finfo.name, base):
+ PrintError('Found illegal path {path} in tarfile, blocking tarfile extraction.'.format(path=finfo.name))
+ return []
+ elif (finfo.issym() or finfo.islnk()) and isBadLink(finfo, base):
+ PrintError('Found illegal link {link} in tarfile, blocking tarfile extraction.'.format(link=finfo.linkname))
+ return []
+ else:
+ result.append(finfo)
+ return result
+
# The list of directories (in order) that we'll search. This list matches the one
# in FindMayaQt.cmake.
dirsToSearch = [context.devkitLocation]
@@ -419,15 +445,17 @@ def haveQtHeaders(rootPath):
try:
# We only need certain Qt components so we only extract the headers for those.
if Windows():
- archive = zipfile.ZipFile(qtZipFile, mode='r')
- files = [n for n in archive.namelist()
+ zipArchive = zipfile.ZipFile(qtZipFile, mode='r')
+ files = [n for n in zipArchive.namelist()
if (n.startswith('QtCore/') or n.startswith('QtGui/') or n.startswith('QtWidgets/'))]
+ zipArchive.extractall(qtZipDirFolder, files)
+ zipArchive.close()
else:
- archive = tarfile.open(qtZipFile, mode='r')
- files = [n for n in archive.getmembers()
+ tarArchive = tarfile.open(qtZipFile, mode='r')
+ files = [n for n in tarArchive.getmembers()
if (n.name.startswith('./QtCore/') or n.name.startswith('./QtGui/') or n.name.startswith('./QtWidgets/'))]
- archive.extractall(qtZipDirFolder, files)
- archive.close()
+ tarArchive.extractall(qtZipDirFolder, members=safeTarfileExtract(files))
+ tarArchive.close()
except zipfile.BadZipfile as error:
PrintError(str(error))
except tarfile.TarError as error:
@@ -449,7 +477,7 @@ def haveQtHeaders(rootPath):
PrintStatus(" Extracting '{zip}' to '{dir}'".format(zip=qtArchive, dir=qtZipDirFolder))
try:
archive = tarfile.open(qtArchive, mode='r')
- archive.extractall(qtZipDirFolder)
+ archive.extractall(qtZipDirFolder, members=safeTarfileExtract(archive.getmembers()))
archive.close()
except tarfile.TarError as error:
PrintError(str(error))
From 8927d6ea660e8bb3c2c710940e43586b43eaef0c Mon Sep 17 00:00:00 2001
From: Sean Donnelly <23455376+seando-adsk@users.noreply.github.com>
Date: Tue, 29 Aug 2023 13:30:29 -0400
Subject: [PATCH 3/4] EMSUSD-282 - MayaUsd: build with Qt directly from Maya
devkit/runtime
* Code review feedback - remove QT_LOCATION completely and cmake
error if Qt cannot be found in Maya devkit.
---
CMakeLists.txt | 62 +++++++++++++++++++-------------------------------
build.py | 4 +---
2 files changed, 25 insertions(+), 41 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index aecaf3e913..672a48d958 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -37,8 +37,6 @@ set(BUILD_WITH_PYTHON_3_VERSION 3.7 CACHE STRING "The version of Python 3 to bui
option(CMAKE_WANT_MATERIALX_BUILD "Enable building with MaterialX." ON)
option(CMAKE_WANT_VALIDATE_UNDO_ITEM "Enable validating undo items list." OFF)
-option(BUILD_WITH_QT_6 "Build with QT 6." OFF)
-
set(PXR_OVERRIDE_PLUGINPATH_NAME PXR_PLUGINPATH_NAME
CACHE STRING "Name of env var USD searches to find plugins")
@@ -154,51 +152,39 @@ if(TARGET hdMtlx)
endif()
endif()
-if(DEFINED QT_LOCATION)
- if(NOT DEFINED QT_VERSION)
- if(BUILD_WITH_QT_6)
- set(QT_VERSION "6.5")
- else() # Maya 2022, 2023, 2024
- set(QT_VERSION "5.15")
- endif()
- message(STATUS "Setting Qt version to Qt ${QT_VERSION}")
- endif()
- set(CMAKE_PREFIX_PATH "${QT_LOCATION}")
-
- if(BUILD_WITH_QT_6)
- find_package(Qt6 ${QT_VERSION} COMPONENTS Core Gui Widgets REQUIRED)
- else()
- find_package(Qt5 ${QT_VERSION} COMPONENTS Core Gui Widgets REQUIRED)
- endif()
- if(Qt5_FOUND OR Qt6_FOUND)
- message(STATUS "Found Qt in custom location, building with Qt ${QT_VERSION} features enabled.")
- set(Qt_FOUND TRUE)
- else()
- message(WARNING "Could not find Qt in custom location: ${QT_LOCATION}. Building with Qt features will be disabled.")
- endif()
-else()
+if(MAYA_APP_VERSION VERSION_GREATER 2024)
# First look for Qt6 in the Maya devkit.
# The Qt6 archive in the Maya devkit contains everything needed for the normal cmake find_package.
set(CMAKE_PREFIX_PATH "${MAYA_DEVKIT_LOCATION}/Qt")
find_package(Qt6 6.5 COMPONENTS Core Gui Widgets QUIET)
- if (Qt6_FOUND)
- message(STATUS "Found Qt6 in Maya devkit, building with Qt ${Qt6_VERSION} features enabled.")
- set(BUILD_WITH_QT_6 ON)
+endif()
+if (Qt6_FOUND)
+ message(STATUS "Found Qt6 in Maya devkit, building with Qt ${Qt6_VERSION} features enabled.")
+ set(Qt_FOUND TRUE)
+else()
+ # If we didn't find Qt6 in Maya devkit, search again, but for Qt5 this time.
+ # Minimum version required is 5.15 (Maya 2022/2023/2024).
+ # This will find Qt in the Maya devkit using a custom find package.
+ # So the version will match Maya we are building for.
+ find_package(Maya_Qt 5.15 COMPONENTS Core Gui Widgets QUIET)
+ if (Maya_Qt_FOUND)
+ message(STATUS "Found Qt5 in Maya devkit, building with Qt ${MAYA_QT_VERSION} features enabled.")
set(Qt_FOUND TRUE)
+ endif()
+endif()
+
+if(NOT Qt_FOUND)
+ message(SEND_ERROR "Could not find Qt in Maya devkit directory: ${MAYA_DEVKIT_LOCATION}.")
+ if(MAYA_APP_VERSION VERSION_GREATER 2024)
+ message(STATUS " You must extract Qt.tar.gz")
else()
- # If we didn't find Qt6 in Maya devkit, search again, but for Qt5 this time.
- # Minimum version required is 5.15 (Maya 2022/2023/2024).
- # This will find Qt in the Maya devkit using a custom find package.
- # So the version will match Maya we are building for.
- find_package(Maya_Qt 5.15 COMPONENTS Core Gui Widgets QUIET)
- if (Maya_Qt_FOUND)
- message(STATUS "Found Qt5 in Maya devkit, building with Qt ${MAYA_QT_VERSION} features enabled.")
- set(BUILD_WITH_QT_6 OFF)
- set(Qt_FOUND TRUE)
+ if (IS_WINDOWS)
+ message(STATUS " In Maya devkit you must extract include/qt_5.15.2_vc14-include.zip")
else()
- message(WARNING "Could not find Qt in Maya devkit directory: ${MAYA_DEVKIT_LOCATION}. Building with Qt features will be disabled.")
+ message(STATUS " In Maya devkit you must extract include/qt_5.15.2-include.tar.gz")
endif()
endif()
+ message(FATAL_ERROR "Cannot build MayaUsd without Qt.")
endif()
#------------------------------------------------------------------------------
diff --git a/build.py b/build.py
index 6921114ed9..668c912176 100755
--- a/build.py
+++ b/build.py
@@ -672,9 +672,7 @@ def __init__(self, args):
# DEPRECATED: Qt Location
if args.qt_location:
- PrintError("--qt-location flag is deprecated as Qt is found automatically in Maya devkit.")
- PrintError("If you want to use custom Qt, use flag: --build-args=-DQT_LOCATION=")
- sys.exit(1)
+ PrintWarning("--qt-location flag is deprecated as Qt is found automatically in Maya devkit.")
# MaterialX
self.materialxEnabled = args.build_materialx
From 547740d32ff19de71233aa37c276740fb8fe62ef Mon Sep 17 00:00:00 2001
From: Sean Donnelly <23455376+seando-adsk@users.noreply.github.com>
Date: Wed, 30 Aug 2023 08:44:01 -0400
Subject: [PATCH 4/4] EMSUSD-282 - MayaUsd: build with Qt directly from Maya
devkit/runtime
* Fixed python scripting error.
---
build.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/build.py b/build.py
index 668c912176..a5f4aac049 100755
--- a/build.py
+++ b/build.py
@@ -393,8 +393,8 @@ def isBadPath(path, base):
return not os.path.realpath(os.path.abspath(os.path.join(base, path))).startswith(base)
def isBadLink(info, base):
# Links are interpreted relative to the directory containing the link.
- tip = os.path.realpath(os.path.abspath(os.path.join(base, dirname(info.name))))
- return _badpath(info.linkname, base=tip)
+ tip = os.path.realpath(os.path.abspath(os.path.join(base, os.path.dirname(info.name))))
+ return isBadPath(info.linkname, base=tip)
base = os.path.realpath(os.path.abspath('.'))
result = []