aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@qt.io>2024-03-01 12:18:19 +0100
committerChristian Kandeler <christian.kandeler@qt.io>2024-03-01 12:18:19 +0100
commitff13b8d47d36b87c2a0f305f4a0ab452b7889f6d (patch)
tree3ded6c202c7a413fbd511514920e48668a4099c5
parentf5a29eee3465e935523bef41bfc014054ce663c7 (diff)
parent75aca0dca12c6c94109e65ee035b6b533b33a3c5 (diff)
Merge 2.3 into master
-rw-r--r--.clang-tidy6
-rw-r--r--.github/workflows/main.yml40
-rw-r--r--doc/config/macros.qdocconf2
-rw-r--r--doc/reference/modules/exporter-cmake.qdoc135
-rw-r--r--docker-compose.yml11
-rw-r--r--docker/focal/Dockerfile117
-rwxr-xr-xdocker/focal/entrypoint.sh96
-rw-r--r--examples/exporters/lib_a/lib_a.qbs5
-rw-r--r--examples/exporters/qbs/imports/MyLibrary.qbs7
-rwxr-xr-xscripts/run-analyzer.sh4
-rw-r--r--share/qbs/modules/Exporter/cmake/cmakeexporter.js239
-rw-r--r--share/qbs/modules/Exporter/cmake/cmakeexporter.qbs84
-rw-r--r--src/app/qbs/session.cpp9
-rw-r--r--src/lib/corelib/api/jobs.cpp2
-rw-r--r--src/lib/corelib/api/project.cpp10
-rw-r--r--src/lib/corelib/api/projectdata.cpp2
-rw-r--r--src/lib/corelib/api/runenvironment.cpp8
-rw-r--r--src/lib/corelib/buildgraph/inputartifactscanner.cpp11
-rw-r--r--src/lib/corelib/buildgraph/nodetreedumper.cpp2
-rw-r--r--src/lib/corelib/jsextensions/utilitiesextension.cpp8
-rw-r--r--src/lib/corelib/language/builtindeclarations.cpp17
-rw-r--r--src/lib/corelib/language/item.cpp9
-rw-r--r--src/lib/corelib/language/qualifiedid.cpp2
-rw-r--r--src/lib/corelib/language/scriptengine.cpp4
-rw-r--r--src/lib/corelib/loader/astpropertiesitemhandler.cpp5
-rw-r--r--src/lib/corelib/loader/dependenciesresolver.cpp6
-rw-r--r--src/lib/corelib/loader/loaderutils.cpp4
-rw-r--r--src/lib/corelib/loader/moduleproviderloader.cpp1
-rw-r--r--src/lib/corelib/logging/logger.cpp2
-rw-r--r--src/lib/corelib/parser/qmljslexer.cpp6
-rw-r--r--src/lib/corelib/tools/clangclinfo.cpp2
-rw-r--r--src/lib/corelib/tools/profiling.cpp2
-rw-r--r--src/lib/corelib/tools/scripttools.cpp2
-rw-r--r--src/lib/corelib/tools/settingsmodel.cpp8
-rw-r--r--src/lib/pkgconfig/pcparser.cpp14
-rw-r--r--src/plugins/scanner/cpp/Lexer.cpp2
-rw-r--r--src/shared/quickjs/.clang-tidy12
-rw-r--r--tests/auto/blackbox/testdata/exports-cmake/Foo.cpp5
-rw-r--r--tests/auto/blackbox/testdata/exports-cmake/Foo.h16
-rw-r--r--tests/auto/blackbox/testdata/exports-cmake/cmake/CMakeLists.txt7
-rw-r--r--tests/auto/blackbox/testdata/exports-cmake/cmake/main.cpp6
-rw-r--r--tests/auto/blackbox/testdata/exports-cmake/exports-cmake.qbs70
-rw-r--r--tests/auto/blackbox/testdata/exports-cmake/find-cmake.qbs46
-rw-r--r--tests/auto/blackbox/tst_blackbox.cpp80
-rw-r--r--tests/auto/blackbox/tst_blackbox.h2
45 files changed, 800 insertions, 328 deletions
diff --git a/.clang-tidy b/.clang-tidy
index e737372e9..92e6eeefe 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -2,6 +2,7 @@
Checks: >
-*,
bugprone-*,
+ -bugprone-easily-swappable-parameters,
-bugprone-narrowing-conversions,
-bugprone-throw-keyword-missing,
cppcoreguidelines-interfaces-global-init,
@@ -12,7 +13,7 @@ Checks: >
google-build-namespaces,
google-global-names-in-headers,
google-objc-*,
- google-readability-casting,
+ -google-readability-casting,
google-readability-namespace-comments,
google-runtime-operator,
misc-definitions-in-headers,
@@ -70,6 +71,3 @@ WarningsAsErrors: >
HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
-CheckOptions:
-...
-
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 6ccd36047..20e936d8d 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -16,18 +16,6 @@ jobs:
matrix:
config:
- {
- name: 'Build on Linux (gcc)',
- image: 'focal-qt6',
- options: 'modules.cpp.compilerWrapper:ccache
- modules.qbs.debugInformation:true
- modules.qbsbuildconfig.enableBundledQt:true
- products.qbs_archive.targetName:qbs-linux-${{ github.run_id }}
- products.qbs_archive.includeTests:true',
- script: './scripts/build-qbs-with-qbs.sh',
- cacheid: 'gcc-qt6',
- suffix: 'linux',
- }
- - {
name: 'Build on Linux (Jammy, gcc)',
image: 'jammy-qt6',
options: 'modules.cpp.compilerWrapper:ccache
@@ -80,19 +68,19 @@ jobs:
- {
name: 'Build on Linux (clang_tidy)',
script: './scripts/run-analyzer.sh',
- image: 'focal-qt6',
+ image: 'jammy-qt6',
options: 'profile:qt-clang_64 modules.cpp.compilerWrapper:ccache',
cacheid: 'clang',
}
- {
name: 'Build on Linux (CMake)',
script: './scripts/build-qbs-with-cmake.sh',
- image: 'focal-qt6',
+ image: 'jammy-qt6',
cacheid: 'cmake',
}
- {
name: 'Build on Linux (gcc, ASAN)',
- image: 'focal-qt6',
+ image: 'jammy-qt6',
script: './scripts/build-qbs-with-qbs.sh',
options: 'modules.cpp.compilerWrapper:ccache
modules.qbsbuildconfig.enableAddressSanitizer:true
@@ -102,7 +90,7 @@ jobs:
}
- {
name: 'Build on Linux (gcc, UBSAN)',
- image: 'focal-qt6',
+ image: 'jammy-qt6',
script: './scripts/build-qbs-with-qbs.sh',
options: 'modules.cpp.compilerWrapper:ccache
modules.qbsbuildconfig.enableUbSanitizer:true
@@ -367,7 +355,7 @@ jobs:
- {
name: 'Run Linux tests (gcc, Qt 5)',
image: 'jammy-qt5',
- suffix: 'linux',
+ suffix: 'linux-jammy',
profile: 'qt-gcc_64',
script: './scripts/test-qt.sh',
}
@@ -381,49 +369,49 @@ jobs:
- {
name: 'Run Android tests (Qt 5.15)',
image: 'jammy-android-515',
- suffix: 'linux',
+ suffix: 'linux-jammy',
profile: '',
script: './scripts/test-qt-for-android.sh',
}
- {
name: 'Run Android tests (Qt 6.2)',
image: 'jammy-android-62',
- suffix: 'linux',
+ suffix: 'linux-jammy',
profile: '',
script: './scripts/test-qt-for-android.sh',
}
- {
name: 'Run Android tests (Qt 6.5)',
image: 'jammy-android-65',
- suffix: 'linux',
+ suffix: 'linux-jammy',
profile: '',
script: './scripts/test-qt-for-android.sh',
}
- {
name: 'Run Android tests (ndk r19c)',
image: 'jammy-android-ndk-r19c',
- suffix: 'linux',
+ suffix: 'linux-jammy',
profile: '',
script: './scripts/test-for-android.sh',
}
- {
name: 'Run Android tests (ndk r21e)',
image: 'jammy-android-ndk-r21e',
- suffix: 'linux',
+ suffix: 'linux-jammy',
profile: '',
script: './scripts/test-for-android.sh',
}
- {
name: 'Run Android tests (ndk r23)',
image: 'jammy-android-ndk-r23',
- suffix: 'linux',
+ suffix: 'linux-jammy',
profile: '',
script: './scripts/test-for-android.sh',
}
- {
name: 'Run Linux tests (Qt 4.8.7)',
image: 'jammy-qt4',
- suffix: 'linux',
+ suffix: 'linux-jammy',
profile: '',
script: './scripts/test-qt4.sh',
}
@@ -458,10 +446,10 @@ jobs:
- name: Download artifact
uses: actions/download-artifact@v1
with:
- name: qbs-linux-${{ github.run_id }}.tar.gz
+ name: qbs-linux-jammy-${{ github.run_id }}.tar.gz
path: ./
- name: Unpack artifact
- run: mkdir -p release/install-root/ && tar xzf qbs-linux-${{ github.run_id }}.tar.gz -C release/install-root/
+ run: mkdir -p release/install-root/ && tar xzf qbs-linux-jammy-${{ github.run_id }}.tar.gz -C release/install-root/
- name: Pull the Docker Image
run: docker-compose pull jammy-baremetal
- name: arm-none-eabi-gcc-10_3
diff --git a/doc/config/macros.qdocconf b/doc/config/macros.qdocconf
index 6811215c0..31b9b9a8d 100644
--- a/doc/config/macros.qdocconf
+++ b/doc/config/macros.qdocconf
@@ -51,6 +51,8 @@ macro.endfloat.HTML = "</div>"
macro.clearfloat.HTML = "<br style=\"clear: both\" />"
macro.emptyspan.HTML = "<span></span>"
+macro.CMAKE = "CMake"
+
# Embed YouTube content by video ID - Example: \youtube dQw4w9WgXcQ
# Also requires a <ID>.jpg thumbnail for offline docs. In .qdocconf, add:
#
diff --git a/doc/reference/modules/exporter-cmake.qdoc b/doc/reference/modules/exporter-cmake.qdoc
new file mode 100644
index 000000000..2f4191a76
--- /dev/null
+++ b/doc/reference/modules/exporter-cmake.qdoc
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2024 Raphael Cotty (raphael.cotty@gmail.com)
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \qmltype Exporter.cmake
+ \inqmlmodule QbsModules
+ \since Qbs 2.3
+
+ \brief Provides support for generating \CMAKE packages from dynamic, static and header library
+ products.
+
+ The Exporter.cmake module contains the properties and rules to create a \CMAKE config
+ \l{https://cmake.org/cmake/help/v3.29/manual/cmake-packages.7.html#config-file-packages}{files}
+ from the \l Export item of a \l Product.
+
+ For instance, suppose you are creating a library. To allow exporting to \CMAKE, you would write
+ something like the following:
+ \code
+ DynamicLibrary {
+ name: "mylibrary"
+ qbs.installPrefix: "/opt/mylibrary"
+ Depends { name: "Exporter.cmake" }
+ Exporter.cmake.packageName: "MyLibrary"
+ property string headersInstallDir: "include"
+ // ...
+ Group {
+ name: "API headers"
+ files: ["mylib.h"]
+ qbs.install: true
+ qbs.installDir: headersInstallDir
+ }
+ Group {
+ fileTagsFilter: ["Exporter.cmake.package"]
+ qbs.installDir: "lib/cmake/MyLibrary"
+ }
+ Export {
+ Depends { name: "cpp" }
+ cpp.includePaths: FileInfo.joinPaths(
+ exportingProduct.qbs.installRoot,
+ exportingProduct.qbs.installPrefix,
+ exportingProduct.headersInstallDir)
+ }
+ }
+ \endcode
+ To build against this library, from within your \CMAKE project, you simply
+ use \l{https://cmake.org/cmake/help/v3.29/command/find_package.html}{find_package}:
+ \code
+ find_package(MyLibrary PATHS REQUIRED)
+ add_executable(Consumer main.cpp)
+ target_link_libraries(Consumer MyLibrary)
+ \endcode
+
+ \section2 Relevant File Tags
+ \target filetags-exporter-qbs
+
+ \table
+ \header
+ \li Tag
+ \li Since
+ \li Description
+ \row
+ \li \c{"Exporter.cmake.package"}
+ \li 2.3.0
+ \li This tag is attached to all generated module files.
+ \row
+ \li \c{"Exporter.cmake.configFile"}
+ \li 2.3.0
+ \li This tag is attached to the generated config file.
+ \row
+ \li \c{"Exporter.cmake.versionFile"}
+ \li 2.3.0
+ \li This tag is attached to the generated version file.
+ \endtable
+*/
+
+/*!
+ \qmlproperty string Exporter.cmake::configFileName
+
+ The name of the generated config file.
+
+ \defaultvalue \c{packageName + "Config.cmake"}
+*/
+
+/*!
+ \qmlproperty string Exporter.cmake::versionFileName
+
+ The name of the generated version file.
+
+ \defaultvalue \c{packageName + "ConfigVersion.cmake"}
+*/
+
+/*!
+ \qmlproperty string Exporter.cmake::packageName
+
+ The name of the \CMAKE package.
+
+ \defaultvalue \l{Product::targetName}{Product.targetName}
+*/
+
diff --git a/docker-compose.yml b/docker-compose.yml
index 27d334647..d852cc5e6 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -54,17 +54,6 @@ services:
QT_VERSION: 6.5.0
QTCREATOR_VERSION: 11.0.3
- focal-qt6:
- << : *linux
- hostname: focal-qt6
- image: ${DOCKER_USER:-qbsbuild}/qbsdev:focal-qt6-6.5.0_1.24.1-0
- build:
- dockerfile: docker/focal/Dockerfile
- context: .
- args:
- QT_VERSION: 6.5.0
- QTCREATOR_VERSION: 9.0.2
-
jammy-android-515:
<< : *linux
hostname: jammy-android
diff --git a/docker/focal/Dockerfile b/docker/focal/Dockerfile
deleted file mode 100644
index 917d4d0a7..000000000
--- a/docker/focal/Dockerfile
+++ /dev/null
@@ -1,117 +0,0 @@
-#
-# Install Qt and Qbs for Linux
-#
-FROM ubuntu:focal
-LABEL Description="Ubuntu development environment for Qbs with Qt and various dependencies for testing Qbs modules and functionality"
-ARG QT_VERSION
-ARG QTCREATOR_VERSION
-
-# Allow colored output on command line.
-ENV TERM=xterm-color
-
-#
-# Make it possible to change UID/GID in the entrypoint script. The docker
-# container usually runs as root user on Linux hosts. When the Docker container
-# mounts a folder on the host and creates files there, those files would be
-# owned by root instead of the current user. Thus we create a user here who's
-# UID will be changed in the entrypoint script to match the UID of the current
-# host user.
-#
-ARG USER_UID=1000
-ARG USER_NAME=devel
-RUN apt-get update -qq && \
- apt-get install -qq -y \
- ca-certificates \
- gosu \
- sudo && \
- groupadd -g ${USER_UID} ${USER_NAME} && \
- useradd -s /bin/bash -u ${USER_UID} -g ${USER_NAME} -o -c "" -m ${USER_NAME} && \
- usermod -a -G sudo ${USER_NAME} && \
- echo "%devel ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers
-
-COPY docker/focal/entrypoint.sh /sbin/entrypoint.sh
-ENTRYPOINT ["/sbin/entrypoint.sh"]
-
-# Qbs build dependencies
-RUN apt-get update -qq && \
- DEBIAN_FRONTEND="noninteractive" apt-get install -qq -y --no-install-recommends \
- bison \
- build-essential \
- ca-certificates \
- capnproto \
- ccache \
- clang-12 \
- clang-tidy-12 \
- cmake \
- curl \
- flex \
- git \
- help2man \
- icoutils \
- libcapnp-dev \
- libdbus-1-3 \
- libfreetype6 \
- libfontconfig1 \
- libgl1-mesa-dev \
- libgl1-mesa-glx \
- libnanopb-dev \
- libprotobuf-dev \
- libgrpc++-dev \
- libxkbcommon-x11-0 \
- locales \
- nanopb \
- ninja-build \
- nsis \
- pkg-config \
- protobuf-compiler \
- protobuf-compiler-grpc \
- psmisc \
- python3-pip \
- python3-setuptools \
- p7zip-full \
- subversion \
- unzip \
- zip && \
- update-alternatives --install /usr/bin/clang clang /usr/bin/clang-12 100 && \
- update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-12 100 && \
- update-alternatives --install /usr/bin/clang-check clang-check /usr/bin/clang-check-12 100 && \
- update-alternatives --install /usr/bin/python python /usr/bin/python3 100 && \
- pip install beautifulsoup4 lxml protobuf==3.19.1 pyyaml
-
-# Set the locale
-RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \
- locale-gen
-ENV LANG en_US.UTF-8
-ENV LANGUAGE en_US:en
-ENV LC_ALL en_US.UTF-8
-
-ENV LLVM_INSTALL_DIR=/usr/lib/llvm-12
-
-
-#
-# Install Qt and Qbs for Linux from qt.io
-#
-COPY scripts/install-qt.sh install-qt.sh
-
-RUN ./install-qt.sh --version ${QT_VERSION} qtbase qtdeclarative qttools qtx11extras qtscxml qt5compat icu && \
- ./install-qt.sh --version ${QTCREATOR_VERSION} qtcreator && \
- echo "export PATH=/opt/Qt/${QT_VERSION}/gcc_64/bin:/opt/Qt/Tools/QtCreator/bin:\${PATH}" > /etc/profile.d/qt.sh
-
-ENV PATH=/opt/Qt/${QT_VERSION}/gcc_64/bin:/opt/Qt/Tools/QtCreator/bin:${PATH}
-
-
-# Configure Qbs
-USER $USER_NAME
-RUN qbs-setup-toolchains /usr/bin/g++ gcc && \
- qbs-setup-toolchains /usr/bin/clang clang && \
- qbs-setup-qt /opt/Qt/${QT_VERSION}/gcc_64/bin/qmake qt-gcc_64 && \
- qbs config profiles.qt-gcc_64.baseProfile gcc && \
- qbs-setup-qt /opt/Qt/${QT_VERSION}/gcc_64/bin/qmake qt-clang_64 && \
- qbs config profiles.qt-clang_64.baseProfile clang && \
- qbs config defaultProfile qt-gcc_64
-
-# Switch back to root user for the entrypoint script.
-USER root
-
-# Work-around for QTBUG-79020
-RUN echo "export QT_NO_GLIB=1" >> /etc/profile.d/qt.sh
diff --git a/docker/focal/entrypoint.sh b/docker/focal/entrypoint.sh
deleted file mode 100755
index 40bc5acb9..000000000
--- a/docker/focal/entrypoint.sh
+++ /dev/null
@@ -1,96 +0,0 @@
-#!/usr/bin/env bash
-set -e
-
-#############################################################################
-##
-## Copyright (C) 2019 Richard Weickelt <richard@weickelt.de>
-## Contact: https://www.qt.io/licensing/
-##
-## This file is part of Qbs.
-##
-## $QT_BEGIN_LICENSE:LGPL$
-## Commercial License Usage
-## Licensees holding valid commercial Qt licenses may use this file in
-## accordance with the commercial license agreement provided with the
-## Software or, alternatively, in accordance with the terms contained in
-## a written agreement between you and The Qt Company. For licensing terms
-## and conditions see https://www.qt.io/terms-conditions. For further
-## information use the contact form at https://www.qt.io/contact-us.
-##
-## GNU Lesser General Public License Usage
-## Alternatively, this file may be used under the terms of the GNU Lesser
-## General Public License version 3 as published by the Free Software
-## Foundation and appearing in the file LICENSE.LGPL3 included in the
-## packaging of this file. Please review the following information to
-## ensure the GNU Lesser General Public License version 3 requirements
-## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-##
-## GNU General Public License Usage
-## Alternatively, this file may be used under the terms of the GNU
-## General Public License version 2.0 or (at your option) the GNU General
-## Public license version 3 or any later version approved by the KDE Free
-## Qt Foundation. The licenses are as published by the Free Software
-## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-## included in the packaging of this file. Please review the following
-## information to ensure the GNU General Public License requirements will
-## be met: https://www.gnu.org/licenses/gpl-2.0.html and
-## https://www.gnu.org/licenses/gpl-3.0.html.
-##
-## $QT_END_LICENSE$
-##
-#############################################################################
-
-#
-# Entrypoint script when starting the container. The script checks the current
-# working directory and changes the uid/gid of developer/users to match whatever
-# is found in the working directory. This is useful to match the user and group
-# of mounted volumes into the container
-
-#
-# If not root, re-run script as root to fix ids
-#
-if [ "$(id -u)" != "0" ]; then
- exec gosu root /sbin/entrypoint.sh "$@"
-fi
-
-#
-# Try to determine the uid of the working directory and adjust the current
-# user's uid/gid accordingly.
-#
-USER_GID=${USER_GID:-$(stat -c "%g" .)}
-USER_UID=${USER_UID:-$(stat -c "%u" .)}
-USER_NAME=${USER_NAME:-devel}
-USER_GROUP=${USER_GROUP:-devel}
-EXEC=""
-export HOME=/home/${USER_NAME}
-
-#
-# This is a problem on Linux hosts when we mount a folder from the
-# user file system and write artifacts into that. Thus, we downgrade
-# the current user and make sure that the uid and gid matches the one
-# of the mounted project folder.
-#
-# This work-around is not needed on Windows hosts as Windows doesn't
-# have such a concept.
-#
-if [ "${USER_UID}" != "0" ]; then
- if [ "$(id -u ${USER_NAME})" != "${USER_UID}" ]; then
- usermod -o -u ${USER_UID} ${USER_NAME}
- # After changing the user's uid, all files in user's home directory
- # automatically get the new uid.
- fi
- current_gid=$(id -g ${USER_NAME})
- if [ "$(id -g ${USER_NAME})" != "${USER_GID}" ]; then
- groupmod -o -g ${USER_GID} ${USER_GROUP}
- # Set the new gid on all files in the home directory that still have the
- # old gid.
- find /home/${USER_NAME} -gid "${current_gid}" ! -type l -exec chgrp ${USER_GID} {} \;
- fi
-fi
-EXEC="exec gosu ${USER_NAME}:${USER_GROUP}"
-
-if [ -z "$1" ]; then
- ${EXEC} bash -l
-else
- ${EXEC} bash -l -c "$*"
-fi
diff --git a/examples/exporters/lib_a/lib_a.qbs b/examples/exporters/lib_a/lib_a.qbs
index f058318e4..fedbb7074 100644
--- a/examples/exporters/lib_a/lib_a.qbs
+++ b/examples/exporters/lib_a/lib_a.qbs
@@ -58,5 +58,10 @@ MyLibrary {
qbs.install: true
qbs.installDir: headersInstallDir
}
+ Export {
+ Depends { name: "cpp" }
+ cpp.dynamicLibraries: "z"
+ cpp.libraryPaths: "/opt/local/lib"
+ }
}
diff --git a/examples/exporters/qbs/imports/MyLibrary.qbs b/examples/exporters/qbs/imports/MyLibrary.qbs
index 3dcfb2796..4607776b3 100644
--- a/examples/exporters/qbs/imports/MyLibrary.qbs
+++ b/examples/exporters/qbs/imports/MyLibrary.qbs
@@ -83,6 +83,13 @@ StaticLibrary {
qbs.installDir: FileInfo.joinPaths(installDir, "pkgconfig")
}
+ Depends { name: "Exporter.cmake" }
+ Group {
+ fileTagsFilter: ["Exporter.cmake.package"]
+ qbs.install: install
+ qbs.installDir: FileInfo.joinPaths(installDir, "cmake", product.name)
+ }
+
Depends { name: 'bundle' }
bundle.isBundle: false
}
diff --git a/scripts/run-analyzer.sh b/scripts/run-analyzer.sh
index a410e8b4c..9e53e50dd 100755
--- a/scripts/run-analyzer.sh
+++ b/scripts/run-analyzer.sh
@@ -45,12 +45,12 @@ LLVM_INSTALL_DIR=${LLVM_INSTALL_DIR:-""}
# update-alternatives --install /usr/bin/run-clang-tidy.py run-clang-tidy.py /usr/bin/run-clang-tidy-4.0.py 1
CLANG_TIDY=`which clang-tidy`
-RUN_CLANG_TIDY=`which run-clang-tidy.py`
+RUN_CLANG_TIDY=`which run-clang-tidy`
if [ -z "$RUN_CLANG_TIDY" ] || [ -z "$CLANG_TIDY" ]; then
if [ ! -z "$LLVM_INSTALL_DIR" ]; then
CLANG_TIDY="$LLVM_INSTALL_DIR/bin/clang-tidy"
- RUN_CLANG_TIDY="$LLVM_INSTALL_DIR/share/clang/run-clang-tidy.py"
+ RUN_CLANG_TIDY="$LLVM_INSTALL_DIR/bin/run-clang-tidy"
else
echo "Can't find clang-tidy and/or run-clang-tidy.py in PATH, try setting LLVM_INSTALL_DIR"
exit 1
diff --git a/share/qbs/modules/Exporter/cmake/cmakeexporter.js b/share/qbs/modules/Exporter/cmake/cmakeexporter.js
new file mode 100644
index 000000000..093032f2e
--- /dev/null
+++ b/share/qbs/modules/Exporter/cmake/cmakeexporter.js
@@ -0,0 +1,239 @@
+/****************************************************************************
+**
+** Copyright (C) 2024 Raphaël Cotty <raphael.cotty@gmail.com>
+** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of the Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+var FileInfo = require("qbs.FileInfo");
+var ModUtils = require("qbs.ModUtils");
+var ExporterHelpers = require("../exporter.js");
+
+function tagListToString(tagList)
+{
+ return JSON.stringify(tagList);
+}
+
+function collectAutodetectedData(project, topLevelProduct, outputs)
+{
+ var packageName = topLevelProduct.Exporter.cmake.packageName;
+
+ var data = {};
+ data.packageName = packageName;
+ data.installPrefixDir = "_" + packageName.toUpperCase() + "_INSTALL_PREFIX";
+ data.packages = [];
+
+ function quote(value)
+ {
+ return "\"" + value + "\"";
+ }
+
+ function quoteAndPrefixify(propName)
+ {
+ function quoteAndPrefixifyHelper(value) {
+ var prefixToStrip =
+ ExporterHelpers.getPrefixToStrip(project, topLevelProduct, propName, value);
+ if (typeof value !== "string"
+ || !prefixToStrip
+ || (value.length > prefixToStrip.length
+ && value[prefixToStrip.length] !== '/')) {
+ return quote(value);
+ }
+ return quote("${" + data.installPrefixDir + "}" + value.slice(prefixToStrip.length));
+ }
+ return quoteAndPrefixifyHelper;
+ }
+
+ var installedOutputFilePath = ModUtils.artifactInstalledFilePath(
+ outputs["Exporter.cmake.configFile"][0]);
+ var installedOutputPathName = FileInfo.path(installedOutputFilePath);
+
+ var installRootPath = FileInfo.joinPaths(topLevelProduct.qbs.installRoot, topLevelProduct.qbs.installPrefix);
+ data.installPrefix = FileInfo.relativePath(installedOutputPathName, installRootPath);
+
+ var libArtifacts;
+ var libImportArtifacts;
+ var isProduct = !topLevelProduct.present;
+ var considerFramework = !isProduct || (topLevelProduct.type
+ && topLevelProduct.type.includes("bundle.content"))
+ && topLevelProduct.bundle
+ && topLevelProduct.bundle.isBundle
+ && topLevelProduct.qbs.targetOS.includes("darwin");
+ var considerDynamicLibs = !isProduct || (topLevelProduct.type
+ && topLevelProduct.type.includes("dynamiclibrary"));
+ var considerStaticLibs = !isProduct || (topLevelProduct.type
+ && topLevelProduct.type.includes("staticlibrary"));
+ if (considerFramework) {
+ libArtifacts = topLevelProduct.artifacts["bundle.symlink.executable"];
+ if (considerDynamicLibs)
+ data.type = "SHARED";
+ else if (considerStaticLibs)
+ data.type = "STATIC";
+ else
+ data.type = "INTERFACE";
+ } else if (considerDynamicLibs) {
+ libArtifacts = topLevelProduct.artifacts.dynamiclibrary;
+ libImportArtifacts = topLevelProduct.artifacts.dynamiclibrary_import;
+ data.type = "SHARED";
+ } else if (considerStaticLibs) {
+ libArtifacts = topLevelProduct.artifacts.staticlibrary;
+ data.type = "STATIC";
+ } else {
+ data.type = "INTERFACE";
+ }
+
+ for (var i = 0; i < (libArtifacts || []).length; ++i) {
+ var libArtifact = libArtifacts[i];
+ var libImportArtifact = (libImportArtifacts || [])[i];
+ if (libArtifact.qbs.install) {
+ var installPath = ModUtils.artifactInstalledFilePath(libArtifact);
+ data.importedLocation = quoteAndPrefixify("installRoot")(installPath);
+ data.soName = topLevelProduct.targetName;
+ if (libImportArtifact && libImportArtifact.qbs.install) {
+ installPath = ModUtils.artifactInstalledFilePath(libImportArtifact);
+ data.importedImplibLocation = quoteAndPrefixify("installRoot")(installPath);
+ }
+ break;
+ }
+ }
+ var cpp = topLevelProduct.exports.cpp;
+ if (cpp) {
+ data.libraryPaths = (cpp.libraryPaths || []).map(quoteAndPrefixify("cpp.libraryPaths"));
+
+ data.linkLibraries = [];
+ data.linkLibraries = data.linkLibraries.concat(cpp.dynamicLibraries || []);
+ data.linkLibraries = data.linkLibraries.concat(cpp.staticLibraries || []);
+ data.linkLibraries = data.linkLibraries.map(quoteAndPrefixify("cpp.dynamicLibraries"));
+
+ data.linkOptions = [];
+ data.linkOptions = data.linkOptions.concat(cpp.driverLinkerFlags || []);
+ if ((cpp.linkerFlags || []).length > 0) {
+ data.linkOptions =
+ data.linkOptions.concat("LINKER:" + (cpp.linkerFlags || []).join(","));
+ }
+ data.linkOptions = data.linkOptions.map(quote);
+
+ data.includeDirectories =
+ (cpp.includePaths || []).map(quoteAndPrefixify("cpp.includePaths"));
+ data.compileDefinitions = (cpp.defines || []).map(quote);
+
+ data.compileOptions = [];
+ data.compileOptions = data.compileOptions.concat(cpp.commonCompilerFlags || []);
+ data.compileOptions = data.compileOptions.concat(cpp.driverFlags || []);
+ data.compileOptions = data.compileOptions.concat(cpp.cxxFlags || []);
+ data.compileOptions = data.compileOptions.concat(cpp.cFlags || []);
+ data.compileOptions = data.compileOptions.map(quote);
+ }
+
+ function gatherDeps(dep) {
+ if (dep.name === "Exporter.cmake")
+ return;
+ var depHasExporter = dep.Exporter && dep.Exporter.cmake;
+ if (!depHasExporter)
+ return;
+ data.packages.push(dep.Exporter.cmake.packageName);
+ }
+
+ var exportedDeps = topLevelProduct.exports ? topLevelProduct.exports.dependencies : [];
+ exportedDeps.forEach(gatherDeps);
+
+ return data;
+}
+
+function writeConfigFile(project, product, outputs)
+{
+ var autoDetectedData = collectAutodetectedData(project, product, outputs);
+ var packageName = autoDetectedData.packageName;
+
+ function writeCommand(command, lines)
+ {
+ if ((lines || []).length === 0)
+ return;
+ cmakeConfigFile.writeLine(command + "(" + packageName + " INTERFACE");
+ for (i = 0; i < lines.length; i++) {
+ cmakeConfigFile.writeLine(" " + lines[i]);
+ }
+ cmakeConfigFile.writeLine(")");
+ }
+
+ var cmakeConfigFile = new TextFile(outputs["Exporter.cmake.configFile"][0].filePath,
+ TextFile.WriteOnly);
+ cmakeConfigFile.writeLine("# Generated by Qbs");
+
+ cmakeConfigFile.writeLine("cmake_minimum_required(VERSION 3.5)");
+
+ cmakeConfigFile.writeLine("if(TARGET " + packageName + ")");
+ cmakeConfigFile.writeLine(" return()");
+ cmakeConfigFile.writeLine("endif()");
+
+ cmakeConfigFile.writeLine("set(" + autoDetectedData.installPrefixDir +
+ " \"${CMAKE_CURRENT_LIST_DIR}/" +
+ autoDetectedData.installPrefix + "\")");
+
+ autoDetectedData.packages.forEach(function(packageName) {
+ cmakeConfigFile.writeLine("find_package(" + packageName + " REQUIRED SILENT)");
+ });
+ cmakeConfigFile.writeLine(
+ "add_library(" + packageName + " " + autoDetectedData.type + " IMPORTED)");
+ var configuration = (product.qbs.buildVariant) ?
+ product.qbs.buildVariant.toUpperCase() : "NONE";
+ cmakeConfigFile.writeLine("set_property(TARGET " + packageName +
+ " APPEND PROPERTY IMPORTED_CONFIGURATIONS " +
+ configuration + ")");
+
+ cmakeConfigFile.writeLine("set_target_properties(" + packageName + " PROPERTIES");
+ cmakeConfigFile.writeLine(" IMPORTED_LINK_INTERFACE_LANGUAGES_" + configuration +
+ " CXX");
+ if (autoDetectedData.type !== "INTERFACE") {
+ cmakeConfigFile.writeLine(" IMPORTED_LOCATION_" + configuration + " " +
+ autoDetectedData.importedLocation);
+ }
+ if (autoDetectedData.importedImplibLocation) {
+ cmakeConfigFile.writeLine(" IMPORTED_IMPLIB_" + configuration + " " +
+ autoDetectedData.importedImplibLocation);
+ }
+ cmakeConfigFile.writeLine(")");
+
+ writeCommand("target_link_directories", autoDetectedData.libraryPaths);
+ writeCommand("target_link_libraries",
+ autoDetectedData.linkLibraries.concat(autoDetectedData.packages));
+ writeCommand("target_link_options", autoDetectedData.linkOptions);
+ writeCommand("target_include_directories", autoDetectedData.includeDirectories);
+ writeCommand("target_compile_definitions", autoDetectedData.compileDefinitions);
+ writeCommand("target_compile_options", autoDetectedData.compileOptions);
+
+ cmakeConfigFile.close();
+}
+
+function writeVersionFile(product, outputs)
+{
+ var cmakeVersionFile = new TextFile(
+ outputs["Exporter.cmake.versionFile"][0].filePath, TextFile.WriteOnly);
+ cmakeVersionFile.writeLine("# Generated by Qbs");
+ cmakeVersionFile.writeLine("set(PACKAGE_VERSION \"" + product.version + "\")");
+ cmakeVersionFile.close();
+}
diff --git a/share/qbs/modules/Exporter/cmake/cmakeexporter.qbs b/share/qbs/modules/Exporter/cmake/cmakeexporter.qbs
new file mode 100644
index 000000000..a578e938b
--- /dev/null
+++ b/share/qbs/modules/Exporter/cmake/cmakeexporter.qbs
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2024 Raphaël Cotty <raphael.cotty@gmail.com>
+** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import qbs.File
+import qbs.FileInfo
+import qbs.ModUtils
+import qbs.TextFile
+
+import "cmakeexporter.js" as HelperFunctions
+
+Module {
+ property string configFileName: packageName + "Config.cmake"
+ property string versionFileName: packageName + "ConfigVersion.cmake"
+ property string packageName: product.targetName
+
+ additionalProductTypes: ["Exporter.cmake.package"]
+
+ Rule {
+ multiplex: true
+ requiresInputs: false
+
+ auxiliaryInputs: {
+ if (product.type.includes("staticlibrary"))
+ return ["staticlibrary"];
+ if (product.type.includes("dynamiclibrary"))
+ return ["dynamiclibrary"];
+ }
+
+ Artifact {
+ filePath: product.Exporter.cmake.configFileName
+ fileTags: ["Exporter.cmake.package", "Exporter.cmake.configFile"]
+ }
+ Artifact {
+ filePath: product.Exporter.cmake.versionFileName
+ fileTags: ["Exporter.cmake.package", "Exporter.cmake.versionFile"]
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generate cmake package files";
+ cmd.sourceCode = function() {
+ HelperFunctions.writeConfigFile(project, product, outputs);
+ HelperFunctions.writeVersionFile(product, outputs);
+ }
+ return [cmd];
+ }
+ }
+}
diff --git a/src/app/qbs/session.cpp b/src/app/qbs/session.cpp
index ebc9015b2..2cdcf2b63 100644
--- a/src/app/qbs/session.cpp
+++ b/src/app/qbs/session.cpp
@@ -623,10 +623,11 @@ Session::ProductSelection Session::getProductSelection(const QJsonObject &reques
{
const QJsonValue productSelection = request.value(StringConstants::productsKey());
if (productSelection.isArray())
- return ProductSelection(getProductsByName(fromJson<QStringList>(productSelection)));
- return ProductSelection(productSelection.toString() == QLatin1String("all")
- ? Project::ProductSelectionWithNonDefault
- : Project::ProductSelectionDefaultOnly);
+ return {getProductsByName(fromJson<QStringList>(productSelection))};
+ return {
+ productSelection.toString() == QLatin1String("all")
+ ? Project::ProductSelectionWithNonDefault
+ : Project::ProductSelectionDefaultOnly};
}
Session::FileUpdateData Session::prepareFileUpdate(const QJsonObject &request)
diff --git a/src/lib/corelib/api/jobs.cpp b/src/lib/corelib/api/jobs.cpp
index 7a845b0ac..10c96bfee 100644
--- a/src/lib/corelib/api/jobs.cpp
+++ b/src/lib/corelib/api/jobs.cpp
@@ -231,7 +231,7 @@ Project SetupProjectJob::project() const
{
auto const wrapper = qobject_cast<const InternalJobThreadWrapper *>(internalJob());
auto const job = qobject_cast<const InternalSetupProjectJob *>(wrapper->synchronousJob());
- return Project(job->project(), job->logger());
+ return {job->project(), job->logger()};
}
void SetupProjectJob::resolve(const Project &existingProject,
diff --git a/src/lib/corelib/api/project.cpp b/src/lib/corelib/api/project.cpp
index 0588b822c..53c711b49 100644
--- a/src/lib/corelib/api/project.cpp
+++ b/src/lib/corelib/api/project.cpp
@@ -797,8 +797,14 @@ RunEnvironment Project::getRunEnvironment(const ProductData &product,
const QStringList &setupRunEnvConfig, Settings *settings) const
{
const ResolvedProductPtr resolvedProduct = d->internalProduct(product);
- return RunEnvironment(resolvedProduct, d->internalProject, installOptions, environment,
- setupRunEnvConfig, settings, d->logger);
+ return {
+ resolvedProduct,
+ d->internalProject,
+ installOptions,
+ environment,
+ setupRunEnvConfig,
+ settings,
+ d->logger};
}
/*!
diff --git a/src/lib/corelib/api/projectdata.cpp b/src/lib/corelib/api/projectdata.cpp
index 34e679d6d..628fe2a5d 100644
--- a/src/lib/corelib/api/projectdata.cpp
+++ b/src/lib/corelib/api/projectdata.cpp
@@ -75,7 +75,7 @@ static QVariant getModuleProperty(const PropertyMap &properties, const QString &
{
const int lastDotIndex = fullPropertyName.lastIndexOf(QLatin1Char('.'));
if (lastDotIndex == -1)
- return QVariant();
+ return {};
return properties.getModuleProperty(fullPropertyName.left(lastDotIndex),
fullPropertyName.mid(lastDotIndex + 1));
}
diff --git a/src/lib/corelib/api/runenvironment.cpp b/src/lib/corelib/api/runenvironment.cpp
index adf0c4557..23d0359b0 100644
--- a/src/lib/corelib/api/runenvironment.cpp
+++ b/src/lib/corelib/api/runenvironment.cpp
@@ -363,16 +363,16 @@ int RunEnvironment::doRunTarget(const QString &targetBin, const QStringList &arg
<< arguments;
}
} else {
- if (QFileInfo(targetExecutable = findExecutable(QStringList()
- << QStringLiteral("iostool"))).isExecutable()) {
+ if (targetExecutable = findExecutable(QStringList{QStringLiteral("iostool")});
+ QFileInfo(targetExecutable).isExecutable()) {
targetArguments = QStringList()
<< QStringLiteral("-run")
<< QStringLiteral("-bundle")
<< QDir::cleanPath(bundlePath);
if (!arguments.empty())
targetArguments << QStringLiteral("-extra-args") << arguments;
- } else if (QFileInfo(targetExecutable = findExecutable(QStringList()
- << QStringLiteral("ios-deploy"))).isExecutable()) {
+ } else if (targetExecutable = findExecutable(QStringList{QStringLiteral("ios-deploy")});
+ QFileInfo(targetExecutable).isExecutable()) {
targetArguments = QStringList()
<< QStringLiteral("--no-wifi")
<< QStringLiteral("--noninteractive")
diff --git a/src/lib/corelib/buildgraph/inputartifactscanner.cpp b/src/lib/corelib/buildgraph/inputartifactscanner.cpp
index fb582c457..0c73f599f 100644
--- a/src/lib/corelib/buildgraph/inputartifactscanner.cpp
+++ b/src/lib/corelib/buildgraph/inputartifactscanner.cpp
@@ -103,9 +103,14 @@ static void resolveDepencency(const RawScannedDependency &dependency,
}
// prioritize found artifacts
- if ((result->file = dependencyInProduct)
- || (result->file = dependencyInOtherProduct)
- || (result->file = fileDependencyArtifact)) {
+ if (dependencyInProduct)
+ result->file = dependencyInProduct;
+ else if (dependencyInOtherProduct)
+ result->file = dependencyInOtherProduct;
+ else
+ result->file = fileDependencyArtifact;
+
+ if (result->file) {
result->filePath = result->file->filePath();
if (result->file == dependencyInOtherProduct && !productOfDependencyIsDependency) {
diff --git a/src/lib/corelib/buildgraph/nodetreedumper.cpp b/src/lib/corelib/buildgraph/nodetreedumper.cpp
index 8475a46cf..6ad597c70 100644
--- a/src/lib/corelib/buildgraph/nodetreedumper.cpp
+++ b/src/lib/corelib/buildgraph/nodetreedumper.cpp
@@ -120,7 +120,7 @@ bool NodeTreeDumper::doVisit(BuildGraphNode *node, const QString &nodeRepr)
QByteArray NodeTreeDumper::indentation() const
{
- return QByteArray(m_indentation, ' ');
+ return {m_indentation, ' '};
}
} // namespace Internal
diff --git a/src/lib/corelib/jsextensions/utilitiesextension.cpp b/src/lib/corelib/jsextensions/utilitiesextension.cpp
index e733d618b..cdcee59fa 100644
--- a/src/lib/corelib/jsextensions/utilitiesextension.cpp
+++ b/src/lib/corelib/jsextensions/utilitiesextension.cpp
@@ -782,7 +782,7 @@ static QStringList detectMachOArchs(QIODevice *device)
if (strncmp(ar_header, ARMAG, SARMAG) == 0) {
while (!device->atEnd()) {
static_assert(sizeof(ar_hdr) == 60, "sizeof(ar_hdr) != 60");
- ar_hdr header;
+ ar_hdr header{};
if (device->read(reinterpret_cast<char *>(&header),
sizeof(ar_hdr)) != sizeof(ar_hdr))
return {};
@@ -832,7 +832,7 @@ static QStringList detectMachOArchs(QIODevice *device)
pos = device->pos();
- fat_header fatheader;
+ fat_header fatheader{};
fatheader.magic = readInt(device, nullptr, false);
if (fatheader.magic == FAT_MAGIC || fatheader.magic == FAT_CIGAM ||
fatheader.magic == FAT_MAGIC_64 || fatheader.magic == FAT_CIGAM_64) {
@@ -845,7 +845,7 @@ static QStringList detectMachOArchs(QIODevice *device)
QStringList archs;
for (uint32_t n = 0; n < fatheader.nfat_arch; ++n) {
- fat_arch_64 fatarch;
+ fat_arch_64 fatarch{};
static_assert(sizeof(fat_arch_64) == 32, "sizeof(fat_arch_64) != 32");
static_assert(sizeof(fat_arch) == 20, "sizeof(fat_arch) != 20");
const qint64 expectedBytes = is64bit ? sizeof(fat_arch_64) : sizeof(fat_arch);
@@ -875,7 +875,7 @@ static QStringList detectMachOArchs(QIODevice *device)
return {};
bool swap = false;
- mach_header header;
+ mach_header header{};
header.magic = readInt(device, nullptr, swap);
switch (header.magic) {
case MH_CIGAM:
diff --git a/src/lib/corelib/language/builtindeclarations.cpp b/src/lib/corelib/language/builtindeclarations.cpp
index 4a83279a8..491b005e8 100644
--- a/src/lib/corelib/language/builtindeclarations.cpp
+++ b/src/lib/corelib/language/builtindeclarations.cpp
@@ -166,25 +166,28 @@ void BuiltinDeclarations::insert(const ItemDeclaration &decl)
static PropertyDeclaration conditionProperty()
{
- return PropertyDeclaration(StringConstants::conditionProperty(), PropertyDeclaration::Boolean,
- StringConstants::trueValue());
+ return {
+ StringConstants::conditionProperty(),
+ PropertyDeclaration::Boolean,
+ StringConstants::trueValue()};
}
static PropertyDeclaration alwaysRunProperty()
{
- return PropertyDeclaration(StringConstants::alwaysRunProperty(), PropertyDeclaration::Boolean,
- StringConstants::falseValue());
+ return {
+ StringConstants::alwaysRunProperty(),
+ PropertyDeclaration::Boolean,
+ StringConstants::falseValue()};
}
static PropertyDeclaration nameProperty()
{
- return PropertyDeclaration(StringConstants::nameProperty(), PropertyDeclaration::String);
+ return {StringConstants::nameProperty(), PropertyDeclaration::String};
}
static PropertyDeclaration buildDirProperty()
{
- return PropertyDeclaration(StringConstants::buildDirectoryProperty(),
- PropertyDeclaration::Path);
+ return {StringConstants::buildDirectoryProperty(), PropertyDeclaration::Path};
}
static PropertyDeclaration prepareScriptProperty()
diff --git a/src/lib/corelib/language/item.cpp b/src/lib/corelib/language/item.cpp
index 29fa1417d..e5de8f195 100644
--- a/src/lib/corelib/language/item.cpp
+++ b/src/lib/corelib/language/item.cpp
@@ -142,7 +142,8 @@ ValuePtr Item::property(const QString &name) const
ValuePtr value;
const Item *item = this;
do {
- if ((value = item->m_properties.value(name)))
+ value = item->m_properties.value(name);
+ if (value)
break;
item = item->m_prototype;
} while (item);
@@ -172,7 +173,7 @@ ItemValuePtr Item::itemProperty(const QString &name, const Item *itemTemplate,
if (v && v->type() == Value::ItemValueType)
return std::static_pointer_cast<ItemValue>(v);
if (!itemTemplate)
- return ItemValuePtr();
+ return {};
const bool createdByPropertiesBlock = itemValue && itemValue->createdByPropertiesBlock();
ItemValuePtr result = ItemValue::create(Item::create(&pool, itemTemplate->type()),
createdByPropertiesBlock);
@@ -184,7 +185,7 @@ JSSourceValuePtr Item::sourceProperty(const QString &name) const
{
ValuePtr v = property(name);
if (!v || v->type() != Value::JSSourceValueType)
- return JSSourceValuePtr();
+ return {};
return std::static_pointer_cast<JSSourceValue>(v);
}
@@ -192,7 +193,7 @@ VariantValuePtr Item::variantProperty(const QString &name) const
{
ValuePtr v = property(name);
if (!v || v->type() != Value::VariantValueType)
- return VariantValuePtr();
+ return {};
return std::static_pointer_cast<VariantValue>(v);
}
diff --git a/src/lib/corelib/language/qualifiedid.cpp b/src/lib/corelib/language/qualifiedid.cpp
index 9eb0e9463..87248ac21 100644
--- a/src/lib/corelib/language/qualifiedid.cpp
+++ b/src/lib/corelib/language/qualifiedid.cpp
@@ -58,7 +58,7 @@ QualifiedId::QualifiedId(const QStringList &nameParts)
QualifiedId QualifiedId::fromString(const QString &str)
{
- return QualifiedId(str.split(QLatin1Char('.')));
+ return {str.split(QLatin1Char('.'))};
}
QString QualifiedId::toString() const
diff --git a/src/lib/corelib/language/scriptengine.cpp b/src/lib/corelib/language/scriptengine.cpp
index 7847cb24d..9131db7f5 100644
--- a/src/lib/corelib/language/scriptengine.cpp
+++ b/src/lib/corelib/language/scriptengine.cpp
@@ -808,7 +808,7 @@ JSValue ScriptEngine::evaluate(JsValueOwner resultOwner, const QString &code,
m_scopeChains << scopeChain;
const QByteArray &codeStr = code.toUtf8();
- m_evalPositions.emplace(std::make_pair(filePath, line));
+ m_evalPositions.emplace(filePath, line);
const JSValue v = JS_EvalThis(m_context, globalObject(), codeStr.constData(), codeStr.length(),
filePath.toUtf8().constData(), line, JS_EVAL_TYPE_GLOBAL);
m_evalPositions.pop();
@@ -829,7 +829,7 @@ ScopedJsValueList ScriptEngine::argumentList(const QStringList &argumentNames,
JSValueList result;
for (const auto &name : argumentNames)
result.push_back(getJsProperty(m_context, context, name));
- return ScopedJsValueList(m_context, result);
+ return {m_context, result};
}
JSClassID ScriptEngine::registerClass(const char *name, JSClassCall *constructor,
diff --git a/src/lib/corelib/loader/astpropertiesitemhandler.cpp b/src/lib/corelib/loader/astpropertiesitemhandler.cpp
index cd6a32908..8183e6b79 100644
--- a/src/lib/corelib/loader/astpropertiesitemhandler.cpp
+++ b/src/lib/corelib/loader/astpropertiesitemhandler.cpp
@@ -159,8 +159,7 @@ static JSSourceValue::AltProperty getPropertyData(const Item *propertiesItem, co
throw ErrorInfo(Tr::tr("Properties.condition must be provided."),
propertiesItem->location());
}
- return JSSourceValue::AltProperty(StringConstants::falseValue(),
- propertiesItem->location());
+ return {StringConstants::falseValue(), propertiesItem->location()};
}
if (Q_UNLIKELY(value->type() != Value::JSSourceValueType)) {
throw ErrorInfo(Tr::tr("Properties.%1 must be a value binding.").arg(name),
@@ -180,7 +179,7 @@ static JSSourceValue::AltProperty getPropertyData(const Item *propertiesItem, co
}
const JSSourceValuePtr srcval = std::static_pointer_cast<JSSourceValue>(value);
- return JSSourceValue::AltProperty(srcval->sourceCodeForEvaluation(), srcval->location());
+ return {srcval->sourceCodeForEvaluation(), srcval->location()};
}
void ASTPropertiesItemHandler::handlePropertiesBlock(const Item *propertiesItem)
diff --git a/src/lib/corelib/loader/dependenciesresolver.cpp b/src/lib/corelib/loader/dependenciesresolver.cpp
index 5df47217f..479318e73 100644
--- a/src/lib/corelib/loader/dependenciesresolver.cpp
+++ b/src/lib/corelib/loader/dependenciesresolver.cpp
@@ -432,7 +432,7 @@ LoadModuleResult DependenciesResolver::loadModule(
dependency.parameters);
} else if (dependency.product) {
productDep = dependency.product; // We have already done the look-up.
- } else if (!(productDep = findMatchingProduct(dependency))) {
+ } else if (productDep = findMatchingProduct(dependency); !productDep) {
moduleItem = findMatchingModule(dependency);
}
@@ -1125,8 +1125,8 @@ DependenciesContextImpl::DependenciesContextImpl(ProductContext &product, Loader
std::pair<ProductDependency, ProductContext *> DependenciesContextImpl::pendingDependency() const
{
QBS_CHECK(!stateStack.empty());
- if (stateStack.front().currentDependsItem
- && !stateStack.front().currentDependsItem->productTypes.empty()) {
+ if (const auto &currentDependsItem = stateStack.front().currentDependsItem;
+ currentDependsItem && !currentDependsItem->productTypes.empty()) {
qCDebug(lcLoaderScheduling) << "product" << m_product.displayName()
<< "to be delayed because of bulk dependency";
return {ProductDependency::Bulk, nullptr};
diff --git a/src/lib/corelib/loader/loaderutils.cpp b/src/lib/corelib/loader/loaderutils.cpp
index a6105ee50..05a077dbe 100644
--- a/src/lib/corelib/loader/loaderutils.cpp
+++ b/src/lib/corelib/loader/loaderutils.cpp
@@ -435,7 +435,9 @@ void TopLevelProjectContext::removeModuleFileFromDirectoryCache(const QString &f
auto &moduleFiles = moduleFilesGuard.get();
const auto it = moduleFiles.find(FileInfo::path(filePath));
QBS_CHECK(it != moduleFiles.end());
- it->second->removeOne(filePath);
+ auto &files = it->second;
+ QBS_CHECK(files);
+ files->removeOne(filePath);
}
void TopLevelProjectContext::addUnknownProfilePropertyError(const Item *moduleProto,
diff --git a/src/lib/corelib/loader/moduleproviderloader.cpp b/src/lib/corelib/loader/moduleproviderloader.cpp
index bceed8ece..a9f5eb26f 100644
--- a/src/lib/corelib/loader/moduleproviderloader.cpp
+++ b/src/lib/corelib/loader/moduleproviderloader.cpp
@@ -168,6 +168,7 @@ ModuleProviderLoader::findOrCreateProviderInfo(
const QualifiedId &moduleName, const QualifiedId &name, ModuleProviderLookup lookupType,
const QVariantMap &qbsModule)
{
+ QBS_CHECK(product.providerConfig);
const QVariantMap config = product.providerConfig->value(name.toString()).toMap();
std::lock_guard lock(m_loaderState.topLevelProject().moduleProvidersCacheLock());
ModuleProvidersCacheKey cacheKey{name.toString(), {}, config, qbsModule, int(lookupType)};
diff --git a/src/lib/corelib/logging/logger.cpp b/src/lib/corelib/logging/logger.cpp
index d4f51cd30..65d0cc27f 100644
--- a/src/lib/corelib/logging/logger.cpp
+++ b/src/lib/corelib/logging/logger.cpp
@@ -231,7 +231,7 @@ void Logger::printWarning(const ErrorInfo &warning)
LogWriter Logger::qbsLog(LoggerLevel level, bool force) const
{
- return LogWriter(m_logSink, level, force);
+ return {m_logSink, level, force};
}
} // namespace Internal
diff --git a/src/lib/corelib/parser/qmljslexer.cpp b/src/lib/corelib/parser/qmljslexer.cpp
index 684be9317..e148652ad 100644
--- a/src/lib/corelib/parser/qmljslexer.cpp
+++ b/src/lib/corelib/parser/qmljslexer.cpp
@@ -1071,7 +1071,7 @@ bool Lexer::scanDirectives(Directives *directives)
const int lineNumber = tokenStartLine();
- if (! (_tokenKind == T_IDENTIFIER || _tokenKind == T_RESERVED_WORD))
+ if (_tokenKind != T_IDENTIFIER && _tokenKind != T_RESERVED_WORD)
return false; // expected a valid QML/JS directive
const QString directiveName = tokenText();
@@ -1083,7 +1083,7 @@ bool Lexer::scanDirectives(Directives *directives)
// it must be a pragma or an import directive.
if (directiveName == QLatin1String("pragma")) {
// .pragma library
- if (! (lex() == T_IDENTIFIER && tokenText() == QLatin1String("library")))
+ if (lex() != T_IDENTIFIER || tokenText() != QLatin1String("library"))
return false; // expected `library
// we found a .pragma library directive
@@ -1126,7 +1126,7 @@ bool Lexer::scanDirectives(Directives *directives)
//
// recognize the mandatory `as' followed by the module name
//
- if (! (lex() == T_RESERVED_WORD && tokenText() == QLatin1String("as")))
+ if (lex() != T_RESERVED_WORD || tokenText() != QLatin1String("as"))
return false; // expected `as'
if (lex() != T_IDENTIFIER)
diff --git a/src/lib/corelib/tools/clangclinfo.cpp b/src/lib/corelib/tools/clangclinfo.cpp
index d89c5cb9b..fd907ebf1 100644
--- a/src/lib/corelib/tools/clangclinfo.cpp
+++ b/src/lib/corelib/tools/clangclinfo.cpp
@@ -47,7 +47,7 @@ static std::vector<MSVCInstallInfo> compatibleMsvcs(Logger &logger)
return true;
bool ok = false;
const int major = versions.at(0).toInt(&ok);
- return !(ok && major >= 15); // support MSVC2017 and above
+ return !ok || major < 15; // support MSVC2017 and above
};
Internal::removeIf(msvcs, filter);
for (const auto &msvc: msvcs) {
diff --git a/src/lib/corelib/tools/profiling.cpp b/src/lib/corelib/tools/profiling.cpp
index 62815912d..b93d3fa17 100644
--- a/src/lib/corelib/tools/profiling.cpp
+++ b/src/lib/corelib/tools/profiling.cpp
@@ -104,7 +104,7 @@ void AccumulatingTimer::stop()
QString elapsedTimeString(qint64 elapsedTimeInNs)
{
- qint64 ms = elapsedTimeInNs / (1000 * 1000);
+ qint64 ms = elapsedTimeInNs / (1000ll * 1000ll);
qint64 s = ms/1000;
ms -= s*1000;
qint64 m = s/60;
diff --git a/src/lib/corelib/tools/scripttools.cpp b/src/lib/corelib/tools/scripttools.cpp
index 6262e7cf7..e89e4a0ad 100644
--- a/src/lib/corelib/tools/scripttools.cpp
+++ b/src/lib/corelib/tools/scripttools.cpp
@@ -123,7 +123,7 @@ ErrorInfo JsException::toErrorInfo() const
ErrorInfo e(msg, stackTrace());
if (e.hasLocation() || !m_fallbackLocation.isValid())
return e;
- return ErrorInfo(msg, m_fallbackLocation);
+ return {msg, m_fallbackLocation};
}
void defineJsProperty(JSContext *ctx, JSValueConst obj, const QString &prop, JSValue val)
diff --git a/src/lib/corelib/tools/settingsmodel.cpp b/src/lib/corelib/tools/settingsmodel.cpp
index e3c995db3..4fa0e14da 100644
--- a/src/lib/corelib/tools/settingsmodel.cpp
+++ b/src/lib/corelib/tools/settingsmodel.cpp
@@ -281,10 +281,10 @@ bool SettingsModel::setData(const QModelIndex &index, const QVariant &value, int
const QString valueString = value.toString();
QString *toChange = nullptr;
if (index.column() == keyColumn() && !valueString.isEmpty()
- && !node->parent->hasDirectChildWithName(valueString)
- && !(node->parent->parent == &d->rootNode
- && node->parent->name == Internal::StringConstants::profilesSettingsKey()
- && valueString == Profile::fallbackName())) {
+ && !node->parent->hasDirectChildWithName(valueString)
+ && (node->parent->parent != &d->rootNode
+ || node->parent->name != Internal::StringConstants::profilesSettingsKey()
+ || valueString != Profile::fallbackName())) {
toChange = &node->name;
} else if (index.column() == valueColumn() && valueString != node->value) {
toChange = &node->value;
diff --git a/src/lib/pkgconfig/pcparser.cpp b/src/lib/pkgconfig/pcparser.cpp
index 4469ca193..eb07aa5ef 100644
--- a/src/lib/pkgconfig/pcparser.cpp
+++ b/src/lib/pkgconfig/pcparser.cpp
@@ -524,9 +524,11 @@ void PcParser::parseLibs(
raiseDuplicateFieldException(fieldName, pkg.filePath);
const auto trimmed = trimAndSubstitute(pkg, str);
+ if (trimmed.empty())
+ return;
const auto argv = splitCommand(trimmed);
- if (!trimmed.empty() && !argv)
+ if (!argv)
throw PcException("Couldn't parse Libs field into an argument vector");
libs = doParseLibs(*argv);
@@ -593,9 +595,11 @@ void PcParser::parseCFlags(PcPackage &pkg, std::string_view str)
raiseDuplicateFieldException("Cflags", pkg.filePath);
const auto command = trimAndSubstitute(pkg, str);
+ if (command.empty())
+ return;
const auto argv = splitCommand(command);
- if (!command.empty() && !argv)
+ if (!argv)
throw PcException("Couldn't parse Cflags field into an argument vector");
std::vector<PcPackage::Flag> cflags;
@@ -722,10 +726,8 @@ void PcParser::parseLine(PcPackage &pkg, std::string_view str)
size_t pos = 0;
for (; pos < s.size(); ++pos) {
auto p = s.data() + pos;
- if (!((*p >= 'A' && *p <= 'Z') ||
- (*p >= 'a' && *p <= 'z') ||
- (*p >= '0' && *p <= '9') ||
- *p == '_' || *p == '.')) {
+ if ((*p < 'A' || *p > 'Z') && (*p < 'a' || *p > 'z') && (*p < '0' || *p > '9')
+ && *p != '_' && *p != '.') {
break;
}
}
diff --git a/src/plugins/scanner/cpp/Lexer.cpp b/src/plugins/scanner/cpp/Lexer.cpp
index ebf843aca..6793080e9 100644
--- a/src/plugins/scanner/cpp/Lexer.cpp
+++ b/src/plugins/scanner/cpp/Lexer.cpp
@@ -564,7 +564,7 @@ void Lexer::scan_helper(Token *tok)
do {
yyinp();
- if (! (isalnum(_yychar) || _yychar == '_' || _yychar == '$'))
+ if (!isalnum(_yychar) && _yychar != '_' && _yychar != '$')
break;
} while (_yychar);
diff --git a/src/shared/quickjs/.clang-tidy b/src/shared/quickjs/.clang-tidy
index c5e5db244..b9209aae5 100644
--- a/src/shared/quickjs/.clang-tidy
+++ b/src/shared/quickjs/.clang-tidy
@@ -1,13 +1,3 @@
----
-Checks: >
- -bugprone-branch-clone,
- -bugprone-easily-swappable-parameters,
- -bugprone-implicit-widening-of-multiplication-result,
- -bugprone-signed-char-misuse,
- -bugprone-suspicious-memory-comparison,
- -bugprone-sizeof-expression,
- -misc-redundant-expression,
- -misc-unused-parameters
+Checks: '-*,misc-definitions-in-headers'
InheritParentConfig: true
-...
diff --git a/tests/auto/blackbox/testdata/exports-cmake/Foo.cpp b/tests/auto/blackbox/testdata/exports-cmake/Foo.cpp
new file mode 100644
index 000000000..ea334f9af
--- /dev/null
+++ b/tests/auto/blackbox/testdata/exports-cmake/Foo.cpp
@@ -0,0 +1,5 @@
+#include "Foo.h"
+int someFooWork()
+{
+ return 42;
+}
diff --git a/tests/auto/blackbox/testdata/exports-cmake/Foo.h b/tests/auto/blackbox/testdata/exports-cmake/Foo.h
new file mode 100644
index 000000000..2f279f577
--- /dev/null
+++ b/tests/auto/blackbox/testdata/exports-cmake/Foo.h
@@ -0,0 +1,16 @@
+#ifndef FOO_H
+#define FOO_H
+#include <dllexport.h>
+
+#ifdef FOO_LIB_STATIC
+#define FOO_LIB_EXPORT
+#else
+#ifdef FOO_LIB
+#define FOO_LIB_EXPORT DLL_EXPORT
+#else
+#define FOO_LIB_EXPORT DLL_IMPORT
+#endif
+#endif
+
+FOO_LIB_EXPORT int someFooWork();
+#endif // FOO_H
diff --git a/tests/auto/blackbox/testdata/exports-cmake/cmake/CMakeLists.txt b/tests/auto/blackbox/testdata/exports-cmake/cmake/CMakeLists.txt
new file mode 100644
index 000000000..d874e0e92
--- /dev/null
+++ b/tests/auto/blackbox/testdata/exports-cmake/cmake/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.10)
+
+project(qbs_import)
+
+find_package(Bar PATHS REQUIRED)
+add_executable(Consumer main.cpp)
+target_link_libraries(Consumer Bar)
diff --git a/tests/auto/blackbox/testdata/exports-cmake/cmake/main.cpp b/tests/auto/blackbox/testdata/exports-cmake/cmake/main.cpp
new file mode 100644
index 000000000..1a1fa90ec
--- /dev/null
+++ b/tests/auto/blackbox/testdata/exports-cmake/cmake/main.cpp
@@ -0,0 +1,6 @@
+#include <Foo.h>
+
+int main()
+{
+ return someFooWork();
+}
diff --git a/tests/auto/blackbox/testdata/exports-cmake/exports-cmake.qbs b/tests/auto/blackbox/testdata/exports-cmake/exports-cmake.qbs
new file mode 100644
index 000000000..6464af705
--- /dev/null
+++ b/tests/auto/blackbox/testdata/exports-cmake/exports-cmake.qbs
@@ -0,0 +1,70 @@
+import qbs.FileInfo
+
+Project {
+ property bool isStatic: false
+ property bool isBundle: false
+
+ property string headersInstallDir: "include"
+
+ Product {
+ name: "DllExport"
+ Depends { name: "Exporter.cmake" }
+ Group {
+ name: "API headers"
+ files: ["../dllexport.h"]
+ qbs.install: true
+ qbs.installDir: project.headersInstallDir
+ }
+ Group {
+ fileTagsFilter: ["Exporter.cmake.package"]
+ qbs.install: true
+ qbs.installDir: "/lib/cmake/DllExport"
+ }
+ Export {
+ Depends { name: "cpp" }
+ cpp.includePaths: FileInfo.joinPaths(
+ exportingProduct.qbs.installRoot,
+ exportingProduct.qbs.installPrefix,
+ project.headersInstallDir)
+ }
+ }
+
+ Library {
+ type: project.isStatic ? "staticlibrary" : "dynamiclibrary"
+ Depends { name: "cpp" }
+ Depends { name: "DllExport" }
+ Depends { name: "Exporter.cmake" }
+ Exporter.cmake.packageName: "Bar"
+ name: "Foo"
+ files: ["Foo.cpp"]
+ version: "1.2.3"
+ cpp.includePaths: "."
+ cpp.defines: "FOO_LIB"
+ Group {
+ name: "API headers"
+ files: ["Foo.h"]
+ qbs.install: true
+ qbs.installDir: project.headersInstallDir
+ }
+ install: true
+ installImportLib: true
+ Group {
+ fileTagsFilter: ["Exporter.cmake.package"]
+ qbs.install: true
+ qbs.installDir: "/lib/cmake/Bar"
+ }
+ Export {
+ Depends { name: "cpp" }
+ cpp.includePaths: FileInfo.joinPaths(
+ exportingProduct.qbs.installRoot,
+ exportingProduct.qbs.installPrefix,
+ project.headersInstallDir)
+ cpp.defines: ["FOO=1"].concat(project.isStatic ? ["FOO_LIB_STATIC"] : [])
+ cpp.commonCompilerFlags: "-DOTHER_DEF=1"
+ cpp.linkerFlags: exportingProduct.qbs.toolchain.contains("gcc") ? ["-s"] : []
+ }
+
+ Depends { name: 'bundle' }
+ bundle.isBundle: qbs.targetOS.includes("darwin") && project.isBundle
+ }
+}
diff --git a/tests/auto/blackbox/testdata/exports-cmake/find-cmake.qbs b/tests/auto/blackbox/testdata/exports-cmake/find-cmake.qbs
new file mode 100644
index 000000000..52f388966
--- /dev/null
+++ b/tests/auto/blackbox/testdata/exports-cmake/find-cmake.qbs
@@ -0,0 +1,46 @@
+import qbs.Probes
+
+Product {
+ Depends { name: "cpp" }
+
+ Probes.BinaryProbe {
+ id: cmakeProbe
+ names: "cmake"
+ }
+
+ Probes.BinaryProbe {
+ id: ninjaProbe
+ names: ["ninja"]
+ }
+
+ property bool test: {
+ var data = {
+ cmakeFound: cmakeProbe.found,
+ cmakeFilePath: cmakeProbe.filePath,
+ crossCompiling: qbs.targetPlatform !== qbs.hostPlatform,
+ installPrefix: qbs.installPrefix
+ };
+ data.buildEnv = {}
+ Object.assign(data.buildEnv, cpp.buildEnv); // deep copy buildEnv from a probe
+ if (qbs.toolchain.includes("gcc")) {
+ data.buildEnv["CC"] = cpp.cCompilerName;
+ data.buildEnv["CXX"] = cpp.cxxCompilerName;
+ } else {
+ data.buildEnv["CC"] = cpp.compilerName;
+ data.buildEnv["CXX"] = cpp.compilerName;
+ }
+
+ if (ninjaProbe.found) {
+ data.generator = "Ninja";
+ } else {
+ if (qbs.toolchain.includes("msvc")) {
+ data.generator = "NMake Makefiles"
+ } else if (qbs.toolchain.includes("mingw")) {
+ data.generator = "MinGW Makefiles";
+ } else if (qbs.toolchain.includes("gcc")) {
+ data.generator = "Unix Makefiles";
+ }
+ }
+ console.info("---" + JSON.stringify(data) + "---");
+ }
+}
diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp
index 395e5aba6..cd611e76f 100644
--- a/tests/auto/blackbox/tst_blackbox.cpp
+++ b/tests/auto/blackbox/tst_blackbox.cpp
@@ -1386,9 +1386,9 @@ void TestBlackbox::variantSuffix_data()
std::make_pair(QString("unix"), QStringList())});
}
-static bool waitForProcessSuccess(QProcess &p)
+static bool waitForProcessSuccess(QProcess &p, int msecs = 30000)
{
- if (!p.waitForStarted() || !p.waitForFinished()) {
+ if (!p.waitForStarted(msecs) || !p.waitForFinished(msecs)) {
qDebug() << p.errorString();
return false;
}
@@ -4099,6 +4099,82 @@ void TestBlackbox::exportToOutsideSearchPath()
m_qbsStderr.constData());
}
+void TestBlackbox::exportsCMake()
+{
+ QFETCH(QStringList, arguments);
+
+ QDir::setCurrent(testDataDir + "/exports-cmake");
+ rmDirR(relativeBuildDir());
+ QbsRunParameters findCMakeParams("resolve", {"-f", "find-cmake.qbs"});
+ QCOMPARE(runQbs(findCMakeParams), 0);
+ const QString output = QString::fromLocal8Bit(m_qbsStdout);
+ const QRegularExpression pattern(
+ QRegularExpression::anchoredPattern(".*---(.*)---.*"),
+ QRegularExpression::DotMatchesEverythingOption);
+ const QRegularExpressionMatch match = pattern.match(output);
+ QVERIFY2(match.hasMatch(), qPrintable(output));
+ QCOMPARE(pattern.captureCount(), 1);
+ const QString jsonString = match.captured(1);
+ const QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonString.toUtf8());
+ const QJsonObject jsonData = jsonDoc.object();
+
+ rmDirR(relativeBuildDir());
+ const QStringList exporterArgs{"-f", "exports-cmake.qbs"};
+ QbsRunParameters exporterRunParams("build", exporterArgs);
+ exporterRunParams.arguments << arguments;
+ QCOMPARE(runQbs(exporterRunParams), 0);
+
+ if (!jsonData.value(u"cmakeFound").toBool()) {
+ QSKIP("cmake is not installed");
+ return;
+ }
+
+ if (jsonData.value(u"crossCompiling").toBool()) {
+ QSKIP("test is not applicable with cross-compile toolchains");
+ return;
+ }
+
+ const auto cmakeFilePath = jsonData.value(u"cmakeFilePath").toString();
+ QVERIFY(!cmakeFilePath.isEmpty());
+
+ const auto generator = jsonData.value(u"generator").toString();
+ if (generator.isEmpty()) {
+ QSKIP("cannot detect cmake generator");
+ return;
+ }
+
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ const auto buildEnv = jsonData.value(u"buildEnv").toObject();
+ for (auto it = buildEnv.begin(), end = buildEnv.end(); it != end; ++it) {
+ env.insert(it.key(), it.value().toString());
+ }
+
+ const auto installPrefix = jsonData.value(u"installPrefix").toString();
+ const auto cmakePrefixPath = QFileInfo(relativeBuildDir()).absoluteFilePath() + "/install-root/"
+ + installPrefix + "/lib/cmake";
+ const auto sourceDirectory = testDataDir + "/exports-cmake/cmake";
+ QProcess configure;
+ configure.setProcessEnvironment(env);
+ configure.setWorkingDirectory(sourceDirectory);
+ configure.start(
+ cmakeFilePath, {".", "-DCMAKE_PREFIX_PATH=" + cmakePrefixPath, "-G" + generator});
+ QVERIFY(waitForProcessSuccess(configure, 120000));
+
+ QProcess build;
+ build.setProcessEnvironment(env);
+ build.setWorkingDirectory(sourceDirectory);
+ build.start(cmakeFilePath, QStringList{"--build", "."});
+ QVERIFY(waitForProcessSuccess(build));
+}
+
+void TestBlackbox::exportsCMake_data()
+{
+ QTest::addColumn<QStringList>("arguments");
+ QTest::newRow("dynamic lib") << QStringList("project.isStatic: false");
+ QTest::newRow("static lib") << QStringList("project.isStatic: true");
+ QTest::newRow("framework") << QStringList("project.isBundle: true");
+}
+
void TestBlackbox::exportsPkgconfig()
{
QDir::setCurrent(testDataDir + "/exports-pkgconfig");
diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h
index 62676625e..701002620 100644
--- a/tests/auto/blackbox/tst_blackbox.h
+++ b/tests/auto/blackbox/tst_blackbox.h
@@ -126,6 +126,8 @@ private slots:
void exportedPropertyInDisabledProduct_data();
void exportRule();
void exportToOutsideSearchPath();
+ void exportsCMake();
+ void exportsCMake_data();
void exportsPkgconfig();
void exportsQbs();
void externalLibs();