From 393c9d4a75569451c04a6e3e4a0477e70d52811a Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Sun, 22 Mar 2026 14:56:59 +0100 Subject: [PATCH 01/24] Add Docker-based analysis workflow Add clang-tidy support to the Docker browser build, capture compiler warnings into a separate report, and document the static analysis approach. Co-authored-by: Codex --- .clang-tidy | 20 ++++++ build-browser-docker.sh | 109 ++++++++++++++++++++++++++-- docs/docker-static-analysis.md | 118 +++++++++++++++++++++++++++++++ toolchains/qt5-static/Dockerfile | 3 + 4 files changed, 243 insertions(+), 7 deletions(-) create mode 100644 .clang-tidy create mode 100644 docs/docker-static-analysis.md diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..b1fb082 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,20 @@ +Checks: > + -*, + bugprone-assignment-in-if-condition, + bugprone-branch-clone, + bugprone-copy-constructor-init, + bugprone-inaccurate-erase, + bugprone-macro-parentheses, + bugprone-sizeof-expression, + bugprone-string-constructor, + modernize-redundant-void-arg, + modernize-use-bool-literals, + modernize-use-nullptr, + readability-duplicate-include, + readability-misleading-indentation, + readability-redundant-control-flow, + readability-simplify-boolean-expr, + readability-static-accessed-through-instance +WarningsAsErrors: '' +HeaderFilterRegex: '(^|.*/)src/.*' +FormatStyle: none diff --git a/build-browser-docker.sh b/build-browser-docker.sh index a197fee..33b472d 100755 --- a/build-browser-docker.sh +++ b/build-browser-docker.sh @@ -9,9 +9,25 @@ fail() { exit 1 } +usage() { + cat <<'EOF' +Usage: ./build-browser-docker.sh [options] + +Options: + --debug Build the debug browser variant + --analyze Build inside Docker and run clang-tidy + --analyze-only Alias for --analyze + --export-fixes Export YAML fix suggestions for clang-tidy + --help Show this help message +EOF +} + IMAGE_TAG="${IMAGE_TAG:-qtweb-qt5-static-poc:5.5.1}" JOBS="${JOBS:-$(nproc 2>/dev/null || echo 4)}" BUILD_TYPE="release" +RUN_ANALYSIS=0 +EXPORT_FIXES=0 +BUILD_DIR="" while [[ $# -gt 0 ]]; do case "$1" in @@ -19,6 +35,19 @@ while [[ $# -gt 0 ]]; do BUILD_TYPE="debug" shift ;; + --analyze|--analyze-only) + RUN_ANALYSIS=1 + shift + ;; + --export-fixes) + RUN_ANALYSIS=1 + EXPORT_FIXES=1 + shift + ;; + --help) + usage + exit 0 + ;; *) fail "unknown argument: $1" ;; @@ -27,8 +56,8 @@ done case "$BUILD_TYPE" in release|debug) - QT_PREFIX_IN_CONTAINER="/workspace/artifacts/qt5-static-5.5.1-${BUILD_TYPE}/install" - BUILD_DIR_IN_CONTAINER="build-docker-${BUILD_TYPE}" + QT_PREFIX_IN_CONTAINER="${REPO_ROOT}/artifacts/qt5-static-5.5.1-${BUILD_TYPE}/install" + BUILD_DIR="${REPO_ROOT}/build-docker-${BUILD_TYPE}" if [[ "$BUILD_TYPE" == "release" ]]; then QMAKE_CONFIG_ARGS="CONFIG+=release CONFIG-=debug" else @@ -43,19 +72,85 @@ esac docker run --rm \ -u "$(id -u):$(id -g)" \ -e JOBS="${JOBS}" \ + -e REPO_ROOT="${REPO_ROOT}" \ -e QT_PREFIX_IN_CONTAINER="${QT_PREFIX_IN_CONTAINER}" \ - -e BUILD_DIR_IN_CONTAINER="${BUILD_DIR_IN_CONTAINER}" \ + -e BUILD_DIR_IN_CONTAINER="${BUILD_DIR}" \ -e QMAKE_CONFIG_ARGS="${QMAKE_CONFIG_ARGS}" \ - -v "${REPO_ROOT}:/workspace" \ + -e EXPORT_FIXES="${EXPORT_FIXES}" \ -v "${REPO_ROOT}:${REPO_ROOT}" \ - -w /workspace \ + -e RUN_ANALYSIS="${RUN_ANALYSIS}" \ + -w "${REPO_ROOT}" \ "${IMAGE_TAG}" \ /bin/bash -lc ' set -euo pipefail + + fail() { + echo "error: $*" >&2 + exit 1 + } + + require_tool() { + command -v "$1" >/dev/null 2>&1 || fail "missing tool in image: $1" + } + + collect_gcc_warnings() { + local build_log="$1" + local warnings_report="$2" + grep -F "warning:" "${build_log}" > "${warnings_report}" || : + } + rm -rf "${BUILD_DIR_IN_CONTAINER}" mkdir -p "${BUILD_DIR_IN_CONTAINER}" cd "${BUILD_DIR_IN_CONTAINER}" "${QT_PREFIX_IN_CONTAINER}/bin/qmake" ../src/QtWeb.pro ${QMAKE_CONFIG_ARGS} - make -j"${JOBS}" - echo "built: /workspace/${BUILD_DIR_IN_CONTAINER}/QtWeb" + build_log="${BUILD_DIR_IN_CONTAINER}/build.log" + gcc_warnings_report="${BUILD_DIR_IN_CONTAINER}/gcc-warnings.txt" + + if [[ "${RUN_ANALYSIS}" == "1" ]]; then + require_tool bear + require_tool clang-tidy + clang_tidy_fixes="${BUILD_DIR_IN_CONTAINER}/clang-tidy-fixes.yaml" + clang_tidy_extra_args=() + + bear make -j"${JOBS}" 2>&1 | tee "${build_log}" + collect_gcc_warnings "${build_log}" "${gcc_warnings_report}" + + mapfile -t ANALYSIS_SOURCES < <(find "${REPO_ROOT}/src" -path "${REPO_ROOT}/src/qt" -prune -o -type f -name "*.cpp" -print | sort) + [[ "${#ANALYSIS_SOURCES[@]}" -gt 0 ]] || fail "no analysis sources found under ${REPO_ROOT}/src" + + if [[ "${EXPORT_FIXES}" == "1" ]]; then + rm -f "${clang_tidy_fixes}" + clang_tidy_extra_args+=(-export-fixes="${clang_tidy_fixes}") + fi + + if [[ "${#clang_tidy_extra_args[@]}" -gt 0 ]]; then + clang-tidy \ + -p "${BUILD_DIR_IN_CONTAINER}" \ + --header-filter="(^|.*/)src/.*" \ + "${clang_tidy_extra_args[@]}" \ + "${ANALYSIS_SOURCES[@]}" \ + > "${BUILD_DIR_IN_CONTAINER}/clang-tidy.txt" 2>&1 + else + clang-tidy \ + -p "${BUILD_DIR_IN_CONTAINER}" \ + --header-filter="(^|.*/)src/.*" \ + "${ANALYSIS_SOURCES[@]}" \ + > "${BUILD_DIR_IN_CONTAINER}/clang-tidy.txt" 2>&1 + fi + + echo "built: ${BUILD_DIR_IN_CONTAINER}/QtWeb" + echo "compile_commands: ${BUILD_DIR_IN_CONTAINER}/compile_commands.json" + echo "build log: ${build_log}" + echo "gcc warnings: ${gcc_warnings_report}" + echo "clang-tidy report: ${BUILD_DIR_IN_CONTAINER}/clang-tidy.txt" + if [[ "${EXPORT_FIXES}" == "1" ]]; then + echo "clang-tidy fixes: ${clang_tidy_fixes}" + fi + else + make -j"${JOBS}" 2>&1 | tee "${build_log}" + collect_gcc_warnings "${build_log}" "${gcc_warnings_report}" + echo "built: ${BUILD_DIR_IN_CONTAINER}/QtWeb" + echo "build log: ${build_log}" + echo "gcc warnings: ${gcc_warnings_report}" + fi ' diff --git a/docs/docker-static-analysis.md b/docs/docker-static-analysis.md new file mode 100644 index 0000000..740624a --- /dev/null +++ b/docs/docker-static-analysis.md @@ -0,0 +1,118 @@ +# Docker Static Analysis Plan + +## Summary +Integrate `clang-tidy` and `clazy` with the existing Docker build path for QtWeb instead of adding a separate ad hoc workflow. Docker remains the canonical environment for generating the browser build and `compile_commands.json`, and `build-browser-docker.sh` remains the main entrypoint for both browser builds and static-analysis runs. + +The first milestone is reproducible Docker-backed analysis plus a conservative cleanup wave for the hand-written QtWeb application code. The goal is to establish a stable baseline and reduce high-value findings without broad refactors or behavior changes. + +## Decisions +- Docker is the canonical build environment and the source of truth for the compilation database. +- Docker also runs `clang-tidy` so it stays on a toolchain version compatible with the Qt `5.5.1` headers in this repository. +- Host-installed `clazy-standalone` consumes the Docker-produced `compile_commands.json`. +- `build-browser-docker.sh` is the main entrypoint for Dockerized analysis. +- The initial scope is application code only: + - `src/*.cpp` + - `src/torrent/*.cpp` +- The first cleanup wave is conservative and focuses on low-risk fixes only. +- Smoke tests, extracted Qt sources, patch files, and generated build outputs are out of scope for the initial analyzer integration. + +## Required Tooling +The Docker image used for browser builds must provide: +- `bear` +- `clang` +- `clang-tidy` + +The host environment running `build-browser-docker.sh --analyze` must provide: +- `clazy-standalone` + +This keeps the build path aligned with Docker while avoiding two compatibility problems: +- Ubuntu `16.04` does not provide `clazy` from the default package repositories. +- the host `clang-tidy` available in this environment is too new for the Qt `5.5.1` headers used by this codebase. + +## Implementation Changes +Extend [`build-browser-docker.sh`](/home/magist3r/code/QtWeb/build-browser-docker.sh) with explicit analysis modes while preserving its current build behavior. + +Expected script behavior: +- `--debug` continues selecting the debug Docker build path. +- `--analyze` runs qmake, captures a compile database, and runs both analyzers. +- `--analyze-only` runs the analysis flow without keeping a separate build-only mode as the primary action. +- Optional convenience flags such as `--clang-tidy-only` or `--clazy-only` can be added if they remain simple and do not complicate the interface. + +Expected analysis flow: +1. Remove and recreate `build-docker-release` or `build-docker-debug` inside the Docker build run. +2. Run `qmake` exactly as the normal Docker build does today. +3. Run `bear -- make -j"${JOBS}"` in Docker to produce `compile_commands.json`. +4. During the container build run, execute `clang-tidy` against the scoped application sources using the generated compilation database. +5. After the container exits, run host `clazy-standalone` against the same source set using that Docker-produced compilation database. +6. Write reports into the Docker build directory so they remain visible in the repository. + +## Scope Boundaries +Included: +- hand-written browser sources in `src/` +- hand-written torrent sources in `src/torrent/` + +Excluded: +- `src/qt` +- `qt-patches/` +- smoke-test projects +- generated `moc/`, `rcc/`, `uic/`, and `qtweb_plugin_import.cpp` +- `artifacts/` +- existing `build-*` outputs except as analyzer working directories + +## Analyzer Policy +The initial analyzer configuration should be intentionally narrow and low-noise. + +Planned `clang-tidy` direction: +- conservative `readability-*` +- conservative `bugprone-*` +- simple `modernize-*` checks that do not force broad API churn + +Planned `clazy` direction: +- Qt-specific checks for clear API misuse +- temporary and container inefficiencies +- connect-related issues with obvious fixes + +The first cleanup wave should fix only findings that are clearly semantics-preserving, such as: +- dead includes +- unused locals +- redundant conditionals +- obvious Qt API misuse +- trivial temporary or container inefficiencies + +The first cleanup wave should not include: +- ownership refactors +- threading changes +- signal/slot behavior changes +- persistence or settings behavior changes +- broad stylistic rewrites + +## Outputs +Expected outputs in the selected Docker build directory: +- `build-docker-release/compile_commands.json` +- `build-docker-release/clang-tidy.txt` +- `build-docker-release/clazy.txt` +- corresponding debug variants when `--debug` is used + +Optional exported fixes files may be added if they remain clearly scoped and reviewable. + +## Validation +A successful first implementation should verify: +1. The Docker image contains `bear`, `clang`, and `clang-tidy`. +2. The host environment contains `clazy-standalone`. +3. `./build-browser-docker.sh --analyze` succeeds end to end. +4. `compile_commands.json` is generated in the selected Docker build directory. +5. The compile database contains representative entries for browser and torrent sources. +6. Both analyzer reports are written to the repository-local build directory. +7. After the first cleanup pass, the normal Docker build still succeeds. + +Representative validation files: +- `src/browsermainwindow.cpp` +- `src/networkaccessmanager.cpp` +- `src/torrent/torrentclient.cpp` + +## Risks +- Ubuntu `16.04` does not provide `clazy` from the default package repositories, so full in-image analyzer installation is not viable in the current base image. +- A host `clang-tidy` that is much newer than Qt `5.5.1` can fail inside Qt headers before project diagnostics are produced. +- Legacy Qt `5.5.1` code and its headers may produce noisy diagnostics if the enabled check set is too broad. +- Generated Qt sources can easily pollute analyzer output if the source list is not explicitly scoped. +- A zero-warning target is likely unrealistic for the first pass and would create unnecessary churn. diff --git a/toolchains/qt5-static/Dockerfile b/toolchains/qt5-static/Dockerfile index adc8f24..da9b652 100644 --- a/toolchains/qt5-static/Dockerfile +++ b/toolchains/qt5-static/Dockerfile @@ -6,9 +6,12 @@ ENV LANG=C.UTF-8 ENV LC_ALL=C.UTF-8 RUN apt-get update && apt-get install -y --no-install-recommends \ + bear \ bison \ build-essential \ ca-certificates \ + clang \ + clang-tidy \ curl \ file \ flex \ From c45e618dc3fd38f92890bb6baf41aac4ada42a8e Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Sun, 22 Mar 2026 15:13:57 +0100 Subject: [PATCH 02/24] Fix app-source GCC warnings Clear the remaining browser-source GCC warnings by removing unused locals and parameters, fixing constructor initialization order, and cleaning up small warning-triggering code patterns. The only warning left after validation comes from the bundled libqjp2 static library in the Qt toolchain, not from QtWeb sources. Co-authored-by: Codex --- src/bookmarks.cpp | 8 +++++++- src/bookmarks.h | 2 +- src/browserapplication.cpp | 9 +++++---- src/browsermainwindow.cpp | 33 +++++++++++++++------------------ src/downloadmanager.cpp | 5 +++-- src/exlineedit.cpp | 2 -- src/history.cpp | 6 +++--- src/networkaccessmanager.cpp | 4 ++-- src/settings.cpp | 6 +++++- src/tabwidget.cpp | 4 +++- src/toolbarsearch.cpp | 3 +-- src/webview.cpp | 6 ++++-- 12 files changed, 49 insertions(+), 39 deletions(-) diff --git a/src/bookmarks.cpp b/src/bookmarks.cpp index 0eab162..6986a2b 100644 --- a/src/bookmarks.cpp +++ b/src/bookmarks.cpp @@ -1261,6 +1261,8 @@ void BookmarksToolBar::build() void BookmarksToolBar::deleteBookmark(const QUrl &url, const QString &title) { + Q_UNUSED(url); + for (int i = 0; i < m_bookmarksModel->rowCount(m_root); ++i) { QModelIndex idx = m_bookmarksModel->index(i, 0, m_root); @@ -1280,6 +1282,8 @@ void BookmarksToolBar::deleteBookmark(const QUrl &url, const QString &title) void BookmarksToolBar::renameBookmark(const QUrl &url, const QString &title, const QString &new_title) { + Q_UNUSED(url); + for (int i = 0; i < m_bookmarksModel->rowCount(m_root); ++i) { QModelIndex idx = m_bookmarksModel->index(i, 0, m_root); @@ -1378,7 +1382,7 @@ void BookmarkToolButton::mouseMoveEvent(QMouseEvent *event) mimeData->setProperty( "move", QVariant(true)); drag->setMimeData(mimeData); - Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction); + drag->exec(Qt::CopyAction | Qt::MoveAction); QToolButton::mousePressEvent(event); } @@ -1406,6 +1410,8 @@ QUrl BookmarkToolButton::url() const void BookmarkToolButton::contextMenuRequested(const QPoint &pt) { + Q_UNUSED(pt); + QMenu menu; menu.addAction(tr("Open"), this, SLOT(openBookmark())); menu.addAction(tr("Open New Tab"), this, SLOT(openBookmarkNewTab())); diff --git a/src/bookmarks.h b/src/bookmarks.h index 95568ff..77e748a 100644 --- a/src/bookmarks.h +++ b/src/bookmarks.h @@ -180,7 +180,7 @@ public slots: BookmarkNode *node(const QModelIndex &index) const; QModelIndex index(BookmarkNode *node) const; - void sort ( int column, Qt::SortOrder order = Qt::AscendingOrder ) {;} + void sort ( int column, Qt::SortOrder order = Qt::AscendingOrder ) { Q_UNUSED(column); Q_UNUSED(order); } private: diff --git a/src/browserapplication.cpp b/src/browserapplication.cpp index 07583d0..59dad8e 100644 --- a/src/browserapplication.cpp +++ b/src/browserapplication.cpp @@ -195,7 +195,7 @@ void BrowserApplication::CheckSetTranslator() bool removeDir(const QString &dirName) { - bool result; + bool result = true; QDir dir(dirName); if (dir.exists()) { @@ -241,9 +241,10 @@ void BrowserApplication::definePortableRunMode() { // Copy settings from base template to temporary storage QDir temp_dir(QDir::temp()); - bool res = temp_dir.mkdir(settings.organizationName()); - res = temp_dir.cd(settings.organizationName()); - res = QFile::copy( settings.fileName(), temp_dir.absolutePath() + QDir::separator() + settings.applicationName() + ".ini" ); + temp_dir.mkdir(settings.organizationName()); + temp_dir.cd(settings.organizationName()); + QFile::copy(settings.fileName(), + temp_dir.absolutePath() + QDir::separator() + settings.applicationName() + ".ini"); // Change path to settings to the temp storage QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, QDir::temp().tempPath()); } diff --git a/src/browsermainwindow.cpp b/src/browsermainwindow.cpp index 04268f8..cb7201b 100644 --- a/src/browsermainwindow.cpp +++ b/src/browsermainwindow.cpp @@ -88,20 +88,24 @@ extern bool ShellExec(QString path); BrowserMainWindow::BrowserMainWindow(QWidget *parent, Qt::WindowFlags flags) : QMainWindow(parent, flags) - , m_tabWidget(new TabWidget(this)) , findWidget(0) - , m_navSplit(0) + , m_showMenuIcons(false) , m_buttonsBar(0) + , m_tabWidget(new TabWidget(this)) + , m_positionRestored(0) + , m_dumpActionQuit(false) + , m_navSplit(0) , m_historyBack(0) , m_historyForward(0) - , m_stop(0) - , m_reload(0) + , m_styles(0) , m_stylesMenu(0) , m_encodingMenu(0) - , m_styles(0) - , m_emptyDiskCache(0) + , m_sizesMenu(0) + , m_compMenu(0) + , m_stop(0) + , m_reload(0) , m_viewZoomTextOnly(0) - , m_positionRestored(0) + , m_emptyDiskCache(0) , m_goBackAction(0) , m_goForwardAction(0) , m_addBookmarkAction(0) @@ -113,26 +117,21 @@ BrowserMainWindow::BrowserMainWindow(QWidget *parent, Qt::WindowFlags flags) , m_resetAction(0) , m_enableInspector(0) , m_inspectElement(0) - , m_dumpActionQuit(false) - , m_showMenuIcons(false) , m_inspectAction(0) , m_keyboardAction(0) , m_textSizeAction(0) , m_bookmarksAction(0) - , m_sizesMenu(0) - , m_textSizeLarger(0) - , m_textSizeNormal(0) - , m_textSizeSmaller(0) - , m_compMenu(0) -// , m_compatMenu(0) , m_compatAction(0) , m_compIE(0) , m_compMozilla(0) - , m_compQtWeb(0) , m_compOpera(0) , m_compSafari(0) + , m_compQtWeb(0) , m_compChrome(0) , m_compCustom(0) + , m_textSizeLarger(0) + , m_textSizeNormal(0) + , m_textSizeSmaller(0) { setAttribute(Qt::WA_DeleteOnClose, true); statusBar()->setSizeGripEnabled(true); @@ -314,8 +313,6 @@ bool BrowserMainWindow::restoreState(const QByteArray &state) bool showStatusbar; bool showTabBarWhenOneTab; QByteArray splitterState1;//, splitterState2; - bool bMenu = true; - stream >> tabState; stream >> showTabBarWhenOneTab; diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index 8acfc8d..357d73a 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -87,9 +87,9 @@ QString DefaultDownloadPath(bool create_dir) DownloadItem::DownloadItem(QNetworkReply *reply, bool requestFileName, QWidget *parent) : QWidget(parent) , m_reply(reply) + , m_to_delete(false) , m_requestFileName(requestFileName) , m_bytesReceived(0) - , m_to_delete(false) , m_finished(false) { setupUi(this); @@ -246,6 +246,7 @@ void DownloadItem::stop() void DownloadItem::mouseDoubleClickEvent ( QMouseEvent * event ) { + Q_UNUSED(event); open(); } @@ -502,6 +503,7 @@ DownloadManager::~DownloadManager() void DownloadManager::openItem(const QModelIndex& index) { + Q_UNUSED(index); } int DownloadManager::activeDownloads() const @@ -838,4 +840,3 @@ bool DownloadModel::removeRows(int row, int count, const QModelIndex &parent) m_downloadManager->save(); return true; } - diff --git a/src/exlineedit.cpp b/src/exlineedit.cpp index afcc4e0..7d341bb 100644 --- a/src/exlineedit.cpp +++ b/src/exlineedit.cpp @@ -79,7 +79,6 @@ void ClearButton::paintEvent(QPaintEvent *event) int height = this->height(); painter.setRenderHint(QPainter::Antialiasing, true); - QColor color = palette().color(QPalette::Midlight); painter.setBrush(isDown() ? palette().color(QPalette::Mid) : palette().color(QPalette::Midlight)); @@ -328,4 +327,3 @@ void ExLineEdit::paintEvent(QPaintEvent *) style()->drawPrimitive(QStyle::PE_PanelLineEdit, &panel, &p, this); } - diff --git a/src/history.cpp b/src/history.cpp index f35f0ad..ddefe73 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -69,10 +69,10 @@ HistoryManager::HistoryManager(QObject *parent) : QWebHistoryInterface(parent) , m_saveTimer(new AutoSaver(this)) , m_historyLimit(7) + , m_historyCleaned(false) , m_historyModel(0) , m_historyFilterModel(0) , m_historyTreeModel(0) - , m_historyCleaned(false) { m_expiredTimer.setSingleShot(true); connect(&m_expiredTimer, SIGNAL(timeout()), @@ -534,7 +534,7 @@ int HistoryMenuModel::rowCount(const QModelIndex &parent) const return bumpedItems + folders; } - if (parent.internalId() == -1) { + if (parent.internalId() == quintptr(-1)) { if (parent.row() < bumpedRows()) return 0; } @@ -559,7 +559,7 @@ QModelIndex HistoryMenuModel::mapToSource(const QModelIndex &proxyIndex) const if (!proxyIndex.isValid()) return QModelIndex(); - if (proxyIndex.internalId() == -1) { + if (proxyIndex.internalId() == quintptr(-1)) { int bumpedItems = bumpedRows(); if (proxyIndex.row() < bumpedItems) return m_treeModel->index(proxyIndex.row(), proxyIndex.column(), m_treeModel->index(0, 0)); diff --git a/src/networkaccessmanager.cpp b/src/networkaccessmanager.cpp index 16a7eb4..507a9dd 100644 --- a/src/networkaccessmanager.cpp +++ b/src/networkaccessmanager.cpp @@ -75,8 +75,8 @@ NetworkAccessManager::NetworkAccessManager(QObject *parent) : QNetworkAccessManager(parent) , m_useProxy(false) , m_proxyExceptions(0) - , m_adBlockEx(0) , m_adBlock(0) + , m_adBlockEx(0) { connect(this, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); @@ -424,4 +424,4 @@ bool NetworkAccessManager::isUrlProxyException(const QUrl& url) return false; } -//HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ +// HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings diff --git a/src/settings.cpp b/src/settings.cpp index efbfc08..3122e5a 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -729,6 +729,8 @@ void SettingsDialog::warnLangChange(int) void SettingsDialog::setAppStyle(int index) { + Q_UNUSED(index); + QString style = comboBoxStyle->currentText(); QApplication::setStyle(QStyleFactory::create(style)); } @@ -869,7 +871,9 @@ void SettingsDialog::removeBlockAdEx() void SettingsDialog::addBlockItems(const QLatin1String& filename, QListWidget* listview) { QFile file(filename); - bool isOpened = file.open(QIODevice::ReadOnly | QIODevice::Text); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return; + QString all = QString(QLatin1String(file.readAll())); file.close(); QStringList lst = all.split("\n"); diff --git a/src/tabwidget.cpp b/src/tabwidget.cpp index 8298de4..3461455 100644 --- a/src/tabwidget.cpp +++ b/src/tabwidget.cpp @@ -74,9 +74,9 @@ TabWidget::TabWidget(QWidget *parent) , m_nextTabAction(0) , m_previousTabAction(0) , m_recentlyClosedTabsMenu(0) - , m_lineEdits(0) , m_prevSelectedTab(-1) , m_prevSelectedTabMark(-1) + , m_lineEdits(0) , m_tabBar(new TabBar(this)) { setElideMode(Qt::ElideRight); @@ -644,6 +644,8 @@ void TabWidget::webViewIconChanged() void TabWidget::webViewLoadFinished(bool ok) { + Q_UNUSED(ok); + WebView *webView = qobject_cast(sender()); int index = webViewIndex(webView); if (-1 != index) diff --git a/src/toolbarsearch.cpp b/src/toolbarsearch.cpp index 8fdbb13..8c71e90 100644 --- a/src/toolbarsearch.cpp +++ b/src/toolbarsearch.cpp @@ -360,7 +360,7 @@ void ToolbarSearch::addSearches() settings.endGroup(); } - QAction* searches = m->addAction(tr("Add..."), this, SLOT(addSearch())); + m->addAction(tr("Add..."), this, SLOT(addSearch())); } void ToolbarSearch::addSearch() @@ -411,4 +411,3 @@ void ToolbarSearch::clear() m_stringListModel->setStringList(QStringList()); save(); } - diff --git a/src/webview.cpp b/src/webview.cpp index e205fce..40b533b 100644 --- a/src/webview.cpp +++ b/src/webview.cpp @@ -66,10 +66,10 @@ WebView::WebView(QWidget* parent) : QWebView(parent) , m_progress(0) - , m_page(new WebPage(this)) - , m_font_resizing(false) , m_is_loading(false) , m_gestureStarted(false) + , m_page(new WebPage(this)) + , m_font_resizing(false) , m_encoding_in_progress(false) , m_ssl_errors_detected(false) , m_linkUnderCursor(false) @@ -748,6 +748,8 @@ void WebView::loadFtpUrl(const QUrl &url) void WebView::ftpDownloadFile(const QUrl &url, QString fileName ) { + Q_UNUSED(url); + if (!m_ftp) return; From 15940b26b263e01f5257e3275d4eaed1029250d4 Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Sun, 22 Mar 2026 16:26:08 +0100 Subject: [PATCH 03/24] Fix low-risk clang-tidy findings Co-authored-by: Codex --- .clang-tidy | 3 --- src/bookmarks.cpp | 8 +++++--- src/bookmarksimport.cpp | 5 +---- src/commands.cpp | 4 ++-- src/downloadmanager.cpp | 9 +++++++-- src/googlesuggest.cpp | 8 +++----- src/history.cpp | 4 +--- src/tabwidget.cpp | 3 +-- src/torrent/torrentclient.cpp | 6 ++++-- src/webview.cpp | 21 ++++++++++++++------- 10 files changed, 38 insertions(+), 33 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index b1fb082..cad446f 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -9,12 +9,9 @@ Checks: > bugprone-string-constructor, modernize-redundant-void-arg, modernize-use-bool-literals, - modernize-use-nullptr, readability-duplicate-include, readability-misleading-indentation, readability-redundant-control-flow, readability-simplify-boolean-expr, readability-static-accessed-through-instance -WarningsAsErrors: '' HeaderFilterRegex: '(^|.*/)src/.*' -FormatStyle: none diff --git a/src/bookmarks.cpp b/src/bookmarks.cpp index 6986a2b..ea237cb 100644 --- a/src/bookmarks.cpp +++ b/src/bookmarks.cpp @@ -656,14 +656,16 @@ int BookmarksModel::columnCount(const QModelIndex &parent) const int BookmarksModel::rowCount(const QModelIndex &parent) const { + BookmarkNode *bookmarksRoot = m_bookmarksManager ? m_bookmarksManager->bookmarks() : 0; + if (parent.column() > 0) return 0; if (!parent.isValid()) - return m_bookmarksManager->bookmarks()->children().count(); + return bookmarksRoot ? bookmarksRoot->children().count() : 0; const BookmarkNode *item = static_cast(parent.internalPointer()); - return item->children().count(); + return item ? item->children().count() : 0; } QModelIndex BookmarksModel::index(int row, int column, const QModelIndex &parent) const @@ -836,7 +838,7 @@ BookmarkNode *BookmarksModel::node(const QModelIndex &index) const { BookmarkNode *itemNode = static_cast(index.internalPointer()); if (!itemNode) - return m_bookmarksManager->bookmarks(); + return m_bookmarksManager ? m_bookmarksManager->bookmarks() : 0; return itemNode; } diff --git a/src/bookmarksimport.cpp b/src/bookmarksimport.cpp index a90d18f..4c271fb 100644 --- a/src/bookmarksimport.cpp +++ b/src/bookmarksimport.cpp @@ -258,9 +258,6 @@ void ParseHtmlBookmarks( QString& books , BookmarkNode* root) BookmarkNode *BookmarksImport::importFromHtml( QString path ) { - BookmarkNode* root = new BookmarkNode(); - - QFile f(path); if (!f.open(QIODevice::ReadOnly | QIODevice::Text) ) return NULL; @@ -288,6 +285,7 @@ BookmarkNode *BookmarksImport::importFromHtml( QString path ) return NULL; } + BookmarkNode* root = new BookmarkNode(); QString books; QByteArray ba; bool bUtf8 = false; @@ -328,4 +326,3 @@ BookmarkNode *BookmarksImport::importFromHtml( QString path ) return root; } - diff --git a/src/commands.cpp b/src/commands.cpp index 190b31d..62021b6 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -21,12 +21,12 @@ #include -MenuCommands::MenuCommands(void) +MenuCommands::MenuCommands() { m_data.beginGroup(QLatin1String("MenuCommands")); } -MenuCommands::~MenuCommands(void) +MenuCommands::~MenuCommands() { m_data.endGroup(); } diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index 357d73a..fc994c5 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -826,8 +826,13 @@ bool DownloadModel::removeRows(int row, int count, const QModelIndex &parent) || m_downloadManager->m_downloads.at(i)->tryAgainButton->isEnabled()) { beginRemoveRows(parent, i, i); DownloadItem* item = m_downloadManager->m_downloads.takeAt(i); - - if (item && item->m_output.exists()) + + if (!item) { + endRemoveRows(); + continue; + } + + if (item->m_output.exists()) { if (item->m_must_be_deleted) item->m_output.remove(); diff --git a/src/googlesuggest.cpp b/src/googlesuggest.cpp index d68cce0..952d235 100644 --- a/src/googlesuggest.cpp +++ b/src/googlesuggest.cpp @@ -152,19 +152,17 @@ bool GSuggestCompletion::eventFilter(QObject *obj, QEvent *ev) } if (ev->type() == QEvent::KeyPress) { - - bool consumed = false; int key = static_cast(ev)->key(); switch (key) { case Qt::Key_Enter: case Qt::Key_Return: doneCompletion(); - consumed = true; + return true; case Qt::Key_Escape: editor->setFocus(); popup->hide(); - consumed = true; + return true; case Qt::Key_Up: case Qt::Key_Down: @@ -181,7 +179,7 @@ bool GSuggestCompletion::eventFilter(QObject *obj, QEvent *ev) break; } - return consumed; + return false; } return false; diff --git a/src/history.cpp b/src/history.cpp index ddefe73..b636560 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -1174,9 +1174,7 @@ QModelIndex HistoryTreeModel::parent(const QModelIndex &index) const bool HistoryTreeModel::hasChildren(const QModelIndex &parent) const { QModelIndex grandparent = parent.parent(); - if (!grandparent.isValid()) - return true; - return false; + return !grandparent.isValid(); } Qt::ItemFlags HistoryTreeModel::flags(const QModelIndex &index) const diff --git a/src/tabwidget.cpp b/src/tabwidget.cpp index 3461455..23af023 100644 --- a/src/tabwidget.cpp +++ b/src/tabwidget.cpp @@ -446,8 +446,7 @@ WebView *TabWidget::newTab(bool makeCurrent, bool empty) case 0: // welcome page { QFile file(QLatin1String(":/Welcome.html")); - bool isOpened = file.open(QIODevice::ReadOnly | QIODevice::Text); - Q_ASSERT(isOpened); + Q_ASSERT(file.open(QIODevice::ReadOnly | QIODevice::Text)); QString html = QString(QLatin1String(file.readAll())); QPixmap pix= style()->standardIcon(QStyle::SP_MessageBoxInformation).pixmap(32,32); diff --git a/src/torrent/torrentclient.cpp b/src/torrent/torrentclient.cpp index 4ac8166..119623a 100644 --- a/src/torrent/torrentclient.cpp +++ b/src/torrent/torrentclient.cpp @@ -583,7 +583,8 @@ void TorrentClient::sendToPeer(int readId, int pieceIndex, int begin, const QByt // Send the requested block to the peer if the client connection // still exists; otherwise do nothing. This slot is called by the // file manager after it has read a block of data. - PeerWireClient *client = d->readIds.value(readId); + QMap::const_iterator it = d->readIds.constFind(readId); + PeerWireClient *client = (it != d->readIds.constEnd()) ? it.value() : 0; if (client) { if ((client->peerWireState() & PeerWireClient::ChokingPeer) == 0) client->sendBlock(pieceIndex, begin, data); @@ -638,7 +639,8 @@ void TorrentClient::fullVerificationDone() void TorrentClient::pieceVerified(int pieceIndex, bool ok) { - TorrentPiece *piece = d->pendingPieces.value(pieceIndex); + QMap::const_iterator pieceIt = d->pendingPieces.constFind(pieceIndex); + TorrentPiece *piece = (pieceIt != d->pendingPieces.constEnd()) ? pieceIt.value() : 0; // Remove this piece from all payloads QMultiMap::Iterator it = d->payloads.begin(); diff --git a/src/webview.cpp b/src/webview.cpp index 40b533b..c8f87f2 100644 --- a/src/webview.cpp +++ b/src/webview.cpp @@ -522,16 +522,16 @@ void WebView::mouseReleaseEvent(QMouseEvent *event) if (difY > 0 && (difX == 0 || abs(difY / difX) >= 2)) down = true; else - if (difX < 0 && difY < 0 && abs(difX / difY) < 2 && abs((float)difX / (float)difY) > 0.5) + if (difX < 0 && difY < 0 && abs(difX / difY) < 2 && qAbs((float)difX / (float)difY) > 0.5) upper_left = true; else - if (difX > 0 && difY < 0 && abs(difX / difY) < 2 && abs((float)difX / (float)difY) > 0.5) + if (difX > 0 && difY < 0 && abs(difX / difY) < 2 && qAbs((float)difX / (float)difY) > 0.5) upper_right = true; else - if (difX > 0 && difY > 0 && abs(difX / difY) < 2 && abs((float)difX / (float)difY) > 0.5) + if (difX > 0 && difY > 0 && abs(difX / difY) < 2 && qAbs((float)difX / (float)difY) > 0.5) down_right = true; else - if (difX < 0 && difY > 0 && abs(difX / difY) < 2 && abs((float)difX / (float)difY) > 0.5) + if (difX < 0 && difY > 0 && abs(difX / difY) < 2 && qAbs((float)difX / (float)difY) > 0.5) down_left = true; if (left) @@ -849,19 +849,26 @@ void WebView::ftpCommandFinished(int res, bool error) if (m_ftp->currentCommand() == QFtp::Get) { + if (!m_ftpFile) { + m_ftpProgressDialog->hide(); + urlChanged(m_initialUrl); + return; + } + + const QString ftpFileName = m_ftpFile->fileName(); if (error) { - setStatusBarText(tr("Canceled download of %1").arg(m_ftpFile->fileName())); + setStatusBarText(tr("Canceled download of %1").arg(ftpFileName)); m_ftpFile->close(); m_ftpFile->remove(); } else { DownloadManager* dm = BrowserApplication::downloadManager(); - setStatusBarText(tr("Successfully downloaded file %1").arg(m_ftpFile->fileName())); + setStatusBarText(tr("Successfully downloaded file %1").arg(ftpFileName)); m_ftpFile->close(); - dm->addItem(m_initialUrl, m_ftpFile->fileName(), true ); + dm->addItem(m_initialUrl, ftpFileName, true ); } delete m_ftpFile; m_ftpFile = nullptr; From 26cbda6b544b67d147375f33ba26b634289bbb42 Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Sun, 22 Mar 2026 17:16:05 +0100 Subject: [PATCH 04/24] Apply clang-tidy nullptr modernization Co-authored-by: Codex --- .clang-tidy | 1 + src/aboutdialog.h | 2 +- src/autocomplete.cpp | 4 +- src/bookmarks.cpp | 46 +++++++++---------- src/bookmarks.h | 16 +++---- src/bookmarksimport.cpp | 8 ++-- src/browserapplication.cpp | 20 ++++----- src/browserapplication.h | 4 +- src/browsermainwindow.cpp | 84 +++++++++++++++++------------------ src/browsermainwindow.h | 2 +- src/certificateinfo.h | 2 +- src/chasewidget.h | 2 +- src/closeapp.h | 2 +- src/cookiejar.h | 10 ++--- src/downloadmanager.cpp | 8 ++-- src/downloadmanager.h | 6 +-- src/edittableview.h | 2 +- src/edittreeview.h | 2 +- src/exlineedit.cpp | 4 +- src/exlineedit.h | 6 +-- src/findwidget.h | 2 +- src/googlesuggest.h | 2 +- src/history.cpp | 8 ++-- src/history.h | 18 ++++---- src/modelmenu.cpp | 2 +- src/modelmenu.h | 4 +- src/networkaccessmanager.cpp | 18 ++++---- src/networkaccessmanager.h | 4 +- src/passwords.h | 2 +- src/resetsettings.h | 2 +- src/savepdf.h | 2 +- src/searchlineedit.cpp | 4 +- src/searchlineedit.h | 2 +- src/settings.h | 2 +- src/shortcuts.cpp | 2 +- src/squeezelabel.h | 2 +- src/tabbar.cpp | 10 ++--- src/tabbar.h | 2 +- src/tabwidget.cpp | 31 +++++++------ src/tabwidget.h | 2 +- src/toolbarsearch.cpp | 4 +- src/toolbarsearch.h | 2 +- src/torrent/torrentclient.cpp | 4 +- src/torrent/torrentserver.cpp | 2 +- src/urllineedit.cpp | 6 +-- src/urllineedit.h | 2 +- src/webpage.cpp | 4 +- src/webpage.h | 2 +- src/webview.h | 2 +- src/xbel.cpp | 4 +- src/xbel.h | 2 +- 51 files changed, 195 insertions(+), 191 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index cad446f..be60c44 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -9,6 +9,7 @@ Checks: > bugprone-string-constructor, modernize-redundant-void-arg, modernize-use-bool-literals, + modernize-use-nullptr, readability-duplicate-include, readability-misleading-indentation, readability-redundant-control-flow, diff --git a/src/aboutdialog.h b/src/aboutdialog.h index 504cb94..260480f 100644 --- a/src/aboutdialog.h +++ b/src/aboutdialog.h @@ -54,7 +54,7 @@ class AboutDialog : public QDialog, private Ui_AboutDialog Q_OBJECT public: - AboutDialog(QWidget *parent = 0); + AboutDialog(QWidget *parent = nullptr); protected slots: void credits(); diff --git a/src/autocomplete.cpp b/src/autocomplete.cpp index 235f032..a473dee 100644 --- a/src/autocomplete.cpp +++ b/src/autocomplete.cpp @@ -307,10 +307,10 @@ bool AutoComplete::complete( QWebFrame * frame) return false; started = true; - QString pwd = QInputDialog::getText( 0, tr("Master Password"), tr("Type a master password:"), QLineEdit::Password); + QString pwd = QInputDialog::getText( nullptr, tr("Master Password"), tr("Type a master password:"), QLineEdit::Password); if ( pwd != DecryptPassword(master)) { - QMessageBox::warning(0, tr("Warning"), tr("Invalid password")); + QMessageBox::warning(nullptr, tr("Warning"), tr("Invalid password")); started = false; return false; } diff --git a/src/bookmarks.cpp b/src/bookmarks.cpp index ea237cb..81af3f7 100644 --- a/src/bookmarks.cpp +++ b/src/bookmarks.cpp @@ -68,8 +68,8 @@ BookmarksManager::BookmarksManager(QObject *parent) : QObject(parent) , m_loaded(false) , m_saveTimer(new AutoSaver(this)) - , m_bookmarkRootNode(0) - , m_bookmarkModel(0) + , m_bookmarkRootNode(nullptr) + , m_bookmarkModel(nullptr) { connect(this, SIGNAL(entryAdded(BookmarkNode *)), m_saveTimer, SLOT(changeOccurred())); @@ -107,13 +107,13 @@ void BookmarksManager::load() XbelReader reader; m_bookmarkRootNode = reader.read(bookmarkFile); if (reader.error() != QXmlStreamReader::NoError) { - QMessageBox::warning(0, tr("Loading Bookmark"), + QMessageBox::warning(nullptr, tr("Loading Bookmark"), tr("Error when loading bookmarks on line %1, column %2:\n" "%3").arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString())); } - BookmarkNode *toolbar = 0; - BookmarkNode *menu = 0; + BookmarkNode *toolbar = nullptr; + BookmarkNode *menu = nullptr; QList others; for (int i = m_bookmarkRootNode->children().count() - 1; i >= 0; --i) { @@ -268,7 +268,7 @@ BookmarkNode *BookmarksManager::menu() return node; } Q_ASSERT(false); - return 0; + return nullptr; } BookmarkNode *BookmarksManager::toolbar() @@ -282,7 +282,7 @@ BookmarkNode *BookmarksManager::toolbar() return node; } Q_ASSERT(false); - return 0; + return nullptr; } QStringList BookmarksManager::find_tag_urls(BookmarkNode *start_node, const QString& tag) { @@ -339,7 +339,7 @@ BookmarkNode *BookmarksManager::find_folder(BookmarkNode *start_node,const QStri return found_node; } } - return 0; + return nullptr; } BookmarksModel *BookmarksManager::bookmarksModel() @@ -357,7 +357,7 @@ void BookmarksManager::importFromIE() importRootNode->setType(BookmarkNode::Folder); importRootNode->title = (tr("Imported %1 from Internet Explorer").arg(QDate::currentDate().toString(Qt::SystemLocaleShortDate))); addBookmark(menu(), importRootNode); - QMessageBox::information(0, tr("Importing Bookmarks"), + QMessageBox::information(nullptr, tr("Importing Bookmarks"), tr("Successfully imported Microsoft Internet Explorer favorites.")); } } @@ -367,7 +367,7 @@ void BookmarksManager::importFromMozilla() QString path = BookmarksImport::mozillaPath(); if (path.isEmpty()) { - QMessageBox::warning(0, tr("Importing Bookmarks"), + QMessageBox::warning(nullptr, tr("Importing Bookmarks"), tr("Mozilla FireFox local profile location is not found.
Please find and import BOOKMARKS.HTML file manually.")); return; } @@ -377,14 +377,14 @@ void BookmarksManager::importFromMozilla() importRootNode->setType(BookmarkNode::Folder); importRootNode->title = (tr("Imported %1 from Mozilla FireFox").arg(QDate::currentDate().toString(Qt::SystemLocaleShortDate))); addBookmark(menu(), importRootNode); - QMessageBox::information(0, tr("Importing Bookmarks"), + QMessageBox::information(nullptr, tr("Importing Bookmarks"), tr("Successfully imported Mozilla FireFox bookmarks.")); } } void BookmarksManager::importFromHTML() { - QString fileName = QFileDialog::getOpenFileName(0, tr("Open File"), + QString fileName = QFileDialog::getOpenFileName(nullptr, tr("Open File"), QString(), tr("Netscape HTML Bookmarks (*.html;*.htm)")); if (fileName.isEmpty()) @@ -397,14 +397,14 @@ void BookmarksManager::importFromHTML() importRootNode->setType(BookmarkNode::Folder); importRootNode->title = (tr("Imported %1 from HTML").arg(QDate::currentDate().toString(Qt::SystemLocaleShortDate))); addBookmark(menu(), importRootNode); - QMessageBox::information(0, tr("Importing Bookmarks"), + QMessageBox::information(nullptr, tr("Importing Bookmarks"), tr("Successfully imported bookmarks from Netscape defined HTML file.")); } } void BookmarksManager::importBookmarks() { - QString fileName = QFileDialog::getOpenFileName(0, tr("Open File"), + QString fileName = QFileDialog::getOpenFileName(nullptr, tr("Open File"), QString(), tr("XBEL (*.xbel *.xml)")); if (fileName.isEmpty()) @@ -413,7 +413,7 @@ void BookmarksManager::importBookmarks() XbelReader reader; BookmarkNode *importRootNode = reader.read(fileName); if (reader.error() != QXmlStreamReader::NoError) { - QMessageBox::warning(0, tr("Loading Bookmark"), + QMessageBox::warning(nullptr, tr("Loading Bookmark"), tr("Error when loading bookmarks on line %1, column %2:\n" "%3").arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString())); } @@ -425,7 +425,7 @@ void BookmarksManager::importBookmarks() void BookmarksManager::exportBookmarks() { - QString fileName = QFileDialog::getSaveFileName(0, tr("Save File"), + QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Save File"), QString("%1 Bookmarks.xbel").arg(QCoreApplication::applicationName()), QString("XBEL (*.xbel *.xml)")); if (fileName.isEmpty()) @@ -433,7 +433,7 @@ void BookmarksManager::exportBookmarks() XbelWriter writer; if (!writer.write(fileName, m_bookmarkRootNode)) - QMessageBox::critical(0, tr("Export error"), tr("error saving bookmarks")); + QMessageBox::critical(nullptr, tr("Export error"), tr("error saving bookmarks")); } RemoveBookmarksCommand::RemoveBookmarksCommand(BookmarksManager *m_bookmarkManagaer, BookmarkNode *parent, int row) @@ -656,7 +656,7 @@ int BookmarksModel::columnCount(const QModelIndex &parent) const int BookmarksModel::rowCount(const QModelIndex &parent) const { - BookmarkNode *bookmarksRoot = m_bookmarksManager ? m_bookmarksManager->bookmarks() : 0; + BookmarkNode *bookmarksRoot = m_bookmarksManager ? m_bookmarksManager->bookmarks() : nullptr; if (parent.column() > 0) return 0; @@ -684,7 +684,7 @@ QModelIndex BookmarksModel::parent(const QModelIndex &index) const return QModelIndex(); BookmarkNode *itemNode = node(index); - BookmarkNode *parentNode = (itemNode ? itemNode->parent() : 0); + BookmarkNode *parentNode = (itemNode ? itemNode->parent() : nullptr); if (!parentNode || parentNode == m_bookmarksManager->bookmarks()) return QModelIndex(); @@ -838,7 +838,7 @@ BookmarkNode *BookmarksModel::node(const QModelIndex &index) const { BookmarkNode *itemNode = static_cast(index.internalPointer()); if (!itemNode) - return m_bookmarksManager ? m_bookmarksManager->bookmarks() : 0; + return m_bookmarksManager ? m_bookmarksManager->bookmarks() : nullptr; return itemNode; } @@ -889,7 +889,7 @@ AddBookmarkDialog::AddBookmarkDialog(const QString &url, const QString &title, c settings.beginGroup(QLatin1String("websettings")); if (!m_default_folder.isEmpty()) { - BookmarkNode* folder = m_bookmarksManager->find_folder(NULL, m_default_folder); + BookmarkNode* folder = m_bookmarksManager->find_folder(nullptr, m_default_folder); if (folder) { QModelIndex ix = m_proxyModel->mapFromSource(model->index(folder)); @@ -950,7 +950,7 @@ void AddBookmarkDialog::acceptDefaultLocation() BookmarksMenu::BookmarksMenu(QWidget *parent) : ModelMenu(parent) - , m_bookmarksManager(0) + , m_bookmarksManager(nullptr) { connect(this, SIGNAL(activated(const QModelIndex &)), this, SLOT(activated(const QModelIndex &))); @@ -1154,7 +1154,7 @@ void BookmarksToolBar::dropEvent(QDropEvent *event) { QList urls = mimeData->urls(); int row = -1; - BookmarkNode * del_node = NULL; + BookmarkNode * del_node = nullptr; QModelIndex parentIndex = m_root; if( mimeData->hasText()) { diff --git a/src/bookmarks.h b/src/bookmarks.h index 77e748a..9b01092 100644 --- a/src/bookmarks.h +++ b/src/bookmarks.h @@ -45,7 +45,7 @@ class BookmarksManager : public QObject void entryChanged(BookmarkNode *item); public: - BookmarksManager(QObject *parent = 0); + BookmarksManager(QObject *parent = nullptr); ~BookmarksManager(); void addBookmark(BookmarkNode *parent, BookmarkNode *node, int row = -1); @@ -159,7 +159,7 @@ public slots: SeparatorRole = Qt::UserRole + 4 }; - BookmarksModel(BookmarksManager *bookmarkManager, QObject *parent = 0); + BookmarksModel(BookmarksManager *bookmarkManager, QObject *parent = nullptr); inline BookmarksManager *bookmarksManager() const { return m_bookmarksManager; } QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; @@ -198,7 +198,7 @@ class BookmarksMenu : public ModelMenu void openUrl(const QUrl &url); public: - BookmarksMenu(QWidget *parent = 0); + BookmarksMenu(QWidget *parent = nullptr); void setInitialActions(QList actions); protected: @@ -221,7 +221,7 @@ class AddBookmarkProxyModel : public QSortFilterProxyModel { Q_OBJECT public: - AddBookmarkProxyModel(QObject * parent = 0); + AddBookmarkProxyModel(QObject * parent = nullptr); int columnCount(const QModelIndex & parent = QModelIndex()) const; protected: @@ -237,7 +237,7 @@ class AddBookmarkDialog : public QDialog, public Ui_AddBookmarkDialog Q_OBJECT public: - AddBookmarkDialog(const QString &url, const QString &title, const QString& default_folder, QWidget *parent = 0, BookmarksManager *bookmarkManager = 0); + AddBookmarkDialog(const QString &url, const QString &title, const QString& default_folder, QWidget *parent = nullptr, BookmarksManager *bookmarkManager = nullptr); void acceptDefaultLocation(); private slots: @@ -260,7 +260,7 @@ class BookmarksDialog : public QDialog, public Ui_BookmarksDialog void openUrl(const QUrl &url); public: - BookmarksDialog(QWidget *parent = 0, BookmarksManager *manager = 0); + BookmarksDialog(QWidget *parent = nullptr, BookmarksManager *manager = nullptr); ~BookmarksDialog(); private slots: @@ -290,7 +290,7 @@ class BookmarksToolBar : public QToolBar void openUrl(const QUrl &url); public: - BookmarksToolBar(BookmarksModel *model, QWidget *parent = 0); + BookmarksToolBar(BookmarksModel *model, QWidget *parent = nullptr); void setRootIndex(const QModelIndex &index); QModelIndex rootIndex() const; @@ -333,7 +333,7 @@ public slots: void addFolder(); public: - BookmarkToolButton(QUrl url, QWidget *parent = 0); + BookmarkToolButton(QUrl url, QWidget *parent = nullptr); QUrl url() const; protected: diff --git a/src/bookmarksimport.cpp b/src/bookmarksimport.cpp index 4c271fb..7fdd966 100644 --- a/src/bookmarksimport.cpp +++ b/src/bookmarksimport.cpp @@ -134,7 +134,7 @@ BookmarkNode *BookmarksImport::importFromIE() { QString path = ieFavoritesPath(); if (path.isEmpty()) - return NULL; + return nullptr; BookmarkNode* root = new BookmarkNode(); @@ -260,7 +260,7 @@ BookmarkNode *BookmarksImport::importFromHtml( QString path ) { QFile f(path); if (!f.open(QIODevice::ReadOnly | QIODevice::Text) ) - return NULL; + return nullptr; bool bIsNetscape = false; // check format @@ -280,9 +280,9 @@ BookmarkNode *BookmarksImport::importFromHtml( QString path ) { // Format not supported f.close(); - QMessageBox::warning(0, QObject::tr("Importing Bookmarks"), + QMessageBox::warning(nullptr, QObject::tr("Importing Bookmarks"), QObject::tr("HTML format is not supported.
Please make sure that HTML file type is NETSCAPE-Bookmark-file-1.")); - return NULL; + return nullptr; } BookmarkNode* root = new BookmarkNode(); diff --git a/src/browserapplication.cpp b/src/browserapplication.cpp index 59dad8e..a540987 100644 --- a/src/browserapplication.cpp +++ b/src/browserapplication.cpp @@ -80,14 +80,14 @@ #include "torrent/torrentwindow.h" -DownloadManager *BrowserApplication::s_downloadManager = 0; -TorrentWindow *BrowserApplication::s_torrents = 0; -HistoryManager *BrowserApplication::s_historyManager = 0; -NetworkAccessManager *BrowserApplication::s_networkAccessManager = 0; -BookmarksManager *BrowserApplication::s_bookmarksManager = 0; +DownloadManager *BrowserApplication::s_downloadManager = nullptr; +TorrentWindow *BrowserApplication::s_torrents = nullptr; +HistoryManager *BrowserApplication::s_historyManager = nullptr; +NetworkAccessManager *BrowserApplication::s_networkAccessManager = nullptr; +BookmarksManager *BrowserApplication::s_bookmarksManager = nullptr; QMap BrowserApplication::s_hostIcons; bool BrowserApplication::s_resetOnQuit = false; -AutoComplete* BrowserApplication::s_autoCompleter = 0; +AutoComplete* BrowserApplication::s_autoCompleter = nullptr; bool BrowserApplication::s_portableRunMode = false; bool BrowserApplication::s_startResizeOnMouseweelClick = true; QReadWriteLock lockIcons; @@ -99,7 +99,7 @@ int BrowserApplication::getApplicationBuild() BrowserApplication::BrowserApplication(int &argc, char **argv) : QApplication(argc, argv) - , m_localServer(0) + , m_localServer(nullptr) , quiting(false) { QCoreApplication::setOrganizationName(QLatin1String("QtWeb.NET")); @@ -524,7 +524,7 @@ void BrowserApplication::restoreLastSession() settings.beginGroup(QLatin1String("MainWindow")); if (settings.value(QLatin1String("restoring"), false).toBool()) { - QMessageBox::information(0, tr("Session restore failed"), + QMessageBox::information(nullptr, tr("Session restore failed"), tr("The saved session will not be restored because QtWeb crashed before while trying to restore this session.")); return; } @@ -554,7 +554,7 @@ void BrowserApplication::restoreLastSession() windows.append(windowState); } for (int i = 0; i < windows.count(); ++i) { - BrowserMainWindow *newWindow = 0; + BrowserMainWindow *newWindow = nullptr; if (i == 0 && m_mainWindows.count() >= 1) { newWindow = mainWindow(); } else { @@ -566,7 +566,7 @@ void BrowserApplication::restoreLastSession() bool BrowserApplication::isTheOnlyBrowser() const { - return (m_localServer != 0); + return (m_localServer != nullptr); } void BrowserApplication::installTranslator(const QString &name) diff --git a/src/browserapplication.h b/src/browserapplication.h index a93ee79..6bbf74e 100644 --- a/src/browserapplication.h +++ b/src/browserapplication.h @@ -82,7 +82,7 @@ class BrowserApplication : public QApplication bool isTheOnlyBrowser() const; BrowserMainWindow *mainWindow(); QList mainWindows(); - QIcon icon(const QUrl &url, const WebView *webView = 0) const; + QIcon icon(const QUrl &url, const WebView *webView = nullptr) const; void CheckSetTranslator(); @@ -115,7 +115,7 @@ class BrowserApplication : public QApplication static void resetSettings( bool reload); static QString dataLocation(); static QString downloadsLocation(bool create_dir); - static bool existDownloadManager() {return s_downloadManager != NULL;} + static bool existDownloadManager() {return s_downloadManager != nullptr;} public slots: BrowserMainWindow *newMainWindow(); void restoreLastSession(); diff --git a/src/browsermainwindow.cpp b/src/browsermainwindow.cpp index cb7201b..cc74ae0 100644 --- a/src/browsermainwindow.cpp +++ b/src/browsermainwindow.cpp @@ -88,50 +88,50 @@ extern bool ShellExec(QString path); BrowserMainWindow::BrowserMainWindow(QWidget *parent, Qt::WindowFlags flags) : QMainWindow(parent, flags) - , findWidget(0) + , findWidget(nullptr) , m_showMenuIcons(false) - , m_buttonsBar(0) + , m_buttonsBar(nullptr) , m_tabWidget(new TabWidget(this)) , m_positionRestored(0) , m_dumpActionQuit(false) - , m_navSplit(0) - , m_historyBack(0) - , m_historyForward(0) - , m_styles(0) - , m_stylesMenu(0) - , m_encodingMenu(0) - , m_sizesMenu(0) - , m_compMenu(0) - , m_stop(0) - , m_reload(0) - , m_viewZoomTextOnly(0) - , m_emptyDiskCache(0) - , m_goBackAction(0) - , m_goForwardAction(0) - , m_addBookmarkAction(0) - , m_homeAction(0) - , m_prefsAction(0) - , m_imagesAction(0) - , m_proxyAction(0) - , m_restoreTabAction(0) - , m_resetAction(0) - , m_enableInspector(0) - , m_inspectElement(0) - , m_inspectAction(0) - , m_keyboardAction(0) - , m_textSizeAction(0) - , m_bookmarksAction(0) - , m_compatAction(0) - , m_compIE(0) - , m_compMozilla(0) - , m_compOpera(0) - , m_compSafari(0) - , m_compQtWeb(0) - , m_compChrome(0) - , m_compCustom(0) - , m_textSizeLarger(0) - , m_textSizeNormal(0) - , m_textSizeSmaller(0) + , m_navSplit(nullptr) + , m_historyBack(nullptr) + , m_historyForward(nullptr) + , m_styles(nullptr) + , m_stylesMenu(nullptr) + , m_encodingMenu(nullptr) + , m_sizesMenu(nullptr) + , m_compMenu(nullptr) + , m_stop(nullptr) + , m_reload(nullptr) + , m_viewZoomTextOnly(nullptr) + , m_emptyDiskCache(nullptr) + , m_goBackAction(nullptr) + , m_goForwardAction(nullptr) + , m_addBookmarkAction(nullptr) + , m_homeAction(nullptr) + , m_prefsAction(nullptr) + , m_imagesAction(nullptr) + , m_proxyAction(nullptr) + , m_restoreTabAction(nullptr) + , m_resetAction(nullptr) + , m_enableInspector(nullptr) + , m_inspectElement(nullptr) + , m_inspectAction(nullptr) + , m_keyboardAction(nullptr) + , m_textSizeAction(nullptr) + , m_bookmarksAction(nullptr) + , m_compatAction(nullptr) + , m_compIE(nullptr) + , m_compMozilla(nullptr) + , m_compOpera(nullptr) + , m_compSafari(nullptr) + , m_compQtWeb(nullptr) + , m_compChrome(nullptr) + , m_compCustom(nullptr) + , m_textSizeLarger(nullptr) + , m_textSizeNormal(nullptr) + , m_textSizeSmaller(nullptr) { setAttribute(Qt::WA_DeleteOnClose, true); statusBar()->setSizeGripEnabled(true); @@ -2110,7 +2110,7 @@ void BrowserMainWindow::loadPage(const QString &page) if (bm) { // if tags are detected - load all urls, and return - QStringList urls = bm->find_tag_urls(NULL, page); + QStringList urls = bm->find_tag_urls(nullptr, page); if (!urls.isEmpty()) { for(int i = 0; i < urls.size(); i++) @@ -2206,7 +2206,7 @@ void BrowserMainWindow::slotAboutToShowForwardMenu() void BrowserMainWindow::slotAboutToShowWindowMenu() { - static QAction *downs = NULL, *tors = NULL; + static QAction *downs = nullptr, *tors = nullptr; bool empty = m_windowMenu->isEmpty(); if (!empty) { diff --git a/src/browsermainwindow.h b/src/browsermainwindow.h index 8092e3a..badc423 100644 --- a/src/browsermainwindow.h +++ b/src/browsermainwindow.h @@ -64,7 +64,7 @@ class BrowserMainWindow : public QMainWindow { Q_OBJECT public: - BrowserMainWindow(QWidget *parent = 0, Qt::WindowFlags flags = 0); + BrowserMainWindow(QWidget *parent = nullptr, Qt::WindowFlags flags = nullptr); ~BrowserMainWindow(); QSize sizeHint() const; diff --git a/src/certificateinfo.h b/src/certificateinfo.h index 072f46e..d6320ca 100644 --- a/src/certificateinfo.h +++ b/src/certificateinfo.h @@ -34,7 +34,7 @@ class CertificateInfo : public QDialog { Q_OBJECT public: - CertificateInfo(QString host, QWidget *parent = 0); + CertificateInfo(QString host, QWidget *parent = nullptr); ~CertificateInfo(); void setCertificateChain(const QList &chain); diff --git a/src/chasewidget.h b/src/chasewidget.h index 2eb20b0..76dbc68 100644 --- a/src/chasewidget.h +++ b/src/chasewidget.h @@ -58,7 +58,7 @@ class ChaseWidget : public QWidget { Q_OBJECT public: - ChaseWidget(QWidget *parent = 0, QPixmap pixmap = QPixmap(), bool pixmapEnabled = false); + ChaseWidget(QWidget *parent = nullptr, QPixmap pixmap = QPixmap(), bool pixmapEnabled = false); void setAnimated(bool value); void setPixmapEnabled(bool enable); diff --git a/src/closeapp.h b/src/closeapp.h index a39d2e9..ec6a058 100644 --- a/src/closeapp.h +++ b/src/closeapp.h @@ -27,7 +27,7 @@ class CloseApp : public QDialog Q_OBJECT public: - CloseApp(QWidget *parent = 0); + CloseApp(QWidget *parent = nullptr); ~CloseApp(); private: diff --git a/src/cookiejar.h b/src/cookiejar.h index 864893d..0a04379 100644 --- a/src/cookiejar.h +++ b/src/cookiejar.h @@ -82,7 +82,7 @@ class CookieJar : public QNetworkCookieJar KeepUntilTimeLimit }; - CookieJar(QObject *parent = 0); + CookieJar(QObject *parent = nullptr); ~CookieJar(); QList cookiesForUrl(const QUrl &url) const; @@ -128,7 +128,7 @@ class CookieModel : public QAbstractTableModel Q_OBJECT public: - CookieModel(CookieJar *jar, QObject *parent = 0); + CookieModel(CookieJar *jar, QObject *parent = nullptr); QVariant headerData(int section, Qt::Orientation orientation, int role) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; @@ -150,7 +150,7 @@ class CookiesDialog : public QDialog, public Ui_CookiesDialog Q_OBJECT public: - CookiesDialog(CookieJar *cookieJar, QWidget *parent = 0); + CookiesDialog(CookieJar *cookieJar, QWidget *parent = nullptr); private: QSortFilterProxyModel *m_proxyModel; @@ -162,7 +162,7 @@ class CookieExceptionsModel : public QAbstractTableModel friend class CookiesExceptionsDialog; public: - CookieExceptionsModel(CookieJar *cookieJar, QObject *parent = 0); + CookieExceptionsModel(CookieJar *cookieJar, QObject *parent = nullptr); void reload(); QVariant headerData(int section, Qt::Orientation orientation, int role) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; @@ -184,7 +184,7 @@ class CookiesExceptionsDialog : public QDialog, public Ui_CookiesExceptionsDialo Q_OBJECT public: - CookiesExceptionsDialog(CookieJar *cookieJar, QWidget *parent = 0); + CookiesExceptionsDialog(CookieJar *cookieJar, QWidget *parent = nullptr); private slots: void block(); diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index fc994c5..6e6d3b2 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -466,7 +466,7 @@ bool DownloadItem::checkAddTorrent() DownloadManager::DownloadManager(QWidget *parent) : QDialog(parent, Qt::Window) , m_manager(BrowserApplication::networkAccessManager()) - , m_iconProvider(0) + , m_iconProvider(nullptr) , m_removePolicy(Never) { setupUi(this); @@ -635,7 +635,7 @@ void DownloadManager::save() const void DownloadManager::addItem(const QUrl& url, QString filename, bool done) { - DownloadItem *item = new DownloadItem(0, false, this); + DownloadItem *item = new DownloadItem(nullptr, false, this); item->m_output.setFileName(filename); item->setOutputTitle(); @@ -738,7 +738,7 @@ void DownloadManager::cleanup_list() updateItemCount(); if (m_downloads.isEmpty() && m_iconProvider) { delete m_iconProvider; - m_iconProvider = 0; + m_iconProvider = nullptr; } save(); } @@ -783,7 +783,7 @@ void DownloadManager::cleanup_full() updateItemCount(); if (m_downloads.isEmpty() && m_iconProvider) { delete m_iconProvider; - m_iconProvider = 0; + m_iconProvider = nullptr; } save(); } diff --git a/src/downloadmanager.h b/src/downloadmanager.h index 1dff290..15f9113 100644 --- a/src/downloadmanager.h +++ b/src/downloadmanager.h @@ -57,7 +57,7 @@ class DownloadItem : public QWidget, public Ui_DownloadItem void statusChanged(); public: - DownloadItem(QNetworkReply *reply = 0, bool requestFileName = false, QWidget *parent = 0); + DownloadItem(QNetworkReply *reply = nullptr, bool requestFileName = false, QWidget *parent = nullptr); ~DownloadItem(); bool downloading() const; bool downloadedSuccessfully() const; @@ -124,7 +124,7 @@ class DownloadManager : public QDialog, public Ui_DownloadDialog SuccessFullDownload }; - DownloadManager(QWidget *parent = 0); + DownloadManager(QWidget *parent = nullptr); ~DownloadManager(); int activeDownloads() const; void load(); @@ -165,7 +165,7 @@ class DownloadModel : public QAbstractListModel Q_OBJECT public: - DownloadModel(DownloadManager *downloadManager, QObject *parent = 0); + DownloadModel(DownloadManager *downloadManager, QObject *parent = nullptr); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; int rowCount(const QModelIndex &parent = QModelIndex()) const; bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); diff --git a/src/edittableview.h b/src/edittableview.h index fe42c46..913d8c0 100644 --- a/src/edittableview.h +++ b/src/edittableview.h @@ -48,7 +48,7 @@ class EditTableView : public QTableView Q_OBJECT public: - EditTableView(QWidget *parent = 0); + EditTableView(QWidget *parent = nullptr); void keyPressEvent(QKeyEvent *event); public slots: diff --git a/src/edittreeview.h b/src/edittreeview.h index 6cbee58..e6eb527 100644 --- a/src/edittreeview.h +++ b/src/edittreeview.h @@ -48,7 +48,7 @@ class EditTreeView : public QTreeView Q_OBJECT public: - EditTreeView(QWidget *parent = 0); + EditTreeView(QWidget *parent = nullptr); void keyPressEvent(QKeyEvent *event); public slots: diff --git a/src/exlineedit.cpp b/src/exlineedit.cpp index 7d341bb..26de917 100644 --- a/src/exlineedit.cpp +++ b/src/exlineedit.cpp @@ -171,9 +171,9 @@ void LineEdit::keyPressEvent ( QKeyEvent * event ) //////////////////////////////////////// ExLineEdit::ExLineEdit(QWidget *parent, bool fix_url) : QWidget(parent) - , m_leftWidget(0) + , m_leftWidget(nullptr) , m_lineEdit(new LineEdit(this, fix_url)) - , m_clearButton(0) + , m_clearButton(nullptr) { setFocusPolicy(m_lineEdit->focusPolicy()); setAttribute(Qt::WA_InputMethodEnabled); diff --git a/src/exlineedit.h b/src/exlineedit.h index 61ac742..f47886b 100644 --- a/src/exlineedit.h +++ b/src/exlineedit.h @@ -54,7 +54,7 @@ class ClearButton : public QAbstractButton Q_OBJECT public: - ClearButton(QWidget *parent = 0); + ClearButton(QWidget *parent = nullptr); void paintEvent(QPaintEvent *event); public slots: @@ -71,7 +71,7 @@ class LineEdit : public QLineEdit public: - LineEdit(QWidget *parent = 0, bool fix_url = false); + LineEdit(QWidget *parent = nullptr, bool fix_url = false); protected: void focusInEvent(QFocusEvent *); @@ -91,7 +91,7 @@ class ExLineEdit : public QWidget Q_OBJECT public: - ExLineEdit(QWidget *parent = 0, bool fix_url = false); + ExLineEdit(QWidget *parent = nullptr, bool fix_url = false); inline QLineEdit *lineEdit() const { return m_lineEdit; } diff --git a/src/findwidget.h b/src/findwidget.h index cc0bcb7..3dc8e10 100644 --- a/src/findwidget.h +++ b/src/findwidget.h @@ -55,7 +55,7 @@ class FindWidget : public QWidget { Q_OBJECT public: - FindWidget(QWidget *parent = 0); + FindWidget(QWidget *parent = nullptr); ~FindWidget(); void show(); diff --git a/src/googlesuggest.h b/src/googlesuggest.h index b52eaad..60e1880 100644 --- a/src/googlesuggest.h +++ b/src/googlesuggest.h @@ -57,7 +57,7 @@ class GSuggestCompletion : public QObject Q_OBJECT public: - GSuggestCompletion(QLineEdit *parent = 0); + GSuggestCompletion(QLineEdit *parent = nullptr); ~GSuggestCompletion(); bool eventFilter(QObject *obj, QEvent *ev); void showCompletion(const QStringList &choices, const QStringList &hits); diff --git a/src/history.cpp b/src/history.cpp index b636560..cb9faa0 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -70,9 +70,9 @@ HistoryManager::HistoryManager(QObject *parent) , m_saveTimer(new AutoSaver(this)) , m_historyLimit(7) , m_historyCleaned(false) - , m_historyModel(0) - , m_historyFilterModel(0) - , m_historyTreeModel(0) + , m_historyModel(nullptr) + , m_historyFilterModel(nullptr) + , m_historyTreeModel(nullptr) { m_expiredTimer.setSingleShot(true); connect(&m_expiredTimer, SIGNAL(timeout()), @@ -615,7 +615,7 @@ QModelIndex HistoryMenuModel::parent(const QModelIndex &index) const HistoryMenu::HistoryMenu(QWidget *parent) : ModelMenu(parent) - , m_history(0) + , m_history(nullptr) { connect(this, SIGNAL(activated(const QModelIndex &)), this, SLOT(activated(const QModelIndex &))); diff --git a/src/history.h b/src/history.h index 701ee3b..2cfb7a1 100644 --- a/src/history.h +++ b/src/history.h @@ -90,7 +90,7 @@ class HistoryManager : public QWebHistoryInterface void entryUpdated(int offset); public: - HistoryManager(QObject *parent = 0); + HistoryManager(QObject *parent = nullptr); ~HistoryManager(); bool historyContains(const QString &url) const; @@ -152,7 +152,7 @@ public slots: UrlStringRole = Qt::UserRole + 4 }; - HistoryModel(HistoryManager *history, QObject *parent = 0); + HistoryModel(HistoryManager *history, QObject *parent = nullptr); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; @@ -173,7 +173,7 @@ class HistoryFilterModel : public QAbstractProxyModel Q_OBJECT public: - HistoryFilterModel(QAbstractItemModel *sourceModel, QObject *parent = 0); + HistoryFilterModel(QAbstractItemModel *sourceModel, QObject *parent = nullptr); inline bool historyContains(const QString &url) const { load(); return m_historyHash.contains(url); } @@ -217,7 +217,7 @@ class HistoryMenuModel : public QAbstractProxyModel Q_OBJECT public: - HistoryMenuModel(HistoryTreeModel *sourceModel, QObject *parent = 0); + HistoryMenuModel(HistoryTreeModel *sourceModel, QObject *parent = nullptr); int columnCount(const QModelIndex &parent) const; int rowCount(const QModelIndex &parent = QModelIndex()) const; QModelIndex mapFromSource(const QModelIndex & sourceIndex) const; @@ -240,7 +240,7 @@ class HistoryMenu : public ModelMenu void openUrl(const QUrl &url); public: - HistoryMenu(QWidget *parent = 0); + HistoryMenu(QWidget *parent = nullptr); void setInitialActions(QList actions); protected: @@ -264,7 +264,7 @@ class HistoryCompletionModel : public QAbstractProxyModel Q_OBJECT public: - HistoryCompletionModel(QObject *parent = 0); + HistoryCompletionModel(QObject *parent = nullptr); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; @@ -287,7 +287,7 @@ class HistoryTreeModel : public QAbstractProxyModel Q_OBJECT public: - HistoryTreeModel(QAbstractItemModel *sourceModel, QObject *parent = 0); + HistoryTreeModel(QAbstractItemModel *sourceModel, QObject *parent = nullptr); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; int columnCount(const QModelIndex &parent) const; int rowCount(const QModelIndex &parent = QModelIndex()) const; @@ -321,7 +321,7 @@ class TreeProxyModel : public QSortFilterProxyModel Q_OBJECT public: - TreeProxyModel(QObject *parent = 0); + TreeProxyModel(QObject *parent = nullptr); protected: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; @@ -337,7 +337,7 @@ class HistoryDialog : public QDialog, public Ui_HistoryDialog void openUrl(const QUrl &url); public: - HistoryDialog(QWidget *parent = 0, HistoryManager *history = 0); + HistoryDialog(QWidget *parent = nullptr, HistoryManager *history = nullptr); private slots: void customContextMenuRequested(const QPoint &pos); diff --git a/src/modelmenu.cpp b/src/modelmenu.cpp index 5bff437..f7a2499 100644 --- a/src/modelmenu.cpp +++ b/src/modelmenu.cpp @@ -50,7 +50,7 @@ ModelMenu::ModelMenu(QWidget * parent) , m_maxWidth(-1) , m_hoverRole(0) , m_separatorRole(0) - , m_model(0) + , m_model(nullptr) { connect(this, SIGNAL(aboutToShow()), this, SLOT(aboutToShow())); } diff --git a/src/modelmenu.h b/src/modelmenu.h index c457768..c8c7d7c 100644 --- a/src/modelmenu.h +++ b/src/modelmenu.h @@ -54,7 +54,7 @@ class ModelMenu : public QMenu void hovered(const QString &text); public: - ModelMenu(QWidget *parent = 0); + ModelMenu(QWidget *parent = nullptr); void setModel(QAbstractItemModel *model); QAbstractItemModel *model() const; @@ -82,7 +82,7 @@ class ModelMenu : public QMenu // add any actions after the tree virtual void postPopulated(); // put all of the children of parent into menu up to max - void createMenu(const QModelIndex &parent, int max, QMenu *parentMenu = 0, QMenu *menu = 0); + void createMenu(const QModelIndex &parent, int max, QMenu *parentMenu = nullptr, QMenu *menu = nullptr); private slots: void aboutToShow(); diff --git a/src/networkaccessmanager.cpp b/src/networkaccessmanager.cpp index 507a9dd..e95cef6 100644 --- a/src/networkaccessmanager.cpp +++ b/src/networkaccessmanager.cpp @@ -74,9 +74,9 @@ NetworkAccessManager::NetworkAccessManager(QObject *parent) : QNetworkAccessManager(parent) , m_useProxy(false) - , m_proxyExceptions(0) - , m_adBlock(0) - , m_adBlockEx(0) + , m_proxyExceptions(nullptr) + , m_adBlock(nullptr) + , m_adBlockEx(nullptr) { connect(this, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); @@ -108,7 +108,7 @@ void NetworkAccessManager::loadSettings() if (m_proxyExceptions) { delete m_proxyExceptions; - m_proxyExceptions = 0; + m_proxyExceptions = nullptr; } QSettings settings; @@ -189,13 +189,13 @@ void NetworkAccessManager::loadSettings() if (m_adBlock) { delete m_adBlock; - m_adBlock = 0; + m_adBlock = nullptr; } if (m_adBlockEx) { delete m_adBlockEx; - m_adBlockEx = 0; + m_adBlockEx = nullptr; } settings.beginGroup(QLatin1String("AdBlock")); @@ -231,7 +231,7 @@ void NetworkAccessManager::loadSettings() if (!settings.value(QLatin1String("enableDiskCache"), false).toBool() && cache()) { cache()->clear(); - setCache(0); + setCache(nullptr); } } @@ -246,7 +246,7 @@ void NetworkAccessManager::authenticationRequired(QNetworkReply *reply, QAuthent passwordDialog.setupUi(&dialog); passwordDialog.iconLabel->setText(QString()); - passwordDialog.iconLabel->setPixmap(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxQuestion, 0, mainWindow).pixmap(32, 32)); + passwordDialog.iconLabel->setPixmap(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxQuestion, nullptr, mainWindow).pixmap(32, 32)); QString introMessage = tr("Enter username and password for \"%1\" at %2"); introMessage = introMessage.arg(reply->url().toString().toHtmlEscaped()).arg(reply->url().toString().toHtmlEscaped()); @@ -270,7 +270,7 @@ void NetworkAccessManager::proxyAuthenticationRequired(const QNetworkProxy &prox proxyDialog.setupUi(&dialog); proxyDialog.iconLabel->setText(QString()); - proxyDialog.iconLabel->setPixmap(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxQuestion, 0, mainWindow).pixmap(32, 32)); + proxyDialog.iconLabel->setPixmap(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxQuestion, nullptr, mainWindow).pixmap(32, 32)); QString introMessage = tr("Connect to proxy \"%1\" using:"); introMessage = introMessage.arg(proxy.hostName().toHtmlEscaped()); diff --git a/src/networkaccessmanager.h b/src/networkaccessmanager.h index 5da0ee9..5cb9562 100644 --- a/src/networkaccessmanager.h +++ b/src/networkaccessmanager.h @@ -51,12 +51,12 @@ class NetworkAccessManager : public QNetworkAccessManager Q_OBJECT public: - NetworkAccessManager(QObject *parent = 0); + NetworkAccessManager(QObject *parent = nullptr); ~NetworkAccessManager(); void blockAd(QString ad); protected: - QNetworkReply * createRequest ( Operation op, const QNetworkRequest & req, QIODevice * outgoingData = 0 ); + QNetworkReply * createRequest ( Operation op, const QNetworkRequest & req, QIODevice * outgoingData = nullptr ); bool useProxy() {return m_useProxy; } bool isUrlProxyException(const QUrl&); diff --git a/src/passwords.h b/src/passwords.h index ecbd6c7..d55f6bb 100644 --- a/src/passwords.h +++ b/src/passwords.h @@ -35,7 +35,7 @@ class PasswordsModel : public QAbstractTableModel Q_OBJECT public: - PasswordsModel(QObject *parent = 0); + PasswordsModel(QObject *parent = nullptr); ~PasswordsModel(); QVariant headerData(int section, Qt::Orientation orientation, int role) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; diff --git a/src/resetsettings.h b/src/resetsettings.h index 0f10307..e7c2cf5 100644 --- a/src/resetsettings.h +++ b/src/resetsettings.h @@ -32,7 +32,7 @@ class ResetSettings : public QDialog, public Ui_ResetSettings ToolbarSearch* m_toolbarSearch; public: - ResetSettings(ToolbarSearch*, QWidget *parent = 0); + ResetSettings(ToolbarSearch*, QWidget *parent = nullptr); ~ResetSettings(); public slots: diff --git a/src/savepdf.h b/src/savepdf.h index 2bff416..df6978e 100644 --- a/src/savepdf.h +++ b/src/savepdf.h @@ -11,7 +11,7 @@ class SavePDF : public QDialog Q_OBJECT public: - SavePDF(const QString& title, QWebFrame* frame, QWidget *parent = 0); + SavePDF(const QString& title, QWebFrame* frame, QWidget *parent = nullptr); ~SavePDF(); protected slots: diff --git a/src/searchlineedit.cpp b/src/searchlineedit.cpp index 22dc636..9bd3d02 100644 --- a/src/searchlineedit.cpp +++ b/src/searchlineedit.cpp @@ -53,7 +53,7 @@ */ class SearchButton : public QAbstractButton { public: - SearchButton(QWidget *parent = 0); + SearchButton(QWidget *parent = nullptr); void paintEvent(QPaintEvent *event); QMenu *m_menu; @@ -63,7 +63,7 @@ class SearchButton : public QAbstractButton { SearchButton::SearchButton(QWidget *parent) : QAbstractButton(parent), - m_menu(0) + m_menu(nullptr) { setObjectName(QLatin1String("SearchButton")); setCursor(Qt::ArrowCursor); diff --git a/src/searchlineedit.h b/src/searchlineedit.h index 99aeade..96bf9b1 100644 --- a/src/searchlineedit.h +++ b/src/searchlineedit.h @@ -60,7 +60,7 @@ class SearchLineEdit : public ExLineEdit void textChanged(const QString &text); public: - SearchLineEdit(QWidget *parent = 0); + SearchLineEdit(QWidget *parent = nullptr); QString inactiveText() const; void setInactiveText(const QString &text); diff --git a/src/settings.h b/src/settings.h index 4d1c4d9..523df6f 100644 --- a/src/settings.h +++ b/src/settings.h @@ -49,7 +49,7 @@ class SettingsDialog : public QDialog, public Ui_Settings Q_OBJECT public: - SettingsDialog(QWidget *parent = 0); + SettingsDialog(QWidget *parent = nullptr); void accept(); void reject(); diff --git a/src/shortcuts.cpp b/src/shortcuts.cpp index f245ea6..d955328 100644 --- a/src/shortcuts.cpp +++ b/src/shortcuts.cpp @@ -98,7 +98,7 @@ bool Shortcuts::save() { if (!m_data.SetShortcuts(i, shorts->text().trimmed())) { - QMessageBox::warning(0, tr("Invalid shortcut assigned"), + QMessageBox::warning(nullptr, tr("Invalid shortcut assigned"), tr("Error assigning shortcut(s) for the menu command: %1.\n\nPlease check the shortcut(s): %2" ).arg(menu->text()).arg(shorts->text().trimmed())); return false; diff --git a/src/squeezelabel.h b/src/squeezelabel.h index 818f5a5..3e0d3d8 100644 --- a/src/squeezelabel.h +++ b/src/squeezelabel.h @@ -48,7 +48,7 @@ class SqueezeLabel : public QLabel Q_OBJECT public: - SqueezeLabel(QWidget *parent = 0); + SqueezeLabel(QWidget *parent = nullptr); protected: void paintEvent(QPaintEvent *event); diff --git a/src/tabbar.cpp b/src/tabbar.cpp index 9d2813a..73f9797 100644 --- a/src/tabbar.cpp +++ b/src/tabbar.cpp @@ -76,7 +76,7 @@ int TabShortcut::tab() } TabBar::TabBar(QWidget *parent) : QTabBar(parent) - , m_viewTabBarAction(0) + , m_viewTabBarAction(nullptr) , m_showTabBarWhenOneTab(true) { setElideMode(Qt::ElideRight); @@ -122,7 +122,7 @@ void TabBar::setShowTabBarWhenOneTab(bool enabled) QTabBar::ButtonPosition TabBar::freeSide() { - QTabBar::ButtonPosition side = (QTabBar::ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, this); + QTabBar::ButtonPosition side = (QTabBar::ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, nullptr, this); side = (side == QTabBar::LeftSide) ? QTabBar::RightSide : QTabBar::LeftSide; return side; } @@ -328,7 +328,7 @@ QSize TabBar::tabSizeHint(int index) const WebActionMapper::WebActionMapper(QAction *root, QWebPage::WebAction webAction, QObject *parent) : QObject(parent) - , m_currentParent(0) + , m_currentParent(nullptr) , m_root(root) , m_webAction(webAction) { @@ -341,12 +341,12 @@ WebActionMapper::WebActionMapper(QAction *root, QWebPage::WebAction webAction, Q void WebActionMapper::rootDestroyed() { - m_root = 0; + m_root = nullptr; } void WebActionMapper::currentDestroyed() { - updateCurrent(0); + updateCurrent(nullptr); } void WebActionMapper::addChild(QAction *action) diff --git a/src/tabbar.h b/src/tabbar.h index 13c5165..a337ed1 100644 --- a/src/tabbar.h +++ b/src/tabbar.h @@ -66,7 +66,7 @@ class TabBar : public QTabBar void loadUrl(const QUrl &url); public: - TabBar(QWidget *parent = 0); + TabBar(QWidget *parent = nullptr); bool showTabBarWhenOneTab() const; void setShowTabBarWhenOneTab(bool enabled); diff --git a/src/tabwidget.cpp b/src/tabwidget.cpp index 23af023..2b7a537 100644 --- a/src/tabwidget.cpp +++ b/src/tabwidget.cpp @@ -68,15 +68,15 @@ TabWidget::TabWidget(QWidget *parent) : QTabWidget(parent) - , m_recentlyClosedTabsAction(0) - , m_newTabAction(0) - , m_closeTabAction(0) - , m_nextTabAction(0) - , m_previousTabAction(0) - , m_recentlyClosedTabsMenu(0) + , m_recentlyClosedTabsAction(nullptr) + , m_newTabAction(nullptr) + , m_closeTabAction(nullptr) + , m_nextTabAction(nullptr) + , m_previousTabAction(nullptr) + , m_recentlyClosedTabsMenu(nullptr) , m_prevSelectedTab(-1) , m_prevSelectedTabMark(-1) - , m_lineEdits(0) + , m_lineEdits(nullptr) , m_tabBar(new TabBar(this)) { setElideMode(Qt::ElideRight); @@ -305,7 +305,7 @@ QLineEdit *TabWidget::lineEdit(int index) const UrlLineEdit *urlLineEdit = qobject_cast(m_lineEdits->widget(index)); if (urlLineEdit) return urlLineEdit->lineEdit(); - return 0; + return nullptr; } WebView *TabWidget::webView(int index) const @@ -343,7 +343,7 @@ WebView *TabWidget::webView(int index) const return currentWebView(); } } - return 0; + return nullptr; } int TabWidget::webViewIndex(WebView *webView) const @@ -390,7 +390,7 @@ WebView *TabWidget::newTab(bool makeCurrent, bool empty) addTab(emptyWidget, tr("Blank Tab")); connect(this, SIGNAL(currentChanged(int)), this, SLOT(currentChanged(int))); - return 0; + return nullptr; } // webview @@ -446,7 +446,10 @@ WebView *TabWidget::newTab(bool makeCurrent, bool empty) case 0: // welcome page { QFile file(QLatin1String(":/Welcome.html")); - Q_ASSERT(file.open(QIODevice::ReadOnly | QIODevice::Text)); + const bool opened = file.open(QIODevice::ReadOnly | QIODevice::Text); + Q_ASSERT(opened); + if (!opened) + break; QString html = QString(QLatin1String(file.readAll())); QPixmap pix= style()->standardIcon(QStyle::SP_MessageBoxInformation).pixmap(32,32); @@ -597,7 +600,7 @@ void TabWidget::closeTab(int index) QLabel *TabWidget::animationLabel(int index, bool addMovie) { if (-1 == index) - return 0; + return nullptr; QTabBar::ButtonPosition side = m_tabBar->freeSide(); QLabel *loadingAnimation = qobject_cast(m_tabBar->tabButton(index, side)); if (!loadingAnimation) { @@ -608,7 +611,7 @@ QLabel *TabWidget::animationLabel(int index, bool addMovie) loadingAnimation->setMovie(movie); movie->start(); } - m_tabBar->setTabButton(index, side, 0); + m_tabBar->setTabButton(index, side, nullptr); m_tabBar->setTabButton(index, side, loadingAnimation); return loadingAnimation; } @@ -634,7 +637,7 @@ void TabWidget::webViewIconChanged() QLabel *label = animationLabel(index, false); QMovie *movie = label->movie(); delete movie; - label->setMovie(0); + label->setMovie(nullptr); label->setPixmap(icon.pixmap(16, 16)); setElideMode(Qt::ElideRight); } diff --git a/src/tabwidget.h b/src/tabwidget.h index abf0ab2..1aa2c42 100644 --- a/src/tabwidget.h +++ b/src/tabwidget.h @@ -83,7 +83,7 @@ class TabWidget : public QTabWidget NewTab }; - TabWidget(QWidget *parent = 0); + TabWidget(QWidget *parent = nullptr); TabBar *tabBar() { return m_tabBar; } void clear(); void addWebAction(QAction *action, QWebPage::WebAction webAction); diff --git a/src/toolbarsearch.cpp b/src/toolbarsearch.cpp index 8c71e90..d6b843b 100644 --- a/src/toolbarsearch.cpp +++ b/src/toolbarsearch.cpp @@ -59,7 +59,7 @@ ToolbarSearch::ToolbarSearch(QWidget *parent) : SearchLineEdit(parent) , m_maxSavedSearches(10) , m_stringListModel(new QStringListModel(this)) - , m_completer(0) + , m_completer(nullptr) { QMenu *m = menu(); connect(m, SIGNAL(aboutToShow()), this, SLOT(aboutToShowMenu())); @@ -236,7 +236,7 @@ void ToolbarSearch::checkGoogleSuggest(bool show_google) else { delete m_completer; - m_completer = NULL; + m_completer = nullptr; } } diff --git a/src/toolbarsearch.h b/src/toolbarsearch.h index 01dd8d6..58bfece 100644 --- a/src/toolbarsearch.h +++ b/src/toolbarsearch.h @@ -59,7 +59,7 @@ class ToolbarSearch : public SearchLineEdit void search(const QUrl &url); public: - ToolbarSearch(QWidget *parent = 0); + ToolbarSearch(QWidget *parent = nullptr); ~ToolbarSearch(); public slots: diff --git a/src/torrent/torrentclient.cpp b/src/torrent/torrentclient.cpp index 119623a..3776172 100644 --- a/src/torrent/torrentclient.cpp +++ b/src/torrent/torrentclient.cpp @@ -584,7 +584,7 @@ void TorrentClient::sendToPeer(int readId, int pieceIndex, int begin, const QByt // still exists; otherwise do nothing. This slot is called by the // file manager after it has read a block of data. QMap::const_iterator it = d->readIds.constFind(readId); - PeerWireClient *client = (it != d->readIds.constEnd()) ? it.value() : 0; + PeerWireClient *client = (it != d->readIds.constEnd()) ? it.value() : nullptr; if (client) { if ((client->peerWireState() & PeerWireClient::ChokingPeer) == 0) client->sendBlock(pieceIndex, begin, data); @@ -640,7 +640,7 @@ void TorrentClient::fullVerificationDone() void TorrentClient::pieceVerified(int pieceIndex, bool ok) { QMap::const_iterator pieceIt = d->pendingPieces.constFind(pieceIndex); - TorrentPiece *piece = (pieceIt != d->pendingPieces.constEnd()) ? pieceIt.value() : 0; + TorrentPiece *piece = (pieceIt != d->pendingPieces.constEnd()) ? pieceIt.value() : nullptr; // Remove this piece from all payloads QMultiMap::Iterator it = d->payloads.begin(); diff --git a/src/torrent/torrentserver.cpp b/src/torrent/torrentserver.cpp index 6517643..dec4cbf 100644 --- a/src/torrent/torrentserver.cpp +++ b/src/torrent/torrentserver.cpp @@ -112,7 +112,7 @@ void TorrentServer::processInfoHash(const QByteArray &infoHash) PeerWireClient *peer = qobject_cast(sender()); for (TorrentClient *client : qAsConst(clients)) { if (client->state() >= TorrentClient::Searching && client->infoHash() == infoHash) { - disconnect(peer, 0, this, 0); + disconnect(peer, nullptr, this, nullptr); client->setupIncomingConnection(peer); return; } diff --git a/src/urllineedit.cpp b/src/urllineedit.cpp index 4941bed..cec77f2 100644 --- a/src/urllineedit.cpp +++ b/src/urllineedit.cpp @@ -66,7 +66,7 @@ UrlIconLabel::UrlIconLabel(QWidget *parent) : QLabel(parent) - , m_webView(0) + , m_webView(nullptr) { setMinimumWidth(16); setMinimumHeight(16); @@ -133,8 +133,8 @@ void UrlIconLabel::mouseMoveEvent(QMouseEvent *event) UrlLineEdit::UrlLineEdit(QWidget *parent) : ExLineEdit(parent, true) - , m_webView(0) - , m_iconLabel(0) + , m_webView(nullptr) + , m_iconLabel(nullptr) { // icon m_iconLabel = new UrlIconLabel(this); diff --git a/src/urllineedit.h b/src/urllineedit.h index 1c95d98..ab4b8a8 100644 --- a/src/urllineedit.h +++ b/src/urllineedit.h @@ -75,7 +75,7 @@ class UrlLineEdit : public ExLineEdit Q_OBJECT public: - UrlLineEdit(QWidget *parent = 0); + UrlLineEdit(QWidget *parent = nullptr); void setWebView(WebView *webView); protected: diff --git a/src/webpage.cpp b/src/webpage.cpp index c481baf..ab3c0c6 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -219,7 +219,7 @@ bool WebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &r return false; } - if (frame == NULL && type == QWebPage::NavigationTypeLinkClicked) // Check for open links in tabs + if (frame == nullptr && type == QWebPage::NavigationTypeLinkClicked) // Check for open links in tabs { QSettings settings; settings.beginGroup(QLatin1String("general")); @@ -275,7 +275,7 @@ bool WebPage::extension(QWebPage::Extension extension, const QWebPage::Extension QBuffer imageBuffer; imageBuffer.open(QBuffer::ReadWrite); - QIcon icon = view()->style()->standardIcon(QStyle::SP_MessageBoxWarning, 0, view()); + QIcon icon = view()->style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, view()); QPixmap pixmap = icon.pixmap(QSize(32,32)); if (pixmap.save(&imageBuffer, "PNG")) { html.replace(QLatin1String("IMAGE_BINARY_DATA_HERE"), diff --git a/src/webpage.h b/src/webpage.h index 5340d77..d664079 100644 --- a/src/webpage.h +++ b/src/webpage.h @@ -66,7 +66,7 @@ class WebPage : public QWebPage { void errorLoadingUrl(); public: - WebPage(QObject *parent = 0); + WebPage(QObject *parent = nullptr); BrowserMainWindow *mainWindow(); static void setUserAgent(QString agent = "default"); diff --git a/src/webview.h b/src/webview.h index 1201669..f61a7d6 100644 --- a/src/webview.h +++ b/src/webview.h @@ -57,7 +57,7 @@ class WebView : public QWebView { Q_OBJECT public: - WebView(QWidget *parent = 0); + WebView(QWidget *parent = nullptr); WebPage *webPage() const { return m_page; } void loadUrl(const QUrl &url, const QString &title = QString()); diff --git a/src/xbel.cpp b/src/xbel.cpp index 87c607a..86795c7 100644 --- a/src/xbel.cpp +++ b/src/xbel.cpp @@ -56,7 +56,7 @@ BookmarkNode::~BookmarkNode() if (m_parent) m_parent->remove(this); qDeleteAll(m_children); - m_parent = 0; + m_parent = nullptr; m_type = BookmarkNode::Root; } @@ -111,7 +111,7 @@ void BookmarkNode::add(BookmarkNode *child, int offset) void BookmarkNode::remove(BookmarkNode *child) { - child->m_parent = 0; + child->m_parent = nullptr; m_children.removeAll(child); } diff --git a/src/xbel.h b/src/xbel.h index 74be9f6..137b44d 100644 --- a/src/xbel.h +++ b/src/xbel.h @@ -54,7 +54,7 @@ class BookmarkNode Separator }; - BookmarkNode(Type type = Root, BookmarkNode *parent = 0); + BookmarkNode(Type type = Root, BookmarkNode *parent = nullptr); ~BookmarkNode(); bool operator==(const BookmarkNode &other); From 0f7575b566f088f4ae4d0a9df33b55a3b05b1285 Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Wed, 1 Apr 2026 01:23:33 +0200 Subject: [PATCH 05/24] Share source cache across build flavors Co-authored-by: Codex --- build-qt5-static.sh | 3 ++- docs/qt5-static-poc.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build-qt5-static.sh b/build-qt5-static.sh index 3dc97e6..bf97834 100755 --- a/build-qt5-static.sh +++ b/build-qt5-static.sh @@ -249,7 +249,8 @@ OUTPUT_ABS="$(cd "$OUTPUT_RAW" && pwd -P)" ensure_output_in_repo "$OUTPUT_ABS" "--output-dir resolves outside repo: $OUTPUT_ABS" -SRC_CACHE_DIR="${OUTPUT_ABS}/src-cache" +SRC_CACHE_DIR="${REPO_ABS}/artifacts/src-cache" +ensure_output_in_repo "$SRC_CACHE_DIR" "source cache resolves outside repo: $SRC_CACHE_DIR" mkdir -p "$SRC_CACHE_DIR" "${OUTPUT_ABS}/logs" "${OUTPUT_ABS}/build" QT5_SRC_ARCHIVE="${SRC_CACHE_DIR}/${QT5_SRC_FILE}" diff --git a/docs/qt5-static-poc.md b/docs/qt5-static-poc.md index 6329169..bca851a 100644 --- a/docs/qt5-static-poc.md +++ b/docs/qt5-static-poc.md @@ -44,7 +44,7 @@ Checksum policy: ## Output Layout Default root: `artifacts/qt5-static-5.5.1` -- `src-cache/`: downloaded archives +- `artifacts/src-cache/`: shared downloaded archives for all build flavors - `build/`: extracted/build tree - `install/`: static Qt install prefix - `icu-static/`: static ICU install prefix From 8417844b2a7c7448e4fcc6ade64a2e7a8f6edaca Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Wed, 1 Apr 2026 01:41:27 +0200 Subject: [PATCH 06/24] Share Qt toolchain defaults from common file Co-authored-by: Codex --- build-browser-docker.sh | 7 +++++-- build-qt5-static.sh | 21 +++++++++++-------- .../qtwebkit-smoke/smoke-build-docker.sh | 7 +++++-- toolchains/qt5-static/common.sh | 2 ++ 4 files changed, 24 insertions(+), 13 deletions(-) create mode 100644 toolchains/qt5-static/common.sh diff --git a/build-browser-docker.sh b/build-browser-docker.sh index 33b472d..b751dfa 100755 --- a/build-browser-docker.sh +++ b/build-browser-docker.sh @@ -9,6 +9,9 @@ fail() { exit 1 } +# shellcheck disable=SC1090 +source "${REPO_ROOT}/toolchains/qt5-static/common.sh" + usage() { cat <<'EOF' Usage: ./build-browser-docker.sh [options] @@ -22,7 +25,7 @@ Options: EOF } -IMAGE_TAG="${IMAGE_TAG:-qtweb-qt5-static-poc:5.5.1}" +IMAGE_TAG="${IMAGE_TAG:-$QT5_STATIC_IMAGE_TAG}" JOBS="${JOBS:-$(nproc 2>/dev/null || echo 4)}" BUILD_TYPE="release" RUN_ANALYSIS=0 @@ -56,7 +59,7 @@ done case "$BUILD_TYPE" in release|debug) - QT_PREFIX_IN_CONTAINER="${REPO_ROOT}/artifacts/qt5-static-5.5.1-${BUILD_TYPE}/install" + QT_PREFIX_IN_CONTAINER="${REPO_ROOT}/artifacts/qt5-static-${QT_VERSION}-${BUILD_TYPE}/install" BUILD_DIR="${REPO_ROOT}/build-docker-${BUILD_TYPE}" if [[ "$BUILD_TYPE" == "release" ]]; then QMAKE_CONFIG_ARGS="CONFIG+=release CONFIG-=debug" diff --git a/build-qt5-static.sh b/build-qt5-static.sh index bf97834..2ccb893 100755 --- a/build-qt5-static.sh +++ b/build-qt5-static.sh @@ -1,28 +1,31 @@ #!/usr/bin/env bash set -euo pipefail -QT_VERSION="5.5.1" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$SCRIPT_DIR" +LOCK_FILE="${REPO_ROOT}/toolchains/qt5-static/sources.lock" +DOCKERFILE="${REPO_ROOT}/toolchains/qt5-static/Dockerfile" +INNER_SCRIPT="/workspace/toolchains/qt5-static/build-inside-container.sh" + +# shellcheck disable=SC1090 +source "${REPO_ROOT}/toolchains/qt5-static/common.sh" + DEFAULT_JOBS="$(nproc 2>/dev/null || echo 8)" JOBS="${COMPILE_JOBS:-$DEFAULT_JOBS}" OUTPUT_DIR="" RUNTIME="auto" CLEAN=false BUILD_TYPE="release" -IMAGE_TAG="qtweb-qt5-static-poc:${QT_VERSION}" +IMAGE_TAG="${IMAGE_TAG:-$QT5_STATIC_IMAGE_TAG}" -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT="$SCRIPT_DIR" -LOCK_FILE="${REPO_ROOT}/toolchains/qt5-static/sources.lock" -DOCKERFILE="${REPO_ROOT}/toolchains/qt5-static/Dockerfile" -INNER_SCRIPT="/workspace/toolchains/qt5-static/build-inside-container.sh" usage() { - cat <<'EOF' + cat < Parallel build jobs (default: nproc) - --output-dir Output directory inside repo (default: artifacts/qt5-static-5.5.1-) + --output-dir Output directory inside repo (default: artifacts/qt5-static-${QT_VERSION}-) --runtime Container runtime selector (default: auto) --debug Build debug Qt libraries diff --git a/smoke-tests/qtwebkit-smoke/smoke-build-docker.sh b/smoke-tests/qtwebkit-smoke/smoke-build-docker.sh index 98efa61..50c16ee 100755 --- a/smoke-tests/qtwebkit-smoke/smoke-build-docker.sh +++ b/smoke-tests/qtwebkit-smoke/smoke-build-docker.sh @@ -9,7 +9,10 @@ fail() { exit 1 } -IMAGE_TAG="${IMAGE_TAG:-qtweb-qt5-static-poc:5.5.1}" +# shellcheck disable=SC1090 +source "${REPO_ROOT}/toolchains/qt5-static/common.sh" + +IMAGE_TAG="${IMAGE_TAG:-$QT5_STATIC_IMAGE_TAG}" JOBS="${JOBS:-$(nproc 2>/dev/null || echo 4)}" BUILD_TYPE="release" @@ -27,7 +30,7 @@ done case "$BUILD_TYPE" in release|debug) - QT_PREFIX_IN_CONTAINER="/workspace/artifacts/qt5-static-5.5.1-${BUILD_TYPE}/install" + QT_PREFIX_IN_CONTAINER="/workspace/artifacts/qt5-static-${QT_VERSION}-${BUILD_TYPE}/install" BUILD_DIR_IN_CONTAINER="smoke-tests/qtwebkit-smoke/build-docker-${BUILD_TYPE}" if [[ "$BUILD_TYPE" == "release" ]]; then QMAKE_CONFIG_ARGS="CONFIG+=release CONFIG-=debug" diff --git a/toolchains/qt5-static/common.sh b/toolchains/qt5-static/common.sh new file mode 100644 index 0000000..9e5b04a --- /dev/null +++ b/toolchains/qt5-static/common.sh @@ -0,0 +1,2 @@ +QT_VERSION="5.5.1" +QT5_STATIC_IMAGE_TAG="qtweb-qt5-static-poc:${QT_VERSION}" From 81688b23fddac45f8add30894681c6c9b335b7bc Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Sun, 12 Apr 2026 23:12:28 +0200 Subject: [PATCH 07/24] Add local editor settings Ignore the local .codex marker and add the repository VS Code watcher/search excludes. Co-authored-by: Codex --- .gitignore | 1 + .vscode/settings.json | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index bee15bb..34be9b3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ src/qt/.* temp-src build artifacts +.codex # C++ objects and libs diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..688424f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,12 @@ +{ + "files.watcherExclude": { + "**/artifacts/**": true, + "**/build-*/**": true, + "**/src/qt/**": true + }, + "search.exclude": { + "**/artifacts/**": true, + "**/build-*/**": true, + "**/src/qt/**": true + } +} From c5717a30e174df3ef50a667baaa4d46495c07537 Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Mon, 13 Apr 2026 02:13:06 +0200 Subject: [PATCH 08/24] Migrate static toolchain to Qt 5.15.17 Retarget the Docker-based Qt5 static build to Qt 5.15.17 and build QtWebKit 5.212 separately against the installed prefix. This also updates the browser and smoke helper script names plus the supporting docs to match the new flow. Co-authored-by: Codex --- build-browser-docker.sh | 16 + build-qt5-static.sh | 72 ++++- docs/docker-static-analysis.md | 8 +- docs/migration.md | 99 +++---- docs/qt5-static-poc.md | 58 ++-- run-broswer.sh => run-browser.sh | 0 smoke-run.sh => run-smoke.sh | 0 smoke-tests/qtwebkit-smoke/README.md | 2 +- src/QtWeb.pro | 4 +- src/main.cpp | 8 +- toolchains/qt5-static/Dockerfile | 40 ++- .../qt5-static/build-inside-container.sh | 280 +++++++++++++----- toolchains/qt5-static/common.sh | 27 +- .../patches/0001-enable-static-webkit.patch | 15 - ...02-javascriptcore-jschar-uchar-casts.patch | 29 -- ...2-wrap-qmake-libs-in-start-end-group.patch | 15 - toolchains/qt5-static/patches/README.md | 12 +- ...2-wrap-qmake-libs-in-start-end-group.patch | 17 ++ .../0004-qt_parts-honor-no-make-tools.patch | 0 ...ascriptcore-skip-shell-for-static-qt.patch | 14 + toolchains/qt5-static/sources.lock | 26 +- 21 files changed, 484 insertions(+), 258 deletions(-) rename run-broswer.sh => run-browser.sh (100%) rename smoke-run.sh => run-smoke.sh (100%) delete mode 100644 toolchains/qt5-static/patches/0001-enable-static-webkit.patch delete mode 100644 toolchains/qt5-static/patches/0002-javascriptcore-jschar-uchar-casts.patch delete mode 100644 toolchains/qt5-static/patches/0003-unixmake2-wrap-qmake-libs-in-start-end-group.patch create mode 100644 toolchains/qt5-static/patches/qt/0003-unixmake2-wrap-qmake-libs-in-start-end-group.patch rename toolchains/qt5-static/patches/{ => qt}/0004-qt_parts-honor-no-make-tools.patch (100%) create mode 100644 toolchains/qt5-static/patches/qtwebkit/0005-javascriptcore-skip-shell-for-static-qt.patch diff --git a/build-browser-docker.sh b/build-browser-docker.sh index b751dfa..e0e6078 100755 --- a/build-browser-docker.sh +++ b/build-browser-docker.sh @@ -12,6 +12,19 @@ fail() { # shellcheck disable=SC1090 source "${REPO_ROOT}/toolchains/qt5-static/common.sh" +SCRIPT_NAME="$(basename "$0")" + +report_run_duration() { + local exit_code="$1" + local outcome="failed" + + if [[ "$exit_code" -eq 0 ]]; then + outcome="completed" + fi + + echo "${SCRIPT_NAME} ${outcome} in $(format_duration "${SECONDS}")" +} + usage() { cat <<'EOF' Usage: ./build-browser-docker.sh [options] @@ -57,6 +70,9 @@ while [[ $# -gt 0 ]]; do esac done +SECONDS=0 +trap 'report_run_duration "$?"' EXIT + case "$BUILD_TYPE" in release|debug) QT_PREFIX_IN_CONTAINER="${REPO_ROOT}/artifacts/qt5-static-${QT_VERSION}-${BUILD_TYPE}/install" diff --git a/build-qt5-static.sh b/build-qt5-static.sh index 2ccb893..819f8e0 100755 --- a/build-qt5-static.sh +++ b/build-qt5-static.sh @@ -10,6 +10,8 @@ INNER_SCRIPT="/workspace/toolchains/qt5-static/build-inside-container.sh" # shellcheck disable=SC1090 source "${REPO_ROOT}/toolchains/qt5-static/common.sh" +SCRIPT_NAME="$(basename "$0")" + DEFAULT_JOBS="$(nproc 2>/dev/null || echo 8)" JOBS="${COMPILE_JOBS:-$DEFAULT_JOBS}" OUTPUT_DIR="" @@ -18,6 +20,7 @@ CLEAN=false BUILD_TYPE="release" IMAGE_TAG="${IMAGE_TAG:-$QT5_STATIC_IMAGE_TAG}" +BUILD_SCOPE="${BUILD_SCOPE:-all}" usage() { cat < Container runtime selector (default: auto) --debug Build debug Qt libraries + --qt-only Build only the static Qt toolchain + --qtwebkit-only Build only QtWebKit against an existing Qt install --clean Remove output directory before running --help Show this help message Environment overrides: + IMAGE_TAG QT5_SRC_URL QT5_SRC_SHA256 QT5_WEBKIT_SRC_URL @@ -110,6 +116,33 @@ pick_runtime() { echo "$RUNTIME" } +RUN_CONTAINER_NAME="" + +cleanup_run_container() { + if [[ -n "${RUN_CONTAINER_NAME:-}" && -n "${CONTAINER_RUNTIME:-}" ]]; then + echo "cleaning up interrupted build container: $RUN_CONTAINER_NAME" + "$CONTAINER_RUNTIME" rm -f "$RUN_CONTAINER_NAME" >/dev/null 2>&1 || true + fi +} + +report_run_duration() { + local exit_code="$1" + local outcome="failed" + + if [[ "$exit_code" -eq 0 ]]; then + outcome="completed" + fi + + echo "${SCRIPT_NAME} ${outcome} in $(format_duration "${SECONDS}")" +} + +cleanup_and_report() { + local exit_code="$1" + + cleanup_run_container + report_run_duration "$exit_code" +} + download_file() { local url="$1" local dst="$2" @@ -182,6 +215,14 @@ while [[ $# -gt 0 ]]; do BUILD_TYPE="debug" shift ;; + --qt-only) + BUILD_SCOPE="qt" + shift + ;; + --qtwebkit-only) + BUILD_SCOPE="qtwebkit" + shift + ;; --clean) CLEAN=true shift @@ -200,6 +241,17 @@ if [[ "$BUILD_TYPE" != "release" && "$BUILD_TYPE" != "debug" ]]; then fail "unsupported build type: $BUILD_TYPE" fi +if [[ "$BUILD_SCOPE" != "all" && "$BUILD_SCOPE" != "qt" && "$BUILD_SCOPE" != "qtwebkit" ]]; then + fail "unsupported build scope: $BUILD_SCOPE" +fi + +SECONDS=0 +trap 'cleanup_and_report "$?"' EXIT + +if [[ "$BUILD_SCOPE" == "qtwebkit" && "$CLEAN" == true ]]; then + fail "--qtwebkit-only cannot be combined with --clean because it requires an existing Qt install in the output directory" +fi + if [[ -z "$OUTPUT_DIR" ]]; then OUTPUT_DIR="artifacts/qt5-static-${QT_VERSION}-${BUILD_TYPE}" fi @@ -274,11 +326,16 @@ echo "using container runtime: $CONTAINER_RUNTIME" "$CONTAINER_RUNTIME" build -f "$DOCKERFILE" -t "$IMAGE_TAG" "$REPO_ROOT" +RUN_CONTAINER_NAME="qt5-static-build-$$-$(date +%s)" +trap cleanup_run_container INT TERM HUP + "$CONTAINER_RUNTIME" run --rm \ + --name "$RUN_CONTAINER_NAME" \ --user "$(id -u):$(id -g)" \ -e JOBS="$JOBS" \ -e CLEAN="$CLEAN" \ -e BUILD_TYPE="$BUILD_TYPE" \ + -e BUILD_SCOPE="$BUILD_SCOPE" \ -e QT_VERSION="$QT_VERSION" \ -e OUTPUT_DIR="${OUTPUT_ABS}" \ -e QT_SRC_ARCHIVE="${QT5_SRC_ARCHIVE}" \ @@ -299,4 +356,17 @@ echo "using container runtime: $CONTAINER_RUNTIME" "$IMAGE_TAG" \ "$INNER_SCRIPT" -echo "static Qt5 POC completed: ${OUTPUT_ABS}" +RUN_CONTAINER_NAME="" +trap - INT TERM HUP + +case "$BUILD_SCOPE" in + all) + echo "static Qt5 toolchain completed: ${OUTPUT_ABS}" + ;; + qt) + echo "static Qt build completed: ${OUTPUT_ABS}" + ;; + qtwebkit) + echo "static QtWebKit build completed: ${OUTPUT_ABS}" + ;; +esac diff --git a/docs/docker-static-analysis.md b/docs/docker-static-analysis.md index 740624a..d3b4431 100644 --- a/docs/docker-static-analysis.md +++ b/docs/docker-static-analysis.md @@ -7,7 +7,7 @@ The first milestone is reproducible Docker-backed analysis plus a conservative c ## Decisions - Docker is the canonical build environment and the source of truth for the compilation database. -- Docker also runs `clang-tidy` so it stays on a toolchain version compatible with the Qt `5.5.1` headers in this repository. +- Docker also runs `clang-tidy` so it stays on a toolchain version compatible with the Qt `5.15.17` headers in this repository. - Host-installed `clazy-standalone` consumes the Docker-produced `compile_commands.json`. - `build-browser-docker.sh` is the main entrypoint for Dockerized analysis. - The initial scope is application code only: @@ -27,7 +27,7 @@ The host environment running `build-browser-docker.sh --analyze` must provide: This keeps the build path aligned with Docker while avoiding two compatibility problems: - Ubuntu `16.04` does not provide `clazy` from the default package repositories. -- the host `clang-tidy` available in this environment is too new for the Qt `5.5.1` headers used by this codebase. +- the host `clang-tidy` available in this environment can diverge from the Qt `5.15.17` headers used by this codebase. ## Implementation Changes Extend [`build-browser-docker.sh`](/home/magist3r/code/QtWeb/build-browser-docker.sh) with explicit analysis modes while preserving its current build behavior. @@ -112,7 +112,7 @@ Representative validation files: ## Risks - Ubuntu `16.04` does not provide `clazy` from the default package repositories, so full in-image analyzer installation is not viable in the current base image. -- A host `clang-tidy` that is much newer than Qt `5.5.1` can fail inside Qt headers before project diagnostics are produced. -- Legacy Qt `5.5.1` code and its headers may produce noisy diagnostics if the enabled check set is too broad. +- A host `clang-tidy` that is much newer than Qt `5.15.17` can fail inside Qt headers before project diagnostics are produced. +- Legacy QtWeb code and its headers may produce noisy diagnostics if the enabled check set is too broad. - Generated Qt sources can easily pollute analyzer output if the source list is not explicitly scoped. - A zero-warning target is likely unrealistic for the first pass and would create unnecessary churn. diff --git a/docs/migration.md b/docs/migration.md index db46165..3ec3594 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -1,69 +1,44 @@ -# Qt5 Browser Port Implementation Plan +# Save Migration Plan In `docs` First, Then Execute Qt 5.15.17 Static Migration ## Summary -Port QtWeb to the existing static Qt `5.5.1` toolchain on Linux while keeping the legacy Qt4 flow intact. The implementation base stays on `qt5-migration`, and the existing `qt5` branch is used as the donor for already-solved Qt5 application changes. The first source mutation is the automated Qt4-to-Qt5 header rewrite, followed by targeted manual integration until the full browser builds and runs with torrent and FTP support preserved. All Qt5 browser validation builds must run inside Docker against the repository's containerized toolchain environment rather than on the host, and they must be invoked through the repository helper scripts rather than direct `docker` or ad hoc build commands. Host-local `qmake`/`make`/compiler validation runs are explicitly out of policy for this repository. +- The first step is documentation: save the migration plan in `docs` before any implementation work starts, so the repo has a single agreed source of truth for the Qt `5.15.17` + QtWebKit `5.212` migration. +- After that, migrate the current `qt5-migration` branch from Qt `5.5.1` to Qt `5.15.17` while keeping QtWebKit `5.212`. +- Do not use the `qt5` branch as a donor or reference baseline. All porting work is done in place from the current `qt5-migration` tree. +- Replace the current Qt `5.5.1` static toolchain flow in place rather than adding a parallel Qt `5.15` path. -## Decisions -- Delivery branch: `qt5-migration` -- Donor branch for application porting work: `qt5` -- Target runtime/build baseline: Qt `5.5.1` static Linux `x86_64` -- Required build environment for Qt5 validation: Docker container using the repository image/toolchain -- Required invocation path for Qt5 validation: repository helper scripts such as `build-browser-docker.sh` and `run-broswer.sh`, not direct `docker` commands -- Keep the existing Qt4 `build.sh` path unchanged -- Preserve torrent support in the first Qt5 browser milestone -- Preserve FTP browsing and FTP downloads in the first Qt5 browser milestone +## Key Changes +- Save this plan first in `docs/migration.md`, replacing the current Qt `5.5.1` / donor-branch-oriented plan before any code or script changes begin. +- Retarget the existing toolchain flow in `build-qt5-static.sh`, `toolchains/qt5-static/sources.lock`, and `toolchains/qt5-static/build-inside-container.sh`: +- update locked sources from Qt `5.5.1` to Qt `5.15.17` +- replace the current "unpack `qtwebkit` into the Qt source tree" flow with a standalone QtWebKit `5.212` build against the installed Qt `5.15.17` prefix +- keep static ICU and OpenSSL handling, and continue verifying `libQt5WebKit.a` and `libQt5WebKitWidgets.a` +- Retarget `build-browser-docker.sh` and the QtWebKit smoke build to the new install prefix, image tag, artifact naming, and verification gates. +- Keep `src/QtWeb.pro` on `webkitwidgets`; do not introduce `webenginewidgets` or any engine-switch abstraction. +- Port the application code directly from current `qt5-migration` sources: +- fix compile and link issues caused by Qt `5.15.17` API tightening +- fix any QtWebKit `5.212` API or behavior differences +- preserve existing browser behavior, torrent support, FTP support, downloads, printing, and settings behavior unless a concrete incompatibility forces a narrow adjustment -## Implementation Order -1. Update this document with the concrete execution plan. -2. Run `/home/magist3r/code/qtbase/bin/fixqt4headers.pl` against `src/` and review the generated include rewrites. -3. Bring the qmake project files up to Qt5.5.1: -- `src/QtWeb.pro` must use `widgets`, `webkitwidgets`, and `printsupport` -- `src/torrent/torrent.pro` must stay compatible with Qt `5.5.1` qmake and must not depend on `requires(qtConfig(filedialog))` -4. Replay the relevant Qt5 source-port work from `qt5`: -- Qt5 include/module split across browser UI, WebKit, and print code -- `QStandardPaths` for storage paths -- `QUrlQuery` for query parsing -- Torrent networking migration from `QHttp` to `QNetworkAccessManager` -5. Adapt donor-branch code back down to Qt `5.5.1` where it assumes newer Qt: -- replace `QDateTime::currentSecsSinceEpoch()` -- replace `QRandomGenerator` -- replace `QOverload` connect syntax -6. Restore and keep both legacy feature areas: -- torrent remains built into the application -- FTP remains supported in `webview` for directory listing and file download -7. Validate the main browser inside Docker on top of the existing smoke-test/toolchain work, using the repository helper scripts instead of direct container or compiler invocations. - -## Public and Internal Interfaces -- No new user-facing CLI or configuration layer is added. -- Internal build interfaces change to Qt5-aware qmake module usage in: -- `src/QtWeb.pro` -- `src/torrent/torrent.pro` -- Torrent internal types move from `QHttp`-based APIs to `QNetworkAccessManager` / `QNetworkReply`. -- Storage path handling moves to `QStandardPaths`. -- Query parsing moves from deprecated Qt4 APIs to `QUrlQuery`. - -## Required Behavior -- The browser must launch and render pages under Qt5. -- Tabs, windows, and navigation behavior must remain functional. -- Downloads must continue to work. -- Torrent support must build and reach tracker communication under Qt5. -- `ftp://` directory browsing must still work. -- FTP file downloads must still work. -- Portable and non-portable settings/data paths must continue to resolve correctly. +## Execution Order +1. Replace `docs/migration.md` with the Qt `5.15.17` + QtWebKit `5.212` migration plan and treat that document as the implementation baseline. +2. Replace the current Qt `5.5.1` toolchain lock, artifact names, and verification assumptions with Qt `5.15.17`. +3. Implement the standalone QtWebKit `5.212` build/install step and prove the static libraries install into the Qt prefix. +4. Update the QtWebKit smoke build and require it to compile/link successfully inside Docker before proceeding. +5. Retarget the main browser Docker build helper to the new prefix and compile the current app as-is to expose the real Qt `5.15.17` breakage list. +6. Fix the browser code in place on `qt5-migration`, starting with WebKit-facing code and then any remaining Qt `5.15.17` compatibility issues. +7. Validate build success through the sanctioned helper scripts and update the remaining Qt5 toolchain docs to match the implemented flow. ## Validation -- Documentation reflects the chosen implementation path and constraints. -- qmake generation succeeds inside Docker when invoked through `build-browser-docker.sh`. -- A clean out-of-tree browser build succeeds inside Docker through the helper scripts, with outputs kept in repository-local `build-docker-*` directories. -- Validate changed Bash / POSIX shell scripts with `shellcheck` when script changes are part of the work. -- Browser smoke validation covers page loading, tabs, windows, downloads, and print-related actions. -- Torrent validation covers successful build and tracker communication after the networking port. -- FTP validation covers directory listing and file download. -- Regression checks cover settings/data paths and autocomplete/password/query parsing after API replacements. +- Documentation gate: `docs/migration.md` is updated first and accurately describes the chosen migration strategy. +- Toolchain gate: `build-qt5-static.sh` produces a static Qt `5.15.17` install and static QtWebKit `5.212` libraries. +- Smoke gate: `smoke-tests/qtwebkit-smoke` builds and links against the produced prefix in Docker. +- Browser gate: `build-browser-docker.sh` completes for release; debug is secondary after release passes. +- Runtime regression testing is explicitly user-owned and out of scope for agent execution. -## Known Risks -- The `qt5` donor branch was written against newer Qt and contains incompatible APIs for `5.5.1`. -- FTP was partially disabled in the donor branch and must be reintroduced without regressing navigation behavior. -- Settings-path or key drift can create silent compatibility regressions. -- Static-build constraints may surface additional link/runtime issues after compilation succeeds. -- Host-native builds can hide or invent problems relative to the intended toolchain, so the Docker helper-script path is the source of truth for Qt5 validation. +## Assumptions And Defaults +- Work starts from current `qt5-migration` head only; the `qt5` branch is explicitly out of scope. +- Qt baseline is pinned to `5.15.17`. +- Linux `x86_64` only. +- Existing Qt4 flow stays untouched. +- QtWebKit `5.212` is accepted despite its age and security risk; this migration plan does not include an engine replacement track. +- If the static QtWebKit smoke gate fails and cannot be resolved cleanly, the migration stops with a documented blocker rather than pivoting to Qt WebEngine. diff --git a/docs/qt5-static-poc.md b/docs/qt5-static-poc.md index bca851a..e3a9bed 100644 --- a/docs/qt5-static-poc.md +++ b/docs/qt5-static-poc.md @@ -4,22 +4,24 @@ Build a reproducible static Qt5 toolchain for QtWeb migration on Linux `x86_64`. Target versions: -- Qt `5.5.1` -- QtWebKit `5.5.1` +- Qt `5.15.17` +- QtWebKit `5.212.0-alpha4` -This POC validates the toolchain pipeline only (not the QtWeb app build). +This POC validates the toolchain pipeline and the QtWebKit smoke-build gate. Primary portability target: static linking plus minimal runtime dependencies. ## Non-Goals -- Migrating QtWeb application sources. +- Running the QtWeb browser UI or other runtime smoke tests on the agent. - Windows/macOS support. - Modifying legacy Qt4 flow in `build.sh`. +- Migrating the browser engine to Qt WebEngine. ## Fixed Baseline -- Qt version is locked to `5.5.1`. +- Qt version is locked to `5.15.17`. +- QtWebKit version is locked to `5.212.0-alpha4`. - Containerized build is required (`podman` or `docker`). - ICU support is required for Qt5 + QtWebKit in this path. -- Outputs stay inside the repository (default: `artifacts/qt5-static-5.5.1`). +- Outputs stay inside the repository (default: `artifacts/qt5-static-5.15.17`). ## Inputs - Wrapper script: `build-qt5-static.sh` @@ -38,22 +40,22 @@ Supported source override env vars: Checksum policy: 1. Prefer `sha256`. -2. Allow `md5` fallback only when `sha256` is unavailable in legacy metadata. +2. Allow `md5` fallback only when `sha256` is unavailable in locked metadata. 3. Abort immediately on mismatch. ## Output Layout -Default root: `artifacts/qt5-static-5.5.1` +Default build roots: `artifacts/qt5-static-5.15.17-release` and `artifacts/qt5-static-5.15.17-debug` - `artifacts/src-cache/`: shared downloaded archives for all build flavors - `build/`: extracted/build tree - `install/`: static Qt install prefix - `icu-static/`: static ICU install prefix -- `logs/`: `icu-configure.log`, `icu-build.log`, `icu-install.log`, `configure.log`, `build.log`, `install.log`, `verify.log` +- `logs/`: `icu-configure.log`, `icu-build.log`, `icu-install.log`, `configure.log`, `build.log`, `install.log`, `qtwebkit-configure.log`, `qtwebkit-build.log`, `qtwebkit-install.log`, `smoke-build.log`, `verify.log` - `build-manifest.txt`: runtime, source URLs/checksums, configure flags, verification summary ## Verification Gates A successful run must satisfy: -1. `qmake -query QT_VERSION` is `5.5.1`. +1. `qmake -query QT_VERSION` is `5.15.17`. 2. Install is static (`QT_CONFIG` contains `static` or static libs prove it). 3. Required static libs exist in `install/lib`: - `libQt5Core.a` @@ -64,34 +66,34 @@ A successful run must satisfy: - `libQt5PrintSupport.a` - `libQt5WebKit.a` - `libQt5WebKitWidgets.a` -4. Verification log ends with `verification passed`. -5. Required static ICU libs exist in `icu-static/lib`: +4. Required static ICU libs exist in `icu-static/lib`: - `libicuuc.a` - `libicui18n.a` - `libicudata.a` +5. The QtWebKit smoke app compiles and links against the produced toolchain. +6. Verification log ends with `verification passed`. -## Current Status vs Planned Gates -Implemented now: +## Current Status +Implemented target behavior: - Containerized build pipeline. - Source lock + checksum verification. - In-container static ICU build from locked source archive. +- Static Qt build. +- Standalone QtWebKit build against installed Qt. - Static Qt + QtWebKit library verification. - Static ICU library verification. +- QtWebKit smoke test compile/link gate. - Manifest/log generation. -Planned (not yet enforced by scripts): -- QtWebKit smoke test binary compile/link gate against produced toolchain. -- Digest-pinned container base image (currently tag-pinned `ubuntu:16.04`). - ## Run Examples Default run: ```bash ./build-qt5-static.sh ``` -Clean rebuild with explicit runtime and jobs: +Clean rebuild: ```bash -./build-qt5-static.sh --clean --runtime podman --jobs 8 +./build-qt5-static.sh --clean ``` Custom output directory inside repo: @@ -100,13 +102,13 @@ Custom output directory inside repo: ``` ## Risks -- Legacy Qt/QtWebKit code may fail under newer host toolchains. -- Static WebKit can still be rejected by configure constraints. +- Legacy Qt/QtWebKit code may fail under newer host and container toolchains. +- Static QtWebKit can still require follow-up patches for newer compilers or linkers. - Archive URLs may become unavailable over time. -- Over-aggressive dependency reduction can break TLS/cert/platform behavior. +- Over-aggressive dependency reduction can break TLS, certificate handling, or module detection. +- Runtime browser validation remains user-owned. -## Next POC Tasks -1. Add and enforce the QtWebKit smoke-test build gate. -2. Add SSL/TLS support in the Qt5 static build and validate it with an HTTPS smoke test. -3. Move Docker base image from tag pinning to digest pinning. -4. Define explicit dependency-audit output for produced artifacts (for example `ldd` policy and exceptions). +## Next Tasks +1. Build the main browser with `build-browser-docker.sh` against the produced toolchain. +2. Fix Qt `5.15.17` or QtWebKit `5.212` source incompatibilities exposed by that build. +3. Move the Docker base image from tag pinning to digest pinning when refreshed online. diff --git a/run-broswer.sh b/run-browser.sh similarity index 100% rename from run-broswer.sh rename to run-browser.sh diff --git a/smoke-run.sh b/run-smoke.sh similarity index 100% rename from smoke-run.sh rename to run-smoke.sh diff --git a/smoke-tests/qtwebkit-smoke/README.md b/smoke-tests/qtwebkit-smoke/README.md index 8678732..acbefe3 100644 --- a/smoke-tests/qtwebkit-smoke/README.md +++ b/smoke-tests/qtwebkit-smoke/README.md @@ -1,6 +1,6 @@ # QtWebKit Smoke Test -Minimal Qt 5.5.1 QtWebKitWidgets app used to verify that the custom Qt build +Minimal Qt 5.15.17 QtWebKitWidgets app used to verify that the custom Qt build can compile and link a `QWebView` application. ## Files diff --git a/src/QtWeb.pro b/src/QtWeb.pro index aaf4a9a..e3d29c6 100644 --- a/src/QtWeb.pro +++ b/src/QtWeb.pro @@ -1,6 +1,6 @@ TEMPLATE = app TARGET = QtWeb -QT += network xml webkitwidgets widgets printsupport +QT += network network-private xml webkitwidgets widgets printsupport CONFIG += static c++11 DEFINES += QT_NO_UITOOLS @@ -9,8 +9,6 @@ INCLUDEPATH += moc \ uic \ . -INCLUDEPATH += $$[QT_INSTALL_HEADERS]/QtNetwork/$$QT_VERSION/QtNetwork - MOC_DIR = moc/ OBJECTS_DIR = obj/ UI_DIR = uic/ diff --git a/src/main.cpp b/src/main.cpp index 80346e4..99d65fa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -46,13 +46,7 @@ int main(int argc, char **argv) #ifndef QT_SHARED Q_INIT_RESOURCE(WebCore); - Q_INIT_RESOURCE(WebKit); - -# if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) - Q_INIT_RESOURCE(InspectorBackendCommands); -# else - Q_INIT_RESOURCE(InspectorBackendStub); -# endif + Q_INIT_RESOURCE(WebInspector); #endif BrowserApplication application(argc, argv); diff --git a/toolchains/qt5-static/Dockerfile b/toolchains/qt5-static/Dockerfile index da9b652..653420f 100644 --- a/toolchains/qt5-static/Dockerfile +++ b/toolchains/qt5-static/Dockerfile @@ -1,5 +1,5 @@ # Base image is version-tagged; switch to a digest-pinned reference when refreshed online. -FROM ubuntu:16.04 +FROM ubuntu:20.04 ENV DEBIAN_FRONTEND=noninteractive ENV LANG=C.UTF-8 @@ -12,13 +12,26 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ clang \ clang-tidy \ + cmake \ curl \ file \ flex \ + fonts-dejavu-core \ + git \ gperf \ - # libdbus-1-dev \ + libdbus-1-dev \ + libegl1-mesa-dev \ + libfontconfig1-dev \ + libfreetype6-dev \ libglib2.0-dev \ - # libsqlite3-dev \ + libgl1-mesa-dev \ + libgles2-mesa-dev \ + libhyphen-dev \ + libicu-dev \ + libjpeg-dev \ + liblzma-dev \ + libpng-dev \ + libsqlite3-dev \ libssl-dev \ libx11-dev \ libx11-xcb-dev \ @@ -28,15 +41,30 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libxext-dev \ libxfixes-dev \ libxi-dev \ - # libxml2-dev \ + libxml2-dev \ libxrandr-dev \ libxrender-dev \ - # libxslt1-dev \ + libxslt1-dev \ libxcb1-dev \ + libxcb-icccm4-dev \ + libxcb-image0-dev \ + libxcb-keysyms1-dev \ + libxcb-randr0-dev \ + libxcb-render-util0-dev \ + libxcb-shape0-dev \ + libxcb-shm0-dev \ + libxcb-sync-dev \ + libxcb-util-dev \ + libxcb-xfixes0-dev \ + libxcb-xinerama0-dev \ + libxkbcommon-dev \ + libxkbcommon-x11-dev \ + ninja-build \ patch \ perl \ pkg-config \ - python \ + python3 \ + python-is-python3 \ ruby \ && rm -rf /var/lib/apt/lists/* diff --git a/toolchains/qt5-static/build-inside-container.sh b/toolchains/qt5-static/build-inside-container.sh index d8df5b9..610fdcf 100755 --- a/toolchains/qt5-static/build-inside-container.sh +++ b/toolchains/qt5-static/build-inside-container.sh @@ -7,64 +7,75 @@ set -euo pipefail : "${QTWEBKIT_ARCHIVE:?QTWEBKIT_ARCHIVE is required}" : "${ICU_SRC_ARCHIVE:?ICU_SRC_ARCHIVE is required}" -JOBS="${JOBS:-8}" +JOBS="${JOBS:-$(nproc 2>/dev/null || echo 8)}" CLEAN="${CLEAN:-false}" BUILD_TYPE="${BUILD_TYPE:-release}" +BUILD_SCOPE="${BUILD_SCOPE:-all}" WORK_DIR="${OUTPUT_DIR}/build" LOG_DIR="${OUTPUT_DIR}/logs" INSTALL_DIR="${OUTPUT_DIR}/install" ICU_INSTALL_DIR="${OUTPUT_DIR}/icu-static" OPENSSL_INCLUDE_DIR="/usr/include" OPENSSL_LIB_DIR="/usr/lib/x86_64-linux-gnu" +SYSTEM_LIB_DIR="/usr/lib/x86_64-linux-gnu" +DEJAVU_FONT_DIR="/usr/share/fonts/truetype/dejavu" MANIFEST_FILE="${OUTPUT_DIR}/build-manifest.txt" -QT_SRC_DIR="${WORK_DIR}/qt-everywhere-opensource-src-${QT_VERSION}" PATCH_DIR="/workspace/toolchains/qt5-static/patches" +QT_SRC_DIR="" +QTWEBKIT_SOURCE_DIR="" +QTWEBKIT_BUILD_DIR="${WORK_DIR}/qtwebkit-build-${BUILD_TYPE}" +SMOKE_DIR="/workspace/smoke-tests/qtwebkit-smoke" +SMOKE_BUILD_DIR="${SMOKE_DIR}/build-docker-${BUILD_TYPE}" fail() { echo "error: $*" >&2 exit 1 } -MIN_DEP_CONFIGURE_FLAGS=( - -no-dbus - -no-gtkstyle - -no-fontconfig - -xkb-config-root /usr/share/X11/xkb - -icu - -qt-pcre - -qt-freetype - -qt-xcb - -qt-xkbcommon-x11 -) case "$BUILD_TYPE" in release) BUILD_CONFIGURE_FLAG="-release" + CMAKE_BUILD_TYPE="Release" ;; debug) BUILD_CONFIGURE_FLAG="-debug" + CMAKE_BUILD_TYPE="Debug" ;; *) fail "BUILD_TYPE must be release or debug, got: $BUILD_TYPE" ;; esac +case "$BUILD_SCOPE" in + all|qt|qtwebkit) ;; + *) + fail "BUILD_SCOPE must be all, qt, or qtwebkit; got: $BUILD_SCOPE" + ;; +esac + CONFIGURE_FLAGS=( -opensource -confirm-license "$BUILD_CONFIGURE_FLAG" -static -prefix "$INSTALL_DIR" + -skip qtwebengine -nomake tests -nomake examples -nomake tools + -no-dbus + -no-gtk + -no-fontconfig + -qt-pcre + -qt-freetype -qt-zlib -qt-libpng -qt-libjpeg + -icu -I "${ICU_INSTALL_DIR}/include" -L "${ICU_INSTALL_DIR}/lib" - -L "${OPENSSL_LIB_DIR}" -openssl-linked - "${MIN_DEP_CONFIGURE_FLAGS[@]}" + -L "${OPENSSL_LIB_DIR}" ) require_file() { @@ -77,47 +88,48 @@ require_dir() { [[ -d "$path" ]] || fail "missing directory: $path" } +is_thin_archive() { + local path="$1" + file "$path" 2>/dev/null | grep -q 'thin archive' +} + log_verify() { local message="$1" echo "$message" echo "$message" >> "${LOG_DIR}/verify.log" } -apply_patches() { +locate_qt_source_dir() { + find "$WORK_DIR" -maxdepth 1 -mindepth 1 -type d -name "qt-everywhere*-${QT_VERSION}" | head -n 1 +} + +apply_matching_patches() { + local tree_name="$1" + local tree_patch_dir="${PATCH_DIR}/${tree_name}" local patch_files=() local patch_file - if [[ ! -d "$PATCH_DIR" ]]; then + if [[ ! -d "$tree_patch_dir" ]]; then return 0 fi - mapfile -t patch_files < <(find "$PATCH_DIR" -maxdepth 1 -type f -name '*.patch' | sort) + mapfile -t patch_files < <(find "$tree_patch_dir" -maxdepth 1 -type f -name '*.patch' | sort) if [[ "${#patch_files[@]}" -eq 0 ]]; then return 0 fi for patch_file in "${patch_files[@]}"; do if patch --dry-run -p1 < "$patch_file" >/dev/null 2>&1; then + echo "==> apply ${tree_name} patch: $(basename "$patch_file")" patch -p1 < "$patch_file" elif patch --dry-run -R -p1 < "$patch_file" >/dev/null 2>&1; then - echo "==> patch already applied: $(basename "$patch_file")" + echo "==> ${tree_name} patch already applied: $(basename "$patch_file")" else - fail "could not apply patch: $patch_file" + fail "${tree_name} patch does not apply cleanly: $(basename "$patch_file")" fi done } -configure_qt() { - local log_file="$1" - echo "==> configure Qt" - ./configure -v "${CONFIGURE_FLAGS[@]}" >"$log_file" 2>&1 -} - -webkit_disabled_by_static_notice() { - local log_file="$1" - grep -q "Using static linking will disable the WebKit module." "$log_file" -} - build_static_icu() { local extract_dir icu_top_dir icu_source_dir @@ -174,6 +186,11 @@ configure_build_env_for_qt() { export OPENSSL_LIBS="-Wl,-Bstatic ${OPENSSL_LIB_DIR}/libssl.a ${OPENSSL_LIB_DIR}/libcrypto.a -Wl,-Bdynamic -ldl -lpthread -lz" } +configure_qt() { + echo "==> configure Qt" + ./configure -v "${CONFIGURE_FLAGS[@]}" >"${LOG_DIR}/configure.log" 2>&1 +} + sync_installed_qmake_metadata() { local qtbase_build_dir="${QT_SRC_DIR}/qtbase" local build_qconfig="${qtbase_build_dir}/mkspecs/qconfig.pri" @@ -195,6 +212,123 @@ sync_installed_qmake_metadata() { sed "s|${qtbase_build_dir}/lib|${install_lib_expr}|g" "$build_network_prl" > "$install_network_prl" } +install_qt_runtime_fonts() { + local font_dir="${INSTALL_DIR}/lib/fonts" + local font_files=("${DEJAVU_FONT_DIR}"/*.ttf) + + require_dir "${INSTALL_DIR}/lib" + require_dir "$DEJAVU_FONT_DIR" + [[ -e "${font_files[0]}" ]] || fail "no DejaVu TTF fonts found in ${DEJAVU_FONT_DIR}" + + mkdir -p "$font_dir" + cp -f "${font_files[@]}" "$font_dir"/ +} + +sync_installed_qtwebkit_metadata() { + local webkit_module_pri="${INSTALL_DIR}/mkspecs/modules/qt_lib_webkit.pri" + local webkitwidgets_module_pri="${INSTALL_DIR}/mkspecs/modules/qt_lib_webkitwidgets.pri" + local install_lib_expr='$$QT_MODULE_LIB_BASE' + local webkit_private_libs="-L${install_lib_expr} -lWebCore -lANGLESupport -lJavaScriptCore -lWTF ${SYSTEM_LIB_DIR}/libxml2.a ${SYSTEM_LIB_DIR}/liblzma.a ${SYSTEM_LIB_DIR}/libicui18n.a ${SYSTEM_LIB_DIR}/libicuuc.a ${SYSTEM_LIB_DIR}/libicudata.a ${SYSTEM_LIB_DIR}/libsqlite3.a -lz -lbmalloc -lxslt ${SYSTEM_LIB_DIR}/libhyphen.a -lwoff2 -lbrotli" + + require_file "$webkit_module_pri" + + if ! grep -Fq -- "-L${install_lib_expr}" "$webkit_module_pri"; then + sed -i "s|^QMAKE_LIBS_PRIVATE += |QMAKE_LIBS_PRIVATE += -L${install_lib_expr} |" "$webkit_module_pri" + fi + + if ! grep -Fq -- "-lANGLESupport" "$webkit_module_pri"; then + sed -i 's/-lWebCore /-lWebCore -lANGLESupport /' "$webkit_module_pri" + fi + + sed -i "s|^QMAKE_LIBS_PRIVATE += .*|QMAKE_LIBS_PRIVATE += ${webkit_private_libs}|" "$webkit_module_pri" + + if [[ -f "$webkitwidgets_module_pri" ]]; then + sed -i 's/\(QT\.webkitwidgets\.module_config = .*v2\)\s*$/\1 staticlib/' "$webkitwidgets_module_pri" + fi +} + +build_qtwebkit() { + local extract_dir source_root + + require_file "$QTWEBKIT_ARCHIVE" + if [[ -f "${INSTALL_DIR}/lib/libQt5WebKit.a" && -f "${INSTALL_DIR}/lib/libQt5WebKitWidgets.a" ]]; then + if is_thin_archive "${INSTALL_DIR}/lib/libQt5WebKit.a" || is_thin_archive "${INSTALL_DIR}/lib/libQt5WebKitWidgets.a"; then + fail "installed QtWebKit archives are thin; remove the installed QtWebKit artifacts and rerun so they can be rebuilt as normal archives" + fi + sync_installed_qtwebkit_metadata + echo "==> reusing installed QtWebKit from ${INSTALL_DIR}" + return + fi + + echo "==> extract QtWebKit" + extract_dir="${WORK_DIR}/_qtwebkit_extract" + rm -rf "$extract_dir" "$QTWEBKIT_BUILD_DIR" + mkdir -p "$extract_dir" "$QTWEBKIT_BUILD_DIR" + tar -xf "$QTWEBKIT_ARCHIVE" -C "$extract_dir" + + source_root="$(find "$extract_dir" -mindepth 1 -maxdepth 1 -type d | head -n 1)" + [[ -n "$source_root" ]] || fail "could not identify extracted QtWebKit source directory" + QTWEBKIT_SOURCE_DIR="${WORK_DIR}/$(basename "$source_root")" + rm -rf "$QTWEBKIT_SOURCE_DIR" + mv "$source_root" "$QTWEBKIT_SOURCE_DIR" + rm -rf "$extract_dir" + + pushd "$QTWEBKIT_SOURCE_DIR" >/dev/null + apply_matching_patches "qtwebkit" + popd >/dev/null + + pushd "$QTWEBKIT_BUILD_DIR" >/dev/null + echo "==> configure QtWebKit" + cmake -G Ninja \ + -DPORT=Qt \ + -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" \ + -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \ + -DCMAKE_PREFIX_PATH="${INSTALL_DIR};${ICU_INSTALL_DIR}" \ + -DQt5_DIR="${INSTALL_DIR}/lib/cmake/Qt5" \ + -DICU_ROOT="${ICU_INSTALL_DIR}" \ + -DENABLE_API_TESTS=OFF \ + -DENABLE_TOOLS=OFF \ + -DENABLE_GEOLOCATION=OFF \ + -DENABLE_PRINT_SUPPORT=ON \ + -DENABLE_VIDEO=OFF \ + -DENABLE_WEBKIT2=OFF \ + -DUSE_THIN_ARCHIVES=OFF \ + -DUSE_GSTREAMER=OFF \ + -DUSE_LD_GOLD=OFF \ + "${QTWEBKIT_SOURCE_DIR}" >"${LOG_DIR}/qtwebkit-configure.log" 2>&1 + echo "==> build QtWebKit" + ninja -j"$JOBS" >"${LOG_DIR}/qtwebkit-build.log" 2>&1 + echo "==> install QtWebKit" + ninja install >"${LOG_DIR}/qtwebkit-install.log" 2>&1 + sync_installed_qtwebkit_metadata + popd >/dev/null +} + +build_smoke_test() { + local qmake_config_args + + require_file "${INSTALL_DIR}/bin/qmake" + require_file "${SMOKE_DIR}/qtwebkit-smoke.pro" + + echo "==> build QtWebKit smoke test" + rm -rf "${SMOKE_BUILD_DIR}" + mkdir -p "${SMOKE_BUILD_DIR}" + pushd "${SMOKE_BUILD_DIR}" >/dev/null + if [[ "${BUILD_TYPE}" == "release" ]]; then + qmake_config_args="CONFIG+=release CONFIG-=debug" + else + qmake_config_args="CONFIG+=debug CONFIG-=release" + fi + "${INSTALL_DIR}/bin/qmake" ../qtwebkit-smoke.pro ${qmake_config_args} >"${LOG_DIR}/smoke-build.log" 2>&1 + make -j"$JOBS" >>"${LOG_DIR}/smoke-build.log" 2>&1 + if [[ -f /etc/ssl/certs/ca-certificates.crt ]]; then + cp /etc/ssl/certs/ca-certificates.crt ./ca-certificates.crt + fi + popd >/dev/null + + require_file "${SMOKE_BUILD_DIR}/qtwebkit-smoke" +} + mkdir -p "$WORK_DIR" "$LOG_DIR" require_file "$QT_SRC_ARCHIVE" require_file "$QTWEBKIT_ARCHIVE" @@ -202,47 +336,47 @@ require_file "$ICU_SRC_ARCHIVE" case "${CLEAN,,}" in 1|true|yes|on) - rm -rf "$QT_SRC_DIR" "$INSTALL_DIR" "$ICU_INSTALL_DIR" + find "$WORK_DIR" -maxdepth 1 -mindepth 1 -type d -name "qt-everywhere*-${QT_VERSION}" -exec rm -rf {} + + rm -rf "$QTWEBKIT_BUILD_DIR" "$INSTALL_DIR" "$ICU_INSTALL_DIR" ;; esac -build_static_icu -configure_build_env_for_qt - -if [[ ! -d "$QT_SRC_DIR" ]]; then - tar -xf "$QT_SRC_ARCHIVE" -C "$WORK_DIR" -fi -[[ -d "$QT_SRC_DIR" ]] || fail "expected source directory not found: $QT_SRC_DIR" +if [[ "$BUILD_SCOPE" == "all" || "$BUILD_SCOPE" == "qt" ]]; then + build_static_icu + configure_build_env_for_qt -if [[ ! -d "${QT_SRC_DIR}/qtwebkit" ]]; then - EXTRACT_DIR="${WORK_DIR}/_qtwebkit_extract" - rm -rf "$EXTRACT_DIR" - mkdir -p "$EXTRACT_DIR" - tar -xf "$QTWEBKIT_ARCHIVE" -C "$EXTRACT_DIR" - - QTWEBKIT_SRC_DIR="$(find "$EXTRACT_DIR" -mindepth 1 -maxdepth 1 -type d | head -n 1)" - [[ -n "$QTWEBKIT_SRC_DIR" ]] || fail "could not identify extracted QtWebKit source directory" + if [[ ! -x "${INSTALL_DIR}/bin/qmake" ]]; then + find "$WORK_DIR" -maxdepth 1 -mindepth 1 -type d -name "qt-everywhere*-${QT_VERSION}" -exec rm -rf {} + + fi - mv "$QTWEBKIT_SRC_DIR" "${QT_SRC_DIR}/qtwebkit" - rm -rf "$EXTRACT_DIR" + QT_SRC_DIR="$(locate_qt_source_dir)" + if [[ -z "$QT_SRC_DIR" ]]; then + tar -xf "$QT_SRC_ARCHIVE" -C "$WORK_DIR" + fi + QT_SRC_DIR="$(locate_qt_source_dir)" + [[ -d "$QT_SRC_DIR" ]] || fail "expected source directory not found: $QT_SRC_DIR" + + pushd "$QT_SRC_DIR" >/dev/null + apply_matching_patches "qt" + configure_qt + echo "==> build Qt (make -j${JOBS})" + make -j"$JOBS" >"${LOG_DIR}/build.log" 2>&1 + echo "==> install Qt" + make install >"${LOG_DIR}/install.log" 2>&1 + sync_installed_qmake_metadata + install_qt_runtime_fonts + popd >/dev/null fi -pushd "$QT_SRC_DIR" >/dev/null -log_verify "configure minimal-deps flags: ${MIN_DEP_CONFIGURE_FLAGS[*]}" -apply_patches -configure_qt "${LOG_DIR}/configure.log" - -if webkit_disabled_by_static_notice "${LOG_DIR}/configure.log"; then - log_verify "warning: configure still reports static WebKit disable notice; continuing to build and validating via installed libraries" +if [[ "$BUILD_SCOPE" == "all" || "$BUILD_SCOPE" == "qtwebkit" ]]; then + build_static_icu + configure_build_env_for_qt + require_file "${INSTALL_DIR}/bin/qmake" + install_qt_runtime_fonts + build_qtwebkit + build_smoke_test fi -echo "==> build Qt (make -j${JOBS})" -make -j"$JOBS" >"${LOG_DIR}/build.log" 2>&1 -echo "==> install Qt" -make install >"${LOG_DIR}/install.log" 2>&1 -sync_installed_qmake_metadata -popd >/dev/null - QMAKE_BIN="${INSTALL_DIR}/bin/qmake" require_file "$QMAKE_BIN" @@ -268,11 +402,16 @@ required_libs=( "libQt5Widgets.a" "libQt5Network.a" "libQt5Xml.a" - "libQt5PrintSupport.a" - "libQt5WebKit.a" - "libQt5WebKitWidgets.a" ) +if [[ "$BUILD_SCOPE" == "all" || "$BUILD_SCOPE" == "qtwebkit" ]]; then + required_libs+=( + "libQt5PrintSupport.a" + "libQt5WebKit.a" + "libQt5WebKitWidgets.a" + ) +fi + required_icu_libs=( "libicuuc.a" "libicui18n.a" @@ -303,8 +442,8 @@ for lib in "${required_ssl_libs[@]}"; do missing=1 fi done -if ! grep -q 'openssl-linked' "${INSTALL_DIR}/mkspecs/qconfig.pri"; then - log_verify "missing openssl-linked in: ${INSTALL_DIR}/mkspecs/qconfig.pri" +if ! grep -q 'openssl-linked' "${INSTALL_DIR}/mkspecs/modules/qt_lib_network_private.pri"; then + log_verify "missing openssl-linked in: ${INSTALL_DIR}/mkspecs/modules/qt_lib_network_private.pri" missing=1 fi if ! grep -q 'libssl\.a' "${INSTALL_DIR}/lib/libQt5Network.prl" \ @@ -321,7 +460,7 @@ fi echo "jobs=${JOBS}" echo "clean=${CLEAN}" echo "build_type=${BUILD_TYPE}" - echo "minimal_dep_configure_flags=${MIN_DEP_CONFIGURE_FLAGS[*]}" + echo "build_scope=${BUILD_SCOPE}" echo "qt_src_archive=${QT_SRC_ARCHIVE}" echo "qtwebkit_archive=${QTWEBKIT_ARCHIVE}" echo "icu_src_archive=${ICU_SRC_ARCHIVE}" @@ -340,6 +479,9 @@ fi echo "verified_libs=${required_libs[*]}" echo "verified_icu_libs=${required_icu_libs[*]}" echo "verified_ssl_libs=${required_ssl_libs[*]}" + if [[ "$BUILD_SCOPE" == "all" || "$BUILD_SCOPE" == "qtwebkit" ]]; then + echo "smoke_binary=${SMOKE_BUILD_DIR}/qtwebkit-smoke" + fi } > "$MANIFEST_FILE" log_verify "verification passed" diff --git a/toolchains/qt5-static/common.sh b/toolchains/qt5-static/common.sh index 9e5b04a..65ad078 100644 --- a/toolchains/qt5-static/common.sh +++ b/toolchains/qt5-static/common.sh @@ -1,2 +1,27 @@ -QT_VERSION="5.5.1" +QT_VERSION="5.15.17" QT5_STATIC_IMAGE_TAG="qtweb-qt5-static-poc:${QT_VERSION}" + +format_duration() { + local total_seconds="$1" + local hours minutes seconds + + if (( total_seconds < 0 )); then + total_seconds=0 + fi + + hours=$((total_seconds / 3600)) + minutes=$(((total_seconds % 3600) / 60)) + seconds=$((total_seconds % 60)) + + if (( hours > 0 )); then + printf '%dh %02dm %02ds' "$hours" "$minutes" "$seconds" + return + fi + + if (( minutes > 0 )); then + printf '%dm %02ds' "$minutes" "$seconds" + return + fi + + printf '%ds' "$seconds" +} diff --git a/toolchains/qt5-static/patches/0001-enable-static-webkit.patch b/toolchains/qt5-static/patches/0001-enable-static-webkit.patch deleted file mode 100644 index 57ca328..0000000 --- a/toolchains/qt5-static/patches/0001-enable-static-webkit.patch +++ /dev/null @@ -1,15 +0,0 @@ ---- a/qtbase/configure -+++ b/qtbase/configure -@@ -6439,12 +6439,6 @@ - canBuildWebKit="no" - fi - --if [ "$CFG_SHARED" = "no" ]; then -- echo -- echo "WARNING: Using static linking will disable the WebKit module." -- echo -- canBuildWebKit="no" --fi - - CFG_CONCURRENT="yes" - if [ "$canBuildQtConcurrent" = "no" ]; then diff --git a/toolchains/qt5-static/patches/0002-javascriptcore-jschar-uchar-casts.patch b/toolchains/qt5-static/patches/0002-javascriptcore-jschar-uchar-casts.patch deleted file mode 100644 index 598a507..0000000 --- a/toolchains/qt5-static/patches/0002-javascriptcore-jschar-uchar-casts.patch +++ /dev/null @@ -1,29 +0,0 @@ ---- a/qtwebkit/Source/JavaScriptCore/API/JSStringRef.cpp -+++ b/qtwebkit/Source/JavaScriptCore/API/JSStringRef.cpp -@@ -37,7 +37,7 @@ - JSStringRef JSStringCreateWithCharacters(const JSChar* chars, size_t numChars) - { - initializeThreading(); -- return OpaqueJSString::create(chars, numChars).leakRef(); -+ return OpaqueJSString::create(reinterpret_cast(chars), numChars).leakRef(); - } - - JSStringRef JSStringCreateWithUTF8CString(const char* string) -@@ -62,7 +62,7 @@ - JSStringRef JSStringCreateWithCharactersNoCopy(const JSChar* chars, size_t numChars) - { - initializeThreading(); -- return OpaqueJSString::create(StringImpl::createWithoutCopying(chars, numChars, WTF::DoesNotHaveTerminatingNullCharacter)).leakRef(); -+ return OpaqueJSString::create(StringImpl::createWithoutCopying(reinterpret_cast(chars), numChars, WTF::DoesNotHaveTerminatingNullCharacter)).leakRef(); - } - - JSStringRef JSStringRetain(JSStringRef string) -@@ -83,7 +83,7 @@ - - const JSChar* JSStringGetCharactersPtr(JSStringRef string) - { -- return string->characters(); -+ return reinterpret_cast(string->characters()); - } - - size_t JSStringGetMaximumUTF8CStringSize(JSStringRef string) diff --git a/toolchains/qt5-static/patches/0003-unixmake2-wrap-qmake-libs-in-start-end-group.patch b/toolchains/qt5-static/patches/0003-unixmake2-wrap-qmake-libs-in-start-end-group.patch deleted file mode 100644 index 55bcca7..0000000 --- a/toolchains/qt5-static/patches/0003-unixmake2-wrap-qmake-libs-in-start-end-group.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/qtbase/qmake/generators/unix/unixmake2.cpp b/qtbase/qmake/generators/unix/unixmake2.cpp -index 3e2b4f2..a11f44e 100644 ---- a/qtbase/qmake/generators/unix/unixmake2.cpp -+++ b/qtbase/qmake/generators/unix/unixmake2.cpp -@@ -188,8 +188,10 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) - if(!project->isActiveConfig("staticlib")) { - t << "LINK = " << var("QMAKE_LINK") << endl; - t << "LFLAGS = " << var("QMAKE_LFLAGS") << endl; -- t << "LIBS = $(SUBLIBS) " << fixLibFlags("QMAKE_LIBS").join(' ') << ' ' -- << fixLibFlags("QMAKE_LIBS_PRIVATE").join(' ') << endl; -+ t << "LIBS = -Wl,--start-group " -+ << "$(SUBLIBS) " << fixLibFlags("QMAKE_LIBS").join(' ') << ' ' -+ << fixLibFlags("QMAKE_LIBS_PRIVATE").join(' ') -+ << " -Wl,--end-group" << endl; - } diff --git a/toolchains/qt5-static/patches/README.md b/toolchains/qt5-static/patches/README.md index 8ca628c..f244189 100644 --- a/toolchains/qt5-static/patches/README.md +++ b/toolchains/qt5-static/patches/README.md @@ -1,8 +1,12 @@ # Optional Patch Hook -Drop Qt source patches (`*.patch`) in this directory to support legacy build fixes. +Store source patches (`*.patch`) under the tree-specific subdirectories: + +- `qt/` for Qt source patches +- `qtwebkit/` for QtWebKit source patches Behavior in `build-inside-container.sh`: -1. Run `configure` once. -2. If `Qt WebKit` is not enabled, apply all patches in lexicographic order. -3. Run `configure` again and continue only if WebKit is enabled. +1. Apply patches from `patches/qt/` only to the Qt tree. +2. Apply patches from `patches/qtwebkit/` only to the QtWebKit tree. +3. Process patches in lexicographic order within that tree. +4. Fail the build if a patch for that tree is neither applicable nor already applied. diff --git a/toolchains/qt5-static/patches/qt/0003-unixmake2-wrap-qmake-libs-in-start-end-group.patch b/toolchains/qt5-static/patches/qt/0003-unixmake2-wrap-qmake-libs-in-start-end-group.patch new file mode 100644 index 0000000..41cd607 --- /dev/null +++ b/toolchains/qt5-static/patches/qt/0003-unixmake2-wrap-qmake-libs-in-start-end-group.patch @@ -0,0 +1,17 @@ +--- a/qtbase/qmake/generators/unix/unixmake2.cpp ++++ b/qtbase/qmake/generators/unix/unixmake2.cpp +@@ -219,10 +219,10 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) + if(!project->isActiveConfig("staticlib")) { + t << "LINK = " << var("QMAKE_LINK") << Qt::endl; + t << "LFLAGS = " << var("QMAKE_LFLAGS") << Qt::endl; +- t << "LIBS = $(SUBLIBS) " << fixLibFlags("LIBS").join(' ') << ' ' +- << fixLibFlags("LIBS_PRIVATE").join(' ') << ' ' +- << fixLibFlags("QMAKE_LIBS").join(' ') << ' ' +- << fixLibFlags("QMAKE_LIBS_PRIVATE").join(' ') << Qt::endl; ++ t << "LIBS = -Wl,--start-group $(SUBLIBS) " << fixLibFlags("LIBS").join(' ') << ' ' ++ << fixLibFlags("LIBS_PRIVATE").join(' ') << ' ' ++ << fixLibFlags("QMAKE_LIBS").join(' ') << ' ' ++ << fixLibFlags("QMAKE_LIBS_PRIVATE").join(' ') << " -Wl,--end-group" << Qt::endl; + } + + t << "AR = " << var("QMAKE_AR") << Qt::endl; diff --git a/toolchains/qt5-static/patches/0004-qt_parts-honor-no-make-tools.patch b/toolchains/qt5-static/patches/qt/0004-qt_parts-honor-no-make-tools.patch similarity index 100% rename from toolchains/qt5-static/patches/0004-qt_parts-honor-no-make-tools.patch rename to toolchains/qt5-static/patches/qt/0004-qt_parts-honor-no-make-tools.patch diff --git a/toolchains/qt5-static/patches/qtwebkit/0005-javascriptcore-skip-shell-for-static-qt.patch b/toolchains/qt5-static/patches/qtwebkit/0005-javascriptcore-skip-shell-for-static-qt.patch new file mode 100644 index 0000000..fc66fa1 --- /dev/null +++ b/toolchains/qt5-static/patches/qtwebkit/0005-javascriptcore-skip-shell-for-static-qt.patch @@ -0,0 +1,14 @@ +diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt +--- a/Source/JavaScriptCore/CMakeLists.txt ++++ b/Source/JavaScriptCore/CMakeLists.txt +@@ -1310,7 +1310,9 @@ WEBKIT_INCLUDE_CONFIG_FILES_IF_EXISTS() + WEBKIT_CREATE_FORWARDING_HEADERS(JavaScriptCore DIRECTORIES ${JavaScriptCore_FORWARDING_HEADERS_DIRECTORIES} FILES ${JavaScriptCore_FORWARDING_HEADERS_FILES}) + + +-add_subdirectory(shell) ++if (NOT QT_STATIC_BUILD) ++ add_subdirectory(shell) ++endif () + + WEBKIT_WRAP_SOURCELIST(${JavaScriptCore_SOURCES}) + WEBKIT_FRAMEWORK(JavaScriptCore) diff --git a/toolchains/qt5-static/sources.lock b/toolchains/qt5-static/sources.lock index 77716ca..f2b119e 100644 --- a/toolchains/qt5-static/sources.lock +++ b/toolchains/qt5-static/sources.lock @@ -3,19 +3,19 @@ # This lock file is sourced by build-qt5-static.sh. # Every source must have at least one checksum (sha256 preferred, md5 fallback). -LOCK_QT_VERSION="5.5.1" +LOCK_QT_VERSION="5.15.17" -LOCK_QT5_SRC_FILE="qt-everywhere-opensource-src-5.5.1.tar.gz" -LOCK_QT5_SRC_URL="https://download.qt.io/new_archive/qt/5.5/5.5.1/single/qt-everywhere-opensource-src-5.5.1.tar.gz" -LOCK_QT5_SRC_SHA256="c7fad41a009af1996b62ec494e438aedcb072b3234b2ad3eeea6e6b1f64be3b3" -LOCK_QT5_SRC_MD5="59f0216819152b77536cf660b015d784" +LOCK_QT5_SRC_FILE="qt-everywhere-opensource-src-5.15.17.tar.xz" +LOCK_QT5_SRC_URL="https://download.qt.io/archive/qt/5.15/5.15.17/single/qt-everywhere-opensource-src-5.15.17.tar.xz" +LOCK_QT5_SRC_SHA256="85eb566333d6ba59be3a97c9445a6e52f2af1b52fc3c54b8a2e7f9ea040a7de4" +LOCK_QT5_SRC_MD5="5f212232bbc41f2eabbdee4fcbc4040e" -LOCK_QT5_WEBKIT_FILE="qtwebkit-opensource-src-5.5.1.tar.gz" -LOCK_QT5_WEBKIT_SRC_URL="https://download.qt.io/new_archive/qt/5.5/5.5.1/submodules/qtwebkit-opensource-src-5.5.1.tar.gz" -LOCK_QT5_WEBKIT_SHA256="d7776b4f76aae5a495cf16879fed5fd8370342a33116d8f41c30ab4ffd0b9ffd" -LOCK_QT5_WEBKIT_MD5="67ebccfbcd2bbb7eb24c8af6467a55dd" +LOCK_QT5_WEBKIT_FILE="qtwebkit-5.212.0-alpha4.tar.xz" +LOCK_QT5_WEBKIT_SRC_URL="https://github.com/qtwebkit/qtwebkit/releases/download/qtwebkit-5.212.0-alpha4/qtwebkit-5.212.0-alpha4.tar.xz" +LOCK_QT5_WEBKIT_SHA256="9ca126da9273664dd23a3ccd0c9bebceb7bb534bddd743db31caf6a5a6d4a9e6" +LOCK_QT5_WEBKIT_MD5="" -LOCK_ICU_SRC_FILE="icu4c-52_1-src.tgz" -LOCK_ICU_SRC_URL="https://download.qt.io/development_releases/prebuilt/icu/src/icu4c-52_1-src.tgz" -LOCK_ICU_SRC_SHA256="2f4d5e68d4698e87759dbdc1a586d053d96935787f79961d192c477b029d8092" -LOCK_ICU_SRC_MD5="9e96ed4c1d99c0d14ac03c140f9f346c" +LOCK_ICU_SRC_FILE="icu4c-65_1-src.tgz" +LOCK_ICU_SRC_URL="https://github.com/unicode-org/icu/releases/download/release-65-1/icu4c-65_1-src.tgz" +LOCK_ICU_SRC_SHA256="53e37466b3d6d6d01ead029e3567d873a43a5d1c668ed2278e253b683136d948" +LOCK_ICU_SRC_MD5="d1ff436e26cabcb28e6cb383d32d1339" From 40844a8ec32418c162a5365cb1922b9fd5a6fef8 Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Mon, 11 May 2026 17:42:25 +0200 Subject: [PATCH 09/24] Limit QtWebKit build parallelism Cap QtWebKit Ninja jobs at 16 while leaving the general build job count unchanged for the rest of the static toolchain. Co-authored-by: Codex --- toolchains/qt5-static/build-inside-container.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/toolchains/qt5-static/build-inside-container.sh b/toolchains/qt5-static/build-inside-container.sh index 610fdcf..617090f 100755 --- a/toolchains/qt5-static/build-inside-container.sh +++ b/toolchains/qt5-static/build-inside-container.sh @@ -8,6 +8,10 @@ set -euo pipefail : "${ICU_SRC_ARCHIVE:?ICU_SRC_ARCHIVE is required}" JOBS="${JOBS:-$(nproc 2>/dev/null || echo 8)}" +QTWEBKIT_JOBS="$JOBS" +if (( QTWEBKIT_JOBS > 16 )); then + QTWEBKIT_JOBS=16 +fi CLEAN="${CLEAN:-false}" BUILD_TYPE="${BUILD_TYPE:-release}" BUILD_SCOPE="${BUILD_SCOPE:-all}" @@ -297,7 +301,7 @@ build_qtwebkit() { -DUSE_LD_GOLD=OFF \ "${QTWEBKIT_SOURCE_DIR}" >"${LOG_DIR}/qtwebkit-configure.log" 2>&1 echo "==> build QtWebKit" - ninja -j"$JOBS" >"${LOG_DIR}/qtwebkit-build.log" 2>&1 + ninja -j"$QTWEBKIT_JOBS" >"${LOG_DIR}/qtwebkit-build.log" 2>&1 echo "==> install QtWebKit" ninja install >"${LOG_DIR}/qtwebkit-install.log" 2>&1 sync_installed_qtwebkit_metadata From 8c8462d3ab6a75a02694fd8f309b90f5ec7d87e4 Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Mon, 11 May 2026 18:51:00 +0200 Subject: [PATCH 10/24] Refactor build script entrypoints Co-authored-by: Codex --- .gitignore | 1 - AGENTS.md | 13 ++- build-browser-docker.sh | 81 +------------------ build-qt5-static.sh | 14 +--- docs/migration.md | 2 +- docs/qt5-static-poc.md | 2 +- run-browser.sh | 14 ++-- run-smoke.sh | 14 ++-- .../qtwebkit-smoke/smoke-build-docker.sh | 18 +---- .../qtwebkit-smoke/smoke-build-entrypoint.sh | 16 ++++ .../qt5-static/browser-build-entrypoint.sh | 70 ++++++++++++++++ toolchains/qt5-static/patches/README.md | 2 +- ...iner.sh => qt5-static-build-entrypoint.sh} | 34 ++------ 13 files changed, 125 insertions(+), 156 deletions(-) create mode 100755 smoke-tests/qtwebkit-smoke/smoke-build-entrypoint.sh create mode 100755 toolchains/qt5-static/browser-build-entrypoint.sh rename toolchains/qt5-static/{build-inside-container.sh => qt5-static-build-entrypoint.sh} (95%) diff --git a/.gitignore b/.gitignore index 34be9b3..51688bc 100644 --- a/.gitignore +++ b/.gitignore @@ -27,4 +27,3 @@ Makefile* build-* !build-browser-docker.sh !build-qt5-static.sh -!toolchains/qt5-static/build-inside-container.sh diff --git a/AGENTS.md b/AGENTS.md index 864469e..a4d2d80 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,10 +1,19 @@ # AGENTS.md +## Code Style +- Do not introduce one-off variables for simple values or small argument groups. Keep values inline at the use site unless a variable removes real duplication, clarifies non-obvious logic, or matches nearby style. +- When individual shell command arguments need comments, prefer a single argument array with comments beside the relevant entries instead of separate helper variables for small flag groups. +- In shell scripts, do not build command strings or use `eval`; use direct command calls or argument arrays so quoting and word splitting stay explicit. +- Do not pass long inline shell programs to Docker with `bash -c`/`bash -lc`; put the container-side logic in a checked-in script and execute that script. +- Do not add helper functions that are only called once unless they isolate a meaningful phase, cleanup/error boundary, or repeated validation pattern. +- Treat `build.sh` as a legacy script: do not apply cleanup/style rewrites there unless the user explicitly asks to modernize that script. + ## Build And Validation Policy - Do not run host-local or ad hoc builds in this repository. - Do not invoke `qmake`, `make`, `cmake`, `ninja`, or compiler commands directly on the host for validation or debugging. -- Use the repository's sanctioned helper-script flows instead, such as `build-browser-docker.sh`, `build-qt5-static.sh`, and `smoke-run.sh`, when a build or runtime validation is explicitly required. +- Use the repository's sanctioned helper-script flows instead, such as `build-browser-docker.sh`, `build-qt5-static.sh`, and `run-smoke.sh`, when a build or runtime validation is explicitly required. - If that sanctioned path is unavailable, blocked, or out of scope for the task, state that validation could not be run. Do not fall back to a local build. - Do not launch the built `QtWeb` binary or other produced executables as an agent. -- Do not run `smoke-run.sh` or start GUI/runtime validation on the user's behalf unless the user explicitly asks for that exact execution. +- Do not run `run-smoke.sh` or start GUI/runtime validation on the user's behalf unless the user explicitly asks for that exact execution. +- Use `ldd ./smoke-tests/qtwebkit-smoke/build-docker-$(build-type)/qtwebkit-smoke` to check for remaining shared dependencies - When a build succeeds, report the output path or the command the user can run; leave execution to the user unless explicitly requested. diff --git a/build-browser-docker.sh b/build-browser-docker.sh index e0e6078..e64dd22 100755 --- a/build-browser-docker.sh +++ b/build-browser-docker.sh @@ -77,11 +77,6 @@ case "$BUILD_TYPE" in release|debug) QT_PREFIX_IN_CONTAINER="${REPO_ROOT}/artifacts/qt5-static-${QT_VERSION}-${BUILD_TYPE}/install" BUILD_DIR="${REPO_ROOT}/build-docker-${BUILD_TYPE}" - if [[ "$BUILD_TYPE" == "release" ]]; then - QMAKE_CONFIG_ARGS="CONFIG+=release CONFIG-=debug" - else - QMAKE_CONFIG_ARGS="CONFIG+=debug CONFIG-=release" - fi ;; *) fail "BUILD_TYPE must be release or debug, got: ${BUILD_TYPE}" @@ -94,82 +89,10 @@ docker run --rm \ -e REPO_ROOT="${REPO_ROOT}" \ -e QT_PREFIX_IN_CONTAINER="${QT_PREFIX_IN_CONTAINER}" \ -e BUILD_DIR_IN_CONTAINER="${BUILD_DIR}" \ - -e QMAKE_CONFIG_ARGS="${QMAKE_CONFIG_ARGS}" \ + -e BUILD_TYPE="${BUILD_TYPE}" \ -e EXPORT_FIXES="${EXPORT_FIXES}" \ -v "${REPO_ROOT}:${REPO_ROOT}" \ -e RUN_ANALYSIS="${RUN_ANALYSIS}" \ -w "${REPO_ROOT}" \ "${IMAGE_TAG}" \ - /bin/bash -lc ' - set -euo pipefail - - fail() { - echo "error: $*" >&2 - exit 1 - } - - require_tool() { - command -v "$1" >/dev/null 2>&1 || fail "missing tool in image: $1" - } - - collect_gcc_warnings() { - local build_log="$1" - local warnings_report="$2" - grep -F "warning:" "${build_log}" > "${warnings_report}" || : - } - - rm -rf "${BUILD_DIR_IN_CONTAINER}" - mkdir -p "${BUILD_DIR_IN_CONTAINER}" - cd "${BUILD_DIR_IN_CONTAINER}" - "${QT_PREFIX_IN_CONTAINER}/bin/qmake" ../src/QtWeb.pro ${QMAKE_CONFIG_ARGS} - build_log="${BUILD_DIR_IN_CONTAINER}/build.log" - gcc_warnings_report="${BUILD_DIR_IN_CONTAINER}/gcc-warnings.txt" - - if [[ "${RUN_ANALYSIS}" == "1" ]]; then - require_tool bear - require_tool clang-tidy - clang_tidy_fixes="${BUILD_DIR_IN_CONTAINER}/clang-tidy-fixes.yaml" - clang_tidy_extra_args=() - - bear make -j"${JOBS}" 2>&1 | tee "${build_log}" - collect_gcc_warnings "${build_log}" "${gcc_warnings_report}" - - mapfile -t ANALYSIS_SOURCES < <(find "${REPO_ROOT}/src" -path "${REPO_ROOT}/src/qt" -prune -o -type f -name "*.cpp" -print | sort) - [[ "${#ANALYSIS_SOURCES[@]}" -gt 0 ]] || fail "no analysis sources found under ${REPO_ROOT}/src" - - if [[ "${EXPORT_FIXES}" == "1" ]]; then - rm -f "${clang_tidy_fixes}" - clang_tidy_extra_args+=(-export-fixes="${clang_tidy_fixes}") - fi - - if [[ "${#clang_tidy_extra_args[@]}" -gt 0 ]]; then - clang-tidy \ - -p "${BUILD_DIR_IN_CONTAINER}" \ - --header-filter="(^|.*/)src/.*" \ - "${clang_tidy_extra_args[@]}" \ - "${ANALYSIS_SOURCES[@]}" \ - > "${BUILD_DIR_IN_CONTAINER}/clang-tidy.txt" 2>&1 - else - clang-tidy \ - -p "${BUILD_DIR_IN_CONTAINER}" \ - --header-filter="(^|.*/)src/.*" \ - "${ANALYSIS_SOURCES[@]}" \ - > "${BUILD_DIR_IN_CONTAINER}/clang-tidy.txt" 2>&1 - fi - - echo "built: ${BUILD_DIR_IN_CONTAINER}/QtWeb" - echo "compile_commands: ${BUILD_DIR_IN_CONTAINER}/compile_commands.json" - echo "build log: ${build_log}" - echo "gcc warnings: ${gcc_warnings_report}" - echo "clang-tidy report: ${BUILD_DIR_IN_CONTAINER}/clang-tidy.txt" - if [[ "${EXPORT_FIXES}" == "1" ]]; then - echo "clang-tidy fixes: ${clang_tidy_fixes}" - fi - else - make -j"${JOBS}" 2>&1 | tee "${build_log}" - collect_gcc_warnings "${build_log}" "${gcc_warnings_report}" - echo "built: ${BUILD_DIR_IN_CONTAINER}/QtWeb" - echo "build log: ${build_log}" - echo "gcc warnings: ${gcc_warnings_report}" - fi - ' + "${REPO_ROOT}/toolchains/qt5-static/browser-build-entrypoint.sh" diff --git a/build-qt5-static.sh b/build-qt5-static.sh index 819f8e0..3412259 100755 --- a/build-qt5-static.sh +++ b/build-qt5-static.sh @@ -5,15 +5,14 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$SCRIPT_DIR" LOCK_FILE="${REPO_ROOT}/toolchains/qt5-static/sources.lock" DOCKERFILE="${REPO_ROOT}/toolchains/qt5-static/Dockerfile" -INNER_SCRIPT="/workspace/toolchains/qt5-static/build-inside-container.sh" +INNER_SCRIPT="/workspace/toolchains/qt5-static/qt5-static-build-entrypoint.sh" # shellcheck disable=SC1090 source "${REPO_ROOT}/toolchains/qt5-static/common.sh" SCRIPT_NAME="$(basename "$0")" -DEFAULT_JOBS="$(nproc 2>/dev/null || echo 8)" -JOBS="${COMPILE_JOBS:-$DEFAULT_JOBS}" +JOBS="${COMPILE_JOBS:-$(nproc 2>/dev/null || echo 8)}" OUTPUT_DIR="" RUNTIME="auto" CLEAN=false @@ -53,13 +52,6 @@ fail() { exit 1 } -abs_path() { - case "$1" in - /*) printf '%s\n' "$1" ;; - *) printf '%s\n' "${REPO_ROOT}/$1" ;; - esac -} - basename_from_url() { local url="$1" url="${url%%\?*}" @@ -283,7 +275,7 @@ QT5_WEBKIT_FILE="$(source_file_name "$QT5_WEBKIT_SRC_URL" "$LOCK_QT5_WEBKIT_SRC_ ICU_SRC_FILE="$(source_file_name "$ICU_SRC_URL" "$LOCK_ICU_SRC_URL" "${LOCK_ICU_SRC_FILE:-}")" REPO_ABS="$(cd "$REPO_ROOT" && pwd -P)" -OUTPUT_RAW="$(abs_path "$OUTPUT_DIR")" +OUTPUT_RAW="$(cd "$REPO_ROOT" && realpath -m -- "$OUTPUT_DIR")" [[ "$JOBS" =~ ^[1-9][0-9]*$ ]] || fail "--jobs must be a positive integer" diff --git a/docs/migration.md b/docs/migration.md index 3ec3594..251256a 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -8,7 +8,7 @@ ## Key Changes - Save this plan first in `docs/migration.md`, replacing the current Qt `5.5.1` / donor-branch-oriented plan before any code or script changes begin. -- Retarget the existing toolchain flow in `build-qt5-static.sh`, `toolchains/qt5-static/sources.lock`, and `toolchains/qt5-static/build-inside-container.sh`: +- Retarget the existing toolchain flow in `build-qt5-static.sh`, `toolchains/qt5-static/sources.lock`, and `toolchains/qt5-static/qt5-static-build-entrypoint.sh`: - update locked sources from Qt `5.5.1` to Qt `5.15.17` - replace the current "unpack `qtwebkit` into the Qt source tree" flow with a standalone QtWebKit `5.212` build against the installed Qt `5.15.17` prefix - keep static ICU and OpenSSL handling, and continue verifying `libQt5WebKit.a` and `libQt5WebKitWidgets.a` diff --git a/docs/qt5-static-poc.md b/docs/qt5-static-poc.md index e3a9bed..8173db4 100644 --- a/docs/qt5-static-poc.md +++ b/docs/qt5-static-poc.md @@ -25,7 +25,7 @@ Primary portability target: static linking plus minimal runtime dependencies. ## Inputs - Wrapper script: `build-qt5-static.sh` -- In-container script: `toolchains/qt5-static/build-inside-container.sh` +- In-container script: `toolchains/qt5-static/qt5-static-build-entrypoint.sh` - Container definition: `toolchains/qt5-static/Dockerfile` - Source lock and checksums: `toolchains/qt5-static/sources.lock` - Optional patch hook: `toolchains/qt5-static/patches/*.patch` diff --git a/run-browser.sh b/run-browser.sh index 8efe378..27b8253 100755 --- a/run-browser.sh +++ b/run-browser.sh @@ -2,7 +2,6 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -BUILD_SCRIPT="${SCRIPT_DIR}/build-browser-docker.sh" BUILD_TYPE="release" RUN_WITH_GDB=0 @@ -42,22 +41,19 @@ esac BINARY="${SCRIPT_DIR}/build-docker-${BUILD_TYPE}/QtWeb" if [[ "${RUN_BUILD}" -eq 1 ]]; then - BUILD_ARGS=() if [[ "${BUILD_TYPE}" == "debug" ]]; then - BUILD_ARGS+=(--debug) + "${SCRIPT_DIR}/build-browser-docker.sh" --debug + else + "${SCRIPT_DIR}/build-browser-docker.sh" fi - "${BUILD_SCRIPT}" "${BUILD_ARGS[@]}" elif [[ ! -x "${BINARY}" ]]; then echo "error: browser binary not found: ${BINARY}" >&2 echo "hint: rerun with --rebuild" >&2 exit 1 fi -RUN_BINARY="${BINARY}" if [[ "${RUN_WITH_GDB}" -eq 1 ]]; then - CMD=(gdb -ex run --args "${RUN_BINARY}") + exec gdb -ex run --args "${BINARY}" "$@" else - CMD=("${RUN_BINARY}") + exec "${BINARY}" "$@" fi - -exec "${CMD[@]}" "$@" diff --git a/run-smoke.sh b/run-smoke.sh index dfe5f92..ed900f8 100755 --- a/run-smoke.sh +++ b/run-smoke.sh @@ -3,7 +3,6 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SMOKE_DIR="${SCRIPT_DIR}/smoke-tests/qtwebkit-smoke" -BUILD_SCRIPT="${SMOKE_DIR}/smoke-build-docker.sh" BUILD_TYPE="release" RUN_WITH_GDB=0 @@ -43,22 +42,19 @@ esac BINARY="${SMOKE_DIR}/build-docker-${BUILD_TYPE}/qtwebkit-smoke" if [[ "${RUN_BUILD}" -eq 1 ]]; then - BUILD_ARGS=() if [[ "${BUILD_TYPE}" == "debug" ]]; then - BUILD_ARGS+=(--debug) + "${SMOKE_DIR}/smoke-build-docker.sh" --debug + else + "${SMOKE_DIR}/smoke-build-docker.sh" fi - "${BUILD_SCRIPT}" "${BUILD_ARGS[@]}" elif [[ ! -x "${BINARY}" ]]; then echo "error: smoke binary not found: ${BINARY}" >&2 echo "hint: rerun with --build" >&2 exit 1 fi -RUN_BINARY="${BINARY}" if [[ "${RUN_WITH_GDB}" -eq 1 ]]; then - CMD=(gdb -ex run --args "${RUN_BINARY}") + exec gdb -ex run --args "${BINARY}" "$@" else - CMD=("${RUN_BINARY}") + exec "${BINARY}" "$@" fi - -exec "${CMD[@]}" "$@" diff --git a/smoke-tests/qtwebkit-smoke/smoke-build-docker.sh b/smoke-tests/qtwebkit-smoke/smoke-build-docker.sh index 50c16ee..ad284b2 100755 --- a/smoke-tests/qtwebkit-smoke/smoke-build-docker.sh +++ b/smoke-tests/qtwebkit-smoke/smoke-build-docker.sh @@ -32,11 +32,6 @@ case "$BUILD_TYPE" in release|debug) QT_PREFIX_IN_CONTAINER="/workspace/artifacts/qt5-static-${QT_VERSION}-${BUILD_TYPE}/install" BUILD_DIR_IN_CONTAINER="smoke-tests/qtwebkit-smoke/build-docker-${BUILD_TYPE}" - if [[ "$BUILD_TYPE" == "release" ]]; then - QMAKE_CONFIG_ARGS="CONFIG+=release CONFIG-=debug" - else - QMAKE_CONFIG_ARGS="CONFIG+=debug CONFIG-=release" - fi ;; *) fail "BUILD_TYPE must be release or debug, got: ${BUILD_TYPE}" @@ -48,18 +43,9 @@ docker run --rm \ -e JOBS="${JOBS}" \ -e QT_PREFIX_IN_CONTAINER="${QT_PREFIX_IN_CONTAINER}" \ -e BUILD_DIR_IN_CONTAINER="${BUILD_DIR_IN_CONTAINER}" \ - -e QMAKE_CONFIG_ARGS="${QMAKE_CONFIG_ARGS}" \ + -e BUILD_TYPE="${BUILD_TYPE}" \ -v "${REPO_ROOT}:/workspace" \ -v "${REPO_ROOT}:${REPO_ROOT}" \ -w /workspace \ "${IMAGE_TAG}" \ - /bin/bash -lc ' - set -euo pipefail - rm -rf "${BUILD_DIR_IN_CONTAINER}" - mkdir -p "${BUILD_DIR_IN_CONTAINER}" - cd "${BUILD_DIR_IN_CONTAINER}" - "${QT_PREFIX_IN_CONTAINER}/bin/qmake" ../qtwebkit-smoke.pro ${QMAKE_CONFIG_ARGS} - make -j"${JOBS}" - cp /etc/ssl/certs/ca-certificates.crt ./ca-certificates.crt - echo "built: /workspace/${BUILD_DIR_IN_CONTAINER}/qtwebkit-smoke" - ' + /workspace/smoke-tests/qtwebkit-smoke/smoke-build-entrypoint.sh diff --git a/smoke-tests/qtwebkit-smoke/smoke-build-entrypoint.sh b/smoke-tests/qtwebkit-smoke/smoke-build-entrypoint.sh new file mode 100755 index 0000000..3795361 --- /dev/null +++ b/smoke-tests/qtwebkit-smoke/smoke-build-entrypoint.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail + +rm -rf "$BUILD_DIR_IN_CONTAINER" +mkdir -p "$BUILD_DIR_IN_CONTAINER" +cd "$BUILD_DIR_IN_CONTAINER" + +if [[ "$BUILD_TYPE" == "release" ]]; then + "${QT_PREFIX_IN_CONTAINER}/bin/qmake" ../qtwebkit-smoke.pro CONFIG+=release CONFIG-=debug +else + "${QT_PREFIX_IN_CONTAINER}/bin/qmake" ../qtwebkit-smoke.pro CONFIG+=debug CONFIG-=release +fi + +make -j"$JOBS" +cp /etc/ssl/certs/ca-certificates.crt ./ca-certificates.crt +echo "built: /workspace/${BUILD_DIR_IN_CONTAINER}/qtwebkit-smoke" diff --git a/toolchains/qt5-static/browser-build-entrypoint.sh b/toolchains/qt5-static/browser-build-entrypoint.sh new file mode 100755 index 0000000..b0d28df --- /dev/null +++ b/toolchains/qt5-static/browser-build-entrypoint.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +set -euo pipefail + +fail() { + echo "error: $*" >&2 + exit 1 +} + +require_tool() { + command -v "$1" >/dev/null 2>&1 || fail "missing tool in image: $1" +} + +collect_gcc_warnings() { + local build_log="$1" + local warnings_report="$2" + grep -F "warning:" "$build_log" > "$warnings_report" || : +} + +rm -rf "$BUILD_DIR_IN_CONTAINER" +mkdir -p "$BUILD_DIR_IN_CONTAINER" +cd "$BUILD_DIR_IN_CONTAINER" + +if [[ "$BUILD_TYPE" == "release" ]]; then + "${QT_PREFIX_IN_CONTAINER}/bin/qmake" ../src/QtWeb.pro CONFIG+=release CONFIG-=debug +else + "${QT_PREFIX_IN_CONTAINER}/bin/qmake" ../src/QtWeb.pro CONFIG+=debug CONFIG-=release +fi + +build_log="${BUILD_DIR_IN_CONTAINER}/build.log" +gcc_warnings_report="${BUILD_DIR_IN_CONTAINER}/gcc-warnings.txt" + +if [[ "$RUN_ANALYSIS" == "1" ]]; then + require_tool bear + require_tool clang-tidy + clang_tidy_fixes="${BUILD_DIR_IN_CONTAINER}/clang-tidy-fixes.yaml" + clang_tidy_extra_args=() + + bear make -j"$JOBS" 2>&1 | tee "$build_log" + collect_gcc_warnings "$build_log" "$gcc_warnings_report" + + mapfile -t ANALYSIS_SOURCES < <(find "${REPO_ROOT}/src" -path "${REPO_ROOT}/src/qt" -prune -o -type f -name "*.cpp" -print | sort) + [[ "${#ANALYSIS_SOURCES[@]}" -gt 0 ]] || fail "no analysis sources found under ${REPO_ROOT}/src" + + if [[ "$EXPORT_FIXES" == "1" ]]; then + rm -f "$clang_tidy_fixes" + clang_tidy_extra_args+=(-export-fixes="$clang_tidy_fixes") + fi + + clang-tidy \ + -p "$BUILD_DIR_IN_CONTAINER" \ + --header-filter="(^|.*/)src/.*" \ + "${clang_tidy_extra_args[@]}" \ + "${ANALYSIS_SOURCES[@]}" \ + > "${BUILD_DIR_IN_CONTAINER}/clang-tidy.txt" 2>&1 + + echo "built: ${BUILD_DIR_IN_CONTAINER}/QtWeb" + echo "compile_commands: ${BUILD_DIR_IN_CONTAINER}/compile_commands.json" + echo "build log: ${build_log}" + echo "gcc warnings: ${gcc_warnings_report}" + echo "clang-tidy report: ${BUILD_DIR_IN_CONTAINER}/clang-tidy.txt" + if [[ "$EXPORT_FIXES" == "1" ]]; then + echo "clang-tidy fixes: ${clang_tidy_fixes}" + fi +else + make -j"$JOBS" 2>&1 | tee "$build_log" + collect_gcc_warnings "$build_log" "$gcc_warnings_report" + echo "built: ${BUILD_DIR_IN_CONTAINER}/QtWeb" + echo "build log: ${build_log}" + echo "gcc warnings: ${gcc_warnings_report}" +fi diff --git a/toolchains/qt5-static/patches/README.md b/toolchains/qt5-static/patches/README.md index f244189..10fdbbf 100644 --- a/toolchains/qt5-static/patches/README.md +++ b/toolchains/qt5-static/patches/README.md @@ -5,7 +5,7 @@ Store source patches (`*.patch`) under the tree-specific subdirectories: - `qt/` for Qt source patches - `qtwebkit/` for QtWebKit source patches -Behavior in `build-inside-container.sh`: +Behavior in `qt5-static-build-entrypoint.sh`: 1. Apply patches from `patches/qt/` only to the Qt tree. 2. Apply patches from `patches/qtwebkit/` only to the QtWebKit tree. 3. Process patches in lexicographic order within that tree. diff --git a/toolchains/qt5-static/build-inside-container.sh b/toolchains/qt5-static/qt5-static-build-entrypoint.sh similarity index 95% rename from toolchains/qt5-static/build-inside-container.sh rename to toolchains/qt5-static/qt5-static-build-entrypoint.sh index 617090f..73567f1 100755 --- a/toolchains/qt5-static/build-inside-container.sh +++ b/toolchains/qt5-static/qt5-static-build-entrypoint.sh @@ -308,31 +308,6 @@ build_qtwebkit() { popd >/dev/null } -build_smoke_test() { - local qmake_config_args - - require_file "${INSTALL_DIR}/bin/qmake" - require_file "${SMOKE_DIR}/qtwebkit-smoke.pro" - - echo "==> build QtWebKit smoke test" - rm -rf "${SMOKE_BUILD_DIR}" - mkdir -p "${SMOKE_BUILD_DIR}" - pushd "${SMOKE_BUILD_DIR}" >/dev/null - if [[ "${BUILD_TYPE}" == "release" ]]; then - qmake_config_args="CONFIG+=release CONFIG-=debug" - else - qmake_config_args="CONFIG+=debug CONFIG-=release" - fi - "${INSTALL_DIR}/bin/qmake" ../qtwebkit-smoke.pro ${qmake_config_args} >"${LOG_DIR}/smoke-build.log" 2>&1 - make -j"$JOBS" >>"${LOG_DIR}/smoke-build.log" 2>&1 - if [[ -f /etc/ssl/certs/ca-certificates.crt ]]; then - cp /etc/ssl/certs/ca-certificates.crt ./ca-certificates.crt - fi - popd >/dev/null - - require_file "${SMOKE_BUILD_DIR}/qtwebkit-smoke" -} - mkdir -p "$WORK_DIR" "$LOG_DIR" require_file "$QT_SRC_ARCHIVE" require_file "$QTWEBKIT_ARCHIVE" @@ -378,7 +353,14 @@ if [[ "$BUILD_SCOPE" == "all" || "$BUILD_SCOPE" == "qtwebkit" ]]; then require_file "${INSTALL_DIR}/bin/qmake" install_qt_runtime_fonts build_qtwebkit - build_smoke_test + echo "==> build QtWebKit smoke test" + require_file "${SMOKE_DIR}/smoke-build-entrypoint.sh" + JOBS="$JOBS" \ + QT_PREFIX_IN_CONTAINER="$INSTALL_DIR" \ + BUILD_DIR_IN_CONTAINER="${SMOKE_BUILD_DIR#/workspace/}" \ + BUILD_TYPE="$BUILD_TYPE" \ + "${SMOKE_DIR}/smoke-build-entrypoint.sh" >"${LOG_DIR}/smoke-build.log" 2>&1 + require_file "${SMOKE_BUILD_DIR}/qtwebkit-smoke" fi QMAKE_BIN="${INSTALL_DIR}/bin/qmake" From 2363674f32f2ae741958c5320cd220c1b24058c9 Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Mon, 11 May 2026 18:55:25 +0200 Subject: [PATCH 11/24] Update QtWebKit static build Switch the QtWebKit source lock to the 2022-09-07 snapshot and add the static-build patch set. Disable dependency-heavy QtWebKit features for the static build, including WebKit2, Web Crypto, XSLT, WOFF2, video/media paths, and Qt Quick/WebChannel integration. Adjust Docker dependencies and installed qmake metadata for the resulting static link. Remove QtWeb's obsolete NPAPI plug-in UI, settings, and dead WebPage plug-in hook now that the updated QtWebKit build no longer exposes QWebSettings::PluginsEnabled. Co-authored-by: Codex --- src/browserapplication.cpp | 1 - src/browsermainwindow.cpp | 19 - src/browsermainwindow.h | 2 - src/commands.cpp | 5 +- src/commands.h | 6 +- src/htmls/Welcome.html | 1 - src/settings.cpp | 3 - src/settings.ui | 17 - src/webpage.cpp | 13 - src/webpage.cpp.bak | 432 ------------------ src/webpage.h | 4 - src/webview.cpp | 1 - toolchains/qt5-static/Dockerfile | 3 +- ...ascriptcore-skip-shell-for-static-qt.patch | 11 +- ...optionsqt-skip-missing-target-export.patch | 11 + ...ake-package-install-for-static-build.patch | 16 + ...publicsuffixqt-fix-localhost-compare.patch | 12 + ...pressionstream-contain-qtzlib-macros.patch | 122 +++++ .../0010-platformqt-build-widgets-only.patch | 65 +++ ...tings-guard-media-setting-with-video.patch | 14 + ...12-webkitlegacy-static-for-static-qt.patch | 14 + .../qt5-static/qt5-static-build-entrypoint.sh | 76 +-- toolchains/qt5-static/sources.lock | 6 +- 23 files changed, 315 insertions(+), 539 deletions(-) delete mode 100644 src/webpage.cpp.bak create mode 100644 toolchains/qt5-static/patches/qtwebkit/0006-optionsqt-skip-missing-target-export.patch create mode 100644 toolchains/qt5-static/patches/qtwebkit/0007-platformqt-skip-cmake-package-install-for-static-build.patch create mode 100644 toolchains/qt5-static/patches/qtwebkit/0008-publicsuffixqt-fix-localhost-compare.patch create mode 100644 toolchains/qt5-static/patches/qtwebkit/0009-compressionstream-contain-qtzlib-macros.patch create mode 100644 toolchains/qt5-static/patches/qtwebkit/0010-platformqt-build-widgets-only.patch create mode 100644 toolchains/qt5-static/patches/qtwebkit/0011-qwebsettings-guard-media-setting-with-video.patch create mode 100644 toolchains/qt5-static/patches/qtwebkit/0012-webkitlegacy-static-for-static-qt.patch diff --git a/src/browserapplication.cpp b/src/browserapplication.cpp index a540987..c9217a4 100644 --- a/src/browserapplication.cpp +++ b/src/browserapplication.cpp @@ -419,7 +419,6 @@ void BrowserApplication::loadSettings() defaultSettings->setAttribute(QWebSettings::ZoomTextOnly, zoom_text_only); defaultSettings->setAttribute(QWebSettings::JavascriptEnabled, settings.value(QLatin1String("enableJavascript"), true).toBool()); - defaultSettings->setAttribute(QWebSettings::PluginsEnabled, settings.value(QLatin1String("enablePlugins"), true).toBool()); defaultSettings->setAttribute(QWebSettings::AutoLoadImages, settings.value(QLatin1String("autoLoadImages"), true).toBool()); defaultSettings->setAttribute(QWebSettings::JavascriptCanOpenWindows, ! (settings.value(QLatin1String("blockPopups"), true).toBool())); diff --git a/src/browsermainwindow.cpp b/src/browsermainwindow.cpp index cc74ae0..4f43232 100644 --- a/src/browsermainwindow.cpp +++ b/src/browsermainwindow.cpp @@ -848,14 +848,6 @@ void BrowserMainWindow::setupMenu() this->addAction(m_disableCookies); m_disableCookies->setCheckable(true); - // Disable Plug-Ins - m_disablePlugIns = new QAction( cmds.PlugInsTitle(), this); - m_disablePlugIns->setShortcuts(cmds.PlugInsShortcuts()); - connect(m_disablePlugIns, SIGNAL(triggered()), this, SLOT(slotDisablePlugIns())); - privacyMenu->addAction(m_disablePlugIns); - this->addAction(m_disablePlugIns); - m_disablePlugIns->setCheckable(true); - // Disable UserAgent m_disableUserAgent = new QAction( cmds.AgentTitle(), this); m_disableUserAgent->setShortcuts(cmds.AgentShortcuts()); @@ -2410,7 +2402,6 @@ void BrowserMainWindow::slotAboutToShowPrivacyMenu() QWebSettings* defaultSettings = QWebSettings::globalSettings(); m_disableJavaScript->setChecked(!defaultSettings->testAttribute(QWebSettings::JavascriptEnabled)); m_disableImages->setChecked(!defaultSettings->testAttribute(QWebSettings::AutoLoadImages)); - m_disablePlugIns->setChecked(!defaultSettings->testAttribute(QWebSettings::PluginsEnabled)); m_disablePopUps->setChecked(!defaultSettings->testAttribute(QWebSettings::JavascriptCanOpenWindows)); @@ -2451,16 +2442,6 @@ void BrowserMainWindow::slotDisableImages() checkToolBarButtons(); } -void BrowserMainWindow::slotDisablePlugIns() -{ - bool enabled = !m_disablePlugIns->isChecked(); - QWebSettings* defaultSettings = QWebSettings::globalSettings(); - defaultSettings->setAttribute(QWebSettings::PluginsEnabled, enabled); - QSettings settings; - settings.beginGroup(QLatin1String("websettings")); - settings.setValue(QLatin1String("enablePlugins"), enabled); -} - void BrowserMainWindow::slotDisableCookies() { bool enabled = !m_disableCookies->isChecked(); diff --git a/src/browsermainwindow.h b/src/browsermainwindow.h index badc423..8e13064 100644 --- a/src/browsermainwindow.h +++ b/src/browsermainwindow.h @@ -134,7 +134,6 @@ private slots: void slotDisableJavaScript(); void slotDisableImages(); void slotDisableCookies(); - void slotDisablePlugIns(); void slotDisableUserAgent(); void slotEnableProxy(); void slotDisablePopUps(); @@ -240,7 +239,6 @@ private slots: QAction *m_disableJavaScript; QAction *m_disableImages; QAction *m_disableCookies; - QAction *m_disablePlugIns; QAction *m_disableUserAgent; QAction *m_enableProxy; QAction *m_disablePopUps; diff --git a/src/commands.cpp b/src/commands.cpp index 62021b6..37a661a 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -31,7 +31,7 @@ MenuCommands::~MenuCommands() m_data.endGroup(); } -#define MAX_COMMANDS 91 +#define MAX_COMMANDS 90 int MenuCommands::GetCommandsCount() const { @@ -221,9 +221,6 @@ QString MenuCommands::Get(int ind, What w) const if (cur++ == ind) return (w == Key ? CookiesKey() : (w == Title? CookiesTitle() : GetStr(CookiesShortcuts()))); - if (cur++ == ind) - return (w == Key ? PlugInsKey() : (w == Title? PlugInsTitle() : GetStr(PlugInsShortcuts()))); - if (cur++ == ind) return (w == Key ? AgentKey() : (w == Title? AgentTitle() : GetStr(AgentShortcuts()))); diff --git a/src/commands.h b/src/commands.h index d7297f6..f85fbda 100644 --- a/src/commands.h +++ b/src/commands.h @@ -291,10 +291,6 @@ class MenuCommands : public QObject QString CookiesTitle() const { return m_data.value( CookiesKey() , tr("Disable &Cookies")).toString(); } QList CookiesShortcuts() const { return loadShortcuts( CookiesKey(), QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_C) ); } - QString PlugInsKey() const { return QLatin1String("PlugIns"); } - QString PlugInsTitle() const { return m_data.value( PlugInsKey() , tr("Disable Plu&g-Ins")).toString(); } - QList PlugInsShortcuts() const { return loadShortcuts( PlugInsKey(), QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_G) ); } - QString AgentKey() const { return QLatin1String("UserAgent"); } QString AgentTitle() const { return m_data.value( AgentKey() , tr("Disable User&Agent")).toString(); } QList AgentShortcuts() const { return loadShortcuts( AgentKey(), QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_A) ); } @@ -425,4 +421,4 @@ class MenuCommands : public QObject QSettings m_data; }; -#endif // MENUCOMMANDS_H \ No newline at end of file +#endif // MENUCOMMANDS_H diff --git a/src/htmls/Welcome.html b/src/htmls/Welcome.html index cee86d2..6b7e468 100644 --- a/src/htmls/Welcome.html +++ b/src/htmls/Welcome.html @@ -241,7 +241,6 @@

Welcome to QtWeb Internet Browser

  • Supported FTP browsing and downloading
  • AutoFill option - stores and pre-populates user names and passwords for the sites you visit most
  • -
  • With Qt 4.6 supported Netscape plugins, like Adobe Flash Player, QuickTime or MediaPlayer
  • Use Scenarios diff --git a/src/settings.cpp b/src/settings.cpp index 3122e5a..4ed948b 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -170,7 +170,6 @@ void SettingsDialog::loadDefaults() downloadsLocation->setText( DefaultDownloadPath( false ) ); enableJavascript->setChecked(defaultSettings->testAttribute(QWebSettings::JavascriptEnabled)); - enablePlugins->setChecked(defaultSettings->testAttribute(QWebSettings::PluginsEnabled)); blockPopups->setChecked( ! (defaultSettings->testAttribute(QWebSettings::JavascriptCanOpenWindows)) ); autoLoadImages->setChecked(defaultSettings->testAttribute(QWebSettings::AutoLoadImages)); @@ -326,7 +325,6 @@ void SettingsDialog::loadFromSettings() fixedLabel->setText(QString(QLatin1String("%1 %2")).arg(fixedFont.family()).arg(fixedFont.pointSize())); enableJavascript->setChecked(settings.value(QLatin1String("enableJavascript"), enableJavascript->isChecked()).toBool()); - enablePlugins->setChecked(settings.value(QLatin1String("enablePlugins"), enablePlugins->isChecked()).toBool()); autoLoadImages->setChecked(settings.value(QLatin1String("autoLoadImages"), autoLoadImages->isChecked()).toBool()); blockPopups->setChecked(settings.value(QLatin1String("blockPopups"), blockPopups->isChecked()).toBool()); @@ -521,7 +519,6 @@ void SettingsDialog::saveToSettings() settings.setValue(QLatin1String("fixedFont"), fixedFont); settings.setValue(QLatin1String("standardFont"), standardFont); settings.setValue(QLatin1String("enableJavascript"), enableJavascript->isChecked()); - settings.setValue(QLatin1String("enablePlugins"), enablePlugins->isChecked()); settings.setValue(QLatin1String("autoLoadImages"), autoLoadImages->isChecked()); settings.setValue(QLatin1String("blockPopups"), blockPopups->isChecked()); settings.setValue(QLatin1String("savePasswords"), chkSavePasswords->isChecked()); diff --git a/src/settings.ui b/src/settings.ui index 7601aac..7fcec6a 100644 --- a/src/settings.ui +++ b/src/settings.ui @@ -1044,22 +1044,6 @@ true - - - - 11 - 90 - 289 - 19 - - - - Enable Plug-Ins - - - true - - @@ -1883,7 +1867,6 @@ enableJavascript autoLoadImages blockPopups - enablePlugins enableDiskCache checkBoxDeleteDownloads chkSavePasswords diff --git a/src/webpage.cpp b/src/webpage.cpp index ab3c0c6..8f19368 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -57,7 +57,6 @@ #include #include #include -//#include #include #include @@ -314,17 +313,6 @@ QWebPage *WebPage::createWindow(QWebPage::WebWindowType type) return mainWindow->currentTab()->page(); } -#if !defined(QT_NO_UITOOLS) -QObject *WebPage::createPlugin(const QString &classId, const QUrl &url, const QStringList ¶mNames, const QStringList ¶mValues) -{ - Q_UNUSED(url); - Q_UNUSED(paramNames); - Q_UNUSED(paramValues); - QUiLoader loader; - return loader.createWidget(classId, view()); -} -#endif // !defined(QT_NO_UITOOLS) - void WebPage::handleUnsupportedContent(QNetworkReply *reply) { if (reply->error() == QNetworkReply::NoError) @@ -340,4 +328,3 @@ void WebPage::handleUnsupportedContent(QNetworkReply *reply) return; } } - diff --git a/src/webpage.cpp.bak b/src/webpage.cpp.bak deleted file mode 100644 index 636f534..0000000 --- a/src/webpage.cpp.bak +++ /dev/null @@ -1,432 +0,0 @@ -/* - * Copyright (C) 2008-2009 Alexei Chaloupov - * Copyright (C) 2007-2008 Benjamin C. Meyer - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA - */ -/**************************************************************************** -** -** Copyright (C) 2007-2008 Trolltech ASA. All rights reserved. -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** Licensees holding a valid Qt License Agreement may use this file in -** accordance with the rights, responsibilities and obligations -** contained therein. Please consult your licensing agreement or -** contact sales@trolltech.com if any conditions of this licensing -** agreement are not clear to you. -** -** Further information about Qt licensing is available at: -** http://www.trolltech.com/products/qt/licensing.html or by -** contacting info@trolltech.com. -** -** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -** -****************************************************************************/ - -#include "browserapplication.h" -#include "browsermainwindow.h" -#include "cookiejar.h" -#include "downloadmanager.h" -#include "networkaccessmanager.h" -#include "tabwidget.h" -#include "webpage.h" -#include "webview.h" -#include "autocomplete.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -WebPage::WebPage(QObject *parent) - : QWebPage(parent) - , m_keyboardModifiers(Qt::NoModifier) - , m_pressedButtons(Qt::NoButton) - , m_openAction(OpenDefault) -{ - setNetworkAccessManager(BrowserApplication::networkAccessManager()); - connect(this, SIGNAL(unsupportedContent(QNetworkReply *)), - this, SLOT(handleUnsupportedContent(QNetworkReply *))); - -} - -BrowserMainWindow *WebPage::mainWindow() -{ - QObject *w = this->parent(); - while (w) { - if (BrowserMainWindow *mw = qobject_cast(w)) - return mw; - w = w->parent(); - } - return BrowserApplication::instance()->mainWindow(); -} - -QString WebPage::m_userAgent; - -void WebPage::setUserAgent(QString agent) -{ - m_userAgent = agent; -} - -void WebPage::setDefaultAgent( ) -{ - QString ver; -#ifdef Q_WS_WIN - switch(QSysInfo::WindowsVersion) - { - case QSysInfo::WV_32s: - ver = "Windows 3.1"; - break; - case QSysInfo::WV_95: - ver = "Windows 95"; - break; - case QSysInfo::WV_98: - ver = "Windows 98"; - break; - case QSysInfo::WV_Me: - ver = "Windows 98; Win 9x 4.90"; - break; - case QSysInfo::WV_NT: - ver = "WinNT4.0"; - break; - case QSysInfo::WV_2000: - ver = "Windows NT 5.0"; - break; - case QSysInfo::WV_XP: - ver = "Windows NT 5.1"; - break; - case QSysInfo::WV_2003: - ver = "Windows NT 5.2"; - break; - case QSysInfo::WV_VISTA: - ver = "Windows NT 6.0"; - break; - case QSysInfo::WV_CE: - ver = "Windows CE"; - break; - case QSysInfo::WV_CENET: - ver = "Windows CE .NET"; - break; - case QSysInfo::WV_CE_5: - ver = "Windows CE 5.x"; - break; - case QSysInfo::WV_CE_6: - ver = "Windows CE 6.x"; - break; - default: - ver = "Windows NT based"; - } -#else - - #ifdef Q_WS_MAC - switch(QSysInfo::MacintoshVersion) - { - case QSysInfo::MV_10_3: - ver = "Intel MacOS X 10.3"; - break; - case QSysInfo::MV_10_4: - ver = "Intel MacOS X 10.4"; - break; - case QSysInfo::MV_10_5: - ver = "Intel MacOS X 10.5"; - break; - case QSysInfo::MV_10_6: - ver = "Intel MacOS X 10.6"; - break; - default: - ver = "MacOS X"; - } - #else - ver = "Linux/Unix"; - #endif -#endif - // language - QString name = QLocale::system().name(); - name[2] = QLatin1Char('-'); - - QSettings settings; - settings.beginGroup(QLatin1String("websettings")); - bool bUseCustomAgent = settings.value(QLatin1String("customUserAgent"), false).toBool(); - if (bUseCustomAgent) - { - m_userAgent = settings.value(QLatin1String("UserAgent"), "").toString(); - if (m_userAgent == "Internet Explorer") - m_userAgent = "Mozilla/4.0 (compatible; MSIE 8.0; %W; Trident/4.0)"; - else if (m_userAgent == "Firefox") - m_userAgent = "Mozilla/5.0 (Windows; U; %W; %L; rv:1.9.0.5) Gecko/2008120121 Firefox/3.0.5"; - else if (m_userAgent == "Opera") - m_userAgent = "Opera/9.63 (%W; U; en) Presto/2.1.1"; - else if (m_userAgent == "Safari") - m_userAgent = "Mozilla/5.0 (Windows; U; %W; %L) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Safari/528.17"; - else if (m_userAgent == "Chrome") - m_userAgent = "Mozilla/5.0 (Windows; U; %W; %L) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.A.B.C Safari/525.13"; - - m_userAgent = m_userAgent.replace("%W", ver); - m_userAgent = m_userAgent.replace("%L", name); - return; - } - -#ifdef Q_WS_MAC - QString ua = QLatin1String("Mozilla/5.0 (Macintosh; %1; %2; "); -#else - QString ua = QLatin1String("Mozilla/5.0 (Windows; %1; %2; "); -#endif - - QChar securityStrength(QLatin1Char('N')); - if (QSslSocket::supportsSsl()) - securityStrength = QLatin1Char('U'); - ua = ua.arg(securityStrength); - - ua = QString(ua).arg(ver); - - // Language - ua.append(name); - ua.append(QLatin1String(") ")); - - // webkit/qt version - ua.append(QLatin1String("AppleWebKit/533.3 (KHTML, like Gecko) ")); - - // Application name/version - QString appName = QCoreApplication::applicationName(); - if (!appName.isEmpty()) { - ua.append(QLatin1Char(' ') + appName); - QString appVer = QCoreApplication::applicationVersion(); - if (!appVer.isEmpty()) - ua.append(QLatin1Char('/') + appVer); - ua.append(QLatin1String(" http://www.QtWeb.net")); - } - - m_userAgent = ua; -} - -const QString& WebPage::getUserAgent() -{ - return m_userAgent; -} - -QString WebPage::userAgentForUrl(const QUrl& url) const -{ - return getUserAgent(); -} - - -extern bool ShellOpenApp(QString app, QString cmd); - -bool WebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type) -{ - if (!request.url().isEmpty()) - { - QString scheme = request.url().scheme(); - QString url = request.url().toString().toLower(); - if ( scheme == "mms" || scheme == QLatin1String("mailto") || - url.indexOf(".wmv") == url.length() - 4 || url.indexOf(".wma") == url.length() - 4) - { - if (QDesktopServices::openUrl(request.url())) - return false; - } - - /* AC: v .3.3.45 - PDF PlugIn is handled properly now in Qt 4.6.1++ - if( url.indexOf(".pdf") == url.length() - 4 ) - { - if (BrowserApplication::downloadManager()) - BrowserApplication::downloadManager()->download(request.url(), false); - return false; - }*/ - - } - - if (frame && (type == NavigationTypeFormSubmitted || type == NavigationTypeFormResubmitted)) - { - QSettings settings; - settings.beginGroup(QLatin1String("websettings")); - if ( settings.value(QLatin1String("savePasswords"), false).toBool()) - { - QUrl u = request.url(); - if (!request.rawHeader("Referer").isEmpty()) - u = QUrl(request.rawHeader("Referer")); - - BrowserApplication::autoCompleter()->setFormHtml( u, frame->toHtml() ); - } - } - - // ctrl open in new tab - // ctrl-shift open in new tab and select - // ctrl-alt open in new window - if (type == QWebPage::NavigationTypeLinkClicked && (m_keyboardModifiers & Qt::ControlModifier || m_pressedButtons == Qt::MidButton)) - { - QSettings settings; - settings.beginGroup(QLatin1String("general")); - int openLinksIn = settings.value(QLatin1String("openLinksIn"), 0).toInt(); - - bool newWindow = (m_keyboardModifiers & Qt::AltModifier); - WebView* webView; - if (newWindow || (openLinksIn == 1)) - { - BrowserApplication::instance()->newMainWindow(); - BrowserMainWindow *newMainWindow = BrowserApplication::instance()->mainWindow(); - webView = newMainWindow->currentTab(); - newMainWindow->raise(); - newMainWindow->activateWindow(); - webView->setFocus(); - } - else - { - bool selectNewTab = (m_keyboardModifiers & Qt::ShiftModifier); - webView = mainWindow()->tabWidget()->newTab(selectNewTab); - } - webView->load(request); - m_keyboardModifiers = Qt::NoModifier; - m_pressedButtons = Qt::NoButton; - DefineHostIcon(request.url()); - return false; - } - - if (frame == NULL && type == QWebPage::NavigationTypeLinkClicked) // Check for open links in tabs - { - QSettings settings; - settings.beginGroup(QLatin1String("general")); - int openLinksIn = settings.value(QLatin1String("openLinksIn"), 0).toInt(); - if (openLinksIn == 0 && !(m_keyboardModifiers & Qt::AltModifier)) - { - WebView* webView = mainWindow()->tabWidget()->newTab(true); - webView->load(request); - //DefineHostIcon(request.url()); - return false; - } - } - - if (frame == mainFrame()) - { - if ( !request.url().isEmpty() ) - { - if (request.url().scheme() != "ftp") - { - m_loadingUrl = request.url(); - //emit loadingUrl(m_loadingUrl); // ??? to avoid unnecessary LineURL change - DefineHostIcon(request.url()); - return true; - } - else - { - m_loadingUrl = request.url(); - WebView* view = (WebView* )parent(); - if (!view->isLoading()) - { - view->loadUrl( request.url() ); - return false; - } - return true; - } - } - } - - return QWebPage::acceptNavigationRequest(frame, request, type); -} - -void WebPage::DefineHostIcon(const QUrl& url) -{ - BrowserApplication::instance()->CheckIcon(url); -} - -QWebPage *WebPage::createWindow(QWebPage::WebWindowType type) -{ - Q_UNUSED(type); - - if (m_keyboardModifiers & Qt::ControlModifier || m_pressedButtons == Qt::MidButton) - m_openAction = WebPage::OpenNewTab; - - if (m_openAction == WebPage::OpenNewTab ) - { - m_openAction = WebPage::OpenDefault; - return mainWindow()->tabWidget()->newTab()->page(); - } - BrowserApplication::instance()->newMainWindow(); - BrowserMainWindow *mainWindow = BrowserApplication::instance()->mainWindow(); - return mainWindow->currentTab()->page(); -} - -#if !defined(QT_NO_UITOOLS) -QObject *WebPage::createPlugin(const QString &classId, const QUrl &url, const QStringList ¶mNames, const QStringList ¶mValues) -{ - Q_UNUSED(url); - Q_UNUSED(paramNames); - Q_UNUSED(paramValues); - QUiLoader loader; - return loader.createWidget(classId, view()); -} -#endif // !defined(QT_NO_UITOOLS) - -void WebPage::handleUnsupportedContent(QNetworkReply *reply) -{ - if (reply->error() == QNetworkReply::NoError) - { - QVariant content = reply->header(QNetworkRequest::ContentTypeHeader); - QString c = content.toString(); - - if ( content.isValid() && !BrowserApplication::handleMIME( c, reply->url() ) ) - { - BrowserApplication::downloadManager()->handleUnsupportedContent(reply); - - } - return; - } - - QFile file(QLatin1String(":/notfound.html")); - bool isOpened = file.open(QIODevice::ReadOnly); - Q_ASSERT(isOpened); - QString title = tr("Loading error: %1").arg(reply->url().toString()); - QString html = QString(QLatin1String(file.readAll())) - .arg(title) - .arg(reply->errorString()) - .arg(reply->url().toString()); - - QBuffer imageBuffer; - imageBuffer.open(QBuffer::ReadWrite); - QIcon icon = view()->style()->standardIcon(QStyle::SP_MessageBoxWarning, 0, view()); - QPixmap pixmap = icon.pixmap(QSize(32,32)); - if (pixmap.save(&imageBuffer, "PNG")) { - html.replace(QLatin1String("IMAGE_BINARY_DATA_HERE"), - QString(QLatin1String(imageBuffer.buffer().toBase64()))); - } - - QList frames; - frames.append(mainFrame()); - while (!frames.isEmpty()) { - QWebFrame *frame = frames.takeFirst(); - if (frame->url() == reply->url()) { - frame->setHtml(html, reply->url()); - return; - } - QList children = frame->childFrames(); - foreach(QWebFrame *frame, children) - frames.append(frame); - } - if (m_loadingUrl == reply->url()) { - mainFrame()->setHtml(html, reply->url()); - } -} - diff --git a/src/webpage.h b/src/webpage.h index d664079..5f95de8 100644 --- a/src/webpage.h +++ b/src/webpage.h @@ -84,10 +84,6 @@ class WebPage : public QWebPage { bool extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output); bool supportsExtension(Extension extension) const; -#if !defined(QT_NO_UITOOLS) - QObject *createPlugin(const QString &classId, const QUrl &url, const QStringList ¶mNames, const QStringList ¶mValues); -#endif - private slots: void handleUnsupportedContent(QNetworkReply *reply); diff --git a/src/webview.cpp b/src/webview.cpp index c8f87f2..8a8441b 100644 --- a/src/webview.cpp +++ b/src/webview.cpp @@ -57,7 +57,6 @@ #include #include #include -//#include #include #include diff --git a/toolchains/qt5-static/Dockerfile b/toolchains/qt5-static/Dockerfile index 653420f..531dc09 100644 --- a/toolchains/qt5-static/Dockerfile +++ b/toolchains/qt5-static/Dockerfile @@ -26,6 +26,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libglib2.0-dev \ libgl1-mesa-dev \ libgles2-mesa-dev \ + libharfbuzz-dev \ libhyphen-dev \ libicu-dev \ libjpeg-dev \ @@ -42,9 +43,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libxfixes-dev \ libxi-dev \ libxml2-dev \ + libwebp-dev \ libxrandr-dev \ libxrender-dev \ - libxslt1-dev \ libxcb1-dev \ libxcb-icccm4-dev \ libxcb-image0-dev \ diff --git a/toolchains/qt5-static/patches/qtwebkit/0005-javascriptcore-skip-shell-for-static-qt.patch b/toolchains/qt5-static/patches/qtwebkit/0005-javascriptcore-skip-shell-for-static-qt.patch index fc66fa1..1efddd7 100644 --- a/toolchains/qt5-static/patches/qtwebkit/0005-javascriptcore-skip-shell-for-static-qt.patch +++ b/toolchains/qt5-static/patches/qtwebkit/0005-javascriptcore-skip-shell-for-static-qt.patch @@ -1,14 +1,11 @@ diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt -@@ -1310,7 +1310,9 @@ WEBKIT_INCLUDE_CONFIG_FILES_IF_EXISTS() - WEBKIT_CREATE_FORWARDING_HEADERS(JavaScriptCore DIRECTORIES ${JavaScriptCore_FORWARDING_HEADERS_DIRECTORIES} FILES ${JavaScriptCore_FORWARDING_HEADERS_FILES}) - - +@@ -1567,4 +1567,6 @@ if (USE_VERSION_STAMPER) + VERBATIM) + endif () + -add_subdirectory(shell) +if (NOT QT_STATIC_BUILD) + add_subdirectory(shell) +endif () - - WEBKIT_WRAP_SOURCELIST(${JavaScriptCore_SOURCES}) - WEBKIT_FRAMEWORK(JavaScriptCore) diff --git a/toolchains/qt5-static/patches/qtwebkit/0006-optionsqt-skip-missing-target-export.patch b/toolchains/qt5-static/patches/qtwebkit/0006-optionsqt-skip-missing-target-export.patch new file mode 100644 index 0000000..9f97e79 --- /dev/null +++ b/toolchains/qt5-static/patches/qtwebkit/0006-optionsqt-skip-missing-target-export.patch @@ -0,0 +1,11 @@ +diff --git a/Source/cmake/OptionsQt.cmake b/Source/cmake/OptionsQt.cmake +--- a/Source/cmake/OptionsQt.cmake ++++ b/Source/cmake/OptionsQt.cmake +@@ -96,7 +96,7 @@ endmacro() + + macro(QT_ADD_EXTRA_WEBKIT_TARGET_EXPORT target) +- if (QT_STATIC_BUILD OR SHARED_CORE) ++ if ((QT_STATIC_BUILD OR SHARED_CORE) AND TARGET ${target}) + install(TARGETS ${target} EXPORT WebKitTargets + DESTINATION "${LIB_INSTALL_DIR}") + endif () diff --git a/toolchains/qt5-static/patches/qtwebkit/0007-platformqt-skip-cmake-package-install-for-static-build.patch b/toolchains/qt5-static/patches/qtwebkit/0007-platformqt-skip-cmake-package-install-for-static-build.patch new file mode 100644 index 0000000..77e256b --- /dev/null +++ b/toolchains/qt5-static/patches/qtwebkit/0007-platformqt-skip-cmake-package-install-for-static-build.patch @@ -0,0 +1,16 @@ +diff --git a/Source/PlatformQt.cmake b/Source/PlatformQt.cmake +--- a/Source/PlatformQt.cmake ++++ b/Source/PlatformQt.cmake +@@ -192,6 +192,7 @@ write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/Qt5WebKitConfigVer + write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/Qt5WebKitWidgetsConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion) ++if (NOT QT_STATIC_BUILD) + + install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/Qt5WebKitConfig.cmake" +@@ -217,3 +218,4 @@ install(EXPORT Qt5WebKitWidgetsTargets + DESTINATION "${KDE_INSTALL_CMAKEPACKAGEDIR}/Qt5WebKitWidgets" + COMPONENT Code + ) ++endif () diff --git a/toolchains/qt5-static/patches/qtwebkit/0008-publicsuffixqt-fix-localhost-compare.patch b/toolchains/qt5-static/patches/qtwebkit/0008-publicsuffixqt-fix-localhost-compare.patch new file mode 100644 index 0000000..df75220 --- /dev/null +++ b/toolchains/qt5-static/patches/qtwebkit/0008-publicsuffixqt-fix-localhost-compare.patch @@ -0,0 +1,12 @@ +diff --git a/Source/WebCore/platform/network/qt/PublicSuffixQt.cpp b/Source/WebCore/platform/network/qt/PublicSuffixQt.cpp +--- a/Source/WebCore/platform/network/qt/PublicSuffixQt.cpp ++++ b/Source/WebCore/platform/network/qt/PublicSuffixQt.cpp +@@ -64,7 +64,7 @@ String topPrivatelyControlledDomain(const String& domain) + return domain; + + String lowercaseDomain = domain.convertToASCIILowercase(); +- if (lowercaseDomain == QLatin1String("localhost")) ++ if (lowercaseDomain == "localhost"_s) + return lowercaseDomain; + + QString qLowercaseDomain = lowercaseDomain; diff --git a/toolchains/qt5-static/patches/qtwebkit/0009-compressionstream-contain-qtzlib-macros.patch b/toolchains/qt5-static/patches/qtwebkit/0009-compressionstream-contain-qtzlib-macros.patch new file mode 100644 index 0000000..01fa401 --- /dev/null +++ b/toolchains/qt5-static/patches/qtwebkit/0009-compressionstream-contain-qtzlib-macros.patch @@ -0,0 +1,122 @@ +diff --git a/Source/WebCore/Modules/compression/CompressionStreamEncoder.h b/Source/WebCore/Modules/compression/CompressionStreamEncoder.h +--- a/Source/WebCore/Modules/compression/CompressionStreamEncoder.h ++++ b/Source/WebCore/Modules/compression/CompressionStreamEncoder.h +@@ -33,6 +33,19 @@ + #include + #include + ++// Qt's static zlib build prefixes its API via preprocessor macros such as ++// inflate -> z_inflate. Keep those macros from leaking into the rest of the ++// unified WebCore translation unit. ++#ifdef deflate ++#undef deflate ++#endif ++#ifdef deflateEnd ++#undef deflateEnd ++#endif ++#ifdef deflateInit2 ++#undef deflateInit2 ++#endif ++ + namespace WebCore { + + class CompressionStreamEncoder : public RefCounted { +@@ -48,7 +61,7 @@ + ~CompressionStreamEncoder() + { + if (m_initialized) +- deflateEnd(&m_zstream); ++ z_deflateEnd(&m_zstream); + } + + private: +diff --git a/Source/WebCore/Modules/compression/CompressionStreamEncoder.cpp b/Source/WebCore/Modules/compression/CompressionStreamEncoder.cpp +--- a/Source/WebCore/Modules/compression/CompressionStreamEncoder.cpp ++++ b/Source/WebCore/Modules/compression/CompressionStreamEncoder.cpp +@@ -76,13 +76,13 @@ + // Values chosen here are based off + // https://developer.apple.com/documentation/compression/compression_algorithm/compression_zlib?language=objc + case Formats::CompressionFormat::Deflate: +- result = deflateInit2(&m_zstream, 5, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); ++ result = z_deflateInit2(&m_zstream, 5, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); + break; + case Formats::CompressionFormat::Zlib: +- result = deflateInit2(&m_zstream, 5, Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY); ++ result = z_deflateInit2(&m_zstream, 5, Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY); + break; + case Formats::CompressionFormat::Gzip: +- result = deflateInit2(&m_zstream, 5, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY); ++ result = z_deflateInit2(&m_zstream, 5, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY); + break; + default: + RELEASE_ASSERT_NOT_REACHED(); +@@ -129,7 +129,7 @@ + m_zstream.next_out = output.data(); + m_zstream.avail_out = output.size(); + +- result = deflate(&m_zstream, (m_finish) ? Z_FINISH : Z_NO_FLUSH); ++ result = z_deflate(&m_zstream, (m_finish) ? Z_FINISH : Z_NO_FLUSH); + if (result != Z_OK && result != Z_STREAM_END && result != Z_BUF_ERROR) + return Exception { TypeError, "Failed to compress data."_s }; + +diff --git a/Source/WebCore/Modules/compression/DecompressionStreamDecoder.h b/Source/WebCore/Modules/compression/DecompressionStreamDecoder.h +--- a/Source/WebCore/Modules/compression/DecompressionStreamDecoder.h ++++ b/Source/WebCore/Modules/compression/DecompressionStreamDecoder.h +@@ -38,6 +38,19 @@ + #include + #include + ++// Qt's static zlib build prefixes its API via preprocessor macros such as ++// inflate -> z_inflate. Keep those macros from leaking into the rest of the ++// unified WebCore translation unit. ++#ifdef inflate ++#undef inflate ++#endif ++#ifdef inflateEnd ++#undef inflateEnd ++#endif ++#ifdef inflateInit2 ++#undef inflateInit2 ++#endif ++ + namespace WebCore { + + class DecompressionStreamDecoder : public RefCounted { +@@ -58,7 +71,7 @@ + compression_stream_destroy(&m_stream); + #endif + } else +- deflateEnd(&m_zstream); ++ z_inflateEnd(&m_zstream); + } + } + +diff --git a/Source/WebCore/Modules/compression/DecompressionStreamDecoder.cpp b/Source/WebCore/Modules/compression/DecompressionStreamDecoder.cpp +--- a/Source/WebCore/Modules/compression/DecompressionStreamDecoder.cpp ++++ b/Source/WebCore/Modules/compression/DecompressionStreamDecoder.cpp +@@ -81,13 +81,13 @@ + + switch (m_format) { + case Formats::CompressionFormat::Deflate: +- result = inflateInit2(&m_zstream, -15); ++ result = z_inflateInit2(&m_zstream, -15); + break; + case Formats::CompressionFormat::Zlib: +- result = inflateInit2(&m_zstream, 15); ++ result = z_inflateInit2(&m_zstream, 15); + break; + case Formats::CompressionFormat::Gzip: +- result = inflateInit2(&m_zstream, 15 + 16); ++ result = z_inflateInit2(&m_zstream, 15 + 16); + break; + default: + RELEASE_ASSERT_NOT_REACHED(); +@@ -133,7 +133,7 @@ + m_zstream.next_out = output.data(); + m_zstream.avail_out = output.size(); + +- result = inflate(&m_zstream, (m_finish) ? Z_FINISH : Z_NO_FLUSH); ++ result = z_inflate(&m_zstream, (m_finish) ? Z_FINISH : Z_NO_FLUSH); + + if (result != Z_OK && result != Z_STREAM_END && result != Z_BUF_ERROR) + return Exception { TypeError, "Failed to Decode Data."_s }; diff --git a/toolchains/qt5-static/patches/qtwebkit/0010-platformqt-build-widgets-only.patch b/toolchains/qt5-static/patches/qtwebkit/0010-platformqt-build-widgets-only.patch new file mode 100644 index 0000000..1828d41 --- /dev/null +++ b/toolchains/qt5-static/patches/qtwebkit/0010-platformqt-build-widgets-only.patch @@ -0,0 +1,65 @@ +diff --git a/Source/WebKit/PlatformQt.cmake b/Source/WebKit/PlatformQt.cmake +--- a/Source/WebKit/PlatformQt.cmake ++++ b/Source/WebKit/PlatformQt.cmake +@@ -106,25 +106,6 @@ + + UIProcess/API/cpp/qt/WKStringQt.cpp + UIProcess/API/cpp/qt/WKURLQt.cpp +- +- UIProcess/API/qt/qquicknetworkreply.cpp +- UIProcess/API/qt/qquicknetworkrequest.cpp +- UIProcess/API/qt/qquickurlschemedelegate.cpp +- UIProcess/API/qt/qquickwebpage.cpp +- UIProcess/API/qt/qquickwebview.cpp +- UIProcess/API/qt/qtwebsecurityorigin.cpp +- UIProcess/API/qt/qwebchannelwebkittransport.cpp +- UIProcess/API/qt/qwebdownloaditem.cpp +- UIProcess/API/qt/qwebdownloaditem_p.h +- UIProcess/API/qt/qwebdownloaditem_p_p.h +- UIProcess/API/qt/qwebiconimageprovider.cpp +- UIProcess/API/qt/qwebkittest.cpp +- UIProcess/API/qt/qwebloadrequest.cpp +- UIProcess/API/qt/qwebnavigationhistory.cpp +- UIProcess/API/qt/qwebnavigationrequest.cpp +- UIProcess/API/qt/qwebpermissionrequest.cpp +- UIProcess/API/qt/qwebpreferences.cpp +- + UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp + + UIProcess/Launcher/qt/ProcessLauncherQt.cpp +@@ -192,19 +173,6 @@ + WebProcess/qt/WebProcessQt.cpp + ) + +-if (COMPILER_IS_GCC_OR_CLANG) +- set_source_files_properties( +- UIProcess/API/qt/qquicknetworkreply.cpp +- UIProcess/API/qt/qquicknetworkrequest.cpp +- UIProcess/API/qt/qquickurlschemedelegate.cpp +- UIProcess/API/qt/qquickwebpage.cpp +- UIProcess/API/qt/qquickwebview.cpp +- UIProcess/API/qt/qwebiconimageprovider.cpp +- PROPERTIES +- COMPILE_FLAGS -frtti +- ) +-endif () +- + if (USE_MACH_PORTS) + list(APPEND WebKit_INCLUDE_DIRECTORIES + "${WEBKIT_DIR}/Platform/IPC/cocoa" +@@ -251,15 +219,11 @@ + list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES + ${GLIB_INCLUDE_DIRS} + ${GSTREAMER_INCLUDE_DIRS} +- ${Qt5Quick_INCLUDE_DIRS} +- ${Qt5Quick_PRIVATE_INCLUDE_DIRS} + ${SQLITE_INCLUDE_DIR} + ) + + list(APPEND WebKit_LIBRARIES + ${Qt5Positioning_LIBRARIES} +- ${Qt5Quick_LIBRARIES} +- ${Qt5WebChannel_LIBRARIES} + ${X11_X11_LIB} + ) + diff --git a/toolchains/qt5-static/patches/qtwebkit/0011-qwebsettings-guard-media-setting-with-video.patch b/toolchains/qt5-static/patches/qtwebkit/0011-qwebsettings-guard-media-setting-with-video.patch new file mode 100644 index 0000000..a96fdb7 --- /dev/null +++ b/toolchains/qt5-static/patches/qtwebkit/0011-qwebsettings-guard-media-setting-with-video.patch @@ -0,0 +1,14 @@ +diff --git a/Source/WebKitLegacy/qt/Api/qwebsettings.cpp b/Source/WebKitLegacy/qt/Api/qwebsettings.cpp +--- a/Source/WebKitLegacy/qt/Api/qwebsettings.cpp ++++ b/Source/WebKitLegacy/qt/Api/qwebsettings.cpp +@@ -175,8 +175,10 @@ void QWebSettingsPrivate::apply() + settings->setMediaSourceEnabled(value); + #endif + ++#if ENABLE(VIDEO) + value = attributes.value(QWebSettings::MediaEnabled, global->attributes.value(QWebSettings::MediaEnabled)); + settings->setMediaEnabled(value); ++#endif + + value = attributes.value(QWebSettings::HyperlinkAuditingEnabled, + global->attributes.value(QWebSettings::HyperlinkAuditingEnabled)); diff --git a/toolchains/qt5-static/patches/qtwebkit/0012-webkitlegacy-static-for-static-qt.patch b/toolchains/qt5-static/patches/qtwebkit/0012-webkitlegacy-static-for-static-qt.patch new file mode 100644 index 0000000..a429744 --- /dev/null +++ b/toolchains/qt5-static/patches/qtwebkit/0012-webkitlegacy-static-for-static-qt.patch @@ -0,0 +1,14 @@ +diff --git a/Source/WebKitLegacy/CMakeLists.txt b/Source/WebKitLegacy/CMakeLists.txt +--- a/Source/WebKitLegacy/CMakeLists.txt ++++ b/Source/WebKitLegacy/CMakeLists.txt +@@ -34,6 +34,10 @@ set(WebKitLegacy_PRIVATE_LIBRARIES + WebKit::WebCore + ) + ++if (${PORT} STREQUAL "Qt" AND QT_STATIC_BUILD) ++ set(WebKitLegacy_LIBRARY_TYPE STATIC) ++endif () ++ + WEBKIT_FRAMEWORK_DECLARE(WebKitLegacy) + WEBKIT_INCLUDE_CONFIG_FILES_IF_EXISTS() + diff --git a/toolchains/qt5-static/qt5-static-build-entrypoint.sh b/toolchains/qt5-static/qt5-static-build-entrypoint.sh index 73567f1..7d38dcc 100755 --- a/toolchains/qt5-static/qt5-static-build-entrypoint.sh +++ b/toolchains/qt5-static/qt5-static-build-entrypoint.sh @@ -63,6 +63,7 @@ CONFIGURE_FLAGS=( "$BUILD_CONFIGURE_FLAG" -static -prefix "$INSTALL_DIR" + -skip qtdeclarative -skip qtwebengine -nomake tests -nomake examples @@ -232,7 +233,8 @@ sync_installed_qtwebkit_metadata() { local webkit_module_pri="${INSTALL_DIR}/mkspecs/modules/qt_lib_webkit.pri" local webkitwidgets_module_pri="${INSTALL_DIR}/mkspecs/modules/qt_lib_webkitwidgets.pri" local install_lib_expr='$$QT_MODULE_LIB_BASE' - local webkit_private_libs="-L${install_lib_expr} -lWebCore -lANGLESupport -lJavaScriptCore -lWTF ${SYSTEM_LIB_DIR}/libxml2.a ${SYSTEM_LIB_DIR}/liblzma.a ${SYSTEM_LIB_DIR}/libicui18n.a ${SYSTEM_LIB_DIR}/libicuuc.a ${SYSTEM_LIB_DIR}/libicudata.a ${SYSTEM_LIB_DIR}/libsqlite3.a -lz -lbmalloc -lxslt ${SYSTEM_LIB_DIR}/libhyphen.a -lwoff2 -lbrotli" + local icu_lib_expr='$$[QT_INSTALL_PREFIX]/../icu-static/lib' + local webkit_private_libs="-L${install_lib_expr} -lWebCore -lPAL -lJavaScriptCore -lWTF ${SYSTEM_LIB_DIR}/libxml2.a ${SYSTEM_LIB_DIR}/liblzma.a ${icu_lib_expr}/libicui18n.a ${icu_lib_expr}/libicuuc.a ${icu_lib_expr}/libicudata.a ${SYSTEM_LIB_DIR}/libsqlite3.a -lz -lbmalloc ${SYSTEM_LIB_DIR}/libhyphen.a -lharfbuzz-icu -latomic" require_file "$webkit_module_pri" @@ -240,10 +242,6 @@ sync_installed_qtwebkit_metadata() { sed -i "s|^QMAKE_LIBS_PRIVATE += |QMAKE_LIBS_PRIVATE += -L${install_lib_expr} |" "$webkit_module_pri" fi - if ! grep -Fq -- "-lANGLESupport" "$webkit_module_pri"; then - sed -i 's/-lWebCore /-lWebCore -lANGLESupport /' "$webkit_module_pri" - fi - sed -i "s|^QMAKE_LIBS_PRIVATE += .*|QMAKE_LIBS_PRIVATE += ${webkit_private_libs}|" "$webkit_module_pri" if [[ -f "$webkitwidgets_module_pri" ]]; then @@ -251,8 +249,17 @@ sync_installed_qtwebkit_metadata() { fi } +sync_installed_qt_plugin_metadata() { + local qwebp_prl="${INSTALL_DIR}/plugins/imageformats/libqwebp.prl" + + if [[ -f "$qwebp_prl" ]]; then + sed -i "s|-lwebpmux -lwebpdemux -lwebp|${SYSTEM_LIB_DIR}/libwebpmux.a ${SYSTEM_LIB_DIR}/libwebpdemux.a ${SYSTEM_LIB_DIR}/libwebp.a|g" "$qwebp_prl" + fi +} + build_qtwebkit() { local extract_dir source_root + local top_level_entries=() require_file "$QTWEBKIT_ARCHIVE" if [[ -f "${INSTALL_DIR}/lib/libQt5WebKit.a" && -f "${INSTALL_DIR}/lib/libQt5WebKitWidgets.a" ]]; then @@ -270,12 +277,22 @@ build_qtwebkit() { mkdir -p "$extract_dir" "$QTWEBKIT_BUILD_DIR" tar -xf "$QTWEBKIT_ARCHIVE" -C "$extract_dir" - source_root="$(find "$extract_dir" -mindepth 1 -maxdepth 1 -type d | head -n 1)" - [[ -n "$source_root" ]] || fail "could not identify extracted QtWebKit source directory" - QTWEBKIT_SOURCE_DIR="${WORK_DIR}/$(basename "$source_root")" + mapfile -t top_level_entries < <(find "$extract_dir" -mindepth 1 -maxdepth 1 | sort) + if [[ "${#top_level_entries[@]}" -eq 1 && -d "${top_level_entries[0]}" ]]; then + source_root="${top_level_entries[0]}" + QTWEBKIT_SOURCE_DIR="${WORK_DIR}/$(basename "$source_root")" + else + require_file "${extract_dir}/CMakeLists.txt" + require_dir "${extract_dir}/Source" + source_root="$extract_dir" + QTWEBKIT_SOURCE_DIR="${WORK_DIR}/qtwebkit-source" + fi + rm -rf "$QTWEBKIT_SOURCE_DIR" mv "$source_root" "$QTWEBKIT_SOURCE_DIR" - rm -rf "$extract_dir" + if [[ "$source_root" != "$extract_dir" ]]; then + rm -rf "$extract_dir" + fi pushd "$QTWEBKIT_SOURCE_DIR" >/dev/null apply_matching_patches "qtwebkit" @@ -283,23 +300,29 @@ build_qtwebkit() { pushd "$QTWEBKIT_BUILD_DIR" >/dev/null echo "==> configure QtWebKit" - cmake -G Ninja \ - -DPORT=Qt \ - -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" \ - -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \ - -DCMAKE_PREFIX_PATH="${INSTALL_DIR};${ICU_INSTALL_DIR}" \ - -DQt5_DIR="${INSTALL_DIR}/lib/cmake/Qt5" \ - -DICU_ROOT="${ICU_INSTALL_DIR}" \ - -DENABLE_API_TESTS=OFF \ - -DENABLE_TOOLS=OFF \ - -DENABLE_GEOLOCATION=OFF \ - -DENABLE_PRINT_SUPPORT=ON \ - -DENABLE_VIDEO=OFF \ - -DENABLE_WEBKIT2=OFF \ - -DUSE_THIN_ARCHIVES=OFF \ - -DUSE_GSTREAMER=OFF \ - -DUSE_LD_GOLD=OFF \ - "${QTWEBKIT_SOURCE_DIR}" >"${LOG_DIR}/qtwebkit-configure.log" 2>&1 + local cmake_args=( + -DPORT=Qt + -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" + -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" + -DCMAKE_PREFIX_PATH="${INSTALL_DIR};${ICU_INSTALL_DIR}" + -DQt5_DIR="${INSTALL_DIR}/lib/cmake/Qt5" + -DICU_ROOT="${ICU_INSTALL_DIR}" + -DENABLE_API_TESTS=OFF + -DENABLE_TOOLS=OFF + -DENABLE_GEOLOCATION=OFF + -DENABLE_PRINT_SUPPORT=ON + -DENABLE_VIDEO=OFF + -DENABLE_WEBKIT=OFF + -DENABLE_WEBKIT2=OFF + -DUSE_THIN_ARCHIVES=OFF + -DUSE_GSTREAMER=OFF + -DUSE_LD_GOLD=OFF + -DUSE_WOFF2=OFF # Avoid WOFF2/Brotli runtime deps; pages fall back to other fonts when available. + -DENABLE_WEB_CRYPTO=OFF # Avoid libgcrypt/libtasn1 deps; HTTPS still works, but window.crypto.subtle is unavailable. + -DENABLE_XSLT=OFF # Avoid libxslt dependency; legacy XML+XSLT pages will not transform client-side. + "${QTWEBKIT_SOURCE_DIR}" + ) + cmake -G Ninja "${cmake_args[@]}" >"${LOG_DIR}/qtwebkit-configure.log" 2>&1 echo "==> build QtWebKit" ninja -j"$QTWEBKIT_JOBS" >"${LOG_DIR}/qtwebkit-build.log" 2>&1 echo "==> install QtWebKit" @@ -352,6 +375,7 @@ if [[ "$BUILD_SCOPE" == "all" || "$BUILD_SCOPE" == "qtwebkit" ]]; then configure_build_env_for_qt require_file "${INSTALL_DIR}/bin/qmake" install_qt_runtime_fonts + sync_installed_qt_plugin_metadata build_qtwebkit echo "==> build QtWebKit smoke test" require_file "${SMOKE_DIR}/smoke-build-entrypoint.sh" diff --git a/toolchains/qt5-static/sources.lock b/toolchains/qt5-static/sources.lock index f2b119e..2a42e88 100644 --- a/toolchains/qt5-static/sources.lock +++ b/toolchains/qt5-static/sources.lock @@ -10,9 +10,9 @@ LOCK_QT5_SRC_URL="https://download.qt.io/archive/qt/5.15/5.15.17/single/qt-every LOCK_QT5_SRC_SHA256="85eb566333d6ba59be3a97c9445a6e52f2af1b52fc3c54b8a2e7f9ea040a7de4" LOCK_QT5_SRC_MD5="5f212232bbc41f2eabbdee4fcbc4040e" -LOCK_QT5_WEBKIT_FILE="qtwebkit-5.212.0-alpha4.tar.xz" -LOCK_QT5_WEBKIT_SRC_URL="https://github.com/qtwebkit/qtwebkit/releases/download/qtwebkit-5.212.0-alpha4/qtwebkit-5.212.0-alpha4.tar.xz" -LOCK_QT5_WEBKIT_SHA256="9ca126da9273664dd23a3ccd0c9bebceb7bb534bddd743db31caf6a5a6d4a9e6" +LOCK_QT5_WEBKIT_FILE="qtwebkit-2022-09-07-src.tar.xz" +LOCK_QT5_WEBKIT_SRC_URL="https://github.com/movableink/webkit/releases/download/2022-09-07/qtwebkit-2022-09-07-src.tar.xz" +LOCK_QT5_WEBKIT_SHA256="1a9f77c3f11a44d147cab6db0fd34aea803f149242e2c217683392aa2f572060" LOCK_QT5_WEBKIT_MD5="" LOCK_ICU_SRC_FILE="icu4c-65_1-src.tgz" From c3a42ce2b22f961db40d430095bfcf120277c4e0 Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Mon, 18 May 2026 13:43:05 +0200 Subject: [PATCH 12/24] Split Qt static source locks Keep the Qt and QtWebKit source checksums in separate lock files so cache keys can track each build stage independently. Co-authored-by: Codex --- toolchains/qt5-static/sources-qt.lock | 13 ++++++++++++ toolchains/qt5-static/sources-qtwebkit.lock | 6 ++++++ toolchains/qt5-static/sources.lock | 22 ++++++--------------- 3 files changed, 25 insertions(+), 16 deletions(-) create mode 100644 toolchains/qt5-static/sources-qt.lock create mode 100644 toolchains/qt5-static/sources-qtwebkit.lock diff --git a/toolchains/qt5-static/sources-qt.lock b/toolchains/qt5-static/sources-qt.lock new file mode 100644 index 0000000..be6598d --- /dev/null +++ b/toolchains/qt5-static/sources-qt.lock @@ -0,0 +1,13 @@ +# shellcheck disable=SC2034 + +LOCK_QT_VERSION="5.15.17" + +LOCK_QT5_SRC_FILE="qt-everywhere-opensource-src-5.15.17.tar.xz" +LOCK_QT5_SRC_URL="https://download.qt.io/archive/qt/5.15/5.15.17/single/qt-everywhere-opensource-src-5.15.17.tar.xz" +LOCK_QT5_SRC_SHA256="85eb566333d6ba59be3a97c9445a6e52f2af1b52fc3c54b8a2e7f9ea040a7de4" +LOCK_QT5_SRC_MD5="5f212232bbc41f2eabbdee4fcbc4040e" + +LOCK_ICU_SRC_FILE="icu4c-65_1-src.tgz" +LOCK_ICU_SRC_URL="https://github.com/unicode-org/icu/releases/download/release-65-1/icu4c-65_1-src.tgz" +LOCK_ICU_SRC_SHA256="53e37466b3d6d6d01ead029e3567d873a43a5d1c668ed2278e253b683136d948" +LOCK_ICU_SRC_MD5="d1ff436e26cabcb28e6cb383d32d1339" diff --git a/toolchains/qt5-static/sources-qtwebkit.lock b/toolchains/qt5-static/sources-qtwebkit.lock new file mode 100644 index 0000000..5dcb613 --- /dev/null +++ b/toolchains/qt5-static/sources-qtwebkit.lock @@ -0,0 +1,6 @@ +# shellcheck disable=SC2034 + +LOCK_QT5_WEBKIT_FILE="qtwebkit-2022-09-07-src.tar.xz" +LOCK_QT5_WEBKIT_SRC_URL="https://github.com/movableink/webkit/releases/download/2022-09-07/qtwebkit-2022-09-07-src.tar.xz" +LOCK_QT5_WEBKIT_SHA256="1a9f77c3f11a44d147cab6db0fd34aea803f149242e2c217683392aa2f572060" +LOCK_QT5_WEBKIT_MD5="" diff --git a/toolchains/qt5-static/sources.lock b/toolchains/qt5-static/sources.lock index 2a42e88..039b585 100644 --- a/toolchains/qt5-static/sources.lock +++ b/toolchains/qt5-static/sources.lock @@ -1,21 +1,11 @@ -# shellcheck disable=SC2034 - # This lock file is sourced by build-qt5-static.sh. # Every source must have at least one checksum (sha256 preferred, md5 fallback). -LOCK_QT_VERSION="5.15.17" - -LOCK_QT5_SRC_FILE="qt-everywhere-opensource-src-5.15.17.tar.xz" -LOCK_QT5_SRC_URL="https://download.qt.io/archive/qt/5.15/5.15.17/single/qt-everywhere-opensource-src-5.15.17.tar.xz" -LOCK_QT5_SRC_SHA256="85eb566333d6ba59be3a97c9445a6e52f2af1b52fc3c54b8a2e7f9ea040a7de4" -LOCK_QT5_SRC_MD5="5f212232bbc41f2eabbdee4fcbc4040e" +LOCK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -LOCK_QT5_WEBKIT_FILE="qtwebkit-2022-09-07-src.tar.xz" -LOCK_QT5_WEBKIT_SRC_URL="https://github.com/movableink/webkit/releases/download/2022-09-07/qtwebkit-2022-09-07-src.tar.xz" -LOCK_QT5_WEBKIT_SHA256="1a9f77c3f11a44d147cab6db0fd34aea803f149242e2c217683392aa2f572060" -LOCK_QT5_WEBKIT_MD5="" +# shellcheck disable=SC1091 +source "${LOCK_DIR}/sources-qt.lock" +# shellcheck disable=SC1091 +source "${LOCK_DIR}/sources-qtwebkit.lock" -LOCK_ICU_SRC_FILE="icu4c-65_1-src.tgz" -LOCK_ICU_SRC_URL="https://github.com/unicode-org/icu/releases/download/release-65-1/icu4c-65_1-src.tgz" -LOCK_ICU_SRC_SHA256="53e37466b3d6d6d01ead029e3567d873a43a5d1c668ed2278e253b683136d948" -LOCK_ICU_SRC_MD5="d1ff436e26cabcb28e6cb383d32d1339" +unset LOCK_DIR From d380870e138027be3c20235ac8d36fa2605e417c Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Tue, 12 May 2026 00:32:00 +0200 Subject: [PATCH 13/24] qt5-static: use container ICU package Use the Docker image ICU headers and static archives instead of downloading and building a locked ICU source archive. Drop the icu-static artifact from CI caches and release packages, and record ICU as a system-package input in the build manifest. Co-authored-by: Codex --- build-qt5-static.sh | 18 +- docs/qt5-static-poc.md | 9 +- ...mageformats-honor-webp-libs-override.patch | 13 ++ ...-platformqt-generate-static-pri-libs.patch | 24 +++ .../qt5-static/qt5-static-build-entrypoint.sh | 165 ++---------------- toolchains/qt5-static/sources-qt.lock | 5 - 6 files changed, 57 insertions(+), 177 deletions(-) create mode 100644 toolchains/qt5-static/patches/qt/0005-imageformats-honor-webp-libs-override.patch create mode 100644 toolchains/qt5-static/patches/qtwebkit/0013-platformqt-generate-static-pri-libs.patch diff --git a/build-qt5-static.sh b/build-qt5-static.sh index 3412259..33b5226 100755 --- a/build-qt5-static.sh +++ b/build-qt5-static.sh @@ -42,8 +42,6 @@ Environment overrides: QT5_SRC_SHA256 QT5_WEBKIT_SRC_URL QT5_WEBKIT_SHA256 - ICU_SRC_URL - ICU_SRC_SHA256 EOF } @@ -262,17 +260,12 @@ QT5_WEBKIT_SRC_URL="${QT5_WEBKIT_SRC_URL:-${LOCK_QT5_WEBKIT_SRC_URL}}" QT5_WEBKIT_SHA256="${QT5_WEBKIT_SHA256:-${LOCK_QT5_WEBKIT_SHA256:-}}" QT5_WEBKIT_MD5="${LOCK_QT5_WEBKIT_MD5:-}" -ICU_SRC_URL="${ICU_SRC_URL:-${LOCK_ICU_SRC_URL}}" -ICU_SRC_SHA256="${ICU_SRC_SHA256:-${LOCK_ICU_SRC_SHA256:-}}" -ICU_SRC_MD5="${LOCK_ICU_SRC_MD5:-}" - -if [[ -z "$QT5_SRC_URL" || -z "$QT5_WEBKIT_SRC_URL" || -z "$ICU_SRC_URL" ]]; then +if [[ -z "$QT5_SRC_URL" || -z "$QT5_WEBKIT_SRC_URL" ]]; then fail "source URLs are empty in lock file" fi QT5_SRC_FILE="$(source_file_name "$QT5_SRC_URL" "$LOCK_QT5_SRC_URL" "${LOCK_QT5_SRC_FILE:-}")" QT5_WEBKIT_FILE="$(source_file_name "$QT5_WEBKIT_SRC_URL" "$LOCK_QT5_WEBKIT_SRC_URL" "${LOCK_QT5_WEBKIT_FILE:-}")" -ICU_SRC_FILE="$(source_file_name "$ICU_SRC_URL" "$LOCK_ICU_SRC_URL" "${LOCK_ICU_SRC_FILE:-}")" REPO_ABS="$(cd "$REPO_ROOT" && pwd -P)" OUTPUT_RAW="$(cd "$REPO_ROOT" && realpath -m -- "$OUTPUT_DIR")" @@ -285,7 +278,6 @@ if $CLEAN && [[ -d "$OUTPUT_RAW" ]]; then rm -rf \ "${OUTPUT_RAW}/build" \ "${OUTPUT_RAW}/install" \ - "${OUTPUT_RAW}/icu-static" \ "${OUTPUT_RAW}/xkb-config-root" \ "${OUTPUT_RAW}/logs" \ "${OUTPUT_RAW}/build-manifest.txt" @@ -302,7 +294,6 @@ mkdir -p "$SRC_CACHE_DIR" "${OUTPUT_ABS}/logs" "${OUTPUT_ABS}/build" QT5_SRC_ARCHIVE="${SRC_CACHE_DIR}/${QT5_SRC_FILE}" QT5_WEBKIT_ARCHIVE="${SRC_CACHE_DIR}/${QT5_WEBKIT_FILE}" -ICU_SRC_ARCHIVE="${SRC_CACHE_DIR}/${ICU_SRC_FILE}" download_file "$QT5_SRC_URL" "$QT5_SRC_ARCHIVE" verify_checksum "$QT5_SRC_ARCHIVE" "$QT5_SRC_SHA256" "$QT5_SRC_MD5" "$QT5_SRC_FILE" @@ -310,9 +301,6 @@ verify_checksum "$QT5_SRC_ARCHIVE" "$QT5_SRC_SHA256" "$QT5_SRC_MD5" "$QT5_SRC_FI download_file "$QT5_WEBKIT_SRC_URL" "$QT5_WEBKIT_ARCHIVE" verify_checksum "$QT5_WEBKIT_ARCHIVE" "$QT5_WEBKIT_SHA256" "$QT5_WEBKIT_MD5" "$QT5_WEBKIT_FILE" -download_file "$ICU_SRC_URL" "$ICU_SRC_ARCHIVE" -verify_checksum "$ICU_SRC_ARCHIVE" "$ICU_SRC_SHA256" "$ICU_SRC_MD5" "$ICU_SRC_FILE" - CONTAINER_RUNTIME="$(pick_runtime)" echo "using container runtime: $CONTAINER_RUNTIME" @@ -332,16 +320,12 @@ trap cleanup_run_container INT TERM HUP -e OUTPUT_DIR="${OUTPUT_ABS}" \ -e QT_SRC_ARCHIVE="${QT5_SRC_ARCHIVE}" \ -e QTWEBKIT_ARCHIVE="${QT5_WEBKIT_ARCHIVE}" \ - -e ICU_SRC_ARCHIVE="${ICU_SRC_ARCHIVE}" \ -e QT_SRC_URL="$QT5_SRC_URL" \ -e QTWEBKIT_URL="$QT5_WEBKIT_SRC_URL" \ - -e ICU_SRC_URL="$ICU_SRC_URL" \ -e QT_SRC_SHA256="$QT5_SRC_SHA256" \ -e QTWEBKIT_SHA256="$QT5_WEBKIT_SHA256" \ - -e ICU_SRC_SHA256="$ICU_SRC_SHA256" \ -e QT_SRC_MD5="$QT5_SRC_MD5" \ -e QTWEBKIT_MD5="$QT5_WEBKIT_MD5" \ - -e ICU_SRC_MD5="$ICU_SRC_MD5" \ -v "${REPO_ROOT}:/workspace" \ -v "${REPO_ROOT}:${REPO_ROOT}" \ -w /workspace \ diff --git a/docs/qt5-static-poc.md b/docs/qt5-static-poc.md index 8173db4..20e5056 100644 --- a/docs/qt5-static-poc.md +++ b/docs/qt5-static-poc.md @@ -35,8 +35,6 @@ Supported source override env vars: - `QT5_SRC_SHA256` - `QT5_WEBKIT_SRC_URL` - `QT5_WEBKIT_SHA256` -- `ICU_SRC_URL` -- `ICU_SRC_SHA256` Checksum policy: 1. Prefer `sha256`. @@ -49,8 +47,7 @@ Default build roots: `artifacts/qt5-static-5.15.17-release` and `artifacts/qt5-s - `artifacts/src-cache/`: shared downloaded archives for all build flavors - `build/`: extracted/build tree - `install/`: static Qt install prefix -- `icu-static/`: static ICU install prefix -- `logs/`: `icu-configure.log`, `icu-build.log`, `icu-install.log`, `configure.log`, `build.log`, `install.log`, `qtwebkit-configure.log`, `qtwebkit-build.log`, `qtwebkit-install.log`, `smoke-build.log`, `verify.log` +- `logs/`: `configure.log`, `build.log`, `install.log`, `qtwebkit-configure.log`, `qtwebkit-build.log`, `qtwebkit-install.log`, `smoke-build.log`, `verify.log` - `build-manifest.txt`: runtime, source URLs/checksums, configure flags, verification summary ## Verification Gates @@ -66,7 +63,7 @@ A successful run must satisfy: - `libQt5PrintSupport.a` - `libQt5WebKit.a` - `libQt5WebKitWidgets.a` -4. Required static ICU libs exist in `icu-static/lib`: +4. Required static ICU libs exist in the container image: - `libicuuc.a` - `libicui18n.a` - `libicudata.a` @@ -77,7 +74,7 @@ A successful run must satisfy: Implemented target behavior: - Containerized build pipeline. - Source lock + checksum verification. -- In-container static ICU build from locked source archive. +- Static ICU from the container image. - Static Qt build. - Standalone QtWebKit build against installed Qt. - Static Qt + QtWebKit library verification. diff --git a/toolchains/qt5-static/patches/qt/0005-imageformats-honor-webp-libs-override.patch b/toolchains/qt5-static/patches/qt/0005-imageformats-honor-webp-libs-override.patch new file mode 100644 index 0000000..13f0aae --- /dev/null +++ b/toolchains/qt5-static/patches/qt/0005-imageformats-honor-webp-libs-override.patch @@ -0,0 +1,13 @@ +diff --git a/qtimageformats/src/imageformats/configure.json b/qtimageformats/src/imageformats/configure.json +index 2a359305..e2c8b2fb 100644 +--- a/qtimageformats/src/imageformats/configure.json ++++ b/qtimageformats/src/imageformats/configure.json +@@ -115,7 +115,7 @@ + ] + }, + "sources": [ +- { "type": "pkgConfig", "args": "libwebp libwebpmux libwebpdemux" }, ++ { "type": "pkgConfig", "condition": "input.webp.libs == ''", "args": "libwebp libwebpmux libwebpdemux" }, + { "libs": "-lwebp -lwebpdemux -lwebpmux" } + ] + } diff --git a/toolchains/qt5-static/patches/qtwebkit/0013-platformqt-generate-static-pri-libs.patch b/toolchains/qt5-static/patches/qtwebkit/0013-platformqt-generate-static-pri-libs.patch new file mode 100644 index 0000000..761ca37 --- /dev/null +++ b/toolchains/qt5-static/patches/qtwebkit/0013-platformqt-generate-static-pri-libs.patch @@ -0,0 +1,24 @@ +diff --git a/Source/WebKitLegacy/PlatformQt.cmake b/Source/WebKitLegacy/PlatformQt.cmake +--- a/Source/WebKitLegacy/PlatformQt.cmake ++++ b/Source/WebKitLegacy/PlatformQt.cmake +@@ -357,6 +357,9 @@ if (QT_STATIC_BUILD) + set(WEBKIT_PKGCONFIG_DEPS "${WEBKIT_PKGCONFIG_DEPS} ${LIB_PREFIX}${LIB_NAME}") + set(WEBKIT_PRI_EXTRA_LIBS "${WEBKIT_PRI_EXTRA_LIBS} -l${LIB_PREFIX}${LIB_NAME}") + endforeach () ++ if (QTWEBKIT_SYSTEM_LIB_DIR) ++ set(WEBKIT_PRI_EXTRA_LIBS "-L\$\$QT_MODULE_LIB_BASE -lWebCore -lPAL -lJavaScriptCore -lWTF ${QTWEBKIT_SYSTEM_LIB_DIR}/libxml2.a ${QTWEBKIT_SYSTEM_LIB_DIR}/liblzma.a ${QTWEBKIT_SYSTEM_LIB_DIR}/libharfbuzz-icu.a ${QTWEBKIT_SYSTEM_LIB_DIR}/libicui18n.a ${QTWEBKIT_SYSTEM_LIB_DIR}/libicuuc.a ${QTWEBKIT_SYSTEM_LIB_DIR}/libicudata.a ${QTWEBKIT_SYSTEM_LIB_DIR}/libsqlite3.a -lz -lbmalloc ${QTWEBKIT_SYSTEM_LIB_DIR}/libhyphen.a -latomic") ++ endif () + endif () + + if (NOT MACOS_BUILD_FRAMEWORKS) +@@ -687,6 +690,10 @@ else () + endif () + endif () + ++if (QT_STATIC_BUILD) ++ list(APPEND WebKitWidgets_PRI_ARGUMENTS MODULE_CONFIG "staticlib") ++endif () ++ + list(APPEND WebKitWidgets_Private_PRI_ARGUMENTS MODULE_CONFIG "internal_module no_link") + + if (MACOS_BUILD_FRAMEWORKS) diff --git a/toolchains/qt5-static/qt5-static-build-entrypoint.sh b/toolchains/qt5-static/qt5-static-build-entrypoint.sh index 7d38dcc..c2ae5b2 100755 --- a/toolchains/qt5-static/qt5-static-build-entrypoint.sh +++ b/toolchains/qt5-static/qt5-static-build-entrypoint.sh @@ -5,7 +5,6 @@ set -euo pipefail : "${OUTPUT_DIR:?OUTPUT_DIR is required}" : "${QT_SRC_ARCHIVE:?QT_SRC_ARCHIVE is required}" : "${QTWEBKIT_ARCHIVE:?QTWEBKIT_ARCHIVE is required}" -: "${ICU_SRC_ARCHIVE:?ICU_SRC_ARCHIVE is required}" JOBS="${JOBS:-$(nproc 2>/dev/null || echo 8)}" QTWEBKIT_JOBS="$JOBS" @@ -18,9 +17,6 @@ BUILD_SCOPE="${BUILD_SCOPE:-all}" WORK_DIR="${OUTPUT_DIR}/build" LOG_DIR="${OUTPUT_DIR}/logs" INSTALL_DIR="${OUTPUT_DIR}/install" -ICU_INSTALL_DIR="${OUTPUT_DIR}/icu-static" -OPENSSL_INCLUDE_DIR="/usr/include" -OPENSSL_LIB_DIR="/usr/lib/x86_64-linux-gnu" SYSTEM_LIB_DIR="/usr/lib/x86_64-linux-gnu" DEJAVU_FONT_DIR="/usr/share/fonts/truetype/dejavu" MANIFEST_FILE="${OUTPUT_DIR}/build-manifest.txt" @@ -77,10 +73,9 @@ CONFIGURE_FLAGS=( -qt-libpng -qt-libjpeg -icu - -I "${ICU_INSTALL_DIR}/include" - -L "${ICU_INSTALL_DIR}/lib" + "ICU_LIBS=${SYSTEM_LIB_DIR}/libicui18n.a ${SYSTEM_LIB_DIR}/libicuuc.a ${SYSTEM_LIB_DIR}/libicudata.a" + "WEBP_LIBS=${SYSTEM_LIB_DIR}/libwebpmux.a ${SYSTEM_LIB_DIR}/libwebpdemux.a ${SYSTEM_LIB_DIR}/libwebp.a -lpthread" -openssl-linked - -L "${OPENSSL_LIB_DIR}" ) require_file() { @@ -135,60 +130,15 @@ apply_matching_patches() { done } -build_static_icu() { - local extract_dir icu_top_dir icu_source_dir - - require_file "$ICU_SRC_ARCHIVE" - - if [[ -f "${ICU_INSTALL_DIR}/lib/libicuuc.a" && -f "${ICU_INSTALL_DIR}/lib/libicui18n.a" && -f "${ICU_INSTALL_DIR}/lib/libicudata.a" ]]; then - echo "==> reusing static ICU install: ${ICU_INSTALL_DIR}" - return - fi - - echo "==> build static ICU" - extract_dir="${WORK_DIR}/_icu_extract" - rm -rf "$extract_dir" - mkdir -p "$extract_dir" - tar -xf "$ICU_SRC_ARCHIVE" -C "$extract_dir" - - icu_top_dir="$(find "$extract_dir" -mindepth 1 -maxdepth 1 -type d | head -n 1)" - [[ -n "$icu_top_dir" ]] || fail "could not identify extracted ICU source root" - - if [[ -f "${icu_top_dir}/source/configure" ]]; then - icu_source_dir="${icu_top_dir}/source" - elif [[ -f "${icu_top_dir}/icu/source/configure" ]]; then - icu_source_dir="${icu_top_dir}/icu/source" - else - fail "could not find ICU configure script in extracted archive" - fi - - rm -rf "$ICU_INSTALL_DIR" - pushd "$icu_source_dir" >/dev/null - ./configure \ - --prefix="$ICU_INSTALL_DIR" \ - --disable-shared \ - --enable-static \ - --disable-dyload \ - --with-data-packaging=static \ - CFLAGS="-fPIC" \ - CXXFLAGS="-fPIC" >"${LOG_DIR}/icu-configure.log" 2>&1 - make -j"$JOBS" >"${LOG_DIR}/icu-build.log" 2>&1 - make install >"${LOG_DIR}/icu-install.log" 2>&1 - popd >/dev/null - - rm -rf "$extract_dir" -} - configure_build_env_for_qt() { - require_dir "$ICU_INSTALL_DIR" + echo "==> verify system ICU static archives" + require_file "${SYSTEM_LIB_DIR}/libicuuc.a" + require_file "${SYSTEM_LIB_DIR}/libicui18n.a" + require_file "${SYSTEM_LIB_DIR}/libicudata.a" echo "==> verify system OpenSSL static archives" - require_file "${OPENSSL_INCLUDE_DIR}/openssl/ssl.h" - require_file "${OPENSSL_LIB_DIR}/libssl.a" - require_file "${OPENSSL_LIB_DIR}/libcrypto.a" - export PKG_CONFIG_PATH="${ICU_INSTALL_DIR}/lib/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}}" - export CPPFLAGS="-I${ICU_INSTALL_DIR}/include${CPPFLAGS:+ ${CPPFLAGS}}" - export LDFLAGS="-L${OPENSSL_LIB_DIR} -L${ICU_INSTALL_DIR}/lib${LDFLAGS:+ ${LDFLAGS}}" - export OPENSSL_LIBS="-Wl,-Bstatic ${OPENSSL_LIB_DIR}/libssl.a ${OPENSSL_LIB_DIR}/libcrypto.a -Wl,-Bdynamic -ldl -lpthread -lz" + require_file "${SYSTEM_LIB_DIR}/libssl.a" + require_file "${SYSTEM_LIB_DIR}/libcrypto.a" + export OPENSSL_LIBS="-Wl,-Bstatic ${SYSTEM_LIB_DIR}/libssl.a ${SYSTEM_LIB_DIR}/libcrypto.a -Wl,-Bdynamic -ldl -lpthread -lz" } configure_qt() { @@ -196,27 +146,6 @@ configure_qt() { ./configure -v "${CONFIGURE_FLAGS[@]}" >"${LOG_DIR}/configure.log" 2>&1 } -sync_installed_qmake_metadata() { - local qtbase_build_dir="${QT_SRC_DIR}/qtbase" - local build_qconfig="${qtbase_build_dir}/mkspecs/qconfig.pri" - local build_qmodule="${qtbase_build_dir}/mkspecs/qmodule.pri" - local build_network_prl="${qtbase_build_dir}/lib/libQt5Network.prl" - local install_qconfig="${INSTALL_DIR}/mkspecs/qconfig.pri" - local install_qmodule="${INSTALL_DIR}/mkspecs/qmodule.pri" - local install_network_prl="${INSTALL_DIR}/lib/libQt5Network.prl" - local install_lib_expr='$$[QT_INSTALL_LIBS]' - - require_file "$build_qconfig" - require_file "$build_qmodule" - require_file "$build_network_prl" - require_dir "${INSTALL_DIR}/mkspecs" - require_dir "${INSTALL_DIR}/lib" - - cp "$build_qconfig" "$install_qconfig" - cp "$build_qmodule" "$install_qmodule" - sed "s|${qtbase_build_dir}/lib|${install_lib_expr}|g" "$build_network_prl" > "$install_network_prl" -} - install_qt_runtime_fonts() { local font_dir="${INSTALL_DIR}/lib/fonts" local font_files=("${DEJAVU_FONT_DIR}"/*.ttf) @@ -229,44 +158,14 @@ install_qt_runtime_fonts() { cp -f "${font_files[@]}" "$font_dir"/ } -sync_installed_qtwebkit_metadata() { - local webkit_module_pri="${INSTALL_DIR}/mkspecs/modules/qt_lib_webkit.pri" - local webkitwidgets_module_pri="${INSTALL_DIR}/mkspecs/modules/qt_lib_webkitwidgets.pri" - local install_lib_expr='$$QT_MODULE_LIB_BASE' - local icu_lib_expr='$$[QT_INSTALL_PREFIX]/../icu-static/lib' - local webkit_private_libs="-L${install_lib_expr} -lWebCore -lPAL -lJavaScriptCore -lWTF ${SYSTEM_LIB_DIR}/libxml2.a ${SYSTEM_LIB_DIR}/liblzma.a ${icu_lib_expr}/libicui18n.a ${icu_lib_expr}/libicuuc.a ${icu_lib_expr}/libicudata.a ${SYSTEM_LIB_DIR}/libsqlite3.a -lz -lbmalloc ${SYSTEM_LIB_DIR}/libhyphen.a -lharfbuzz-icu -latomic" - - require_file "$webkit_module_pri" - - if ! grep -Fq -- "-L${install_lib_expr}" "$webkit_module_pri"; then - sed -i "s|^QMAKE_LIBS_PRIVATE += |QMAKE_LIBS_PRIVATE += -L${install_lib_expr} |" "$webkit_module_pri" - fi - - sed -i "s|^QMAKE_LIBS_PRIVATE += .*|QMAKE_LIBS_PRIVATE += ${webkit_private_libs}|" "$webkit_module_pri" - - if [[ -f "$webkitwidgets_module_pri" ]]; then - sed -i 's/\(QT\.webkitwidgets\.module_config = .*v2\)\s*$/\1 staticlib/' "$webkitwidgets_module_pri" - fi -} - -sync_installed_qt_plugin_metadata() { - local qwebp_prl="${INSTALL_DIR}/plugins/imageformats/libqwebp.prl" - - if [[ -f "$qwebp_prl" ]]; then - sed -i "s|-lwebpmux -lwebpdemux -lwebp|${SYSTEM_LIB_DIR}/libwebpmux.a ${SYSTEM_LIB_DIR}/libwebpdemux.a ${SYSTEM_LIB_DIR}/libwebp.a|g" "$qwebp_prl" - fi -} - build_qtwebkit() { local extract_dir source_root local top_level_entries=() - require_file "$QTWEBKIT_ARCHIVE" if [[ -f "${INSTALL_DIR}/lib/libQt5WebKit.a" && -f "${INSTALL_DIR}/lib/libQt5WebKitWidgets.a" ]]; then if is_thin_archive "${INSTALL_DIR}/lib/libQt5WebKit.a" || is_thin_archive "${INSTALL_DIR}/lib/libQt5WebKitWidgets.a"; then fail "installed QtWebKit archives are thin; remove the installed QtWebKit artifacts and rerun so they can be rebuilt as normal archives" fi - sync_installed_qtwebkit_metadata echo "==> reusing installed QtWebKit from ${INSTALL_DIR}" return fi @@ -304,9 +203,12 @@ build_qtwebkit() { -DPORT=Qt -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" - -DCMAKE_PREFIX_PATH="${INSTALL_DIR};${ICU_INSTALL_DIR}" + -DCMAKE_PREFIX_PATH="${INSTALL_DIR}" -DQt5_DIR="${INSTALL_DIR}/lib/cmake/Qt5" - -DICU_ROOT="${ICU_INSTALL_DIR}" + -DICU_UC_LIBRARY="${SYSTEM_LIB_DIR}/libicuuc.a" + -DICU_I18N_LIBRARY="${SYSTEM_LIB_DIR}/libicui18n.a" + -DICU_DATA_LIBRARY="${SYSTEM_LIB_DIR}/libicudata.a" + -DQTWEBKIT_SYSTEM_LIB_DIR="${SYSTEM_LIB_DIR}" -DENABLE_API_TESTS=OFF -DENABLE_TOOLS=OFF -DENABLE_GEOLOCATION=OFF @@ -327,24 +229,21 @@ build_qtwebkit() { ninja -j"$QTWEBKIT_JOBS" >"${LOG_DIR}/qtwebkit-build.log" 2>&1 echo "==> install QtWebKit" ninja install >"${LOG_DIR}/qtwebkit-install.log" 2>&1 - sync_installed_qtwebkit_metadata popd >/dev/null } mkdir -p "$WORK_DIR" "$LOG_DIR" require_file "$QT_SRC_ARCHIVE" require_file "$QTWEBKIT_ARCHIVE" -require_file "$ICU_SRC_ARCHIVE" case "${CLEAN,,}" in 1|true|yes|on) find "$WORK_DIR" -maxdepth 1 -mindepth 1 -type d -name "qt-everywhere*-${QT_VERSION}" -exec rm -rf {} + - rm -rf "$QTWEBKIT_BUILD_DIR" "$INSTALL_DIR" "$ICU_INSTALL_DIR" + rm -rf "$QTWEBKIT_BUILD_DIR" "$INSTALL_DIR" ;; esac if [[ "$BUILD_SCOPE" == "all" || "$BUILD_SCOPE" == "qt" ]]; then - build_static_icu configure_build_env_for_qt if [[ ! -x "${INSTALL_DIR}/bin/qmake" ]]; then @@ -365,17 +264,14 @@ if [[ "$BUILD_SCOPE" == "all" || "$BUILD_SCOPE" == "qt" ]]; then make -j"$JOBS" >"${LOG_DIR}/build.log" 2>&1 echo "==> install Qt" make install >"${LOG_DIR}/install.log" 2>&1 - sync_installed_qmake_metadata install_qt_runtime_fonts popd >/dev/null fi if [[ "$BUILD_SCOPE" == "all" || "$BUILD_SCOPE" == "qtwebkit" ]]; then - build_static_icu configure_build_env_for_qt require_file "${INSTALL_DIR}/bin/qmake" install_qt_runtime_fonts - sync_installed_qt_plugin_metadata build_qtwebkit echo "==> build QtWebKit smoke test" require_file "${SMOKE_DIR}/smoke-build-entrypoint.sh" @@ -422,16 +318,6 @@ if [[ "$BUILD_SCOPE" == "all" || "$BUILD_SCOPE" == "qtwebkit" ]]; then ) fi -required_icu_libs=( - "libicuuc.a" - "libicui18n.a" - "libicudata.a" -) -required_ssl_libs=( - "libssl.a" - "libcrypto.a" -) - missing=0 for lib in "${required_libs[@]}"; do if [[ ! -f "${INSTALL_DIR}/lib/${lib}" ]]; then @@ -440,18 +326,6 @@ for lib in "${required_libs[@]}"; do fi done -for lib in "${required_icu_libs[@]}"; do - if [[ ! -f "${ICU_INSTALL_DIR}/lib/${lib}" ]]; then - log_verify "missing: ${ICU_INSTALL_DIR}/lib/${lib}" - missing=1 - fi -done -for lib in "${required_ssl_libs[@]}"; do - if [[ ! -f "${OPENSSL_LIB_DIR}/${lib}" ]]; then - log_verify "missing: ${OPENSSL_LIB_DIR}/${lib}" - missing=1 - fi -done if ! grep -q 'openssl-linked' "${INSTALL_DIR}/mkspecs/modules/qt_lib_network_private.pri"; then log_verify "missing openssl-linked in: ${INSTALL_DIR}/mkspecs/modules/qt_lib_network_private.pri" missing=1 @@ -473,22 +347,15 @@ fi echo "build_scope=${BUILD_SCOPE}" echo "qt_src_archive=${QT_SRC_ARCHIVE}" echo "qtwebkit_archive=${QTWEBKIT_ARCHIVE}" - echo "icu_src_archive=${ICU_SRC_ARCHIVE}" echo "qt_src_url=${QT_SRC_URL:-}" echo "qtwebkit_url=${QTWEBKIT_URL:-}" - echo "icu_src_url=${ICU_SRC_URL:-}" echo "qt_src_sha256=${QT_SRC_SHA256:-}" echo "qtwebkit_sha256=${QTWEBKIT_SHA256:-}" - echo "icu_src_sha256=${ICU_SRC_SHA256:-}" echo "qt_src_md5=${QT_SRC_MD5:-}" echo "qtwebkit_md5=${QTWEBKIT_MD5:-}" - echo "icu_src_md5=${ICU_SRC_MD5:-}" + echo "icu_source=system-package" echo "openssl_source=system-package" - echo "openssl_include_dir=${OPENSSL_INCLUDE_DIR}" - echo "openssl_lib_dir=${OPENSSL_LIB_DIR}" echo "verified_libs=${required_libs[*]}" - echo "verified_icu_libs=${required_icu_libs[*]}" - echo "verified_ssl_libs=${required_ssl_libs[*]}" if [[ "$BUILD_SCOPE" == "all" || "$BUILD_SCOPE" == "qtwebkit" ]]; then echo "smoke_binary=${SMOKE_BUILD_DIR}/qtwebkit-smoke" fi diff --git a/toolchains/qt5-static/sources-qt.lock b/toolchains/qt5-static/sources-qt.lock index be6598d..55fb227 100644 --- a/toolchains/qt5-static/sources-qt.lock +++ b/toolchains/qt5-static/sources-qt.lock @@ -6,8 +6,3 @@ LOCK_QT5_SRC_FILE="qt-everywhere-opensource-src-5.15.17.tar.xz" LOCK_QT5_SRC_URL="https://download.qt.io/archive/qt/5.15/5.15.17/single/qt-everywhere-opensource-src-5.15.17.tar.xz" LOCK_QT5_SRC_SHA256="85eb566333d6ba59be3a97c9445a6e52f2af1b52fc3c54b8a2e7f9ea040a7de4" LOCK_QT5_SRC_MD5="5f212232bbc41f2eabbdee4fcbc4040e" - -LOCK_ICU_SRC_FILE="icu4c-65_1-src.tgz" -LOCK_ICU_SRC_URL="https://github.com/unicode-org/icu/releases/download/release-65-1/icu4c-65_1-src.tgz" -LOCK_ICU_SRC_SHA256="53e37466b3d6d6d01ead029e3567d873a43a5d1c668ed2278e253b683136d948" -LOCK_ICU_SRC_MD5="d1ff436e26cabcb28e6cb383d32d1339" From 6fe8b27252bf6207dfa19abeb8cac4a196bf41be Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Sun, 17 May 2026 15:32:04 +0200 Subject: [PATCH 14/24] Add host-side runner check mode Add --check mode to the smoke and browser runner scripts so CI and local validation can use the same xvfb-backed host-side flow. Document the smoke and browser check commands as the only runtime-check path for agents. Co-authored-by: Codex --- README.md | 2 +- docs/qt5-static-poc.md | 5 ++++- run-browser.sh | 20 +++++++++++++++++++- run-smoke.sh | 22 ++++++++++++++++++++-- smoke-tests/qtwebkit-smoke/README.md | 12 ++++++++++++ 5 files changed, 56 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e4d8b82..35cff9d 100644 --- a/README.md +++ b/README.md @@ -3,4 +3,4 @@ QtWeb QtWeb Internet Browser -Build policy: do not use host-local or ad hoc builds for this repository. Use the repository helper scripts and containerized flows for build or validation work; if that path is unavailable, report validation as not run instead of falling back to local `qmake`/`make` commands. Agents should not launch the built `QtWeb` binary or other produced executables unless explicitly asked; they should report the path or command for the user to run instead. +Build policy: do not use host-local or ad hoc builds for this repository. Use the repository helper scripts and containerized flows for build or validation work; if that path is unavailable, report validation as not run instead of falling back to local `qmake`/`make` commands. `./run-smoke.sh --check about:blank` is a valid host-side runtime check for an existing Docker-built smoke binary. After rebuilding the browser, `./run-browser.sh --check about:blank` is the valid host-side runtime check for the Docker-built browser. Agents may only use `run-smoke.sh` and `run-browser.sh` for runtime checks; directly launching the built `QtWeb` binary or other produced executables is prohibited. diff --git a/docs/qt5-static-poc.md b/docs/qt5-static-poc.md index 20e5056..ddd7465 100644 --- a/docs/qt5-static-poc.md +++ b/docs/qt5-static-poc.md @@ -8,6 +8,8 @@ Target versions: - QtWebKit `5.212.0-alpha4` This POC validates the toolchain pipeline and the QtWebKit smoke-build gate. +After rebuilding the browser, use `./run-browser.sh --check about:blank` from +the host to runtime-check the Docker-built browser. Primary portability target: static linking plus minimal runtime dependencies. ## Non-Goals @@ -103,7 +105,8 @@ Custom output directory inside repo: - Static QtWebKit can still require follow-up patches for newer compilers or linkers. - Archive URLs may become unavailable over time. - Over-aggressive dependency reduction can break TLS, certificate handling, or module detection. -- Runtime browser validation remains user-owned. +- Runtime browser validation must use the host-side `run-browser.sh --check` + helper for the Docker-built browser. ## Next Tasks 1. Build the main browser with `build-browser-docker.sh` against the produced toolchain. diff --git a/run-browser.sh b/run-browser.sh index 27b8253..8ab9c3c 100755 --- a/run-browser.sh +++ b/run-browser.sh @@ -6,6 +6,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" BUILD_TYPE="release" RUN_WITH_GDB=0 RUN_BUILD=0 +RUN_CHECK=0 while [[ $# -gt 0 ]]; do case "$1" in --rebuild) @@ -21,6 +22,10 @@ while [[ $# -gt 0 ]]; do BUILD_TYPE="debug" shift ;; + --check) + RUN_CHECK=1 + shift + ;; --) shift break @@ -39,6 +44,11 @@ case "${BUILD_TYPE}" in ;; esac +if [[ "${RUN_WITH_GDB}" -eq 1 && "${RUN_CHECK}" -eq 1 ]]; then + echo "error: --gdb cannot be used with --check" >&2 + exit 1 +fi + BINARY="${SCRIPT_DIR}/build-docker-${BUILD_TYPE}/QtWeb" if [[ "${RUN_BUILD}" -eq 1 ]]; then if [[ "${BUILD_TYPE}" == "debug" ]]; then @@ -52,7 +62,15 @@ elif [[ ! -x "${BINARY}" ]]; then exit 1 fi -if [[ "${RUN_WITH_GDB}" -eq 1 ]]; then +if [[ "${RUN_CHECK}" -eq 1 ]]; then + set +e + xvfb-run -a timeout 20s "${BINARY}" "$@" + status="$?" + set -e + if [[ "${status}" -ne 0 && "${status}" -ne 124 ]]; then + exit "${status}" + fi +elif [[ "${RUN_WITH_GDB}" -eq 1 ]]; then exec gdb -ex run --args "${BINARY}" "$@" else exec "${BINARY}" "$@" diff --git a/run-smoke.sh b/run-smoke.sh index ed900f8..86f8aed 100755 --- a/run-smoke.sh +++ b/run-smoke.sh @@ -7,6 +7,7 @@ SMOKE_DIR="${SCRIPT_DIR}/smoke-tests/qtwebkit-smoke" BUILD_TYPE="release" RUN_WITH_GDB=0 RUN_BUILD=0 +RUN_CHECK=0 while [[ $# -gt 0 ]]; do case "$1" in --rebuild) @@ -22,6 +23,10 @@ while [[ $# -gt 0 ]]; do BUILD_TYPE="debug" shift ;; + --check) + RUN_CHECK=1 + shift + ;; --) shift break @@ -40,6 +45,11 @@ case "${BUILD_TYPE}" in ;; esac +if [[ "${RUN_WITH_GDB}" -eq 1 && "${RUN_CHECK}" -eq 1 ]]; then + echo "error: --gdb cannot be used with --check" >&2 + exit 1 +fi + BINARY="${SMOKE_DIR}/build-docker-${BUILD_TYPE}/qtwebkit-smoke" if [[ "${RUN_BUILD}" -eq 1 ]]; then if [[ "${BUILD_TYPE}" == "debug" ]]; then @@ -49,11 +59,19 @@ if [[ "${RUN_BUILD}" -eq 1 ]]; then fi elif [[ ! -x "${BINARY}" ]]; then echo "error: smoke binary not found: ${BINARY}" >&2 - echo "hint: rerun with --build" >&2 + echo "hint: rerun with --rebuild" >&2 exit 1 fi -if [[ "${RUN_WITH_GDB}" -eq 1 ]]; then +if [[ "${RUN_CHECK}" -eq 1 ]]; then + set +e + xvfb-run -a timeout 20s "${BINARY}" "$@" + status="$?" + set -e + if [[ "${status}" -ne 0 && "${status}" -ne 124 ]]; then + exit "${status}" + fi +elif [[ "${RUN_WITH_GDB}" -eq 1 ]]; then exec gdb -ex run --args "${BINARY}" "$@" else exec "${BINARY}" "$@" diff --git a/smoke-tests/qtwebkit-smoke/README.md b/smoke-tests/qtwebkit-smoke/README.md index acbefe3..c8d6ae5 100644 --- a/smoke-tests/qtwebkit-smoke/README.md +++ b/smoke-tests/qtwebkit-smoke/README.md @@ -33,6 +33,18 @@ Debug output binary: `smoke-tests/qtwebkit-smoke/build-docker-debug/qtwebkit-smoke` +## Host Check + +After the Docker build has produced the smoke binary, run the headless check +from the repository root on the host: + +```bash +./run-smoke.sh --check about:blank +``` + +This uses `xvfb-run` on the host. It does not build inside the host +environment. + ## Notes - Docker build is required because the smoke app must link against the SSL From f6bc7b2458dcacd9e18b3a3d7333fb65a9d9963c Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Mon, 18 May 2026 13:37:52 +0200 Subject: [PATCH 15/24] Consolidate migration docs Replace the migration planning docs with a concise migration status and implementation plan split. Document the policy for moving completed work from the plan into migration status. Clean up the stale qt5-static-poc image tag name. Co-authored-by: Codex --- AGENTS.md | 5 ++ docs/docker-static-analysis.md | 118 -------------------------------- docs/migration-status.md | 15 ++++ docs/migration.md | 44 ------------ docs/plan.md | 11 +++ docs/qt5-static-poc.md | 114 ------------------------------ toolchains/qt5-static/common.sh | 2 +- 7 files changed, 32 insertions(+), 277 deletions(-) delete mode 100644 docs/docker-static-analysis.md create mode 100644 docs/migration-status.md delete mode 100644 docs/migration.md create mode 100644 docs/plan.md delete mode 100644 docs/qt5-static-poc.md diff --git a/AGENTS.md b/AGENTS.md index a4d2d80..5057628 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,3 +17,8 @@ - Do not run `run-smoke.sh` or start GUI/runtime validation on the user's behalf unless the user explicitly asks for that exact execution. - Use `ldd ./smoke-tests/qtwebkit-smoke/build-docker-$(build-type)/qtwebkit-smoke` to check for remaining shared dependencies - When a build succeeds, report the output path or the command the user can run; leave execution to the user unless explicitly requested. + +## Documentation Policy +- Keep `docs/migration-status.md` limited to behavior that is implemented in the repository. +- Keep `docs/plan.md` limited to planned or pending work. +- When implementing a planned change, update both docs in the same change: move completed points from `docs/plan.md` to `docs/migration-status.md` and remove stale planned items. diff --git a/docs/docker-static-analysis.md b/docs/docker-static-analysis.md deleted file mode 100644 index d3b4431..0000000 --- a/docs/docker-static-analysis.md +++ /dev/null @@ -1,118 +0,0 @@ -# Docker Static Analysis Plan - -## Summary -Integrate `clang-tidy` and `clazy` with the existing Docker build path for QtWeb instead of adding a separate ad hoc workflow. Docker remains the canonical environment for generating the browser build and `compile_commands.json`, and `build-browser-docker.sh` remains the main entrypoint for both browser builds and static-analysis runs. - -The first milestone is reproducible Docker-backed analysis plus a conservative cleanup wave for the hand-written QtWeb application code. The goal is to establish a stable baseline and reduce high-value findings without broad refactors or behavior changes. - -## Decisions -- Docker is the canonical build environment and the source of truth for the compilation database. -- Docker also runs `clang-tidy` so it stays on a toolchain version compatible with the Qt `5.15.17` headers in this repository. -- Host-installed `clazy-standalone` consumes the Docker-produced `compile_commands.json`. -- `build-browser-docker.sh` is the main entrypoint for Dockerized analysis. -- The initial scope is application code only: - - `src/*.cpp` - - `src/torrent/*.cpp` -- The first cleanup wave is conservative and focuses on low-risk fixes only. -- Smoke tests, extracted Qt sources, patch files, and generated build outputs are out of scope for the initial analyzer integration. - -## Required Tooling -The Docker image used for browser builds must provide: -- `bear` -- `clang` -- `clang-tidy` - -The host environment running `build-browser-docker.sh --analyze` must provide: -- `clazy-standalone` - -This keeps the build path aligned with Docker while avoiding two compatibility problems: -- Ubuntu `16.04` does not provide `clazy` from the default package repositories. -- the host `clang-tidy` available in this environment can diverge from the Qt `5.15.17` headers used by this codebase. - -## Implementation Changes -Extend [`build-browser-docker.sh`](/home/magist3r/code/QtWeb/build-browser-docker.sh) with explicit analysis modes while preserving its current build behavior. - -Expected script behavior: -- `--debug` continues selecting the debug Docker build path. -- `--analyze` runs qmake, captures a compile database, and runs both analyzers. -- `--analyze-only` runs the analysis flow without keeping a separate build-only mode as the primary action. -- Optional convenience flags such as `--clang-tidy-only` or `--clazy-only` can be added if they remain simple and do not complicate the interface. - -Expected analysis flow: -1. Remove and recreate `build-docker-release` or `build-docker-debug` inside the Docker build run. -2. Run `qmake` exactly as the normal Docker build does today. -3. Run `bear -- make -j"${JOBS}"` in Docker to produce `compile_commands.json`. -4. During the container build run, execute `clang-tidy` against the scoped application sources using the generated compilation database. -5. After the container exits, run host `clazy-standalone` against the same source set using that Docker-produced compilation database. -6. Write reports into the Docker build directory so they remain visible in the repository. - -## Scope Boundaries -Included: -- hand-written browser sources in `src/` -- hand-written torrent sources in `src/torrent/` - -Excluded: -- `src/qt` -- `qt-patches/` -- smoke-test projects -- generated `moc/`, `rcc/`, `uic/`, and `qtweb_plugin_import.cpp` -- `artifacts/` -- existing `build-*` outputs except as analyzer working directories - -## Analyzer Policy -The initial analyzer configuration should be intentionally narrow and low-noise. - -Planned `clang-tidy` direction: -- conservative `readability-*` -- conservative `bugprone-*` -- simple `modernize-*` checks that do not force broad API churn - -Planned `clazy` direction: -- Qt-specific checks for clear API misuse -- temporary and container inefficiencies -- connect-related issues with obvious fixes - -The first cleanup wave should fix only findings that are clearly semantics-preserving, such as: -- dead includes -- unused locals -- redundant conditionals -- obvious Qt API misuse -- trivial temporary or container inefficiencies - -The first cleanup wave should not include: -- ownership refactors -- threading changes -- signal/slot behavior changes -- persistence or settings behavior changes -- broad stylistic rewrites - -## Outputs -Expected outputs in the selected Docker build directory: -- `build-docker-release/compile_commands.json` -- `build-docker-release/clang-tidy.txt` -- `build-docker-release/clazy.txt` -- corresponding debug variants when `--debug` is used - -Optional exported fixes files may be added if they remain clearly scoped and reviewable. - -## Validation -A successful first implementation should verify: -1. The Docker image contains `bear`, `clang`, and `clang-tidy`. -2. The host environment contains `clazy-standalone`. -3. `./build-browser-docker.sh --analyze` succeeds end to end. -4. `compile_commands.json` is generated in the selected Docker build directory. -5. The compile database contains representative entries for browser and torrent sources. -6. Both analyzer reports are written to the repository-local build directory. -7. After the first cleanup pass, the normal Docker build still succeeds. - -Representative validation files: -- `src/browsermainwindow.cpp` -- `src/networkaccessmanager.cpp` -- `src/torrent/torrentclient.cpp` - -## Risks -- Ubuntu `16.04` does not provide `clazy` from the default package repositories, so full in-image analyzer installation is not viable in the current base image. -- A host `clang-tidy` that is much newer than Qt `5.15.17` can fail inside Qt headers before project diagnostics are produced. -- Legacy QtWeb code and its headers may produce noisy diagnostics if the enabled check set is too broad. -- Generated Qt sources can easily pollute analyzer output if the source list is not explicitly scoped. -- A zero-warning target is likely unrealistic for the first pass and would create unnecessary churn. diff --git a/docs/migration-status.md b/docs/migration-status.md new file mode 100644 index 0000000..2e33547 --- /dev/null +++ b/docs/migration-status.md @@ -0,0 +1,15 @@ +# QtWeb Migration Status + +- Qt `5.15.17` is the active Qt5 migration baseline. +- QtWebKit is pinned to the Movable Ink `2022-09-07` source archive. +- Static Qt5 release and debug toolchain builds are supported. +- Standalone QtWebKit builds against the static Qt5 toolchain are supported. +- Static Qt, QtWebKit, ICU, and OpenSSL library verification is implemented. +- QtWebKit smoke build validation is implemented. +- Docker browser builds against the static Qt5 toolchain are implemented. +- Host-side browser runtime checking through the repository helper is implemented. +- Docker-backed `clang-tidy` analysis is implemented. +- Analyzer fix export is implemented for `clang-tidy`. +- Generated build manifests and build logs are implemented. +- The browser remains on QtWebKit Widgets; no Qt WebEngine migration has been implemented. +- Existing Qt4 build flow remains untouched. diff --git a/docs/migration.md b/docs/migration.md deleted file mode 100644 index 251256a..0000000 --- a/docs/migration.md +++ /dev/null @@ -1,44 +0,0 @@ -# Save Migration Plan In `docs` First, Then Execute Qt 5.15.17 Static Migration - -## Summary -- The first step is documentation: save the migration plan in `docs` before any implementation work starts, so the repo has a single agreed source of truth for the Qt `5.15.17` + QtWebKit `5.212` migration. -- After that, migrate the current `qt5-migration` branch from Qt `5.5.1` to Qt `5.15.17` while keeping QtWebKit `5.212`. -- Do not use the `qt5` branch as a donor or reference baseline. All porting work is done in place from the current `qt5-migration` tree. -- Replace the current Qt `5.5.1` static toolchain flow in place rather than adding a parallel Qt `5.15` path. - -## Key Changes -- Save this plan first in `docs/migration.md`, replacing the current Qt `5.5.1` / donor-branch-oriented plan before any code or script changes begin. -- Retarget the existing toolchain flow in `build-qt5-static.sh`, `toolchains/qt5-static/sources.lock`, and `toolchains/qt5-static/qt5-static-build-entrypoint.sh`: -- update locked sources from Qt `5.5.1` to Qt `5.15.17` -- replace the current "unpack `qtwebkit` into the Qt source tree" flow with a standalone QtWebKit `5.212` build against the installed Qt `5.15.17` prefix -- keep static ICU and OpenSSL handling, and continue verifying `libQt5WebKit.a` and `libQt5WebKitWidgets.a` -- Retarget `build-browser-docker.sh` and the QtWebKit smoke build to the new install prefix, image tag, artifact naming, and verification gates. -- Keep `src/QtWeb.pro` on `webkitwidgets`; do not introduce `webenginewidgets` or any engine-switch abstraction. -- Port the application code directly from current `qt5-migration` sources: -- fix compile and link issues caused by Qt `5.15.17` API tightening -- fix any QtWebKit `5.212` API or behavior differences -- preserve existing browser behavior, torrent support, FTP support, downloads, printing, and settings behavior unless a concrete incompatibility forces a narrow adjustment - -## Execution Order -1. Replace `docs/migration.md` with the Qt `5.15.17` + QtWebKit `5.212` migration plan and treat that document as the implementation baseline. -2. Replace the current Qt `5.5.1` toolchain lock, artifact names, and verification assumptions with Qt `5.15.17`. -3. Implement the standalone QtWebKit `5.212` build/install step and prove the static libraries install into the Qt prefix. -4. Update the QtWebKit smoke build and require it to compile/link successfully inside Docker before proceeding. -5. Retarget the main browser Docker build helper to the new prefix and compile the current app as-is to expose the real Qt `5.15.17` breakage list. -6. Fix the browser code in place on `qt5-migration`, starting with WebKit-facing code and then any remaining Qt `5.15.17` compatibility issues. -7. Validate build success through the sanctioned helper scripts and update the remaining Qt5 toolchain docs to match the implemented flow. - -## Validation -- Documentation gate: `docs/migration.md` is updated first and accurately describes the chosen migration strategy. -- Toolchain gate: `build-qt5-static.sh` produces a static Qt `5.15.17` install and static QtWebKit `5.212` libraries. -- Smoke gate: `smoke-tests/qtwebkit-smoke` builds and links against the produced prefix in Docker. -- Browser gate: `build-browser-docker.sh` completes for release; debug is secondary after release passes. -- Runtime regression testing is explicitly user-owned and out of scope for agent execution. - -## Assumptions And Defaults -- Work starts from current `qt5-migration` head only; the `qt5` branch is explicitly out of scope. -- Qt baseline is pinned to `5.15.17`. -- Linux `x86_64` only. -- Existing Qt4 flow stays untouched. -- QtWebKit `5.212` is accepted despite its age and security risk; this migration plan does not include an engine replacement track. -- If the static QtWebKit smoke gate fails and cannot be resolved cleanly, the migration stops with a documented blocker rather than pivoting to Qt WebEngine. diff --git a/docs/plan.md b/docs/plan.md new file mode 100644 index 0000000..fe1c017 --- /dev/null +++ b/docs/plan.md @@ -0,0 +1,11 @@ +# QtWeb Implementation Plan + +- Docker-backed `clazy` analysis is planned. +- `clazy` report generation is planned. +- `clazy` validation alongside the existing `clang-tidy` analysis is planned. +- Analyzer cleanup for clear Qt API misuse is planned. +- Analyzer cleanup for unused locals, dead includes, redundant conditionals, and trivial temporary/container inefficiencies is planned. +- Docker base image digest pinning is planned. +- Additional dependency reduction checks for TLS, certificate handling, and module detection are planned before removing more runtime dependencies. +- Normal Docker browser build validation after analyzer cleanup is planned. +- Documentation updates must move completed points from this file to `docs/migration-status.md`. diff --git a/docs/qt5-static-poc.md b/docs/qt5-static-poc.md deleted file mode 100644 index ddd7465..0000000 --- a/docs/qt5-static-poc.md +++ /dev/null @@ -1,114 +0,0 @@ -# Qt5 Static Build POC - -## Objective -Build a reproducible static Qt5 toolchain for QtWeb migration on Linux `x86_64`. - -Target versions: -- Qt `5.15.17` -- QtWebKit `5.212.0-alpha4` - -This POC validates the toolchain pipeline and the QtWebKit smoke-build gate. -After rebuilding the browser, use `./run-browser.sh --check about:blank` from -the host to runtime-check the Docker-built browser. -Primary portability target: static linking plus minimal runtime dependencies. - -## Non-Goals -- Running the QtWeb browser UI or other runtime smoke tests on the agent. -- Windows/macOS support. -- Modifying legacy Qt4 flow in `build.sh`. -- Migrating the browser engine to Qt WebEngine. - -## Fixed Baseline -- Qt version is locked to `5.15.17`. -- QtWebKit version is locked to `5.212.0-alpha4`. -- Containerized build is required (`podman` or `docker`). -- ICU support is required for Qt5 + QtWebKit in this path. -- Outputs stay inside the repository (default: `artifacts/qt5-static-5.15.17`). - -## Inputs -- Wrapper script: `build-qt5-static.sh` -- In-container script: `toolchains/qt5-static/qt5-static-build-entrypoint.sh` -- Container definition: `toolchains/qt5-static/Dockerfile` -- Source lock and checksums: `toolchains/qt5-static/sources.lock` -- Optional patch hook: `toolchains/qt5-static/patches/*.patch` - -Supported source override env vars: -- `QT5_SRC_URL` -- `QT5_SRC_SHA256` -- `QT5_WEBKIT_SRC_URL` -- `QT5_WEBKIT_SHA256` - -Checksum policy: -1. Prefer `sha256`. -2. Allow `md5` fallback only when `sha256` is unavailable in locked metadata. -3. Abort immediately on mismatch. - -## Output Layout -Default build roots: `artifacts/qt5-static-5.15.17-release` and `artifacts/qt5-static-5.15.17-debug` - -- `artifacts/src-cache/`: shared downloaded archives for all build flavors -- `build/`: extracted/build tree -- `install/`: static Qt install prefix -- `logs/`: `configure.log`, `build.log`, `install.log`, `qtwebkit-configure.log`, `qtwebkit-build.log`, `qtwebkit-install.log`, `smoke-build.log`, `verify.log` -- `build-manifest.txt`: runtime, source URLs/checksums, configure flags, verification summary - -## Verification Gates -A successful run must satisfy: -1. `qmake -query QT_VERSION` is `5.15.17`. -2. Install is static (`QT_CONFIG` contains `static` or static libs prove it). -3. Required static libs exist in `install/lib`: - - `libQt5Core.a` - - `libQt5Gui.a` - - `libQt5Widgets.a` - - `libQt5Network.a` - - `libQt5Xml.a` - - `libQt5PrintSupport.a` - - `libQt5WebKit.a` - - `libQt5WebKitWidgets.a` -4. Required static ICU libs exist in the container image: - - `libicuuc.a` - - `libicui18n.a` - - `libicudata.a` -5. The QtWebKit smoke app compiles and links against the produced toolchain. -6. Verification log ends with `verification passed`. - -## Current Status -Implemented target behavior: -- Containerized build pipeline. -- Source lock + checksum verification. -- Static ICU from the container image. -- Static Qt build. -- Standalone QtWebKit build against installed Qt. -- Static Qt + QtWebKit library verification. -- Static ICU library verification. -- QtWebKit smoke test compile/link gate. -- Manifest/log generation. - -## Run Examples -Default run: -```bash -./build-qt5-static.sh -``` - -Clean rebuild: -```bash -./build-qt5-static.sh --clean -``` - -Custom output directory inside repo: -```bash -./build-qt5-static.sh --output-dir artifacts/qt5-static-poc-run1 -``` - -## Risks -- Legacy Qt/QtWebKit code may fail under newer host and container toolchains. -- Static QtWebKit can still require follow-up patches for newer compilers or linkers. -- Archive URLs may become unavailable over time. -- Over-aggressive dependency reduction can break TLS, certificate handling, or module detection. -- Runtime browser validation must use the host-side `run-browser.sh --check` - helper for the Docker-built browser. - -## Next Tasks -1. Build the main browser with `build-browser-docker.sh` against the produced toolchain. -2. Fix Qt `5.15.17` or QtWebKit `5.212` source incompatibilities exposed by that build. -3. Move the Docker base image from tag pinning to digest pinning when refreshed online. diff --git a/toolchains/qt5-static/common.sh b/toolchains/qt5-static/common.sh index 65ad078..045bbd5 100644 --- a/toolchains/qt5-static/common.sh +++ b/toolchains/qt5-static/common.sh @@ -1,5 +1,5 @@ QT_VERSION="5.15.17" -QT5_STATIC_IMAGE_TAG="qtweb-qt5-static-poc:${QT_VERSION}" +QT5_STATIC_IMAGE_TAG="qtweb-qt5-static:${QT_VERSION}" format_duration() { local total_seconds="$1" From 8b0111a30af7a7994cbe950599314ff6245d6154 Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Mon, 18 May 2026 13:44:53 +0200 Subject: [PATCH 16/24] Add Qt5 static CI workflow Build Qt5, QtWebKit, and QtWeb in separate GitHub Actions jobs with cache keys based on the static toolchain inputs. Publish Qt5 and QtWebKit toolchain release assets for tag builds. Keep CI smoke runtime checks disabled while preserving the build and shared dependency checks. Co-authored-by: Codex --- .github/workflows/qt5-static.yml | 246 +++++++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 .github/workflows/qt5-static.yml diff --git a/.github/workflows/qt5-static.yml b/.github/workflows/qt5-static.yml new file mode 100644 index 0000000..6a395ca --- /dev/null +++ b/.github/workflows/qt5-static.yml @@ -0,0 +1,246 @@ +name: Qt5 Static + +on: + push: + branches: + - "**" + tags: + - "**" + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +env: + BUILD_TYPE: release + QT_VERSION: 5.15.17 + QTWEBKIT_VERSION: "2022-09-07" + TOOLCHAIN_PLATFORM: ubuntu-20.04-x86_64 + +jobs: + qt5: + name: Build Qt5 static + runs-on: ubuntu-24.04 + timeout-minutes: 720 + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Check Qt version consistency + run: | + set -euo pipefail + + workflow_qt_version="${QT_VERSION}" + # shellcheck disable=SC1091 + source toolchains/qt5-static/common.sh + if [[ "${QT_VERSION}" != "${workflow_qt_version}" ]]; then + echo "error: workflow QT_VERSION=${workflow_qt_version} does not match common.sh QT_VERSION=${QT_VERSION}" >&2 + exit 1 + fi + + - name: Cache Qt5 build + id: qt5-cache + uses: actions/cache@v4 + with: + path: | + artifacts/qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}/install + artifacts/qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}/logs + artifacts/qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}/build-manifest.txt + key: qt5-static-${{ runner.os }}-${{ env.BUILD_TYPE }}-${{ hashFiles('toolchains/qt5-static/Dockerfile', 'toolchains/qt5-static/qt5-static-build-entrypoint.sh', 'toolchains/qt5-static/sources-qt.lock', 'toolchains/qt5-static/patches/qt/*.patch') }} + + - name: Cache source archives + if: steps.qt5-cache.outputs.cache-hit != 'true' + uses: actions/cache@v4 + with: + path: artifacts/src-cache + key: qt5-static-sources-${{ hashFiles('toolchains/qt5-static/sources.lock', 'toolchains/qt5-static/sources-qt.lock', 'toolchains/qt5-static/sources-qtwebkit.lock') }} + + - name: Build static Qt5 + if: steps.qt5-cache.outputs.cache-hit != 'true' + run: ./build-qt5-static.sh --runtime docker --qt-only + + qtwebkit: + name: Build QtWebKit + runs-on: ubuntu-24.04 + needs: qt5 + timeout-minutes: 720 + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Cache QtWebKit build + id: qtwebkit-cache + uses: actions/cache@v4 + with: + path: | + artifacts/qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}/install + artifacts/qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}/logs + artifacts/qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}/build-manifest.txt + key: qtwebkit-static-${{ runner.os }}-${{ env.BUILD_TYPE }}-${{ hashFiles('toolchains/qt5-static/Dockerfile', 'toolchains/qt5-static/qt5-static-build-entrypoint.sh', 'toolchains/qt5-static/sources-qt.lock', 'toolchains/qt5-static/patches/qt/*.patch', 'toolchains/qt5-static/sources-qtwebkit.lock', 'toolchains/qt5-static/patches/qtwebkit/*.patch') }} + + - name: Cache source archives + if: steps.qtwebkit-cache.outputs.cache-hit != 'true' + uses: actions/cache@v4 + with: + path: artifacts/src-cache + key: qt5-static-sources-${{ hashFiles('toolchains/qt5-static/sources.lock', 'toolchains/qt5-static/sources-qt.lock', 'toolchains/qt5-static/sources-qtwebkit.lock') }} + + - name: Restore Qt5 build + if: steps.qtwebkit-cache.outputs.cache-hit != 'true' + uses: actions/cache/restore@v4 + with: + path: | + artifacts/qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}/install + artifacts/qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}/logs + artifacts/qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}/build-manifest.txt + key: qt5-static-${{ runner.os }}-${{ env.BUILD_TYPE }}-${{ hashFiles('toolchains/qt5-static/Dockerfile', 'toolchains/qt5-static/qt5-static-build-entrypoint.sh', 'toolchains/qt5-static/sources-qt.lock', 'toolchains/qt5-static/patches/qt/*.patch') }} + + - name: Build CI container image + run: docker build -f toolchains/qt5-static/Dockerfile -t qtweb-qt5-static:${QT_VERSION} . + + - name: Build static QtWebKit + if: steps.qtwebkit-cache.outputs.cache-hit != 'true' + run: ./build-qt5-static.sh --runtime docker --qtwebkit-only + + - name: Build QtWebKit smoke test + run: ./smoke-tests/qtwebkit-smoke/smoke-build-docker.sh + + # - name: Smoke test QtWebKit app + # run: ./run-smoke.sh --check about:blank + + - name: Check QtWebKit shared dependencies + run: ldd ./smoke-tests/qtwebkit-smoke/build-docker-${BUILD_TYPE}/qtwebkit-smoke + + qtweb: + name: Build QtWeb + runs-on: ubuntu-24.04 + needs: qtwebkit + timeout-minutes: 120 + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Restore QtWebKit build + uses: actions/cache/restore@v4 + with: + path: | + artifacts/qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}/install + artifacts/qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}/logs + artifacts/qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}/build-manifest.txt + key: qtwebkit-static-${{ runner.os }}-${{ env.BUILD_TYPE }}-${{ hashFiles('toolchains/qt5-static/Dockerfile', 'toolchains/qt5-static/qt5-static-build-entrypoint.sh', 'toolchains/qt5-static/sources-qt.lock', 'toolchains/qt5-static/patches/qt/*.patch', 'toolchains/qt5-static/sources-qtwebkit.lock', 'toolchains/qt5-static/patches/qtwebkit/*.patch') }} + + - name: Build CI container image + run: docker build -f toolchains/qt5-static/Dockerfile -t qtweb-qt5-static:${QT_VERSION} . + + - name: Build QtWeb + run: ./build-browser-docker.sh + + # - name: Smoke test QtWeb + # run: ./run-browser.sh --check about:blank + + - name: Check QtWeb shared dependencies + run: ldd ./build-docker-${BUILD_TYPE}/QtWeb + + publish-qt-toolchain: + name: Publish Qt5 toolchain + runs-on: ubuntu-24.04 + needs: qt5 + if: startsWith(github.ref, 'refs/tags/') + permissions: + contents: write + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Restore Qt5 build + uses: actions/cache/restore@v4 + with: + path: | + artifacts/qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}/install + artifacts/qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}/logs + artifacts/qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}/build-manifest.txt + key: qt5-static-${{ runner.os }}-${{ env.BUILD_TYPE }}-${{ hashFiles('toolchains/qt5-static/Dockerfile', 'toolchains/qt5-static/qt5-static-build-entrypoint.sh', 'toolchains/qt5-static/sources-qt.lock', 'toolchains/qt5-static/patches/qt/*.patch') }} + + - name: Package Qt5 toolchain + run: | + set -euo pipefail + + toolchain_dir="artifacts/qt5-static-${QT_VERSION}-${BUILD_TYPE}" + asset="qt5-static-${QT_VERSION}-${BUILD_TYPE}-${TOOLCHAIN_PLATFORM}.tar.zst" + + test -d "${toolchain_dir}/install" + test -f "${toolchain_dir}/build-manifest.txt" + + tar --zstd -cf "${asset}" \ + -C "${toolchain_dir}" \ + install \ + build-manifest.txt + + - name: Upload release asset + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + + asset="qt5-static-${QT_VERSION}-${BUILD_TYPE}-${TOOLCHAIN_PLATFORM}.tar.zst" + + if ! gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1; then + gh release create "${GITHUB_REF_NAME}" \ + --title "${GITHUB_REF_NAME}" \ + --notes "Static Qt5 and QtWebKit toolchains." + fi + + gh release upload "${GITHUB_REF_NAME}" "${asset}" --clobber + + publish-qtwebkit-toolchain: + name: Publish QtWebKit toolchain + runs-on: ubuntu-24.04 + needs: + - qtwebkit + - publish-qt-toolchain + if: startsWith(github.ref, 'refs/tags/') + permissions: + contents: write + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Restore QtWebKit build + uses: actions/cache/restore@v4 + with: + path: | + artifacts/qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}/install + artifacts/qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}/logs + artifacts/qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}/build-manifest.txt + key: qtwebkit-static-${{ runner.os }}-${{ env.BUILD_TYPE }}-${{ hashFiles('toolchains/qt5-static/Dockerfile', 'toolchains/qt5-static/qt5-static-build-entrypoint.sh', 'toolchains/qt5-static/sources-qt.lock', 'toolchains/qt5-static/patches/qt/*.patch', 'toolchains/qt5-static/sources-qtwebkit.lock', 'toolchains/qt5-static/patches/qtwebkit/*.patch') }} + + - name: Package QtWebKit toolchain + run: | + set -euo pipefail + + toolchain_dir="artifacts/qt5-static-${QT_VERSION}-${BUILD_TYPE}" + asset="qt5-static-${QT_VERSION}-qtwebkit-${QTWEBKIT_VERSION}-${BUILD_TYPE}-${TOOLCHAIN_PLATFORM}.tar.zst" + + test -d "${toolchain_dir}/install" + test -f "${toolchain_dir}/build-manifest.txt" + + tar --zstd -cf "${asset}" \ + -C "${toolchain_dir}" \ + install \ + build-manifest.txt + + - name: Upload release asset + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + + asset="qt5-static-${QT_VERSION}-qtwebkit-${QTWEBKIT_VERSION}-${BUILD_TYPE}-${TOOLCHAIN_PLATFORM}.tar.zst" + + gh release upload "${GITHUB_REF_NAME}" "${asset}" --clobber From 0d90d055d2b11d08c66a3b21c2867374d2671a88 Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Mon, 18 May 2026 17:17:39 +0200 Subject: [PATCH 17/24] Publish Qt toolchains as workflow artifacts Upload Qt5 and QtWebKit toolchain tarballs as workflow artifacts on non-tag builds while keeping release uploads tag-only. Co-authored-by: Codex --- .github/workflows/qt5-static.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/qt5-static.yml b/.github/workflows/qt5-static.yml index 6a395ca..40518e0 100644 --- a/.github/workflows/qt5-static.yml +++ b/.github/workflows/qt5-static.yml @@ -149,7 +149,6 @@ jobs: name: Publish Qt5 toolchain runs-on: ubuntu-24.04 needs: qt5 - if: startsWith(github.ref, 'refs/tags/') permissions: contents: write @@ -181,7 +180,14 @@ jobs: install \ build-manifest.txt + - name: Upload workflow artifact + uses: actions/upload-artifact@v4 + with: + name: qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}-${{ env.TOOLCHAIN_PLATFORM }} + path: qt5-static-${{ env.QT_VERSION }}-${{ env.BUILD_TYPE }}-${{ env.TOOLCHAIN_PLATFORM }}.tar.zst + - name: Upload release asset + if: startsWith(github.ref, 'refs/tags/') env: GH_TOKEN: ${{ github.token }} run: | @@ -203,7 +209,6 @@ jobs: needs: - qtwebkit - publish-qt-toolchain - if: startsWith(github.ref, 'refs/tags/') permissions: contents: write @@ -235,7 +240,14 @@ jobs: install \ build-manifest.txt + - name: Upload workflow artifact + uses: actions/upload-artifact@v4 + with: + name: qt5-static-${{ env.QT_VERSION }}-qtwebkit-${{ env.QTWEBKIT_VERSION }}-${{ env.BUILD_TYPE }}-${{ env.TOOLCHAIN_PLATFORM }} + path: qt5-static-${{ env.QT_VERSION }}-qtwebkit-${{ env.QTWEBKIT_VERSION }}-${{ env.BUILD_TYPE }}-${{ env.TOOLCHAIN_PLATFORM }}.tar.zst + - name: Upload release asset + if: startsWith(github.ref, 'refs/tags/') env: GH_TOKEN: ${{ github.token }} run: | From 5de76b6b275d516d5a76cbd50cec198a6a449a2b Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Sun, 7 Jun 2026 00:39:06 +0200 Subject: [PATCH 18/24] Keep QtWeb ICU dependencies statically linked Remove the app-level qmake static CONFIG flag from the browser project. The Qt installation used by the Docker toolchain is already static, and its module metadata records ICU and harfbuzz-icu dependencies as absolute static archive paths. Leaving CONFIG+=static on the application caused qmake to rewrite some of those archive paths into generic -l flags in the generated browser link line. With the linker back in dynamic mode at that point, those names resolved to shared ICU and harfbuzz-icu libraries, adding runtime DT_NEEDED entries that the dependency checker correctly rejected. Let the static Qt module metadata drive the link line instead, matching the smoke test project and preserving the intended static ICU linkage. Co-authored-by: Codex --- src/QtWeb.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QtWeb.pro b/src/QtWeb.pro index e3d29c6..a8c05c9 100644 --- a/src/QtWeb.pro +++ b/src/QtWeb.pro @@ -1,7 +1,7 @@ TEMPLATE = app TARGET = QtWeb QT += network network-private xml webkitwidgets widgets printsupport -CONFIG += static c++11 +CONFIG += c++11 DEFINES += QT_NO_UITOOLS INCLUDEPATH += moc \ From eb8c64de802f697a36228ef2806438c5fd123312 Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Sun, 7 Jun 2026 00:39:14 +0200 Subject: [PATCH 19/24] Restore shared-deps CI checks and split runtime checks Make --check run only shared dependency validation so CI can use it without requiring Xvfb. Keep the old Xvfb-backed launch path available behind --runtime-check. Co-authored-by: Codex --- .github/workflows/qt5-static.yml | 12 +- README.md | 2 +- run-browser.sh | 78 +---------- run-smoke.sh | 80 ++--------- smoke-tests/qtwebkit-smoke/README.md | 5 +- toolchains/qt5-static/check-shared-deps.py | 155 +++++++++++++++++++++ toolchains/qt5-static/run-common.sh | 85 +++++++++++ 7 files changed, 265 insertions(+), 152 deletions(-) create mode 100755 toolchains/qt5-static/check-shared-deps.py create mode 100644 toolchains/qt5-static/run-common.sh diff --git a/.github/workflows/qt5-static.yml b/.github/workflows/qt5-static.yml index 40518e0..119bc16 100644 --- a/.github/workflows/qt5-static.yml +++ b/.github/workflows/qt5-static.yml @@ -108,11 +108,11 @@ jobs: - name: Build QtWebKit smoke test run: ./smoke-tests/qtwebkit-smoke/smoke-build-docker.sh - # - name: Smoke test QtWebKit app - # run: ./run-smoke.sh --check about:blank + # - name: Runtime test QtWebKit app + # run: ./run-smoke.sh --runtime-check about:blank - name: Check QtWebKit shared dependencies - run: ldd ./smoke-tests/qtwebkit-smoke/build-docker-${BUILD_TYPE}/qtwebkit-smoke + run: ./run-smoke.sh --check qtweb: name: Build QtWeb @@ -139,11 +139,11 @@ jobs: - name: Build QtWeb run: ./build-browser-docker.sh - # - name: Smoke test QtWeb - # run: ./run-browser.sh --check about:blank + # - name: Runtime test QtWeb + # run: ./run-browser.sh --runtime-check about:blank - name: Check QtWeb shared dependencies - run: ldd ./build-docker-${BUILD_TYPE}/QtWeb + run: ./run-browser.sh --check publish-qt-toolchain: name: Publish Qt5 toolchain diff --git a/README.md b/README.md index 35cff9d..43d8be1 100644 --- a/README.md +++ b/README.md @@ -3,4 +3,4 @@ QtWeb QtWeb Internet Browser -Build policy: do not use host-local or ad hoc builds for this repository. Use the repository helper scripts and containerized flows for build or validation work; if that path is unavailable, report validation as not run instead of falling back to local `qmake`/`make` commands. `./run-smoke.sh --check about:blank` is a valid host-side runtime check for an existing Docker-built smoke binary. After rebuilding the browser, `./run-browser.sh --check about:blank` is the valid host-side runtime check for the Docker-built browser. Agents may only use `run-smoke.sh` and `run-browser.sh` for runtime checks; directly launching the built `QtWeb` binary or other produced executables is prohibited. +Build policy: do not use host-local or ad hoc builds for this repository. Use the repository helper scripts and containerized flows for build or validation work; if that path is unavailable, report validation as not run instead of falling back to local `qmake`/`make` commands. `./run-smoke.sh --check` and `./run-browser.sh --check` validate shared dependencies for existing Docker-built binaries. `./run-smoke.sh --runtime-check about:blank` and `./run-browser.sh --runtime-check about:blank` are the host-side runtime checks. Agents may only use `run-smoke.sh` and `run-browser.sh` for runtime checks; directly launching the built `QtWeb` binary or other produced executables is prohibited. diff --git a/run-browser.sh b/run-browser.sh index 8ab9c3c..73610f6 100755 --- a/run-browser.sh +++ b/run-browser.sh @@ -2,76 +2,12 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="${SCRIPT_DIR}" -BUILD_TYPE="release" -RUN_WITH_GDB=0 -RUN_BUILD=0 -RUN_CHECK=0 -while [[ $# -gt 0 ]]; do - case "$1" in - --rebuild) - RUN_BUILD=1 - shift - ;; - --debug) - BUILD_TYPE="debug" - shift - ;; - --gdb) - RUN_WITH_GDB=1 - BUILD_TYPE="debug" - shift - ;; - --check) - RUN_CHECK=1 - shift - ;; - --) - shift - break - ;; - *) - break - ;; - esac -done +APP_LABEL="browser" +BUILD_SCRIPT="${REPO_ROOT}/build-browser-docker.sh" +BINARY_ROOT="${REPO_ROOT}" +BINARY_NAME="QtWeb" -case "${BUILD_TYPE}" in - release|debug) ;; - *) - echo "error: BUILD_TYPE must be release or debug, got: ${BUILD_TYPE}" >&2 - exit 1 - ;; -esac - -if [[ "${RUN_WITH_GDB}" -eq 1 && "${RUN_CHECK}" -eq 1 ]]; then - echo "error: --gdb cannot be used with --check" >&2 - exit 1 -fi - -BINARY="${SCRIPT_DIR}/build-docker-${BUILD_TYPE}/QtWeb" -if [[ "${RUN_BUILD}" -eq 1 ]]; then - if [[ "${BUILD_TYPE}" == "debug" ]]; then - "${SCRIPT_DIR}/build-browser-docker.sh" --debug - else - "${SCRIPT_DIR}/build-browser-docker.sh" - fi -elif [[ ! -x "${BINARY}" ]]; then - echo "error: browser binary not found: ${BINARY}" >&2 - echo "hint: rerun with --rebuild" >&2 - exit 1 -fi - -if [[ "${RUN_CHECK}" -eq 1 ]]; then - set +e - xvfb-run -a timeout 20s "${BINARY}" "$@" - status="$?" - set -e - if [[ "${status}" -ne 0 && "${status}" -ne 124 ]]; then - exit "${status}" - fi -elif [[ "${RUN_WITH_GDB}" -eq 1 ]]; then - exec gdb -ex run --args "${BINARY}" "$@" -else - exec "${BINARY}" "$@" -fi +# shellcheck disable=SC1090 +source "${REPO_ROOT}/toolchains/qt5-static/run-common.sh" diff --git a/run-smoke.sh b/run-smoke.sh index 86f8aed..269c044 100755 --- a/run-smoke.sh +++ b/run-smoke.sh @@ -2,77 +2,13 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -SMOKE_DIR="${SCRIPT_DIR}/smoke-tests/qtwebkit-smoke" +REPO_ROOT="${SCRIPT_DIR}" +SMOKE_DIR="${REPO_ROOT}/smoke-tests/qtwebkit-smoke" -BUILD_TYPE="release" -RUN_WITH_GDB=0 -RUN_BUILD=0 -RUN_CHECK=0 -while [[ $# -gt 0 ]]; do - case "$1" in - --rebuild) - RUN_BUILD=1 - shift - ;; - --debug) - BUILD_TYPE="debug" - shift - ;; - --gdb) - RUN_WITH_GDB=1 - BUILD_TYPE="debug" - shift - ;; - --check) - RUN_CHECK=1 - shift - ;; - --) - shift - break - ;; - *) - break - ;; - esac -done +APP_LABEL="smoke" +BUILD_SCRIPT="${SMOKE_DIR}/smoke-build-docker.sh" +BINARY_ROOT="${SMOKE_DIR}" +BINARY_NAME="qtwebkit-smoke" -case "${BUILD_TYPE}" in - release|debug) ;; - *) - echo "error: BUILD_TYPE must be release or debug, got: ${BUILD_TYPE}" >&2 - exit 1 - ;; -esac - -if [[ "${RUN_WITH_GDB}" -eq 1 && "${RUN_CHECK}" -eq 1 ]]; then - echo "error: --gdb cannot be used with --check" >&2 - exit 1 -fi - -BINARY="${SMOKE_DIR}/build-docker-${BUILD_TYPE}/qtwebkit-smoke" -if [[ "${RUN_BUILD}" -eq 1 ]]; then - if [[ "${BUILD_TYPE}" == "debug" ]]; then - "${SMOKE_DIR}/smoke-build-docker.sh" --debug - else - "${SMOKE_DIR}/smoke-build-docker.sh" - fi -elif [[ ! -x "${BINARY}" ]]; then - echo "error: smoke binary not found: ${BINARY}" >&2 - echo "hint: rerun with --rebuild" >&2 - exit 1 -fi - -if [[ "${RUN_CHECK}" -eq 1 ]]; then - set +e - xvfb-run -a timeout 20s "${BINARY}" "$@" - status="$?" - set -e - if [[ "${status}" -ne 0 && "${status}" -ne 124 ]]; then - exit "${status}" - fi -elif [[ "${RUN_WITH_GDB}" -eq 1 ]]; then - exec gdb -ex run --args "${BINARY}" "$@" -else - exec "${BINARY}" "$@" -fi +# shellcheck disable=SC1090 +source "${REPO_ROOT}/toolchains/qt5-static/run-common.sh" diff --git a/smoke-tests/qtwebkit-smoke/README.md b/smoke-tests/qtwebkit-smoke/README.md index c8d6ae5..d3b0296 100644 --- a/smoke-tests/qtwebkit-smoke/README.md +++ b/smoke-tests/qtwebkit-smoke/README.md @@ -39,11 +39,12 @@ After the Docker build has produced the smoke binary, run the headless check from the repository root on the host: ```bash -./run-smoke.sh --check about:blank +./run-smoke.sh --runtime-check about:blank ``` This uses `xvfb-run` on the host. It does not build inside the host -environment. +environment. To check the binary for unexpected shared dependencies instead, +run `./run-smoke.sh --check`. ## Notes diff --git a/toolchains/qt5-static/check-shared-deps.py b/toolchains/qt5-static/check-shared-deps.py new file mode 100755 index 0000000..3bca089 --- /dev/null +++ b/toolchains/qt5-static/check-shared-deps.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 +import sys + +sys.dont_write_bytecode = True + +import os +import re +import subprocess + + +ALLOWED_LIBRARIES = { + "ld-linux-x86-64.so.2", + "libatomic.so.1", + "libbsd.so.0", + "libc.so.6", + "libdl.so.2", + "libEGL.so.1", + "libbrotlicommon.so.1", + "libbrotlidec.so.1", + "libbz2.so.1", + "libfreetype.so.6", + "libgcc_s.so.1", + "libglib-2.0.so.0", + "libGL.so.1", + "libGLdispatch.so.0", + "libGLX.so.0", + "libgraphite2.so.3", + "libharfbuzz.so.0", + "libgthread-2.0.so.0", + "libICE.so.6", + "libm.so.6", + "libmd.so.0", + "libpcre.so.3", + "libpcre2-8.so.0", + "libpthread.so.0", + "libpng16.so.16", + "librt.so.1", + "libSM.so.6", + "libstdc++.so.6", + "libX11.so.6", + "libX11-xcb.so.1", + "libXau.so.6", + "libxcb.so.1", + "libxcb-icccm.so.4", + "libxcb-image.so.0", + "libxcb-keysyms.so.1", + "libxcb-randr.so.0", + "libxcb-render.so.0", + "libxcb-render-util.so.0", + "libxcb-shape.so.0", + "libxcb-shm.so.0", + "libxcb-sync.so.1", + "libxcb-util.so.1", + "libxcb-xfixes.so.0", + "libxcb-xinerama.so.0", + "libxcb-xkb.so.1", + "libXcomposite.so.1", + "libXcursor.so.1", + "libXdamage.so.1", + "libXdmcp.so.6", + "libXext.so.6", + "libXfixes.so.3", + "libXi.so.6", + "libxkbcommon.so.0", + "libxkbcommon-x11.so.0", + "libXrandr.so.2", + "libXrender.so.1", + "libz.so.1", + "linux-vdso.so.1", +} + + +LDD_ARROW_LINE_RE = re.compile(r"^\s*(\S+)\s+=>") +LDD_LOADER_LINE_RE = re.compile(r"^\s*/\S*/([^/\s]+)\s+\(") +LDD_DIRECT_LINE_RE = re.compile(r"^\s*(\S+)\s+\(") + + +def fail(message: str) -> None: + print(f"error: {message}", file=sys.stderr) + sys.exit(1) + + +def parse_library(line: str) -> str: + if "not found" in line: + return line.split(None, 1)[0] + + for pattern in (LDD_ARROW_LINE_RE, LDD_LOADER_LINE_RE, LDD_DIRECT_LINE_RE): + match = pattern.match(line) + if match: + return match.group(1) + + fail(f"could not parse ldd line: {line}") + + +def main() -> int: + if len(sys.argv) != 2: + fail(f"usage: {sys.argv[0]} ") + + binary = sys.argv[1] + if not os.path.isfile(binary) or not os.access(binary, os.X_OK): + fail(f"binary not found or not executable: {binary}") + + result = subprocess.run( + ["ldd", binary], + check=False, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + ) + print(result.stdout, end="") + + missing_libraries = [] + unexpected_libraries = [] + matched_allowed_libraries = set() + for line in result.stdout.splitlines(): + library = parse_library(line) + matching_allowed_libraries = { + allowed_library + for allowed_library in ALLOWED_LIBRARIES + if library.startswith(allowed_library) + } + matched_allowed_libraries.update(matching_allowed_libraries) + if "not found" in line: + missing_libraries.append(library) + elif not matching_allowed_libraries: + unexpected_libraries.append(library) + + failed = False + if missing_libraries: + print(f"error: missing shared dependencies for {binary}:", file=sys.stderr) + for library in sorted(set(missing_libraries)): + print(f" {library}", file=sys.stderr) + failed = True + + if unexpected_libraries: + print(f"error: unexpected shared dependencies for {binary}:", file=sys.stderr) + for library in sorted(set(unexpected_libraries)): + print(f" {library}", file=sys.stderr) + failed = True + + if failed: + return 1 + + unused_allowed_libraries = sorted(ALLOWED_LIBRARIES - matched_allowed_libraries) + if unused_allowed_libraries: + print(f"warning: allowed libraries not linked by {binary}:", file=sys.stderr) + for library in unused_allowed_libraries: + print(f" {library}", file=sys.stderr) + + print(f"shared dependencies allowed: {binary}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/toolchains/qt5-static/run-common.sh b/toolchains/qt5-static/run-common.sh new file mode 100644 index 0000000..ca343eb --- /dev/null +++ b/toolchains/qt5-static/run-common.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +BUILD_TYPE="release" +RUN_WITH_GDB=0 +RUN_BUILD=0 +RUN_CHECK=0 +RUN_RUNTIME_CHECK=0 +while [[ $# -gt 0 ]]; do + case "$1" in + --rebuild) + RUN_BUILD=1 + shift + ;; + --debug) + BUILD_TYPE="debug" + shift + ;; + --gdb) + RUN_WITH_GDB=1 + BUILD_TYPE="debug" + shift + ;; + --check) + RUN_CHECK=1 + shift + ;; + --runtime-check) + RUN_RUNTIME_CHECK=1 + shift + ;; + --) + shift + break + ;; + *) + break + ;; + esac +done + +case "${BUILD_TYPE}" in + release|debug) ;; + *) + echo "error: BUILD_TYPE must be release or debug, got: ${BUILD_TYPE}" >&2 + exit 1 + ;; +esac + +if [[ "${RUN_WITH_GDB}" -eq 1 && ( "${RUN_CHECK}" -eq 1 || "${RUN_RUNTIME_CHECK}" -eq 1 ) ]]; then + echo "error: --gdb cannot be used with --check or --runtime-check" >&2 + exit 1 +fi + +if [[ "${RUN_CHECK}" -eq 1 && "${RUN_RUNTIME_CHECK}" -eq 1 ]]; then + echo "error: --check cannot be used with --runtime-check" >&2 + exit 1 +fi + +BINARY="${BINARY_ROOT}/build-docker-${BUILD_TYPE}/${BINARY_NAME}" +if [[ "${RUN_BUILD}" -eq 1 ]]; then + if [[ "${BUILD_TYPE}" == "debug" ]]; then + "${BUILD_SCRIPT}" --debug + else + "${BUILD_SCRIPT}" + fi +elif [[ ! -x "${BINARY}" ]]; then + echo "error: ${APP_LABEL} binary not found: ${BINARY}" >&2 + echo "hint: rerun with --rebuild" >&2 + exit 1 +fi + +if [[ "${RUN_CHECK}" -eq 1 ]]; then + "${REPO_ROOT}/toolchains/qt5-static/check-shared-deps.py" "${BINARY}" +elif [[ "${RUN_RUNTIME_CHECK}" -eq 1 ]]; then + set +e + xvfb-run -a -s "-screen 0 1280x1024x24" timeout 20s "${BINARY}" "$@" + status="$?" + set -e + if [[ "${status}" -ne 0 && "${status}" -ne 124 ]]; then + exit "${status}" + fi +elif [[ "${RUN_WITH_GDB}" -eq 1 ]]; then + exec gdb -ex run --args "${BINARY}" "$@" +else + exec "${BINARY}" "$@" +fi From 9977969d559e94feece4498ad637eedf6de374fe Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Sat, 13 Jun 2026 16:54:28 +0200 Subject: [PATCH 20/24] Document static build validation flow Co-authored-by: Codex --- .clang-tidy | 1 + AGENTS.md | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index be60c44..0396b69 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,5 +1,6 @@ Checks: > -*, + clang-analyzer-*, bugprone-assignment-in-if-condition, bugprone-branch-clone, bugprone-copy-constructor-init, diff --git a/AGENTS.md b/AGENTS.md index 5057628..3b49240 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,9 +15,18 @@ - If that sanctioned path is unavailable, blocked, or out of scope for the task, state that validation could not be run. Do not fall back to a local build. - Do not launch the built `QtWeb` binary or other produced executables as an agent. - Do not run `run-smoke.sh` or start GUI/runtime validation on the user's behalf unless the user explicitly asks for that exact execution. -- Use `ldd ./smoke-tests/qtwebkit-smoke/build-docker-$(build-type)/qtwebkit-smoke` to check for remaining shared dependencies +- Use `./run-smoke.sh --check` and `./run-browser.sh --check` to check existing Docker-built binaries for remaining shared dependencies. - When a build succeeds, report the output path or the command the user can run; leave execution to the user unless explicitly requested. +## QtWeb Static Build Notes +- Shared Qt build defaults live in `toolchains/qt5-static/common.sh`: Qt `5.15.17`, image tag `qtweb-qt5-static:5.15.17`. +- Use `./build-qt5-static.sh --runtime docker --qt-only` for the static Qt stage and `./build-qt5-static.sh --runtime docker --qtwebkit-only` for the QtWebKit stage. +- Use `./build-browser-docker.sh` for the QtWeb browser stage; add `--analyze` only when clang-tidy analysis is explicitly requested. +- Use `./smoke-tests/qtwebkit-smoke/smoke-build-docker.sh` for the QtWebKit smoke-test build. +- Runtime checks are host-side wrappers and must only be run on explicit request: `./run-smoke.sh --runtime-check about:blank` or `./run-browser.sh --runtime-check about:blank`. +- The CI workflow is `.github/workflows/qt5-static.yml`; its main order is `qt5` -> `qtwebkit` -> `qtweb`, followed by publish jobs. +- For build failures, classify the first real error as configure-time, compile-time, link-time, runtime/smoke-test, CI resource exhaustion, or missing static dependency before editing scripts. + ## Documentation Policy - Keep `docs/migration-status.md` limited to behavior that is implemented in the repository. - Keep `docs/plan.md` limited to planned or pending work. From 5d3ba879336ecba8ababec6ea89c4c59d770f2f5 Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Sun, 14 Jun 2026 21:13:53 +0200 Subject: [PATCH 21/24] Add static Qt build runner instructions Add a dedicated .agents build runner for long static Qt 5 debug builds so the main agent can delegate monitored build execution without touching unrelated state. Document when to use that runner, record the expected local validation scope, and keep the .agents build runner configuration tracked despite the build-* ignore pattern. Co-authored-by: Codex --- .agents/build-static-qt5.toml | 38 +++++++++++++++++++++++++++++++++++ .gitignore | 1 + AGENTS.md | 4 ++++ 3 files changed, 43 insertions(+) create mode 100644 .agents/build-static-qt5.toml diff --git a/.agents/build-static-qt5.toml b/.agents/build-static-qt5.toml new file mode 100644 index 0000000..53d4232 --- /dev/null +++ b/.agents/build-static-qt5.toml @@ -0,0 +1,38 @@ +name = "build-static-qt5" +description = "Run and monitor the long static Qt 5 build, then report completion or failure." + +model = "gpt-5.4-mini" +model_reasoning_effort = "low" + +developer_instructions = """ +You are a narrow build runner for this repository. + +Your only job is to run the requested static Qt 5 helper flow. + +Allowed local commands are: +- ./build-qt5-static.sh --runtime docker --debug --clean +- ./build-qt5-static.sh --runtime docker --debug --qt-only --clean +- ./build-qt5-static.sh --runtime docker --debug --qtwebkit-only + +Use the full debug clean flow unless the caller explicitly asks for a scoped +Qt-only or QtWebKit-only build. Do not add release-build flags; release builds +are validated by CI. + +Monitor the command until it completes or fails. Do not edit files, refactor code, +inspect unrelated project state, or run unrelated commands. + +Use the repository's sanctioned helper-script flow only. Do not run host-local or +ad hoc qmake, make, cmake, ninja, compiler, or produced-binary commands. + +The clean debug Qt run is intentional when Qt patches changed: it avoids stale +generated Qt source trees. Do not combine --qtwebkit-only with --clean because +that scope requires an existing Qt install. + +When the build finishes, hand the result back to the top-level caller with: +- whether the build completed successfully or failed +- the exit status, if available +- the most relevant final output +- the first clear error message or failing step, if the build failed + +Keep the report concise and factual. +""" diff --git a/.gitignore b/.gitignore index 51688bc..052d04a 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ Makefile* build-* !build-browser-docker.sh !build-qt5-static.sh +!.agents/build-static-qt5.toml diff --git a/AGENTS.md b/AGENTS.md index 3b49240..430de37 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,6 +12,7 @@ - Do not run host-local or ad hoc builds in this repository. - Do not invoke `qmake`, `make`, `cmake`, `ninja`, or compiler commands directly on the host for validation or debugging. - Use the repository's sanctioned helper-script flows instead, such as `build-browser-docker.sh`, `build-qt5-static.sh`, and `run-smoke.sh`, when a build or runtime validation is explicitly required. +- For any `build-qt5-static.sh` request, including short requests like "clean rebuild", use the `.agents/build-static-qt5.toml` subagent instead of running the long build directly in the main agent. - If that sanctioned path is unavailable, blocked, or out of scope for the task, state that validation could not be run. Do not fall back to a local build. - Do not launch the built `QtWeb` binary or other produced executables as an agent. - Do not run `run-smoke.sh` or start GUI/runtime validation on the user's behalf unless the user explicitly asks for that exact execution. @@ -20,6 +21,9 @@ ## QtWeb Static Build Notes - Shared Qt build defaults live in `toolchains/qt5-static/common.sh`: Qt `5.15.17`, image tag `qtweb-qt5-static:5.15.17`. +- Static-linking fixes must be applied in the Qt or QtWebKit build itself, such as configure inputs, source patches, or checked-in container-side build scripts. This keeps future Qt/QtWebKit upgrades honest: patches should fail early and be rebased deliberately instead of relying on post-build metadata rewrites or other broken hacks. +- For local validation, check only debug builds to save time; release builds are validated by CI. +- Use the `.agents/build-static-qt5.toml` subagent when running full or scoped `./build-qt5-static.sh` flows so long builds are monitored without unrelated edits or commands. The default clean rebuild command is `./build-qt5-static.sh --runtime docker --debug --clean`. - Use `./build-qt5-static.sh --runtime docker --qt-only` for the static Qt stage and `./build-qt5-static.sh --runtime docker --qtwebkit-only` for the QtWebKit stage. - Use `./build-browser-docker.sh` for the QtWeb browser stage; add `--analyze` only when clang-tidy analysis is explicitly requested. - Use `./smoke-tests/qtwebkit-smoke/smoke-build-docker.sh` for the QtWebKit smoke-test build. From a75e13eb22ca749633b9eb0d212ba7cbb0759cbf Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Sun, 14 Jun 2026 21:14:11 +0200 Subject: [PATCH 22/24] Import Qt plugins for static Unix builds Disable qmake's automatic plugin import path for static Unix builds and list the Qt platform, image format, and bearer plugins required by the browser and QtWebKit smoke-test targets. Add matching staticplugins.cpp import units for both targets so static builds pull in the required plugin symbols explicitly. Co-authored-by: Codex --- smoke-tests/qtwebkit-smoke/qtwebkit-smoke.pro | 2 ++ src/QtWeb.pro | 2 ++ src/staticplugins.cpp | 14 ++++++++++++++ src/staticplugins.pri | 16 ++++++++++++++++ 4 files changed, 34 insertions(+) create mode 100644 src/staticplugins.cpp create mode 100644 src/staticplugins.pri diff --git a/smoke-tests/qtwebkit-smoke/qtwebkit-smoke.pro b/smoke-tests/qtwebkit-smoke/qtwebkit-smoke.pro index 0234f86..b3a3aef 100644 --- a/smoke-tests/qtwebkit-smoke/qtwebkit-smoke.pro +++ b/smoke-tests/qtwebkit-smoke/qtwebkit-smoke.pro @@ -6,3 +6,5 @@ QT += core gui widgets network webkit webkitwidgets CONFIG += c++11 SOURCES += main.cpp + +include(../../src/staticplugins.pri) diff --git a/src/QtWeb.pro b/src/QtWeb.pro index a8c05c9..ff5b383 100644 --- a/src/QtWeb.pro +++ b/src/QtWeb.pro @@ -4,6 +4,8 @@ QT += network network-private xml webkitwidgets widgets printsupport CONFIG += c++11 DEFINES += QT_NO_UITOOLS +include(staticplugins.pri) + INCLUDEPATH += moc \ rcc \ uic \ diff --git a/src/staticplugins.cpp b/src/staticplugins.cpp new file mode 100644 index 0000000..0b06f54 --- /dev/null +++ b/src/staticplugins.cpp @@ -0,0 +1,14 @@ +#include + +Q_IMPORT_PLUGIN(QXcbIntegrationPlugin) +Q_IMPORT_PLUGIN(QXcbEglIntegrationPlugin) +Q_IMPORT_PLUGIN(QXcbGlxIntegrationPlugin) +Q_IMPORT_PLUGIN(QGifPlugin) +Q_IMPORT_PLUGIN(QICNSPlugin) +Q_IMPORT_PLUGIN(QICOPlugin) +Q_IMPORT_PLUGIN(QJpegPlugin) +Q_IMPORT_PLUGIN(QTgaPlugin) +Q_IMPORT_PLUGIN(QTiffPlugin) +Q_IMPORT_PLUGIN(QWbmpPlugin) +Q_IMPORT_PLUGIN(QWebpPlugin) +Q_IMPORT_PLUGIN(QGenericEnginePlugin) diff --git a/src/staticplugins.pri b/src/staticplugins.pri new file mode 100644 index 0000000..9e9daa1 --- /dev/null +++ b/src/staticplugins.pri @@ -0,0 +1,16 @@ +static:unix { + CONFIG -= import_plugins + QTPLUGIN += qxcb \ + qxcb-egl-integration \ + qxcb-glx-integration \ + qgif \ + qicns \ + qico \ + qjpeg \ + qtga \ + qtiff \ + qwbmp \ + qwebp \ + qgenericbearer + SOURCES += $$PWD/staticplugins.cpp +} From 9a64c991e14a91b68190d1a8cb34a8d8eded886a Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Sun, 14 Jun 2026 21:14:27 +0200 Subject: [PATCH 23/24] Refine static build dependency checks Print the raw ldd output separately from the dependency check summary so captured logs show both the observed linker state and the interpreted result. Treat missing libraries from the allowed shared-dependency list as warnings, while still failing for missing or linked libraries outside that list. This keeps checks useful on hosts that do not have every allowed runtime library installed. Lower the QtWebKit build job cap from 16 to 12 to reduce resource pressure during static builds. Co-authored-by: Codex --- toolchains/qt5-static/check-shared-deps.py | 32 +++++++++++++------ .../qt5-static/qt5-static-build-entrypoint.sh | 4 +-- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/toolchains/qt5-static/check-shared-deps.py b/toolchains/qt5-static/check-shared-deps.py index 3bca089..8c066bc 100755 --- a/toolchains/qt5-static/check-shared-deps.py +++ b/toolchains/qt5-static/check-shared-deps.py @@ -107,9 +107,13 @@ def main() -> int: stderr=subprocess.STDOUT, text=True, ) + print(f"==> ldd output: {binary}") print(result.stdout, end="") + print() + print(f"==> dependency check: {binary}") - missing_libraries = [] + missing_allowed_libraries = [] + missing_unexpected_libraries = [] unexpected_libraries = [] matched_allowed_libraries = set() for line in result.stdout.splitlines(): @@ -121,31 +125,39 @@ def main() -> int: } matched_allowed_libraries.update(matching_allowed_libraries) if "not found" in line: - missing_libraries.append(library) + if matching_allowed_libraries: + missing_allowed_libraries.append(library) + else: + missing_unexpected_libraries.append(library) elif not matching_allowed_libraries: unexpected_libraries.append(library) failed = False - if missing_libraries: - print(f"error: missing shared dependencies for {binary}:", file=sys.stderr) - for library in sorted(set(missing_libraries)): - print(f" {library}", file=sys.stderr) + if missing_unexpected_libraries: + print(f"error: missing shared dependencies for {binary}:") + for library in sorted(set(missing_unexpected_libraries)): + print(f" {library}") failed = True if unexpected_libraries: - print(f"error: unexpected shared dependencies for {binary}:", file=sys.stderr) + print(f"error: unexpected shared dependencies for {binary}:") for library in sorted(set(unexpected_libraries)): - print(f" {library}", file=sys.stderr) + print(f" {library}") failed = True if failed: return 1 + if missing_allowed_libraries: + print(f"warning: allowed shared dependencies not installed on check host for {binary}:") + for library in sorted(set(missing_allowed_libraries)): + print(f" {library}") + unused_allowed_libraries = sorted(ALLOWED_LIBRARIES - matched_allowed_libraries) if unused_allowed_libraries: - print(f"warning: allowed libraries not linked by {binary}:", file=sys.stderr) + print(f"warning: allowed libraries not linked by {binary}:") for library in unused_allowed_libraries: - print(f" {library}", file=sys.stderr) + print(f" {library}") print(f"shared dependencies allowed: {binary}") return 0 diff --git a/toolchains/qt5-static/qt5-static-build-entrypoint.sh b/toolchains/qt5-static/qt5-static-build-entrypoint.sh index c2ae5b2..8b7ded6 100755 --- a/toolchains/qt5-static/qt5-static-build-entrypoint.sh +++ b/toolchains/qt5-static/qt5-static-build-entrypoint.sh @@ -8,8 +8,8 @@ set -euo pipefail JOBS="${JOBS:-$(nproc 2>/dev/null || echo 8)}" QTWEBKIT_JOBS="$JOBS" -if (( QTWEBKIT_JOBS > 16 )); then - QTWEBKIT_JOBS=16 +if (( QTWEBKIT_JOBS > 12 )); then + QTWEBKIT_JOBS=12 fi CLEAN="${CLEAN:-false}" BUILD_TYPE="${BUILD_TYPE:-release}" From c6da8502100da3ca6a0bd64ae4ad303c2e8bc13c Mon Sep 17 00:00:00 2001 From: Sergei Lopatin Date: Fri, 3 Jul 2026 21:28:58 +0200 Subject: [PATCH 24/24] Extend plan with Qt API cleanup and Qt6 scope Add planned items for removing deprecated Qt API usage (QRegExp, QString::SkipEmptyParts, QDesktopWidget, qrand, Q_ENUMS, Q_FOREACH, string-based signal/slot connections), reviewing the QTextCodec encoding paths and the remaining QFtp download path, and constrain Qt6 planning to a QtWebKit-preserving migration with a compatibility review of the QWebView/QWebPage browser surface. Co-Authored-By: Claude --- docs/plan.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/plan.md b/docs/plan.md index fe1c017..846564b 100644 --- a/docs/plan.md +++ b/docs/plan.md @@ -5,6 +5,11 @@ - `clazy` validation alongside the existing `clang-tidy` analysis is planned. - Analyzer cleanup for clear Qt API misuse is planned. - Analyzer cleanup for unused locals, dead includes, redundant conditionals, and trivial temporary/container inefficiencies is planned. +- Removal of deprecated Qt API usage is planned, including `QRegExp`, `QString::SkipEmptyParts`, `QDesktopWidget`/`QApplication::desktop()`, `qrand()`/`qsrand()`, `Q_ENUMS`, `Q_FOREACH`/`foreach`, and legacy string-based `SIGNAL`/`SLOT` connections. +- Review of `QTextCodec`-based page/source encoding paths is planned before Qt6 migration work. +- Removal or replacement of the remaining `QFtp` download path is planned. +- Qt6 migration planning is constrained to a QtWebKit-preserving path; no QtWebKit code removal or Qt WebEngine replacement is planned. +- QtWebKit compatibility review is planned for the browser surface that currently depends on `QWebView`, `QWebPage`, `QWebFrame`, `QWebSettings`, `QWebHistoryInterface`, `QWebHitTestResult`, and `QWebHistory`. - Docker base image digest pinning is planned. - Additional dependency reduction checks for TLS, certificate handling, and module detection are planned before removing more runtime dependencies. - Normal Docker browser build validation after analyzer cleanup is planned.