Skip to content

Commit

Permalink
Add support for a wayland variant of Qt for Linux
Browse files Browse the repository at this point in the history
- Remove unnecessary wrapper scripts build-linux-aarch64.sh and build-linux-x86.sh
- Add special build_config_wayland.json and Dockerfile.wayland to support the wayland variant
- Update docker_build_qt_linux.sh to support the environment option 'ENABLE_QT_WAYLAND' which is set in the Dockerfile
- Update docker_build_qt_linux.sh to support building the additional qtwayland package from source

Signed-off-by: Steve Pham <[email protected]>
  • Loading branch information
spham-amzn committed Nov 15, 2024
1 parent 11c082c commit e653154
Show file tree
Hide file tree
Showing 11 changed files with 532 additions and 77 deletions.
1 change: 1 addition & 0 deletions package-system/Qt/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
update-locale LANG=en_US.UTF-8

ENV LANG=en_US.UTF-8
ENV ENABLE_QT_WAYLAND=0

# Install the development packages needed to build Qt from source
RUN apt-get install -y qtbase5-dev \
Expand Down
58 changes: 58 additions & 0 deletions package-system/Qt/Dockerfile.wayland
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@

# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#

# This docker file uses ubuntu 20.04 as the base image to install the dependencies to build Qt from source
#

FROM public.ecr.aws/ubuntu/ubuntu:20.04_stable

WORKDIR /data/workspace

# Initilize apt cache
RUN apt-get clean && apt-get update

# Setup time zone and locale data (necessary for SSL and HTTPS packages)
RUN DEBIAN_FRONTEND="noninteractive" apt-get -y install tzdata locales keyboard-configuration

RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
dpkg-reconfigure --frontend=noninteractive locales && \
update-locale LANG=en_US.UTF-8

ENV LANG=en_US.UTF-8
ENV ENABLE_QT_WAYLAND=1

# Install the development packages needed to build Qt from source
RUN apt-get install -y qtbase5-dev \
build-essential \
perl \
python3 \
git \
'^libxcb.*-dev' \
libx11-xcb-dev \
libglu1-mesa-dev \
libxrender-dev \
libxi-dev \
libxkbcommon-dev \
libxkbcommon-x11-dev \
libgbm-dev \
libxext-dev \
libfontconfig1-dev \
libtiff-dev \
libwayland-dev \
libwayland-egl1-mesa \
libwayland-server0 \
libgles2-mesa-dev

# Prepare a target folder within the container to install the build artifacts tp
RUN mkdir -p /data/workspace/qt

RUN git clone --single-branch --recursive --branch v5.15.1 git://code.qt.io/qt/qtwayland.git && \
ln -s /data/workspace/qtwayland/include/QtWaylandCompositor/5.15.1/QtWaylandCompositor/private/qwayland-server-qt-texture-sharing-unstable-v1.h /data/workspace/qtwayland/src/compositor/qwayland-server-qt-texture-sharing-unstable-v1.h && \
ln -s /data/workspace/qtwayland/include/QtWaylandCompositor/5.15.1/QtWaylandCompositor/private/wayland-qt-texture-sharing-unstable-v1-server-protocol.h /data/workspace/qtwayland/src/compositor/wayland-qt-texture-sharing-unstable-v1-server-protocol.h

# Copy the build script specific to this Docker script in order to execute the build
COPY docker_build_qt_linux.sh /data/workspace/
288 changes: 288 additions & 0 deletions package-system/Qt/FindQt.cmake.wayland
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#

if(TARGET 3rdParty::Qt::Core) # Check we are not called multiple times
return()
endif()

set(QT_PACKAGE_NAME qt)

set(QT_PATH "${CMAKE_CURRENT_LIST_DIR}/qt-wayland" CACHE STRING "The root path to Qt" FORCE)
mark_as_advanced(QT_PATH)
if(NOT EXISTS ${QT_PATH})
message(FATAL_ERROR "Cannot find 3rdParty library ${QT_PACKAGE_NAME} on path ${QT_PATH}")
endif()

# Force-set QtCore's version here to ensure CMake detects Qt's existence and allows AUTOMOC to work
set(Qt5Core_VERSION_MAJOR "5" CACHE STRING "Qt's major version" FORCE)
set(Qt5Core_VERSION_MINOR "15" CACHE STRING "Qt's minor version" FORCE)
set(Qt5Core_VERSION_PATCH "2" CACHE STRING "Qt's patch version" FORCE)
mark_as_advanced(Qt5Core_VERSION_MAJOR)
mark_as_advanced(Qt5Core_VERSION_MINOR)
mark_as_advanced(Qt5Core_VERSION_PATCH)

set(QT5_COMPONENTS
Core
Concurrent
Gui
LinguistTools
Network
OpenGL
Svg
Test
Widgets
Xml
)

include(${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}/Qt_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)

list(APPEND CMAKE_PREFIX_PATH ${QT_LIB_PATH}/cmake/Qt5)

# Clear the cache for found DIRs
unset(Qt5_DIR CACHE)
foreach(component ${QT5_COMPONENTS})
unset(Qt5${component}_DIR CACHE)
endforeach()
unset(Qt5Positioning_DIR CACHE)
unset(Qt5PrintSupport_DIR CACHE)
unset(Qt5Qml_DIR CACHE)
unset(Qt5QmlModels_DIR CACHE)
unset(Qt5Quick_DIR CACHE)

# Populate the Qt5 configurations
find_package(Qt5
COMPONENTS ${QT5_COMPONENTS}
REQUIRED
NO_CMAKE_PACKAGE_REGISTRY
)

# Now create libraries that wrap the dependency so we can refer to them in our format
foreach(component ${QT5_COMPONENTS})
if(TARGET Qt5::${component})

# Convert the includes to system includes
get_target_property(system_includes Qt5::${component} INTERFACE_INCLUDE_DIRECTORIES)
set_target_properties(Qt5::${component} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "") # Clear it in case someone refers to it
ly_target_include_system_directories(TARGET Qt5::${component}
INTERFACE ${system_includes}
)

# Alias the target with our prefix
add_library(3rdParty::Qt::${component} ALIAS Qt5::${component})
mark_as_advanced(Qt5${component}_DIR) # Hiding from GUI

# Qt only has debug and release, we map the configurations we use in o3de. We map all the configurations
# except debug to release
foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES)
string(TOUPPER ${conf} UCONF)
ly_qt_configuration_mapping(${UCONF} MAPPED_CONF)
set_target_properties(Qt5::${component} PROPERTIES
MAP_IMPORTED_CONFIG_${UCONF} ${MAPPED_CONF}
)
endforeach()

endif()
endforeach()

# Some extra DIR variables we want to hide from GUI
mark_as_advanced(Qt5_DIR) # Hiding from GUI
mark_as_advanced(Qt5LinguistTools_DIR) # Hiding from GUI, this variable comes from the LinguistTools module
mark_as_advanced(Qt5Positioning_DIR)
mark_as_advanced(Qt5PrintSupport_DIR)
mark_as_advanced(Qt5Qml_DIR)
mark_as_advanced(Qt5QmlModels_DIR)
mark_as_advanced(Qt5Quick_DIR)

# Special case for Qt::Gui, we are using the private headers...
ly_target_include_system_directories(TARGET Qt5::Gui
INTERFACE "${Qt5Gui_PRIVATE_INCLUDE_DIRS}"
)

# Another special case: Qt:Widgets, we are also using private headers
ly_target_include_system_directories(TARGET Qt5::Widgets
INTERFACE "${Qt5Widgets_PRIVATE_INCLUDE_DIRS}"
)

# Qt plugins/translations/aux files.
# We create libraries that wraps them so they get deployed properly.
# This used to be deployed through winqtdeploy/macqtdeploy, however, those tools
# are old and unmaintaned, macqtdeploy takes long times to run
add_library(3rdParty::Qt::Core::Translations INTERFACE IMPORTED GLOBAL)
file(GLOB tranlation_files ${QT_PATH}/translations/qt_*.qm)
if(tranlation_files)
ly_add_target_files(TARGETS 3rdParty::Qt::Core::Translations
FILES ${tranlation_files}
OUTPUT_SUBDIRECTORY translations
)
endif()
ly_add_dependencies(Qt5::Core 3rdParty::Qt::Core::Translations)

# plugins, each platform will define the files it has and the OUTPUT_SUBDIRECTORY
set(QT_PLUGINS
Network
Gui
Widgets
)
foreach(plugin ${QT_PLUGINS})
add_library(3rdParty::Qt::${plugin}::Plugins INTERFACE IMPORTED GLOBAL)
ly_add_dependencies(Qt5::${plugin} 3rdParty::Qt::${plugin}::Plugins)
endforeach()
include(${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}/QtPlugin_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)

# UIC executable
unset(QT_UIC_EXECUTABLE CACHE)
find_program(QT_UIC_EXECUTABLE uic HINTS "${QT_PATH}/bin")
mark_as_advanced(QT_UIC_EXECUTABLE) # Hiding from GUI

# RCC executable
unset(AUTORCC_EXECUTABLE CACHE)
find_program(AUTORCC_EXECUTABLE rcc HINTS "${QT_PATH}/bin")
mark_as_advanced(AUTORCC_EXECUTABLE) # Hiding from GUI
set(Qt5Core_RCC_EXECUTABLE "${AUTORCC_EXECUTABLE}" CACHE FILEPATH "Qt's resource compiler, used by qt5_add_resources" FORCE)
mark_as_advanced(Qt5Core_RCC_EXECUTABLE) # Hiding from GUI

# LRELEASE executable
unset(QT_LRELEASE_EXECUTABLE CACHE)
find_program(QT_LRELEASE_EXECUTABLE lrelease HINTS "${QT_PATH}/bin")
mark_as_advanced(QT_LRELEASE_EXECUTABLE) # Hiding from GUI
if(NOT QT_LRELEASE_EXECUTABLE)
message(FATAL_ERROR "Qt's lrelease executbale not found")
endif()
set(Qt5_LRELEASE_EXECUTABLE "${QT_LRELEASE_EXECUTABLE}" CACHE FILEPATH "Qt's lrelease executable, used by qt5_add_translation" FORCE)
mark_as_advanced(Qt5_LRELEASE_EXECUTABLE) # Hiding from GUI

#! ly_qt_uic_target: handles qt's ui files by injecting uic generation
#
# AUTOUIC has issues to detect changes in UIC files and trigger regeneration:
# https://gitlab.kitware.com/cmake/cmake/-/issues/18741
# So instead, we are going to manually wrap the files. We dont use qt5_wrap_ui because
# it outputs to ${CMAKE_CURRENT_BINARY_DIR}/ui_${outfile}.h and we want to follow the
# same folder structure that AUTOUIC uses
#
function(ly_qt_uic_target TARGET)

get_target_property(all_ui_sources ${TARGET} SOURCES)
list(FILTER all_ui_sources INCLUDE REGEX "^.*\\.ui$")
if(NOT all_ui_sources)
message(FATAL_ERROR "Target ${TARGET} contains AUTOUIC but doesnt have any .ui file")
endif()

if(AUTOGEN_BUILD_DIR)
set(gen_dir ${AUTOGEN_BUILD_DIR})
else()
set(gen_dir ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_autogen/include)
endif()

foreach(ui_source ${all_ui_sources})

get_filename_component(filename ${ui_source} NAME_WE)
get_filename_component(dir ${ui_source} DIRECTORY)
if(IS_ABSOLUTE ${dir})
file(RELATIVE_PATH dir ${CMAKE_CURRENT_SOURCE_DIR} ${dir})
endif()

set(outfolder ${gen_dir}/${dir})
set(outfile ${outfolder}/ui_${filename}.h)
get_filename_component(infile ${ui_source} ABSOLUTE)

file(MAKE_DIRECTORY ${outfolder})
add_custom_command(OUTPUT ${outfile}
COMMAND ${QT_UIC_EXECUTABLE} -o ${outfile} ${infile}
MAIN_DEPENDENCY ${infile} VERBATIM
COMMENT "UIC ${infile}"
)

set_source_files_properties(${infile} PROPERTIES SKIP_AUTOUIC TRUE)
set_source_files_properties(${outfile} PROPERTIES
SKIP_AUTOMOC TRUE
SKIP_AUTOUIC TRUE
GENERATED TRUE
)
list(APPEND all_ui_wrapped_sources ${outfile})

endforeach()

# Add files to the target
target_sources(${TARGET} PRIVATE ${all_ui_wrapped_sources})
source_group("Generated Files" FILES ${all_ui_wrapped_sources})

# Add include directories relative to the generated folder
# query for the property first to avoid the "NOTFOUND" in a list
get_property(has_includes TARGET ${TARGET} PROPERTY INCLUDE_DIRECTORIES SET)
if(has_includes)
get_property(all_include_directories TARGET ${TARGET} PROPERTY INCLUDE_DIRECTORIES)
foreach(dir ${all_include_directories})
if(IS_ABSOLUTE ${dir})
file(RELATIVE_PATH dir ${CMAKE_CURRENT_SOURCE_DIR} ${dir})
endif()
list(APPEND new_includes ${gen_dir}/${dir})
endforeach()
endif()
list(APPEND new_includes ${gen_dir})
target_include_directories(${TARGET} PRIVATE ${new_includes})

endfunction()

#! ly_add_translations: adds translations (ts) to a target.
#
# This wrapper will generate a qrc file with those translations and add the files under "prefix" and add them to
# the indicated targets. These files will be added under the "Generated Files" filter
#
# \arg:TARGETS name of the targets that the translations will be added to
# \arg:PREFIX prefix where the translation will be located within the qrc file
# \arg:FILES translation files to add
#
function(ly_add_translations)

set(options)
set(oneValueArgs PREFIX)
set(multiValueArgs TARGETS FILES)

cmake_parse_arguments(ly_add_translations "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

# Validate input arguments
if(NOT ly_add_translations_TARGETS)
message(FATAL_ERROR "You must provide at least one target")
endif()
if(NOT ly_add_translations_FILES)
message(FATAL_ERROR "You must provide at least a translation file")
endif()

qt5_add_translation(TRANSLATED_FILES ${ly_add_translations_FILES})

set(qrc_file_contents
"<RCC>
<qresource prefix=\"/${ly_add_translations_PREFIX}\">
")
foreach(file ${TRANSLATED_FILES})
get_filename_component(filename ${file} NAME)
string(APPEND qrc_file_contents " <file>${filename}</file>
")
endforeach()
string(APPEND qrc_file_contents " </qresource>
</RCC>
")
set(qrc_file_path ${CMAKE_CURRENT_BINARY_DIR}/i18n_${ly_add_translations_PREFIX}.qrc)
file(WRITE
${qrc_file_path}
${qrc_file_contents}
)
set_source_files_properties(
${TRANSLATED_FILES}
${qrc_file_path}
PROPERTIES
GENERATED TRUE
SKIP_AUTORCC TRUE
)
qt5_add_resources(RESOURCE_FILE ${qrc_file_path})

foreach(target ${ly_add_translations_TARGETS})
target_sources(${target} PRIVATE "${TRANSLATED_FILES};${qrc_file_path};${RESOURCE_FILE}")
endforeach()

endfunction()
18 changes: 0 additions & 18 deletions package-system/Qt/build-linux-aarch64.sh

This file was deleted.

18 changes: 0 additions & 18 deletions package-system/Qt/build-linux-x86.sh

This file was deleted.

Loading

0 comments on commit e653154

Please sign in to comment.