qbs-src-2.5.1/0000755000175100001660000000000014744424375012452 5ustar runnerdockerqbs-src-2.5.1/docker/0000755000175100001660000000000014744424375013721 5ustar runnerdockerqbs-src-2.5.1/docker/noble/0000755000175100001660000000000014744424375015020 5ustar runnerdockerqbs-src-2.5.1/docker/noble/test-baremetal.Dockerfile0000644000175100001660000000300114744424375021714 0ustar runnerdocker# # Baremetal toolchains for testing Qbs # FROM ubuntu:noble LABEL Description="Ubuntu baremetal test environment for Qbs" # 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 && \ userdel ubuntu && \ 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/entrypoint.sh /sbin/entrypoint.sh ENTRYPOINT ["/sbin/entrypoint.sh"] # Install baremetal toolchains and Qbs runtime dependencies. RUN apt-get update -qq && \ apt-get install -qq -y \ libasan5 \ libglib2.0-0 \ libgssapi-krb5-2 \ gcc-arm-none-eabi \ gcc-avr \ avr-libc \ sdcc \ binutils-xtensa-lx106 \ gcc-xtensa-lx106 \ gcc-riscv64-unknown-elf # Work-around for QTBUG-79020. RUN echo "export QT_NO_GLIB=1" >> /etc/profile.d/qt.sh qbs-src-2.5.1/docker/noble/test-android-no-qt.Dockerfile0000644000175100001660000001040714744424375022444 0ustar runnerdocker# # Android SDK/NDK for testing Qbs # FROM ubuntu:noble LABEL Description="Ubuntu test environment for Qbs for Android" # 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 && \ userdel ubuntu && \ 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/entrypoint.sh /sbin/entrypoint.sh ENTRYPOINT ["/sbin/entrypoint.sh"] # Qbs build dependencies RUN apt-get update -qq && \ apt-get install -qq -y --no-install-recommends \ ca-certificates \ curl \ gdb \ libasan5 \ libglib2.0-0 \ openjdk-8-jdk-headless \ p7zip-full \ unzip ENV JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 RUN echo "export JAVA_HOME=${JAVA_HOME}" > /etc/profile.d/android.sh && \ echo "export PATH=${JAVA_HOME}/bin:\${PATH}" >> /etc/profile.d/android.sh ARG ANDROID_NDK_VERSION ENV ANDROID_HOME="/home/${USER_NAME}/android" ENV ANDROID_SDK_ROOT=${ANDROID_HOME} ENV ANDROID_NDK_ROOT=${ANDROID_HOME}/"ndk"/${ANDROID_NDK_VERSION} ENV PATH="${JAVA_HOME}:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/cmdline-tools/bin:$PATH" RUN echo "export ANDROID_HOME=/home/${USER_NAME}/android" >> /etc/profile.d/android.sh && \ echo "export ANDROID_SDK_ROOT=${ANDROID_SDK_ROOT}" >> /etc/profile.d/android.sh && \ echo "export ANDROID_NDK_ROOT=${ANDROID_NDK_ROOT}" >> /etc/profile.d/android.sh && \ echo "export PATH=${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/cmdline-tools/bin:\$PATH" >> /etc/profile.d/android.sh # # We ned to run the following steps as the target user # USER ${USER_NAME} RUN mkdir ${ANDROID_HOME} # Get Android command line tools ARG COMMAND_LINE_TOOLS_VERSION="6858069" RUN curl -s https://dl.google.com/android/repository/commandlinetools-linux-${COMMAND_LINE_TOOLS_VERSION}_latest.zip > ${ANDROID_HOME}/commandlinetools.zip && \ unzip ${ANDROID_HOME}/commandlinetools.zip -d ${ANDROID_HOME} && \ rm -v ${ANDROID_HOME}/commandlinetools.zip # Accept SDK license ARG ANDROID_PLATFORM="android-29" ARG BUILD_TOOLS="29.0.2" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" --verbose --licenses && \ sdkmanager "--sdk_root=${ANDROID_HOME}" --update && \ sdkmanager "--sdk_root=${ANDROID_HOME}" "platforms;${ANDROID_PLATFORM}" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" "build-tools;${BUILD_TOOLS}" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" "platform-tools" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" "tools" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" "ndk;${ANDROID_NDK_VERSION}" RUN /usr/lib/jvm/java-8-openjdk-amd64/bin/keytool -genkey -keystore /home/${USER_NAME}/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android -keyalg RSA -keysize 2048 -validity 10000 -dname 'CN=Android Debug,O=Android,C=US' # Install ndk samples in ${ANDROID_NDK_ROOT}/samples RUN cd ${ANDROID_NDK_ROOT} && \ curl -sLO https://github.com/android/ndk-samples/archive/master.zip && \ unzip -q master.zip && \ rm -v master.zip && \ mv ndk-samples-master samples # Install android-BasicMediaDecoder in ${ANDROID_SDK_ROOT}/samples RUN mkdir ${ANDROID_SDK_ROOT}/samples && \ cd ${ANDROID_SDK_ROOT}/samples && \ curl -sLO https://github.com/googlearchive/android-BasicMediaDecoder/archive/master.zip && \ unzip -q master.zip && \ rm -v master.zip && \ mv android-BasicMediaDecoder-master android-BasicMediaDecoder # Download buildtool to generate aab packages in ${ANDROID_SDK_ROOT} RUN cd ${ANDROID_SDK_ROOT} && \ curl -sLO https://github.com/google/bundletool/releases/download/1.3.0/bundletool-all-1.3.0.jar USER root qbs-src-2.5.1/docker/noble/test-android.Dockerfile0000644000175100001660000001266214744424375021415 0ustar runnerdocker# # Android SDK/NDK + Qt for Android for testing Qbs # FROM ubuntu:noble LABEL Description="Ubuntu test environment for Qbs and Qt for Android" # 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 && \ userdel ubuntu && \ 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/entrypoint.sh /sbin/entrypoint.sh ENTRYPOINT ["/sbin/entrypoint.sh"] # Qbs build dependencies RUN apt-get update -qq && \ apt-get install -qq -y --no-install-recommends \ ca-certificates \ curl \ gdb \ libasan5 \ libglib2.0-0 \ locales \ openjdk-8-jdk-headless \ p7zip-full \ unzip # 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 JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 RUN echo "export JAVA_HOME=${JAVA_HOME}" > /etc/profile.d/android.sh && \ echo "export PATH=${JAVA_HOME}/bin:\${PATH}" >> /etc/profile.d/android.sh ARG ANDROID_NDK_VERSION ENV ANDROID_HOME="/home/${USER_NAME}/android" ENV ANDROID_SDK_ROOT=${ANDROID_HOME} ENV ANDROID_NDK_ROOT=${ANDROID_HOME}/"ndk"/${ANDROID_NDK_VERSION} ENV PATH="${JAVA_HOME}:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/cmdline-tools/bin:$PATH" RUN echo "export ANDROID_HOME=/home/${USER_NAME}/android" >> /etc/profile.d/android.sh && \ echo "export ANDROID_SDK_ROOT=${ANDROID_SDK_ROOT}" >> /etc/profile.d/android.sh && \ echo "export ANDROID_NDK_ROOT=${ANDROID_NDK_ROOT}" >> /etc/profile.d/android.sh && \ echo "export PATH=${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/cmdline-tools/bin:\$PATH" >> /etc/profile.d/android.sh # # We ned to run the following steps as the target user # USER ${USER_NAME} RUN mkdir ${ANDROID_HOME} # Get Android command line tools ARG COMMAND_LINE_TOOLS_VERSION="6858069" RUN curl -s https://dl.google.com/android/repository/commandlinetools-linux-${COMMAND_LINE_TOOLS_VERSION}_latest.zip > ${ANDROID_HOME}/commandlinetools.zip && \ unzip ${ANDROID_HOME}/commandlinetools.zip -d ${ANDROID_HOME} && \ rm -v ${ANDROID_HOME}/commandlinetools.zip # Accept SDK license ARG ANDROID_PLATFORM="android-30" ARG BUILD_TOOLS="29.0.2" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" --verbose --licenses && \ sdkmanager "--sdk_root=${ANDROID_HOME}" --update && \ sdkmanager "--sdk_root=${ANDROID_HOME}" "platforms;${ANDROID_PLATFORM}" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" "build-tools;${BUILD_TOOLS}" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" "platform-tools" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" "tools" RUN yes | sdkmanager "--sdk_root=${ANDROID_HOME}" "ndk;${ANDROID_NDK_VERSION}" RUN /usr/lib/jvm/java-8-openjdk-amd64/bin/keytool -genkey -keystore /home/${USER_NAME}/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android -keyalg RSA -keysize 2048 -validity 10000 -dname 'CN=Android Debug,O=Android,C=US' # Install ndk samples in ${ANDROID_NDK_ROOT}/samples RUN cd ${ANDROID_NDK_ROOT} && \ curl -sLO https://github.com/android/ndk-samples/archive/master.zip && \ unzip -q master.zip && \ rm -v master.zip && \ mv ndk-samples-master samples # Install android-BasicMediaDecoder in ${ANDROID_SDK_ROOT}/samples RUN mkdir ${ANDROID_SDK_ROOT}/samples && \ cd ${ANDROID_SDK_ROOT}/samples && \ curl -sLO https://github.com/googlearchive/android-BasicMediaDecoder/archive/master.zip && \ unzip -q master.zip && \ rm -v master.zip && \ mv android-BasicMediaDecoder-master android-BasicMediaDecoder # Download buildtool to generate aab packages in ${ANDROID_SDK_ROOT} RUN cd ${ANDROID_SDK_ROOT} && \ curl -sLO https://github.com/google/bundletool/releases/download/1.3.0/bundletool-all-1.3.0.jar USER root # # Install Qt and Qbs for Linux from qt.io # ARG QT_VERSION COPY scripts/install-qt.sh install-qt.sh RUN if [ "${QT_VERSION}" \< "5.14" ] || [ ! "${QT_VERSION}" \< "6.0.0" ]; then \ QT_ABIS="android_armv7 android_arm64_v8a android_x86 android_x86_64"; \ else \ QT_ABIS="any"; \ fi; \ if [ ! "${QT_VERSION}" \< "6.0.0" ]; then \ ./install-qt.sh --version ${QT_VERSION} qtbase qtdeclarative icu; \ if [ "${QT_VERSION}" \< "6.1.0" ]; then \ QT_COMPONENTS="qtbase qtdeclarative qttools qtquickcontrols2 qtquicktimeline svg"; \ else \ QT_COMPONENTS="qtbase qtdeclarative qttools qtquicktimeline svg"; \ fi; \ else \ QT_COMPONENTS="qtbase qtdeclarative qttools qtimageformats"; \ fi; \ for abi in ${QT_ABIS}; do \ ./install-qt.sh --version ${QT_VERSION} --target android --toolchain ${abi} ${QT_COMPONENTS}; \ done && \ echo "export QT_VERSION=${QT_VERSION}" >> /etc/profile.d/qt.sh qbs-src-2.5.1/docker/noble/test-qt6-wasm.Dockerfile0000644000175100001660000000465214744424375021454 0ustar runnerdocker# # Testing Qbs with Web Assembly # FROM ubuntu:noble LABEL Description="Ubuntu wasm test environment for Qbs" ARG QT_VERSION ARG EMSCRIPTEN_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 && \ userdel ubuntu && \ 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/entrypoint.sh /sbin/entrypoint.sh ENTRYPOINT ["/sbin/entrypoint.sh"] RUN sudo apt-get update -qq && \ apt-get install -qq -y \ curl \ libglib2.0-0 \ locales \ p7zip-full \ python3 \ python3-pip \ unzip # 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 RUN curl -L https://github.com/emscripten-core/emsdk/archive/refs/heads/main.zip > /emsdk.zip && \ unzip /emsdk.zip && \ rm /emsdk.zip && \ mv /emsdk-main /emsdk && \ cd /emsdk && \ ./emsdk install ${EMSCRIPTEN_VERSION} && \ ./emsdk activate ${EMSCRIPTEN_VERSION} ENV EMSDK=/emsdk \ PATH="/emsdk:/emsdk/upstream/emscripten:/emsdk/node/18.20.3_64bit/bin:${PATH}" # # Install Qt for Wasm 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 && \ echo "export PATH=/opt/Qt/${QT_VERSION}/gcc_64/bin:\${PATH}" > /etc/profile.d/qt.sh RUN ./install-qt.sh --version ${QT_VERSION} --target wasm --toolchain wasm_multithread qtbase qtdeclarative qttools qtx11extras qtscxml qt5compat icu && \ echo "export PATH=/opt/Qt/${QT_VERSION}/wasm_multithread/bin:\${PATH}" > /etc/profile.d/qt.sh # Work-around for QTBUG-79020 RUN echo "export QT_NO_GLIB=1" >> /etc/profile.d/qt.sh qbs-src-2.5.1/docker/noble/Dockerfile0000644000175100001660000000757014744424375017023 0ustar runnerdocker# # Install Qt and Qbs for Linux # FROM ubuntu:noble 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 && \ userdel ubuntu && \ 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/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-18 \ clang-tidy-18 \ cmake \ curl \ flex \ git \ gdb \ help2man \ icoutils \ libcapnp-dev \ libclang-rt-18-dev \ libdbus-1-3 \ libfreetype6 \ libfontconfig1 \ libgl1-mesa-dev \ 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 \ python3-venv \ p7zip-full \ subversion \ unzip \ zip && \ update-alternatives --install /usr/bin/clang clang /usr/bin/clang-18 100 && \ update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-18 100 && \ update-alternatives --install /usr/bin/clang-check clang-check /usr/bin/clang-check-18 100 && \ update-alternatives --install /usr/bin/python python /usr/bin/python3 100 ENV LLVM_INSTALL_DIR=/usr/lib/llvm-18 # Set up Python RUN python3 -m venv /venv && \ /venv/bin/pip3 install beautifulsoup4 lxml protobuf==3.19.1 pyyaml conan ENV PATH=/venv/bin:${PATH} # 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 # # 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 # Configure Conan RUN conan profile detect --name qbs-test # 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 qbs-src-2.5.1/docker/entrypoint.sh0000755000175100001660000000720014744424375016472 0ustar runnerdocker#!/usr/bin/env bash set -e ############################################################################# ## ## Copyright (C) 2019 Richard Weickelt ## 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 qbs-src-2.5.1/docker/docker.qbs0000644000175100001660000000042114744424375015674 0ustar runnerdocker // This is a convenience product to be able to use Qt Creator for editing the docker files. // For building and managing the images, use docker-compose as explained in // https://doc.qt.io/qbs/building-qbs.html#using-docker. Product { name: "docker" files: "**" } qbs-src-2.5.1/docker/windowsservercore/0000755000175100001660000000000014744424375017513 5ustar runnerdockerqbs-src-2.5.1/docker/windowsservercore/Dockerfile0000644000175100001660000000503114744424375021504 0ustar runnerdocker FROM mcr.microsoft.com/windows/servercore:1809 LABEL Description="Windows Server Core development environment for Qbs with Qt, Chocolatey and various dependencies for testing Qbs modules and functionality" # Disable crash dialog for release-mode runtimes RUN reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting" /v Disabled /t REG_DWORD /d 1 /f RUN reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting" /v DontShowUI /t REG_DWORD /d 1 /f # Install VS 2019 from the website since chocolatey has broken .NET 4.8 (dotnetfx package) which is a # dependency for the visualstudio2019buildtools package RUN powershell -NoProfile -ExecutionPolicy Bypass -Command \ Invoke-WebRequest "https://aka.ms/vs/16/release/vs_community.exe" \ -OutFile "%TEMP%\vs_community.exe" -UseBasicParsing RUN "%TEMP%\vs_community.exe" --quiet --wait --norestart --noUpdateInstaller \ --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 \ --add Microsoft.VisualStudio.Component.Windows10SDK.20348 RUN powershell -NoProfile -ExecutionPolicy Bypass -Command \ $Env:chocolateyVersion = '0.10.15' ; \ $Env:chocolateyUseWindowsCompression = 'false' ; \ "[Net.ServicePointManager]::SecurityProtocol = \"tls12, tls11, tls\"; iex ((New-Object System.Net.WebClient).DownloadString('http://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin" RUN choco install -y python --version 3.9 && \ choco install -y 7zip --version 19.0 && \ choco install -y git --version 2.24.0 --params "/GitAndUnixToolsOnPath" && \ choco install -y vswhere # for building the documentation RUN pip install beautifulsoup4 lxml # clcache for speeding up MSVC builds ENV CLCACHE_DIR="C:/.ccache" RUN certutil -generateSSTFromWU roots.sst && \ certutil -addstore -f root roots.sst && \ del roots.sst && \ pip install --trusted-host=pypi.org \ git+https://github.com/frerich/clcache.git@cae73d8255d78db8ba11e23c51fd2c9a89e7475b ########### Install Qt ############# ARG QT_VERSION COPY scripts/install-qt.sh install-qt.sh RUN bash -c "./install-qt.sh -d /c/Qt --version ${QT_VERSION} --toolchain win64_msvc2019_64 qtbase qtdeclarative qttools qt5compat" ENV QTDIR64=C:\\Qt\\${QT_VERSION}\\msvc2019_64 ########### Install Qbs ############# ARG QTCREATOR_VERSION RUN bash -c "./install-qt.sh -d /c/Qt --version ${QTCREATOR_VERSION} qtcreator" RUN setx PATH "C:\\Qt\\Tools\\QtCreator\\bin;%PATH%" RUN qbs setup-toolchains --detect && \ qbs setup-qt %QTDIR64%/bin/qmake.exe qt64 && \ qbs config defaultProfile qt64 qbs-src-2.5.1/docker/leap/0000755000175100001660000000000014744424375014642 5ustar runnerdockerqbs-src-2.5.1/docker/leap/entrypoint.sh0000755000175100001660000000720414744424375017417 0ustar runnerdocker#!/usr/bin/env bash set -e ############################################################################# ## ## Copyright (C) 2019 Richard Weickelt ## 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 sudo -i /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 sudo -u ${USER_NAME} -g ${USER_GROUP}" if [ -z "$1" ]; then ${EXEC} bash -l else ${EXEC} bash -l -c "$*" fi qbs-src-2.5.1/docker/leap/Dockerfile0000644000175100001660000000557614744424375016651 0ustar runnerdocker# # Install Qt and Qbs for Linux # FROM opensuse/leap:15.3 LABEL Description="OpenSUSE 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 zypper in -y \ ca-certificates \ sudo \ system-user-mail \ system-group-wheel && \ groupadd -g ${USER_UID} ${USER_NAME} && \ useradd -s /bin/bash -u ${USER_UID} -g ${USER_NAME} -o -c "" -m ${USER_NAME} && \ usermod -a -G wheel ${USER_NAME} && \ echo "%devel ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers COPY docker/leap/entrypoint.sh /sbin/entrypoint.sh ENTRYPOINT ["/sbin/entrypoint.sh"] # # Qbs build dependencies RUN zypper install -y \ bison \ capnproto \ ccache \ cmake \ command-not-found \ curl \ gcc10 \ gcc10-c++ \ glibc-devel-static \ flex \ fontconfig \ git \ gzip \ help2man \ icoutils \ libcapnp-devel \ libgthread-2_0-0 \ libfreetype6 \ Mesa-libGL-devel \ Mesa-libGL1 \ nanopb-devel \ ninja \ perl \ pkg-config \ psmisc \ python3-pip \ p7zip-full \ subversion \ tar \ unzip \ which \ zip && \ update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 100 && \ update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 100 && \ pip install --upgrade pip && \ pip install beautifulsoup4 lxml # # 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-qt /opt/Qt/${QT_VERSION}/gcc_64/bin/qmake qt-gcc_64 && \ qbs config profiles.qt-gcc_64.baseProfile gcc && \ 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 qbs-src-2.5.1/.mailmap0000644000175100001660000000266014744424375014077 0ustar runnerdocker qbs-src-2.5.1/tutorial/0000755000175100001660000000000014744424375014315 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-1/0000755000175100001660000000000014744424375016101 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-1/myproject.qbs0000644000175100001660000000017114744424375020623 0ustar runnerdocker//! [0] Project { name: "My Project" minimumQbsVersion: "2.0" references: [ "app/app.qbs" ] } //! [0] qbs-src-2.5.1/tutorial/chapter-1/app/0000755000175100001660000000000014744424375016661 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-1/app/main.c0000644000175100001660000000013714744424375017752 0ustar runnerdocker//! [0] #include int main() { printf("Hello, world\n"); return 0; } //! [0] qbs-src-2.5.1/tutorial/chapter-1/app/app.qbs0000644000175100001660000000032114744424375020144 0ustar runnerdocker//! [0] CppApplication { name: "My Application" targetName: "myapp" files: "main.c" version: "1.0.0" consoleApplication: true install: true installDebugInformation: true } //! [0] qbs-src-2.5.1/tutorial/chapter-9/0000755000175100001660000000000014744424375016111 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-9/myproject.qbs0000644000175100001660000000134114744424375020633 0ustar runnerdockerProject { property string version: "1.0.0" property bool withTests: true property bool installDebugInformation: true property stringList autotestArguments: [] property stringList autotestWrapper: [] name: "My Project" minimumQbsVersion: "2.0" //! [0] // myproject.qbs references: [ "app/app.qbs", "lib/lib.qbs", "version-header/version-header.qbs", ] //! [0] qbsSearchPaths: "qbs" SubProject { filePath: "test/test.qbs" Properties { condition: parent.withTests } } AutotestRunner { condition: parent.withTests arguments: parent.autotestArguments wrapper: parent.autotestWrapper } } qbs-src-2.5.1/tutorial/chapter-9/version-header/0000755000175100001660000000000014744424375021024 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-9/version-header/version.h.in0000644000175100001660000000023614744424375023270 0ustar runnerdocker//! [0] // version-header/version.h.in #ifndef VERSION_H #define VERSION_H const char kProductVersion[] = "${PRODUCT_VERSION}"; #endif // VERSION_H //! [0] qbs-src-2.5.1/tutorial/chapter-9/version-header/version-header.qbs0000644000175100001660000000234514744424375024452 0ustar runnerdocker//! [5] // version-header/version-header.qbs //! [0] import qbs.TextFile Product { name: "version_header" type: "hpp" Depends { name: "mybuildconfig" } //! [0] //! [1] Group { files: ["version.h.in"] fileTags: ["version_h_in"] } //! [1] //! [2] Rule { inputs: ["version_h_in"] Artifact { filePath: "version.h" fileTags: "hpp" } //! [2] //! [3] prepare: { var cmd = new JavaScriptCommand(); cmd.description = "generating " + output.fileName; cmd.highlight = "codegen"; cmd.sourceCode = function() { var file = new TextFile(input.filePath, TextFile.ReadOnly); var content = file.readAll(); content = content.replace( "${PRODUCT_VERSION}", product.mybuildconfig.productVersion); file = new TextFile(output.filePath, TextFile.WriteOnly); file.write(content); file.close(); } return cmd; } //! [3] } //! [4] Export { Depends { name: "cpp" } cpp.includePaths: exportingProduct.buildDirectory } //! [4] } //! [5] qbs-src-2.5.1/tutorial/chapter-9/app/0000755000175100001660000000000014744424375016671 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-9/app/main.c0000644000175100001660000000033414744424375017761 0ustar runnerdocker//![0] #include #include #include int main() { printf("Hello, world\n"); printf("%s\n", get_string()); printf("ProductVersion = %s\n", kProductVersion); return 0; } //![0] qbs-src-2.5.1/tutorial/chapter-9/app/app.qbs0000644000175100001660000000025614744424375020163 0ustar runnerdocker//! [0] MyApplication { Depends { name: "mylib" } Depends { name: "version_header" } name: "My Application" targetName: "myapp" files: "main.c" } //! [0] qbs-src-2.5.1/tutorial/chapter-9/lib/0000755000175100001660000000000014744424375016657 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-9/lib/lib_global.h0000644000175100001660000000107514744424375021121 0ustar runnerdocker#ifndef LIB_GLOBAL_H #define LIB_GLOBAL_H #if defined(_WIN32) || defined(WIN32) #define MY_LIB_DECL_EXPORT __declspec(dllexport) #define MY_LIB_DECL_IMPORT __declspec(dllimport) #else #define MY_LIB_DECL_EXPORT __attribute__((visibility("default"))) #define MY_LIB_DECL_IMPORT __attribute__((visibility("default"))) #endif // ![0] // lib/lib_global.h #if defined(MYLIB_STATIC_LIBRARY) #define MYLIB_EXPORT #else #if defined(MYLIB_LIBRARY) #define MYLIB_EXPORT MY_LIB_DECL_EXPORT #else #define MYLIB_EXPORT MY_LIB_DECL_IMPORT #endif #endif // ![0] #endif // LIB_GLOBAL_H qbs-src-2.5.1/tutorial/chapter-9/lib/lib.c0000644000175100001660000000022414744424375017567 0ustar runnerdocker#include "lib.h" #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE not defined #endif const char *get_string() { return "Hello from library"; } qbs-src-2.5.1/tutorial/chapter-9/lib/lib.h0000644000175100001660000000015614744424375017600 0ustar runnerdocker#ifndef LIB_H #define LIB_H #include "lib_global.h" MYLIB_EXPORT const char *get_string(); #endif // LIB_H qbs-src-2.5.1/tutorial/chapter-9/lib/lib.qbs0000644000175100001660000000022614744424375020134 0ustar runnerdockerMyLibrary { name: "mylib" files: [ "lib.c", "lib.h", ] Depends { name: 'cpp' } cpp.defines: ['CRUCIAL_DEFINE'] } qbs-src-2.5.1/tutorial/chapter-9/test/0000755000175100001660000000000014744424375017070 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-9/test/test.c0000644000175100001660000000056214744424375020216 0ustar runnerdocker#include "lib.h" #include #include int main(int argc, char *argv[]) { if (argc > 2) { printf("usage: test [value]\n"); return 1; } const char *expected = argc == 2 ? argv[1] : "Hello from library"; if (strcmp(get_string(), expected) != 0) { printf("text differs\n"); return 1; } return 0; } qbs-src-2.5.1/tutorial/chapter-9/test/test.qbs0000644000175100001660000000012414744424375020553 0ustar runnerdockerMyAutoTest { Depends { name: "mylib" } name: "mytest" files: "test.c" } qbs-src-2.5.1/tutorial/chapter-9/qbs/0000755000175100001660000000000014744424375016676 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-9/qbs/imports/0000755000175100001660000000000014744424375020373 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-9/qbs/imports/MyAutoTest.qbs0000644000175100001660000000007014744424375023155 0ustar runnerdockerMyApplication { type: ["application", "autotest"] } qbs-src-2.5.1/tutorial/chapter-9/qbs/imports/MyApplication.qbs0000644000175100001660000000044414744424375023655 0ustar runnerdockerCppApplication { Depends { name: "mybuildconfig" } version: mybuildconfig.productVersion cpp.rpaths: mybuildconfig.libRPaths consoleApplication: true installDir: mybuildconfig.appInstallDir install: true installDebugInformation: project.installDebugInformation } qbs-src-2.5.1/tutorial/chapter-9/qbs/imports/MyLibrary.qbs0000644000175100001660000000173514744424375023022 0ustar runnerdocker// ![0] Library { Depends { name: "cpp" } Depends { name: "mybuildconfig" } type: mybuildconfig.staticBuild ? "staticlibrary" : "dynamiclibrary" version: mybuildconfig.productVersion install: !mybuildconfig.staticBuild || mybuildconfig.installStaticLib installDir: mybuildconfig.libInstallDir readonly property string _nameUpper : name.replace(" ", "_").toUpperCase() property string libraryMacro: _nameUpper + "_LIBRARY" property string staticLibraryMacro: _nameUpper + "_STATIC_LIBRARY" cpp.defines: mybuildconfig.staticBuild ? [staticLibraryMacro] : [libraryMacro] cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] cpp.defines: exportingProduct.mybuildconfig.staticBuild ? [exportingProduct.staticLibraryMacro] : [] } Depends { name: "bundle" } bundle.isBundle: false } // ![0] qbs-src-2.5.1/tutorial/chapter-9/qbs/modules/0000755000175100001660000000000014744424375020346 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-9/qbs/modules/mybuildconfig/0000755000175100001660000000000014744424375023201 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-9/qbs/modules/mybuildconfig/mybuildconfig.qbs0000644000175100001660000000157114744424375026547 0ustar runnerdockerimport qbs.FileInfo //! [0] // qbs/modules/mybuildconfig/mybuildconfig.qbs Module { Depends { name: "cpp" } property string productVersion: "1.0.0" // ... //! [0] property string appInstallDir: "bin" property string libDirName: "lib" property string libInstallDir: qbs.targetOS.contains("windows") ? "bin" : libDirName property bool staticBuild: false property bool installStaticLib: true property bool enableRPath: true property stringList libRPaths: { if (enableRPath && cpp.rpathOrigin && product.installDir) { return [ FileInfo.joinPaths( cpp.rpathOrigin, FileInfo.relativePath( FileInfo.joinPaths('/', product.installDir), FileInfo.joinPaths('/', libDirName))) ]; } return []; } } qbs-src-2.5.1/tutorial/LICENSE0000644000175100001660000000465714744424375015336 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 Ivan Komissarov (abbapoh@gmail.com) ** Contact: https://www.qt.io/licensing/ ** ** Files in this directory are part of the Qbs tutorial. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use these files 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. ** ** BSD License Usage ** Alternatively, you may use this these files under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/qbs-src-2.5.1/tutorial/chapter-6/0000755000175100001660000000000014744424375016106 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-6/myproject.qbs0000644000175100001660000000132714744424375020634 0ustar runnerdocker//! [0] Project { property string version: "1.0.0" property bool installDebugInformation: true property bool withTests: false property stringList autotestArguments: [] property stringList autotestWrapper: [] name: "My Project" minimumQbsVersion: "2.0" // ... //! [0] references: [ "app/app.qbs", "lib/lib.qbs", ] qbsSearchPaths: "qbs" //! [1] SubProject { filePath: "test/test.qbs" Properties { condition: parent.withTests } } //! [1] //! [2] AutotestRunner { condition: parent.withTests arguments: parent.autotestArguments wrapper: parent.autotestWrapper } //! [2] } qbs-src-2.5.1/tutorial/chapter-6/app/0000755000175100001660000000000014744424375016666 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-6/app/main.c0000644000175100001660000000020314744424375017751 0ustar runnerdocker#include #include "lib.h" int main() { printf("Hello, world\n"); printf("%s\n", get_string()); return 0; } qbs-src-2.5.1/tutorial/chapter-6/app/app.qbs0000644000175100001660000000016714744424375020161 0ustar runnerdockerMyApplication { Depends { name: "mylib" } name: "My Application" targetName: "myapp" files: "main.c" } qbs-src-2.5.1/tutorial/chapter-6/lib/0000755000175100001660000000000014744424375016654 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-6/lib/lib_global.h0000644000175100001660000000071714744424375021120 0ustar runnerdocker#ifndef LIB_GLOBAL_H #define LIB_GLOBAL_H #if defined(_WIN32) || defined(WIN32) #define MYLIB_DECL_EXPORT __declspec(dllexport) #define MYLIB_DECL_IMPORT __declspec(dllimport) #else #define MYLIB_DECL_EXPORT __attribute__((visibility("default"))) #define MYLIB_DECL_IMPORT __attribute__((visibility("default"))) #endif #if defined(MYLIB_LIBRARY) #define MYLIB_EXPORT MYLIB_DECL_EXPORT #else #define MYLIB_EXPORT MYLIB_DECL_IMPORT #endif #endif // LIB_GLOBAL_H qbs-src-2.5.1/tutorial/chapter-6/lib/lib.c0000644000175100001660000000022414744424375017564 0ustar runnerdocker#include "lib.h" #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE not defined #endif const char *get_string() { return "Hello from library"; } qbs-src-2.5.1/tutorial/chapter-6/lib/lib.h0000644000175100001660000000015614744424375017575 0ustar runnerdocker#ifndef LIB_H #define LIB_H #include "lib_global.h" MYLIB_EXPORT const char *get_string(); #endif // LIB_H qbs-src-2.5.1/tutorial/chapter-6/lib/lib.qbs0000644000175100001660000000023614744424375020132 0ustar runnerdockerMyLibrary { name: "mylib" files: [ "lib.c", "lib.h", "lib_global.h", ] cpp.defines: base.concat(['CRUCIAL_DEFINE']) } qbs-src-2.5.1/tutorial/chapter-6/test/0000755000175100001660000000000014744424375017065 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-6/test/test.c0000644000175100001660000000056214744424375020213 0ustar runnerdocker#include "lib.h" #include #include int main(int argc, char *argv[]) { if (argc > 2) { printf("usage: test [value]\n"); return 1; } const char *expected = argc == 2 ? argv[1] : "Hello from library"; if (strcmp(get_string(), expected) != 0) { printf("text differs\n"); return 1; } return 0; } qbs-src-2.5.1/tutorial/chapter-6/test/test.qbs0000644000175100001660000000012414744424375020550 0ustar runnerdockerMyAutoTest { Depends { name: "mylib" } name: "mytest" files: "test.c" } qbs-src-2.5.1/tutorial/chapter-6/qbs/0000755000175100001660000000000014744424375016673 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-6/qbs/imports/0000755000175100001660000000000014744424375020370 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-6/qbs/imports/MyAutoTest.qbs0000644000175100001660000000006614744424375023157 0ustar runnerdockerMyApplication { type: base.concat(["autotest"]) } qbs-src-2.5.1/tutorial/chapter-6/qbs/imports/MyApplication.qbs0000644000175100001660000000103014744424375023642 0ustar runnerdockerimport qbs.FileInfo //! [0] CppApplication { version: project.version consoleApplication: true install: true installDebugInformation: project.installDebugInformation // ... //! [0] cpp.rpaths: { if (!cpp.rpathOrigin) return []; return [ FileInfo.joinPaths( cpp.rpathOrigin, FileInfo.relativePath( FileInfo.joinPaths("/", product.installDir), FileInfo.joinPaths("/", "lib"))) ]; } } qbs-src-2.5.1/tutorial/chapter-6/qbs/imports/MyLibrary.qbs0000644000175100001660000000101114744424375023002 0ustar runnerdockerDynamicLibrary { version: project.version install: true installDebugInformation: project.installDebugInformation Depends { name: 'cpp' } property string libraryMacro: name.replace(" ", "_").toUpperCase() + "_LIBRARY" cpp.defines: [libraryMacro] cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] } Depends { name: 'bundle' } bundle.isBundle: false } qbs-src-2.5.1/tutorial/chapter-2/0000755000175100001660000000000014744424375016102 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-2/myproject.qbs0000644000175100001660000000021714744424375020625 0ustar runnerdocker//! [0] Project { name: "My Project" minimumQbsVersion: "2.0" references: [ "app/app.qbs", "lib/lib.qbs" ] } //! [0] qbs-src-2.5.1/tutorial/chapter-2/app/0000755000175100001660000000000014744424375016662 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-2/app/main.c0000644000175100001660000000020314744424375017745 0ustar runnerdocker#include #include "lib.h" int main() { printf("Hello, world\n"); printf("%s\n", get_string()); return 0; } qbs-src-2.5.1/tutorial/chapter-2/app/app.qbs0000644000175100001660000000033714744424375020154 0ustar runnerdockerCppApplication { Depends { name: "mylib" } name: "My Application" targetName: "myapp" files: "main.c" version: "1.0.0" consoleApplication: true install: true installDebugInformation: true } qbs-src-2.5.1/tutorial/chapter-2/lib/0000755000175100001660000000000014744424375016650 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-2/lib/lib.c0000644000175100001660000000026514744424375017565 0ustar runnerdocker//! [0] // lib/lib.cpp #include "lib.h" #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE not defined #endif const char *get_string() { return "Hello from library"; } //! [0] qbs-src-2.5.1/tutorial/chapter-2/lib/lib.h0000644000175100001660000000014714744424375017571 0ustar runnerdocker//! [0] // lib/lib.h #ifndef LIB_H #define LIB_H const char *get_string(); #endif // LIB_H //! [0] qbs-src-2.5.1/tutorial/chapter-2/lib/lib.qbs0000644000175100001660000000070514744424375020127 0ustar runnerdocker//! [0] StaticLibrary { name: "mylib" files: [ "lib.c", "lib.h", ] version: "1.0.0" install: true //! [1] Depends { name: 'cpp' } cpp.defines: ['CRUCIAL_DEFINE'] //! [1] //! [2] Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] } //! [2] //! [3] Depends { name: 'bundle' } bundle.isBundle: false //! [3] } //! [0] qbs-src-2.5.1/tutorial/chapter-10-1/0000755000175100001660000000000014744424375016317 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-10-1/myproject.qbs0000644000175100001660000000112614744424375021042 0ustar runnerdocker// myproject.qbs CppApplication { condition: { if (qbs.toolchainType === "msvc" || ((qbs.toolchainType === "gcc" || qbs.toolchainType === "mingw") && cpp.compilerVersionMajor >= 11) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) { return true; } console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } consoleApplication: true install: true files: ["hello.cppm", "main.cpp" ] cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true } qbs-src-2.5.1/tutorial/chapter-10-1/hello.cppm0000644000175100001660000000037114744424375020304 0ustar runnerdocker//![0] // hello.cppm module; #include #include export module hello; export namespace Hello { void printHello(std::string_view name) { std::cout << "Hello, " << name << '!' << std::endl; } } // namespace Hello //![0]qbs-src-2.5.1/tutorial/chapter-10-1/main.cpp0000644000175100001660000000013014744424375017741 0ustar runnerdocker//![0] // main.cpp import hello; int main() { Hello::printHello("World"); } //![0]qbs-src-2.5.1/tutorial/chapter-5/0000755000175100001660000000000014744424375016105 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-5/myproject.qbs0000644000175100001660000000040014744424375020622 0ustar runnerdockerProject { name: "My Project" minimumQbsVersion: "2.0" // ![0] references: [ "app/app.qbs", "lib/lib.qbs", "test/test.qbs", ] // ![0] qbsSearchPaths: "qbs" AutotestRunner { timeout: 60 } } qbs-src-2.5.1/tutorial/chapter-5/app/0000755000175100001660000000000014744424375016665 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-5/app/main.c0000644000175100001660000000020314744424375017750 0ustar runnerdocker#include #include "lib.h" int main() { printf("Hello, world\n"); printf("%s\n", get_string()); return 0; } qbs-src-2.5.1/tutorial/chapter-5/app/app.qbs0000644000175100001660000000016714744424375020160 0ustar runnerdockerMyApplication { Depends { name: "mylib" } name: "My Application" targetName: "myapp" files: "main.c" } qbs-src-2.5.1/tutorial/chapter-5/lib/0000755000175100001660000000000014744424375016653 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-5/lib/lib_global.h0000644000175100001660000000071714744424375021117 0ustar runnerdocker#ifndef LIB_GLOBAL_H #define LIB_GLOBAL_H #if defined(_WIN32) || defined(WIN32) #define MYLIB_DECL_EXPORT __declspec(dllexport) #define MYLIB_DECL_IMPORT __declspec(dllimport) #else #define MYLIB_DECL_EXPORT __attribute__((visibility("default"))) #define MYLIB_DECL_IMPORT __attribute__((visibility("default"))) #endif #if defined(MYLIB_LIBRARY) #define MYLIB_EXPORT MYLIB_DECL_EXPORT #else #define MYLIB_EXPORT MYLIB_DECL_IMPORT #endif #endif // LIB_GLOBAL_H qbs-src-2.5.1/tutorial/chapter-5/lib/lib.c0000644000175100001660000000022414744424375017563 0ustar runnerdocker#include "lib.h" #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE not defined #endif const char *get_string() { return "Hello from library"; } qbs-src-2.5.1/tutorial/chapter-5/lib/lib.h0000644000175100001660000000015614744424375017574 0ustar runnerdocker#ifndef LIB_H #define LIB_H #include "lib_global.h" MYLIB_EXPORT const char *get_string(); #endif // LIB_H qbs-src-2.5.1/tutorial/chapter-5/lib/lib.qbs0000644000175100001660000000023614744424375020131 0ustar runnerdockerMyLibrary { name: "mylib" files: [ "lib.c", "lib.h", "lib_global.h", ] cpp.defines: base.concat(['CRUCIAL_DEFINE']) } qbs-src-2.5.1/tutorial/chapter-5/test/0000755000175100001660000000000014744424375017064 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-5/test/test.c0000644000175100001660000000062114744424375020206 0ustar runnerdocker//! [0] // test/test.c #include "lib.h" #include #include int main(int argc, char *argv[]) { if (argc > 2) { printf("usage: test [value]\n"); return 1; } const char *expected = argc == 2 ? argv[1] : "Hello from library"; if (strcmp(get_string(), expected) != 0) { printf("text differs\n"); return 1; } return 0; } //! [0]qbs-src-2.5.1/tutorial/chapter-5/test/test.qbs0000644000175100001660000000016614744424375020555 0ustar runnerdocker//! [0] // test/test.qbs MyAutoTest { Depends { name: "mylib" } name: "mytest" files: "test.c" } //! [0] qbs-src-2.5.1/tutorial/chapter-5/qbs/0000755000175100001660000000000014744424375016672 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-5/qbs/imports/0000755000175100001660000000000014744424375020367 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-5/qbs/imports/MyAutoTest.qbs0000644000175100001660000000014514744424375023154 0ustar runnerdocker//! [0] // qbs/imports/MyAutoTest.qbs MyApplication { type: base.concat(["autotest"]) } //! [0] qbs-src-2.5.1/tutorial/chapter-5/qbs/imports/MyApplication.qbs0000644000175100001660000000072614744424375023654 0ustar runnerdockerimport qbs.FileInfo CppApplication { version: "1.0.0" consoleApplication: true install: true installDebugInformation: true cpp.rpaths: { if (!cpp.rpathOrigin) return []; return [ FileInfo.joinPaths( cpp.rpathOrigin, FileInfo.relativePath( FileInfo.joinPaths("/", product.installDir), FileInfo.joinPaths("/", "lib"))) ]; } } qbs-src-2.5.1/tutorial/chapter-5/qbs/imports/MyLibrary.qbs0000644000175100001660000000070414744424375023011 0ustar runnerdockerDynamicLibrary { version: "1.0.0" install: true Depends { name: 'cpp' } property string libraryMacro: name.replace(" ", "_").toUpperCase() + "_LIBRARY" cpp.defines: [libraryMacro] cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] } Depends { name: 'bundle' } bundle.isBundle: false } qbs-src-2.5.1/tutorial/chapter-7/0000755000175100001660000000000014744424375016107 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-7/myproject.qbs0000644000175100001660000000114214744424375020630 0ustar runnerdockerProject { property bool withTests: true property bool installDebugInformation: true property stringList autotestArguments: [] property stringList autotestWrapper: [] name: "My Project" minimumQbsVersion: "2.0" references: [ "app/app.qbs", "lib/lib.qbs", ] qbsSearchPaths: "qbs" SubProject { filePath: "test/test.qbs" Properties { condition: parent.withTests } } AutotestRunner { condition: parent.withTests arguments: parent.autotestArguments wrapper: parent.autotestWrapper } } qbs-src-2.5.1/tutorial/chapter-7/app/0000755000175100001660000000000014744424375016667 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-7/app/main.c0000644000175100001660000000020314744424375017752 0ustar runnerdocker#include #include "lib.h" int main() { printf("Hello, world\n"); printf("%s\n", get_string()); return 0; } qbs-src-2.5.1/tutorial/chapter-7/app/app.qbs0000644000175100001660000000016714744424375020162 0ustar runnerdockerMyApplication { Depends { name: "mylib" } name: "My Application" targetName: "myapp" files: "main.c" } qbs-src-2.5.1/tutorial/chapter-7/lib/0000755000175100001660000000000014744424375016655 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-7/lib/lib_global.h0000644000175100001660000000071714744424375021121 0ustar runnerdocker#ifndef LIB_GLOBAL_H #define LIB_GLOBAL_H #if defined(_WIN32) || defined(WIN32) #define MYLIB_DECL_EXPORT __declspec(dllexport) #define MYLIB_DECL_IMPORT __declspec(dllimport) #else #define MYLIB_DECL_EXPORT __attribute__((visibility("default"))) #define MYLIB_DECL_IMPORT __attribute__((visibility("default"))) #endif #if defined(MYLIB_LIBRARY) #define MYLIB_EXPORT MYLIB_DECL_EXPORT #else #define MYLIB_EXPORT MYLIB_DECL_IMPORT #endif #endif // LIB_GLOBAL_H qbs-src-2.5.1/tutorial/chapter-7/lib/lib.c0000644000175100001660000000022414744424375017565 0ustar runnerdocker#include "lib.h" #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE not defined #endif const char *get_string() { return "Hello from library"; } qbs-src-2.5.1/tutorial/chapter-7/lib/lib.h0000644000175100001660000000015614744424375017576 0ustar runnerdocker#ifndef LIB_H #define LIB_H #include "lib_global.h" MYLIB_EXPORT const char *get_string(); #endif // LIB_H qbs-src-2.5.1/tutorial/chapter-7/lib/lib.qbs0000644000175100001660000000504214744424375020133 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of Qbs. ** ** $QT_BEGIN_LICENSE:BSD$ ** 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. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ MyLibrary { name: "mylib" files: [ "lib.c", "lib.h", ] Depends { name: 'cpp' } cpp.defines: ['CRUCIAL_DEFINE'] } qbs-src-2.5.1/tutorial/chapter-7/test/0000755000175100001660000000000014744424375017066 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-7/test/test.c0000644000175100001660000000056214744424375020214 0ustar runnerdocker#include "lib.h" #include #include int main(int argc, char *argv[]) { if (argc > 2) { printf("usage: test [value]\n"); return 1; } const char *expected = argc == 2 ? argv[1] : "Hello from library"; if (strcmp(get_string(), expected) != 0) { printf("text differs\n"); return 1; } return 0; } qbs-src-2.5.1/tutorial/chapter-7/test/test.qbs0000644000175100001660000000012414744424375020551 0ustar runnerdockerMyAutoTest { Depends { name: "mylib" } name: "mytest" files: "test.c" } qbs-src-2.5.1/tutorial/chapter-7/qbs/0000755000175100001660000000000014744424375016674 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-7/qbs/imports/0000755000175100001660000000000014744424375020371 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-7/qbs/imports/MyAutoTest.qbs0000644000175100001660000000007014744424375023153 0ustar runnerdockerMyApplication { type: ["application", "autotest"] } qbs-src-2.5.1/tutorial/chapter-7/qbs/imports/MyApplication.qbs0000644000175100001660000000040314744424375023646 0ustar runnerdocker//! [0] CppApplication { Depends { name: "mybuildconfig" } installDir: mybuildconfig.appInstallDir version: "1.0.0" // ... //! [0] consoleApplication: true install: true installDebugInformation: project.installDebugInformation } qbs-src-2.5.1/tutorial/chapter-7/qbs/imports/MyLibrary.qbs0000644000175100001660000000123614744424375023014 0ustar runnerdockerDynamicLibrary { version: project.version install: true installDebugInformation: project.installDebugInformation //! [0] // qbs/imports/MyLibrary.qbs // ... Depends { name: "mybuildconfig" } installDir: mybuildconfig.libInstallDir Depends { name: "cpp" } property string libraryMacro: name.replace(" ", "_").toUpperCase() + "_LIBRARY" cpp.defines: [libraryMacro] cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined Export { // ... //! [0] Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] } Depends { name: 'bundle' } bundle.isBundle: false } qbs-src-2.5.1/tutorial/chapter-7/qbs/modules/0000755000175100001660000000000014744424375020344 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-7/qbs/modules/mybuildconfig/0000755000175100001660000000000014744424375023177 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-7/qbs/modules/mybuildconfig/mybuildconfig.qbs0000644000175100001660000000137314744424375026545 0ustar runnerdockerimport qbs.FileInfo //! [1] //! [0] // qbs/modules/mybuildconfig.qbs Module { property string appInstallDir: "bin" property string libDirName: "lib" property string libInstallDir: qbs.targetOS.contains("windows") ? appInstallDir : libDirName //! [0] Depends { name: "cpp" } property bool enableRPath: true property stringList libRPaths: { if (enableRPath && cpp.rpathOrigin && product.installDir) { return [FileInfo.joinPaths(cpp.rpathOrigin, FileInfo.relativePath( FileInfo.joinPaths('/', product.installDir), FileInfo.joinPaths('/', libInstallDir)))]; } return []; } cpp.rpaths: libRPaths } //! [1] qbs-src-2.5.1/tutorial/tutorial.qbs0000644000175100001660000000005714744424375016671 0ustar runnerdockerProduct { files: [ "*/**", ] } qbs-src-2.5.1/tutorial/chapter-10-2/0000755000175100001660000000000014744424375016320 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-10-2/myproject.qbs0000644000175100001660000000017714744424375021050 0ustar runnerdockerProject { name: "My Project" minimumQbsVersion: "2.5" references: [ "app/app.qbs", "lib/lib.qbs" ] } qbs-src-2.5.1/tutorial/chapter-10-2/app/0000755000175100001660000000000014744424375017100 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-10-2/app/main.cpp0000644000175100001660000000007614744424375020533 0ustar runnerdockerimport hello; int main() { Hello::printHello("world"); } qbs-src-2.5.1/tutorial/chapter-10-2/app/app.qbs0000644000175100001660000000106314744424375020367 0ustar runnerdockerCppApplication { condition: qbs.toolchainType === "msvc" || (qbs.toolchainType === "gcc" && cpp.compilerVersionMajor >= 11) || (qbs.toolchainType === "mingw" && cpp.compilerVersionMajor >= 13) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16) consoleApplication: true name: "app" files: ["main.cpp"] install: true cpp.rpaths: [cpp.rpathOrigin + "/../lib"] cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true cpp.treatWarningsAsErrors: true Depends { name: "mylib" } } qbs-src-2.5.1/tutorial/chapter-10-2/lib/0000755000175100001660000000000014744424375017066 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-10-2/lib/hello.cppm0000644000175100001660000000044214744424375021052 0ustar runnerdocker//![0] // lib/hello.cppm module; #include "lib_global.h" #include #include export module hello; export namespace Hello { void MYLIB_EXPORT printHello(std::string_view name) { std::cout << "Hello, " << name << '!' << std::endl; } } // namespace Hello //![0]qbs-src-2.5.1/tutorial/chapter-10-2/lib/lib_global.h0000644000175100001660000000076514744424375021335 0ustar runnerdocker//! [0] // lib/lib_global.h #ifndef LIB_GLOBAL_H #define LIB_GLOBAL_H #if defined(_WIN32) || defined(WIN32) #define MYLIB_DECL_EXPORT __declspec(dllexport) #define MYLIB_DECL_IMPORT __declspec(dllimport) #else #define MYLIB_DECL_EXPORT __attribute__((visibility("default"))) #define MYLIB_DECL_IMPORT __attribute__((visibility("default"))) #endif #if defined(MYLIB_LIBRARY) #define MYLIB_EXPORT MYLIB_DECL_EXPORT #else #define MYLIB_EXPORT MYLIB_DECL_IMPORT #endif #endif // LIB_GLOBAL_H //! [0] qbs-src-2.5.1/tutorial/chapter-10-2/lib/lib.qbs0000644000175100001660000000151514744424375020345 0ustar runnerdocker//! [0] // lib/lib.qbs DynamicLibrary { condition: { if (qbs.toolchainType === "msvc" || (qbs.toolchainType === "gcc" && cpp.compilerVersionMajor >= 11) || (qbs.toolchainType === "mingw" && cpp.compilerVersionMajor >= 13) || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 16)) { return true; } console.info("Unsupported toolchainType " + qbs.toolchainType); return false; } name: "mylib" files: ["hello.cppm", "lib_global.h"] version: "1.0.0" install: true Depends { name: "cpp" } cpp.defines: "MYLIB_LIBRARY" cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined cpp.cxxLanguageVersion: "c++20" cpp.forceUseCxxModules: true Depends { name: "bundle" } bundle.isBundle: false } qbs-src-2.5.1/tutorial/chapter-3/0000755000175100001660000000000014744424375016103 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-3/myproject.qbs0000644000175100001660000000017714744424375020633 0ustar runnerdockerProject { name: "My Project" minimumQbsVersion: "2.0" references: [ "app/app.qbs", "lib/lib.qbs" ] } qbs-src-2.5.1/tutorial/chapter-3/app/0000755000175100001660000000000014744424375016663 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-3/app/main.c0000644000175100001660000000020314744424375017746 0ustar runnerdocker#include #include "lib.h" int main() { printf("Hello, world\n"); printf("%s\n", get_string()); return 0; } qbs-src-2.5.1/tutorial/chapter-3/app/app.qbs0000644000175100001660000000112114744424375020145 0ustar runnerdocker//! [1] // app/app.qbs import qbs.FileInfo CppApplication { Depends { name: "mylib" } name: "My Application" targetName: "myapp" files: "main.c" version: "1.0.0" consoleApplication: true install: true //! [0] cpp.rpaths: { if (!cpp.rpathOrigin) return []; return [ FileInfo.joinPaths( cpp.rpathOrigin, FileInfo.relativePath( FileInfo.joinPaths("/", product.installDir), FileInfo.joinPaths("/", "lib"))) ]; } //! [0] } //! [1] qbs-src-2.5.1/tutorial/chapter-3/lib/0000755000175100001660000000000014744424375016651 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-3/lib/lib_global.h0000644000175100001660000000076514744424375021120 0ustar runnerdocker//! [0] // lib/lib_global.h #ifndef LIB_GLOBAL_H #define LIB_GLOBAL_H #if defined(_WIN32) || defined(WIN32) #define MYLIB_DECL_EXPORT __declspec(dllexport) #define MYLIB_DECL_IMPORT __declspec(dllimport) #else #define MYLIB_DECL_EXPORT __attribute__((visibility("default"))) #define MYLIB_DECL_IMPORT __attribute__((visibility("default"))) #endif #if defined(MYLIB_LIBRARY) #define MYLIB_EXPORT MYLIB_DECL_EXPORT #else #define MYLIB_EXPORT MYLIB_DECL_IMPORT #endif #endif // LIB_GLOBAL_H //! [0] qbs-src-2.5.1/tutorial/chapter-3/lib/lib.c0000644000175100001660000000026614744424375017567 0ustar runnerdocker //! [0] // lib/lib.cpp #include "lib.h" #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE not defined #endif const char *get_string() { return "Hello from library"; } //! [0] qbs-src-2.5.1/tutorial/chapter-3/lib/lib.h0000644000175100001660000000021314744424375017564 0ustar runnerdocker#ifndef LIB_H #define LIB_H //! [0] // lib/lib.h #include "lib_global.h" MYLIB_EXPORT const char *get_string(); //! [0] #endif // LIB_H qbs-src-2.5.1/tutorial/chapter-3/lib/lib.qbs0000644000175100001660000000100414744424375020121 0ustar runnerdocker//! [0] // lib/lib.qbs DynamicLibrary { name: "mylib" files: [ "lib.c", "lib.h", "lib_global.h", ] version: "1.0.0" install: true Depends { name: "cpp" } cpp.defines: ["MYLIB_LIBRARY", "CRUCIAL_DEFINE"] cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] } Depends { name: "bundle" } bundle.isBundle: false } //! [0] qbs-src-2.5.1/tutorial/chapter-4/0000755000175100001660000000000014744424375016104 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-4/myproject.qbs0000644000175100001660000000025014744424375020624 0ustar runnerdocker//! [0] Project { name: "My Project" minimumQbsVersion: "2.0" references: [ "app/app.qbs", "lib/lib.qbs" ] qbsSearchPaths: "qbs" } //! [0] qbs-src-2.5.1/tutorial/chapter-4/app/0000755000175100001660000000000014744424375016664 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-4/app/main.c0000644000175100001660000000020314744424375017747 0ustar runnerdocker#include #include "lib.h" int main() { printf("Hello, world\n"); printf("%s\n", get_string()); return 0; } qbs-src-2.5.1/tutorial/chapter-4/app/app.qbs0000644000175100001660000000022714744424375020154 0ustar runnerdocker//! [0] // app/app.qbs MyApplication { Depends { name: "mylib" } name: "My Application" targetName: "myapp" files: "main.c" } //! [0] qbs-src-2.5.1/tutorial/chapter-4/lib/0000755000175100001660000000000014744424375016652 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-4/lib/lib_global.h0000644000175100001660000000071714744424375021116 0ustar runnerdocker#ifndef LIB_GLOBAL_H #define LIB_GLOBAL_H #if defined(_WIN32) || defined(WIN32) #define MYLIB_DECL_EXPORT __declspec(dllexport) #define MYLIB_DECL_IMPORT __declspec(dllimport) #else #define MYLIB_DECL_EXPORT __attribute__((visibility("default"))) #define MYLIB_DECL_IMPORT __attribute__((visibility("default"))) #endif #if defined(MYLIB_LIBRARY) #define MYLIB_EXPORT MYLIB_DECL_EXPORT #else #define MYLIB_EXPORT MYLIB_DECL_IMPORT #endif #endif // LIB_GLOBAL_H qbs-src-2.5.1/tutorial/chapter-4/lib/lib.c0000644000175100001660000000022414744424375017562 0ustar runnerdocker#include "lib.h" #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE not defined #endif const char *get_string() { return "Hello from library"; } qbs-src-2.5.1/tutorial/chapter-4/lib/lib.h0000644000175100001660000000015614744424375017573 0ustar runnerdocker#ifndef LIB_H #define LIB_H #include "lib_global.h" MYLIB_EXPORT const char *get_string(); #endif // LIB_H qbs-src-2.5.1/tutorial/chapter-4/lib/lib.qbs0000644000175100001660000000027614744424375020134 0ustar runnerdocker//! [0] // lib/lib.qbs MyLibrary { name: "mylib" files: [ "lib.c", "lib.h", "lib_global.h", ] cpp.defines: base.concat(["CRUCIAL_DEFINE"]) } //! [0] qbs-src-2.5.1/tutorial/chapter-4/qbs/0000755000175100001660000000000014744424375016671 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-4/qbs/imports/0000755000175100001660000000000014744424375020366 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-4/qbs/imports/MyApplication.qbs0000644000175100001660000000074614744424375023655 0ustar runnerdocker//! [0] // qbs/imports/MyApplication.qbs import qbs.FileInfo CppApplication { version: "1.0.0" consoleApplication: true install: true cpp.rpaths: { if (!cpp.rpathOrigin) return []; return [ FileInfo.joinPaths( cpp.rpathOrigin, FileInfo.relativePath( FileInfo.joinPaths("/", product.installDir), FileInfo.joinPaths("/", "lib"))) ]; } } //! [0] qbs-src-2.5.1/tutorial/chapter-4/qbs/imports/MyLibrary.qbs0000644000175100001660000000076214744424375023014 0ustar runnerdocker//! [0] // qbs/imports/MyLibrary.qbs DynamicLibrary { version: "1.0.0" install: true Depends { name: 'cpp' } property string libraryMacro: name.replace(" ", "_").toUpperCase() + "_LIBRARY" cpp.defines: [libraryMacro] cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] } Depends { name: 'bundle' } bundle.isBundle: false } //! [0] qbs-src-2.5.1/tutorial/chapter-8/0000755000175100001660000000000014744424375016110 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-8/myproject.qbs0000644000175100001660000000114214744424375020631 0ustar runnerdockerProject { property bool withTests: true property bool installDebugInformation: true property stringList autotestArguments: [] property stringList autotestWrapper: [] name: "My Project" minimumQbsVersion: "2.0" references: [ "app/app.qbs", "lib/lib.qbs", ] qbsSearchPaths: "qbs" SubProject { filePath: "test/test.qbs" Properties { condition: parent.withTests } } AutotestRunner { condition: parent.withTests arguments: parent.autotestArguments wrapper: parent.autotestWrapper } } qbs-src-2.5.1/tutorial/chapter-8/app/0000755000175100001660000000000014744424375016670 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-8/app/main.c0000644000175100001660000000020314744424375017753 0ustar runnerdocker#include #include "lib.h" int main() { printf("Hello, world\n"); printf("%s\n", get_string()); return 0; } qbs-src-2.5.1/tutorial/chapter-8/app/app.qbs0000644000175100001660000000016714744424375020163 0ustar runnerdockerMyApplication { Depends { name: "mylib" } name: "My Application" targetName: "myapp" files: "main.c" } qbs-src-2.5.1/tutorial/chapter-8/lib/0000755000175100001660000000000014744424375016656 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-8/lib/lib_global.h0000644000175100001660000000107414744424375021117 0ustar runnerdocker#ifndef LIB_GLOBAL_H #define LIB_GLOBAL_H #if defined(_WIN32) || defined(WIN32) #define MY_LIB_DECL_EXPORT __declspec(dllexport) #define MY_LIB_DECL_IMPORT __declspec(dllimport) #else #define MY_LIB_DECL_EXPORT __attribute__((visibility("default"))) #define MY_LIB_DECL_IMPORT __attribute__((visibility("default"))) #endif // ![0] // lib/lib_global.h #if defined(MYLIB_STATIC_LIBRARY) #define MYLIB_EXPORT #else #if defined(MYLIB_LIBRARY) #define MYLIB_EXPORT MY_LIB_DECL_EXPORT #else #define MYLIB_EXPORT MY_LIB_DECL_IMPORT #endif #endif // ![0] #endif // LIB_GLOBAL_Hqbs-src-2.5.1/tutorial/chapter-8/lib/lib.c0000644000175100001660000000022414744424375017566 0ustar runnerdocker#include "lib.h" #ifndef CRUCIAL_DEFINE # error CRUCIAL_DEFINE not defined #endif const char *get_string() { return "Hello from library"; } qbs-src-2.5.1/tutorial/chapter-8/lib/lib.h0000644000175100001660000000015614744424375017577 0ustar runnerdocker#ifndef LIB_H #define LIB_H #include "lib_global.h" MYLIB_EXPORT const char *get_string(); #endif // LIB_H qbs-src-2.5.1/tutorial/chapter-8/lib/lib.qbs0000644000175100001660000000022614744424375020133 0ustar runnerdockerMyLibrary { name: "mylib" files: [ "lib.c", "lib.h", ] Depends { name: 'cpp' } cpp.defines: ['CRUCIAL_DEFINE'] } qbs-src-2.5.1/tutorial/chapter-8/test/0000755000175100001660000000000014744424375017067 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-8/test/test.c0000644000175100001660000000056214744424375020215 0ustar runnerdocker#include "lib.h" #include #include int main(int argc, char *argv[]) { if (argc > 2) { printf("usage: test [value]\n"); return 1; } const char *expected = argc == 2 ? argv[1] : "Hello from library"; if (strcmp(get_string(), expected) != 0) { printf("text differs\n"); return 1; } return 0; } qbs-src-2.5.1/tutorial/chapter-8/test/test.qbs0000644000175100001660000000012414744424375020552 0ustar runnerdockerMyAutoTest { Depends { name: "mylib" } name: "mytest" files: "test.c" } qbs-src-2.5.1/tutorial/chapter-8/qbs/0000755000175100001660000000000014744424375016675 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-8/qbs/imports/0000755000175100001660000000000014744424375020372 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-8/qbs/imports/MyAutoTest.qbs0000644000175100001660000000007014744424375023154 0ustar runnerdockerMyApplication { type: ["application", "autotest"] } qbs-src-2.5.1/tutorial/chapter-8/qbs/imports/MyApplication.qbs0000644000175100001660000000041714744424375023654 0ustar runnerdockerCppApplication { Depends { name: "mybuildconfig" } version: "1.0.0" cpp.rpaths: mybuildconfig.libRPaths consoleApplication: true installDir: mybuildconfig.appInstallDir install: true installDebugInformation: project.installDebugInformation } qbs-src-2.5.1/tutorial/chapter-8/qbs/imports/MyLibrary.qbs0000644000175100001660000000171014744424375023012 0ustar runnerdocker// ![0] Library { Depends { name: "cpp" } Depends { name: "mybuildconfig" } type: mybuildconfig.staticBuild ? "staticlibrary" : "dynamiclibrary" version: "1.0.0" install: !mybuildconfig.staticBuild || mybuildconfig.installStaticLib installDir: mybuildconfig.libInstallDir readonly property string _nameUpper : name.replace(" ", "_").toUpperCase() property string libraryMacro: _nameUpper + "_LIBRARY" property string staticLibraryMacro: _nameUpper + "_STATIC_LIBRARY" cpp.defines: mybuildconfig.staticBuild ? [staticLibraryMacro] : [libraryMacro] cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined Export { Depends { name: "cpp" } cpp.includePaths: [exportingProduct.sourceDirectory] cpp.defines: exportingProduct.mybuildconfig.staticBuild ? [exportingProduct.staticLibraryMacro] : [] } Depends { name: "bundle" } bundle.isBundle: false } // ![0] qbs-src-2.5.1/tutorial/chapter-8/qbs/modules/0000755000175100001660000000000014744424375020345 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-8/qbs/modules/mybuildconfig/0000755000175100001660000000000014744424375023200 5ustar runnerdockerqbs-src-2.5.1/tutorial/chapter-8/qbs/modules/mybuildconfig/mybuildconfig.qbs0000644000175100001660000000137714744424375026552 0ustar runnerdockerimport qbs.FileInfo Module { Depends { name: "cpp" } property string appInstallDir: "bin" property string libDirName: "lib" property string libInstallDir: qbs.targetOS.contains("windows") ? "bin" : libDirName property bool staticBuild: false property bool installStaticLib: true property bool enableRPath: true property stringList libRPaths: { if (enableRPath && cpp.rpathOrigin && product.installDir) { return [ FileInfo.joinPaths( cpp.rpathOrigin, FileInfo.relativePath( FileInfo.joinPaths('/', product.installDir), FileInfo.joinPaths('/', libDirName))) ]; } return []; } } qbs-src-2.5.1/docker-compose.yml0000644000175100001660000000603514744424375016113 0ustar runnerdockerversion: "3.7" x-default-service: &linux working_dir: /qbs environment: - BUILD_OPTIONS - QTEST_FUNCTION_TIMEOUT - QBS_AUTOTEST_PROFILE - QBS_TEST_SOURCE_ROOT - WITH_ARCHIVE - WITH_TESTS - CLCACHE_DIR volumes: - .:/qbs - ~/.ccache:/home/devel/.ccache - /cores:/cores network_mode: bridge cap_add: - SYS_PTRACE ulimits: core: soft: -1 hard: -1 services: noble-qt6: &noble-qt6 << : *linux hostname: noble-qt6 image: ${DOCKER_USER:-qbsbuild}/qbsdev:noble-qt6-6.5.3_2.3.2-0 build: dockerfile: docker/noble/Dockerfile context: . args: QT_VERSION: 6.5.3 QTCREATOR_VERSION: 13.0.2 noble: << : *noble-qt6 noble-qt5: << : *linux hostname: noble-qt5 image: ${DOCKER_USER:-qbsbuild}/qbsdev:noble-5.15.2_2.3.2-0 build: dockerfile: docker/noble/Dockerfile context: . args: QT_VERSION: 5.15.2 QTCREATOR_VERSION: 13.0.2 noble-android-65: << : *linux hostname: noble-android image: ${DOCKER_USER:-qbsbuild}/qbsdev:noble-android-6.5.0-0 build: dockerfile: docker/noble/test-android.Dockerfile context: . args: QT_VERSION: 6.5.0 ANDROID_NDK_VERSION: 25.1.8937393 noble-android-515: << : *linux hostname: noble-android image: ${DOCKER_USER:-qbsbuild}/qbsdev:noble-android-5.15.2-0 build: dockerfile: docker/noble/test-android.Dockerfile context: . args: QT_VERSION: 5.15.2 ANDROID_NDK_VERSION: 23.0.7599858 noble-android-ndk-r25: << : *linux hostname: noble-android image: ${DOCKER_USER:-qbsbuild}/qbsdev:noble-android-ndk-r25-0 build: dockerfile: docker/noble/test-android-no-qt.Dockerfile context: . args: ANDROID_NDK_VERSION: 25.1.8937393 noble-baremetal: << : *linux hostname: noble-baremetal image: ${DOCKER_USER:-qbsbuild}/qbsdev:noble-baremetal-0 build: dockerfile: docker/noble/test-baremetal.Dockerfile context: . noble-qt6-wasm: << : *linux hostname: noble-qt6-wasm image: ${DOCKER_USER:-qbsbuild}/qbsdev:noble-qt6-wasm-6.7.0-0 build: dockerfile: docker/noble/test-qt6-wasm.Dockerfile context: . args: QT_VERSION: 6.7.0 EMSCRIPTEN_VERSION: 3.1.50 leap: << : *linux hostname: leap image: ${DOCKER_USER:-qbsbuild}/qbsdev:leap-5.15.2_1.20.1-1 build: dockerfile: docker/leap/Dockerfile context: . args: QT_VERSION: 5.15.2 QTCREATOR_VERSION: 5.0.3 windows: image: ${DOCKER_USER:-qbsbuild}/qbsdev:windowsservercore-6.6.0_1.24.0-0 build: dockerfile: docker/windowsservercore/Dockerfile context: . args: QT_VERSION: 6.6.0 QTCREATOR_VERSION: 9.0.1 working_dir: 'C:/qbs' environment: - BUILD_OPTIONS - WITH_DOCS volumes: - type: bind source: . target: C:\qbs - type: bind source: ~/.ccache target: C:\.ccache network_mode: nat qbs-src-2.5.1/LICENSE.LGPLv210000644000175100001660000006350214744424375014553 0ustar runnerdocker GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! qbs-src-2.5.1/src/0000755000175100001660000000000014744424375013241 5ustar runnerdockerqbs-src-2.5.1/src/app/0000755000175100001660000000000014744424375014021 5ustar runnerdockerqbs-src-2.5.1/src/app/qbs-create-project/0000755000175100001660000000000014744424375017513 5ustar runnerdockerqbs-src-2.5.1/src/app/qbs-create-project/createproject.h0000644000175100001660000000651614744424375022526 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_CREATEPROJECT_H #define QBS_CREATEPROJECT_H #include #include #include #include #include #include QT_BEGIN_NAMESPACE class QDir; class QTextStream; QT_END_NAMESPACE enum class ProjectStructure { Flat, Composite }; class ProjectCreator { public: void run(const QString &topLevelDir, ProjectStructure projectStructure, const QStringList &whiteList, const QStringList &blacklist); private: enum ProductFlag { IsApp = 1, NeedsCpp = 2, NeedsQt = 4 }; Q_DECLARE_FLAGS(ProductFlags, ProductFlag) struct Project; void setupProject(Project *project); void serializeProject(const Project &project); void addGroups(QTextStream &stream, const QDir &baseDir, const Project &subProject); bool isSourceFile(const QString &fileName); ProductFlags getFlags(const Project &project); void getFlagsFromFileNames(const Project &project, ProductFlags &flags); void getFlagsFromFileContents(const Project &project, ProductFlags &flags); using ProjectPtr = std::unique_ptr; struct Project { QString dirPath; QString dirName; QStringList fileNames; std::vector subProjects; }; Project m_topLevelProject; ProjectStructure m_projectStructure = ProjectStructure::Flat; QList m_whiteList; QList m_blackList; }; #endif // QBS_CREATEPROJECT_H qbs-src-2.5.1/src/app/qbs-create-project/create-project-main.cpp0000644000175100001660000001051714744424375024054 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "createproject.h" #include #include #include #include #include #include #include #include #include int main(int argc, char *argv[]) { using qbs::ErrorInfo; using qbs::Internal::Tr; QCoreApplication app(argc, argv); const QCommandLineOption flatOpt(QStringLiteral("flat"), Tr::tr("Do not create nested project files, even if there are subdirectories and " "the top-level directory does not contain any files.")); const QCommandLineOption whiteListOpt(QStringLiteral("whitelist"), Tr::tr("Only consider files whose names match these patterns. The list entries " "can contain wildcards and are separated by commas. By default, all files " "are considered."), QStringLiteral("whitelist")); const QCommandLineOption blackListOpt(QStringLiteral("blacklist"), Tr::tr("Ignore files whose names match these patterns. The list entries " "can contain wildcards and are separated by commas. By default, no files " "are ignored."), QStringLiteral("blacklist")); QCommandLineParser parser; parser.setApplicationDescription(Tr::tr("This tool creates a qbs project from an existing " "source tree.\nNote: The resulting project file(s) " "will likely require manual editing.")); parser.addOption(flatOpt); parser.addOption(whiteListOpt); parser.addOption(blackListOpt); parser.addHelpOption(); parser.process(app); const ProjectStructure projectStructure = parser.isSet(flatOpt) ? ProjectStructure::Flat : ProjectStructure::Composite; const QStringList whiteList = parser.value(whiteListOpt).split(QLatin1Char(','), Qt::SkipEmptyParts); const QStringList blackList = parser.value(blackListOpt).split(QLatin1Char(','), Qt::SkipEmptyParts); try { ProjectCreator().run(QDir::currentPath(), projectStructure, whiteList, blackList); } catch (const ErrorInfo &e) { std::cerr << qPrintable(Tr::tr("Error creating project: %1").arg(e.toString())) << std::endl; return 1; } } qbs-src-2.5.1/src/app/qbs-create-project/createproject.cpp0000644000175100001660000002332414744424375023055 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "createproject.h" #include #include #include #include #include #include #include #include #include #include #include using qbs::ErrorInfo; using qbs::Internal::Tr; static const char *indent = " "; void ProjectCreator::run(const QString &topLevelDir, ProjectStructure projectStructure, const QStringList &whiteList, const QStringList &blackList) { m_projectStructure = projectStructure; qbs::Internal::transform(whiteList, m_whiteList, [](const QString &s) { return QRegularExpression(QRegularExpression::wildcardToRegularExpression(s)); }); qbs::Internal::transform(blackList, m_blackList, [](const QString &s) { return QRegularExpression(QRegularExpression::wildcardToRegularExpression(s)); }); m_topLevelProject.dirPath = topLevelDir; setupProject(&m_topLevelProject); serializeProject(m_topLevelProject); } void ProjectCreator::setupProject(Project *project) { QDirIterator dit(project->dirPath, QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); while (dit.hasNext()) { dit.next(); if (dit.fileInfo().isFile()) { if (dit.fileName().endsWith(QLatin1String(".qbs"))) throw ErrorInfo(Tr::tr("Project already contains qbs files, aborting.")); if (isSourceFile(dit.fileName())) project->fileNames << dit.fileName(); } else if (dit.fileInfo().isDir()) { ProjectPtr subProject(new Project); subProject->dirName = dit.fileName(); subProject->dirPath = dit.filePath(); setupProject(subProject.get()); if (!subProject->fileNames.empty() || !subProject->subProjects.empty()) project->subProjects.push_back(std::move(subProject)); } } project->fileNames.sort(); std::sort(project->subProjects.begin(), project->subProjects.end(), [](const ProjectPtr &p1, const ProjectPtr &p2) { return p1->dirName < p2->dirName; }); } void ProjectCreator::serializeProject(const ProjectCreator::Project &project) { const QString fileName = QFileInfo(project.dirPath).baseName() + QLatin1String(".qbs"); QFile projectFile(project.dirPath + QLatin1Char('/') + fileName); if (!projectFile.open(QIODevice::WriteOnly)) { throw ErrorInfo(Tr::tr("Failed to open '%1' for writing: %2") .arg(projectFile.fileName(), projectFile.errorString())); } QTextStream fileContents(&projectFile); qbs::setupDefaultCodec(fileContents); if (!project.fileNames.empty() || m_projectStructure == ProjectStructure::Flat) { fileContents << "Product {\n"; const ProductFlags productFlags = getFlags(project); if (productFlags.testFlag(IsApp)) { fileContents << indent << "type: [\"application\"]\n"; } else { fileContents << indent << "type: [\"unknown\"] // E.g. \"application\", " "\"dynamiclibrary\", \"staticlibrary\"\n"; } if (productFlags.testFlag(NeedsQt)) { fileContents << indent << "Depends {\n"; fileContents << indent << indent << "name: \"Qt\"\n"; fileContents << indent << indent << "submodules: [\"core\"] " "// Add more here if needed\n"; fileContents << indent << "}\n"; } else if (productFlags.testFlag(NeedsCpp)) { fileContents << indent << "Depends { name: \"cpp\" }\n"; } fileContents << indent << "files: [\n"; for (const QString &fileName : std::as_const(project.fileNames)) fileContents << indent << indent << qbs::toJSLiteral(fileName) << ",\n"; fileContents << indent << "]\n"; for (const ProjectPtr &p : project.subProjects) addGroups(fileContents, QDir(project.dirPath), *p); } else { fileContents << "Project {\n"; fileContents << indent << "references: [\n"; for (const ProjectPtr &p : project.subProjects) { serializeProject(*p); fileContents << indent << indent << qbs::toJSLiteral(QFileInfo(p->dirPath).fileName()) << ",\n"; } fileContents << indent << "]\n"; } fileContents << "}\n"; } void ProjectCreator::addGroups(QTextStream &stream, const QDir &baseDir, const ProjectCreator::Project &subProject) { stream << indent << "Group {\n"; stream << indent << indent << "name: " << qbs::toJSLiteral(QFileInfo(subProject.dirPath).fileName()) << "\n"; stream << indent << indent << "prefix: " << qbs::toJSLiteral(baseDir.relativeFilePath(subProject.dirPath) + QLatin1Char('/')) << '\n'; stream << indent << indent << "files: [\n"; for (const QString &fileName : std::as_const(subProject.fileNames)) stream << indent << indent << indent << qbs::toJSLiteral(fileName) << ",\n"; stream << indent << indent << "]\n"; stream << indent << "}\n"; for (const ProjectPtr &p : subProject.subProjects) addGroups(stream, baseDir, *p); } bool ProjectCreator::isSourceFile(const QString &fileName) { const auto isMatch = [fileName](const QRegularExpression &rex) { return rex.match(fileName).hasMatch(); }; return !qbs::Internal::any_of(m_blackList, isMatch) && (m_whiteList.empty() || qbs::Internal::any_of(m_whiteList, isMatch)); } ProjectCreator::ProductFlags ProjectCreator::getFlags(const ProjectCreator::Project &project) { ProductFlags flags; getFlagsFromFileNames(project, flags); if (flags.testFlag(IsApp) && flags.testFlag(NeedsQt)) return flags; if (!flags.testFlag(NeedsCpp)) return flags; getFlagsFromFileContents(project, flags); return flags; } void ProjectCreator::getFlagsFromFileNames(const ProjectCreator::Project &project, ProductFlags &flags) { for (const QString &fileName : std::as_const(project.fileNames)) { if (flags.testFlag(IsApp) && flags.testFlag(NeedsQt)) return; const QFileInfo fi(project.dirPath + QLatin1Char('/') + fileName); const QString &suffix = fi.suffix(); if (suffix == QLatin1String("qrc")) { flags |= NeedsQt; continue; } if (suffix == QLatin1String("cpp") || suffix == QLatin1String("c") || suffix == QLatin1String("m") || suffix == QLatin1String("mm")) { flags |= NeedsCpp; } if (flags.testFlag(NeedsCpp) && fi.completeBaseName() == QLatin1String("main")) flags |= IsApp; } for (const ProjectPtr &p : project.subProjects) { getFlagsFromFileNames(*p, flags); if (flags.testFlag(IsApp) && flags.testFlag(NeedsQt)) return; } } void ProjectCreator::getFlagsFromFileContents(const ProjectCreator::Project &project, ProductFlags &flags) { for (const QString &fileName : std::as_const(project.fileNames)) { QFile f (project.dirPath + QLatin1Char('/') + fileName); if (!f.open(QIODevice::ReadOnly)) { qDebug() << "Ignoring failure to read" << f.fileName(); continue; } while (!f.atEnd()) { const QByteArray &line = f.readLine(); if (line.contains("#include namespace qbs { class Profile; class Settings; } void xcodeProbe(qbs::Settings *settings, std::vector &profiles); #endif // Header guard qbs-src-2.5.1/src/app/qbs-setup-toolchains/qbs-setup-toolchains.exe.manifest0000644000175100001660000000073614744424375026507 0ustar runnerdocker qbs-src-2.5.1/src/app/qbs-setup-toolchains/emscriptenprobe.h0000644000175100001660000000466714744424375023474 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 Danya Patrushev ** 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$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_EMSCRIPTENPROBE_H #define QBS_SETUPTOOLCHAINS_EMSCRIPTENPROBE_H #include QT_BEGIN_NAMESPACE class QFileInfo; class QString; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } // namespace qbs bool isEmscriptenCompiler(const QString &compilerName); qbs::Profile createEmscriptenProfile( const QFileInfo &compiler, qbs::Settings *settings, const QString &profileName = QString()); void emscriptenProbe(qbs::Settings *settings, std::vector &profiles); #endif // QBS_SETUPTOOLCHAINS_EMSCRIPTENPROBE_H qbs-src-2.5.1/src/app/qbs-setup-toolchains/msvcprobe.h0000644000175100001660000000445614744424375022267 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_MSVCPROBE_H #define QBS_SETUPTOOLCHAINS_MSVCPROBE_H #include #include QT_BEGIN_NAMESPACE class QFileInfo; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } void createMsvcProfile(const QFileInfo &compiler, qbs::Settings *settings, const QString &profileName); void msvcProbe(qbs::Settings *settings, std::vector &profiles); #endif // Header guard qbs-src-2.5.1/src/app/qbs-setup-toolchains/iarewprobe.h0000644000175100001660000000453314744424375022422 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** 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$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_IAREWPROBE_H #define QBS_SETUPTOOLCHAINS_IAREWPROBE_H #include QT_BEGIN_NAMESPACE class QFileInfo; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } bool isIarCompiler(const QString &compilerName); void createIarProfile(const QFileInfo &compiler, qbs::Settings *settings, QString profileName); void iarProbe(qbs::Settings *settings, std::vector &profiles); #endif // Header guard qbs-src-2.5.1/src/app/qbs-setup-toolchains/clangclprobe.h0000644000175100001660000000450414744424375022714 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://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$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_CLANGCLPROBE_H #define QBS_SETUPTOOLCHAINS_CLANGCLPROBE_H #include #include QT_BEGIN_NAMESPACE class QFileInfo; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } void createClangClProfile(const QFileInfo &compiler, qbs::Settings *settings, const QString &profileName); void clangClProbe(qbs::Settings *settings, std::vector &profiles); #endif // Header guard qbs-src-2.5.1/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs0000644000175100001660000000223414744424375024701 0ustar runnerdockerQbsApp { name: "qbs-setup-toolchains" cpp.dynamicLibraries: qbs.targetOS.contains("windows") ? base.concat("shell32") : base files: [ "clangclprobe.cpp", "clangclprobe.h", "commandlineparser.cpp", "commandlineparser.h", "cosmicprobe.cpp", "cosmicprobe.h", "dmcprobe.cpp", "dmcprobe.h", "emscriptenprobe.cpp", "emscriptenprobe.h", "gccprobe.cpp", "gccprobe.h", "iarewprobe.cpp", "iarewprobe.h", "keilprobe.cpp", "keilprobe.h", "main.cpp", "msvcprobe.cpp", "msvcprobe.h", "probe.cpp", "probe.h", "sdccprobe.cpp", "sdccprobe.h", "watcomprobe.cpp", "watcomprobe.h", "xcodeprobe.cpp", "xcodeprobe.h", ] Group { name: "MinGW specific files" condition: qbs.toolchain.contains("mingw") files: "qbs-setup-toolchains.rc" Group { name: "qbs-setup-toolchains manifest" files: "qbs-setup-toolchains.exe.manifest" fileTags: [] // the manifest is referenced by the rc file } } } qbs-src-2.5.1/src/app/qbs-setup-toolchains/sdccprobe.h0000644000175100001660000000520114744424375022220 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** 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$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_SDCCPROBE_H #define QBS_SETUPTOOLCHAINS_SDCCPROBE_H #include #include QT_BEGIN_NAMESPACE class QFileInfo; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } struct SdccInstallInfo { QString compilerPath; QString version; }; inline bool operator==(const SdccInstallInfo &lhs, const SdccInstallInfo &rhs) { return std::tie(lhs.compilerPath, lhs.version) == std::tie(rhs.compilerPath, rhs.version); } bool isSdccCompiler(const QString &compilerName); void createSdccProfile(const QFileInfo &compiler, qbs::Settings *settings, const QString &profileName); void sdccProbe(qbs::Settings *settings, std::vector &profiles); #endif // Header guard qbs-src-2.5.1/src/app/qbs-setup-toolchains/cosmicprobe.cpp0000644000175100001660000001526314744424375023125 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Denis Shienkov ** 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$ ** ****************************************************************************/ #include "probe.h" #include "cosmicprobe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include using namespace qbs; using Internal::Tr; using Internal::HostOsInfo; static QStringList knownCosmicCompilerNames() { return {QStringLiteral("cxcorm"), QStringLiteral("cxstm8"), QStringLiteral("cx6808"), QStringLiteral("cx6812"), QStringLiteral("cx332")}; } static QString guessCosmicArchitecture(const QFileInfo &compiler) { const auto baseName = compiler.baseName(); if (baseName == QLatin1String("cxcorm")) return QStringLiteral("arm"); if (baseName == QLatin1String("cxstm8")) return QStringLiteral("stm8"); if (baseName == QLatin1String("cx6808")) return QStringLiteral("hcs8"); if (baseName == QLatin1String("cx6812")) return QStringLiteral("hcs12"); if (baseName == QLatin1String("cx332")) return QStringLiteral("m68k"); return {}; } static Profile createCosmicProfileHelper(const ToolchainInstallInfo &info, Settings *settings, QString profileName = QString()) { const QFileInfo compiler = info.compilerPath; const QString architecture = guessCosmicArchitecture(compiler); // In case the profile is auto-detected. if (profileName.isEmpty()) { if (!info.compilerVersion.isValid()) { profileName = QStringLiteral("cosmic-unknown-%1").arg(architecture); } else { const QString version = info.compilerVersion.toString(QLatin1Char('_'), QLatin1Char('_')); profileName = QStringLiteral("cosmic-%1-%2").arg( version, architecture); } } Profile profile(profileName, settings); profile.setValue(QLatin1String("cpp.toolchainInstallPath"), compiler.absolutePath()); profile.setValue(QLatin1String("qbs.toolchainType"), QLatin1String("cosmic")); if (!architecture.isEmpty()) profile.setValue(QLatin1String("qbs.architecture"), architecture); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.").arg( profile.name(), compiler.absoluteFilePath()); return profile; } static Version dumpCosmicCompilerVersion(const QFileInfo &compiler) { QProcess p; QStringList args; p.start(compiler.absoluteFilePath(), args); p.waitForFinished(3000); const auto es = p.exitStatus(); if (es != QProcess::NormalExit) { const QByteArray out = p.readAll(); qbsWarning() << Tr::tr("Compiler dumping failed:\n%1") .arg(QString::fromUtf8(out)); return Version{}; } const QByteArray output = p.readAllStandardError(); const QRegularExpression re(QLatin1String("^COSMIC.+V(\\d+)\\.?(\\d+)\\.?(\\*|\\d+)?")); const QRegularExpressionMatch match = re.match(QString::fromLatin1(output)); if (!match.hasMatch()) return Version{}; const auto major = match.captured(1).toInt(); const auto minor = match.captured(2).toInt(); const auto patch = match.captured(3).toInt(); return Version{major, minor, patch}; } static std::vector installedCosmicsFromPath() { std::vector infos; const auto compilerNames = knownCosmicCompilerNames(); for (const QString &compilerName : compilerNames) { const QFileInfo cosmicPath( findExecutable( HostOsInfo::appendExecutableSuffix(compilerName))); if (!cosmicPath.exists()) continue; const Version version = dumpCosmicCompilerVersion(cosmicPath); infos.push_back({cosmicPath, version}); } std::sort(infos.begin(), infos.end()); return infos; } bool isCosmicCompiler(const QString &compilerName) { return Internal::any_of(knownCosmicCompilerNames(), [compilerName](const QString &knownName) { return compilerName.contains(knownName); }); } void createCosmicProfile(const QFileInfo &compiler, Settings *settings, QString profileName) { const ToolchainInstallInfo info = {compiler, Version{}}; createCosmicProfileHelper(info, settings, std::move(profileName)); } void cosmicProbe(Settings *settings, std::vector &profiles) { qbsInfo() << Tr::tr("Trying to detect COSMIC toolchains..."); const std::vector allInfos = installedCosmicsFromPath(); qbs::Internal::transform(allInfos, profiles, [settings](const auto &info) { return createCosmicProfileHelper(info, settings); }); if (allInfos.empty()) qbsInfo() << Tr::tr("No COSMIC toolchains found."); } qbs-src-2.5.1/src/app/qbs-setup-toolchains/msvcprobe.cpp0000644000175100001660000002117714744424375022621 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "msvcprobe.h" #include "probe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace qbs; using namespace qbs::Internal; using Internal::Tr; QT_BEGIN_NAMESPACE Q_DECLARE_TYPEINFO(WinSDK, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(MSVC, Q_MOVABLE_TYPE); QT_END_NAMESPACE // Not necessary but helps setup-qt automatically associate base profiles static void setQtHelperProperties(Profile &p, const MSVC *msvc) { QString targetArch = msvc->architecture.split(QLatin1Char('_')).last(); if (targetArch.isEmpty()) targetArch = QStringLiteral("x86"); if (targetArch == QStringLiteral("arm")) targetArch = QStringLiteral("armv7"); p.setValue(QStringLiteral("qbs.architecture"), canonicalArchitecture(targetArch)); } static void addMSVCPlatform(Settings *settings, std::vector &profiles, QString name, MSVC *msvc) { qbsInfo() << Tr::tr("Setting up profile '%1'.").arg(name); Profile p(std::move(name), settings); p.removeProfile(); p.setValue(QStringLiteral("qbs.targetPlatform"), QStringLiteral("windows")); p.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("msvc")); p.setValue(QStringLiteral("cpp.toolchainInstallPath"), msvc->binPath); setQtHelperProperties(p, msvc); profiles.push_back(p); } static QString wow6432Key() { #ifdef Q_OS_WIN64 return QStringLiteral("\\Wow6432Node"); #else return {}; #endif } void msvcProbe(Settings *settings, std::vector &profiles) { qbsInfo() << Tr::tr("Detecting MSVC toolchains..."); // 1) Installed SDKs preferred over standalone Visual studio std::vector winSDKs; WinSDK defaultWinSDK; const QSettings sdkRegistry(QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE") + wow6432Key() + QLatin1String("\\Microsoft\\Microsoft SDKs\\Windows"), QSettings::NativeFormat); const QString defaultSdkPath = sdkRegistry.value(QStringLiteral("CurrentInstallFolder")).toString(); if (!defaultSdkPath.isEmpty()) { const auto sdkKeys = sdkRegistry.childGroups(); for (const QString &sdkKey : sdkKeys) { WinSDK sdk; sdk.version = sdkKey; sdk.vcInstallPath = sdkRegistry.value(sdkKey + QLatin1String("/InstallationFolder")).toString(); sdk.isDefault = (sdk.vcInstallPath == defaultSdkPath); if (sdk.vcInstallPath.isEmpty()) continue; if (sdk.vcInstallPath.endsWith(QLatin1Char('\\'))) sdk.vcInstallPath.chop(1); if (sdk.isDefault) defaultWinSDK = sdk; const auto ais = MSVC::findSupportedArchitectures(sdk); qbs::Internal::transform(ais, winSDKs, [&sdk](const auto &ai) { WinSDK specificSDK = sdk; specificSDK.architecture = ai.arch; specificSDK.binPath = ai.binPath; return specificSDK; }); } } for (const WinSDK &sdk : std::as_const(winSDKs)) { qbsInfo() << Tr::tr(" Windows SDK %1 detected:\n" " installed in %2").arg(sdk.version, sdk.vcInstallPath); if (sdk.isDefault) qbsInfo() << Tr::tr(" This is the default SDK on this machine."); } // 2) Installed MSVCs std::vector msvcs = MSVC::installedCompilers(ConsoleLogger::instance()); for (const MSVC &msvc : std::as_const(msvcs)) { qbsInfo() << Tr::tr(" MSVC %1 (%2) detected in\n" " %3").arg(msvc.version, msvc.architecture, QDir::toNativeSeparators(msvc.binPath)); } if (winSDKs.empty() && msvcs.empty()) { qbsInfo() << Tr::tr("Could not detect an installation of " "the Windows SDK or Visual Studio."); return; } qbsInfo() << Tr::tr("Detecting build environment..."); std::vector msvcPtrs; msvcPtrs.reserve(winSDKs.size() + msvcs.size()); std::transform(winSDKs.begin(), winSDKs.end(), std::back_inserter(msvcPtrs), [] (WinSDK &sdk) -> MSVC * { return &sdk; }); std::transform(msvcs.begin(), msvcs.end(), std::back_inserter(msvcPtrs), [] (MSVC &msvc) -> MSVC * { return &msvc; }); for (WinSDK &sdk : winSDKs) { const QString name = QLatin1String("WinSDK") + sdk.version + QLatin1Char('-') + sdk.architecture; try { addMSVCPlatform(settings, profiles, name, &sdk); } catch (const ErrorInfo &error) { qbsWarning() << Tr::tr("Failed to set up %1: %2").arg(name, error.toString()); } } // we want the same MSVC version share the same suffix in profiles, thus use // a set to know the number of versions processed so far std::map> msvcCounters; for (MSVC &msvc : msvcs) { // each VS needs its own counter auto &msvcVersions = msvcCounters[msvc.version]; // vcInstallPath is "Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.16.27023/bin" // Since msvcs are sorted by version, when the new vcInstallPath is inserted, we start // a new group of compilers of the same version incrementing the set size msvcVersions.insert(msvc.vcInstallPath); // index is the number of specific vcInstallPaths (e.g. compiler versions) seen so far const size_t index = msvcVersions.size() - 1; const QString suffix = index == 0 ? QString() : QStringLiteral("-%1").arg(index); const QString name = QLatin1String("MSVC") + msvc.version + suffix + QLatin1Char('-') + msvc.architecture; try { addMSVCPlatform(settings, profiles, name, &msvc); } catch (const ErrorInfo &error) { qbsWarning() << Tr::tr("Failed to set up %1: %2").arg(name, error.toString()); } } } void createMsvcProfile(const QFileInfo &compiler, Settings *settings, const QString &profileName) { const auto compilerFilePath = compiler.absoluteFilePath(); MSVC msvc(compilerFilePath, MSVC::architectureFromClPath(compilerFilePath)); msvc.init(); std::vector dummy; addMSVCPlatform(settings, dummy, profileName, &msvc); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.") .arg(profileName, QDir::toNativeSeparators(compilerFilePath)); } qbs-src-2.5.1/src/app/qbs-setup-toolchains/commandlineparser.h0000644000175100001660000000607514744424375023771 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_COMMANDLINEPARSER_H #define QBS_SETUPTOOLCHAINS_COMMANDLINEPARSER_H #include #include class CommandLineParser { public: void parse(const QStringList &commandLine); bool helpRequested() const { return m_helpRequested; } bool autoDetectionMode() const { return m_autoDetectionMode; } QString compilerPath() const { return m_compilerPath; } QString toolchainType() const { return m_toolchainType; } QString profileName() const { return m_profileName; } QString settingsDir() const { return m_settingsDir; } qbs::Settings::Scope settingsScope() const { return m_settingsScope; } QString usageString() const; private: [[noreturn]] void throwError(const QString &message); void assignOptionArgument(const QString &option, QString &argument); [[noreturn]] void complainAboutExtraArguments(); bool m_helpRequested = false; bool m_autoDetectionMode = false; qbs::Settings::Scope m_settingsScope = qbs::Settings::UserScope; QString m_compilerPath; QString m_toolchainType; QString m_profileName; QString m_settingsDir; QStringList m_commandLine; QString m_command; }; #endif // Header guard qbs-src-2.5.1/src/app/qbs-setup-toolchains/CMakeLists.txt0000644000175100001660000000113714744424375022647 0ustar runnerdockerset(SOURCES clangclprobe.cpp clangclprobe.h commandlineparser.cpp commandlineparser.h cosmicprobe.cpp cosmicprobe.h dmcprobe.cpp dmcprobe.h emscriptenprobe.cpp emscriptenprobe.h gccprobe.cpp gccprobe.h iarewprobe.cpp iarewprobe.h keilprobe.cpp keilprobe.h main.cpp msvcprobe.cpp msvcprobe.h probe.cpp probe.h sdccprobe.cpp sdccprobe.h watcomprobe.cpp watcomprobe.h xcodeprobe.cpp xcodeprobe.h ) add_qbs_app(qbs-setup-toolchains DEPENDS qbscore qbsconsolelogger SOURCES ${SOURCES} ) qbs-src-2.5.1/src/app/qbs-setup-toolchains/iarewprobe.cpp0000644000175100001660000003347514744424375022764 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** 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$ ** ****************************************************************************/ #include "probe.h" #include "iarewprobe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include using namespace qbs; using Internal::Tr; using Internal::HostOsInfo; static QStringList knownIarCompilerNames() { return {QStringLiteral("icc8051"), QStringLiteral("iccarm"), QStringLiteral("iccavr"), QStringLiteral("iccstm8"), QStringLiteral("icc430"), QStringLiteral("iccrl78"), QStringLiteral("iccrx"), QStringLiteral("iccrh850"), QStringLiteral("iccv850"), QStringLiteral("icc78k"), QStringLiteral("iccavr32"), QStringLiteral("iccsh"), QStringLiteral("iccriscv"), QStringLiteral("icccf"), QStringLiteral("iccm32c"), QStringLiteral("iccr32c"), QStringLiteral("iccm16c"), QStringLiteral("icccr16c"), QStringLiteral("icchcs12"), QStringLiteral("iccs08")}; } static QString guessIarArchitecture(const QFileInfo &compiler) { const auto baseName = compiler.baseName(); if (baseName == QLatin1String("icc8051")) return QStringLiteral("mcs51"); if (baseName == QLatin1String("iccarm")) return QStringLiteral("arm"); if (baseName == QLatin1String("iccavr")) return QStringLiteral("avr"); if (baseName == QLatin1String("iccstm8")) return QStringLiteral("stm8"); if (baseName == QLatin1String("icc430")) return QStringLiteral("msp430"); if (baseName == QLatin1String("iccrl78")) return QStringLiteral("rl78"); if (baseName == QLatin1String("iccrx")) return QStringLiteral("rx"); if (baseName == QLatin1String("iccrh850")) return QStringLiteral("rh850"); if (baseName == QLatin1String("iccv850")) return QStringLiteral("v850"); if (baseName == QLatin1String("icc78k")) return QStringLiteral("78k"); if (baseName == QLatin1String("iccavr32")) return QStringLiteral("avr32"); if (baseName == QLatin1String("iccsh")) return QStringLiteral("sh"); if (baseName == QLatin1String("iccriscv")) return QStringLiteral("riscv"); if (baseName == QLatin1String("icccf")) return QStringLiteral("m68k"); if (baseName == QLatin1String("iccm32c")) return QStringLiteral("m32c"); if (baseName == QLatin1String("iccr32c")) return QStringLiteral("r32c"); if (baseName == QLatin1String("iccm16c")) return QStringLiteral("m16c"); if (baseName == QLatin1String("icccr16c")) return QStringLiteral("cr16"); if (baseName == QLatin1String("icchcs12")) return QStringLiteral("hcs12"); if (baseName == QLatin1String("iccs08")) return QStringLiteral("hcs8"); return {}; } static Profile createIarProfileHelper(const ToolchainInstallInfo &info, Settings *settings, QString profileName = QString()) { const QFileInfo compiler = info.compilerPath; const QString architecture = guessIarArchitecture(compiler); // In case the profile is auto-detected. if (profileName.isEmpty()) { if (!info.compilerVersion.isValid()) { profileName = QStringLiteral("iar-unknown-%1").arg(architecture); } else { const QString version = info.compilerVersion.toString(QLatin1Char('_'), QLatin1Char('_')); profileName = QStringLiteral("iar-%1-%2").arg( version, architecture); } } Profile profile(profileName, settings); profile.setValue(QLatin1String("cpp.toolchainInstallPath"), compiler.absolutePath()); profile.setValue(QLatin1String("qbs.toolchainType"), QLatin1String("iar")); if (!architecture.isEmpty()) profile.setValue(QLatin1String("qbs.architecture"), architecture); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.").arg( profile.name(), compiler.absoluteFilePath()); return profile; } static Version dumpIarCompilerVersion(const QFileInfo &compiler) { const QString outFilePath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + QLatin1String("/macros.dump"); const QStringList args = {QStringLiteral("."), QStringLiteral("--predef_macros"), outFilePath}; QProcess p; p.start(compiler.absoluteFilePath(), args); p.waitForFinished(3000); const auto es = p.exitStatus(); if (es != QProcess::NormalExit) { const QByteArray out = p.readAll(); qbsWarning() << Tr::tr("Compiler dumping failed:\n%1") .arg(QString::fromUtf8(out)); return Version{}; } QByteArray dump; QFile out(outFilePath); if (out.open(QIODevice::ReadOnly)) dump = out.readAll(); out.remove(); const int verCode = extractVersion(dump, "__VER__ "); if (verCode < 0) { qbsWarning() << Tr::tr("No '__VER__' token was found in a compiler dump:\n%1") .arg(QString::fromUtf8(dump)); return Version{}; } const QString arch = guessIarArchitecture(compiler); if (arch == QLatin1String("arm")) return Version{verCode / 1000000, (verCode / 1000) % 1000, verCode % 1000}; if (arch == QLatin1String("avr") || arch == QLatin1String("mcs51") || arch == QLatin1String("stm8") || arch == QLatin1String("msp430") || arch == QLatin1String("rl78") || arch == QLatin1String("rx") || arch == QLatin1String("rh850") || arch == QLatin1String("v850") || arch == QLatin1String("78k") || arch == QLatin1String("avr32") || arch == QLatin1String("sh") || arch == QLatin1String("riscv") || arch == QLatin1String("m68k") || arch == QLatin1String("m32c") || arch == QLatin1String("r32c") || arch == QLatin1String("m16c") || arch == QLatin1String("rc16") || arch == QLatin1String("hcs12") || arch == QLatin1String("hcs8")) { return Version{verCode / 100, verCode % 100}; } return Version{}; } static std::vector installedIarsFromPath() { std::vector infos; const auto compilerNames = knownIarCompilerNames(); for (const QString &compilerName : compilerNames) { const QFileInfo iarPath( findExecutable( HostOsInfo::appendExecutableSuffix(compilerName))); if (!iarPath.exists()) continue; const Version version = dumpIarCompilerVersion(iarPath); infos.push_back({iarPath, version}); } std::sort(infos.begin(), infos.end()); return infos; } static std::vector installedIarsFromRegistry() { std::vector infos; if (HostOsInfo::isWindowsHost()) { #ifdef Q_OS_WIN64 static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\IAR Systems\\Embedded Workbench"; #else static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\IAR Systems\\Embedded Workbench"; #endif // Dictionary for know toolchains. static const struct Entry { QString registryKey; QString subExePath; } knowToolchains[] = { {QStringLiteral("EWARM"), QStringLiteral("/arm/bin/iccarm.exe")}, {QStringLiteral("EWAVR"), QStringLiteral("/avr/bin/iccavr.exe")}, {QStringLiteral("EW8051"), QStringLiteral("/8051/bin/icc8051.exe")}, {QStringLiteral("EWSTM8"), QStringLiteral("/stm8/bin/iccstm8.exe")}, {QStringLiteral("EW430"), QStringLiteral("/430/bin/icc430.exe")}, {QStringLiteral("EWRL78"), QStringLiteral("/rl78/bin/iccrl78.exe")}, {QStringLiteral("EWRX"), QStringLiteral("/rx/bin/iccrx.exe")}, {QStringLiteral("EWRH850"), QStringLiteral("/rh850/bin/iccrh850.exe")}, {QStringLiteral("EWV850"), QStringLiteral("/v850/bin/iccv850.exe")}, {QStringLiteral("EW78K"), QStringLiteral("/78k/bin/icc78k.exe")}, {QStringLiteral("EWAVR32"), QStringLiteral("/avr32/bin/iccavr32.exe")}, {QStringLiteral("EWSH"), QStringLiteral("/sh/bin/iccsh.exe")}, {QStringLiteral("EWRISCV"), QStringLiteral("/riscv/bin/iccriscv.exe")}, {QStringLiteral("EWCF"), QStringLiteral("/cf/bin/icccf.exe")}, {QStringLiteral("EWM32C"), QStringLiteral("/m32c/bin/iccm32c.exe")}, {QStringLiteral("EWR32C"), QStringLiteral("/r32c/bin/iccr32c.exe")}, {QStringLiteral("EWM16C"), QStringLiteral("/m16c/bin/iccm16c.exe")}, {QStringLiteral("EWCR16C"), QStringLiteral("/cr16c/bin/icccr16c.exe")}, {QStringLiteral("EWHCS12"), QStringLiteral("/hcs12/bin/icchcs12.exe")}, {QStringLiteral("EWS08"), QStringLiteral("/s08/bin/iccs08.exe")}, }; QSettings registry(QLatin1String(kRegistryNode), QSettings::NativeFormat); const auto oneLevelGroups = registry.childGroups(); for (const QString &oneLevelKey : oneLevelGroups) { registry.beginGroup(oneLevelKey); const auto twoLevelGroups = registry.childGroups(); for (const Entry &entry : knowToolchains) { if (twoLevelGroups.contains(entry.registryKey)) { registry.beginGroup(entry.registryKey); const auto threeLevelGroups = registry.childGroups(); for (const QString &threeLevelKey : threeLevelGroups) { registry.beginGroup(threeLevelKey); const QString rootPath = registry.value( QStringLiteral("InstallPath")).toString(); if (!rootPath.isEmpty()) { // Build full compiler path. const QFileInfo iarPath(rootPath + entry.subExePath); if (iarPath.exists()) { // Note: threeLevelKey is a guessed toolchain version. infos.push_back({iarPath, Version::fromString(threeLevelKey, true)}); } } registry.endGroup(); } registry.endGroup(); } } registry.endGroup(); } } std::sort(infos.begin(), infos.end()); return infos; } bool isIarCompiler(const QString &compilerName) { return Internal::any_of(knownIarCompilerNames(), [compilerName]( const QString &knownName) { return compilerName.contains(knownName); }); } void createIarProfile(const QFileInfo &compiler, Settings *settings, QString profileName) { const ToolchainInstallInfo info = {compiler, Version{}}; createIarProfileHelper(info, settings, std::move(profileName)); } void iarProbe(Settings *settings, std::vector &profiles) { qbsInfo() << Tr::tr("Trying to detect IAR toolchains..."); // Make sure that a returned infos are sorted before using the std::set_union! const std::vector regInfos = installedIarsFromRegistry(); const std::vector pathInfos = installedIarsFromPath(); std::vector allInfos; allInfos.reserve(regInfos.size() + pathInfos.size()); std::set_union(regInfos.cbegin(), regInfos.cend(), pathInfos.cbegin(), pathInfos.cend(), std::back_inserter(allInfos)); qbs::Internal::transform(allInfos, profiles, [settings](const auto &info) { return createIarProfileHelper(info, settings); }); if (allInfos.empty()) qbsInfo() << Tr::tr("No IAR toolchains found."); } qbs-src-2.5.1/src/app/qbs-setup-toolchains/main.cpp0000644000175100001660000000571714744424375021547 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "commandlineparser.h" #include "probe.h" #include #include #include #include #include #include using qbs::Settings; static void printUsage(const QString &usageString) { std::cout << qPrintable(usageString) << std::endl; } int main(int argc, char **argv) { QCoreApplication app(argc, argv); CommandLineParser clParser; try { clParser.parse(app.arguments()); if (clParser.helpRequested()) { printUsage(clParser.usageString()); return EXIT_SUCCESS; } Settings settings(clParser.settingsDir()); settings.setScopeForWriting(clParser.settingsScope()); if (clParser.autoDetectionMode()) { probe(&settings); return EXIT_SUCCESS; } createProfile(clParser.profileName(), clParser.toolchainType(), clParser.compilerPath(), &settings); } catch (const qbs::ErrorInfo &e) { std::cerr << qPrintable(e.toString()) << std::endl; return EXIT_FAILURE; } } qbs-src-2.5.1/src/app/qbs-setup-toolchains/xcodeprobe.cpp0000644000175100001660000002243414744424375022750 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "probe.h" #include "xcodeprobe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace qbs; using Internal::Tr; static const QString defaultDeveloperPath = QStringLiteral("/Applications/Xcode.app/Contents/Developer"); static const std::regex defaultDeveloperPathRegex( "^/Applications/Xcode([a-zA-Z0-9 ._-]+)\\.app/Contents/Developer$"); static QString targetOS(const QString &applePlatformName) { if (applePlatformName == QStringLiteral("macosx")) return QStringLiteral("macos"); if (applePlatformName == QStringLiteral("iphoneos")) return QStringLiteral("ios"); if (applePlatformName == QStringLiteral("iphonesimulator")) return QStringLiteral("ios-simulator"); if (applePlatformName == QStringLiteral("appletvos")) return QStringLiteral("tvos"); if (applePlatformName == QStringLiteral("appletvsimulator")) return QStringLiteral("tvos-simulator"); if (applePlatformName == QStringLiteral("watchos")) return QStringLiteral("watchos"); if (applePlatformName == QStringLiteral("watchsimulator")) return QStringLiteral("watchos-simulator"); return {}; } static QStringList archList(const QString &applePlatformName) { QStringList archs; if (applePlatformName == QStringLiteral("macosx") || applePlatformName == QStringLiteral("iphonesimulator") || applePlatformName == QStringLiteral("appletvsimulator") || applePlatformName == QStringLiteral("watchsimulator")) { if (applePlatformName != QStringLiteral("appletvsimulator")) archs << QStringLiteral("x86"); if (applePlatformName != QStringLiteral("watchsimulator")) archs << QStringLiteral("x86_64"); if (applePlatformName == QStringLiteral("macosx")) archs << QStringLiteral("arm64"); } else if (applePlatformName == QStringLiteral("iphoneos") || applePlatformName == QStringLiteral("appletvos")) { if (applePlatformName != QStringLiteral("appletvos")) archs << QStringLiteral("armv7a"); archs << QStringLiteral("arm64"); } else if (applePlatformName == QStringLiteral("watchos")) { archs << QStringLiteral("armv7k"); } return archs; } namespace { class XcodeProbe { public: XcodeProbe(qbs::Settings *settings, std::vector &profiles) : settings(settings), profiles(profiles) { } bool addDeveloperPath(const QString &path); void detectDeveloperPaths(); void setupDefaultToolchains(const QString &devPath, const QString &xCodeName); void detectAll(); private: qbs::Settings *settings; std::vector &profiles; QStringList developerPaths; }; bool XcodeProbe::addDeveloperPath(const QString &path) { if (path.isEmpty()) return false; QFileInfo pInfo(path); if (!pInfo.exists() || !pInfo.isDir()) return false; if (developerPaths.contains(path)) return false; developerPaths.push_back(path); qbsInfo() << Tr::tr("Added developer path %1").arg(path); return true; } void XcodeProbe::detectDeveloperPaths() { QProcess selectedXcode; QString program = QStringLiteral("/usr/bin/xcode-select"); QStringList arguments(QStringLiteral("--print-path")); selectedXcode.start(program, arguments, QProcess::ReadOnly); if (!selectedXcode.waitForFinished(-1) || selectedXcode.exitCode()) { qbsInfo() << Tr::tr("Could not detect selected Xcode with /usr/bin/xcode-select"); } else { QString path = QString::fromLocal8Bit(selectedXcode.readAllStandardOutput().trimmed()); addDeveloperPath(path); } addDeveloperPath(defaultDeveloperPath); QProcess launchServices; program = QStringLiteral("/usr/bin/mdfind"); arguments = QStringList(QStringLiteral("kMDItemCFBundleIdentifier == 'com.apple.dt.Xcode'")); launchServices.start(program, arguments, QProcess::ReadOnly); if (!launchServices.waitForFinished(-1) || launchServices.exitCode()) { qbsInfo() << Tr::tr("Could not detect additional Xcode installations with /usr/bin/mdfind"); } else { const auto paths = QString::fromLocal8Bit(launchServices.readAllStandardOutput()) .split(QLatin1Char('\n'), Qt::SkipEmptyParts); for (const QString &path : paths) addDeveloperPath(path + QStringLiteral("/Contents/Developer")); } } void XcodeProbe::setupDefaultToolchains(const QString &devPath, const QString &xcodeName) { qbsInfo() << Tr::tr("Profile '%1' created for '%2'.").arg(xcodeName, devPath); Profile installationProfile(xcodeName, settings); installationProfile.removeProfile(); installationProfile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("xcode")); if (devPath != defaultDeveloperPath) installationProfile.setValue(QStringLiteral("xcode.developerPath"), devPath); profiles.push_back(installationProfile); QStringList platforms; platforms << QStringLiteral("macosx") << QStringLiteral("iphoneos") << QStringLiteral("iphonesimulator") << QStringLiteral("appletvos") << QStringLiteral("appletvsimulator") << QStringLiteral("watchos") << QStringLiteral("watchsimulator"); for (const QString &platform : std::as_const(platforms)) { Profile platformProfile(xcodeName + QLatin1Char('-') + platform, settings); platformProfile.removeProfile(); platformProfile.setBaseProfile(installationProfile.name()); platformProfile.setValue(QStringLiteral("qbs.targetPlatform"), targetOS(platform)); profiles.push_back(platformProfile); const auto architectures = archList(platform); for (const QString &arch : architectures) { Profile archProfile(xcodeName + QLatin1Char('-') + platform + QLatin1Char('-') + arch, settings); archProfile.removeProfile(); archProfile.setBaseProfile(platformProfile.name()); archProfile.setValue(QStringLiteral("qbs.architecture"), qbs::canonicalArchitecture(arch)); profiles.push_back(archProfile); } } } void XcodeProbe::detectAll() { int i = 1; detectDeveloperPaths(); for (const QString &developerPath : std::as_const(developerPaths)) { QString profileName = QStringLiteral("xcode"); if (developerPath != defaultDeveloperPath) { const auto devPath = developerPath.toStdString(); std::smatch match; if (std::regex_match(devPath, match, defaultDeveloperPathRegex)) profileName += QString::fromStdString(match[1]).toLower(). replace(QLatin1Char(' '), QLatin1Char('-')). replace(QLatin1Char('.'), QLatin1Char('_')); else profileName += QString::number(i++); } setupDefaultToolchains(developerPath, profileName); } } } // end anonymous namespace void xcodeProbe(qbs::Settings *settings, std::vector &profiles) { XcodeProbe probe(settings, profiles); probe.detectAll(); } qbs-src-2.5.1/src/app/qbs-setup-toolchains/probe.h0000644000175100001660000000617714744424375021400 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_PROBE_H #define QBS_SETUPTOOLCHAINS_PROBE_H #include #include #include #include #include // for std::function #include // for std::tie namespace qbs { class Settings; } QStringList systemSearchPaths(); QString findExecutable(const QString &fileName); QString toolchainTypeFromCompilerName(const QString &compilerName); void createProfile(const QString &profileName, const QString &toolchainType, const QString &compilerFilePath, qbs::Settings *settings); void probe(qbs::Settings *settings); struct ToolchainInstallInfo { QFileInfo compilerPath; qbs::Version compilerVersion; }; inline bool operator<(const ToolchainInstallInfo &lhs, const ToolchainInstallInfo &rhs) { const auto lp = lhs.compilerPath.absoluteFilePath(); const auto rp = rhs.compilerPath.absoluteFilePath(); return std::tie(lp, lhs.compilerVersion) < std::tie(rp, rhs.compilerVersion); } int extractVersion(const QByteArray ¯oDump, const QByteArray &keyToken); bool isSameExecutable(const QString &exe1, const QString &exe2); using MacrosMap = QMap; MacrosMap dumpMacros(const std::function &func); #endif // Header guard qbs-src-2.5.1/src/app/qbs-setup-toolchains/dmcprobe.cpp0000644000175100001660000002462714744424375022417 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Denis Shienkov ** 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$ ** ****************************************************************************/ #include "probe.h" #include "dmcprobe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include #include using namespace qbs; using Internal::Tr; using Internal::HostOsInfo; namespace { struct Target { QString platform; QString architecture; QString extender; }; } static QStringList knownDmcCompilerNames() { return {QStringLiteral("dmc")}; } static QStringList dumpOutput(const QFileInfo &compiler, const QStringList &flags, const QStringList &keys) { const QString filePath = QDir(QDir::tempPath()).absoluteFilePath( QLatin1String("dmc-dump.c")); QFile fakeIn(filePath); if (!fakeIn.open(QIODevice::Truncate | QIODevice::WriteOnly | QIODevice::Text)) { qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2") .arg(fakeIn.fileName(), fakeIn.errorString()); return {}; } fakeIn.write("#define VALUE_TO_STRING(x) #x\n"); fakeIn.write("#define VALUE(x) VALUE_TO_STRING(x)\n"); fakeIn.write("#define VAR_NAME_VALUE(var) \"#define \" #var\" \"VALUE(var)\n"); for (const auto &key : keys) { const auto content = key.toLatin1(); fakeIn.write("#if defined(" + content + ")\n"); fakeIn.write("#pragma message (VAR_NAME_VALUE(" + content + "))\n"); fakeIn.write("#endif\n"); } fakeIn.close(); QStringList args = {QStringLiteral("-e")}; args.reserve(args.size() + int(flags.size())); std::copy(flags.cbegin(), flags.cend(), std::back_inserter(args)); args.push_back(QDir::toNativeSeparators(filePath)); QProcess p; p.start(compiler.absoluteFilePath(), args); p.waitForFinished(3000); fakeIn.remove(); static QRegularExpression re(QLatin1String("\\r?\\n")); return QString::fromUtf8(p.readAllStandardOutput()).split(re); } static std::optional dumpDmcTarget(const QFileInfo &compiler, const QStringList &flags) { const QStringList keys = { QStringLiteral("DOS16RM"), QStringLiteral("DOS386"), QStringLiteral("MSDOS"), QStringLiteral("__NT__"), QStringLiteral("_WINDOWS"), }; const auto macros = dumpMacros([&compiler, &flags, &keys]() { return dumpOutput(compiler, flags, keys); }); if (macros.contains(QLatin1String("__NT__"))) { return Target{QLatin1String("windows"), QLatin1String("x86"), QLatin1String("")}; } else if (macros.contains(QLatin1String("_WINDOWS"))) { return Target{QLatin1String("windows"), QLatin1String("x86_16"), QLatin1String("")}; } else if (macros.contains(QLatin1String("DOS386"))) { if (flags.contains(QLatin1String("-mx"))) return Target{QLatin1String("dos"), QLatin1String("x86"), QLatin1String("dosx")}; else if (flags.contains(QLatin1String("-mp"))) return Target{QLatin1String("dos"), QLatin1String("x86"), QLatin1String("dosp")}; } else if (macros.contains(QLatin1String("DOS16RM"))) { if (flags.contains(QLatin1String("-mz"))) return Target{QLatin1String("dos"), QLatin1String("x86_16"), QLatin1String("dosz")}; else if (flags.contains(QLatin1String("-mr"))) return Target{QLatin1String("dos"), QLatin1String("x86_16"), QLatin1String("dosr")}; } else if (macros.contains(QLatin1String("MSDOS"))) { return Target{QLatin1String("dos"), QLatin1String("x86_16"), QLatin1String("")}; } return {}; } static std::vector createDmcProfileHelper(const ToolchainInstallInfo &info, Settings *settings, QStringView profileName = {}) { const QFileInfo compiler = info.compilerPath; std::vector profiles; const QVector probes = { { QStringLiteral("-mn"), QStringLiteral("-WA") }, // Windows NT 32 bit. { QStringLiteral("-ml"), QStringLiteral("-WA") }, // Windows 3.x 16 bit. { QStringLiteral("-mx") }, // DOS with DOSX extender 32 bit. { QStringLiteral("-mp") }, // DOS with Phar Lap extender 32 bit. { QStringLiteral("-mr") }, // DOS with Rational DOS Extender 16 bit. { QStringLiteral("-mz") }, // DOS with ZPM DOS Extender 16 bit. { QStringLiteral("-mc") }, // DOS 16 bit. }; for (const auto &flags : probes) { const auto target = dumpDmcTarget(compiler, flags); if (!target) continue; QString fullProfilename; QString platform = target->extender.isEmpty() ? target->platform : target->extender; if (profileName.isEmpty()) { // Create a full profile name in case we is in auto-detecting mode. if (!info.compilerVersion.isValid()) { fullProfilename = QStringLiteral("dmc-unknown-%1-%2") .arg(platform, target->architecture); } else { const QString version = info.compilerVersion.toString(QLatin1Char('_'), QLatin1Char('_')); fullProfilename = QStringLiteral("dmc-%1-%2-%3") .arg(version, platform, target->architecture); } } else { // Append the detected actual architecture name to the proposed profile name. fullProfilename = QStringLiteral("%1-%2-%3") .arg(profileName, platform, target->architecture); } Profile profile(fullProfilename, settings); profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath()); profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("dmc")); profile.setValue(QStringLiteral("qbs.architecture"), target->architecture); profile.setValue(QStringLiteral("qbs.targetPlatform"), target->platform); if (!target->extender.isEmpty()) profile.setValue(QStringLiteral("cpp.extenderName"), target->extender); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.") .arg(profile.name(), compiler.absoluteFilePath()); profiles.push_back(std::move(profile)); } return profiles; } static Version dumpDmcVersion(const QFileInfo &compiler) { const QStringList keys = {QStringLiteral("__DMC__")}; const auto macros = dumpMacros([&compiler, keys]() { return dumpOutput(compiler, {}, keys); }); for (const auto ¯o : macros) { if (!macro.startsWith(QLatin1String("0x"))) continue; const int verCode = macro.mid(2).toInt(); return Version{(verCode / 100), (verCode % 100), 0}; } qbsWarning() << Tr::tr("No __DMC__ token was found in the compiler dump"); return Version{}; } static std::vector installedDmcsFromPath() { std::vector infos; const auto compilerNames = knownDmcCompilerNames(); for (const QString &compilerName : compilerNames) { const QFileInfo dmcPath( findExecutable( HostOsInfo::appendExecutableSuffix(compilerName))); if (!dmcPath.exists()) continue; const Version version = dumpDmcVersion(dmcPath); infos.push_back({dmcPath, version}); } std::sort(infos.begin(), infos.end()); return infos; } bool isDmcCompiler(const QString &compilerName) { return Internal::any_of(knownDmcCompilerNames(), [compilerName](const QString &knownName) { return compilerName.contains(knownName); }); } void createDmcProfile(const QFileInfo &compiler, Settings *settings, QStringView profileName) { const ToolchainInstallInfo info = {compiler, Version{}}; createDmcProfileHelper(info, settings, profileName); } void dmcProbe(Settings *settings, std::vector &profiles) { qbsInfo() << Tr::tr("Trying to detect DMC toolchains..."); const std::vector allInfos = installedDmcsFromPath(); if (allInfos.empty()) { qbsInfo() << Tr::tr("No DMC toolchains found."); return; } for (const ToolchainInstallInfo &info : allInfos) { const auto newProfiles = createDmcProfileHelper(info, settings); profiles.reserve(profiles.size() + int(newProfiles.size())); std::copy(newProfiles.cbegin(), newProfiles.cend(), std::back_inserter(profiles)); } } qbs-src-2.5.1/src/app/qbs-setup-toolchains/gccprobe.cpp0000644000175100001660000005547714744424375022417 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "probe.h" #include "gccprobe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include #include using namespace qbs; using Internal::HostOsInfo; using Internal::Tr; constexpr char kUninstallRegistryKey[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\" \ "Windows\\CurrentVersion\\Uninstall\\"; static QString qsystem(const QString &exe, const QStringList &args = QStringList()) { QProcess p; p.setProcessChannelMode(QProcess::MergedChannels); p.start(exe, args); if (!p.waitForStarted()) { throw qbs::ErrorInfo(Tr::tr("Failed to start compiler '%1': %2") .arg(exe, p.errorString())); } if (!p.waitForFinished(-1) || p.exitCode() != 0) throw qbs::ErrorInfo(Tr::tr("Failed to run compiler '%1': %2") .arg(exe, p.errorString())); return QString::fromLocal8Bit(p.readAll()); } static QStringList validMinGWMachines() { // List of MinGW machine names (gcc -dumpmachine) recognized by Qbs return {QStringLiteral("mingw32"), QStringLiteral("mingw64"), QStringLiteral("i686-w64-mingw32"), QStringLiteral("x86_64-w64-mingw32"), QStringLiteral("i686-w64-mingw32.shared"), QStringLiteral("x86_64-w64-mingw32.shared"), QStringLiteral("i686-w64-mingw32.static"), QStringLiteral("x86_64-w64-mingw32.static"), QStringLiteral("i586-mingw32msvc"), QStringLiteral("amd64-mingw32msvc")}; } static QString gccMachineName(const QFileInfo &compiler) { return qsystem(compiler.absoluteFilePath(), {QStringLiteral("-dumpmachine")}) .trimmed(); } static QStringList standardCompilerFileNames() { return {HostOsInfo::appendExecutableSuffix(QStringLiteral("gcc")), HostOsInfo::appendExecutableSuffix(QStringLiteral("g++")), HostOsInfo::appendExecutableSuffix(QStringLiteral("clang")), HostOsInfo::appendExecutableSuffix(QStringLiteral("clang++"))}; } class ToolchainDetails { public: explicit ToolchainDetails(const QFileInfo &compiler) { auto baseName = HostOsInfo::stripExecutableSuffix(compiler.fileName()); // Extract the version sub-string if it exists. We assume that a version // sub-string located after the compiler prefix && suffix. E.g. this code // parses a version from the compiler names, like this: // - avr-gcc-4.9.2.exe // - arm-none-eabi-gcc-8.2.1 // - rl78-elf-gcc-4.9.2.201902-GNURL78 const QRegularExpression re(QLatin1String("-(\\d+|\\d+\\.\\d+|" \ "\\d+\\.\\d+\\.\\d+|" \ "\\d+\\.\\d+\\.\\d+\\.\\d+)" \ "[-[0-9a-zA-Z]*]?$")); const QRegularExpressionMatch match = re.match(baseName); if (match.hasMatch()) { version = match.captured(1); baseName = baseName.left(match.capturedStart()); } const auto dashIndex = baseName.lastIndexOf(QLatin1Char('-')); suffix = baseName.mid(dashIndex + 1); prefix = baseName.left(dashIndex + 1); } QString prefix; QString suffix; QString version; }; static void setCommonProperties(Profile &profile, const QFileInfo &compiler, const QString &toolchainType, const ToolchainDetails &details) { if (toolchainType == QStringLiteral("mingw")) profile.setValue(QStringLiteral("qbs.targetPlatform"), QStringLiteral("windows")); if (!details.prefix.isEmpty()) profile.setValue(QStringLiteral("cpp.toolchainPrefix"), details.prefix); profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath()); profile.setValue(QStringLiteral("qbs.toolchainType"), toolchainType); if (!standardCompilerFileNames().contains( HostOsInfo::appendExecutableSuffix(details.suffix))) { qWarning("%s", qPrintable( QStringLiteral("'%1' is not a standard compiler file name; " "you must set the cpp.cCompilerName and " "cpp.cxxCompilerName properties of this profile " "manually").arg(compiler.fileName()))); } } class ToolPathSetup { public: explicit ToolPathSetup(Profile *profile, QString path, ToolchainDetails details) : m_profile(profile), m_compilerDirPath(std::move(path)), m_details(std::move(details)) { } void apply(const QString &toolName, const QString &propertyName) const { // Check for full tool name at first (includes suffix and version). QString filePath = toolFilePath(toolName, UseFullToolName); if (filePath.isEmpty()) { // Check for base tool name at second (without of suffix and version). filePath = toolFilePath(toolName, UseBaseToolName); if (filePath.isEmpty()) { // Check for short tool name at third (only a tool name). filePath = toolFilePath(toolName, UseOnlyShortToolName); } } if (filePath.isEmpty()) { qWarning("%s", qPrintable( QStringLiteral("'%1' not found in '%2'. " "Qbs will try to find it in PATH at build time.") .arg(toolName, m_compilerDirPath))); } else { m_profile->setValue(propertyName, filePath); } } private: enum ToolNameParts : quint8 { UseOnlyShortToolName = 0x0, UseToolPrefix = 0x01, UseToolSuffix = 0x02, UseToolVersion = 0x04, UseFullToolName = UseToolPrefix | UseToolSuffix | UseToolVersion, UseBaseToolName = UseToolPrefix, }; QString toolFilePath(const QString &toolName, int parts) const { QString fileName; if ((parts & UseToolPrefix) && !m_details.prefix.isEmpty()) fileName += m_details.prefix; if ((parts & UseToolSuffix) && !m_details.suffix.isEmpty()) fileName += m_details.suffix + QLatin1Char('-'); fileName += toolName; if ((parts & UseToolVersion) && !m_details.version.isEmpty()) fileName += QLatin1Char('-') + m_details.version; fileName = HostOsInfo::appendExecutableSuffix(fileName); QString filePath = QDir(m_compilerDirPath).absoluteFilePath(fileName); if (QFile::exists(filePath)) return filePath; return {}; } Profile * const m_profile; QString m_compilerDirPath; ToolchainDetails m_details; }; static bool doesProfileTargetOS(const Profile &profile, const QString &os) { const auto target = profile.value(QStringLiteral("qbs.targetPlatform")); if (target.isValid()) return Internal::contains(HostOsInfo::canonicalOSIdentifiers(target.toString()), os); return Internal::contains(HostOsInfo::hostOSIdentifiers(), os); } static QString buildProfileName(const QFileInfo &cfi) { // We need to replace a dot-separated compiler version string // with a underscore-separated string, because the profile // name does not allow a dots. auto result = cfi.completeBaseName(); result.replace(QLatin1Char('.'), QLatin1Char('_')); return result; } static QStringList buildCompilerNameFilters(const QString &compilerName) { QStringList filters = { // "clang", "gcc" compilerName, // "clang-8", "gcc-5" compilerName + QLatin1String("-[1-9]*"), // "avr-gcc" QLatin1String("*-") + compilerName, // "avr-gcc-5.4.0" QLatin1String("*-") + compilerName + QLatin1String("-[1-9]*"), // "arm-none-eabi-gcc" QLatin1String("*-*-*-") + compilerName, // "arm-none-eabi-gcc-9.1.0" QLatin1String("*-*-*-") + compilerName + QLatin1String("-[1-9]*"), // "x86_64-pc-linux-gnu-gcc" QLatin1String("*-*-*-*-") + compilerName, // "x86_64-pc-linux-gnu-gcc-7.4.1" QLatin1String("*-*-*-*-") + compilerName + QLatin1String("-[1-9]*") }; Internal::transform(filters, [](const auto &filter) { return HostOsInfo::appendExecutableSuffix(filter); }); return filters; } static QStringList gnuRegistrySearchPaths() { if (!HostOsInfo::isWindowsHost()) return {}; #ifdef Q_OS_WIN64 static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\ARM"; #else static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\ARM"; #endif QStringList searchPaths; QSettings registry(QLatin1String(kRegistryNode), QSettings::NativeFormat); const auto groupKeys = registry.childGroups(); for (const QString &groupKey : groupKeys) { registry.beginGroup(groupKey); const QString rootPath = registry.value(QStringLiteral("InstallFolder")).toString(); if (!rootPath.isEmpty()) { const QFileInfo toolchainPath(rootPath + QLatin1String("/bin")); if (toolchainPath.exists()) { const auto filePath = toolchainPath.absoluteFilePath(); if (!searchPaths.contains(filePath)) searchPaths.push_back(filePath); } } registry.endGroup(); } return searchPaths; } static QStringList atmelRegistrySearchPaths() { if (!HostOsInfo::isWindowsHost()) return {}; // Registry token for the "Atmel" toolchains, e.g. provided by installed // "Atmel Studio" IDE. static const char kRegistryToken[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Atmel\\"; QStringList searchPaths; QSettings registry(QLatin1String(kRegistryToken), QSettings::NativeFormat); // This code enumerate the installed toolchains provided // by the Atmel Studio v6.x. const auto toolchainGroups = registry.childGroups(); for (const QString &toolchainKey : toolchainGroups) { if (!toolchainKey.endsWith(QLatin1String("GCC"))) continue; registry.beginGroup(toolchainKey); const auto entries = registry.childGroups(); for (const auto &entryKey : entries) { registry.beginGroup(entryKey); const QString installDir = registry.value( QStringLiteral("Native/InstallDir")).toString(); const QString version = registry.value( QStringLiteral("Native/Version")).toString(); registry.endGroup(); QString toolchainPath = installDir + QLatin1String("/Atmel Toolchain/") + toolchainKey + QLatin1String("/Native/") + version; if (toolchainKey.startsWith(QLatin1String("ARM"))) toolchainPath += QLatin1String("/arm-gnu-toolchain"); else if (toolchainKey.startsWith(QLatin1String("AVR32"))) toolchainPath += QLatin1String("/avr32-gnu-toolchain"); else if (toolchainKey.startsWith(QLatin1String("AVR8)"))) toolchainPath += QLatin1String("/avr8-gnu-toolchain"); else break; toolchainPath += QLatin1String("/bin"); if (QFileInfo::exists(toolchainPath)) { searchPaths.push_back(toolchainPath); break; } } registry.endGroup(); } // This code enumerate the installed toolchains provided // by the Atmel Studio v7. registry.beginGroup(QStringLiteral("AtmelStudio")); const auto productVersions = registry.childGroups(); for (const auto &productVersionKey : productVersions) { registry.beginGroup(productVersionKey); const QString installDir = registry.value( QStringLiteral("InstallDir")).toString(); registry.endGroup(); const QStringList knownToolchainSubdirs = { QStringLiteral("/toolchain/arm/arm-gnu-toolchain/bin/"), QStringLiteral("/toolchain/avr8/avr8-gnu-toolchain/bin/"), QStringLiteral("/toolchain/avr32/avr32-gnu-toolchain/bin/"), }; for (const auto &subdir : knownToolchainSubdirs) { const QString toolchainPath = installDir + subdir; if (!QFileInfo::exists(toolchainPath)) continue; searchPaths.push_back(toolchainPath); } } registry.endGroup(); return searchPaths; } static QStringList renesasRl78RegistrySearchPaths() { if (!HostOsInfo::isWindowsHost()) return {}; QStringList searchPaths; QSettings registry(QLatin1String(kUninstallRegistryKey), QSettings::NativeFormat); const auto productGroups = registry.childGroups(); for (const QString &productKey : productGroups) { // Registry token for the "Renesas RL78" toolchain. if (!productKey.startsWith( QLatin1String("GCC for Renesas RL78"))) { continue; } registry.beginGroup(productKey); const QString installLocation = registry.value( QLatin1String("InstallLocation")).toString(); registry.endGroup(); if (installLocation.isEmpty()) continue; const QFileInfo toolchainPath(QDir(installLocation).absolutePath() + QLatin1String("/rl78-elf/rl78-elf/bin")); if (!toolchainPath.exists()) continue; searchPaths.push_back(toolchainPath.absoluteFilePath()); } return searchPaths; } static QStringList mplabX32RegistrySearchPaths() { if (!HostOsInfo::isWindowsHost()) return {}; QStringList searchPaths; QSettings registry(QLatin1String(kUninstallRegistryKey), QSettings::NativeFormat); const auto productGroups = registry.childGroups(); for (const QString &productKey : productGroups) { // Registry token for the "MPLAB X32" toolchain. if (!productKey.startsWith( QLatin1String("MPLAB XC32 Compiler"))) { continue; } registry.beginGroup(productKey); const QString installLocation = registry.value( QLatin1String("InstallLocation")).toString(); registry.endGroup(); if (installLocation.isEmpty()) continue; const QFileInfo toolchainPath(QDir(installLocation).absolutePath() + QLatin1String("/bin")); if (!toolchainPath.exists()) continue; searchPaths.push_back(toolchainPath.absoluteFilePath()); } return searchPaths; } Profile createGccProfile(const QFileInfo &compiler, Settings *settings, const QString &toolchainType, const QString &profileName) { const QString machineName = gccMachineName(compiler); if (toolchainType == QLatin1String("mingw")) { if (!validMinGWMachines().contains(machineName)) { throw ErrorInfo(Tr::tr("Detected gcc platform '%1' is not supported.") .arg(machineName)); } } Profile profile(!profileName.isEmpty() ? profileName : machineName, settings); profile.removeProfile(); const ToolchainDetails details(compiler); setCommonProperties(profile, compiler, toolchainType, details); if (HostOsInfo::isWindowsHost() && toolchainType == QLatin1String("clang")) { const QStringList profileNames = settings->profiles(); bool foundMingw = false; for (const QString &profileName : profileNames) { const Profile otherProfile(profileName, settings); if (otherProfile.value(QLatin1String("qbs.toolchainType")).toString() == QLatin1String("mingw") || otherProfile.value(QLatin1String("qbs.toolchain")) .toStringList().contains(QLatin1String("mingw"))) { const QFileInfo tcDir(otherProfile.value(QLatin1String("cpp.toolchainInstallPath")) .toString()); if (!tcDir.fileName().isEmpty() && tcDir.exists()) { profile.setValue(QLatin1String("qbs.sysroot"), tcDir.path()); foundMingw = true; break; } } } if (!foundMingw) { qbsWarning() << Tr::tr("Using clang on Windows requires a mingw installation. " "Please set qbs.sysroot accordingly for profile '%1'.") .arg(profile.name()); } } if (toolchainType != QLatin1String("clang")) { // Check whether auxiliary tools reside within the toolchain's install path. // This might not be the case when using icecc or another compiler wrapper. const QString compilerDirPath = compiler.absolutePath(); const ToolPathSetup toolPathSetup(&profile, compilerDirPath, details); toolPathSetup.apply(QStringLiteral("ar"), QStringLiteral("cpp.archiverPath")); toolPathSetup.apply(QStringLiteral("as"), QStringLiteral("cpp.assemblerPath")); toolPathSetup.apply(QStringLiteral("nm"), QStringLiteral("cpp.nmPath")); if (doesProfileTargetOS(profile, QStringLiteral("darwin"))) toolPathSetup.apply(QStringLiteral("dsymutil"), QStringLiteral("cpp.dsymutilPath")); else toolPathSetup.apply(QStringLiteral("objcopy"), QStringLiteral("cpp.objcopyPath")); toolPathSetup.apply(QStringLiteral("strip"), QStringLiteral("cpp.stripPath")); } qbsInfo() << Tr::tr("Profile '%1' created for '%2'.") .arg(profile.name(), compiler.absoluteFilePath()); return profile; } void gccProbe(Settings *settings, std::vector &profiles, const QString &compilerName) { qbsInfo() << Tr::tr("Trying to detect %1...").arg(compilerName); QStringList searchPaths; searchPaths << systemSearchPaths() << gnuRegistrySearchPaths() << atmelRegistrySearchPaths() << renesasRl78RegistrySearchPaths() << mplabX32RegistrySearchPaths(); std::vector candidates; const auto filters = buildCompilerNameFilters(compilerName); for (const auto &searchPath : std::as_const(searchPaths)) { const QDir dir(searchPath); const QStringList fileNames = dir.entryList( filters, QDir::Files | QDir::Executable); for (const QString &fileName : fileNames) { // Ignore unexpected compiler names. if (fileName.startsWith(QLatin1String("c89-gcc")) || fileName.startsWith(QLatin1String("c99-gcc"))) { continue; } const QFileInfo candidate(dir.filePath(fileName)); // Filter duplicates. const auto existingEnd = candidates.end(); const auto existingIt = std::find_if( candidates.begin(), existingEnd, [candidate](const QFileInfo &existing) { return isSameExecutable(candidate.absoluteFilePath(), existing.absoluteFilePath()); }); if (existingIt == existingEnd) { // No duplicates are found, just add a new candidate. candidates.push_back(candidate); } else { // Replace the existing entry if a candidate name more than // an existing name. const auto candidateName = candidate.completeBaseName(); const auto existingName = existingIt->completeBaseName(); if (candidateName > existingName) *existingIt = candidate; } } } if (candidates.empty()) { qbsInfo() << Tr::tr("No %1 toolchains found.").arg(compilerName); return; } // Sort candidates so that mingw comes first. Information from mingw profiles is potentially // used for setting up clang profiles. if (HostOsInfo::isWindowsHost()) { std::sort(candidates.begin(), candidates.end(), [](const QFileInfo &fi1, const QFileInfo &fi2) { return fi1.absoluteFilePath().contains(QLatin1String("mingw")) && !fi2.absoluteFilePath().contains(QLatin1String("mingw")); }); } for (const auto &candidate : std::as_const(candidates)) { const QString toolchainType = toolchainTypeFromCompilerName( candidate.baseName()); const QString profileName = buildProfileName(candidate); try { auto profile = createGccProfile(candidate, settings, toolchainType, profileName); profiles.push_back(std::move(profile)); } catch (const qbs::ErrorInfo &info) { qbsWarning() << Tr::tr("Skipping %1: %2").arg(profileName, info.toString()); } } } qbs-src-2.5.1/src/app/qbs-setup-toolchains/gccprobe.h0000644000175100001660000000466714744424375022057 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_GCCPROBE_H #define QBS_SETUPTOOLCHAINS_GCCPROBE_H #include QT_BEGIN_NAMESPACE class QFileInfo; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } qbs::Profile createGccProfile(const QFileInfo &compiler, qbs::Settings *settings, const QString &toolchainType, const QString &profileName = QString()); void gccProbe(qbs::Settings *settings, std::vector &profiles, const QString &compilerName); #endif // Header guard qbs-src-2.5.1/src/app/qbs-setup-toolchains/watcomprobe.h0000644000175100001660000000455014744424375022604 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2022 Denis Shienkov ** 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$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_WATCOMPROBE_H #define QBS_SETUPTOOLCHAINS_WATCOMPROBE_H #include QT_BEGIN_NAMESPACE class QFileInfo; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } // namespace qbs bool isWatcomCompiler(const QString &compilerName); void createWatcomProfile( const QFileInfo &compiler, qbs::Settings *settings, QStringView profileName); void watcomProbe(qbs::Settings *settings, std::vector &profiles); #endif // Header guard qbs-src-2.5.1/src/app/qbs-setup-toolchains/commandlineparser.cpp0000644000175100001660000001342114744424375024315 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "commandlineparser.h" #include #include #include using qbs::Internal::Tr; static QString helpOptionShort() { return QStringLiteral("-h"); } static QString helpOptionLong() { return QStringLiteral("--help"); } static QString detectOption() { return QStringLiteral("--detect"); } static QString typeOption() { return QStringLiteral("--type"); } static QString settingsDirOption() { return QStringLiteral("--settings-dir"); } static QString systemOption() { return QStringLiteral("--system"); } void CommandLineParser::parse(const QStringList &commandLine) { m_commandLine = commandLine; Q_ASSERT(!m_commandLine.empty()); m_command = QFileInfo(m_commandLine.takeFirst()).fileName(); m_helpRequested = false; m_autoDetectionMode = false; m_compilerPath.clear(); m_toolchainType.clear(); m_profileName.clear(); m_settingsDir.clear(); if (m_commandLine.empty()) throwError(Tr::tr("No command-line arguments provided.")); while (!m_commandLine.empty()) { const QString arg = m_commandLine.front(); if (!arg.startsWith(QLatin1Char('-'))) break; m_commandLine.removeFirst(); if (arg == helpOptionShort() || arg == helpOptionLong()) m_helpRequested = true; else if (arg == detectOption()) m_autoDetectionMode = true; else if (arg == systemOption()) m_settingsScope = qbs::Settings::SystemScope; else if (arg == typeOption()) assignOptionArgument(typeOption(), m_toolchainType); else if (arg == settingsDirOption()) assignOptionArgument(settingsDirOption(), m_settingsDir); } if (m_helpRequested || m_autoDetectionMode) { if (!m_commandLine.empty()) complainAboutExtraArguments(); return; } switch (m_commandLine.size()) { case 0: case 1: throwError(Tr::tr("Not enough command-line arguments provided.")); case 2: m_compilerPath = m_commandLine.at(0); m_profileName = m_commandLine.at(1); m_profileName.replace(QLatin1Char('.'), QLatin1Char('-')); break; default: complainAboutExtraArguments(); } } void CommandLineParser::throwError(const QString &message) { qbs::ErrorInfo error(Tr::tr("Syntax error: %1").arg(message)); error.append(usageString()); throw error; } QString CommandLineParser::usageString() const { QString s = Tr::tr("This tool creates qbs profiles from toolchains.\n"); s += Tr::tr("Usage:\n"); s += Tr::tr(" %1 [%2 ] [%4] %3\n") .arg(m_command, settingsDirOption(), detectOption(), systemOption()); s += Tr::tr(" %1 [%3 ] [%4] [%2 ] " " \n") .arg(m_command, typeOption(), settingsDirOption(), systemOption()); s += Tr::tr(" %1 %2|%3\n").arg(m_command, helpOptionShort(), helpOptionLong()); s += Tr::tr("The first form tries to auto-detect all known toolchains, looking them up " "via the PATH environment variable.\n"); s += Tr::tr("The second form creates one profile for one toolchain. It will attempt " "to find out the toolchain type automatically.\nIn case the compiler has " "an unusual file name, you may need to provide the '--type' option."); return s; } void CommandLineParser::assignOptionArgument(const QString &option, QString &argument) { if (m_commandLine.empty()) throwError(Tr::tr("Option '%1' needs an argument.").arg(option)); argument = m_commandLine.takeFirst(); if (argument.isEmpty()) throwError(Tr::tr("Argument for option '%1' must not be empty.").arg(option)); } void CommandLineParser::complainAboutExtraArguments() { throwError(Tr::tr("Extraneous command-line arguments '%1'.") .arg(m_commandLine.join(QLatin1Char(' ')))); } qbs-src-2.5.1/src/app/qbs-setup-toolchains/probe.cpp0000644000175100001660000002763014744424375021730 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "probe.h" #include "clangclprobe.h" #include "cosmicprobe.h" #include "dmcprobe.h" #include "emscriptenprobe.h" #include "gccprobe.h" #include "iarewprobe.h" #include "keilprobe.h" #include "msvcprobe.h" #include "sdccprobe.h" #include "watcomprobe.h" #include "xcodeprobe.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN // We need defines for Windows 8. #undef _WIN32_WINNT #define _WIN32_WINNT _WIN32_WINNT_WIN8 #include #include #else #include #endif // Q_OS_WIN using namespace qbs; using Internal::HostOsInfo; using Internal::Tr; static QTextStream qStdout(stdout); static QTextStream qStderr(stderr); QStringList systemSearchPaths() { return QString::fromLocal8Bit(qgetenv("PATH")).split(HostOsInfo::pathListSeparator()); } QString findExecutable(const QString &fileName) { QStringList suffixList{QString()}; if (HostOsInfo::isWindowsHost()) { if (!fileName.endsWith(QLatin1String(".exe"), Qt::CaseInsensitive) && !fileName.endsWith(QLatin1String(".bat"), Qt::CaseInsensitive)) suffixList = QStringList{QStringLiteral(".exe"), QStringLiteral(".bat")}; } const auto ppaths = systemSearchPaths(); for (const QString &ppath : ppaths) { for (const auto &suffix : suffixList) { const QString fullPath = ppath + QLatin1Char('/') + fileName + suffix; if (QFileInfo::exists(fullPath)) return QDir::cleanPath(fullPath); } } return {}; } QString toolchainTypeFromCompilerName(const QString &compilerName) { if (compilerName == QLatin1String("cl.exe")) return QStringLiteral("msvc"); if (compilerName == QLatin1String("clang-cl.exe")) return QStringLiteral("clang-cl"); const auto types = { QStringLiteral("clang"), QStringLiteral("llvm"), QStringLiteral("mingw"), QStringLiteral("gcc") }; for (const auto &type : types) { if (compilerName.contains(type)) return type; } if (compilerName == QLatin1String("g++")) return QStringLiteral("gcc"); if (isEmscriptenCompiler(compilerName)) return QStringLiteral("emscripten"); if (isIarCompiler(compilerName)) return QStringLiteral("iar"); if (isKeilCompiler(compilerName)) return QStringLiteral("keil"); if (isSdccCompiler(compilerName)) return QStringLiteral("sdcc"); if (isCosmicCompiler(compilerName)) return QStringLiteral("cosmic"); if (isDmcCompiler(compilerName)) return QStringLiteral("dmc"); if (isWatcomCompiler(compilerName)) return QStringLiteral("watcom"); return {}; } void probe(Settings *settings) { std::vector profiles; if (HostOsInfo::isWindowsHost()) { msvcProbe(settings, profiles); clangClProbe(settings, profiles); } else if (HostOsInfo::isMacosHost()) { xcodeProbe(settings, profiles); } gccProbe(settings, profiles, QStringLiteral("gcc")); gccProbe(settings, profiles, QStringLiteral("clang")); iarProbe(settings, profiles); keilProbe(settings, profiles); sdccProbe(settings, profiles); cosmicProbe(settings, profiles); dmcProbe(settings, profiles); watcomProbe(settings, profiles); emscriptenProbe(settings, profiles); if (profiles.empty()) { qStderr << Tr::tr("Could not detect any toolchains. No profile created.") << Qt::endl; } else if (profiles.size() == 1 && settings->defaultProfile().isEmpty()) { const QString profileName = profiles.front().name(); qStdout << Tr::tr("Making profile '%1' the default.").arg(profileName) << Qt::endl; settings->setValue(QStringLiteral("defaultProfile"), profileName); } } void createProfile(const QString &profileName, const QString &toolchainType, const QString &compilerFilePath, Settings *settings) { QFileInfo compiler(compilerFilePath); if (compilerFilePath == compiler.fileName() && !compiler.exists()) compiler = QFileInfo(findExecutable(compilerFilePath)); if (!compiler.exists()) { throw qbs::ErrorInfo(Tr::tr("Compiler '%1' not found") .arg(compilerFilePath)); } const QString realToolchainType = !toolchainType.isEmpty() ? toolchainType : toolchainTypeFromCompilerName(compiler.fileName()); const QStringList toolchain = canonicalToolchain(realToolchainType); if (toolchain.contains(QLatin1String("clang-cl"))) createClangClProfile(compiler, settings, profileName); else if (toolchain.contains(QLatin1String("msvc"))) createMsvcProfile(compiler, settings, profileName); else if (toolchain.contains(QLatin1String("emscripten"))) createEmscriptenProfile(compiler, settings, profileName); else if (toolchain.contains(QLatin1String("gcc"))) createGccProfile(compiler, settings, realToolchainType, profileName); else if (toolchain.contains(QLatin1String("iar"))) createIarProfile(compiler, settings, profileName); else if (toolchain.contains(QLatin1String("keil"))) createKeilProfile(compiler, settings, profileName); else if (toolchain.contains(QLatin1String("sdcc"))) createSdccProfile(compiler, settings, profileName); else if (toolchain.contains(QLatin1String("cosmic"))) createCosmicProfile(compiler, settings, profileName); else if (toolchain.contains(QLatin1String("dmc"))) createDmcProfile(compiler, settings, profileName); else if (toolchain.contains(QLatin1String("watcom"))) createWatcomProfile(compiler, settings, profileName); else throw qbs::ErrorInfo(Tr::tr("Cannot create profile: Unknown toolchain type.")); } int extractVersion(const QByteArray ¯oDump, const QByteArray &keyToken) { const int startIndex = macroDump.indexOf(keyToken); if (startIndex == -1) return -1; const int endIndex = macroDump.indexOf('\n', startIndex); if (endIndex == -1) return -1; const auto keyLength = keyToken.length(); const int version = macroDump.mid(startIndex + keyLength, endIndex - startIndex - keyLength) .toInt(); return version; } static QString resolveSymlinks(const QString &filePath) { QFileInfo fi(filePath); int links = 16; while (links-- && fi.isSymLink()) fi.setFile(fi.dir(), fi.symLinkTarget()); if (links <= 0) return {}; return fi.filePath(); } // Copied from qfilesystemengine_win.cpp. #ifdef Q_OS_WIN // File ID for Windows up to version 7. static inline QByteArray fileIdWin7(HANDLE handle) { BY_HANDLE_FILE_INFORMATION info; if (GetFileInformationByHandle(handle, &info)) { char buffer[sizeof "01234567:0123456701234567\0"]; std::snprintf(buffer, sizeof(buffer), "%lx:%08lx%08lx", info.dwVolumeSerialNumber, info.nFileIndexHigh, info.nFileIndexLow); return QByteArray(buffer); } return {}; } // File ID for Windows starting from version 8. static QByteArray fileIdWin8(HANDLE handle) { QByteArray result; FILE_ID_INFO infoEx = {}; if (::GetFileInformationByHandleEx( handle, static_cast(18), // FileIdInfo in Windows 8 &infoEx, sizeof(FILE_ID_INFO))) { result = QByteArray::number(infoEx.VolumeSerialNumber, 16); result += ':'; // Note: MinGW-64's definition of FILE_ID_128 differs from the MSVC one. result += QByteArray(reinterpret_cast(&infoEx.FileId), int(sizeof(infoEx.FileId))).toHex(); } return result; } static QByteArray fileIdWin(HANDLE fHandle) { return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8 ? fileIdWin8(HANDLE(fHandle)) : fileIdWin7(HANDLE(fHandle)); } static QByteArray fileId(const QString &filePath) { QByteArray result; const HANDLE handle = ::CreateFile( reinterpret_cast(filePath.utf16()), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); if (handle != INVALID_HANDLE_VALUE) { result = fileIdWin(handle); ::CloseHandle(handle); } return result; } static qint64 fileSize(const QString &filePath) { return QFileInfo(filePath).size(); } #else static QByteArray fileId(const QString &filePath) { QByteArray result; if (Q_UNLIKELY(filePath.isEmpty())) return {}; QT_STATBUF statResult = {}; if (QT_STAT(filePath.toLocal8Bit().constData(), &statResult)) return {}; result = QByteArray::number(quint64(statResult.st_dev), 16); result += ':'; result += QByteArray::number(quint64(statResult.st_ino)); return result; } #endif // Q_OS_WIN bool isSameExecutable(const QString &filePath1, const QString &filePath2) { if (filePath1 == filePath2) return true; if (resolveSymlinks(filePath1) == resolveSymlinks(filePath2)) return true; if (fileId(filePath1) == fileId(filePath2)) return true; #ifdef Q_OS_WIN if (fileSize(filePath1) == fileSize(filePath2)) return true; #endif return false; } MacrosMap dumpMacros(const std::function &func) { MacrosMap macros; const QStringList lines = func(); for (const QString &line : lines) { const QString prefix = QLatin1String("#define "); if (!line.startsWith(prefix)) return macros; const auto index = line.indexOf(QLatin1String(" "), prefix.length()); if (index != -1) { const auto key = line.mid(prefix.length(), index - prefix.length()); const auto value = line.mid(index + 1); macros.insert(key, value); } } return macros; } qbs-src-2.5.1/src/app/qbs-setup-toolchains/cosmicprobe.h0000644000175100001660000000455114744424375022570 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Denis Shienkov ** 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$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_COSMICPROBE_H #define QBS_SETUPTOOLCHAINS_COSMICPROBE_H #include QT_BEGIN_NAMESPACE class QFileInfo; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } bool isCosmicCompiler(const QString &compilerName); void createCosmicProfile(const QFileInfo &compiler, qbs::Settings *settings, QString profileName); void cosmicProbe(qbs::Settings *settings, std::vector &profiles); #endif // Header guard qbs-src-2.5.1/src/app/qbs-setup-toolchains/qbs-setup-toolchains.rc0000644000175100001660000000023014744424375024512 0ustar runnerdocker#define RT_MANIFEST 24 #define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "qbs-setup-toolchains.exe.manifest" qbs-src-2.5.1/src/app/qbs-setup-toolchains/clangclprobe.cpp0000644000175100001660000001233614744424375023251 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com) ** Contact: http://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$ ** ****************************************************************************/ #include "clangclprobe.h" #include "msvcprobe.h" #include "probe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include #include using qbs::Settings; using qbs::Profile; using qbs::Internal::ClangClInfo; using qbs::Internal::HostOsInfo; using qbs::Internal::Tr; namespace { Profile createProfileHelper( Settings *settings, const QString &profileName, const QString &toolchainInstallPath, const QString &vcvarsallPath, const QString &architecture) { Profile profile(profileName, settings); profile.removeProfile(); profile.setValue(QStringLiteral("qbs.architecture"), architecture); profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("clang-cl")); profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), toolchainInstallPath); profile.setValue(QStringLiteral("cpp.vcvarsallPath"), vcvarsallPath); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.") .arg(profile.name(), QDir::toNativeSeparators(toolchainInstallPath)); return profile; } QString findClangCl() { const auto compilerName = HostOsInfo::appendExecutableSuffix(QStringLiteral("clang-cl")); auto compilerFromPath = findExecutable(compilerName); if (!compilerFromPath.isEmpty()) return compilerFromPath; return {}; } } // namespace void createClangClProfile(const QFileInfo &compiler, Settings *settings, const QString &profileName) { const auto clangCl = ClangClInfo::fromCompilerFilePath( compiler.filePath(), ConsoleLogger::instance()); if (clangCl.isEmpty()) return; const auto hostArch = HostOsInfo::hostOSArchitecture(); createProfileHelper( settings, profileName, clangCl.toolchainInstallPath, clangCl.vcvarsallPath, hostArch); } /*! \brief Creates a clang-cl profile based on auto-detected vsversion. \internal */ void clangClProbe(Settings *settings, std::vector &profiles) { const auto compilerName = QStringLiteral("clang-cl"); qbsInfo() << Tr::tr("Trying to detect %1...").arg(compilerName); const auto clangCls = ClangClInfo::installedCompilers( {findClangCl()}, ConsoleLogger::instance()); if (clangCls.empty()) { qbsInfo() << Tr::tr("%1 was not found.").arg(compilerName); return; } const QString architectures[] = { QStringLiteral("x86_64"), QStringLiteral("x86") }; for (size_t index = 0; index < clangCls.size(); ++index) { const auto &clangCl = clangCls[index]; const QString suffix = index == 0 ? QString() : QStringLiteral("-%1").arg(index); qbs::Internal::transform( architectures, profiles, [settings, clangCl, suffix](const auto &arch) { const auto profileName = QStringLiteral("clang-cl") + suffix + QStringLiteral("-%1").arg(arch); return createProfileHelper( settings, profileName, clangCl.toolchainInstallPath, clangCl.vcvarsallPath, arch); }); } } qbs-src-2.5.1/src/app/qbs-setup-toolchains/watcomprobe.cpp0000644000175100001660000002341414744424375023137 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2022 Denis Shienkov ** 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$ ** ****************************************************************************/ #include "watcomprobe.h" #include "probe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include using namespace qbs; using Internal::HostOsInfo; using Internal::Tr; namespace { struct Details { QStringView architecture; QStringView platform; }; constexpr struct Platform { QStringView flag; Details keys; Details target; } knownPlatforms[] = { // DOS 16/32 bit. {u"-bdos", {u"__I86__", u"__DOS__"}, {u"x86_16", u"dos"}}, {u"-bdos4g", {u"__386__", u"__DOS__"}, {u"x86", u"dos"}}, // Windows 16/32 bit. {u"-bwindows", {u"__I86__", u"__WINDOWS__"}, {u"x86_16", u"windows"}}, {u"-bnt", {u"__386__", u"__NT__"}, {u"x86", u"windows"}}, // OS/2 16/32 bit. {u"-bos2", {u"__I86__", u"__OS2__"}, {u"x86_16", u"os2"}}, {u"-bos2v2", {u"__386__", u"__OS2__"}, {u"x86", u"os2"}}, // Linux 32 bit. {u"-blinux", {u"__386__", u"__LINUX__"}, {u"x86", u"linux"}}, }; } // namespace static QStringList knownWatcomCompilerNames() { return {QStringLiteral("owcc")}; } static QStringList dumpOutput(const QFileInfo &compiler, QStringView flag, const QList &keys) { const QString filePath = QDir(QDir::tempPath()).absoluteFilePath( QLatin1String("watcom-dump.c")); QFile fakeIn(filePath); if (!fakeIn.open(QIODevice::Truncate | QIODevice::WriteOnly | QIODevice::Text)) { qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2") .arg(fakeIn.fileName(), fakeIn.errorString()); return {}; } fakeIn.write("#define VALUE_TO_STRING(x) #x\n"); fakeIn.write("#define VALUE(x) VALUE_TO_STRING(x)\n"); fakeIn.write("#define VAR_NAME_VALUE(var) \"#define \" #var\" \"VALUE(var)\n"); for (const auto &key : keys) { fakeIn.write("#if defined(" + key.toLatin1() + ")\n"); fakeIn.write("#pragma message (VAR_NAME_VALUE(" + key.toLatin1() + "))\n"); fakeIn.write("#endif\n"); } fakeIn.close(); QProcess p; QStringList args; if (!flag.isEmpty()) args.push_back(flag.toString()); args.push_back(QDir::toNativeSeparators(filePath)); p.start(compiler.absoluteFilePath(), args); p.waitForFinished(3000); fakeIn.remove(); QStringList lines = QString::fromUtf8(p.readAllStandardOutput()) .split(QRegularExpression(QLatin1String("\\r?\\n"))); return lines; } static bool supportsWatcomPlatform(const QFileInfo &compiler, const Platform &platform) { const auto macros = dumpMacros([&compiler, &platform]() { const QList keys = {platform.keys.architecture, platform.keys.platform}; return dumpOutput(compiler, platform.flag, keys); }); auto matches = [¯os](QStringView key) { const auto k = key.toString(); if (!macros.contains(k)) return false; return macros.value(k) == QLatin1String("1"); }; return matches(platform.keys.architecture) && matches(platform.keys.platform); } static std::vector createWatcomProfileHelper(const ToolchainInstallInfo &info, Settings *settings, QStringView profileName = {}) { const QFileInfo compiler = info.compilerPath; std::vector profiles; for (const auto &knownPlatform : knownPlatforms) { // Don't create a profile in case the compiler does // not support the proposed architecture. if (!supportsWatcomPlatform(compiler, knownPlatform)) continue; QString fullProfilename; if (profileName.isEmpty()) { // Create a full profile name in case we is in auto-detecting mode. if (!info.compilerVersion.isValid()) { fullProfilename = QStringLiteral("watcom-unknown-%1-%2") .arg(knownPlatform.target.platform) .arg(knownPlatform.target.architecture); } else { const QString version= info.compilerVersion.toString(QLatin1Char('_'), QLatin1Char('_')); fullProfilename = QStringLiteral("watcom-%1-%2-%3") .arg(version) .arg(knownPlatform.target.platform) .arg(knownPlatform.target.architecture); } } else { // Append the detected actual architecture name to the proposed profile name. fullProfilename = QStringLiteral("%1-%2-%3") .arg(profileName) .arg(knownPlatform.target.platform) .arg(knownPlatform.target.architecture); } Profile profile(fullProfilename, settings); profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath()); profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("watcom")); profile.setValue(QStringLiteral("qbs.architecture"), knownPlatform.target.architecture.toString()); profile.setValue(QStringLiteral("qbs.targetPlatform"), knownPlatform.target.platform.toString()); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.") .arg(profile.name(), compiler.absoluteFilePath()); profiles.push_back(std::move(profile)); } return profiles; } static Version dumpWatcomVersion(const QFileInfo &compiler) { const QList keys = {u"__WATCOMC__", u"__WATCOM_CPLUSPLUS__"}; const auto macros = dumpMacros([&compiler, &keys]() { return dumpOutput(compiler, u"", keys); }); for (const auto ¯o : macros) { const int verCode = macro.toInt(); return Version{(verCode - 1100) / 100, (verCode / 10) % 10, ((verCode % 10) > 0) ? (verCode % 10) : 0}; } qbsWarning() << Tr::tr("No __WATCOMC__ or __WATCOM_CPLUSPLUS__ tokens was found" " in the compiler dump"); return Version{}; } static std::vector installedWatcomsFromPath() { std::vector infos; const auto compilerNames = knownWatcomCompilerNames(); for (const QString &compilerName : compilerNames) { const QFileInfo watcomPath(findExecutable( HostOsInfo::appendExecutableSuffix(compilerName))); if (!watcomPath.exists()) continue; const Version version = dumpWatcomVersion(watcomPath); infos.push_back({watcomPath, version}); } std::sort(infos.begin(), infos.end()); return infos; } bool isWatcomCompiler(const QString &compilerName) { return Internal::any_of(knownWatcomCompilerNames(), [compilerName](const QString &knownName) { return compilerName.contains(knownName); }); } void createWatcomProfile(const QFileInfo &compiler, Settings *settings, QStringView profileName) { const ToolchainInstallInfo info = {compiler, Version{}}; createWatcomProfileHelper(info, settings, profileName); } void watcomProbe(Settings *settings, std::vector &profiles) { qbsInfo() << Tr::tr("Trying to detect WATCOM toolchains..."); const std::vector allInfos = installedWatcomsFromPath(); if (allInfos.empty()) { qbsInfo() << Tr::tr("No WATCOM toolchains found."); return; } for (const ToolchainInstallInfo &info : allInfos) { const auto newProfiles = createWatcomProfileHelper(info, settings); profiles.reserve(profiles.size() + int(newProfiles.size())); std::copy(newProfiles.cbegin(), newProfiles.cend(), std::back_inserter(profiles)); } } qbs-src-2.5.1/src/app/qbs-setup-toolchains/keilprobe.h0000644000175100001660000000453514744424375022241 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** 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$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_KEILPROBE_H #define QBS_SETUPTOOLCHAINS_KEILPROBE_H #include QT_BEGIN_NAMESPACE class QFileInfo; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } bool isKeilCompiler(const QString &compilerName); void createKeilProfile(const QFileInfo &compiler, qbs::Settings *settings, QString profileName); void keilProbe(qbs::Settings *settings, std::vector &profiles); #endif // Header guard qbs-src-2.5.1/src/app/qbs-setup-toolchains/keilprobe.cpp0000644000175100001660000004077514744424375022602 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** 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$ ** ****************************************************************************/ #include "probe.h" #include "keilprobe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include using namespace qbs; using Internal::Tr; using Internal::HostOsInfo; static QStringList knownKeilCompilerNames() { return {QStringLiteral("c51"), QStringLiteral("c251"), QStringLiteral("c166"), QStringLiteral("armcc"), QStringLiteral("armclang")}; } static QString guessKeilArchitecture(const QFileInfo &compiler) { const auto baseName = compiler.baseName(); if (baseName == QLatin1String("c51")) return QStringLiteral("mcs51"); if (baseName == QLatin1String("c251")) return QStringLiteral("mcs251"); if (baseName == QLatin1String("c166")) return QStringLiteral("c166"); if (baseName == QLatin1String("armcc")) return QStringLiteral("arm"); if (baseName == QLatin1String("armclang")) return QStringLiteral("arm"); return {}; } static bool isArmClangCompiler(const QFileInfo &compiler) { return compiler.baseName() == QLatin1String("armclang"); } static Profile createKeilProfileHelper(const ToolchainInstallInfo &info, Settings *settings, QString profileName = QString()) { const QFileInfo compiler = info.compilerPath; const QString architecture = guessKeilArchitecture(compiler); // In case the profile is auto-detected. if (profileName.isEmpty()) { if (!info.compilerVersion.isValid()) { profileName = QStringLiteral("keil-unknown-%1").arg(architecture); } else { const QString version = info.compilerVersion.toString(QLatin1Char('_'), QLatin1Char('_')); if (architecture == QLatin1String("arm") && isArmClangCompiler(compiler)) { profileName = QStringLiteral("keil-llvm-%1-%2").arg( version, architecture); } else { profileName = QStringLiteral("keil-%1-%2").arg( version, architecture); } } } Profile profile(profileName, settings); profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath()); profile.setValue(QStringLiteral("cpp.compilerName"), compiler.fileName()); profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("keil")); if (!architecture.isEmpty()) profile.setValue(QStringLiteral("qbs.architecture"), architecture); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.").arg( profile.name(), compiler.absoluteFilePath()); return profile; } static Version dumpMcsCompilerVersion(const QFileInfo &compiler) { QTemporaryFile fakeIn; if (!fakeIn.open()) { qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2") .arg(fakeIn.fileName(), fakeIn.errorString()); return Version{}; } fakeIn.write("#define VALUE_TO_STRING(x) #x\n"); fakeIn.write("#define VALUE(x) VALUE_TO_STRING(x)\n"); // Prepare for C51 compiler. fakeIn.write("#if defined(__C51__) || defined(__CX51__)\n"); fakeIn.write("# define VAR_NAME_VALUE(var) \"(\"\"\"\"|\"#var\"|\"VALUE(var)\"|\"\"\"\")\"\n"); fakeIn.write("# if defined (__C51__)\n"); fakeIn.write("# pragma message (VAR_NAME_VALUE(__C51__))\n"); fakeIn.write("# endif\n"); fakeIn.write("# if defined(__CX51__)\n"); fakeIn.write("# pragma message (VAR_NAME_VALUE(__CX51__))\n"); fakeIn.write("# endif\n"); fakeIn.write("#endif\n"); // Prepare for C251 compiler. fakeIn.write("#if defined(__C251__)\n"); fakeIn.write("# define VAR_NAME_VALUE(var) \"\"|#var|VALUE(var)|\"\"\n"); fakeIn.write("# if defined(__C251__)\n"); fakeIn.write("# warning (VAR_NAME_VALUE(__C251__))\n"); fakeIn.write("# endif\n"); fakeIn.write("#endif\n"); fakeIn.close(); const QStringList args = {fakeIn.fileName()}; QProcess p; p.start(compiler.absoluteFilePath(), args); p.waitForFinished(3000); const QStringList knownKeys = {QStringLiteral("__C51__"), QStringLiteral("__CX51__"), QStringLiteral("__C251__")}; auto extractVersion = [&knownKeys](const QByteArray &output) { QTextStream stream(output); QString line; while (stream.readLineInto(&line)) { if (!line.startsWith(QLatin1String("***"))) continue; enum { KEY_INDEX = 1, VALUE_INDEX = 2, ALL_PARTS = 4 }; const QStringList parts = line.split(QLatin1String("\"|\"")); if (parts.count() != ALL_PARTS) continue; if (!knownKeys.contains(parts.at(KEY_INDEX))) continue; return parts.at(VALUE_INDEX).toInt(); } return -1; }; const QByteArray dump = p.readAllStandardOutput(); const int verCode = extractVersion(dump); if (verCode < 0) { qbsWarning() << Tr::tr("No %1 tokens was found" " in the compiler dump:\n%2") .arg(knownKeys.join(QLatin1Char(',')), QString::fromUtf8(dump)); return Version{}; } return Version{verCode / 100, verCode % 100}; } static Version dumpC166CompilerVersion(const QFileInfo &compiler) { QTemporaryFile fakeIn; if (!fakeIn.open()) { qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2") .arg(fakeIn.fileName(), fakeIn.errorString()); return Version{}; } fakeIn.write("#if defined(__C166__)\n"); fakeIn.write("# warning __C166__\n"); fakeIn.write("# pragma __C166__\n"); fakeIn.write("#endif\n"); fakeIn.close(); const QStringList args = {fakeIn.fileName()}; QProcess p; p.start(compiler.absoluteFilePath(), args); p.waitForFinished(3000); // Extract the compiler version pattern in the form, like: // // *** WARNING C320 IN LINE 41 OF c51.c: __C166__ // *** WARNING C2 IN LINE 42 OF c51.c: '757': unknown #pragma/control, line ignored // // where the '__C166__' is a key, and the '757' is a value (aka version). auto extractVersion = [](const QString &output) { const QStringList lines = output.split(QStringLiteral("\r\n")); for (auto it = lines.cbegin(); it != lines.cend();) { if (it->startsWith(QLatin1String("***")) && it->endsWith(QLatin1String("__C166__"))) { ++it; if (it == lines.cend() || !it->startsWith(QLatin1String("***"))) break; const int startIndex = it->indexOf(QLatin1Char('\'')); if (startIndex == -1) break; const int stopIndex = it->indexOf(QLatin1Char('\''), startIndex + 1); if (stopIndex == -1) break; const QString v = it->mid(startIndex + 1, stopIndex - startIndex - 1); return v.toInt(); } ++it; } return -1; }; const QByteArray dump = p.readAllStandardOutput(); const int verCode = extractVersion(QString::fromUtf8(dump)); if (verCode < 0) { qbsWarning() << Tr::tr("No __C166__ token was found" " in the compiler dump:\n%1") .arg(QString::fromUtf8(dump)); return Version{}; } return Version{verCode / 100, verCode % 100}; } static Version dumpArmCCCompilerVersion(const QFileInfo &compiler) { const QStringList args = {QStringLiteral("-E"), QStringLiteral("--list-macros"), QStringLiteral("nul")}; QProcess p; p.start(compiler.absoluteFilePath(), args); p.waitForFinished(3000); const auto es = p.exitStatus(); if (es != QProcess::NormalExit) { const QByteArray out = p.readAll(); qbsWarning() << Tr::tr("Compiler dumping failed:\n%1") .arg(QString::fromUtf8(out)); return Version{}; } const QByteArray dump = p.readAll(); const int verCode = extractVersion(dump, "__ARMCC_VERSION "); if (verCode < 0) { qbsWarning() << Tr::tr("No '__ARMCC_VERSION' token was found " "in the compiler dump:\n%1") .arg(QString::fromUtf8(dump)); return Version{}; } return Version{verCode / 1000000, (verCode / 10000) % 100, verCode % 10000}; } static Version dumpArmClangCompilerVersion(const QFileInfo &compiler) { const QStringList args = {QStringLiteral("-dM"), QStringLiteral("-E"), QStringLiteral("-xc"), QStringLiteral("--target=arm-arm-none-eabi"), QStringLiteral("-mcpu=cortex-m0"), QStringLiteral("nul")}; QProcess p; p.start(compiler.absoluteFilePath(), args); p.waitForFinished(3000); const auto es = p.exitStatus(); if (es != QProcess::NormalExit) { const QByteArray out = p.readAll(); qbsWarning() << Tr::tr("Compiler dumping failed:\n%1") .arg(QString::fromUtf8(out)); return Version{}; } const QByteArray dump = p.readAll(); const int verCode = extractVersion(dump, "__ARMCC_VERSION "); if (verCode < 0) { qbsWarning() << Tr::tr("No '__ARMCC_VERSION' token was found " "in the compiler dump:\n%1") .arg(QString::fromUtf8(dump)); return Version{}; } return Version{verCode / 1000000, (verCode / 10000) % 100, verCode % 10000}; } static Version dumpKeilCompilerVersion(const QFileInfo &compiler) { const QString arch = guessKeilArchitecture(compiler); if (arch == QLatin1String("mcs51") || arch == QLatin1String("mcs251")) return dumpMcsCompilerVersion(compiler); if (arch == QLatin1String("c166")) return dumpC166CompilerVersion(compiler); if (arch == QLatin1String("arm")) { if (isArmClangCompiler(compiler)) return dumpArmClangCompilerVersion(compiler); return dumpArmCCCompilerVersion(compiler); } return Version{}; } static std::vector installedKeilsFromPath() { std::vector infos; const auto compilerNames = knownKeilCompilerNames(); for (const QString &compilerName : compilerNames) { const QFileInfo keilPath( findExecutable( HostOsInfo::appendExecutableSuffix(compilerName))); if (!keilPath.exists()) continue; const Version version = dumpKeilCompilerVersion(keilPath); infos.push_back({keilPath, version}); } std::sort(infos.begin(), infos.end()); return infos; } static std::vector installedKeilsFromRegistry() { std::vector infos; if (HostOsInfo::isWindowsHost()) { #ifdef Q_OS_WIN64 static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Keil\\Products"; #else static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Keil\\Products"; #endif QSettings registry(QLatin1String(kRegistryNode), QSettings::NativeFormat); const auto productGroups = registry.childGroups(); for (const QString &productKey : productGroups) { registry.beginGroup(productKey); const QString productPath = registry.value(QStringLiteral("Path")) .toString(); QString productVersion = registry.value(QStringLiteral("Version")) .toString(); if (productVersion.startsWith(QLatin1Char('V'))) productVersion.remove(0, 1); if (productKey == QLatin1String("MDK")) { const QFileInfo ccPath(productPath + QStringLiteral("/ARMCC/bin/armcc.exe")); if (ccPath.exists()) infos.push_back({ccPath, Version::fromString(productVersion)}); const QFileInfo clangPath(productPath + QStringLiteral("/ARMCLANG/bin/armclang.exe")); if (clangPath.exists()) infos.push_back({clangPath, Version::fromString(productVersion)}); } if (productKey == QLatin1String("C51")) { const QFileInfo cPath(productPath + QStringLiteral("/BIN/c51.exe")); if (cPath.exists()) infos.push_back({cPath, Version::fromString(productVersion)}); } if (productKey == QLatin1String("C251")) { const QFileInfo cPath(productPath + QStringLiteral("/BIN/c251.exe")); if (cPath.exists()) infos.push_back({cPath, Version::fromString(productVersion)}); } if (productKey == QLatin1String("C166")) { const QFileInfo cPath(productPath + QStringLiteral("/BIN/c166.exe")); if (cPath.exists()) infos.push_back({cPath, Version::fromString(productVersion)}); } registry.endGroup(); } } std::sort(infos.begin(), infos.end()); return infos; } bool isKeilCompiler(const QString &compilerName) { return Internal::any_of(knownKeilCompilerNames(), [compilerName]( const QString &knownName) { return compilerName.contains(knownName); }); } void createKeilProfile(const QFileInfo &compiler, Settings *settings, QString profileName) { const ToolchainInstallInfo info = {compiler, Version{}}; createKeilProfileHelper(info, settings, std::move(profileName)); } void keilProbe(Settings *settings, std::vector &profiles) { qbsInfo() << Tr::tr("Trying to detect KEIL toolchains..."); // Make sure that a returned infos are sorted before using the std::set_union! const std::vector regInfos = installedKeilsFromRegistry(); const std::vector pathInfos = installedKeilsFromPath(); std::vector allInfos; allInfos.reserve(regInfos.size() + pathInfos.size()); std::set_union(regInfos.cbegin(), regInfos.cend(), pathInfos.cbegin(), pathInfos.cend(), std::back_inserter(allInfos)); qbs::Internal::transform(allInfos, profiles, [settings](const auto &info) { return createKeilProfileHelper(info, settings); }); if (allInfos.empty()) qbsInfo() << Tr::tr("No KEIL toolchains found."); } qbs-src-2.5.1/src/app/qbs-setup-toolchains/emscriptenprobe.cpp0000644000175100001660000000767314744424375024027 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 Danya Patrushev ** 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$ ** ****************************************************************************/ #include "emscriptenprobe.h" #include "../shared/logging/consolelogger.h" #include "probe.h" #include #include #include #include #include #include #include #include using namespace qbs; using Internal::HostOsInfo; using Internal::Tr; namespace { qbs::Profile writeProfile( const QString &profileName, const QFileInfo &compiler, qbs::Settings *settings) { qbs::Profile profile(profileName, settings); profile.setValue(QStringLiteral("qbs.architecture"), QStringLiteral("wasm")); profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("emscripten")); profile.setValue(QStringLiteral("qbs.targetPlatform"), QStringLiteral("wasm-emscripten")); profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath()); return profile; } } //namespace bool isEmscriptenCompiler(const QString &compilerName) { return compilerName.startsWith(QLatin1String("emcc")) || compilerName.startsWith(QLatin1String("em++")); } qbs::Profile createEmscriptenProfile( const QFileInfo &compiler, qbs::Settings *settings, const QString &profileName) { qbs::Profile profile = writeProfile(profileName, compiler, settings); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.") .arg(profile.name(), compiler.absoluteFilePath()); return profile; } void emscriptenProbe(qbs::Settings *settings, std::vector &profiles) { qbsInfo() << Tr::tr("Trying to detect emscripten toolchain..."); const QString emcc = HostOsInfo::isWindowsHost() ? QStringLiteral("emcc.bat") : QStringLiteral("emcc"); const QString compilerPath = findExecutable(emcc); if (compilerPath.isEmpty()) { qbsInfo() << Tr::tr("No emscripten toolchain found."); return; } const qbs::Profile profile = createEmscriptenProfile( QFileInfo(compilerPath), settings, QLatin1String("wasm")); profiles.push_back(profile); } qbs-src-2.5.1/src/app/qbs-setup-toolchains/dmcprobe.h0000644000175100001660000000453314744424375022056 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2021 Denis Shienkov ** 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$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_DMCPROBE_H #define QBS_SETUPTOOLCHAINS_DMCPROBE_H #include QT_BEGIN_NAMESPACE class QFileInfo; QT_END_NAMESPACE namespace qbs { class Profile; class Settings; } bool isDmcCompiler(const QString &compilerName); void createDmcProfile(const QFileInfo &compiler, qbs::Settings *settings, QStringView profileName); void dmcProbe(qbs::Settings *settings, std::vector &profiles); #endif // Header guard qbs-src-2.5.1/src/app/qbs-setup-toolchains/sdccprobe.cpp0000644000175100001660000002521214744424375022557 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 Denis Shienkov ** 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$ ** ****************************************************************************/ #include "probe.h" #include "sdccprobe.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include using namespace qbs; using Internal::Tr; using Internal::HostOsInfo; static QStringList knownSdccCompilerNames() { return {QStringLiteral("sdcc")}; } static QStringList dumpOutput(const QFileInfo &compiler, const QString &targetFlag = QString()) { QTemporaryFile fakeIn(QStringLiteral("XXXXXX.c")); if (!fakeIn.open()) { qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2") .arg(fakeIn.fileName(), fakeIn.errorString()); return {}; } fakeIn.close(); const QStringList args = {QStringLiteral("-dM"), QStringLiteral("-E"), targetFlag, fakeIn.fileName()}; QProcess p; p.start(compiler.absoluteFilePath(), args); p.waitForFinished(3000); const auto es = p.exitStatus(); if (es != QProcess::NormalExit) { const QByteArray out = p.readAll(); qbsWarning() << Tr::tr("Compiler dumping failed:\n%1").arg(QString::fromUtf8(out)); return {}; } static QRegularExpression re(QStringLiteral("\\r?\\n")); return QString::fromUtf8(p.readAllStandardOutput()).split(re); } static bool supportsSdccArchitecture(const QFileInfo &compiler, QStringView flag) { const auto target = QStringLiteral("-m%1").arg(flag); const auto macros = dumpMacros([&compiler, &target]() { return dumpOutput(compiler, target); }); const auto token = QStringLiteral("__SDCC_%1").arg(flag); return macros.contains(token); } static std::vector createSdccProfileHelper(const ToolchainInstallInfo &info, Settings *settings, const QString &profileName = QString()) { const QFileInfo compiler = info.compilerPath; std::vector profiles; static constexpr struct KnownArch { QStringView architecture; QStringView flag; } knownArchs[] = {{u"mcs51", u"mcs51"}, {u"stm8", u"stm8"}, {u"hcs8", u"hc08"}}; for (const auto &knownArch : knownArchs) { // Don't create a profile in case the compiler does // not support the proposed architecture. if (!supportsSdccArchitecture(compiler, knownArch.flag)) continue; QString fullProfileName; if (profileName.isEmpty()) { // Create a full profile name in case we is // in auto-detecting mode. if (!info.compilerVersion.isValid()) { fullProfileName = QStringLiteral("sdcc-unknown-%1").arg(knownArch.architecture); } else { const QString version = info.compilerVersion.toString( QLatin1Char('_'), QLatin1Char('_')); fullProfileName = QStringLiteral("sdcc-%1-%2").arg( version, knownArch.architecture); } } else { // Append the detected actual architecture name // to the proposed profile name. fullProfileName = QStringLiteral("%1-%2").arg(profileName, knownArch.architecture); } Profile profile(fullProfileName, settings); profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath()); profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("sdcc")); profile.setValue(QStringLiteral("qbs.architecture"), knownArch.architecture.toString()); qbsInfo() << Tr::tr("Profile '%1' created for '%2'.").arg( profile.name(), compiler.absoluteFilePath()); profiles.push_back(std::move(profile)); } return profiles; } static Version dumpSdccVersion(const QFileInfo &compiler) { const auto macros = dumpMacros([&compiler]() { return dumpOutput(compiler); }); if (!macros.contains(QLatin1String("__SDCC"))) { qbsWarning() << Tr::tr("No __SDCC token was found in the compiler dump"); return Version{}; } auto value = macros.value(QLatin1String("__SDCC")); value.replace(QLatin1Char('_'), QLatin1Char('.')); return Version::fromString(value); } static std::vector installedSdccsFromPath() { std::vector infos; const auto compilerNames = knownSdccCompilerNames(); for (const QString &compilerName : compilerNames) { const QFileInfo sdccPath( findExecutable( HostOsInfo::appendExecutableSuffix(compilerName))); if (!sdccPath.exists()) continue; const Version version = dumpSdccVersion(sdccPath); infos.push_back({sdccPath, version}); } std::sort(infos.begin(), infos.end()); return infos; } static std::vector installedSdccsFromRegistry() { std::vector infos; if (HostOsInfo::isWindowsHost()) { // Tries to detect the candidate from the 32-bit // or 64-bit system registry format. auto probeSdccToolchainInfo = [](QSettings::Format format) { SdccInstallInfo info; QSettings registry(QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\SDCC"), format); const QString rootPath = registry.value(QStringLiteral("Default")) .toString(); if (rootPath.isEmpty()) return info; // Build full compiler path. const QFileInfo sdccPath(rootPath + QLatin1String("\\bin\\sdcc.exe")); if (!sdccPath.exists()) return info; info.compilerPath = sdccPath.filePath(); // Build compiler version. const QString version = QStringLiteral("%1.%2.%3").arg( registry.value(QStringLiteral("VersionMajor")).toString(), registry.value(QStringLiteral("VersionMinor")).toString(), registry.value(QStringLiteral("VersionRevision")).toString()); info.version = version; return info; }; static constexpr QSettings::Format allowedFormats[] = { QSettings::NativeFormat, #ifdef Q_OS_WIN QSettings::Registry32Format, QSettings::Registry64Format, #endif }; for (const QSettings::Format format : allowedFormats) { const SdccInstallInfo candidate = probeSdccToolchainInfo(format); if (candidate.compilerPath.isEmpty()) continue; const auto infosEnd = infos.cend(); const auto infosIt = std::find_if(infos.cbegin(), infosEnd, [candidate](const ToolchainInstallInfo &info) { return candidate == SdccInstallInfo{ info.compilerPath.filePath(), info.compilerVersion.toString()}; }); if (infosIt == infosEnd) { infos.push_back({QFileInfo(candidate.compilerPath), Version::fromString(candidate.version)}); } } } std::sort(infos.begin(), infos.end()); return infos; } bool isSdccCompiler(const QString &compilerName) { return Internal::any_of(knownSdccCompilerNames(), [compilerName]( const QString &knownName) { return compilerName.contains(knownName); }); } void createSdccProfile(const QFileInfo &compiler, Settings *settings, const QString &profileName) { const ToolchainInstallInfo info = {compiler, Version{}}; createSdccProfileHelper(info, settings, profileName); } void sdccProbe(Settings *settings, std::vector &profiles) { qbsInfo() << Tr::tr("Trying to detect SDCC toolchains..."); // Make sure that a returned infos are sorted before using the std::set_union! const std::vector regInfos = installedSdccsFromRegistry(); const std::vector pathInfos = installedSdccsFromPath(); std::vector allInfos; allInfos.reserve(regInfos.size() + pathInfos.size()); std::set_union(regInfos.cbegin(), regInfos.cend(), pathInfos.cbegin(), pathInfos.cend(), std::back_inserter(allInfos)); if (allInfos.empty()) qbsInfo() << Tr::tr("No SDCC toolchains found."); for (const ToolchainInstallInfo &info : allInfos) { const auto newProfiles = createSdccProfileHelper(info, settings); profiles.reserve(profiles.size() + int(newProfiles.size())); std::copy(newProfiles.cbegin(), newProfiles.cend(), std::back_inserter(profiles)); } } qbs-src-2.5.1/src/app/config/0000755000175100001660000000000014744424375015266 5ustar runnerdockerqbs-src-2.5.1/src/app/config/configcommandexecutor.h0000644000175100001660000000512514744424375022025 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef CONFIGCOMMANDEXECUTOR_H #define CONFIGCOMMANDEXECUTOR_H #include #include class ConfigCommand; class ConfigCommandExecutor { Q_DECLARE_TR_FUNCTIONS(ConfigCommandExecutor) public: ConfigCommandExecutor(qbs::Settings *settings, qbs::Settings::Scopes scope); void execute(const ConfigCommand &command); private: void setValue(const QString &key, const QString &rawInput); void printSettings(const ConfigCommand &command); void printOneSetting(const QString &key); void exportSettings(const QString &filename); void importSettings(const QString &filename); qbs::Settings *m_settings; const qbs::Settings::Scopes m_scope; }; #endif // CONFIGCOMMANDEXECUTOR_H qbs-src-2.5.1/src/app/config/config.qbs0000644000175100001660000000037614744424375017250 0ustar runnerdockerQbsApp { name: "qbs-config" files: [ "configcommand.h", "configcommandexecutor.cpp", "configcommandexecutor.h", "configcommandlineparser.cpp", "configcommandlineparser.h", "configmain.cpp" ] } qbs-src-2.5.1/src/app/config/CMakeLists.txt0000644000175100001660000000041314744424375020024 0ustar runnerdockerset(SOURCES configcommand.h configcommandexecutor.cpp configcommandexecutor.h configcommandlineparser.cpp configcommandlineparser.h configmain.cpp ) add_qbs_app(qbs-config DEPENDS qbscore qbsconsolelogger SOURCES ${SOURCES} ) qbs-src-2.5.1/src/app/config/configcommandlineparser.cpp0000644000175100001660000001635414744424375022674 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "configcommandlineparser.h" #include #include #include using namespace qbs; using namespace Internal; void ConfigCommandLineParser::parse(const QStringList &commandLine) { m_command = ConfigCommand(); m_helpRequested = false; m_settingsDir.clear(); m_commandLine = commandLine; if (m_commandLine.empty()) throw Error(Tr::tr("No parameters supplied.")); if (m_commandLine.size() == 1 && (m_commandLine.front() == QLatin1String("--help") || m_commandLine.front() == QLatin1String("-h"))) { m_helpRequested = true; return; } while (!m_commandLine.empty() && m_commandLine.front().startsWith(QLatin1String("--"))) { const QString arg = m_commandLine.takeFirst().mid(2); if (arg == QLatin1String("list")) setCommand(ConfigCommand::CfgList); else if (arg == QLatin1String("unset")) setCommand(ConfigCommand::CfgUnset); else if (arg == QLatin1String("export")) setCommand(ConfigCommand::CfgExport); else if (arg == QLatin1String("import")) setCommand(ConfigCommand::CfgImport); else if (arg == QLatin1String("add-profile")) setCommand(ConfigCommand::CfgAddProfile); else if (arg == QLatin1String("settings-dir")) assignOptionArgument(arg, m_settingsDir); else if (arg == QLatin1String("user")) setScope(qbs::Settings::UserScope); else if (arg == QLatin1String("system")) setScope(qbs::Settings::SystemScope); else throw Error(Tr::tr("Unknown option for config command.")); } switch (command().command) { case ConfigCommand::CfgNone: if (m_commandLine.empty()) throw Error(Tr::tr("No parameters supplied.")); if (m_commandLine.size() > 2) throw Error(Tr::tr("Too many arguments.")); m_command.varNames << m_commandLine.front(); if (m_commandLine.size() == 1) { setCommand(ConfigCommand::CfgList); } else { m_command.varValue = m_commandLine.at(1); setCommand(ConfigCommand::CfgSet); } break; case ConfigCommand::CfgUnset: if (m_commandLine.empty()) throw Error(Tr::tr("Need name of variable to unset.")); m_command.varNames = m_commandLine; break; case ConfigCommand::CfgExport: if (m_commandLine.size() != 1) throw Error(Tr::tr("Need name of file to which to export.")); m_command.fileName = m_commandLine.front(); break; case ConfigCommand::CfgImport: if (m_commandLine.size() != 1) throw Error(Tr::tr("Need name of file from which to import.")); m_command.fileName = m_commandLine.front(); break; case ConfigCommand::CfgList: m_command.varNames = m_commandLine; break; case ConfigCommand::CfgAddProfile: if (m_commandLine.empty()) throw Error(Tr::tr("Profile name missing.")); m_command.varValue = m_commandLine.takeFirst(); if (m_command.varValue.isEmpty()) throw Error(Tr::tr("Profile name must not be empty.")); m_command.varNames = m_commandLine; if (m_command.varNames.isEmpty()) throw Error(Tr::tr("Profile properties must be provided.")); if (m_command.varNames.size() % 2 != 0) throw Error(Tr::tr("Profile properties must be key/value pairs.")); for (const auto &varName : std::as_const(m_command.varNames)) { if (varName.isEmpty()) throw Error(Tr::tr("Property names must not be empty.")); } break; default: break; } } void ConfigCommandLineParser::setCommand(ConfigCommand::Command command) { if (m_command.command != ConfigCommand::CfgNone) throw Error(Tr::tr("You cannot specify more than one command.")); m_command.command = command; } void ConfigCommandLineParser::setScope(Settings::Scope scope) { if (m_scope != qbs::Settings::allScopes()) throw Error(Tr::tr("The --user and --system options can only appear once.")); m_scope = scope; } void ConfigCommandLineParser::printUsage() const { std::puts("Usage:\n" " qbs config [--settings-dir \n" " qbs config [--settings-dir \n" " qbs config [--settings-dir " "\n" "Options:\n" " --list [ ...] list keys under key or all keys\n" " --user consider only user-level settings\n" " --system consider only system-level settings\n" " --unset remove key with given name\n" " --add-profile ... add profile with the given name and properties\n" " --import import settings from given file\n" " --export export settings to given file\n"); } void ConfigCommandLineParser::assignOptionArgument(const QString &option, QString &argument) { if (m_commandLine.empty()) throw Error(Tr::tr("Option '%1' needs an argument.").arg(option)); argument = m_commandLine.takeFirst(); if (argument.isEmpty()) throw Error(Tr::tr("Argument for option '%1' must not be empty.").arg(option)); } qbs-src-2.5.1/src/app/config/configmain.cpp0000644000175100001660000000565414744424375020116 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "configcommandlineparser.h" #include "configcommandexecutor.h" #include #include #include #include #include #include using qbs::Internal::Tr; using qbs::Settings; int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); ConfigCommandLineParser parser; try { parser.parse(app.arguments().mid(1)); if (parser.helpRequested()) { std::cout << qPrintable(Tr::tr("This tool manages qbs settings.")) << std::endl; parser.printUsage(); return EXIT_SUCCESS; } Settings settings(parser.settingsDir()); ConfigCommandExecutor(&settings, parser.scope()).execute(parser.command()); } catch (const ConfigCommandLineParser::Error &e) { std::cerr << qPrintable(e.message()) << std::endl; parser.printUsage(); return EXIT_FAILURE; } catch (const qbs::ErrorInfo &e) { std::cerr << qPrintable(e.toString()) << std::endl; return EXIT_FAILURE; } } qbs-src-2.5.1/src/app/config/configcommandexecutor.cpp0000644000175100001660000002053214744424375022357 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "configcommandexecutor.h" #include "configcommand.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include #include using namespace qbs; static QJsonObject settingsToJSONObject( Settings &settings, qbs::Settings::Scopes scopes, const QString &parentGroup = {}) { QJsonObject result; const auto allKeys = settings.directChildren(parentGroup, scopes); for (const auto& key : allKeys) { const auto fullKey = parentGroup.isEmpty() ? key : QStringLiteral("%1.%2").arg(parentGroup, key); const auto value = settings.value(fullKey, scopes); if (value.isValid()) { // looks like a real value result[key] = QJsonValue::fromVariant(value); } else { // looks like a group result[key] = settingsToJSONObject(settings, scopes, fullKey); } } return result; } static void settingsFromJSONObject( Settings &settings, const QJsonObject &object, const QString &parentGroup = {}) { for (auto it = object.begin(), end = object.end(); it != end; ++it) { const auto key = it.key(); const auto value = it.value(); const auto fullKey = parentGroup.isEmpty() ? key : QStringLiteral("%1.%2").arg(parentGroup, key); if (value.isObject()) { settingsFromJSONObject(settings, it.value().toObject(), fullKey); } else { settings.setValue(fullKey, value.toVariant()); } } } ConfigCommandExecutor::ConfigCommandExecutor(Settings *settings, Settings::Scopes scope) : m_settings(settings), m_scope(scope) { if (m_scope == qbs::Settings::SystemScope) m_settings->setScopeForWriting(qbs::Settings::SystemScope); } void ConfigCommandExecutor::execute(const ConfigCommand &command) { switch (command.command) { case ConfigCommand::CfgList: printSettings(command); break; case ConfigCommand::CfgSet: setValue(command.varNames.front(), command.varValue); break; case ConfigCommand::CfgUnset: for (const QString &varName : command.varNames) m_settings->remove(varName); break; case ConfigCommand::CfgAddProfile: { Profile profile(command.varValue, m_settings); profile.removeProfile(); Q_ASSERT(command.varNames.size() % 2 == 0); for (int i = 0; i < command.varNames.size(); i += 2) { const QString &key = command.varNames.at(i); const QString &rawValue = command.varNames.at(i + 1); profile.setValue(key, representationToSettingsValue(rawValue)); } break; } case ConfigCommand::CfgExport: exportSettings(command.fileName); break; case ConfigCommand::CfgImport: // Display old and new settings, in case import fails or user accidentally nukes everything std::printf("old "); // Will end up as "old settings:" printSettings(command); importSettings(command.fileName); std::printf("\nnew "); printSettings(command); break; case ConfigCommand::CfgNone: qFatal("%s: Impossible command value.", Q_FUNC_INFO); break; } } void ConfigCommandExecutor::setValue(const QString &key, const QString &rawInput) { m_settings->setValue(key, representationToSettingsValue(rawInput)); } void ConfigCommandExecutor::printSettings(const ConfigCommand &command) { if (command.varNames.empty()) { const auto keys = m_settings->allKeys(m_scope); for (const QString &key : keys) printOneSetting(key); } else { for (const QString &parentKey : command.varNames) { if (m_settings->value(parentKey, m_scope).isValid()) { // Key is a leaf. printOneSetting(parentKey); } else { // Key is a node. const auto keys = m_settings->allKeysWithPrefix(parentKey, m_scope); for (const QString &key : keys) printOneSetting(parentKey + QLatin1Char('.') + key); } } } } void ConfigCommandExecutor::printOneSetting(const QString &key) { std::printf("%s: %s\n", qPrintable(key), qPrintable(qbs::settingsValueToRepresentation(m_settings->value(key, m_scope)))); } void ConfigCommandExecutor::exportSettings(const QString &filename) { QFile file(filename); if (!file.open(QFile::Truncate | QFile::WriteOnly | QFile::Text)) { throw ErrorInfo(tr("Could not open file '%1' for writing: %2") .arg(QDir::toNativeSeparators(filename), file.errorString())); } if (QFileInfo(filename).suffix() == u"json") { QJsonDocument doc; doc.setObject(settingsToJSONObject(*m_settings, m_scope)); file.write(doc.toJson()); } else { QTextStream stream(&file); setupDefaultCodec(stream); const auto keys = m_settings->allKeys(m_scope); for (const QString &key : keys) stream << key << ": " << qbs::settingsValueToRepresentation(m_settings->value(key, m_scope)) << Qt::endl; } } void ConfigCommandExecutor::importSettings(const QString &filename) { QFile file(filename); if (!file.open(QFile::ReadOnly | QFile::Text)) { throw ErrorInfo(tr("Could not open file '%1' for reading: %2") .arg(QDir::toNativeSeparators(filename), file.errorString())); } // Remove all current settings const auto keys = m_settings->allKeys(m_scope); for (const QString &key : keys) m_settings->remove(key); if (QFileInfo(filename).suffix() == u"json") { const auto doc = QJsonDocument::fromJson(file.readAll()); const auto object = doc.object(); settingsFromJSONObject(*m_settings, doc.object()); } else { QTextStream stream(&file); setupDefaultCodec(stream); while (!stream.atEnd()) { QString line = stream.readLine(); int colon = line.indexOf(QLatin1Char(':')); if (colon >= 0 && !line.startsWith(QLatin1Char('#'))) { const QString key = line.left(colon).trimmed(); const QString value = line.mid(colon + 1).trimmed(); m_settings->setValue(key, representationToSettingsValue(value)); } } } } qbs-src-2.5.1/src/app/config/configcommandlineparser.h0000644000175100001660000000566114744424375022340 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef COMMANDLINEPARSER_H #define COMMANDLINEPARSER_H #include "configcommand.h" #include #include class ConfigCommandLineParser { public: void parse(const QStringList &commandLine); ConfigCommand command() const { return m_command; } qbs::Settings::Scopes scope() const { return m_scope; } QString settingsDir() const { return m_settingsDir; } bool helpRequested() const { return m_helpRequested; } void printUsage() const; class Error { public: Error(QString message) : m_message(std::move(message)) { } QString message() const { return m_message; } private: QString m_message; }; private: void assignOptionArgument(const QString &option, QString &argument); void setCommand(ConfigCommand::Command command); void setScope(qbs::Settings::Scope scope); ConfigCommand m_command; qbs::Settings::Scopes m_scope = qbs::Settings::allScopes(); bool m_helpRequested = false; QString m_settingsDir; QStringList m_commandLine; }; #endif // COMMANDLINEPARSER_H qbs-src-2.5.1/src/app/config/configcommand.h0000644000175100001660000000441414744424375020246 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef CONFIGCOMMAND_H #define CONFIGCOMMAND_H #include #include #include class ConfigCommand { public: enum Command { CfgSet, CfgUnset, CfgList, CfgExport, CfgImport, CfgAddProfile, CfgNone }; ConfigCommand() : command(CfgNone) {} Command command; QStringList varNames; QString varValue; QString fileName; }; #endif // CONFIGCOMMAND_H qbs-src-2.5.1/src/app/qbs-setup-qt/0000755000175100001660000000000014744424375016366 5ustar runnerdockerqbs-src-2.5.1/src/app/qbs-setup-qt/qbs-setup-qt.exe.manifest0000644000175100001660000000072614744424375023250 0ustar runnerdocker qbs-src-2.5.1/src/app/qbs-setup-qt/setupqt.cpp0000644000175100001660000003542114744424375020604 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "setupqt.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { using Internal::none_of; using Internal::contains; using Internal::HostOsInfo; using Internal::Tr; using Internal::rangeTo; static QStringList qmakeExecutableNames() { const QString baseName = HostOsInfo::appendExecutableSuffix(QStringLiteral("qmake")); QStringList lst(baseName); if (HostOsInfo::isLinuxHost()) { // Some distributions ship binaries called qmake-qt5 or qmake-qt4. lst << baseName + QLatin1String("-qt5") << baseName + QLatin1String("-qt4"); } return lst; } static QStringList collectQmakePaths() { const QStringList qmakeExeNames = qmakeExecutableNames(); QStringList qmakePaths; QByteArray environmentPath = qgetenv("PATH"); const QList environmentPaths = environmentPath.split(HostOsInfo::pathListSeparator().toLatin1()); for (const QByteArray &path : environmentPaths) { for (const QString &qmakeExecutableName : qmakeExeNames) { QFileInfo pathFileInfo(QDir(QLatin1String(path)), qmakeExecutableName); if (pathFileInfo.exists()) { QString qmakePath = pathFileInfo.absoluteFilePath(); if (!qmakePaths.contains(qmakePath)) qmakePaths.push_back(qmakePath); } } } return qmakePaths; } bool SetupQt::isQMakePathValid(const QString &qmakePath) { QFileInfo qmakeFileInfo(qmakePath); return qmakeFileInfo.exists() && qmakeFileInfo.isFile() && qmakeFileInfo.isExecutable(); } std::vector SetupQt::fetchEnvironments() { std::vector qtEnvironments; const auto qmakePaths = collectQmakePaths(); for (const QString &qmakePath : qmakePaths) { const QtEnvironment env = fetchEnvironment(qmakePath); if (none_of(qtEnvironments, [&env](const QtEnvironment &otherEnv) { return env.qmakeFilePath == otherEnv.qmakeFilePath; })) { qtEnvironments.push_back(env); } } return qtEnvironments; } // These functions work only for Qt from installer. static QStringList qbsToolchainFromDirName(const QString &dir) { if (dir.startsWith(QLatin1String("msvc"))) return {QStringLiteral("msvc")}; if (dir.startsWith(QLatin1String("mingw"))) return {QStringLiteral("mingw"), QStringLiteral("gcc")}; if (dir.startsWith(QLatin1String("clang"))) return {QStringLiteral("clang"), QStringLiteral("llvm"), QStringLiteral("gcc")}; if (dir.startsWith(QLatin1String("gcc"))) return {QStringLiteral("gcc")}; return {}; } static Version vcVersionFromDirName(const QString &dir) { static const std::regex regexp("^msvc(\\d\\d\\d\\d).*$"); std::smatch match; const std::string dirString = dir.toStdString(); if (!std::regex_match(dirString, match, regexp)) return Version{}; // see https://dev.to/yumetodo/list-of-mscver-and-mscfullver-8nd QMap mapping{ std::make_pair("2005", "8"), std::make_pair("2008", "9"), std::make_pair("2010", "10"), std::make_pair("2012", "11"), std::make_pair("2013", "12"), std::make_pair("2015", "14"), std::make_pair("2017", "14.10"), std::make_pair("2019", "14.20"), std::make_pair("2022", "14.30")}; return Version::fromString(QString::fromStdString(mapping.value(match[1].str()))); } static Version vcVersionFromToolchainInstallPath(const QString &toolchainPath) { // e.g. 14.40.33807\bin\Hostx64\x64 QDir dir(toolchainPath); dir.cdUp(); dir.cdUp(); dir.cdUp(); return Version::fromString(dir.dirName()); } static QString archFromDirName(const QString &dir) { static const std::regex regexp("^[^_]+_(.*).*$"); std::smatch match; const std::string dirString = dir.toStdString(); if (!std::regex_match(dirString, match, regexp)) return {}; QString arch = QString::fromStdString(match[1]); if (arch == QLatin1String("32")) return QStringLiteral("x86"); if (arch == QLatin1String("64")) return QStringLiteral("x86_64"); if (arch.contains(QLatin1String("arm64"))) return QStringLiteral("arm64"); return arch; } static QString platformFromDirName(const QString &dir) { if (dir.startsWith(QLatin1String("android"))) return QStringLiteral("android"); if (dir == QLatin1String("Boot2Qt")) return QStringLiteral("linux"); return HostOsInfo::hostOSIdentifier(); } QtEnvironment SetupQt::fetchEnvironment(const QString &qmakePath) { QtEnvironment env; env.qmakeFilePath = qmakePath; QDir qtDir = QFileInfo(qmakePath).dir(); if (qtDir.dirName() == QLatin1String("bin")) { qtDir.cdUp(); env.qbsToolchain = qbsToolchainFromDirName(qtDir.dirName()); env.vcVersion = vcVersionFromDirName(qtDir.dirName()); env.architecture = archFromDirName(qtDir.dirName()); if (env.vcVersion.isValid() && env.architecture.isEmpty()) env.architecture = QStringLiteral("x86"); env.targetPlatform = platformFromDirName(qtDir.dirName()); qtDir.cdUp(); env.qtVersion = Version::fromString(qtDir.dirName()); } return env; } static bool isToolchainProfile(const Profile &profile) { const auto actual = rangeTo>( profile.allKeys(Profile::KeySelectionRecursive)); Internal::Set expected{ QStringLiteral("qbs.toolchainType") }; if (HostOsInfo::isMacosHost()) expected.insert(QStringLiteral("qbs.targetPlatform")); // match only Xcode profiles return Internal::Set(actual).unite(expected) == actual; } static bool isQtProfile(const Profile &profile) { if (!profile.value(QStringLiteral("moduleProviders.Qt.qmakeFilePaths")).toStringList() .empty()) { return true; } // For Profiles created with setup-qt < 5.13. const QStringList searchPaths = profile.value(QStringLiteral("preferences.qbsSearchPaths")).toStringList(); return Internal::any_of(searchPaths, [] (const QString &path) { return QFileInfo(path + QStringLiteral("/modules/Qt")).isDir(); }); } template bool areProfilePropertiesIncompatible(const T &set1, const T &set2) { // Two objects are only considered incompatible if they are both non empty and compare inequal // This logic is used for comparing target OS, toolchain lists, and architectures return set1.size() > 0 && set2.size() > 0 && set1 != set2; } enum Match { MatchFull, MatchPartial, MatchNone }; static Match compatibility(const QtEnvironment &env, const Profile &toolchainProfile) { Match match = MatchFull; const auto toolchainType = toolchainProfile.value(QStringLiteral("qbs.toolchainType")).toString(); const auto toolchain = !toolchainType.isEmpty() ? canonicalToolchain(toolchainType) : toolchainProfile.value(QStringLiteral("qbs.toolchain")).toStringList(); const auto toolchainNames = rangeTo>(toolchain); const auto qtToolchainNames = rangeTo>(env.qbsToolchain); if (areProfilePropertiesIncompatible(toolchainNames, qtToolchainNames)) { auto intersection = toolchainNames; intersection.intersect(qtToolchainNames); if (!intersection.empty()) match = MatchPartial; else return MatchNone; } const auto targetPlatform = toolchainProfile.value( QStringLiteral("qbs.targetPlatform")).toString(); if (!targetPlatform.isEmpty() && targetPlatform != env.targetPlatform) return MatchNone; const QString toolchainArchitecture = toolchainProfile.value(QStringLiteral("qbs.architecture")) .toString(); if (areProfilePropertiesIncompatible(canonicalArchitecture(env.architecture), canonicalArchitecture(toolchainArchitecture))) return MatchNone; if (toolchainType == QStringLiteral("msvc") && env.vcVersion.isValid()) { // We want to know for sure that MSVC compiler versions match, // because it's especially important for this toolchain const Version compilerVersion = vcVersionFromToolchainInstallPath( toolchainProfile.value(QStringLiteral("cpp.toolchainInstallPath")).toString()); static const Version vs2017Version{14, 10}; if (env.vcVersion >= vs2017Version) { if (env.vcVersion.majorVersion() != compilerVersion.majorVersion() || compilerVersion < vs2017Version) { return MatchNone; } } else if ( env.vcVersion.majorVersion() != compilerVersion.majorVersion() || env.vcVersion.minorVersion() != compilerVersion.minorVersion()) { return MatchNone; } } return match; } QString profileNameWithoutHostArch(const QString &profileName) { QString result; int i = profileName.indexOf(QLatin1Char('-')); if (i == -1) return result; ++i; int j = profileName.indexOf(QLatin1Char('_'), i); if (j == -1) return result; result = profileName.mid(0, i) + profileName.mid(j + 1); return result; } // "Compressing" MSVC profiles means that if MSVC2017-x64 and MSVC2017-x86_x64 fully match, // then we drop the crosscompiling toolchain MSVC2017-x86_x64. static void compressMsvcProfiles(QStringList &profiles) { Internal::removeIf(profiles, [&profiles] (const QString &profileName) { int idx = profileName.indexOf(QLatin1Char('_')); if (idx == -1) return false; return contains(profiles, profileNameWithoutHostArch(profileName)); }); } void SetupQt::saveToQbsSettings(const QString &qtVersionName, const QtEnvironment &qtEnvironment, Settings *settings) { const QString cleanQtVersionName = Profile::cleanName(qtVersionName); QString msg = QCoreApplication::translate("SetupQt", "Creating profile '%1'.") .arg(cleanQtVersionName); std::printf("%s\n", qPrintable(msg)); Profile profile(cleanQtVersionName, settings); profile.removeProfile(); profile.setValue(QStringLiteral("moduleProviders.Qt.qmakeFilePaths"), QStringList(qtEnvironment.qmakeFilePath)); if (!profile.baseProfile().isEmpty()) return; if (isToolchainProfile(profile)) return; QStringList fullMatches; QStringList partialMatches; const auto profileNames = settings->profiles(); for (const QString &profileName : profileNames) { const Profile otherProfile(profileName, settings); if (profileName == profile.name() || !isToolchainProfile(otherProfile) || isQtProfile(otherProfile)) continue; switch (compatibility(qtEnvironment, otherProfile)) { case MatchFull: fullMatches << profileName; break; case MatchPartial: partialMatches << profileName; break; default: break; } } if (fullMatches.size() > 1) compressMsvcProfiles(fullMatches); QString bestMatch; if (fullMatches.size() == 1) bestMatch = fullMatches.front(); else if (fullMatches.empty() && partialMatches.size() == 1) bestMatch = partialMatches.front(); if (bestMatch.isEmpty()) { QString message = Tr::tr("You may want to set up toolchain information " "for the generated Qt profile. "); if (!fullMatches.empty() || !partialMatches.empty()) { message += Tr::tr("Consider setting one of these profiles as this profile's base " "profile: %1.").arg((fullMatches + partialMatches) .join(QLatin1String(", "))); } qbsInfo() << message; } else { profile.setBaseProfile(bestMatch); qbsInfo() << Tr::tr("Setting profile '%1' as the base profile for this profile.") .arg(bestMatch); } } bool SetupQt::checkIfMoreThanOneQtWithTheSameVersion(const Version &qtVersion, const std::vector &qtEnvironments) { bool foundOneVersion = false; for (const QtEnvironment &qtEnvironment : qtEnvironments) { if (qtEnvironment.qtVersion == qtVersion) { if (foundOneVersion) return true; foundOneVersion = true; } } return false; } } // namespace qbs qbs-src-2.5.1/src/app/qbs-setup-qt/qbs-setup-qt.rc0000644000175100001660000000022014744424375021253 0ustar runnerdocker#define RT_MANIFEST 24 #define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "qbs-setup-qt.exe.manifest" qbs-src-2.5.1/src/app/qbs-setup-qt/qbs-setup-qt.qbs0000644000175100001660000000077314744424375021451 0ustar runnerdockerQbsApp { name: "qbs-setup-qt" files: [ "commandlineparser.cpp", "commandlineparser.h", "main.cpp", "setupqt.cpp", "setupqt.h" ] Group { name: "MinGW specific files" condition: qbs.toolchain.contains("mingw") files: "qbs-setup-qt.rc" Group { name: "qbs-setup-qt manifest" files: "qbs-setup-qt.exe.manifest" fileTags: [] // the manifest is referenced by the rc file } } } qbs-src-2.5.1/src/app/qbs-setup-qt/commandlineparser.h0000644000175100001660000000573114744424375022250 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_SETUPTOOLCHAINS_COMMANDLINEPARSER_H #define QBS_SETUPTOOLCHAINS_COMMANDLINEPARSER_H #include #include class CommandLineParser { public: void parse(const QStringList &commandLine); bool helpRequested() const { return m_helpRequested; } bool autoDetectionMode() const { return m_autoDetectionMode; } QString qmakePath() const { return m_qmakePath; } QString profileName() const { return m_profileName; } QString settingsDir() const { return m_settingsDir; } qbs::Settings::Scope settingsScope() const { return m_settingsScope; } QString usageString() const; private: [[noreturn]] void throwError(const QString &message); void assignOptionArgument(const QString &option, QString &argument); [[noreturn]] void complainAboutExtraArguments(); bool m_helpRequested = false; bool m_autoDetectionMode = false; qbs::Settings::Scope m_settingsScope = qbs::Settings::UserScope; QString m_qmakePath; QString m_profileName; QString m_settingsDir; QStringList m_commandLine; QString m_command; }; #endif // Include guard qbs-src-2.5.1/src/app/qbs-setup-qt/CMakeLists.txt0000644000175100001660000000031314744424375021123 0ustar runnerdockerset(SOURCES commandlineparser.cpp commandlineparser.h main.cpp setupqt.cpp setupqt.h ) add_qbs_app(qbs-setup-qt DEPENDS qbscore qbsconsolelogger SOURCES ${SOURCES} ) qbs-src-2.5.1/src/app/qbs-setup-qt/main.cpp0000644000175100001660000001074314744424375020023 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "setupqt.h" #include "commandlineparser.h" #include #include #include #include #include #include #include #include using namespace qbs; using Internal::Tr; int main(int argc, char *argv[]) { QCoreApplication application(argc, argv); try { CommandLineParser clParser; clParser.parse(application.arguments()); if (clParser.helpRequested()) { std::cout << qPrintable(clParser.usageString()) << std::endl; return EXIT_SUCCESS; } Settings settings(clParser.settingsDir()); settings.setScopeForWriting(clParser.settingsScope()); if (clParser.autoDetectionMode()) { // search all Qt's in path and dump their settings const std::vector qtEnvironments = SetupQt::fetchEnvironments(); if (qtEnvironments.empty()) { std::cout << qPrintable(Tr::tr("No Qt installations detected. " "No profiles created.")) << std::endl; } for (const QtEnvironment &qtEnvironment : qtEnvironments) { QString profileName = QLatin1String("qt-") + qtEnvironment.qtVersion.toString(); if (SetupQt::checkIfMoreThanOneQtWithTheSameVersion(qtEnvironment.qtVersion, qtEnvironments)) { QStringList prefixPathParts = QFileInfo(qtEnvironment.qmakeFilePath).path() .split(QLatin1Char('/'), Qt::SkipEmptyParts); if (!prefixPathParts.empty()) profileName += QLatin1String("-") + prefixPathParts.last(); } SetupQt::saveToQbsSettings(profileName, qtEnvironment, &settings); } return EXIT_SUCCESS; } if (!SetupQt::isQMakePathValid(clParser.qmakePath())) { std::cerr << qPrintable(Tr::tr("'%1' does not seem to be a qmake executable.") .arg(clParser.qmakePath())) << std::endl; return EXIT_FAILURE; } const QtEnvironment qtEnvironment = SetupQt::fetchEnvironment(clParser.qmakePath()); QString profileName = clParser.profileName(); profileName.replace(QLatin1Char('.'), QLatin1Char('-')); SetupQt::saveToQbsSettings(profileName, qtEnvironment, &settings); return EXIT_SUCCESS; } catch (const ErrorInfo &e) { std::cerr << qPrintable(e.toString()) << std::endl; return EXIT_FAILURE; } } qbs-src-2.5.1/src/app/qbs-setup-qt/commandlineparser.cpp0000644000175100001660000001241614744424375022601 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "commandlineparser.h" #include #include #include using qbs::Internal::Tr; static QString helpOptionShort() { return QStringLiteral("-h"); } static QString helpOptionLong() { return QStringLiteral("--help"); } static QString detectOption() { return QStringLiteral("--detect"); } static QString settingsDirOption() { return QStringLiteral("--settings-dir"); } static QString systemOption() { return QStringLiteral("--system"); } void CommandLineParser::parse(const QStringList &commandLine) { m_commandLine = commandLine; Q_ASSERT(!m_commandLine.empty()); m_command = QFileInfo(m_commandLine.takeFirst()).fileName(); m_helpRequested = false; m_autoDetectionMode = false; m_qmakePath.clear(); m_profileName.clear(); m_settingsDir.clear(); if (m_commandLine.empty()) throwError(Tr::tr("No command-line arguments provided.")); while (!m_commandLine.empty()) { const QString arg = m_commandLine.front(); if (!arg.startsWith(QLatin1Char('-'))) break; m_commandLine.removeFirst(); if (arg == helpOptionShort() || arg == helpOptionLong()) m_helpRequested = true; else if (arg == detectOption()) m_autoDetectionMode = true; else if (arg == systemOption()) m_settingsScope = qbs::Settings::SystemScope; else if (arg == settingsDirOption()) assignOptionArgument(settingsDirOption(), m_settingsDir); } if (m_helpRequested || m_autoDetectionMode) { if (!m_commandLine.empty()) complainAboutExtraArguments(); return; } switch (m_commandLine.size()) { case 0: case 1: throwError(Tr::tr("Not enough command-line arguments provided.")); case 2: m_qmakePath = m_commandLine.at(0); m_profileName = m_commandLine.at(1); break; default: complainAboutExtraArguments(); } } void CommandLineParser::throwError(const QString &message) { qbs::ErrorInfo error(Tr::tr("Syntax error: %1").arg(message)); error.append(usageString()); throw error; } QString CommandLineParser::usageString() const { QString s = Tr::tr("This tool creates qbs profiles from Qt versions.\n"); s += Tr::tr("Usage:\n"); s += Tr::tr(" %1 [%2 ] [%4] %3\n") .arg(m_command, settingsDirOption(), detectOption(), systemOption()); s += Tr::tr(" %1 [%2 ] [%4] \n") .arg(m_command, settingsDirOption(), systemOption()); s += Tr::tr(" %1 %2|%3\n").arg(m_command, helpOptionShort(), helpOptionLong()); s += Tr::tr("The first form tries to auto-detect all known Qt versions, looking them up " "via the PATH environment variable.\n"); s += Tr::tr("The second form creates one profile for one Qt version."); return s; } void CommandLineParser::assignOptionArgument(const QString &option, QString &argument) { if (m_commandLine.empty()) throwError(Tr::tr("Option '%1' needs an argument.").arg(option)); argument = m_commandLine.takeFirst(); if (argument.isEmpty()) throwError(Tr::tr("Argument for option '%1' must not be empty.").arg(option)); } void CommandLineParser::complainAboutExtraArguments() { throwError(Tr::tr("Extraneous command-line arguments '%1'.") .arg(m_commandLine.join(QLatin1Char(' ')))); } qbs-src-2.5.1/src/app/qbs-setup-qt/setupqt.h0000644000175100001660000000557314744424375020256 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_SETUPQT_H #define QBS_SETUPQT_H #include #include #include #include #include namespace qbs { class Settings; class QtEnvironment { public: QString qmakeFilePath; QStringList qbsToolchain; QString architecture; QString targetPlatform; Version qtVersion; Version vcVersion; }; class SetupQt { Q_DECLARE_TR_FUNCTIONS(SetupQt) public: static bool isQMakePathValid(const QString &qmakePath); static std::vector fetchEnvironments(); static QtEnvironment fetchEnvironment(const QString &qmakePath); static bool checkIfMoreThanOneQtWithTheSameVersion(const Version &qtVersion, const std::vector &qtEnvironments); static void saveToQbsSettings(const QString &qtVersionName, const QtEnvironment &qtEnvironment, Settings *settings); }; } // namespace qbs #endif // QBS_SETUPQT_H qbs-src-2.5.1/src/app/apps.qbs0000644000175100001660000000054214744424375015474 0ustar runnerdockerProject { references: [ "config/config.qbs", "config-ui/config-ui.qbs", "qbs/qbs.qbs", "qbs-create-project/qbs-create-project.qbs", "qbs-setup-android/qbs-setup-android.qbs", "qbs-setup-qt/qbs-setup-qt.qbs", "qbs-setup-toolchains/qbs-setup-toolchains.qbs", "shared/shared.qbs", ] } qbs-src-2.5.1/src/app/CMakeLists.txt0000644000175100001660000000036314744424375016563 0ustar runnerdockeradd_subdirectory(config) add_subdirectory(config-ui) add_subdirectory(qbs) add_subdirectory(qbs-create-project) add_subdirectory(qbs-setup-android) add_subdirectory(qbs-setup-qt) add_subdirectory(qbs-setup-toolchains) add_subdirectory(shared) qbs-src-2.5.1/src/app/qbs-setup-android/0000755000175100001660000000000014744424375017362 5ustar runnerdockerqbs-src-2.5.1/src/app/qbs-setup-android/qbs-setup-android.qbs0000644000175100001660000000103414744424375023430 0ustar runnerdockerQbsApp { name: "qbs-setup-android" files: [ "android-setup.cpp", "android-setup.h", "commandlineparser.cpp", "commandlineparser.h", "main.cpp", ] Group { name: "MinGW specific files" condition: qbs.toolchain.contains("mingw") files: "qbs-setup-android.rc" Group { name: "qbs-setup-android manifest" files: "qbs-setup-android.exe.manifest" fileTags: [] // the manifest is referenced by the rc file } } } qbs-src-2.5.1/src/app/qbs-setup-android/qbs-setup-android.rc0000644000175100001660000000022514744424375023250 0ustar runnerdocker#define RT_MANIFEST 24 #define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "qbs-setup-android.exe.manifest" qbs-src-2.5.1/src/app/qbs-setup-android/commandlineparser.h0000644000175100001660000000602014744424375023234 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_SETUP_ANDROID_COMMANDLINEPARSER_H #define QBS_SETUP_ANDROID_COMMANDLINEPARSER_H #include #include class CommandLineParser { public: CommandLineParser(); void parse(const QStringList &commandLine); bool helpRequested() const { return m_helpRequested; } QString sdkDir() const { return m_sdkDir; } QString ndkDir() const { return m_ndkDir; } QString qtSdkDir() const { return m_qtSdkDir; } QString profileName() const { return m_profileName; } QString settingsDir() const { return m_settingsDir; } qbs::Settings::Scope settingsScope() const { return m_settingsScope; } QString usageString() const; private: [[noreturn]] void throwError(const QString &message); void assignOptionArgument(const QString &option, QString &argument); [[noreturn]] void complainAboutExtraArguments(); bool m_helpRequested = false; qbs::Settings::Scope m_settingsScope = qbs::Settings::UserScope; QString m_sdkDir; QString m_ndkDir; QString m_qtSdkDir; QString m_profileName; QString m_settingsDir; QStringList m_commandLine; QString m_command; }; #endif // Include guard. qbs-src-2.5.1/src/app/qbs-setup-android/CMakeLists.txt0000644000175100001660000000033414744424375022122 0ustar runnerdockerset(SOURCES android-setup.cpp android-setup.h commandlineparser.cpp commandlineparser.h main.cpp ) add_qbs_app(qbs-setup-android DEPENDS qbscore qbsconsolelogger SOURCES ${SOURCES} ) qbs-src-2.5.1/src/app/qbs-setup-android/main.cpp0000644000175100001660000000545214744424375021020 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "commandlineparser.h" #include "android-setup.h" #include #include #include #include #include #include int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); CommandLineParser clParser; try { clParser.parse(app.arguments()); if (clParser.helpRequested()) { std::cout << qPrintable(clParser.usageString()) << std::endl; return EXIT_SUCCESS; } qbs::Settings settings(clParser.settingsDir()); settings.setScopeForWriting(clParser.settingsScope()); setupAndroid(&settings, clParser.profileName(), clParser.sdkDir(), clParser.ndkDir(), clParser.qtSdkDir()); } catch (const qbs::ErrorInfo &e) { std::cerr << qPrintable(qbs::Internal::Tr::tr("Error: %1").arg(e.toString())) << std::endl; return EXIT_FAILURE; } } qbs-src-2.5.1/src/app/qbs-setup-android/android-setup.cpp0000644000175100001660000002313214744424375022645 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "android-setup.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace qbs; using qbs::Internal::Tr; static QString qls(const char *s) { return QLatin1String(s); } static QStringList expectedArchs() { return {QStringLiteral("arm64"), QStringLiteral("armv7a"), QStringLiteral("x86"), QStringLiteral("x86_64")}; } void setupSdk(qbs::Settings *settings, const QString &profileName, const QString &sdkDirPath) { if (!QDir(sdkDirPath).exists()) { throw ErrorInfo(Tr::tr("SDK directory '%1' does not exist.") .arg(QDir::toNativeSeparators(sdkDirPath))); } Profile profile(profileName, settings); profile.removeProfile(); if (!sdkDirPath.isEmpty()) profile.setValue(qls("Android.sdk.sdkDir"), QDir::cleanPath(sdkDirPath)); profile.setValue(qls("qbs.targetPlatform"), qls("android")); } static QString mapArch(const QString &androidName) { if (androidName == qls("arm64-v8a")) return qls("arm64"); if (androidName == qls("armeabi")) return qls("armv5te"); if (androidName == qls("armeabi-v7a")) return qls("armv7a"); return androidName; } struct QtAndroidInfo { bool isValid() const { return !archs.isEmpty(); } QString qmakePath; QStringList archs; QString platform; }; static QtAndroidInfo getInfoForQtDir(const QString &qtDir) { QtAndroidInfo info; info.qmakePath = qbs::Internal::HostOsInfo::appendExecutableSuffix(qtDir + qls("/bin/qmake")); if (!QFile::exists(info.qmakePath)) return info; QFile qdevicepri(qtDir + qls("/mkspecs/qdevice.pri")); if (!qdevicepri.open(QIODevice::ReadOnly)) return info; while (!qdevicepri.atEnd()) { // For Qt < 5.14 use DEFAULT_ANDROID_TARGET_ARCH (which is the abi) to compute // the architecture // DEFAULT_ANDROID_ABIS doesn't exit // For Qt >= 5.14: // DEFAULT_ANDROID_TARGET_ARCH doesn't exist, use DEFAULT_ANDROID_ABIS to compute // the architectures const QByteArray line = qdevicepri.readLine().simplified(); const bool isArchLine = line.startsWith("DEFAULT_ANDROID_TARGET_ARCH"); const bool isAbisLine = line.startsWith("DEFAULT_ANDROID_ABIS"); const bool isPlatformLine = line.startsWith("DEFAULT_ANDROID_PLATFORM"); if (!isArchLine && !isPlatformLine && !isAbisLine) continue; const QList elems = line.split('='); if (elems.size() != 2) continue; const QString rhs = QString::fromLatin1(elems.at(1).trimmed()); if (isArchLine) { info.archs << mapArch(rhs); } else if (isAbisLine) { const auto abis = rhs.split(QLatin1Char(' ')); for (const QString &abi: abis) info.archs << mapArch(abi); } else { info.platform = rhs; } } return info; } using QtInfoPerArch = QHash; static QtInfoPerArch getQtAndroidInfo(const QString &qtSdkDir) { QtInfoPerArch archs; if (qtSdkDir.isEmpty()) return archs; QStringList qtDirs(qtSdkDir); const QStringList nameFilters{QStringLiteral("android_*"), QStringLiteral("android")}; QDirIterator dit(qtSdkDir, nameFilters, QDir::Dirs); while (dit.hasNext()) qtDirs << dit.next(); for (const auto &qtDir : std::as_const(qtDirs)) { const QtAndroidInfo info = getInfoForQtDir(qtDir); if (info.isValid()) { for (const QString &arch: info.archs) archs.insert(arch, info); } } return archs; } static QString maximumPlatform(const QString &platform1, const QString &platform2) { if (platform1.isEmpty()) return platform2; if (platform2.isEmpty()) return platform1; static const QString prefix = qls("android-"); const QString numberString1 = platform1.mid(prefix.size()); const QString numberString2 = platform2.mid(prefix.size()); bool ok; const int value1 = numberString1.toInt(&ok); if (!ok) { qWarning("Ignoring malformed Android platform string '%s'.", qPrintable(platform1)); return platform2; } const int value2 = numberString2.toInt(&ok); if (!ok) { qWarning("Ignoring malformed Android platform string '%s'.", qPrintable(platform2)); return platform1; } return prefix + QString::number(std::max(value1, value2)); } static QString getToolchainType(const QString &ndkDirPath) { QFile sourceProperties(ndkDirPath + qls("/source.properties")); if (!sourceProperties.open(QIODevice::ReadOnly)) return QStringLiteral("gcc"); // <= r10 while (!sourceProperties.atEnd()) { const QByteArray curLine = sourceProperties.readLine().simplified(); static const QByteArray prefix = "Pkg.Revision = "; if (!curLine.startsWith(prefix)) continue; qbs::Version ndkVersion = qbs::Version::fromString( QString::fromLatin1(curLine.mid(prefix.size()))); if (!ndkVersion.isValid()) { qWarning("Unexpected format of NDK revision string in '%s'", qPrintable(sourceProperties.fileName())); return QStringLiteral("clang"); } return qls(ndkVersion.majorVersion() >= 18 ? "clang" : "gcc"); } qWarning("No revision entry found in '%s'", qPrintable(sourceProperties.fileName())); return QStringLiteral("clang"); } static void setupNdk(qbs::Settings *settings, const QString &profileName, const QString &ndkDirPath, const QString &qtSdkDirPath) { if (!QDir(ndkDirPath).exists()) { throw ErrorInfo(Tr::tr("NDK directory '%1' does not exist.") .arg(QDir::toNativeSeparators(ndkDirPath))); } Profile mainProfile(profileName, settings); if (!ndkDirPath.isEmpty()) { mainProfile.setValue(qls("Android.ndk.ndkDir"), QDir::cleanPath(ndkDirPath)); mainProfile.setValue(qls("Android.sdk.ndkDir"), QDir::cleanPath(ndkDirPath)); } mainProfile.setValue(qls("qbs.toolchainType"), getToolchainType(ndkDirPath)); const QStringList archs = expectedArchs(); const QtInfoPerArch infoPerArch = getQtAndroidInfo(qtSdkDirPath); const QStringList archsForProfile = infoPerArch.empty() ? archs : QStringList(infoPerArch.keys()); if (archsForProfile.size() == 1) mainProfile.setValue(qls("qbs.architecture"), archsForProfile.front()); else mainProfile.setValue(qls("qbs.architectures"), archsForProfile); QStringList qmakeFilePaths; QString platform; for (const QString &arch : archs) { const QtAndroidInfo qtAndroidInfo = infoPerArch.value(arch); if (!qtAndroidInfo.isValid()) continue; qmakeFilePaths << qtAndroidInfo.qmakePath; platform = maximumPlatform(platform, qtAndroidInfo.platform); } if (!qmakeFilePaths.empty()) { qmakeFilePaths.removeDuplicates(); mainProfile.setValue(qls("moduleProviders.Qt.qmakeFilePaths"), qmakeFilePaths); } if (!platform.isEmpty()) mainProfile.setValue(qls("Android.ndk.platform"), platform); } void setupAndroid(Settings *settings, const QString &profileName, const QString &sdkDirPath, const QString &ndkDirPath, const QString &qtSdkDirPath) { setupSdk(settings, profileName, sdkDirPath); setupNdk(settings, profileName, ndkDirPath, qtSdkDirPath); } qbs-src-2.5.1/src/app/qbs-setup-android/qbs-setup-android.exe.manifest0000644000175100001660000000073314744424375025236 0ustar runnerdocker qbs-src-2.5.1/src/app/qbs-setup-android/commandlineparser.cpp0000644000175100001660000001336714744424375023603 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "commandlineparser.h" #include #include #include CommandLineParser::CommandLineParser() = default; using qbs::Internal::Tr; static QString helpOptionShort() { return QStringLiteral("-h"); } static QString helpOptionLong() { return QStringLiteral("--help"); } static QString settingsDirOption() { return QStringLiteral("--settings-dir"); } static QString sdkDirOption() { return QStringLiteral("--sdk-dir"); } static QString ndkDirOption() { return QStringLiteral("--ndk-dir"); } static QString qtSdkDirOption() { return QStringLiteral("--qt-dir"); } static QString systemOption() { return QStringLiteral("--system"); } void CommandLineParser::parse(const QStringList &commandLine) { m_commandLine = commandLine; Q_ASSERT(!m_commandLine.empty()); m_command = QFileInfo(m_commandLine.takeFirst()).fileName(); m_helpRequested = false; m_sdkDir.clear(); m_ndkDir.clear(); m_profileName.clear(); m_settingsDir.clear(); if (m_commandLine.empty()) throwError(Tr::tr("No command-line arguments provided.")); while (!m_commandLine.empty()) { const QString arg = m_commandLine.front(); if (!arg.startsWith(QLatin1Char('-'))) break; m_commandLine.removeFirst(); if (arg == helpOptionShort() || arg == helpOptionLong()) m_helpRequested = true; else if (arg == settingsDirOption()) assignOptionArgument(settingsDirOption(), m_settingsDir); else if (arg == systemOption()) m_settingsScope = qbs::Settings::SystemScope; else if (arg == sdkDirOption()) assignOptionArgument(sdkDirOption(), m_sdkDir); else if (arg == ndkDirOption()) assignOptionArgument(ndkDirOption(), m_ndkDir); else if (arg == qtSdkDirOption()) assignOptionArgument(arg, m_qtSdkDir); else throwError(Tr::tr("Unknown option '%1'.").arg(arg)); } if (m_helpRequested) { if (!m_commandLine.empty()) complainAboutExtraArguments(); return; } switch (m_commandLine.size()) { case 0: throwError(Tr::tr("No profile name supplied.")); case 1: m_profileName = m_commandLine.takeFirst(); m_profileName.replace(QLatin1Char('.'), QLatin1Char('-')); break; default: complainAboutExtraArguments(); } } void CommandLineParser::throwError(const QString &message) { qbs::ErrorInfo error(Tr::tr("Syntax error: %1").arg(message)); error.append(usageString()); throw error; } QString CommandLineParser::usageString() const { QString s = Tr::tr("This tool creates qbs profiles from Android SDK and NDK installations.\n"); s += Tr::tr("Usage:\n"); s += Tr::tr(" %1 [%2 ] [%6] [%3 ] [%4 ] [%5 ] " "\n") .arg(m_command, settingsDirOption(), ndkDirOption(), sdkDirOption(), qtSdkDirOption(), systemOption()); s += Tr::tr(" %1 %2|%3\n").arg(m_command, helpOptionShort(), helpOptionLong()); s += Tr::tr("If an NDK path is given, the profile will be suitable for use with Android " "projects that contain native C/C++ code.\n"); s += Tr::tr("If a Qt path is also given, the profile will be suitable for developing " "Qt applications for Android.\n"); return s; } void CommandLineParser::assignOptionArgument(const QString &option, QString &argument) { if (m_commandLine.empty()) throwError(Tr::tr("Option '%1' needs an argument.").arg(option)); argument = m_commandLine.takeFirst(); if (argument.isEmpty()) throwError(Tr::tr("Argument for option '%1' must not be empty.").arg(option)); } void CommandLineParser::complainAboutExtraArguments() { throwError(Tr::tr("Extraneous command-line arguments '%1'.") .arg(m_commandLine.join(QLatin1Char(' ')))); } qbs-src-2.5.1/src/app/qbs-setup-android/android-setup.h0000644000175100001660000000435014744424375022313 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_SETUP_ANDROID_SDKSETUP_H #define QBS_SETUP_ANDROID_SDKSETUP_H #include namespace qbs { class Settings; } QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE void setupAndroid(qbs::Settings *settings, const QString &profileName, const QString &sdkDirPath, const QString &ndkDirPath, const QString &qtSdkDirPath); #endif // Include guard. qbs-src-2.5.1/src/app/shared/0000755000175100001660000000000014744424375015267 5ustar runnerdockerqbs-src-2.5.1/src/app/shared/logging/0000755000175100001660000000000014744424375016715 5ustar runnerdockerqbs-src-2.5.1/src/app/shared/logging/coloredoutput.cpp0000644000175100001660000000741014744424375022333 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "coloredoutput.h" #include #ifdef Q_OS_WIN32 # include #endif #include #ifdef Q_OS_UNIX #include #endif void printfColored(TextColor color, const char *str, va_list vl) { fprintfColored(color, stdout, str, vl); } void printfColored(TextColor color, const char *str, ...) { va_list vl; va_start(vl, str); printfColored(color, str, vl); va_end(vl); } void fprintfColored(TextColor color, std::FILE *file, const char *str, va_list vl) { #if defined(Q_OS_UNIX) if (color != TextColorDefault && isatty(fileno(file))) { unsigned char bright = (color & TextColorBright) >> 3; std::fprintf(file, "\033[%d;%dm", bright, 30 + (color & ~TextColorBright)); std::vfprintf(file, str, vl); std::fprintf(stdout, "\033[0m"); std::fprintf(stderr, "\033[0m"); } else #elif defined(Q_OS_WIN32) HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO csbiInfo; if (color != TextColorDefault && hStdout != INVALID_HANDLE_VALUE && GetConsoleScreenBufferInfo(hStdout, &csbiInfo)) { WORD bgrColor = ((color & 1) << 2) | (color & 2) | ((color & 4) >> 2); // BGR instead of RGB. if (color & TextColorBright) bgrColor += FOREGROUND_INTENSITY; SetConsoleTextAttribute(hStdout, (csbiInfo.wAttributes & 0xf0) | bgrColor); std::vfprintf(file, str, vl); SetConsoleTextAttribute(hStdout, csbiInfo.wAttributes); } else #endif { std::vfprintf(file, str, vl); } } void fprintfColored(TextColor color, std::FILE *file, const char *str, ...) { va_list vl; va_start(vl, str); fprintfColored(color, file, str, vl); va_end(vl); } bool terminalSupportsColor() { #if defined(Q_OS_UNIX) const QByteArray &term = qgetenv("TERM"); return !term.isEmpty() && term != "dumb"; #else return true; #endif } qbs-src-2.5.1/src/app/shared/logging/consolelogger.h0000644000175100001660000000637314744424375021741 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_LOGSINK_H #define QBS_LOGSINK_H #include "coloredoutput.h" #include namespace qbs { class Settings; } class ConsoleLogSink : public qbs::ILogSink { public: ConsoleLogSink(); void setColoredOutputEnabled(bool enabled) { m_coloredOutputEnabled = enabled; } void setEnabled(bool enabled) { m_enabled = enabled; } private: void doPrintMessage(qbs::LoggerLevel level, const QString &message, const QString &tag) override; void fprintfWrapper(TextColor color, FILE *file, const char *str, ...); private: bool m_coloredOutputEnabled; bool m_enabled; }; class ConsoleLogger : public qbs::Internal::Logger { public: static ConsoleLogger &instance(qbs::Settings *settings = 0); ConsoleLogSink *logSink() { return &m_logSink; } void setSettings(qbs::Settings *settings); private: ConsoleLogger(qbs::Settings *settings); ConsoleLogSink m_logSink; }; inline qbs::Internal::LogWriter qbsError() { return ConsoleLogger::instance().qbsLog(qbs::LoggerError); } inline qbs::Internal::LogWriter qbsWarning() { return ConsoleLogger::instance().qbsWarning(); } inline qbs::Internal::LogWriter qbsInfo() { return ConsoleLogger::instance().qbsInfo(); } inline qbs::Internal::LogWriter qbsDebug() { return ConsoleLogger::instance().qbsDebug(); } inline qbs::Internal::LogWriter qbsTrace() { return ConsoleLogger::instance().qbsTrace(); } #endif // QBS_LOGSINK_H qbs-src-2.5.1/src/app/shared/logging/CMakeLists.txt0000644000175100001660000000030314744424375021451 0ustar runnerdockerset(SOURCES coloredoutput.cpp coloredoutput.h consolelogger.cpp consolelogger.h ) add_qbs_library(qbsconsolelogger STATIC DEPENDS qbscore SOURCES ${SOURCES} ) qbs-src-2.5.1/src/app/shared/logging/coloredoutput.h0000644000175100001660000000616314744424375022004 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_COLOREDOUTPUT_H #define QBS_COLOREDOUTPUT_H #include #include // http://en.wikipedia.org/wiki/ANSI_escape_code#Colors enum TextColor { TextColorDefault = -1, TextColorBlack = 0, TextColorDarkRed = 1, TextColorDarkGreen = 2, TextColorDarkBlue = 4, TextColorDarkCyan = TextColorDarkGreen | TextColorDarkBlue, TextColorDarkMagenta = TextColorDarkRed | TextColorDarkBlue, TextColorDarkYellow = TextColorDarkRed | TextColorDarkGreen, TextColorGray = 7, TextColorBright = 8, TextColorRed = TextColorDarkRed | TextColorBright, TextColorGreen = TextColorDarkGreen | TextColorBright, TextColorBlue = TextColorDarkBlue | TextColorBright, TextColorCyan = TextColorDarkCyan | TextColorBright, TextColorMagenta = TextColorDarkMagenta | TextColorBright, TextColorYellow = TextColorDarkYellow | TextColorBright, TextColorWhite = TextColorGray | TextColorBright }; void printfColored(TextColor color, const char *str, va_list vl); void printfColored(TextColor color, const char *str, ...); void fprintfColored(TextColor color, std::FILE *file, const char *str, va_list vl); void fprintfColored(TextColor color, std::FILE *file, const char *str, ...); bool terminalSupportsColor(); #endif // QBS_COLOREDOUTPUT_H qbs-src-2.5.1/src/app/shared/logging/consolelogger.cpp0000644000175100001660000000773214744424375022274 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "consolelogger.h" #include #include #include static QHash setupColorTable() { QHash colorTable; colorTable[QStringLiteral("compiler")] = TextColorDefault; colorTable[QStringLiteral("linker")] = TextColorDarkGreen; colorTable[QStringLiteral("codegen")] = TextColorDarkYellow; colorTable[QStringLiteral("filegen")] = TextColorDarkYellow; return colorTable; } ConsoleLogSink::ConsoleLogSink() : m_coloredOutputEnabled(true), m_enabled(true) { } void ConsoleLogSink::doPrintMessage(qbs::LoggerLevel level, const QString &message, const QString &tag) { if (!m_enabled) return; std::FILE * const file = level == qbs::LoggerInfo && tag != QStringLiteral("stdErr") ? stdout : stderr; const QString levelTag = logLevelTag(level); TextColor color = TextColorDefault; switch (level) { case qbs::LoggerError: color = TextColorRed; break; case qbs::LoggerWarning: color = TextColorYellow; break; default: break; } fprintfWrapper(color, file, levelTag.toLocal8Bit().constData()); static QHash colorTable = setupColorTable(); fprintfWrapper(colorTable.value(tag, TextColorDefault), file, "%s\n", message.toLocal8Bit().constData()); std::fflush(file); } void ConsoleLogSink::fprintfWrapper(TextColor color, std::FILE *file, const char *str, ...) { va_list vl; va_start(vl, str); if (m_coloredOutputEnabled && terminalSupportsColor()) fprintfColored(color, file, str, vl); else std::vfprintf(file, str, vl); va_end(vl); } ConsoleLogger &ConsoleLogger::instance(qbs::Settings *settings) { static ConsoleLogger logger(settings); return logger; } void ConsoleLogger::setSettings(qbs::Settings *settings) { if (settings) m_logSink.setColoredOutputEnabled(qbs::Preferences(settings).useColoredOutput()); } ConsoleLogger::ConsoleLogger(qbs::Settings *settings) : Logger(&m_logSink) { setSettings(settings); } qbs-src-2.5.1/src/app/shared/logging/logging.qbs0000644000175100001660000000050214744424375021047 0ustar runnerdockerQbsStaticLibrary { Depends { name: "qbscore" } name: "qbsconsolelogger" files: [ "coloredoutput.cpp", "coloredoutput.h", "consolelogger.cpp", "consolelogger.h" ] Export { Depends { name: "cpp" } cpp.includePaths: exportingProduct.sourceDirectory } } qbs-src-2.5.1/src/app/shared/CMakeLists.txt0000644000175100001660000000003214744424375020022 0ustar runnerdockeradd_subdirectory(logging) qbs-src-2.5.1/src/app/shared/shared.qbs0000644000175100001660000000010314744424375017236 0ustar runnerdockerProject { references: [ "logging/logging.qbs", ] } qbs-src-2.5.1/src/app/config-ui/0000755000175100001660000000000014744424375015701 5ustar runnerdockerqbs-src-2.5.1/src/app/config-ui/mainwindow.cpp0000644000175100001660000002163014744424375020563 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include #include #include #include #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #include #else #include #endif #include #include #include #include #include namespace { class TrimValidator : public QValidator { public: explicit TrimValidator(QObject *parent = nullptr) : QValidator(parent) {} // QValidator interface State validate(QString &input, int &pos) const override { Q_UNUSED(pos); if (input.startsWith(QLatin1Char(' ')) || input.endsWith(QLatin1Char(' '))) return State::Intermediate; return State::Acceptable; } void fixup(QString &input) const override { input = input.trimmed(); } }; class SettingsItemDelegate: public QStyledItemDelegate { public: explicit SettingsItemDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {} QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override { const auto editor = QStyledItemDelegate::createEditor(parent, option, index); const auto lineEdit = qobject_cast(editor); if (lineEdit) lineEdit->setValidator(new TrimValidator(lineEdit)); return editor; } }; } // namespace MainWindow::MainWindow(const QString &settingsDir, qbs::Settings::Scope scope, QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); m_model = new qbs::SettingsModel(settingsDir, scope, this); ui->treeView->setModel(m_model); ui->treeView->setItemDelegate(new SettingsItemDelegate(ui->treeView)); ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->treeView, &QTreeView::expanded, this, &MainWindow::adjustColumns); connect(ui->treeView, &QWidget::customContextMenuRequested, this, &MainWindow::provideContextMenu); adjustColumns(); QMenu * const fileMenu = menuBar()->addMenu(tr("&File")); QMenu * const viewMenu = menuBar()->addMenu(tr("&View")); const auto reloadAction = new QAction(tr("&Reload"), this); reloadAction->setShortcut(QKeySequence::Refresh); connect(reloadAction, &QAction::triggered, this, &MainWindow::reloadSettings); const auto saveAction = new QAction(tr("&Save"), this); saveAction->setShortcut(QKeySequence::Save); connect(saveAction, &QAction::triggered, this, &MainWindow::saveSettings); const auto expandAllAction = new QAction(tr("&Expand All"), this); expandAllAction->setShortcut(int(Qt::CTRL) | int(Qt::Key_E)); connect(expandAllAction, &QAction::triggered, this, &MainWindow::expandAll); const auto collapseAllAction = new QAction(tr("C&ollapse All"), this); collapseAllAction->setShortcut(int(Qt::CTRL) | int(Qt::Key_O)); connect(collapseAllAction, &QAction::triggered, this, &MainWindow::collapseAll); const auto exitAction = new QAction(tr("E&xit"), this); exitAction->setShortcut(QKeySequence::Quit); exitAction->setMenuRole(QAction::QuitRole); connect(exitAction, &QAction::triggered, this, &MainWindow::exit); fileMenu->addAction(reloadAction); fileMenu->addAction(saveAction); fileMenu->addSeparator(); fileMenu->addAction(exitAction); viewMenu->addAction(expandAllAction); viewMenu->addAction(collapseAllAction); ui->treeView->installEventFilter(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::adjustColumns() { for (int column = 0; column < m_model->columnCount(); ++column) ui->treeView->resizeColumnToContents(column); } void MainWindow::expandAll() { ui->treeView->expandAll(); adjustColumns(); } void MainWindow::collapseAll() { ui->treeView->collapseAll(); adjustColumns(); } void MainWindow::reloadSettings() { if (m_model->hasUnsavedChanges()) { const QMessageBox::StandardButton answer = QMessageBox::question(this, tr("Unsaved Changes"), tr("You have unsaved changes. Do you want to discard them?")); if (answer != QMessageBox::Yes) return; } m_model->reload(); } void MainWindow::saveSettings() { m_model->save(); } void MainWindow::exit() { if (m_model->hasUnsavedChanges()) { const QMessageBox::StandardButton answer = QMessageBox::question(this, tr("Unsaved Changes"), tr("You have unsaved changes. Do you want to save them now?")); if (answer == QMessageBox::Yes) m_model->save(); } qApp->quit(); } void MainWindow::provideContextMenu(const QPoint &pos) { const QModelIndex index = ui->treeView->indexAt(pos); if (index.isValid() && index.column() != m_model->keyColumn()) return; const QString settingsKey = m_model->data(index).toString(); QMenu contextMenu; QAction addKeyAction(this); QAction removeKeyAction(this); if (index.isValid()) { addKeyAction.setText(tr("Add new key below '%1'").arg(settingsKey)); removeKeyAction.setText(tr("Remove key '%1' and all its sub-keys").arg(settingsKey)); contextMenu.addAction(&addKeyAction); contextMenu.addAction(&removeKeyAction); } else { addKeyAction.setText(tr("Add new top-level key")); contextMenu.addAction(&addKeyAction); } const QAction *action = contextMenu.exec(ui->treeView->mapToGlobal(pos)); if (action == &addKeyAction) m_model->addNewKey(index); else if (action == &removeKeyAction) m_model->removeKey(index); } extern "C" void qt_macos_forceTransformProcessToForegroundApplicationAndActivate(); bool MainWindow::eventFilter(QObject *watched, QEvent *event) { if (ui->treeView->hasFocus() && event->type() == QEvent::KeyPress) { const auto keyEvent = static_cast(event); if (keyEvent->matches(QKeySequence::Delete)) { const QModelIndexList indexes = ui->treeView->selectionModel()->selectedRows(); if (indexes.size() == 1) { const QModelIndex index = indexes.front(); if (index.isValid()) { m_model->removeKey(index); return true; } } } } if (event->type() == QEvent::WindowActivate) { // Effectively delay the foreground process transformation from QApplication construction to // when the UI is shown - this prevents the application icon from popping up in the Dock // when running `qbs help`, and QCoreApplication::arguments() requires the application // object to be constructed, so it is not easily worked around #if defined(Q_OS_MACOS) qt_macos_forceTransformProcessToForegroundApplicationAndActivate(); #endif } return QMainWindow::eventFilter(watched, event); } qbs-src-2.5.1/src/app/config-ui/commandlineparser.h0000644000175100001660000000527514744424375021566 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_CONFIGUI_COMMANDLINEPARSER_H #define QBS_CONFIGUI_COMMANDLINEPARSER_H #include #include class CommandLineParser { public: void parse(const QStringList &commandLine); bool helpRequested() const { return m_helpRequested; } QString settingsDir() const { return m_settingsDir; } qbs::Settings::Scope settingsScope() const { return m_settingsScope; } QString usageString() const; private: [[noreturn]] void throwError(const QString &message); void assignOptionArgument(const QString &option, QString &argument); [[noreturn]] void complainAboutExtraArguments(); bool m_helpRequested = false; qbs::Settings::Scope m_settingsScope = qbs::Settings::UserScope; QString m_settingsDir; QStringList m_commandLine; QString m_command; }; #endif // Include guard qbs-src-2.5.1/src/app/config-ui/mainwindow.h0000644000175100001660000000520514744424375020230 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include namespace qbs { class SettingsModel; } QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } class QPoint; QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(const QString &settingsDir, qbs::Settings::Scope scope, QWidget *parent = nullptr); ~MainWindow() override; bool eventFilter(QObject *watched, QEvent *event) override; private: void adjustColumns(); void expandAll(); void collapseAll(); void reloadSettings(); void saveSettings(); void exit(); void provideContextMenu(const QPoint &pos); Ui::MainWindow *ui; qbs::SettingsModel *m_model; }; #endif // MAINWINDOW_H qbs-src-2.5.1/src/app/config-ui/CMakeLists.txt0000644000175100001660000000070414744424375020442 0ustar runnerdockerset(SOURCES commandlineparser.cpp commandlineparser.h main.cpp mainwindow.cpp mainwindow.h mainwindow.ui ) # TODO: support Info.plist if(APPLE) set(MACOS_SOURCES fgapp.mm) set(MACOS_FRAMEWORKS "-framework ApplicationServices" "-framework Cocoa") endif() add_qbs_app(qbs-config-ui DEPENDS qbscore qbsconsolelogger Qt${QT_VERSION_MAJOR}::Widgets ${MACOS_FRAMEWORKS} SOURCES ${SOURCES} ${MACOS_SOURCES} ) qbs-src-2.5.1/src/app/config-ui/Info.plist0000644000175100001660000000070614744424375017654 0ustar runnerdocker CFBundleIdentifier org.qt-project.qbs-config-ui CFBundleInfoDictionaryVersion 6.0 CFBundleName Qbs Settings LSUIElement 1 qbs-src-2.5.1/src/app/config-ui/main.cpp0000644000175100001660000000507014744424375017333 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "mainwindow.h" #include "commandlineparser.h" #include #include #include #include #include int main(int argc, char *argv[]) { QApplication app(argc, argv); CommandLineParser clParser; try { clParser.parse(app.arguments()); if (clParser.helpRequested()) { std::cout << qPrintable(clParser.usageString()); return EXIT_SUCCESS; } } catch (const qbs::ErrorInfo &error) { std::cerr << qPrintable(error.toString()); return EXIT_FAILURE; } MainWindow mw(clParser.settingsDir(), clParser.settingsScope()); mw.show(); return app.exec(); } qbs-src-2.5.1/src/app/config-ui/commandlineparser.cpp0000644000175100001660000001047414744424375022116 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "commandlineparser.h" #include #include #include using qbs::Internal::Tr; static QString helpOptionShort() { return QStringLiteral("-h"); } static QString helpOptionLong() { return QStringLiteral("--help"); } static QString settingsDirOption() { return QStringLiteral("--settings-dir"); } static QString systemOption() { return QStringLiteral("--system"); } void CommandLineParser::parse(const QStringList &commandLine) { m_commandLine = commandLine; Q_ASSERT(!m_commandLine.empty()); m_command = QFileInfo(m_commandLine.takeFirst()).fileName(); m_helpRequested = false; m_settingsDir.clear(); if (m_commandLine.empty()) return; const QString &arg = m_commandLine.front(); if (arg == helpOptionShort() || arg == helpOptionLong()) { m_commandLine.removeFirst(); m_helpRequested = true; } else if (arg == systemOption()) { m_commandLine.removeFirst(); m_settingsScope = qbs::Settings::SystemScope; } else if (arg == settingsDirOption()) { m_commandLine.removeFirst(); assignOptionArgument(settingsDirOption(), m_settingsDir); } if (!m_commandLine.empty()) complainAboutExtraArguments(); } void CommandLineParser::throwError(const QString &message) { qbs::ErrorInfo error(Tr::tr("Syntax error: %1").arg(message)); error.append(usageString()); throw error; } QString CommandLineParser::usageString() const { QString s = Tr::tr("This tool displays qbs settings in a GUI.\n" "If you have more than a few settings, this might be preferable to " "plain \"qbs config\", as it presents a hierarchical view.\n"); s += Tr::tr("Usage:\n"); s += Tr::tr(" %1 [%2 ] [%5] [%3|%4]\n") .arg(m_command, settingsDirOption(), helpOptionShort(), helpOptionLong(), systemOption()); return s; } void CommandLineParser::assignOptionArgument(const QString &option, QString &argument) { if (m_commandLine.empty()) throwError(Tr::tr("Option '%1' needs an argument.").arg(option)); argument = m_commandLine.takeFirst(); if (argument.isEmpty()) throwError(Tr::tr("Argument for option '%1' must not be empty.").arg(option)); } void CommandLineParser::complainAboutExtraArguments() { throwError(Tr::tr("Extraneous command-line arguments '%1'.") .arg(m_commandLine.join(QLatin1Char(' ')))); } qbs-src-2.5.1/src/app/config-ui/fgapp.mm0000644000175100001660000000426114744424375017334 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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 #include extern "C" void qt_macos_forceTransformProcessToForegroundApplicationAndActivate() { [[NSApplication sharedApplication] setActivationPolicy:NSApplicationActivationPolicyRegular]; [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; } qbs-src-2.5.1/src/app/config-ui/mainwindow.ui0000644000175100001660000000151414744424375020415 0ustar runnerdocker MainWindow 0 0 800 600 Qbs Settings 0 0 800 27 qbs-src-2.5.1/src/app/config-ui/config-ui.qbs0000644000175100001660000000126514744424375020274 0ustar runnerdockerQbsApp { Depends { name: "Qt.widgets" } name: "qbs-config-ui" consoleApplication: false files: [ "commandlineparser.cpp", "commandlineparser.h", "main.cpp", "mainwindow.cpp", "mainwindow.h", "mainwindow.ui", ] Group { condition: qbs.targetOS.contains("macos") files: [ "fgapp.mm", "Info.plist" ] } Properties { condition: qbs.targetOS.contains("macos") cpp.frameworks: ["ApplicationServices", "Cocoa"] bundle.isBundle: false } Properties { condition: qbs.targetOS.contains("darwin") bundle.isBundle: false } } qbs-src-2.5.1/src/app/qbs/0000755000175100001660000000000014744424375014606 5ustar runnerdockerqbs-src-2.5.1/src/app/qbs/sessionpacket.h0000644000175100001660000000472314744424375017640 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_SESSIONPACKET_H #define QBS_SESSIONPACKET_H #include #include namespace qbs { namespace Internal { class SessionPacket { public: enum class Status { Incomplete, Complete, Invalid }; Status parseInput(QByteArray &input); QJsonObject retrievePacket(); static QByteArray createPacket(const QJsonObject &packet); static QJsonObject helloMessage(const QString &lspSocket); private: bool isComplete() const; QByteArray m_payload; int m_expectedPayloadLength = -1; }; } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.5.1/src/app/qbs/commandlinefrontend.h0000644000175100001660000001070414744424375021007 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef COMMANDLINEFRONTEND_H #define COMMANDLINEFRONTEND_H #include "parser/commandlineparser.h" #include #include #include #include #include #include QT_BEGIN_NAMESPACE class QTimer; QT_END_NAMESPACE namespace qbs { class AbstractJob; class ConsoleProgressObserver; class ErrorInfo; class ProcessResult; class ProjectGenerator; class Settings; class CommandLineFrontend : public QObject { Q_OBJECT public: explicit CommandLineFrontend(const CommandLineParser &parser, Settings *settings, QObject *parent = nullptr); ~CommandLineFrontend() override; void cancel(); void start(); private: void handleCommandDescriptionReport(const QString &highlight, const QString &message); void handleJobFinished(bool success, qbs::AbstractJob *job); void handleNewTaskStarted(const QString &description, int totalEffort); void handleTotalEffortChanged(int totalEffort); void handleTaskProgress(int value, qbs::AbstractJob *job); void handleProcessResultReport(const qbs::ProcessResult &result); void checkCancelStatus(); using ProductMap = QHash>; ProductMap productsToUse() const; bool resolvingMultipleProjects() const; bool isResolving() const; bool isBuilding() const; void handleProjectsResolved(); void makeClean(); int runShell(); void build(); void checkGeneratorName(); void generate(); int runTarget(); void updateTimestamps(); void dumpNodesTree(); void listProducts(); void connectBuildJobs(); void connectBuildJob(AbstractJob *job); void connectJob(AbstractJob *job); ProductData getTheOneRunnableProduct(); void install(); BuildOptions buildOptions(const Project &project) const; QString buildDirectory(const QString &profileName) const; const CommandLineParser &m_parser; Settings * const m_settings; QList m_resolveJobs; QList m_buildJobs; QList m_projects; ConsoleProgressObserver *m_observer = nullptr; enum CancelStatus { CancelStatusNone, CancelStatusRequested, CancelStatusCanceling }; CancelStatus m_cancelStatus = CancelStatus::CancelStatusNone; QTimer * const m_cancelTimer; int m_buildEffortsNeeded = 0; int m_buildEffortsRetrieved = 0; int m_totalBuildEffort = 0; int m_currentBuildEffort = 0; QHash m_buildEfforts; std::shared_ptr m_generator; }; } // namespace qbs #endif // COMMANDLINEFRONTEND_H qbs-src-2.5.1/src/app/qbs/sessionpacketreader.h0000644000175100001660000000471014744424375021017 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_SESSIONPACKETREADER_H #define QBS_SESSIONPACKETREADER_H #include #include #include namespace qbs { namespace Internal { class SessionPacketReader : public QObject { Q_OBJECT public: explicit SessionPacketReader(QObject *parent = nullptr); ~SessionPacketReader() override; void start(); signals: void packetReceived(const QJsonObject &packet); void errorOccurred(const QString &msg); private: class Private; const std::unique_ptr d; }; } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.5.1/src/app/qbs/status.cpp0000644000175100001660000001552114744424375016641 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "status.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include namespace qbs { static QList createIgnoreList(const QString &projectRootPath) { QList ignoreRegularExpressionList { QRegularExpression(QRegularExpression::anchoredPattern(projectRootPath + QLatin1String("/build.*"))), QRegularExpression(QRegularExpression::wildcardToRegularExpression(QStringLiteral("*.qbs"))), QRegularExpression(QRegularExpression::wildcardToRegularExpression(QStringLiteral("*.pro"))), QRegularExpression(QRegularExpression::wildcardToRegularExpression(QStringLiteral("*Makefile"))), QRegularExpression(QRegularExpression::wildcardToRegularExpression(QStringLiteral("*.so*"))), QRegularExpression(QRegularExpression::wildcardToRegularExpression(QStringLiteral("*.o"))) }; QString ignoreFilePath = projectRootPath + QLatin1String("/.qbsignore"); QFile ignoreFile(ignoreFilePath); if (ignoreFile.open(QFile::ReadOnly)) { const QList ignoreTokenList = ignoreFile.readAll().split('\n'); for (const QByteArray &btoken : ignoreTokenList) { const QString token = QString::fromLatin1(btoken); if (token.startsWith(QLatin1String("/"))) ignoreRegularExpressionList.push_back( QRegularExpression(QRegularExpression::anchoredPattern( projectRootPath + token + QLatin1String(".*")))); else if (!token.isEmpty()) ignoreRegularExpressionList.push_back( QRegularExpression(QRegularExpression::anchoredPattern(token))); } } return ignoreRegularExpressionList; } static QStringList allFilesInDirectoryRecursive( const QDir &rootDirecory, const QList &ignoreRegularExpressionList) { QStringList fileList; const auto fileInfos = rootDirecory.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, QDir::Name); for (const QFileInfo &fileInfo : fileInfos) { QString absoluteFilePath = fileInfo.absoluteFilePath(); bool inIgnoreList = false; for (const QRegularExpression &ignoreRegularExpression : ignoreRegularExpressionList) { if (ignoreRegularExpression.match(absoluteFilePath).hasMatch()) { inIgnoreList = true; break; } } if (!inIgnoreList) { if (fileInfo.isFile()) fileList.push_back(absoluteFilePath); else if (fileInfo.isDir()) fileList << allFilesInDirectoryRecursive(QDir(absoluteFilePath), ignoreRegularExpressionList); } } return fileList; } static QStringList allFilesInProject(const QString &projectRootPath) { QList ignoreRegularExpressionList = createIgnoreList(projectRootPath); return allFilesInDirectoryRecursive(QDir(projectRootPath), ignoreRegularExpressionList); } QStringList allFiles(const ProductData &product) { QStringList files; for (const GroupData &group : product.groups()) files += group.allFilePaths(); return files; } int printStatus(const ProjectData &project) { const QString projectFilePath = project.location().filePath(); QString projectDirectory = QFileInfo(projectFilePath).dir().path(); int projectDirectoryPathLength = projectDirectory.length(); QStringList untrackedFilesInProject = allFilesInProject(projectDirectory); QStringList missingFiles; for (const ProductData &product : project.allProducts()) { qbsInfo() << "\nProduct: " << product.name() << " (" << product.location().filePath() << ":" << product.location().line() << ")"; for (const GroupData &group : product.groups()) { qbsInfo() << " Group: " << group.name() << " (" << group.location().filePath() << ":" << group.location().line() << ")"; const QStringList sourceFiles = Internal::sorted(group.allFilePaths()); for (const QString &sourceFile : sourceFiles) { if (!QFileInfo::exists(sourceFile)) missingFiles.push_back(sourceFile); qbsInfo() << " " << sourceFile.mid(projectDirectoryPathLength + 1); untrackedFilesInProject.removeOne(sourceFile); } } } qbsInfo() << "\nMissing files:"; for (const QString &untrackedFile : std::as_const(missingFiles)) qbsInfo() << " " << untrackedFile.mid(projectDirectoryPathLength + 1); qbsInfo() << "\nUntracked files:"; for (const QString &missingFile : std::as_const(untrackedFilesInProject)) qbsInfo() << " " << missingFile.mid(projectDirectoryPathLength + 1); return 0; } } // namespace qbs qbs-src-2.5.1/src/app/qbs/qbstool.h0000644000175100001660000000502514744424375016444 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_QBSTOOL_H #define QBS_QBSTOOL_H #include class QbsTool { public: void runTool(const QString &toolName, const QStringList &arguments); bool failedToStart() const { return m_failedToStart; } int exitCode() const { return m_exitCode; } QString stdOut() const { return m_stdout; } QString stdErr() const { return m_stderr; } static QStringList allToolNames(); static bool tryToRunTool(const QString &toolName, const QStringList &arguments, int *exitCode = 0); private: bool m_failedToStart = false; int m_exitCode = 0; QString m_stdout; QString m_stderr; }; #endif // QBS_QBSTOOL_H qbs-src-2.5.1/src/app/qbs/ctrlchandler.h0000644000175100001660000000370614744424375017432 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef CTRLCHANDLER_H #define CTRLCHANDLER_H void installCtrlCHandler(); #endif // CTRLCHANDLER_H qbs-src-2.5.1/src/app/qbs/ctrlchandler.cpp0000644000175100001660000000473414744424375017767 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "application.h" static void cancel() { qbs::Application * const app = qbs::Application::instance(); if (app) app->userInterrupt(); } #if defined(Q_OS_WIN) && defined(Q_CC_MSVC) #include static BOOL WINAPI consoleCtrlHandlerRoutine(__in DWORD dwCtrlType) { Q_UNUSED(dwCtrlType); cancel(); return TRUE; } void installCtrlCHandler() { SetConsoleCtrlHandler(&consoleCtrlHandlerRoutine, TRUE); } #else #include static void sigIntHandler(int sig) { Q_UNUSED(sig); cancel(); } void installCtrlCHandler() { signal(SIGINT, sigIntHandler); } #endif qbs-src-2.5.1/src/app/qbs/lspserver.cpp0000644000175100001660000005556114744424375017353 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "lspserver.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WINDOWS #include #else #include #endif namespace qbs::Internal { static int getPid() { #ifdef Q_OS_WINDOWS return _getpid(); #else return getpid(); #endif } using LspErrorResponse = lsp::ResponseError; using LspErrorCode = LspErrorResponse::ErrorCodes; class Document { public: bool isPositionUpToDate(const CodePosition &pos) const; bool isPositionUpToDate(const lsp::Position &pos) const; QString savedContent; QString currentContent; }; static CodePosition posFromLspPos(const lsp::Position &pos) { return {pos.line() + 1, pos.character() + 1}; } static lsp::Position lspPosFromCodeLocation(const CodeLocation &loc) { return {loc.line() - 1, loc.column() - 1}; } static QString uriToString(const lsp::DocumentUri &uri) { return uri.toFilePath([](const lsp::Utils::FilePath &fp) { return fp; }); } static int posToOffset(const CodePosition &pos, const QString &doc); static int posToOffset(const lsp::Position &pos, const QString &doc) { return posToOffset(posFromLspPos(pos), doc); } class AstNodeLocator : public QbsQmlJS::AST::Visitor { public: AstNodeLocator(int position, QbsQmlJS::AST::UiProgram &ast) : m_position(position) { ast.accept(this); } QList path() const { return m_path; } private: bool preVisit(QbsQmlJS::AST::Node *node) override { if (int(node->firstSourceLocation().offset) > m_position) return false; if (int(node->lastSourceLocation().offset) < m_position) return false; m_path << node; return true; } const int m_position; QList m_path; }; class LspServer::Private { public: void setupConnection(); void handleIncomingData(); void discardSocket(); template void sendResponse(const T &msg); void sendErrorResponse(LspErrorCode code, const QString &message); void sendErrorNotification(const QString &message); void sendNoSuchDocumentError(const QString &filePath); void sendMessage(const lsp::JsonObject &msg); void sendMessage(const lsp::JsonRpcMessage &msg); void handleCurrentMessage(); void handleInitializeRequest(); void handleInitializedNotification(); void handleGotoDefinitionRequest(); void handleCompletionRequest(); void handleShutdownRequest(); void handleDidOpenNotification(); void handleDidChangeNotification(); void handleDidSaveNotification(); void handleDidCloseNotification(); QLocalServer server; QBuffer incomingData; lsp::BaseMessage currentMessage; QJsonObject messageObject; QLocalSocket *socket = nullptr; ProjectData projectData; CodeLinks codeLinks; std::unordered_map documents; enum class State { None, InitRequest, InitNotification, Shutdown }; State state = State::None; }; LspServer::LspServer() : d(new Private) { if (!d->server.listen(QString::fromLatin1("qbs-lsp-%1").arg(getPid()))) { // This is not fatal, qbs main operation can continue. qWarning() << "failed to open lsp socket:" << d->server.errorString(); return; } QObject::connect(&d->server, &QLocalServer::newConnection, [this] { d->socket = d->server.nextPendingConnection(); d->setupConnection(); d->server.close(); }); } LspServer::~LspServer() { delete d; } void LspServer::updateProjectData(const ProjectData &projectData, const CodeLinks &codeLinks) { d->projectData = projectData; d->codeLinks = codeLinks; } QString LspServer::socketPath() const { return d->server.fullServerName(); } void LspServer::Private::setupConnection() { QBS_ASSERT(socket, return); QObject::connect(socket, &QLocalSocket::errorOccurred, [this] { discardSocket(); }); QObject::connect(socket, &QLocalSocket::disconnected, [this] { discardSocket(); }); QObject::connect(socket, &QLocalSocket::readyRead, [this] { handleIncomingData(); }); incomingData.open(QIODevice::ReadWrite | QIODevice::Append); handleIncomingData(); } void LspServer::Private::handleIncomingData() { const int pos = incomingData.pos(); incomingData.write(socket->readAll()); incomingData.seek(pos); QString parseError; lsp::BaseMessage::parse(&incomingData, parseError, currentMessage); if (!parseError.isEmpty()) return sendErrorResponse(LspErrorResponse::ParseError, parseError); if (currentMessage.isComplete()) { incomingData.buffer().remove(0, incomingData.pos()); incomingData.seek(0); handleCurrentMessage(); currentMessage = {}; messageObject = {}; if (socket) handleIncomingData(); } } void LspServer::Private::discardSocket() { socket->disconnect(); socket->deleteLater(); socket = nullptr; } template void LspServer::Private::sendResponse(const T &msg) { lsp::Response response(lsp::MessageId(messageObject.value(lsp::idKey))); response.setResult(msg); sendMessage(response); } void LspServer::Private::sendErrorResponse(LspErrorCode code, const QString &message) { lsp::Response response(lsp::MessageId( messageObject.value(lsp::idKey))); lsp::ResponseError error; error.setCode(code); error.setMessage(message); response.setError(error); sendMessage(response); } void LspServer::Private::sendErrorNotification(const QString &message) { lsp::ShowMessageParams params; params.setType(lsp::Error); params.setMessage(message); sendMessage(lsp::ShowMessageNotification(params)); } void LspServer::Private::sendNoSuchDocumentError(const QString &filePath) { sendErrorNotification(Tr::tr("No such document: '%1'").arg(filePath)); } void LspServer::Private::sendMessage(const lsp::JsonObject &msg) { sendMessage(lsp::JsonRpcMessage(msg)); } void LspServer::Private::sendMessage(const lsp::JsonRpcMessage &msg) { lsp::BaseMessage baseMsg = msg.toBaseMessage(); socket->write(baseMsg.header()); socket->write(baseMsg.content); } void LspServer::Private::handleCurrentMessage() { messageObject = lsp::JsonRpcMessage(currentMessage).toJsonObject(); const QString method = messageObject.value(lsp::methodKey).toString(); if (method == QLatin1String("exit")) return discardSocket(); if (state == State::Shutdown) { return sendErrorResponse(LspErrorResponse::InvalidRequest, Tr::tr("Method '%1' not allowed after shutdown.")); } if (method == "shutdown") return handleShutdownRequest(); if (method == QLatin1String("initialize")) return handleInitializeRequest(); if (state == State::None) { return sendErrorResponse(LspErrorResponse::ServerNotInitialized, Tr::tr("First message must be initialize request.")); } if (method == "initialized") return handleInitializedNotification(); if (method == "textDocument/didOpen") return handleDidOpenNotification(); if (method == "textDocument/didChange") return handleDidChangeNotification(); if (method == "textDocument/didSave") return handleDidSaveNotification(); if (method == "textDocument/didClose") return handleDidCloseNotification(); if (method == "textDocument/definition") return handleGotoDefinitionRequest(); if (method == "textDocument/completion") return handleCompletionRequest(); sendErrorResponse(LspErrorResponse::MethodNotFound, Tr::tr("This server can do very little.")); } void LspServer::Private::handleInitializeRequest() { if (state != State::None) { return sendErrorResponse(LspErrorResponse::InvalidRequest, Tr::tr("Received initialize request in initialized state.")); } state = State::InitRequest; lsp::ServerInfo serverInfo; serverInfo.insert(lsp::nameKey, "qbs"); serverInfo.insert(lsp::versionKey, QBS_VERSION); lsp::InitializeResult result; result.insert(lsp::serverInfoKey, serverInfo); lsp::ServerCapabilities capabilities; // TODO: hover capabilities.setDefinitionProvider(true); capabilities.setTextDocumentSync({int(lsp::TextDocumentSyncKind::Incremental)}); lsp::ServerCapabilities::CompletionOptions completionOptions; completionOptions.setTriggerCharacters({"."}); capabilities.setCompletionProvider(completionOptions); result.setCapabilities(capabilities); sendResponse(result); } void LspServer::Private::handleInitializedNotification() { if (state != State::InitRequest) { return sendErrorResponse(LspErrorResponse::InvalidRequest, Tr::tr("Unexpected initialized notification.")); } state = State::InitNotification; } void LspServer::Private::handleGotoDefinitionRequest() { const lsp::TextDocumentPositionParams params(messageObject.value(lsp::paramsKey)); const QString sourceFile = params.textDocument().uri().toLocalFile(); const Document *sourceDoc = nullptr; if (const auto it = documents.find(sourceFile); it != documents.end()) sourceDoc = &it->second; const auto fileEntry = codeLinks.constFind(sourceFile); if (fileEntry == codeLinks.constEnd()) return sendResponse(nullptr); const CodePosition sourcePos = posFromLspPos(params.position()); if (sourceDoc && !sourceDoc->isPositionUpToDate(sourcePos)) return sendResponse(nullptr); for (auto it = fileEntry->cbegin(); it != fileEntry->cend(); ++it) { if (!it.key().contains(sourcePos)) continue; if (sourceDoc && !sourceDoc->isPositionUpToDate(it.key().end())) return sendResponse(nullptr); QList targets = it.value(); QBS_ASSERT(!targets.isEmpty(), return sendResponse(nullptr)); for (auto it = targets.begin(); it != targets.end();) { const Document *targetDoc = nullptr; if (it->filePath() == sourceFile) targetDoc = sourceDoc; else if (const auto docIt = documents.find(it->filePath()); docIt != documents.end()) targetDoc = &docIt->second; if (targetDoc && !targetDoc->isPositionUpToDate(CodePosition(it->line(), it->column()))) it = targets.erase(it); else ++it; } struct JsonArray : public QJsonArray { void reserve(std::size_t) {}}; const auto locations = transformed(targets, [](const CodeLocation &loc) { const lsp::Position startPos = lspPosFromCodeLocation(loc); const lsp::Position endPos(startPos.line(), startPos.character() + 1); lsp::Location targetLocation; targetLocation.setUri(lsp::DocumentUri::fromProtocol( QUrl::fromLocalFile(loc.filePath()).toString())); targetLocation.setRange({startPos, endPos}); return QJsonObject(targetLocation); }); if (locations.size() == 1) return sendResponse(locations.first().toObject()); return sendResponse(locations); } sendResponse(nullptr); } // We operate under the assumption that the client has basic QML support. // Therefore, we only provide completion for qbs modules and their properties. // Only a simple prefix match is implemented, with no regard to the contents after the cursor. void LspServer::Private::handleCompletionRequest() { if (!projectData.isValid()) return sendResponse(nullptr); const lsp::CompletionParams params(messageObject.value(lsp::paramsKey)); const QString sourceFile = params.textDocument().uri().toLocalFile(); const Document *sourceDoc = nullptr; if (const auto it = documents.find(sourceFile); it != documents.end()) sourceDoc = &it->second; if (!sourceDoc) return sendResponse(nullptr); // If there are products corresponding to this file, check only these when looking for modules. // Otherwise, check all products. const QList allProducts = projectData.allProducts(); if (allProducts.isEmpty()) return sendResponse(nullptr); QList relevantProducts; for (const ProductData &p : allProducts) { if (p.location().filePath() == sourceFile) relevantProducts << p; } if (relevantProducts.isEmpty()) relevantProducts = allProducts; QString identifierPrefix; QStringList modulePrefixes; const int offset = posToOffset(params.position(), sourceDoc->currentContent) - 1; if (offset < 0 || offset >= sourceDoc->currentContent.length()) return sendResponse(nullptr); const auto collectFromRawString = [&] { int currentPos = offset; const auto constructIdentifier = [&] { QString id; while (currentPos >= 0) { const QChar c = sourceDoc->currentContent.at(currentPos); if (!c.isLetterOrNumber() && c != '_') break; id.prepend(c); --currentPos; } return id; }; identifierPrefix = constructIdentifier(); while (true) { if (currentPos <= 0 || sourceDoc->currentContent.at(currentPos) != '.') return; --currentPos; const QString modulePrefix = constructIdentifier(); if (modulePrefix.isEmpty()) return; modulePrefixes.prepend(modulePrefix); } }; // Parse the current file. Note that completion usually happens on invalid code, which // often confuses the parser so much that it yields unusable results. Therefore, we always // gather our input parameters from the raw string. We only use the parse result to skip // completion in contexts where it is undesirable. QbsQmlJS::Engine engine; QbsQmlJS::Lexer lexer(&engine); lexer.setCode(sourceDoc->currentContent, 1); QbsQmlJS::Parser parser(&engine); parser.parse(); if (parser.ast()) { AstNodeLocator locator(offset, *parser.ast()); const QList &astPath = locator.path(); if (!astPath.isEmpty()) { switch (astPath.last()->kind) { case QbsQmlJS::AST::Node::Kind_FieldMemberExpression: case QbsQmlJS::AST::Node::Kind_UiObjectDefinition: case QbsQmlJS::AST::Node::Kind_UiQualifiedId: case QbsQmlJS::AST::Node::Kind_UiScriptBinding: break; default: return sendResponse(nullptr); } } } collectFromRawString(); if (modulePrefixes.isEmpty() && identifierPrefix.isEmpty()) return sendResponse(nullptr); // We do not want to start completion from nothing. QJsonArray results; QMap namesAndTypes; for (const ProductData &product : std::as_const(relevantProducts)) { const PropertyMap &moduleProps = product.moduleProperties(); const QStringList allModules = moduleProps.allModules(); const QString moduleNameOrPrefix = modulePrefixes.join('.'); // Case 1: Prefixes match a module name. Identifier can only expand to the name // of a module property. // Example: "Qt.core.a^" -> "Qt.core.availableBuildVariants" if (!modulePrefixes.isEmpty() && allModules.contains(moduleNameOrPrefix)) { for (const PropertyMap::PropertyInfo &info : moduleProps.allPropertiesForModule(moduleNameOrPrefix)) { if (info.isBuiltin) continue; if (!identifierPrefix.isEmpty() && !info.name.startsWith(identifierPrefix)) continue; namesAndTypes.insert(info.name, info.type); } continue; } // Case 2: Isolated identifier. Can only expand to a module name. // Example: "Q^" -> "Qt.core", "Qt.widgets", ... // Case 3: Prefixes match a module prefix. Identifier can only expand to a module name. // Example: "Qt.c^" -> "Qt.core", "Qt.concurrent", ... QString fullPrefix = identifierPrefix; int nameOffset = 0; if (!modulePrefixes.isEmpty()) { fullPrefix.prepend(moduleNameOrPrefix + '.'); nameOffset = moduleNameOrPrefix.length() + 1; } for (const QString &module : allModules) { if (module.startsWith(fullPrefix)) namesAndTypes.insert(module.mid(nameOffset), {}); } } for (auto it = namesAndTypes.cbegin(); it != namesAndTypes.cend(); ++it) { lsp::CompletionItem item; item.setLabel(it.key()); if (!it.value().isEmpty()) item.setDetail(it.value()); results.append(QJsonObject(item)); }; sendResponse(results); } void LspServer::Private::handleShutdownRequest() { state = State::Shutdown; sendResponse(nullptr); } void LspServer::Private::handleDidOpenNotification() { const lsp::TextDocumentItem docItem = lsp::DidOpenTextDocumentNotification(messageObject) .params().value_or(lsp::DidOpenTextDocumentParams()) .textDocument(); if (!docItem.isValid()) return sendErrorNotification(Tr::tr("Invalid didOpen parameters.")); const QString filePath = uriToString(docItem.uri()); Document &doc = documents[filePath]; doc.savedContent = doc.currentContent = docItem.text(); } void LspServer::Private::handleDidChangeNotification() { const auto params = lsp::DidChangeTextDocumentNotification(messageObject) .params().value_or(lsp::DidChangeTextDocumentParams()); if (!params.isValid()) return sendErrorNotification(Tr::tr("Invalid didChange parameters.")); const QString filePath = uriToString(params.textDocument().uri()); const auto docIt = documents.find(filePath); if (docIt == documents.end()) return sendNoSuchDocumentError(filePath); Document &doc = docIt->second; const auto changes = params.contentChanges(); for (const auto &change : changes) { const auto range = change.range(); if (!range) { doc.currentContent = change.text(); continue; } const int startPos = posToOffset(range->start(), doc.currentContent); const int endPos = posToOffset(range->end(), doc.currentContent); if (startPos == -1 || endPos == -1 || startPos > endPos) return sendErrorResponse(LspErrorResponse::InvalidParams, Tr::tr("Invalid range.")); doc.currentContent.replace(startPos, endPos - startPos, change.text()); } } void LspServer::Private::handleDidSaveNotification() { const QString filePath = uriToString(lsp::DidSaveTextDocumentNotification(messageObject) .params().value_or(lsp::DidSaveTextDocumentParams()) .textDocument().uri()); const auto docIt = documents.find(filePath); if (docIt == documents.end()) return sendNoSuchDocumentError(filePath); docIt->second.savedContent = docIt->second.currentContent; // TODO: Mark the project data as out of date until the next update(),if the document // is in buildSystemFiles(). } void LspServer::Private::handleDidCloseNotification() { const QString filePath = uriToString(lsp::DidCloseTextDocumentNotification(messageObject) .params().value_or(lsp::DidCloseTextDocumentParams()) .textDocument().uri()); const auto docIt = documents.find(filePath); if (docIt == documents.end()) return sendNoSuchDocumentError(filePath); documents.erase(docIt); } static int posToOffset(const CodePosition &pos, const QString &doc) { int offset = 0; for (int newlines = 0, next = 0; newlines < pos.line() - 1; ++newlines) { offset = doc.indexOf('\n', next); if (offset == -1) return -1; next = offset + 1; } return offset + pos.column(); } bool Document::isPositionUpToDate(const CodePosition &pos) const { const int origOffset = posToOffset(pos, savedContent); if (origOffset > int(currentContent.size())) return false; return QStringView(currentContent).left(origOffset) == QStringView(savedContent).left(origOffset); } bool Document::isPositionUpToDate(const lsp::Position &pos) const { return isPositionUpToDate(posFromLspPos(pos)); } } // namespace qbs::Internal qbs-src-2.5.1/src/app/qbs/status.h0000644000175100001660000000377514744424375016316 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef STATUS_H #define STATUS_H namespace qbs { class ProjectData; int printStatus(const ProjectData &project); } // namespace qbs #endif // STATUS_H qbs-src-2.5.1/src/app/qbs/qbs.qbs0000644000175100001660000000370214744424375016104 0ustar runnerdockerimport qbs.Utilities QbsApp { name: "qbs_app" targetName: "qbs" Depends { name: "qbs resources" } Depends { name: "qtclsp" } Depends { name: "Qt.network" } Depends { condition: Qt.core.staticBuild || qbsbuildconfig.staticBuild productTypes: ["qbsplugin"] } cpp.defines: base.concat([ "QBS_VERSION=" + Utilities.cStringQuote(qbsversion.version), "QBS_RELATIVE_LIBEXEC_PATH=" + Utilities.cStringQuote(qbsbuildconfig.relativeLibexecPath), "QBS_RELATIVE_SEARCH_PATH=" + Utilities.cStringQuote(qbsbuildconfig.relativeSearchPath), "QBS_RELATIVE_PLUGINS_PATH=" + Utilities.cStringQuote(qbsbuildconfig.relativePluginsPath), ]) files: [ "application.cpp", "application.h", "commandlinefrontend.cpp", "commandlinefrontend.h", "consoleprogressobserver.cpp", "consoleprogressobserver.h", "ctrlchandler.cpp", "ctrlchandler.h", "main.cpp", "qbstool.cpp", "qbstool.h", "session.cpp", "session.h", "sessionpacket.cpp", "sessionpacket.h", "sessionpacketreader.cpp", "sessionpacketreader.h", "status.cpp", "status.h", "stdinreader.cpp", "stdinreader.h", ] Group { name: "parser" prefix: name + '/' files: [ "commandlineoption.cpp", "commandlineoption.h", "commandlineoptionpool.cpp", "commandlineoptionpool.h", "commandlineparser.cpp", "commandlineparser.h", "commandpool.cpp", "commandpool.h", "commandtype.h", "parsercommand.cpp", "parsercommand.h", ] } Group { name: "lsp" cpp.defines: outer.filter(function(d) { return d !== "QT_NO_CAST_FROM_ASCII"; }) files: [ "lspserver.cpp", "lspserver.h", ] } } qbs-src-2.5.1/src/app/qbs/consoleprogressobserver.cpp0000644000175100001660000001007414744424375022313 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "consoleprogressobserver.h" #include #include #include namespace qbs { void ConsoleProgressObserver::initialize(const QString &task, int max) { m_maximum = max; m_value = 0; m_percentage = 0; m_hashesPrinted = 0; std::cout << task.toLocal8Bit().constData() << ": 0%" << std::flush; setMaximum(max); } void ConsoleProgressObserver::setMaximum(int maximum) { m_maximum = maximum; if (maximum == 0) { m_percentage = 100; updateProgressBarIfNecessary(); writePercentageString(); std::cout << std::endl; } } void ConsoleProgressObserver::setProgressValue(int value) { if (value > m_maximum || value <= m_value) return; // TODO: Should be an assertion, but the executor currently breaks it. m_value = value; const int newPercentage = (100 * m_value) / m_maximum; if (newPercentage == m_percentage) return; eraseCurrentPercentageString(); m_percentage = newPercentage; updateProgressBarIfNecessary(); writePercentageString(); if (m_value == m_maximum) std::cout << std::endl; else std::cout << std::flush; } void ConsoleProgressObserver::eraseCurrentPercentageString() { const int charsToErase = m_percentage == 0 ? 2 : m_percentage < 10 ? 3 : 4; const QByteArray backspaceCommand(charsToErase, '\b'); // Move cursor before the old percentage string. std::cout << backspaceCommand.constData(); // Erase old percentage string. std::cout << QByteArray(charsToErase, ' ').constData(); // Move cursor before the erased string. std::cout << backspaceCommand.constData(); } void ConsoleProgressObserver::updateProgressBarIfNecessary() { static const int TotalHashCount = 50; // Should fit on most terminals without a line break. const int hashesNeeded = (m_percentage * TotalHashCount) / 100; if (m_hashesPrinted < hashesNeeded) { std::cout << QByteArray(hashesNeeded - m_hashesPrinted, '#').constData(); m_hashesPrinted = hashesNeeded; } } void ConsoleProgressObserver::writePercentageString() { std::cout << QStringLiteral(" %1%").arg(m_percentage).toLocal8Bit().constData(); } } // namespace qbs qbs-src-2.5.1/src/app/qbs/CMakeLists.txt0000644000175100001660000000241514744424375017350 0ustar runnerdockerset(SOURCES application.cpp application.h commandlinefrontend.cpp commandlinefrontend.h consoleprogressobserver.cpp consoleprogressobserver.h ctrlchandler.cpp ctrlchandler.h lspserver.cpp lspserver.h main.cpp qbstool.cpp qbstool.h session.cpp session.h sessionpacket.cpp sessionpacket.h sessionpacketreader.cpp sessionpacketreader.h status.cpp status.h stdinreader.cpp stdinreader.h ) set(PARSER_SOURCES commandlineoption.cpp commandlineoption.h commandlineoptionpool.cpp commandlineoptionpool.h commandlineparser.cpp commandlineparser.h commandpool.cpp commandpool.h commandtype.h parsercommand.cpp parsercommand.h ) list_transform_prepend(PARSER_SOURCES parser/) add_qbs_app(qbs DEFINES "QBS_VERSION=\"${QBS_VERSION}\"" "QBS_RELATIVE_LIBEXEC_PATH=\"${QBS_RELATIVE_LIBEXEC_PATH}\"" "QBS_RELATIVE_SEARCH_PATH=\"${QBS_RELATIVE_SEARCH_PATH}\"" "QBS_RELATIVE_PLUGINS_PATH=\"${QBS_RELATIVE_PLUGINS_PATH}\"" DEPENDS qbscore qbsconsolelogger qtclsp Qt${QT_VERSION_MAJOR}::Network SOURCES ${SOURCES} ${PARSER_SOURCES} ) add_dependencies(qbs qbs_cpp_scanner qbs_qt_scanner) qbs-src-2.5.1/src/app/qbs/application.h0000644000175100001660000000450414744424375017265 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef APPLICATION_H #define APPLICATION_H #include namespace qbs { class CommandLineFrontend; class Application : public QCoreApplication { Q_OBJECT public: Application(int &argc, char **argv); static Application *instance(); void setCommandLineFrontend(CommandLineFrontend *clFrontend); void userInterrupt(); private: CommandLineFrontend *m_clFrontend; bool m_canceled; }; } // namespace qbs #endif // APPLICATION_H qbs-src-2.5.1/src/app/qbs/main.cpp0000644000175100001660000000660614744424375016246 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "application.h" #include "commandlinefrontend.h" #include "qbstool.h" #include "parser/commandlineparser.h" #include "../shared/logging/consolelogger.h" #include #include #include using namespace qbs; static bool tryToRunTool(const QStringList &arguments, int &exitCode) { if (arguments.empty()) return false; QStringList toolArgs = arguments; const QString toolName = toolArgs.takeFirst(); if (toolName.startsWith(QLatin1Char('-'))) return false; return QbsTool::tryToRunTool(toolName, toolArgs, &exitCode); } int main(int argc, char *argv[]) { ConsoleLogger::instance(); try { Application app(argc, argv); QStringList arguments = app.arguments(); arguments.removeFirst(); int toolExitCode = 0; if (tryToRunTool(arguments, toolExitCode)) return toolExitCode; CommandLineParser parser; if (!parser.parseCommandLine(arguments)) return EXIT_FAILURE; if (parser.command() == HelpCommandType) { parser.printHelp(); return 0; } Settings settings(parser.settingsDir()); ConsoleLogger::instance().setSettings(&settings); CommandLineFrontend clFrontend(parser, &settings); app.setCommandLineFrontend(&clFrontend); QTimer::singleShot(0, &clFrontend, &CommandLineFrontend::start); return app.exec(); } catch (const ErrorInfo &error) { qbsError() << error.toString(); return EXIT_FAILURE; } } qbs-src-2.5.1/src/app/qbs/commandlinefrontend.cpp0000644000175100001660000006652414744424375021355 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "commandlinefrontend.h" #include "application.h" #include "consoleprogressobserver.h" #include "session.h" #include "status.h" #include "parser/commandlineoption.h" #include "../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace qbs { using namespace Internal; CommandLineFrontend::CommandLineFrontend(const CommandLineParser &parser, Settings *settings, QObject *parent) : QObject(parent) , m_parser(parser) , m_settings(settings) , m_observer(nullptr) , m_cancelStatus(CancelStatusNone) , m_cancelTimer(new QTimer(this)) { } CommandLineFrontend::~CommandLineFrontend() { m_cancelTimer->stop(); delete m_observer; } // Called from interrupt handler. Don't do anything non-trivial here. void CommandLineFrontend::cancel() { m_cancelStatus = CancelStatusRequested; } void CommandLineFrontend::checkCancelStatus() { switch (m_cancelStatus) { case CancelStatusNone: break; case CancelStatusRequested: m_cancelStatus = CancelStatusCanceling; m_cancelTimer->stop(); if (m_resolveJobs.empty() && m_buildJobs.empty()) std::exit(EXIT_FAILURE); for (AbstractJob * const job : std::as_const(m_resolveJobs)) job->cancel(); for (AbstractJob * const job : std::as_const(m_buildJobs)) job->cancel(); break; case CancelStatusCanceling: QBS_ASSERT(false, return); break; } } void CommandLineFrontend::start() { try { switch (m_parser.command()) { case RunCommandType: case ShellCommandType: if (m_parser.products().size() > 1) { throw ErrorInfo(Tr::tr("Invalid use of command '%1': Cannot use more than one " "product.\nUsage: %2") .arg(m_parser.commandName(), m_parser.commandDescription())); } Q_FALLTHROUGH(); case StatusCommandType: case InstallCommandType: case DumpNodesTreeCommandType: case ListProductsCommandType: if (m_parser.buildConfigurations().size() > 1) { QString error = Tr::tr("Invalid use of command '%1': There can be only one " "build configuration.\n").arg(m_parser.commandName()); error += Tr::tr("Usage: %1").arg(m_parser.commandDescription()); throw ErrorInfo(error); } break; case SessionCommandType: { startSession(); return; } default: break; } if (m_parser.showVersion()) { std::puts(QBS_VERSION); qApp->exit(EXIT_SUCCESS); return; } if (m_parser.showProgress()) m_observer = new ConsoleProgressObserver; SetupProjectParameters params; params.setEnvironment(QProcessEnvironment::systemEnvironment()); params.setProjectFilePath(m_parser.projectFilePath()); params.setDryRun(m_parser.dryRun()); params.setForceProbeExecution(m_parser.forceProbesExecution()); params.setWaitLockBuildGraph(m_parser.waitLockBuildGraph()); params.setLogElapsedTime(m_parser.logTime()); params.setSettingsDirectory(m_settings->baseDirectory()); params.setOverrideBuildGraphData(m_parser.command() == ResolveCommandType); params.setPropertyCheckingMode(ErrorHandlingMode::Strict); params.setDeprecationWarningMode(m_parser.deprecationWarningMode()); if (!m_parser.buildBeforeInstalling() || !m_parser.commandCanResolve()) params.setRestoreBehavior(SetupProjectParameters::RestoreOnly); const auto buildConfigs = m_parser.buildConfigurations(); for (const QVariantMap &buildConfig : buildConfigs) { QVariantMap userConfig = buildConfig; const QString configurationKey = QStringLiteral("qbs.configurationName"); const QString profileKey = QStringLiteral("qbs.profile"); const QString installRootKey = QStringLiteral("qbs.installRoot"); QString installRoot = userConfig.value(installRootKey).toString(); if (!installRoot.isEmpty() && QFileInfo(installRoot).isRelative()) { installRoot.prepend(QLatin1Char('/')).prepend(QDir::currentPath()); userConfig.insert(installRootKey, installRoot); } const QString configurationName = userConfig.take(configurationKey).toString(); const QString profileName = userConfig.take(profileKey).toString(); const Preferences prefs(m_settings); params.setSearchPaths(prefs.searchPaths(QDir::cleanPath(QCoreApplication::applicationDirPath() + QLatin1String("/" QBS_RELATIVE_SEARCH_PATH)))); params.setPluginPaths(prefs.pluginPaths(QDir::cleanPath(QCoreApplication::applicationDirPath() + QLatin1String("/" QBS_RELATIVE_PLUGINS_PATH)))); params.setLibexecPath(QDir::cleanPath(QCoreApplication::applicationDirPath() + QLatin1String("/" QBS_RELATIVE_LIBEXEC_PATH))); params.setTopLevelProfile(profileName); params.setConfigurationName(configurationName); params.setBuildRoot(buildDirectory(profileName)); params.setOverriddenValues(userConfig); params.setMaxJobCount(m_parser.jobCount(profileName)); SetupProjectJob * const job = Project().setupProject(params, ConsoleLogger::instance().logSink(), this); connectJob(job); m_resolveJobs.push_back(job); } /* * Progress reporting on the terminal gets a bit tricky when resolving several projects * concurrently, since we cannot show multiple progress bars at the same time. Instead, * we just set the total effort to the number of projects and increase the progress * every time one of them finishes, ignoring the progress reports from the jobs themselves. * (Yes, that does mean it will take disproportionately long for the first progress * notification to arrive.) */ if (m_parser.showProgress() && resolvingMultipleProjects()) m_observer->initialize(tr("Setting up projects"), m_resolveJobs.size()); // Check every two seconds whether we received a cancel request. This value has been // experimentally found to be acceptable. // Note that this polling approach is not problematic here, since we are doing work anyway, // so there's no danger of waking up the processor for no reason. connect(m_cancelTimer, &QTimer::timeout, this, &CommandLineFrontend::checkCancelStatus); m_cancelTimer->start(2000); } catch (const ErrorInfo &error) { qbsError() << error.toString(); if (m_buildJobs.empty() && m_resolveJobs.empty()) { qApp->exit(EXIT_FAILURE); } else { cancel(); checkCancelStatus(); } } } void CommandLineFrontend::handleCommandDescriptionReport(const QString &highlight, const QString &message) { qbsInfo() << MessageTag(highlight) << message; } void CommandLineFrontend::handleJobFinished(bool success, AbstractJob *job) { try { job->deleteLater(); if (!success) { qbsError() << job->error().toString(); m_resolveJobs.removeOne(job); m_buildJobs.removeOne(job); if (m_resolveJobs.empty() && m_buildJobs.empty()) { qApp->exit(EXIT_FAILURE); return; } cancel(); } else if (const auto setupJob = qobject_cast(job)) { m_resolveJobs.removeOne(job); m_projects.push_back(setupJob->project()); if (m_observer && resolvingMultipleProjects()) m_observer->incrementProgressValue(); if (m_resolveJobs.empty()) handleProjectsResolved(); } else if (qobject_cast(job)) { if (m_parser.command() == RunCommandType) qApp->exit(runTarget()); else qApp->quit(); } else { // Build or clean. m_buildJobs.removeOne(job); if (m_buildJobs.empty()) { switch (m_parser.command()) { case RunCommandType: case InstallCommandType: install(); break; case GenerateCommandType: generate(); // fall through case BuildCommandType: case CleanCommandType: qApp->exit(m_cancelStatus == CancelStatusNone ? EXIT_SUCCESS : EXIT_FAILURE); break; default: Q_ASSERT_X(false, Q_FUNC_INFO, "Missing case in switch statement"); } } } } catch (const ErrorInfo &error) { qbsError() << error.toString(); qApp->exit(EXIT_FAILURE); } } void CommandLineFrontend::handleNewTaskStarted(const QString &description, int totalEffort) { // If the user does not want a progress bar, we just print the current activity. if (!m_parser.showProgress()) { if (!m_parser.logTime()) qbsInfo() << description; return; } if (isBuilding()) { m_totalBuildEffort += totalEffort; if (++m_buildEffortsRetrieved == m_buildEffortsNeeded) { m_observer->initialize(tr("Building"), m_totalBuildEffort); if (m_currentBuildEffort > 0) m_observer->setProgressValue(m_currentBuildEffort); } } else if (!resolvingMultipleProjects()) { m_observer->initialize(description, totalEffort); } } void CommandLineFrontend::handleTotalEffortChanged(int totalEffort) { // Can only happen when resolving. if (m_parser.showProgress() && !isBuilding() && !resolvingMultipleProjects()) m_observer->setMaximum(totalEffort); } void CommandLineFrontend::handleTaskProgress(int value, AbstractJob *job) { if (isBuilding()) { int ¤tJobEffort = m_buildEfforts[job]; m_currentBuildEffort += value - currentJobEffort; currentJobEffort = value; if (m_buildEffortsRetrieved == m_buildEffortsNeeded) m_observer->setProgressValue(m_currentBuildEffort); } else if (!resolvingMultipleProjects()) { m_observer->setProgressValue(value); } } void CommandLineFrontend::handleProcessResultReport(const qbs::ProcessResult &result) { bool hasOutput = !result.stdOut().empty() || !result.stdErr().empty(); if (!hasOutput && result.success()) return; LogWriter w = result.success() ? qbsInfo() : qbsError(); w << shellQuote(QDir::toNativeSeparators(result.executableFilePath()), result.arguments()) << (hasOutput ? QStringLiteral("\n") : QString()) << (result.stdOut().empty() ? QString() : result.stdOut().join(QLatin1Char('\n'))); if (!result.stdErr().empty()) w << result.stdErr().join(QLatin1Char('\n')) << MessageTag(QStringLiteral("stdErr")); } bool CommandLineFrontend::resolvingMultipleProjects() const { return isResolving() && m_resolveJobs.size() + m_projects.size() > 1; } bool CommandLineFrontend::isResolving() const { return !m_resolveJobs.empty(); } bool CommandLineFrontend::isBuilding() const { return !m_buildJobs.empty(); } CommandLineFrontend::ProductMap CommandLineFrontend::productsToUse() const { ProductMap products; QStringList productNames; const bool useAll = m_parser.products().empty(); for (const Project &project : std::as_const(m_projects)) { QList &productList = products[project]; const ProjectData projectData = project.projectData(); for (const ProductData &product : projectData.allProducts()) { productNames << product.fullDisplayName(); if (useAll || m_parser.products().contains(product.fullDisplayName())) { productList.push_back(product); } } } const auto parsedProductNames = m_parser.products(); for (const QString &productName : parsedProductNames) { if (!productNames.contains(productName)) { QString msg; if (productNames.size() <= 10) { productNames.sort(); const QString available = productNames.join(QLatin1String("', '")); msg = Tr::tr("No such product '%1'. " "Available products: '%2'").arg(productName, available); } else { msg = Tr::tr("No such product '%1'. Use 'list-products' to see " "all available products.").arg(productName); } throw ErrorInfo(msg); } } return products; } void CommandLineFrontend::handleProjectsResolved() { if (m_cancelStatus != CancelStatusNone) throw ErrorInfo(Tr::tr("Execution canceled.")); switch (m_parser.command()) { case ResolveCommandType: qApp->quit(); break; case CleanCommandType: makeClean(); break; case ShellCommandType: qApp->exit(runShell()); break; case StatusCommandType: qApp->exit(printStatus(m_projects.front().projectData())); break; case GenerateCommandType: checkGeneratorName(); Q_FALLTHROUGH(); case BuildCommandType: build(); break; case InstallCommandType: case RunCommandType: if (m_parser.buildBeforeInstalling()) build(); else install(); break; case UpdateTimestampsCommandType: updateTimestamps(); qApp->quit(); break; case DumpNodesTreeCommandType: dumpNodesTree(); qApp->quit(); break; case ListProductsCommandType: listProducts(); qApp->quit(); break; case HelpCommandType: case VersionCommandType: case SessionCommandType: Q_ASSERT_X(false, Q_FUNC_INFO, "Impossible."); } } void CommandLineFrontend::makeClean() { if (m_parser.products().empty()) { for (const Project &project : std::as_const(m_projects)) { m_buildJobs << project.cleanAllProducts(m_parser.cleanOptions(project.profile()), this); } } else { const ProductMap &products = productsToUse(); for (ProductMap::ConstIterator it = products.begin(); it != products.end(); ++it) { m_buildJobs.push_back(it.key().cleanSomeProducts( it.value(), m_parser.cleanOptions(it.key().profile()), this)); } } connectBuildJobs(); } int CommandLineFrontend::runShell() { ProductData productToRun; switch (m_parser.products().size()) { case 0: // No specific product, use project-global environment. break; case 1: productToRun = productsToUse().values().front().front(); break; default: throw ErrorInfo(Tr::tr("The command '%1' cannot take more than one product.")); } RunEnvironment runEnvironment = m_projects.front().getRunEnvironment(productToRun, m_parser.installOptions(m_projects.front().profile()), QProcessEnvironment::systemEnvironment(), QStringList(), m_settings); return runEnvironment.doRunShell(); } BuildOptions CommandLineFrontend::buildOptions(const Project &project) const { BuildOptions options = m_parser.buildOptions(m_projects.front().profile()); if (options.maxJobCount() <= 0) { const QString profileName = project.profile(); QBS_CHECK(!profileName.isEmpty()); options.setMaxJobCount(Preferences(m_settings, profileName).jobs()); } return options; } QString CommandLineFrontend::buildDirectory(const QString &profileName) const { QString buildDir = m_parser.projectBuildDirectory(); if (buildDir.isEmpty()) { buildDir = Preferences(m_settings, profileName).defaultBuildDirectory(); if (buildDir.isEmpty()) { qbsDebug() << "No project build directory given; using current directory."; buildDir = QDir::currentPath(); } else { qbsDebug() << "No project build directory given; using directory from preferences."; } } QString projectName(QFileInfo(m_parser.projectFilePath()).baseName()); QString originalBuildDir = buildDir; buildDir.replace(BuildDirectoryOption::magicProjectString(), projectName); const QString buildDirPlaceHolderMsgTemplate = Tr::tr( "You must provide the path to the project file when using build directory " "placeholder '%1'."); if (buildDir != originalBuildDir && projectName.isEmpty()) { throw ErrorInfo( buildDirPlaceHolderMsgTemplate.arg(BuildDirectoryOption::magicProjectString())); } QString projectDir(QFileInfo(m_parser.projectFilePath()).path()); originalBuildDir = buildDir; buildDir.replace(BuildDirectoryOption::magicProjectDirString(), projectDir); if (buildDir != originalBuildDir && projectDir.isEmpty()) { throw ErrorInfo( buildDirPlaceHolderMsgTemplate.arg(BuildDirectoryOption::magicProjectDirString())); } if (!QFileInfo(buildDir).isAbsolute()) buildDir = QDir::currentPath() + QLatin1Char('/') + buildDir; buildDir = QDir::cleanPath(buildDir); return buildDir; } void CommandLineFrontend::build() { if (m_parser.products().empty()) { const Project::ProductSelection productSelection = m_parser.withNonDefaultProducts() ? Project::ProductSelectionWithNonDefault : Project::ProductSelectionDefaultOnly; for (const Project &project : std::as_const(m_projects)) m_buildJobs << project.buildAllProducts(buildOptions(project), productSelection, this); } else { const ProductMap &products = productsToUse(); for (ProductMap::ConstIterator it = products.begin(); it != products.end(); ++it) m_buildJobs.push_back(it.key().buildSomeProducts(it.value(), buildOptions(it.key()), this)); } connectBuildJobs(); /* * Progress reporting for the build jobs works as follows: We know that for every job, * the newTaskStarted() signal is emitted exactly once (unless there's an error). So we add up * the respective total efforts as they come in. Once all jobs have reported their total * efforts, we can start the overall progress report. */ m_buildEffortsNeeded = m_buildJobs.size(); m_buildEffortsRetrieved = 0; m_totalBuildEffort = 0; m_currentBuildEffort = 0; } void CommandLineFrontend::checkGeneratorName() { const QString generatorName = m_parser.generateOptions().generatorName(); m_generator = ProjectGeneratorManager::findGenerator(generatorName); if (m_generator) return; const auto generatorNames = ProjectGeneratorManager::loadedGeneratorNames(); if (!generatorNames.empty()) { const QString generatorNamesString = generatorNames.join(QLatin1String("\n\t")); if (!generatorName.isEmpty()) { throw ErrorInfo(Tr::tr("No generator named '%1'. Available generators:\n\t%2") .arg(generatorName, generatorNamesString)); } throw ErrorInfo(Tr::tr("No generator specified. Available generators:\n\t%1") .arg(generatorNamesString)); } throw ErrorInfo(Tr::tr("No generator specified or no generators are available.")); } void CommandLineFrontend::generate() { QBS_CHECK(!!m_generator); const ErrorInfo error = m_generator->generate(m_projects, m_parser.buildConfigurations(), m_parser.installOptions(QString()), m_parser.settingsDir(), ConsoleLogger::instance(m_settings)); if (error.hasError()) throw error; } int CommandLineFrontend::runTarget() { const ProductData productToRun = getTheOneRunnableProduct(); const QString executableFilePath = productToRun.targetExecutable(); if (executableFilePath.isEmpty()) { throw ErrorInfo(Tr::tr("Cannot run: Product '%1' is not an application.") .arg(productToRun.fullDisplayName())); } RunEnvironment runEnvironment = m_projects.front().getRunEnvironment(productToRun, m_parser.installOptions(m_projects.front().profile()), QProcessEnvironment::systemEnvironment(), m_parser.runEnvConfig(), m_settings); return runEnvironment.doRunTarget(executableFilePath, m_parser.runArgs(), m_parser.dryRun()); } void CommandLineFrontend::updateTimestamps() { const ProductMap &products = productsToUse(); for (ProductMap::ConstIterator it = products.constBegin(); it != products.constEnd(); ++it) { Project p = it.key(); p.updateTimestamps(it.value()); } } void CommandLineFrontend::dumpNodesTree() { QFile stdOut; stdOut.open(stdout, QIODevice::WriteOnly); const ErrorInfo error = m_projects.front().dumpNodesTree(stdOut, productsToUse() .value(m_projects.front())); if (error.hasError()) throw error; } void CommandLineFrontend::listProducts() { const QList products = productsToUse().constBegin().value(); QStringList output; for (const ProductData &p : products) { QString productInfo = p.fullDisplayName(); if (!p.isEnabled()) productInfo.append(QLatin1Char(' ')).append(Tr::tr("[disabled]")); else if (!p.properties().value(QStringLiteral("builtByDefault")).toBool()) productInfo.append(QLatin1Char(' ')).append(Tr::tr("[not built by default]")); output += productInfo; } output.sort(); qbsInfo() << output.join(QLatin1Char('\n')); } void CommandLineFrontend::connectBuildJobs() { for (AbstractJob * const job : std::as_const(m_buildJobs)) connectBuildJob(job); } void CommandLineFrontend::connectBuildJob(AbstractJob *job) { connectJob(job); const auto bjob = qobject_cast(job); if (!bjob) return; connect(bjob, &BuildJob::reportCommandDescription, this, &CommandLineFrontend::handleCommandDescriptionReport); connect(bjob, &BuildJob::reportProcessResult, this, &CommandLineFrontend::handleProcessResultReport); } void CommandLineFrontend::connectJob(AbstractJob *job) { connect(job, &AbstractJob::finished, this, &CommandLineFrontend::handleJobFinished); connect(job, &AbstractJob::taskStarted, this, &CommandLineFrontend::handleNewTaskStarted); connect(job, &AbstractJob::totalEffortChanged, this, &CommandLineFrontend::handleTotalEffortChanged); if (m_parser.showProgress()) { connect(job, &AbstractJob::taskProgress, this, &CommandLineFrontend::handleTaskProgress); } } ProductData CommandLineFrontend::getTheOneRunnableProduct() { QBS_CHECK(m_projects.size() == 1); // Has been checked earlier. if (m_parser.products().size() == 1) { for (const ProductData &p : m_projects.front().projectData().allProducts()) { if (p.fullDisplayName() == m_parser.products().constFirst()) return p; } QBS_CHECK(false); } QBS_CHECK(m_parser.products().isEmpty()); QList runnableProducts; for (const ProductData &p : m_projects.front().projectData().allProducts()) { if (p.isRunnable()) runnableProducts.push_back(p); } if (runnableProducts.size() == 1) return runnableProducts.front(); if (runnableProducts.empty()) { throw ErrorInfo(Tr::tr("Cannot execute command '%1': Project has no runnable product.") .arg(m_parser.commandName())); } ErrorInfo error(Tr::tr("Ambiguous use of command '%1': No product given, but project " "has more than one runnable product.").arg(m_parser.commandName())); error.append(Tr::tr("Use the '--products' option with one of the following products:")); for (const ProductData &p : std::as_const(runnableProducts)) error.append(QLatin1String("\t") + p.fullDisplayName()); throw error; } void CommandLineFrontend::install() { Q_ASSERT(m_projects.size() == 1); const Project project = m_projects.front(); InstallJob *installJob; if (m_parser.products().empty()) { const Project::ProductSelection productSelection = m_parser.withNonDefaultProducts() ? Project::ProductSelectionWithNonDefault : Project::ProductSelectionDefaultOnly; installJob = project.installAllProducts(m_parser.installOptions(project.profile()), productSelection); } else { const Project project = m_projects.front(); const ProductMap products = productsToUse(); installJob = project.installSomeProducts(products.value(project), m_parser.installOptions(project.profile())); } connectJob(installJob); } } // namespace qbs qbs-src-2.5.1/src/app/qbs/qbstool.cpp0000644000175100001660000000772314744424375017006 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "qbstool.h" #include #include #include #include #include #include static QString toolPrefix() { return QStringLiteral("qbs-"); } static QString qbsBinDir() { return QCoreApplication::applicationDirPath(); } static QString qbsToolFilePath(const QString &toolName) { return qbsBinDir() + QLatin1Char('/') + toolPrefix() + qbs::Internal::HostOsInfo::appendExecutableSuffix(toolName); } void QbsTool::runTool(const QString &toolName, const QStringList &arguments) { m_failedToStart = false; m_exitCode = -1; const QString filePath = qbsToolFilePath(toolName); const QFileInfo fi(filePath); if (!fi.exists() || !fi.isFile() || !fi.isExecutable()) { m_failedToStart = true; return; } QProcess toolProc; toolProc.start(filePath, arguments); if (!toolProc.waitForStarted()) m_failedToStart = true; toolProc.waitForFinished(-1); m_exitCode = toolProc.exitCode(); m_stdout = QString::fromLocal8Bit(toolProc.readAllStandardOutput()); m_stderr = QString::fromLocal8Bit(toolProc.readAllStandardError()); } bool QbsTool::tryToRunTool(const QString &toolName, const QStringList &arguments, int *exitCode) { QbsTool tool; tool.runTool(toolName, arguments); if (exitCode) *exitCode = tool.exitCode(); if (tool.failedToStart()) return false; std::cout << qPrintable(tool.stdOut()); std::cerr << qPrintable(tool.stdErr()); return true; } QStringList QbsTool::allToolNames() { const QString suffix = QLatin1String(QBS_HOST_EXE_SUFFIX); const QStringList toolFileNames = QDir(qbsBinDir()).entryList(QStringList(toolPrefix() + QStringLiteral("*%1").arg(suffix)), QDir::Files, QDir::Name); QStringList toolNames; const int prefixLength = toolPrefix().size(); for (const QString &toolFileName : toolFileNames) { toolNames << toolFileName.mid(prefixLength, toolFileName.size() - prefixLength - suffix.size()); } return toolNames; } qbs-src-2.5.1/src/app/qbs/parser/0000755000175100001660000000000014744424375016102 5ustar runnerdockerqbs-src-2.5.1/src/app/qbs/parser/commandlineoption.cpp0000644000175100001660000005710514744424375022335 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "commandlineoption.h" #include #include #include #include #include namespace qbs { using namespace Internal; CommandLineOption::~CommandLineOption() = default; void CommandLineOption::parse(CommandType command, const QString &representation, QStringList &input) { m_command = command; doParse(representation, input); } CommandLineOption::CommandLineOption() : m_command(static_cast(-1)) { } QString CommandLineOption::getArgument(const QString &representation, QStringList &input) { if (input.empty()) { throw ErrorInfo(Tr::tr("Invalid use of option '%1': Missing argument.\nUsage: %2") .arg(representation, description(command()))); } return input.takeFirst(); } QString FileOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1|%2 \n" "\tUse as the project file.\n" "\tIf is a directory and it contains a single file ending in '.qbs',\n" "\tthat file will be used.\n" "\tIf this option is not given at all, behavior is the same as for '-f .'.\n") .arg(longRepresentation(), shortRepresentation()); } QString FileOption::shortRepresentation() const { return QStringLiteral("-f"); } QString FileOption::longRepresentation() const { return QStringLiteral("--file"); } void FileOption::doParse(const QString &representation, QStringList &input) { m_projectFilePath = getArgument(representation, input); } QString BuildDirectoryOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1|%2 \n" "\tBuild in the given directory. The default value is the current directory\n" "\tunless preferences.defaultBuildDirectory is set.\n" "\tRelative paths will be interpreted relative to the current directory.\n" "\tIf the directory does not exist, it will be created. Use the following\n" "\tspecial values as placeholders:\n" "\t%3: name of the project file excluding the extension\n" "\t%4: directory containing the project file\n") .arg(longRepresentation(), shortRepresentation(), magicProjectString(), magicProjectDirString()); } QString BuildDirectoryOption::shortRepresentation() const { return QStringLiteral("-d"); } QString BuildDirectoryOption::longRepresentation() const { return QStringLiteral("--build-directory"); } QString BuildDirectoryOption::magicProjectString() { return QStringLiteral("@project"); } QString BuildDirectoryOption::magicProjectDirString() { return QStringLiteral("@path"); } void BuildDirectoryOption::doParse(const QString &representation, QStringList &input) { m_projectBuildDirectory = getArgument(representation, input); } QString GeneratorOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1|%2 \n" "\tUse the given build system generator.\n") .arg(longRepresentation(), shortRepresentation()); } QString GeneratorOption::shortRepresentation() const { return QStringLiteral("-g"); } QString GeneratorOption::longRepresentation() const { return QStringLiteral("--generator"); } void GeneratorOption::doParse(const QString &representation, QStringList &input) { m_generatorName = getArgument(representation, input); if (m_generatorName.isEmpty()) { throw ErrorInfo(Tr::tr("Invalid use of option '%1': No generator given.\nUsage: %2") .arg(representation, description(command()))); } } static QString loglevelLongRepresentation() { return QStringLiteral("--log-level"); } QString VerboseOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1|%2\n" "\tBe more verbose. Increases the log level by one.\n" "\tThis option can be given more than once.\n" "\tExcessive occurrences have no effect.\n" "\tIf option '%3' appears anywhere on the command line in addition\n" "\tto this option, its value is taken as the base which to increase.\n") .arg(longRepresentation(), shortRepresentation(), loglevelLongRepresentation()); } QString VerboseOption::shortRepresentation() const { return QStringLiteral("-v"); } QString VerboseOption::longRepresentation() const { return QStringLiteral("--more-verbose"); } QString QuietOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1|%2\n" "\tBe more quiet. Decreases the log level by one.\n" "\tThis option can be given more than once.\n" "\tExcessive occurrences have no effect.\n" "\tIf option '%3' appears anywhere on the command line in addition\n" "\tto this option, its value is taken as the base which to decrease.\n") .arg(longRepresentation(), shortRepresentation(), loglevelLongRepresentation()); } QString QuietOption::shortRepresentation() const { return QStringLiteral("-q"); } QString QuietOption::longRepresentation() const { return QStringLiteral("--less-verbose"); } QString JobsOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1|%2 \n" "\tUse concurrent build jobs. must be an integer greater than zero.\n" "\tThe default is the number of cores.\n") .arg(longRepresentation(), shortRepresentation()); } QString JobsOption::shortRepresentation() const { return QStringLiteral("-j"); } QString JobsOption::longRepresentation() const { return QStringLiteral("--jobs"); } void JobsOption::doParse(const QString &representation, QStringList &input) { const QString jobCountString = getArgument(representation, input); bool stringOk; m_jobCount = jobCountString.toInt(&stringOk); if (!stringOk || m_jobCount <= 0) throw ErrorInfo(Tr::tr("Invalid use of option '%1': Illegal job count '%2'.\nUsage: %3") .arg(representation, jobCountString, description(command()))); } QString KeepGoingOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1|%2\n" "\tKeep going when errors occur (if at all possible).\n") .arg(longRepresentation(), shortRepresentation()); } QString KeepGoingOption::shortRepresentation() const { return QStringLiteral("-k"); } QString KeepGoingOption::longRepresentation() const { return QStringLiteral("--keep-going"); } QString DryRunOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1|%2\n" "\tDry run. No commands will be executed and no permanent changes to the\n" "\tbuild graph will be done.\n") .arg(longRepresentation(), shortRepresentation()); } QString DryRunOption::shortRepresentation() const { return QStringLiteral("-n"); } QString DryRunOption::longRepresentation() const { return QStringLiteral("--dry-run"); } QString ForceProbesOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n" "\tForce re-execution of all Probe items' configure scripts, rather than using the\n" "\tcached data.\n") .arg(longRepresentation()); } QString ForceProbesOption::longRepresentation() const { return QStringLiteral("--force-probe-execution"); } QString NoInstallOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n" "\tDo not install any artifacts as part of the build process.\n") .arg(longRepresentation()); } QString NoInstallOption::longRepresentation() const { return QStringLiteral("--no-install"); } static QString logTimeRepresentation() { return QStringLiteral("--log-time"); } QString ShowProgressOption::description(CommandType command) const { Q_UNUSED(command); QString desc = Tr::tr("%1\n" "\tShow a progress bar. Implies '%2=%3'.\n").arg(longRepresentation(), loglevelLongRepresentation(), logLevelName(LoggerMinLevel)); return desc += Tr::tr("\tThis option is mutually exclusive with '%1'.\n") .arg(logTimeRepresentation()); } static QString showProgressRepresentation() { return QStringLiteral("--show-progress"); } QString ShowProgressOption::longRepresentation() const { return showProgressRepresentation(); } void StringListOption::doParse(const QString &representation, QStringList &input) { m_arguments = getArgument(representation, input).split(QLatin1Char(',')); if (m_arguments.empty()) { throw ErrorInfo(Tr::tr("Invalid use of option '%1': Argument list must not be empty.\n" "Usage: %2").arg(representation, description(command()))); } for (const QString &element : std::as_const(m_arguments)) { if (element.isEmpty()) { throw ErrorInfo(Tr::tr("Invalid use of option '%1': Argument list must not contain " "empty elements.\nUsage: %2") .arg(representation, description(command()))); } } } QString ChangedFilesOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1 [,...]\n" "\tAssume these and only these files have changed.\n").arg(longRepresentation()); } QString ChangedFilesOption::longRepresentation() const { return QStringLiteral("--changed-files"); } QString ProductsOption::description(CommandType command) const { const QString prefix = Tr::tr("%1|%2").arg(longRepresentation(), shortRepresentation()); switch (command) { case InstallCommandType: case RunCommandType: case ShellCommandType: return Tr::tr("%1 \n\tUse the specified product.\n").arg(prefix); default: return Tr::tr("%1 [,...]\n" "\tTake only the specified products into account.\n").arg(prefix); } } QString ProductsOption::shortRepresentation() const { return QStringLiteral("-p"); } QString ProductsOption::longRepresentation() const { return QStringLiteral("--products"); } static QStringList allLogLevelStrings() { QStringList result; for (int i = static_cast(LoggerMinLevel); i <= static_cast(LoggerMaxLevel); ++i) result << logLevelName(static_cast(i)); return result; } LogLevelOption::LogLevelOption() : m_logLevel(defaultLogLevel()) { } QString LogLevelOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1 \n" "\tUse the specified log level.\n" "\tPossible values are '%2'.\n" "\tThe default is '%3'.\n").arg(longRepresentation(), allLogLevelStrings().join(QLatin1String("', '")), logLevelName(defaultLogLevel())); } QString LogLevelOption::longRepresentation() const { return loglevelLongRepresentation(); } void LogLevelOption::doParse(const QString &representation, QStringList &input) { const QString levelString = getArgument(representation, input); const QList levels = QList() << LoggerError << LoggerWarning << LoggerInfo << LoggerDebug << LoggerTrace; for (const LoggerLevel &l : levels) { if (logLevelName(l) == levelString) { m_logLevel = l; return; } } throw ErrorInfo(Tr::tr("Invalid use of option '%1': Unknown log level '%2'.\nUsage: %3") .arg(representation, levelString, description(command()))); } QString ForceTimeStampCheckOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n\tForce timestamp checks.\n" "\tInstead of using the file timestamps that are stored in the build graph,\n" "\tretrieve the timestamps from the file system.\n").arg(longRepresentation()); } QString ForceTimeStampCheckOption::longRepresentation() const { return QStringLiteral("--check-timestamps"); } QString ForceOutputCheckOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n\tForce transformer output artifact checks.\n" "\tVerify that the output artifacts declared by rules in the\n" "\tproject are actually created.\n").arg(longRepresentation()); } QString ForceOutputCheckOption::longRepresentation() const { return QStringLiteral("--check-outputs"); } QString BuildNonDefaultOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n\tBuild all products, even if their builtByDefault property is false.\n") .arg(longRepresentation()); } QString BuildNonDefaultOption::longRepresentation() const { return QStringLiteral("--all-products"); } InstallRootOption::InstallRootOption() : m_useSysroot(false) { } static QString magicSysrootString() { return QStringLiteral("@sysroot"); } QString InstallRootOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1 \n" "\tInstall into the given directory.\n" "\tThe default value is '/%2'.\n" "\tIf the directory does not exist, it will be created. Use the special\n" "\tvalue '%3' to install into the sysroot (i.e. the value of the\n" "\tproperty qbs.sysroot).\n") .arg(longRepresentation(), InstallOptions::defaultInstallRoot(), magicSysrootString()); } QString InstallRootOption::longRepresentation() const { return QStringLiteral("--install-root"); } void InstallRootOption::doParse(const QString &representation, QStringList &input) { if (input.empty()) { throw ErrorInfo(Tr::tr("Invalid use of option '%1: Argument expected.\n" "Usage: %2").arg(representation, description(command()))); } const QString installRoot = input.takeFirst(); if (installRoot == magicSysrootString()) m_useSysroot = true; else m_installRoot = installRoot; } QString RemoveFirstOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n\tRemove the installation base directory before installing.\n") .arg(longRepresentation()); } QString RemoveFirstOption::longRepresentation() const { return QStringLiteral("--clean-install-root"); } QString NoBuildOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n\tDo not build before installing.\n") .arg(longRepresentation()); } QString NoBuildOption::longRepresentation() const { return QStringLiteral("--no-build"); } QString LogTimeOption::description(CommandType command) const { Q_UNUSED(command); QString desc = Tr::tr("%1\n\tLog the time that the operations involved in this command take.\n") .arg(longRepresentation()); desc += Tr::tr("\tThis option is implied in log levels '%1' and higher.\n") .arg(logLevelName(LoggerDebug)); return desc += Tr::tr("\tThis option is mutually exclusive with '%1'.\n") .arg(showProgressRepresentation()); } QString LogTimeOption::shortRepresentation() const { return QStringLiteral("-t"); } QString LogTimeOption::longRepresentation() const { return logTimeRepresentation(); } SettingsDirOption::SettingsDirOption() = default; QString SettingsDirOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1 \n" "\tRead all settings (such as profile information) from the given directory.\n" "\tThe default value is system-specific (see the QSettings documentation).\n" "\tIf the directory does not exist, it will be created.\n") .arg(longRepresentation()); } QString SettingsDirOption::longRepresentation() const { return QStringLiteral("--settings-dir"); } void SettingsDirOption::doParse(const QString &representation, QStringList &input) { if (input.empty()) { throw ErrorInfo(Tr::tr("Invalid use of option '%1: Argument expected.\n" "Usage: %2").arg(representation, description(command()))); } m_settingsDir = input.takeFirst(); } QString JobLimitsOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1 :[,:...]\n" "\tSet pool-specific job limits.\n").arg(longRepresentation()); } QString JobLimitsOption::longRepresentation() const { return QStringLiteral("--job-limits"); } void JobLimitsOption::doParse(const QString &representation, QStringList &input) { if (input.empty()) { throw ErrorInfo(Tr::tr("Invalid use of option '%1: Argument expected.\n" "Usage: %2").arg(representation, description(command()))); } const QString jobLimitsSpec = input.takeFirst(); const QStringList jobLimitStrings = jobLimitsSpec.split(QLatin1Char(',')); for (const QString &jobLimitString : jobLimitStrings) { const int sepIndex = jobLimitString.indexOf(QLatin1Char(':')); if (sepIndex <= 0 || sepIndex == jobLimitString.size() - 1) { throw ErrorInfo(Tr::tr("Invalid use of option '%1: " "Invalid job limits specification '%2'.\n" "Usage: %3").arg(representation, jobLimitsSpec, description(command()))); } const QString pool = jobLimitString.left(sepIndex); const QString limitString = jobLimitString.mid(sepIndex + 1); bool isValidNumber; const int limit = limitString.toInt(&isValidNumber); if (!isValidNumber) { throw ErrorInfo(Tr::tr("Invalid use of option '%1: '%2' is not a number.\n" "Usage: %3").arg(representation, limitString, description(command()))); } m_jobLimits.setJobLimit(pool, limit); } } QString RespectProjectJobLimitsOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n\tGive maximum priority to job limits defined inside the project.\n") .arg(longRepresentation()); } QString RespectProjectJobLimitsOption::longRepresentation() const { return QStringLiteral("--enforce-project-job-limits"); } CommandEchoModeOption::CommandEchoModeOption() = default; QString CommandEchoModeOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1 \n" "\tKind of output to show when executing commands.\n" "\tPossible values are '%2'.\n" "\tThe default is '%3'.\n") .arg(longRepresentation(), allCommandEchoModeStrings().join(QLatin1String("', '")), commandEchoModeName(defaultCommandEchoMode())); } QString CommandEchoModeOption::longRepresentation() const { return QStringLiteral("--command-echo-mode"); } CommandEchoMode CommandEchoModeOption::commandEchoMode() const { return m_echoMode; } void CommandEchoModeOption::doParse(const QString &representation, QStringList &input) { const QString mode = getArgument(representation, input); if (mode.isEmpty()) { throw ErrorInfo(Tr::tr("Invalid use of option '%1': No command echo mode given.\nUsage: %2") .arg(representation, description(command()))); } if (!allCommandEchoModeStrings().contains(mode)) { throw ErrorInfo(Tr::tr("Invalid use of option '%1': " "Invalid command echo mode '%2' given.\nUsage: %3") .arg(representation, mode, description(command()))); } m_echoMode = commandEchoModeFromName(mode); } QString DeprecationWarningsOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1 \n" "\tWhat to do when encountering deprecated items or properties.\n" "\tPossible values are '%2'.\n" "\tThe default is '%3'.\n") .arg(longRepresentation(), allDeprecationWarningModeStrings().join(QLatin1String("', '")), deprecationWarningModeName(defaultDeprecationWarningMode())); } QString DeprecationWarningsOption::longRepresentation() const { return QStringLiteral("--deprecation-warnings"); } void DeprecationWarningsOption::doParse(const QString &representation, QStringList &input) { const QString mode = getArgument(representation, input); if (mode.isEmpty()) { throw ErrorInfo(Tr::tr("Invalid use of option '%1': No deprecation warning mode given.\n" "Usage: %2") .arg(representation, description(command()))); } if (!allDeprecationWarningModeStrings().contains(mode)) { throw ErrorInfo(Tr::tr("Invalid use of option '%1': " "Invalid deprecation warning mode '%2' given.\nUsage: %3") .arg(representation, mode, description(command()))); } m_mode = deprecationWarningModeFromName(mode); } QString WaitLockOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n\tWait indefinitely for other processes to release the build graph lock.\n") .arg(longRepresentation()); } QString WaitLockOption::longRepresentation() const { return QStringLiteral("--wait-lock"); } QString RunEnvConfigOption::description(CommandType command) const { Q_UNUSED(command); return Tr::tr("%1\n\tComma-separated list of strings to pass to all modules' " "setupRunEnvironment scripts.\n").arg(longRepresentation()); } QString RunEnvConfigOption::longRepresentation() const { return QStringLiteral("--setup-run-env-config"); } } // namespace qbs qbs-src-2.5.1/src/app/qbs/parser/parsercommand.cpp0000644000175100001660000005073514744424375021453 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "parsercommand.h" #include "commandlineoption.h" #include "commandlineoptionpool.h" #include #include #include #include #include #include #include namespace qbs { using namespace Internal; Command::~Command() = default; void Command::parse(QStringList &input) { while (!input.empty()) parseNext(input); } bool Command::canResolve() const { return supportedOptions().contains(CommandLineOption::FileOptionType); } void Command::parsePropertyAssignment(const QString &argument) { const auto throwError = [argument](const QString &msgTemplate) { ErrorInfo error(msgTemplate.arg(argument)); error.append(QLatin1String("Expected an assignment of the form :, " "profile: or config:.")); throw error; }; if (argument.startsWith(QLatin1Char('-'))) throwError(Tr::tr("Unexpected option '%1'.")); const int sepPos = argument.indexOf(QLatin1Char(':')); if (sepPos == -1) throwError(Tr::tr("Unexpected command line parameter '%1'.")); if (sepPos == 0) throwError(Tr::tr("Empty key not allowed in assignment '%1'.")); if (!canResolve() && argument.contains(QLatin1Char(':')) && !argument.startsWith(QLatin1String("config:"))) { throw ErrorInfo(Tr::tr("The '%1' command does not support property assignments.") .arg(representation())); } m_additionalArguments << argument; } QList Command::actualSupportedOptions() const { QList options = supportedOptions(); if (type() != HelpCommandType) options.push_back(CommandLineOption::SettingsDirOptionType); // Valid for almost all commands. return options; } void Command::parseOption(QStringList &input) { const QString optionString = input.front(); QBS_CHECK(optionString.startsWith(QLatin1Char('-'))); input.removeFirst(); if (optionString.size() == 1) throwError(Tr::tr("Empty options are not allowed.")); // Split up grouped short options. if (optionString.at(1) != QLatin1Char('-') && optionString.size() > 2) { QString parameter; for (int i = optionString.size(); --i > 0;) { const QChar c = optionString.at(i); if (c.isDigit()) { parameter.prepend(c); } else { if (!parameter.isEmpty()) { input.prepend(parameter); parameter.clear(); } input.prepend(QLatin1Char('-') + c); } } if (!parameter.isEmpty()) throwError(Tr::tr("Unknown numeric option '%1'.").arg(parameter)); return; } bool matchFound = false; const auto optionTypes = actualSupportedOptions(); for (const CommandLineOption::Type optionType : optionTypes) { CommandLineOption * const option = optionPool().getOption(optionType); if (option->shortRepresentation() != optionString && option->longRepresentation() != optionString) { continue; } if (contains(m_usedOptions, option) && !option->canAppearMoreThanOnce()) throwError(Tr::tr("Option '%1' cannot appear more than once.").arg(optionString)); option->parse(type(), optionString, input); m_usedOptions.insert(option); matchFound = true; break; } if (!matchFound) throwError(Tr::tr("Unknown option '%1'.").arg(optionString)); } void Command::parseNext(QStringList &input) { QBS_CHECK(!input.empty()); if (input.front().startsWith(QLatin1Char('-'))) parseOption(input); else parsePropertyAssignment(input.takeFirst()); } QString Command::supportedOptionsDescription() const { // Sorting the options by name is nicer for the user. QMap optionMap; const auto opTypes = actualSupportedOptions(); for (const CommandLineOption::Type opType : opTypes) { const CommandLineOption * const option = optionPool().getOption(opType); optionMap.insert(option->longRepresentation(), option); } QString s = Tr::tr("The possible options are:\n"); for (const CommandLineOption *option : std::as_const(optionMap)) s += option->description(type()); return s; } void Command::throwError(const QString &reason) { ErrorInfo error(Tr::tr("Invalid use of command '%1': %2").arg(representation(), reason)); error.append(Tr::tr("Type 'qbs help %1' to see how to use this command.") .arg(representation())); throw error; } QString ResolveCommand::shortDescription() const { return Tr::tr("Resolve a project without building it."); } QString ResolveCommand::longDescription() const { QString description = Tr::tr( "qbs %1 [options] [[config:] [:] ...] ...\n") .arg(representation()); description += Tr::tr("Resolves a project in one or more configuration(s).\n"); return description += supportedOptionsDescription(); } QString ResolveCommand::representation() const { return QStringLiteral("resolve"); } static QList resolveOptions() { return { CommandLineOption::FileOptionType, CommandLineOption::BuildDirectoryOptionType, CommandLineOption::LogLevelOptionType, CommandLineOption::VerboseOptionType, CommandLineOption::QuietOptionType, CommandLineOption::ShowProgressOptionType, CommandLineOption::DryRunOptionType, CommandLineOption::ForceProbesOptionType, CommandLineOption::LogTimeOptionType, CommandLineOption::DeprecationWarningsOptionType, CommandLineOption::JobsOptionType}; } QList ResolveCommand::supportedOptions() const { return resolveOptions(); } QString GenerateCommand::shortDescription() const { return Tr::tr("Generate project files for another build tool."); } QString GenerateCommand::longDescription() const { QString description = Tr::tr( "qbs %1 [options] [[config:] [:] ...] ...\n") .arg(representation()); description += Tr::tr("Generates files to build the project using another build tool.\n"); return description += supportedOptionsDescription(); } QString GenerateCommand::representation() const { return QStringLiteral("generate"); } QList GenerateCommand::supportedOptions() const { return {CommandLineOption::FileOptionType, CommandLineOption::BuildDirectoryOptionType, CommandLineOption::LogLevelOptionType, CommandLineOption::VerboseOptionType, CommandLineOption::QuietOptionType, CommandLineOption::ShowProgressOptionType, CommandLineOption::InstallRootOptionType, CommandLineOption::LogTimeOptionType, CommandLineOption::GeneratorOptionType}; } QString BuildCommand::shortDescription() const { return Tr::tr("Build (parts of) a project. This is the default command."); } QString BuildCommand::longDescription() const { QString description = Tr::tr( "qbs %1 [options] [[config:] [:] ...] ...\n") .arg(representation()); description += Tr::tr("Builds a project in one or more configuration(s).\n"); return description += supportedOptionsDescription(); } static QString buildCommandRepresentation() { return QStringLiteral("build"); } QString BuildCommand::representation() const { return buildCommandRepresentation(); } static QList buildOptions() { QList options = resolveOptions(); return options << CommandLineOption::KeepGoingOptionType << CommandLineOption::ProductsOptionType << CommandLineOption::ChangedFilesOptionType << CommandLineOption::ForceTimestampCheckOptionType << CommandLineOption::ForceOutputCheckOptionType << CommandLineOption::BuildNonDefaultOptionType << CommandLineOption::CommandEchoModeOptionType << CommandLineOption::NoInstallOptionType << CommandLineOption::RemoveFirstOptionType << CommandLineOption::JobLimitsOptionType << CommandLineOption::RespectProjectJobLimitsOptionType << CommandLineOption::WaitLockOptionType; } QList BuildCommand::supportedOptions() const { return buildOptions(); } QString CleanCommand::shortDescription() const { return Tr::tr("Remove the files generated during a build."); } QString CleanCommand::longDescription() const { QString description = Tr::tr( "qbs %1 [options] [config:] ...\n") .arg(representation()); description += Tr::tr("Removes build artifacts for the given configuration(s).\n"); return description += supportedOptionsDescription(); } QString CleanCommand::representation() const { return QStringLiteral("clean"); } QList CleanCommand::supportedOptions() const { return {CommandLineOption::BuildDirectoryOptionType, CommandLineOption::DryRunOptionType, CommandLineOption::KeepGoingOptionType, CommandLineOption::LogTimeOptionType, CommandLineOption::ProductsOptionType, CommandLineOption::QuietOptionType, CommandLineOption::SettingsDirOptionType, CommandLineOption::ShowProgressOptionType, CommandLineOption::VerboseOptionType}; } QString InstallCommand::shortDescription() const { return Tr::tr("Install (parts of) a project."); } QString InstallCommand::longDescription() const { QString description = Tr::tr( "qbs %1 [options] [[config:] [:] ...]\n") .arg(representation()); description += Tr::tr("Install all files marked as installable " "to their respective destinations.\n" "The project is built first, if necessary, unless the '%1' option " "is given.\n").arg(optionPool().noBuildOption()->longRepresentation()); return description += supportedOptionsDescription(); } QString InstallCommand::representation() const { return QStringLiteral("install"); } QList installOptions() { QList options = buildOptions() << CommandLineOption::InstallRootOptionType << CommandLineOption::NoBuildOptionType; options.removeOne(CommandLineOption::NoInstallOptionType); return options; } QList InstallCommand::supportedOptions() const { return installOptions(); } QString RunCommand::shortDescription() const { return QStringLiteral("Run an executable generated by building a project."); } QString RunCommand::longDescription() const { QString description = Tr::tr( "qbs %1 [options] [config:] [:] ... " "[ -- ]\n").arg(representation()); description += Tr::tr("Run the specified product's executable with the specified arguments.\n"); description += Tr::tr("If the project has only one product, the '%1' option may be omitted.\n") .arg(optionPool().productsOption()->longRepresentation()); description += Tr::tr("The product will be built if it is not up to date; " "see the '%2' command.\n").arg(buildCommandRepresentation()); return description += supportedOptionsDescription(); } QString RunCommand::representation() const { return QStringLiteral("run"); } QList RunCommand::supportedOptions() const { return QList() << installOptions() << CommandLineOption::RunEnvConfigOptionType; } void RunCommand::parseNext(QStringList &input) { QBS_CHECK(!input.empty()); if (input.front() != QLatin1String("--")) { Command::parseNext(input); return; } input.removeFirst(); m_targetParameters = input; input.clear(); } QString ShellCommand::shortDescription() const { return Tr::tr("Open a shell with a product's environment."); } QString ShellCommand::longDescription() const { QString description = Tr::tr( "qbs %1 [options] [config:] [:] ...\n") .arg(representation()); description += Tr::tr("Opens a shell in the same environment that a build with the given " "parameters would use.\n"); return description += supportedOptionsDescription(); } QString ShellCommand::representation() const { return QStringLiteral("shell"); } QList ShellCommand::supportedOptions() const { return {CommandLineOption::FileOptionType, CommandLineOption::BuildDirectoryOptionType, CommandLineOption::ProductsOptionType}; } QString StatusCommand::shortDescription() const { return Tr::tr("Show the status of files in the project directory."); } QString StatusCommand::longDescription() const { QString description = Tr::tr("qbs %1 [options] [config:]\n") .arg(representation()); description += Tr::tr("Lists all the files in the project directory and shows whether " "they are known to qbs in the respective configuration.\n"); return description += supportedOptionsDescription(); } QString StatusCommand::representation() const { return QStringLiteral("status"); } QList StatusCommand::supportedOptions() const { return {CommandLineOption::BuildDirectoryOptionType}; } QString UpdateTimestampsCommand::shortDescription() const { return Tr::tr("Mark the build as up to date."); } QString UpdateTimestampsCommand::longDescription() const { QString description = Tr::tr( "qbs %1 [options] [config:] ...\n") .arg(representation()); description += Tr::tr("Update the timestamps of all build artifacts, causing the next " "builds of the project to do nothing if no updates to source files happen in between.\n" "This functionality is useful if you know that the current changes to source files " "are irrelevant to the build.\n" "NOTE: Doing this causes a discrepancy between the \"real world\" and the information " "in the build graph, so use with care.\n"); return description += supportedOptionsDescription(); } QString UpdateTimestampsCommand::representation() const { return QStringLiteral("update-timestamps"); } QList UpdateTimestampsCommand::supportedOptions() const { return {CommandLineOption::BuildDirectoryOptionType, CommandLineOption::LogLevelOptionType, CommandLineOption::VerboseOptionType, CommandLineOption::QuietOptionType, CommandLineOption::ProductsOptionType}; } QString DumpNodesTreeCommand::shortDescription() const { return Tr::tr("Dumps the nodes in the build graph to stdout."); } QString DumpNodesTreeCommand::longDescription() const { QString description = Tr::tr("qbs %1 [options] [config:] ...\n") .arg(representation()); description += Tr::tr("Internal command; for debugging purposes only.\n"); return description += supportedOptionsDescription(); } QString DumpNodesTreeCommand::representation() const { return QStringLiteral("dump-nodes-tree"); } QList DumpNodesTreeCommand::supportedOptions() const { return {CommandLineOption::BuildDirectoryOptionType, CommandLineOption::ProductsOptionType}; } QString ListProductsCommand::shortDescription() const { return Tr::tr("Lists all products in the project, including sub-projects."); } QString ListProductsCommand::longDescription() const { QString description = Tr::tr("qbs %1 [options] [[config:] " "[:] ...] ...\n").arg(representation()); return description += supportedOptionsDescription(); } QString ListProductsCommand::representation() const { return QStringLiteral("list-products"); } QList ListProductsCommand::supportedOptions() const { return {CommandLineOption::FileOptionType, CommandLineOption::BuildDirectoryOptionType}; } QString HelpCommand::shortDescription() const { return Tr::tr("Show general or command-specific help."); } QString HelpCommand::longDescription() const { QString description = Tr::tr("qbs %1 []\n").arg(representation()); return description += Tr::tr("Shows either the general help or a description of " "the given command.\n"); } QString HelpCommand::representation() const { return QStringLiteral("help"); } QList HelpCommand::supportedOptions() const { return {}; } void HelpCommand::parseNext(QStringList &input) { if (input.empty()) return; if (input.size() > 1) throwError(Tr::tr("Cannot describe more than one command.")); m_command = input.takeFirst(); QBS_CHECK(input.empty()); } QString VersionCommand::shortDescription() const { return Tr::tr("Print the Qbs version number to stdout."); } QString VersionCommand::longDescription() const { QString description = Tr::tr("qbs %1\n").arg(representation()); return description += Tr::tr("%1\n").arg(shortDescription()); } QString VersionCommand::representation() const { return QStringLiteral("show-version"); } QList VersionCommand::supportedOptions() const { return {}; } void VersionCommand::parseNext(QStringList &input) { QBS_CHECK(!input.empty()); throwError(Tr::tr("This command takes no arguments.")); } QString SessionCommand::shortDescription() const { return Tr::tr("Starts a session for an IDE."); } QString SessionCommand::longDescription() const { QString description = Tr::tr("qbs %1\n").arg(representation()); return description += Tr::tr("Communicates on stdin and stdout via a JSON-based API.\n" "Intended for use with other tools, such as IDEs.\n"); } QString SessionCommand::representation() const { return QLatin1String("session"); } void SessionCommand::parseNext(QStringList &input) { QBS_CHECK(!input.empty()); throwError(Tr::tr("This command takes no arguments.")); } } // namespace qbs qbs-src-2.5.1/src/app/qbs/parser/commandpool.cpp0000644000175100001660000000740714744424375021126 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "commandpool.h" #include "parsercommand.h" namespace qbs { CommandPool::CommandPool(CommandLineOptionPool &optionPool) : m_optionPool(optionPool) { } CommandPool::~CommandPool() { qDeleteAll(m_commands); } qbs::Command *CommandPool::getCommand(CommandType type) const { Command *& command = m_commands[type]; if (!command) { switch (type) { case ResolveCommandType: command = new ResolveCommand(m_optionPool); break; case GenerateCommandType: command = new GenerateCommand(m_optionPool); break; case BuildCommandType: command = new BuildCommand(m_optionPool); break; case CleanCommandType: command = new CleanCommand(m_optionPool); break; case RunCommandType: command = new RunCommand(m_optionPool); break; case ShellCommandType: command = new ShellCommand(m_optionPool); break; case StatusCommandType: command = new StatusCommand(m_optionPool); break; case UpdateTimestampsCommandType: command = new UpdateTimestampsCommand(m_optionPool); break; case InstallCommandType: command = new InstallCommand(m_optionPool); break; case DumpNodesTreeCommandType: command = new DumpNodesTreeCommand(m_optionPool); break; case ListProductsCommandType: command = new ListProductsCommand(m_optionPool); break; case HelpCommandType: command = new HelpCommand(m_optionPool); break; case VersionCommandType: command = new VersionCommand(m_optionPool); break; case SessionCommandType: command = new SessionCommand(m_optionPool); break; } } return command; } } // namespace qbs qbs-src-2.5.1/src/app/qbs/parser/commandtype.h0000644000175100001660000000442014744424375020573 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef COMMANDTYPE_H #define COMMANDTYPE_H namespace qbs { enum CommandType { ResolveCommandType, BuildCommandType, CleanCommandType, RunCommandType, ShellCommandType, StatusCommandType, UpdateTimestampsCommandType, DumpNodesTreeCommandType, InstallCommandType, HelpCommandType, GenerateCommandType, ListProductsCommandType, VersionCommandType, SessionCommandType, }; } // namespace qbs #endif // COMMANDTYPE_H qbs-src-2.5.1/src/app/qbs/parser/commandlineparser.h0000644000175100001660000000713014744424375021757 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_COMMANDLINEPARSER_H #define QBS_COMMANDLINEPARSER_H #include "commandtype.h" #include #include #include #include namespace qbs { class BuildOptions; class CleanOptions; class GenerateOptions; class InstallOptions; class Settings; class CommandLineParser { Q_DISABLE_COPY(CommandLineParser) public: CommandLineParser(); ~CommandLineParser(); bool parseCommandLine(const QStringList &args); void printHelp() const; CommandType command() const; QString commandName() const; bool commandCanResolve() const; QString commandDescription() const; QString projectFilePath() const; QString projectBuildDirectory() const; BuildOptions buildOptions(const QString &profile) const; CleanOptions cleanOptions(const QString &profile) const; GenerateOptions generateOptions() const; InstallOptions installOptions(const QString &profile) const; int jobCount(const QString &profile) const; bool forceTimestampCheck() const; bool forceOutputCheck() const; bool dryRun() const; bool forceProbesExecution() const; bool waitLockBuildGraph() const; bool logTime() const; bool withNonDefaultProducts() const; bool buildBeforeInstalling() const; QStringList runArgs() const; QStringList products() const; QStringList runEnvConfig() const; QList buildConfigurations() const; bool showProgress() const; bool showVersion() const; QString settingsDir() const; DeprecationWarningMode deprecationWarningMode() const; private: class CommandLineParserPrivate; std::unique_ptr d; }; } // namespace qbs #endif // QBS_COMMANDLINEPARSER_H qbs-src-2.5.1/src/app/qbs/parser/commandlineoptionpool.cpp0000644000175100001660000002435714744424375023232 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "commandlineoptionpool.h" namespace qbs { CommandLineOptionPool::~CommandLineOptionPool() { qDeleteAll(m_options); } CommandLineOption *CommandLineOptionPool::getOption(CommandLineOption::Type type) const { CommandLineOption *& option = m_options[type]; if (!option) { switch (type) { case CommandLineOption::FileOptionType: option = new FileOption; break; case CommandLineOption::BuildDirectoryOptionType: option = new BuildDirectoryOption; break; case CommandLineOption::LogLevelOptionType: option = new LogLevelOption; break; case CommandLineOption::VerboseOptionType: option = new VerboseOption; break; case CommandLineOption::QuietOptionType: option = new QuietOption; break; case CommandLineOption::JobsOptionType: option = new JobsOption; break; case CommandLineOption::KeepGoingOptionType: option = new KeepGoingOption; break; case CommandLineOption::DryRunOptionType: option = new DryRunOption; break; case CommandLineOption::ForceProbesOptionType: option = new ForceProbesOption; break; case CommandLineOption::ShowProgressOptionType: option = new ShowProgressOption; break; case CommandLineOption::ChangedFilesOptionType: option = new ChangedFilesOption; break; case CommandLineOption::ProductsOptionType: option = new ProductsOption; break; case CommandLineOption::NoInstallOptionType: option = new NoInstallOption; break; case CommandLineOption::InstallRootOptionType: option = new InstallRootOption; break; case CommandLineOption::RemoveFirstOptionType: option = new RemoveFirstOption; break; case CommandLineOption::NoBuildOptionType: option = new NoBuildOption; break; case CommandLineOption::ForceTimestampCheckOptionType: option = new ForceTimeStampCheckOption; break; case CommandLineOption::ForceOutputCheckOptionType: option = new ForceOutputCheckOption; break; case CommandLineOption::BuildNonDefaultOptionType: option = new BuildNonDefaultOption; break; case CommandLineOption::LogTimeOptionType: option = new LogTimeOption; break; case CommandLineOption::CommandEchoModeOptionType: option = new CommandEchoModeOption; break; case CommandLineOption::SettingsDirOptionType: option = new SettingsDirOption; break; case CommandLineOption::JobLimitsOptionType: option = new JobLimitsOption; break; case CommandLineOption::RespectProjectJobLimitsOptionType: option = new RespectProjectJobLimitsOption; break; case CommandLineOption::GeneratorOptionType: option = new GeneratorOption; break; case CommandLineOption::WaitLockOptionType: option = new WaitLockOption; break; case CommandLineOption::RunEnvConfigOptionType: option = new RunEnvConfigOption; break; case CommandLineOption::DeprecationWarningsOptionType: option = new DeprecationWarningsOption; break; default: qFatal("Unknown option type %d", type); } } return option; } FileOption *CommandLineOptionPool::fileOption() const { return static_cast(getOption(CommandLineOption::FileOptionType)); } BuildDirectoryOption *CommandLineOptionPool::buildDirectoryOption() const { return static_cast(getOption(CommandLineOption::BuildDirectoryOptionType)); } LogLevelOption *CommandLineOptionPool::logLevelOption() const { return static_cast(getOption(CommandLineOption::LogLevelOptionType)); } VerboseOption *CommandLineOptionPool::verboseOption() const { return static_cast(getOption(CommandLineOption::VerboseOptionType)); } QuietOption *CommandLineOptionPool::quietOption() const { return static_cast(getOption(CommandLineOption::QuietOptionType)); } ShowProgressOption *CommandLineOptionPool::showProgressOption() const { return static_cast(getOption(CommandLineOption::ShowProgressOptionType)); } DryRunOption *CommandLineOptionPool::dryRunOption() const { return static_cast(getOption(CommandLineOption::DryRunOptionType)); } ForceProbesOption *CommandLineOptionPool::forceProbesOption() const { return static_cast(getOption(CommandLineOption::ForceProbesOptionType)); } ChangedFilesOption *CommandLineOptionPool::changedFilesOption() const { return static_cast(getOption(CommandLineOption::ChangedFilesOptionType)); } KeepGoingOption *CommandLineOptionPool::keepGoingOption() const { return static_cast(getOption(CommandLineOption::KeepGoingOptionType)); } JobsOption *CommandLineOptionPool::jobsOption() const { return static_cast(getOption(CommandLineOption::JobsOptionType)); } ProductsOption *CommandLineOptionPool::productsOption() const { return static_cast(getOption(CommandLineOption::ProductsOptionType)); } NoInstallOption *CommandLineOptionPool::noInstallOption() const { return static_cast(getOption(CommandLineOption::NoInstallOptionType)); } InstallRootOption *CommandLineOptionPool::installRootOption() const { return static_cast(getOption(CommandLineOption::InstallRootOptionType)); } RemoveFirstOption *CommandLineOptionPool::removeFirstoption() const { return static_cast(getOption(CommandLineOption::RemoveFirstOptionType)); } NoBuildOption *CommandLineOptionPool::noBuildOption() const { return static_cast(getOption(CommandLineOption::NoBuildOptionType)); } ForceTimeStampCheckOption *CommandLineOptionPool::forceTimestampCheckOption() const { return static_cast( getOption(CommandLineOption::ForceTimestampCheckOptionType)); } ForceOutputCheckOption *CommandLineOptionPool::forceOutputCheckOption() const { return static_cast( getOption(CommandLineOption::ForceOutputCheckOptionType)); } BuildNonDefaultOption *CommandLineOptionPool::buildNonDefaultOption() const { return static_cast( getOption(CommandLineOption::BuildNonDefaultOptionType)); } LogTimeOption *CommandLineOptionPool::logTimeOption() const { return static_cast(getOption(CommandLineOption::LogTimeOptionType)); } CommandEchoModeOption *CommandLineOptionPool::commandEchoModeOption() const { return static_cast( getOption(CommandLineOption::CommandEchoModeOptionType)); } SettingsDirOption *CommandLineOptionPool::settingsDirOption() const { return static_cast(getOption(CommandLineOption::SettingsDirOptionType)); } JobLimitsOption *CommandLineOptionPool::jobLimitsOption() const { return static_cast(getOption(CommandLineOption::JobLimitsOptionType)); } RespectProjectJobLimitsOption *CommandLineOptionPool::respectProjectJobLimitsOption() const { return static_cast( getOption(CommandLineOption::RespectProjectJobLimitsOptionType)); } GeneratorOption *CommandLineOptionPool::generatorOption() const { return static_cast(getOption(CommandLineOption::GeneratorOptionType)); } WaitLockOption *CommandLineOptionPool::waitLockOption() const { return static_cast(getOption(CommandLineOption::WaitLockOptionType)); } RunEnvConfigOption *CommandLineOptionPool::runEnvConfigOption() const { return static_cast(getOption(CommandLineOption::RunEnvConfigOptionType)); } DeprecationWarningsOption *CommandLineOptionPool::deprecationWarningsOption() const { return static_cast (getOption(CommandLineOption::DeprecationWarningsOptionType)); } } // namespace qbs qbs-src-2.5.1/src/app/qbs/parser/commandlineoption.h0000644000175100001660000003145314744424375022000 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_COMMANDLINEOPTION_H #define QBS_COMMANDLINEOPTION_H #include "commandtype.h" #include #include #include #include namespace qbs { class CommandLineOption { public: enum Type { FileOptionType, BuildDirectoryOptionType, LogLevelOptionType, VerboseOptionType, QuietOptionType, JobsOptionType, KeepGoingOptionType, DryRunOptionType, ForceProbesOptionType, ShowProgressOptionType, ChangedFilesOptionType, ProductsOptionType, NoInstallOptionType, InstallRootOptionType, RemoveFirstOptionType, NoBuildOptionType, ForceTimestampCheckOptionType, ForceOutputCheckOptionType, BuildNonDefaultOptionType, LogTimeOptionType, CommandEchoModeOptionType, SettingsDirOptionType, JobLimitsOptionType, RespectProjectJobLimitsOptionType, GeneratorOptionType, WaitLockOptionType, RunEnvConfigOptionType, DeprecationWarningsOptionType, }; virtual ~CommandLineOption(); virtual QString description(CommandType command) const = 0; virtual QString shortRepresentation() const = 0; virtual QString longRepresentation() const = 0; virtual bool canAppearMoreThanOnce() const { return false; } void parse(CommandType command, const QString &representation, QStringList &input); protected: CommandLineOption(); QString getArgument(const QString &representation, QStringList &input); CommandType command() const { return m_command; } private: virtual void doParse(const QString &representation, QStringList &input) = 0; CommandType m_command; }; class FileOption : public CommandLineOption { public: QString projectFilePath() const { return m_projectFilePath; } private: QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; void doParse(const QString &representation, QStringList &input) override; private: QString m_projectFilePath; }; class BuildDirectoryOption : public CommandLineOption { public: QString projectBuildDirectory() const { return m_projectBuildDirectory; } static QString magicProjectString(); static QString magicProjectDirString(); private: QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; void doParse(const QString &representation, QStringList &input) override; private: QString m_projectBuildDirectory; }; class GeneratorOption : public CommandLineOption { public: QString generatorName() const { return m_generatorName; } private: QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; void doParse(const QString &representation, QStringList &input) override; private: QString m_generatorName; }; class CountingOption : public CommandLineOption { public: int count() const { return m_count; } protected: CountingOption() : m_count(0) {} private: bool canAppearMoreThanOnce() const override{ return true; } void doParse(const QString &, QStringList &) override { ++m_count; } int m_count; }; class VerboseOption : public CountingOption { QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; }; class QuietOption : public CountingOption { QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; }; class JobsOption : public CommandLineOption { public: JobsOption() : m_jobCount(0) {} int jobCount() const { return m_jobCount; } private: QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; void doParse(const QString &representation, QStringList &input) override; int m_jobCount; }; class OnOffOption : public CommandLineOption { public: bool enabled() const { return m_enabled; } protected: OnOffOption() : m_enabled(false) {} private: void doParse(const QString &, QStringList &) override { m_enabled = true; } bool m_enabled; }; class KeepGoingOption : public OnOffOption { QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; }; class DryRunOption : public OnOffOption { QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; }; class ForceProbesOption : public OnOffOption { QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class NoInstallOption : public OnOffOption { QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class ShowProgressOption : public OnOffOption { public: QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class ForceTimeStampCheckOption : public OnOffOption { QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class ForceOutputCheckOption : public OnOffOption { QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class BuildNonDefaultOption : public OnOffOption { QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class StringListOption : public CommandLineOption { public: QStringList arguments() const { return m_arguments; } private: void doParse(const QString &representation, QStringList &input) override; QStringList m_arguments; }; class ChangedFilesOption : public StringListOption { QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class ProductsOption : public StringListOption { public: QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; }; class RunEnvConfigOption : public StringListOption { QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class LogLevelOption : public CommandLineOption { public: LogLevelOption(); int logLevel() const { return m_logLevel; } private: QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; void doParse(const QString &representation, QStringList &input) override; int m_logLevel; }; class InstallRootOption : public CommandLineOption { public: InstallRootOption(); QString installRoot() const { return m_installRoot; } bool useSysroot() const { return m_useSysroot; } QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; private: void doParse(const QString &representation, QStringList &input) override; QString m_installRoot; bool m_useSysroot; }; class RemoveFirstOption : public OnOffOption { public: QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class NoBuildOption : public OnOffOption { public: QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class LogTimeOption : public OnOffOption { public: QString description(CommandType command) const override; QString shortRepresentation() const override; QString longRepresentation() const override; }; class CommandEchoModeOption : public CommandLineOption { public: CommandEchoModeOption(); QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; CommandEchoMode commandEchoMode() const; private: void doParse(const QString &representation, QStringList &input) override; CommandEchoMode m_echoMode = CommandEchoModeInvalid; }; class DeprecationWarningsOption : public CommandLineOption { public: QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; DeprecationWarningMode mode() const { return m_mode; } private: void doParse(const QString &representation, QStringList &input) override; DeprecationWarningMode m_mode = defaultDeprecationWarningMode(); }; class SettingsDirOption : public CommandLineOption { public: SettingsDirOption(); QString settingsDir() const { return m_settingsDir; } QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; private: void doParse(const QString &representation, QStringList &input) override; QString m_settingsDir; }; class JobLimitsOption : public CommandLineOption { public: JobLimits jobLimits() const { return m_jobLimits; } QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; private: void doParse(const QString &representation, QStringList &input) override; JobLimits m_jobLimits; }; class RespectProjectJobLimitsOption : public OnOffOption { public: QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; class WaitLockOption : public OnOffOption { public: QString description(CommandType command) const override; QString shortRepresentation() const override { return {}; } QString longRepresentation() const override; }; } // namespace qbs #endif // QBS_COMMANDLINEOPTION_H qbs-src-2.5.1/src/app/qbs/parser/commandlineoptionpool.h0000644000175100001660000000717514744424375022676 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_COMMANDLINEOPTIONPOOL_H #define QBS_COMMANDLINEOPTIONPOOL_H #include "commandlineoption.h" #include namespace qbs { class CommandLineOptionPool { public: ~CommandLineOptionPool(); CommandLineOption *getOption(CommandLineOption::Type type) const; FileOption *fileOption() const; BuildDirectoryOption *buildDirectoryOption() const; LogLevelOption *logLevelOption() const; VerboseOption *verboseOption() const; QuietOption *quietOption() const; ShowProgressOption *showProgressOption() const; DryRunOption *dryRunOption() const; ForceProbesOption *forceProbesOption() const; ChangedFilesOption *changedFilesOption() const; KeepGoingOption *keepGoingOption() const; JobsOption *jobsOption() const; ProductsOption *productsOption() const; NoInstallOption *noInstallOption() const; InstallRootOption *installRootOption() const; RemoveFirstOption *removeFirstoption() const; NoBuildOption *noBuildOption() const; ForceTimeStampCheckOption *forceTimestampCheckOption() const; ForceOutputCheckOption *forceOutputCheckOption() const; BuildNonDefaultOption *buildNonDefaultOption() const; LogTimeOption *logTimeOption() const; CommandEchoModeOption *commandEchoModeOption() const; SettingsDirOption *settingsDirOption() const; JobLimitsOption *jobLimitsOption() const; RespectProjectJobLimitsOption *respectProjectJobLimitsOption() const; GeneratorOption *generatorOption() const; WaitLockOption *waitLockOption() const; RunEnvConfigOption *runEnvConfigOption() const; DeprecationWarningsOption *deprecationWarningsOption() const; private: mutable QHash m_options; }; } // namespace qbs #endif // QBS_COMMANDLINEOPTIONPOOL_H qbs-src-2.5.1/src/app/qbs/parser/parsercommand.h0000644000175100001660000002266214744424375021116 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_PARSER_COMMAND_H #define QBS_PARSER_COMMAND_H #include "commandlineoption.h" #include "commandtype.h" #include namespace qbs { class CommandLineOptionPool; class Command { public: virtual ~Command(); virtual CommandType type() const = 0; virtual QString shortDescription() const = 0; virtual QString longDescription() const = 0; virtual QString representation() const = 0; void parse(QStringList &input); QStringList additionalArguments() const { return m_additionalArguments; } bool canResolve() const; protected: Command(CommandLineOptionPool &optionPool) : m_optionPool(optionPool) {} const CommandLineOptionPool &optionPool() const { return m_optionPool; } QString supportedOptionsDescription() const; [[noreturn]] void throwError(const QString &reason); virtual void parseNext(QStringList &input); private: QList actualSupportedOptions() const; void parseOption(QStringList &input); void parsePropertyAssignment(const QString &argument); virtual QList supportedOptions() const = 0; QStringList m_additionalArguments; std::set m_usedOptions; const CommandLineOptionPool &m_optionPool; }; class ResolveCommand : public Command { public: ResolveCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return ResolveCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; class GenerateCommand : public Command { public: GenerateCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return GenerateCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; class BuildCommand : public Command { public: BuildCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return BuildCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; class CleanCommand : public Command { public: CleanCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return CleanCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; class InstallCommand : public Command { public: InstallCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return InstallCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; class RunCommand : public Command { public: RunCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} QStringList targetParameters() const { return m_targetParameters; } private: CommandType type() const override { return RunCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; void parseNext(QStringList &input) override; QStringList m_targetParameters; }; class ShellCommand : public Command { public: ShellCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return ShellCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; // TODO: It seems wrong that a configuration has to be given here. Ideally, this command would just track *all* files regardless of conditions. Is that possible? class StatusCommand : public Command { public: StatusCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return StatusCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; class UpdateTimestampsCommand : public Command { public: UpdateTimestampsCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return UpdateTimestampsCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; class DumpNodesTreeCommand : public Command { public: DumpNodesTreeCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override{ return DumpNodesTreeCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; class ListProductsCommand : public Command { public: ListProductsCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return ListProductsCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; }; class HelpCommand : public Command { public: HelpCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} QString commandToDescribe() const { return m_command; } private: CommandType type() const override { return HelpCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; void parseNext(QStringList &input) override; QString m_command; }; class VersionCommand : public Command { public: VersionCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return VersionCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override; void parseNext(QStringList &input) override; }; class SessionCommand : public Command { public: SessionCommand(CommandLineOptionPool &optionPool) : Command(optionPool) {} private: CommandType type() const override { return SessionCommandType; } QString shortDescription() const override; QString longDescription() const override; QString representation() const override; QList supportedOptions() const override { return {}; } void parseNext(QStringList &input) override; }; } // namespace qbs #endif // QBS_PARSER_COMMAND_H qbs-src-2.5.1/src/app/qbs/parser/commandlineparser.cpp0000644000175100001660000005520414744424375022317 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "commandlineparser.h" #include "commandlineoption.h" #include "commandlineoptionpool.h" #include "commandpool.h" #include "parsercommand.h" #include "../qbstool.h" #include "../../shared/logging/consolelogger.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_UNIX #include #endif namespace qbs { using Internal::Tr; class CommandLineParser::CommandLineParserPrivate { public: CommandLineParserPrivate(); void doParse(); Command *commandFromString(const QString &commandString) const; QList allCommands() const; QString generalHelp() const; void setupProjectFile(); void setupBuildDirectory(); void setupProgress(); void setupLogLevel(); void setupBuildOptions(); void setupBuildConfigurations(); bool checkForExistingBuildConfiguration(const QList &buildConfigs, const QString &configurationName); bool withNonDefaultProducts() const; bool dryRun() const; QString settingsDir() const { return optionPool.settingsDirOption()->settingsDir(); } CommandEchoMode echoMode() const; QString propertyName(const QString &aCommandLineName) const; QStringList commandLine; Command *command; QString projectFilePath; QString projectBuildDirectory; BuildOptions buildOptions; QList buildConfigurations; CommandLineOptionPool optionPool; CommandPool commandPool; bool showProgress; bool logTime; }; CommandLineParser::CommandLineParser() = default; CommandLineParser::~CommandLineParser() = default; void CommandLineParser::printHelp() const { QTextStream stream(stdout); Q_ASSERT(d->command == d->commandPool.getCommand(HelpCommandType)); const auto helpCommand = static_cast(d->command); if (helpCommand->commandToDescribe().isEmpty()) { stream << "Qbs " QBS_VERSION ", a cross-platform build tool.\n"; stream << d->generalHelp(); } else { const Command * const commandToDescribe = d->commandFromString(helpCommand->commandToDescribe()); if (commandToDescribe) { stream << commandToDescribe->longDescription(); } else if (!QbsTool::tryToRunTool(helpCommand->commandToDescribe(), QStringList(QStringLiteral("--help")))) { throw ErrorInfo(Tr::tr("No such command '%1'.\n%2") .arg(helpCommand->commandToDescribe(), d->generalHelp())); } } } CommandType CommandLineParser::command() const { return d->command->type(); } QString CommandLineParser::projectFilePath() const { return d->projectFilePath; } QString CommandLineParser::projectBuildDirectory() const { return d->projectBuildDirectory; } BuildOptions CommandLineParser::buildOptions(const QString &profile) const { d->buildOptions.setMaxJobCount(jobCount(profile)); if (d->buildOptions.echoMode() < 0) { Settings settings(settingsDir()); d->buildOptions.setEchoMode(Preferences(&settings, profile).defaultEchoMode()); } return d->buildOptions; } CleanOptions CommandLineParser::cleanOptions(const QString &profile) const { CleanOptions options; options.setDryRun(buildOptions(profile).dryRun()); options.setKeepGoing(buildOptions(profile).keepGoing()); options.setLogElapsedTime(logTime()); return options; } GenerateOptions CommandLineParser::generateOptions() const { GenerateOptions options; options.setGeneratorName(d->optionPool.generatorOption()->generatorName()); return options; } InstallOptions CommandLineParser::installOptions(const QString &profile) const { InstallOptions options; options.setRemoveExistingInstallation(d->optionPool.removeFirstoption()->enabled()); options.setInstallRoot(d->optionPool.installRootOption()->installRoot()); options.setInstallIntoSysroot(d->optionPool.installRootOption()->useSysroot()); if (!options.installRoot().isEmpty()) { QFileInfo fi(options.installRoot()); if (!fi.isAbsolute()) options.setInstallRoot(fi.absoluteFilePath()); } options.setDryRun(buildOptions(profile).dryRun()); options.setKeepGoing(buildOptions(profile).keepGoing()); options.setLogElapsedTime(logTime()); return options; } int CommandLineParser::jobCount(const QString &profile) const { if (const int explicitJobCount = d->optionPool.jobsOption()->jobCount(); explicitJobCount > 0) return explicitJobCount; Settings settings(settingsDir()); return Preferences(&settings, profile).jobs(); } bool CommandLineParser::forceTimestampCheck() const { return d->optionPool.forceTimestampCheckOption()->enabled(); } bool CommandLineParser::forceOutputCheck() const { return d->optionPool.forceOutputCheckOption()->enabled(); } bool CommandLineParser::dryRun() const { return d->dryRun(); } bool CommandLineParser::forceProbesExecution() const { return d->optionPool.forceProbesOption()->enabled(); } bool CommandLineParser::waitLockBuildGraph() const { return d->optionPool.waitLockOption()->enabled(); } bool CommandLineParser::logTime() const { return d->logTime; } bool CommandLineParser::withNonDefaultProducts() const { return d->withNonDefaultProducts(); } bool CommandLineParser::buildBeforeInstalling() const { return !d->optionPool.noBuildOption()->enabled(); } QStringList CommandLineParser::runArgs() const { Q_ASSERT(d->command->type() == RunCommandType); return static_cast(d->command)->targetParameters(); } QStringList CommandLineParser::products() const { return d->optionPool.productsOption()->arguments(); } QStringList CommandLineParser::runEnvConfig() const { return d->optionPool.runEnvConfigOption()->arguments(); } bool CommandLineParser::showProgress() const { return d->showProgress; } bool CommandLineParser::showVersion() const { return d->command->type() == VersionCommandType; } QString CommandLineParser::settingsDir() const { return d->settingsDir(); } DeprecationWarningMode CommandLineParser::deprecationWarningMode() const { return d->optionPool.deprecationWarningsOption()->mode(); } QString CommandLineParser::commandName() const { return d->command->representation(); } bool CommandLineParser::commandCanResolve() const { return d->command->canResolve(); } QString CommandLineParser::commandDescription() const { return d->command->longDescription(); } static QString getBuildConfigurationName(const QVariantMap &buildConfig) { return buildConfig.value(QStringLiteral("qbs.configurationName")).toString(); } QList CommandLineParser::buildConfigurations() const { return d->buildConfigurations; } bool CommandLineParser::parseCommandLine(const QStringList &args) { d = std::make_unique(); d->commandLine = args; try { d->doParse(); return true; } catch (const ErrorInfo &error) { qbsError() << error.toString(); return false; } } CommandLineParser::CommandLineParserPrivate::CommandLineParserPrivate() : command(nullptr), commandPool(optionPool), showProgress(false), logTime(false) { } void CommandLineParser::CommandLineParserPrivate::doParse() { if (commandLine.empty()) { // No command given, use default. command = commandPool.getCommand(BuildCommandType); } else { command = commandFromString(commandLine.front()); if (command) { const QString commandName = commandLine.takeFirst(); // if the command line contains a `` with // either `-h` or `--help` switch, we transform // it to corresponding `help ` instead const QStringList helpSwitches = {QStringLiteral("-h"), QStringLiteral("--help")}; if (auto it = std::find_first_of( commandLine.begin(), commandLine.end(), helpSwitches.begin(), helpSwitches.end()); it != commandLine.end()) { command = commandPool.getCommand(HelpCommandType); commandLine = QList{commandName}; // keep only command's name } } else { // No command given. if (commandLine.front() == QLatin1String("-h") || commandLine.front() == QLatin1String("--help")) { command = commandPool.getCommand(HelpCommandType); commandLine.takeFirst(); } else if (commandLine.front() == QLatin1String("-V") || commandLine.front() == QLatin1String("--version")) { command = commandPool.getCommand(VersionCommandType); commandLine.takeFirst(); } else { command = commandPool.getCommand(BuildCommandType); } } } command->parse(commandLine); if (command->type() == HelpCommandType || command->type() == VersionCommandType) return; setupBuildDirectory(); setupBuildConfigurations(); setupProjectFile(); setupProgress(); setupLogLevel(); setupBuildOptions(); } Command *CommandLineParser::CommandLineParserPrivate::commandFromString(const QString &commandString) const { const auto commands = allCommands(); for (Command * const command : commands) { if (command->representation() == commandString) return command; } return nullptr; } QList CommandLineParser::CommandLineParserPrivate::allCommands() const { return {commandPool.getCommand(GenerateCommandType), commandPool.getCommand(ResolveCommandType), commandPool.getCommand(BuildCommandType), commandPool.getCommand(CleanCommandType), commandPool.getCommand(RunCommandType), commandPool.getCommand(ShellCommandType), commandPool.getCommand(StatusCommandType), commandPool.getCommand(UpdateTimestampsCommandType), commandPool.getCommand(InstallCommandType), commandPool.getCommand(DumpNodesTreeCommandType), commandPool.getCommand(ListProductsCommandType), commandPool.getCommand(VersionCommandType), commandPool.getCommand(SessionCommandType), commandPool.getCommand(HelpCommandType)}; } static QString extractToolDescription(const QString &tool, const QString &output) { if (tool == QLatin1String("create-project")) { // This command uses QCommandLineParser, where the description is not in the first line. const int eol1Pos = output.indexOf(QLatin1Char('\n')); const int eol2Pos = output.indexOf(QLatin1Char('\n'), eol1Pos + 1); return output.mid(eol1Pos + 1, eol2Pos - eol1Pos - 1); } return output.left(output.indexOf(QLatin1Char('\n'))); } QString CommandLineParser::CommandLineParserPrivate::generalHelp() const { QString help = Tr::tr("Usage: qbs [command] [command parameters]\n"); help += Tr::tr("Built-in commands:\n"); const int rhsIndentation = 30; // Sorting the commands by name is nicer for the user. QMap commandMap; const auto commands = allCommands(); for (const Command * command : commands) commandMap.insert(command->representation(), command); for (const Command * command : std::as_const(commandMap)) { help.append(QLatin1String(" ")).append(command->representation()); const QString whitespace = QString(rhsIndentation - 2 - command->representation().size(), QLatin1Char(' ')); help.append(whitespace).append(command->shortDescription()).append(QLatin1Char('\n')); } QStringList toolNames = QbsTool::allToolNames(); toolNames.sort(); if (!toolNames.empty()) { help.append(QLatin1Char('\n')).append(Tr::tr("Auxiliary commands:\n")); for (const QString &toolName : std::as_const(toolNames)) { help.append(QLatin1String(" ")).append(toolName); const QString whitespace = QString(rhsIndentation - 2 - toolName.size(), QLatin1Char(' ')); QbsTool tool; tool.runTool(toolName, QStringList(QStringLiteral("--help"))); if (tool.exitCode() != 0) continue; const QString shortDescription = extractToolDescription(toolName, tool.stdOut()); help.append(whitespace).append(shortDescription).append(QLatin1Char('\n')); } } return help; } void CommandLineParser::CommandLineParserPrivate::setupProjectFile() { projectFilePath = optionPool.fileOption()->projectFilePath(); } void CommandLineParser::CommandLineParserPrivate::setupBuildDirectory() { projectBuildDirectory = optionPool.buildDirectoryOption()->projectBuildDirectory(); } void CommandLineParser::CommandLineParserPrivate::setupBuildOptions() { buildOptions.setDryRun(dryRun()); QStringList changedFiles = optionPool.changedFilesOption()->arguments(); QDir currentDir; for (QString &file : changedFiles) file = QDir::fromNativeSeparators(currentDir.absoluteFilePath(file)); buildOptions.setChangedFiles(changedFiles); buildOptions.setKeepGoing(optionPool.keepGoingOption()->enabled()); buildOptions.setForceTimestampCheck(optionPool.forceTimestampCheckOption()->enabled()); buildOptions.setForceOutputCheck(optionPool.forceOutputCheckOption()->enabled()); const JobsOption * jobsOption = optionPool.jobsOption(); buildOptions.setMaxJobCount(jobsOption->jobCount()); buildOptions.setLogElapsedTime(logTime); buildOptions.setEchoMode(echoMode()); buildOptions.setInstall(!optionPool.noInstallOption()->enabled()); buildOptions.setRemoveExistingInstallation(optionPool.removeFirstoption()->enabled()); buildOptions.setJobLimits(optionPool.jobLimitsOption()->jobLimits()); buildOptions.setProjectJobLimitsTakePrecedence( optionPool.respectProjectJobLimitsOption()->enabled()); buildOptions.setSettingsDirectory(settingsDir()); } void CommandLineParser::CommandLineParserPrivate::setupBuildConfigurations() { // first: configuration name, second: properties. // Empty configuration name used for global properties. using PropertyListItem = std::pair; QList propertiesPerConfiguration; const QString configurationNameKey = QStringLiteral("qbs.configurationName"); QString currentConfigurationName; QVariantMap currentProperties; const auto args = command->additionalArguments(); for (const QString &arg : args) { const int sepPos = arg.indexOf(QLatin1Char(':')); QBS_CHECK(sepPos > 0); const QString key = arg.left(sepPos); const QString rawValue = arg.mid(sepPos + 1); if (key == QLatin1String("config") || key == configurationNameKey) { propertiesPerConfiguration.push_back(std::make_pair(currentConfigurationName, currentProperties)); currentConfigurationName = rawValue; currentProperties.clear(); continue; } currentProperties.insert(propertyName(key), representationToSettingsValue(rawValue)); } propertiesPerConfiguration.push_back(std::make_pair(currentConfigurationName, currentProperties)); if (propertiesPerConfiguration.size() == 1) // No configuration name specified on command line. propertiesPerConfiguration.push_back(PropertyListItem(QStringLiteral("default"), QVariantMap())); const QVariantMap globalProperties = propertiesPerConfiguration.takeFirst().second; QList buildConfigs; for (const PropertyListItem &item : std::as_const(propertiesPerConfiguration)) { QVariantMap properties = item.second; for (QVariantMap::ConstIterator globalPropIt = globalProperties.constBegin(); globalPropIt != globalProperties.constEnd(); ++globalPropIt) { if (!properties.contains(globalPropIt.key())) properties.insert(globalPropIt.key(), globalPropIt.value()); } const QString configurationName = item.first; if (checkForExistingBuildConfiguration(buildConfigs, configurationName)) { qbsWarning() << Tr::tr("Ignoring redundant request to build for configuration '%1'.") .arg(configurationName); continue; } properties.insert(configurationNameKey, configurationName); buildConfigs.push_back(properties); } buildConfigurations = buildConfigs; } void CommandLineParser::CommandLineParserPrivate::setupProgress() { const ShowProgressOption * const option = optionPool.showProgressOption(); showProgress = option->enabled(); #ifdef Q_OS_UNIX if (showProgress && !isatty(STDOUT_FILENO)) { showProgress = false; qbsWarning() << Tr::tr("Ignoring option '%1', because standard output is " "not connected to a terminal.").arg(option->longRepresentation()); } #endif } void CommandLineParser::CommandLineParserPrivate::setupLogLevel() { const LogLevelOption * const logLevelOption = optionPool.logLevelOption(); const VerboseOption * const verboseOption = optionPool.verboseOption(); const QuietOption * const quietOption = optionPool.quietOption(); int logLevel = logLevelOption->logLevel(); logLevel += verboseOption->count(); logLevel -= quietOption->count(); if (showProgress && logLevel != LoggerMinLevel) { const bool logLevelWasSetByUser = logLevelOption->logLevel() != defaultLogLevel() || verboseOption->count() > 0 || quietOption->count() > 0; if (logLevelWasSetByUser) { qbsInfo() << Tr::tr("Setting log level to '%1', because option '%2'" " has been given.").arg(logLevelName(LoggerMinLevel), optionPool.showProgressOption()->longRepresentation()); } logLevel = LoggerMinLevel; } if (logLevel < LoggerMinLevel) { qbsWarning() << Tr::tr("Cannot decrease log level as much as specified; using '%1'.") .arg(logLevelName(LoggerMinLevel)); logLevel = LoggerMinLevel; } else if (logLevel > LoggerMaxLevel) { qbsWarning() << Tr::tr("Cannot increase log level as much as specified; using '%1'.") .arg(logLevelName(LoggerMaxLevel)); logLevel = LoggerMaxLevel; } logTime = optionPool.logTimeOption()->enabled(); if (showProgress && logTime) { qbsWarning() << Tr::tr("Options '%1' and '%2' are incompatible. Ignoring '%2'.") .arg(optionPool.showProgressOption()->longRepresentation(), optionPool.logTimeOption()->longRepresentation()); logTime = false; } ConsoleLogger::instance().logSink()->setLogLevel(static_cast(logLevel)); } QString CommandLineParser::CommandLineParserPrivate::propertyName(const QString &aCommandLineName) const { // Make fully-qualified, ie "platform" -> "qbs.platform" if (aCommandLineName.contains(QLatin1Char('.'))) return aCommandLineName; return QLatin1String("qbs.") + aCommandLineName; } bool CommandLineParser::CommandLineParserPrivate::checkForExistingBuildConfiguration( const QList &buildConfigs, const QString &configurationName) { return Internal::any_of(buildConfigs, [&configurationName](const auto &buildConfig) { return configurationName == getBuildConfigurationName(buildConfig); }); } bool CommandLineParser::CommandLineParserPrivate::withNonDefaultProducts() const { if (command->type() == GenerateCommandType) return true; return optionPool.buildNonDefaultOption()->enabled(); } bool CommandLineParser::CommandLineParserPrivate::dryRun() const { if (command->type() == GenerateCommandType || command->type() == ListProductsCommandType) return true; return optionPool.dryRunOption()->enabled(); } CommandEchoMode CommandLineParser::CommandLineParserPrivate::echoMode() const { if (command->type() == GenerateCommandType) return CommandEchoModeSilent; if (optionPool.commandEchoModeOption()->commandEchoMode() < CommandEchoModeInvalid) return optionPool.commandEchoModeOption()->commandEchoMode(); return defaultCommandEchoMode(); } } // namespace qbs qbs-src-2.5.1/src/app/qbs/parser/commandpool.h0000644000175100001660000000453214744424375020567 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_COMMANDPOOL_H #define QBS_COMMANDPOOL_H #include "commandtype.h" #include namespace qbs { class Command; class CommandLineOptionPool; class CommandPool { Q_DISABLE_COPY(CommandPool) public: CommandPool(CommandLineOptionPool &optionPool); ~CommandPool(); Command *getCommand(CommandType type) const; private: CommandLineOptionPool &m_optionPool; mutable QHash m_commands; }; } // namespace qbs #endif // QBS_COMMANDPOOL_H qbs-src-2.5.1/src/app/qbs/application.cpp0000644000175100001660000000535014744424375017620 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "application.h" #include "commandlinefrontend.h" #include "ctrlchandler.h" namespace qbs { Application::Application(int &argc, char **argv) : QCoreApplication(argc, argv), m_clFrontend(nullptr), m_canceled(false) { setApplicationName(QStringLiteral("qbs")); setOrganizationName(QStringLiteral("QtProject")); setOrganizationDomain(QStringLiteral("qt-project.org")); } Application *Application::instance() { return qobject_cast(QCoreApplication::instance()); } void Application::setCommandLineFrontend(CommandLineFrontend *clFrontend) { installCtrlCHandler(); m_clFrontend = clFrontend; } /** * Interrupt the application. This is directly called from a signal handler. */ void Application::userInterrupt() { if (m_canceled) return; Q_ASSERT(m_clFrontend); m_canceled = true; m_clFrontend->cancel(); } } // namespace qbs qbs-src-2.5.1/src/app/qbs/stdinreader.cpp0000644000175100001660000002475114744424375017627 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "stdinreader.h" #include #include #include #include #include #include #include #ifdef Q_OS_WIN32 #include #else #include #endif namespace qbs { namespace Internal { class UnixStdinReader : public StdinReader { public: UnixStdinReader(QObject *parent) : StdinReader(parent), m_notifier(0, QSocketNotifier::Read) {} private: void start() override { if (!m_stdIn.open(stdin, QIODevice::ReadOnly)) { emit errorOccurred(tr("Cannot read from standard input.")); return; } #ifdef Q_OS_UNIX const auto emitError = [this] { emit errorOccurred(tr("Failed to make standard input non-blocking: %1") .arg(QLatin1String(std::strerror(errno)))); }; const int flags = fcntl(0, F_GETFL, 0); if (flags == -1) { emitError(); return; } if (fcntl(0, F_SETFL, flags | O_NONBLOCK)) { emitError(); return; } #endif connect(&m_notifier, &QSocketNotifier::activated, this, [this] { emit dataAvailable(m_stdIn.readAll()); }); // Neither the aboutToClose() nor the readChannelFinished() signals // are triggering, so we need a timer to check whether the controlling // process disappeared. const auto stdinClosedChecker = new QTimer(this); connect(stdinClosedChecker, &QTimer::timeout, this, [this, stdinClosedChecker] { if (m_stdIn.atEnd()) { stdinClosedChecker->stop(); emit errorOccurred(tr("Input channel closed unexpectedly.")); } }); stdinClosedChecker->start(1000); } QFile m_stdIn; QSocketNotifier m_notifier; }; class WindowsStdinReader : public StdinReader { public: WindowsStdinReader(QObject *parent) : StdinReader(parent) {} private: #ifdef Q_OS_WIN32 class FileReaderThread : public QThread { public: FileReaderThread(WindowsStdinReader &parent, HANDLE stdInHandle, HANDLE exitEventHandle) : QThread(&parent), m_stdIn{stdInHandle}, m_exitEvent{exitEventHandle} { } ~FileReaderThread() { wait(); CloseHandle(m_exitEvent); } void run() override { WindowsStdinReader *r = static_cast(parent()); char buf[1024]; while (true) { DWORD bytesRead = 0; if (!ReadFile(m_stdIn, buf, sizeof buf, &bytesRead, nullptr)) { emit r->errorOccurred(tr("Failed to read from input channel.")); break; } if (!bytesRead) break; emit r->dataAvailable(QByteArray(buf, bytesRead)); } } private: HANDLE m_stdIn; HANDLE m_exitEvent; }; class ConsoleReaderThread : public QThread { public: ConsoleReaderThread(WindowsStdinReader &parent, HANDLE stdInHandle, HANDLE exitEventHandle) : QThread(&parent), m_stdIn{stdInHandle}, m_exitEvent{exitEventHandle} { } virtual ~ConsoleReaderThread() override { SetEvent(m_exitEvent); wait(); CloseHandle(m_exitEvent); } void run() override { WindowsStdinReader *r = static_cast(parent()); DWORD origConsoleMode; GetConsoleMode(m_stdIn, &origConsoleMode); DWORD consoleMode = ENABLE_PROCESSED_INPUT; SetConsoleMode(m_stdIn, consoleMode); HANDLE handles[2] = {m_exitEvent, m_stdIn}; char buf[1024]; while (true) { auto result = WaitForMultipleObjects(2, handles, FALSE, INFINITE); if (result == WAIT_OBJECT_0) break; INPUT_RECORD consoleInput; DWORD inputsRead = 0; if (!PeekConsoleInputA(m_stdIn, &consoleInput, 1, &inputsRead)) { emit r->errorOccurred(tr("Failed to read from input channel.")); break; } if (inputsRead) { if (consoleInput.EventType != KEY_EVENT || !consoleInput.Event.KeyEvent.bKeyDown || !consoleInput.Event.KeyEvent.uChar.AsciiChar) { if (!ReadConsoleInputA(m_stdIn, &consoleInput, 1, &inputsRead)) { emit r->errorOccurred(tr("Failed to read console input.")); break; } } else { DWORD bytesRead = 0; if (!ReadConsoleA(m_stdIn, buf, sizeof buf, &bytesRead, nullptr)) { emit r->errorOccurred(tr("Failed to read console.")); break; } emit r->dataAvailable(QByteArray(buf, bytesRead)); } } } SetConsoleMode(m_stdIn, origConsoleMode); } private: HANDLE m_stdIn; HANDLE m_exitEvent; }; class PipeReaderThread : public QThread { public: PipeReaderThread(WindowsStdinReader &parent, HANDLE stdInHandle, HANDLE exitEventHandle) : QThread(&parent), m_stdIn{stdInHandle}, m_exitEvent{exitEventHandle} { } virtual ~PipeReaderThread() override { SetEvent(m_exitEvent); wait(); CloseHandle(m_exitEvent); } void run() override { WindowsStdinReader *r = static_cast(parent()); OVERLAPPED overlapped = {}; overlapped.hEvent = CreateEventA(NULL, TRUE, TRUE, NULL); if (!overlapped.hEvent) { emit r->errorOccurred(StdinReader::tr("Failed to create handle for overlapped event.")); return; } char buf[1024]; DWORD bytesRead; HANDLE handles[2] = {m_exitEvent, overlapped.hEvent}; while (true) { bytesRead = 0; auto readResult = ReadFile(m_stdIn, buf, sizeof buf, NULL, &overlapped); if (!readResult) { if (GetLastError() != ERROR_IO_PENDING) { emit r->errorOccurred(StdinReader::tr("ReadFile Failed.")); break; } auto result = WaitForMultipleObjects(2, handles, FALSE, INFINITE); if (result == WAIT_OBJECT_0) break; } if (!GetOverlappedResult(m_stdIn, &overlapped, &bytesRead, FALSE)) { if (GetLastError() != ERROR_HANDLE_EOF) emit r->errorOccurred(StdinReader::tr("Error GetOverlappedResult.")); break; } emit r->dataAvailable(QByteArray(buf, bytesRead)); } CancelIo(m_stdIn); CloseHandle(overlapped.hEvent); } private: HANDLE m_stdIn; HANDLE m_exitEvent; }; #endif void start() override { #ifdef Q_OS_WIN32 HANDLE stdInHandle = GetStdHandle(STD_INPUT_HANDLE); if (!stdInHandle) { emit errorOccurred(StdinReader::tr("Failed to create handle for standard input.")); return; } HANDLE exitEventHandle = CreateEventA(NULL, TRUE, FALSE, NULL); if (!exitEventHandle) { emit errorOccurred(StdinReader::tr("Failed to create handle for exit event.")); return; } auto result = GetFileType(stdInHandle); switch (result) { case FILE_TYPE_CHAR: (new ConsoleReaderThread(*this, stdInHandle, exitEventHandle))->start(); return; case FILE_TYPE_PIPE: (new PipeReaderThread(*this, stdInHandle, exitEventHandle))->start(); return; case FILE_TYPE_DISK: (new FileReaderThread(*this, stdInHandle, exitEventHandle))->start(); return; default: emit errorOccurred(StdinReader::tr("Unable to handle unknown input type")); return; } #endif } }; StdinReader *StdinReader::create(QObject *parent) { if (HostOsInfo::isWindowsHost()) return new WindowsStdinReader(parent); return new UnixStdinReader(parent); } StdinReader::StdinReader(QObject *parent) : QObject(parent) { } } // namespace Internal } // namespace qbs qbs-src-2.5.1/src/app/qbs/consoleprogressobserver.h0000644000175100001660000000477514744424375021773 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef CONSOLEPROGRESSOBSERVER_H #define CONSOLEPROGRESSOBSERVER_H #include QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE namespace qbs { class ConsoleProgressObserver { public: void initialize(const QString &task, int max); void setMaximum(int maximum); void setProgressValue(int value); void incrementProgressValue() { setProgressValue(m_value + 1); } private: void eraseCurrentPercentageString(); void updateProgressBarIfNecessary(); void writePercentageString(); int m_maximum; int m_value; int m_percentage; int m_hashesPrinted; }; } // namespace qbs #endif // CONSOLEPROGRESSOBSERVER_H qbs-src-2.5.1/src/app/qbs/lspserver.h0000644000175100001660000000436614744424375017015 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2023 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #pragma once #include #include namespace qbs { class ProjectData; namespace Internal { class LspServer { public: LspServer(); ~LspServer(); void updateProjectData(const ProjectData &projectData, const CodeLinks &codeLinks); QString socketPath() const; private: class Private; Private * const d; }; } // namespace Internal } // namespace qbs qbs-src-2.5.1/src/app/qbs/session.h0000644000175100001660000000401614744424375016443 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_SESSION_H #define QBS_SESSION_H namespace qbs { namespace Internal { void startSession(); } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.5.1/src/app/qbs/sessionpacket.cpp0000644000175100001660000001041114744424375020162 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "sessionpacket.h" #include #include #include #include #include #include #include namespace qbs { namespace Internal { const QByteArray packetStart = "qbsmsg:"; SessionPacket::Status SessionPacket::parseInput(QByteArray &input) { //qDebug() << m_expectedPayloadLength << m_payload << input; if (m_expectedPayloadLength == -1) { const int packetStartOffset = input.indexOf(packetStart); if (packetStartOffset == -1) return Status::Incomplete; const int numberOffset = packetStartOffset + packetStart.length(); const int newLineOffset = input.indexOf('\n', numberOffset); if (newLineOffset == -1) return Status::Incomplete; const QByteArray sizeString = input.mid(numberOffset, newLineOffset - numberOffset); bool isNumber; const int payloadLen = sizeString.toInt(&isNumber); if (!isNumber || payloadLen < 0) return Status::Invalid; m_expectedPayloadLength = payloadLen; input.remove(0, newLineOffset + 1); } const int bytesToAdd = m_expectedPayloadLength - m_payload.length(); QBS_ASSERT(bytesToAdd >= 0, return Status::Invalid); m_payload += input.left(bytesToAdd); input.remove(0, bytesToAdd); return isComplete() ? Status::Complete : Status::Incomplete; } QJsonObject SessionPacket::retrievePacket() { QBS_ASSERT(isComplete(), return QJsonObject()); auto packet = QJsonDocument::fromJson(QByteArray::fromBase64(m_payload)).object(); m_payload.clear(); m_expectedPayloadLength = -1; return packet; } QByteArray SessionPacket::createPacket(const QJsonObject &packet) { const QByteArray jsonData = QJsonDocument(packet).toJson(QJsonDocument::Compact).toBase64(); return QByteArray(packetStart).append(QByteArray::number(jsonData.length())).append('\n') .append(jsonData); } QJsonObject SessionPacket::helloMessage(const QString &lspSocket) { return QJsonObject{ {StringConstants::type(), QLatin1String("hello")}, {QLatin1String("api-level"), 6}, {QLatin1String("api-compat-level"), 2}, {QLatin1String("lsp-socket"), lspSocket}}; } bool SessionPacket::isComplete() const { return m_payload.length() == m_expectedPayloadLength; } } // namespace Internal } // namespace qbs qbs-src-2.5.1/src/app/qbs/session.cpp0000644000175100001660000007773614744424375017021 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "session.h" #include "lspserver.h" #include "sessionpacket.h" #include "sessionpacketreader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN32 #include #include #include #include #include #endif namespace qbs { namespace Internal { using FilePair = std::pair; class SessionLogSink : public QObject, public ILogSink { Q_OBJECT signals: void newMessage(const QJsonObject &msg); private: void doPrintMessage(LoggerLevel, const QString &message, const QString &) override { QJsonObject msg; msg.insert(StringConstants::type(), QLatin1String("log-data")); msg.insert(StringConstants::messageKey(), message); emit newMessage(msg); } void doPrintWarning(const ErrorInfo &warning) override { QJsonObject msg; static const QString warningString(QLatin1String("warning")); msg.insert(StringConstants::type(), warningString); msg.insert(warningString, warning.toJson()); emit newMessage(msg); } }; class Session : public QObject { Q_OBJECT public: Session(); private: enum class ProjectDataMode { Never, Always, OnlyIfChanged }; ProjectDataMode dataModeFromRequest(const QJsonObject &request); QStringList modulePropertiesFromRequest(const QJsonObject &request); void insertProjectDataIfNecessary( QJsonObject &reply, ProjectDataMode dataMode, const ProjectData &oldProjectData, bool includeTopLevelData ); void setLogLevelFromRequest(const QJsonObject &request); bool checkNormalRequestPrerequisites(const char *replyType); void sendPacket(const QJsonObject &message); void setupProject(const QJsonObject &request); void buildProject(const QJsonObject &request); void cleanProject(const QJsonObject &request); void installProject(const QJsonObject &request); void addFiles(const QJsonObject &request); void removeFiles(const QJsonObject &request); void renameFiles(const QJsonObject &request); void getRunEnvironment(const QJsonObject &request); void getGeneratedFilesForSources(const QJsonObject &request); void releaseProject(); void cancelCurrentJob(); void quitSession(); void sendErrorReply(const char *replyType, const QString &message); void sendErrorReply(const char *replyType, const ErrorInfo &error); void insertErrorInfoIfNecessary(QJsonObject &reply, const ErrorInfo &error); void connectProgressSignals(AbstractJob *job); QList getProductsByName(const QStringList &productNames) const; ProductData getProductByName(const QString &productName) const; struct ProductSelection { ProductSelection(Project::ProductSelection s) : selection(s) {} ProductSelection(QList p) : products(std::move(p)) {} Project::ProductSelection selection = Project::ProductSelectionDefaultOnly; QList products; }; ProductSelection getProductSelection(const QJsonObject &request); template struct FileUpdateData { QJsonObject createErrorReply(const char *type, const QString &mainMessage) const; ProductData product; GroupData group; QList filePaths; ErrorInfo error; }; template FileUpdateData prepareFileUpdate(const QJsonObject &request); SessionPacketReader m_packetReader; LspServer m_lspServer; SessionLogSink m_logSink; Project m_project; ProjectData m_projectData; std::unique_ptr m_settings; QJsonObject m_resolveRequest; QStringList m_moduleProperties; AbstractJob *m_currentJob = nullptr; }; void startSession() { const auto session = new Session; QObject::connect(qApp, &QCoreApplication::aboutToQuit, session, [session] { delete session; }); } Session::Session() { #ifdef Q_OS_WIN32 // Make sure the line feed character appears as itself. if (_setmode(_fileno(stdout), _O_BINARY) == -1) { constexpr size_t errmsglen = FILENAME_MAX; char errmsg[errmsglen]; strerror_s(errmsg, errmsglen, errno); std::cerr << "Failed to set stdout to binary mode: " << errmsg << std::endl; qApp->exit(EXIT_FAILURE); } #endif sendPacket(SessionPacket::helloMessage(m_lspServer.socketPath())); connect(&m_logSink, &SessionLogSink::newMessage, this, &Session::sendPacket); connect(&m_packetReader, &SessionPacketReader::errorOccurred, this, [](const QString &msg) { std::cerr << qPrintable(tr("Error: %1").arg(msg)); qApp->exit(EXIT_FAILURE); }); connect(&m_packetReader, &SessionPacketReader::packetReceived, this, [this](const QJsonObject &packet) { // qDebug() << "got packet:" << packet; // Uncomment for debugging. const QString type = packet.value(StringConstants::type()).toString(); if (type == QLatin1String("resolve-project")) setupProject(packet); else if (type == QLatin1String("build-project")) buildProject(packet); else if (type == QLatin1String("clean-project")) cleanProject(packet); else if (type == QLatin1String("install-project")) installProject(packet); else if (type == QLatin1String("add-files")) addFiles(packet); else if (type == QLatin1String("remove-files")) removeFiles(packet); else if (type == QLatin1String("rename-files")) renameFiles(packet); else if (type == QLatin1String("get-run-environment")) getRunEnvironment(packet); else if (type == QLatin1String("get-generated-files-for-sources")) getGeneratedFilesForSources(packet); else if (type == QLatin1String("release-project")) releaseProject(); else if (type == QLatin1String("quit")) quitSession(); else if (type == QLatin1String("cancel-job")) cancelCurrentJob(); else sendErrorReply("protocol-error", tr("Unknown request type '%1'.").arg(type)); }); m_packetReader.start(); } Session::ProjectDataMode Session::dataModeFromRequest(const QJsonObject &request) { const QString modeString = request.value(QLatin1String("data-mode")).toString(); if (modeString == QLatin1String("only-if-changed")) return ProjectDataMode::OnlyIfChanged; if (modeString == QLatin1String("always")) return ProjectDataMode::Always; return ProjectDataMode::Never; } void Session::sendPacket(const QJsonObject &message) { std::cout << SessionPacket::createPacket(message).constData() << std::flush; } void Session::setupProject(const QJsonObject &request) { if (m_currentJob) { if (qobject_cast(m_currentJob) && m_currentJob->state() == AbstractJob::StateCanceling) { m_resolveRequest = request; return; } sendErrorReply("project-resolved", tr("Cannot start resolving while another job is still running.")); return; } m_moduleProperties = modulePropertiesFromRequest(request); auto params = SetupProjectParameters::fromJson(request); const ProjectDataMode dataMode = dataModeFromRequest(request); m_settings = std::make_unique(params.settingsDirectory()); const Preferences prefs(m_settings.get()); const QString appDir = QDir::cleanPath(QCoreApplication::applicationDirPath()); params.setSearchPaths(prefs.searchPaths(appDir + QLatin1String( "/" QBS_RELATIVE_SEARCH_PATH))); params.setPluginPaths(prefs.pluginPaths(appDir + QLatin1String( "/" QBS_RELATIVE_PLUGINS_PATH))); params.setLibexecPath(appDir + QLatin1String("/" QBS_RELATIVE_LIBEXEC_PATH)); params.setOverrideBuildGraphData(true); setLogLevelFromRequest(request); SetupProjectJob * const setupJob = m_project.setupProject(params, &m_logSink, this); m_currentJob = setupJob; connectProgressSignals(setupJob); connect(setupJob, &AbstractJob::finished, this, [this, setupJob, dataMode](bool success) { if (!m_resolveRequest.isEmpty()) { // Canceled job was superseded. const QJsonObject newRequest = std::move(m_resolveRequest); m_resolveRequest = QJsonObject(); m_currentJob->deleteLater(); m_currentJob = nullptr; setupProject(newRequest); return; } const ProjectData oldProjectData = m_projectData; m_project = setupJob->project(); m_projectData = m_project.projectData(); m_lspServer.updateProjectData(m_projectData, m_project.codeLinks()); QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String("project-resolved")); if (success) insertProjectDataIfNecessary(reply, dataMode, oldProjectData, true); else insertErrorInfoIfNecessary(reply, setupJob->error()); sendPacket(reply); m_currentJob->deleteLater(); m_currentJob = nullptr; }); } void Session::buildProject(const QJsonObject &request) { if (!checkNormalRequestPrerequisites("project-built")) return; const ProductSelection productSelection = getProductSelection(request); setLogLevelFromRequest(request); auto options = BuildOptions::fromJson(request); options.setSettingsDirectory(m_settings->baseDirectory()); BuildJob * const buildJob = productSelection.products.empty() ? m_project.buildAllProducts(options, productSelection.selection, this) : m_project.buildSomeProducts(productSelection.products, options, this); m_currentJob = buildJob; m_moduleProperties = modulePropertiesFromRequest(request); const ProjectDataMode dataMode = dataModeFromRequest(request); connectProgressSignals(buildJob); connect(buildJob, &BuildJob::reportCommandDescription, this, [this](const QString &highlight, const QString &message) { QJsonObject descData; descData.insert(StringConstants::type(), QLatin1String("command-description")); descData.insert(QLatin1String("highlight"), highlight); descData.insert(StringConstants::messageKey(), message); sendPacket(descData); }); connect(buildJob, &BuildJob::reportProcessResult, this, [this](const ProcessResult &result) { if (result.success() && result.stdOut().isEmpty() && result.stdErr().isEmpty()) return; QJsonObject resultData = result.toJson(); resultData.insert(StringConstants::type(), QLatin1String("process-result")); sendPacket(resultData); }); connect(buildJob, &BuildJob::finished, this, [this, dataMode](bool success) { QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String("project-built")); const ProjectData oldProjectData = m_projectData; m_projectData = m_project.projectData(); if (success) insertProjectDataIfNecessary(reply, dataMode, oldProjectData, false); else insertErrorInfoIfNecessary(reply, m_currentJob->error()); sendPacket(reply); m_currentJob->deleteLater(); m_currentJob = nullptr; }); } void Session::cleanProject(const QJsonObject &request) { if (!checkNormalRequestPrerequisites("project-cleaned")) return; setLogLevelFromRequest(request); const ProductSelection productSelection = getProductSelection(request); const auto options = CleanOptions::fromJson(request); m_currentJob = productSelection.products.empty() ? m_project.cleanAllProducts(options, this) : m_project.cleanSomeProducts(productSelection.products, options, this); connectProgressSignals(m_currentJob); connect(m_currentJob, &AbstractJob::finished, this, [this](bool success) { QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String("project-cleaned")); if (!success) insertErrorInfoIfNecessary(reply, m_currentJob->error()); sendPacket(reply); m_currentJob->deleteLater(); m_currentJob = nullptr; }); } void Session::installProject(const QJsonObject &request) { if (!checkNormalRequestPrerequisites("install-done")) return; setLogLevelFromRequest(request); const ProductSelection productSelection = getProductSelection(request); const auto options = InstallOptions::fromJson(request); m_currentJob = productSelection.products.empty() ? m_project.installAllProducts(options, productSelection.selection, this) : m_project.installSomeProducts(productSelection.products, options, this); connectProgressSignals(m_currentJob); connect(m_currentJob, &AbstractJob::finished, this, [this](bool success) { QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String("install-done")); if (!success) insertErrorInfoIfNecessary(reply, m_currentJob->error()); sendPacket(reply); m_currentJob->deleteLater(); m_currentJob = nullptr; }); } void Session::addFiles(const QJsonObject &request) { const FileUpdateData data = prepareFileUpdate(request); if (data.error.hasError()) { sendPacket(data.createErrorReply("files-added", tr("Failed to add files to project: %1") .arg(data.error.toString()))); return; } ErrorInfo error; QStringList failedFiles; for (const QString &filePath : data.filePaths) { const ErrorInfo e = m_project.addFiles(data.product, data.group, {filePath}); if (e.hasError()) { for (const ErrorItem &ei : e.items()) error.append(ei); failedFiles.push_back(filePath); } } QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String("files-added")); insertErrorInfoIfNecessary(reply, error); if (failedFiles.size() != data.filePaths.size()) { // Note that Project::addFiles() directly changes the existing project data object, so // there's no need to retrieve it from m_project. insertProjectDataIfNecessary(reply, ProjectDataMode::Always, {}, false); } if (!failedFiles.isEmpty()) reply.insert(QLatin1String("failed-files"), QJsonArray::fromStringList(failedFiles)); sendPacket(reply); } void Session::removeFiles(const QJsonObject &request) { const FileUpdateData data = prepareFileUpdate(request); if (data.error.hasError()) { sendPacket(data.createErrorReply("files-removed", tr("Failed to remove files from project: %1") .arg(data.error.toString()))); return; } ErrorInfo error; QStringList failedFiles; for (const QString &filePath : data.filePaths) { const ErrorInfo e = m_project.removeFiles(data.product, data.group, {filePath}); if (e.hasError()) { for (const ErrorItem &ei : e.items()) error.append(ei); failedFiles.push_back(filePath); } } QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String("files-removed")); insertErrorInfoIfNecessary(reply, error); if (failedFiles.size() != data.filePaths.size()) insertProjectDataIfNecessary(reply, ProjectDataMode::Always, {}, false); if (!failedFiles.isEmpty()) reply.insert(QLatin1String("failed-files"), QJsonArray::fromStringList(failedFiles)); sendPacket(reply); } void Session::renameFiles(const QJsonObject &request) { const FileUpdateData data = prepareFileUpdate(request); if (data.error.hasError()) { sendPacket(data.createErrorReply( "files-renamed", tr("Failed to rename files in project: %1").arg(data.error.toString()))); return; } ErrorInfo error; QStringList failedFiles; for (const FilePair &sourceAndTarget : data.filePaths) { const ErrorInfo removeError = m_project.removeFiles( data.product, data.group, {sourceAndTarget.first}); if (removeError.hasError()) { for (const ErrorItem &ei : removeError.items()) error.append(ei); failedFiles.push_back(sourceAndTarget.first); } else { const ErrorInfo addError = m_project.addFiles( data.product, data.group, {sourceAndTarget.second}); if (addError.hasError()) { for (const ErrorItem &ei : addError.items()) error.append(ei); failedFiles.push_back(sourceAndTarget.first); } } } QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String("files-renamed")); insertErrorInfoIfNecessary(reply, error); if (failedFiles.size() != data.filePaths.size()) insertProjectDataIfNecessary(reply, ProjectDataMode::Always, {}, false); if (!failedFiles.isEmpty()) reply.insert(QLatin1String("failed-files"), QJsonArray::fromStringList(failedFiles)); sendPacket(reply); } void Session::connectProgressSignals(AbstractJob *job) { static QString maxProgressString(QLatin1String("max-progress")); connect(job, &AbstractJob::taskStarted, this, [this](const QString &description, int maxProgress) { QJsonObject msg; msg.insert(StringConstants::type(), QLatin1String("task-started")); msg.insert(StringConstants::descriptionProperty(), description); msg.insert(maxProgressString, maxProgress); sendPacket(msg); }); connect(job, &AbstractJob::totalEffortChanged, this, [this](int maxProgress) { QJsonObject msg; msg.insert(StringConstants::type(), QLatin1String("new-max-progress")); msg.insert(maxProgressString, maxProgress); sendPacket(msg); }); connect(job, &AbstractJob::taskProgress, this, [this](int progress) { QJsonObject msg; msg.insert(StringConstants::type(), QLatin1String("task-progress")); msg.insert(QLatin1String("progress"), progress); sendPacket(msg); }); } static QList getProductsByNameForProject(const ProjectData &project, QStringList &productNames) { QList products; if (productNames.empty()) return products; for (const ProductData &p : project.products()) { for (auto it = productNames.begin(); it != productNames.end(); ++it) { if (*it == p.fullDisplayName()) { products << p; productNames.erase(it); if (productNames.empty()) return products; break; } } } for (const ProjectData &p : project.subProjects()) { products << getProductsByNameForProject(p, productNames); if (productNames.empty()) break; } return products; } QList Session::getProductsByName(const QStringList &productNames) const { QStringList remainingNames = productNames; return getProductsByNameForProject(m_projectData, remainingNames); } ProductData Session::getProductByName(const QString &productName) const { const QList products = getProductsByName({productName}); return products.empty() ? ProductData() : products.first(); } void Session::getRunEnvironment(const QJsonObject &request) { const char * const replyType = "run-environment"; if (!checkNormalRequestPrerequisites(replyType)) return; const QString productName = request.value(QLatin1String("product")).toString(); const ProductData product = getProductByName(productName); if (!product.isValid()) { sendErrorReply(replyType, tr("No such product '%1'.").arg(productName)); return; } const auto inEnv = fromJson( request.value(QLatin1String("base-environment"))); const QStringList config = fromJson(request.value(QLatin1String("config"))); const RunEnvironment runEnv = m_project.getRunEnvironment(product, InstallOptions(), inEnv, config, m_settings.get()); ErrorInfo error; const QProcessEnvironment outEnv = runEnv.runEnvironment(&error); if (error.hasError()) { sendErrorReply(replyType, error); return; } QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String(replyType)); QJsonObject outEnvObj; const QStringList keys = outEnv.keys(); for (const QString &key : keys) outEnvObj.insert(key, outEnv.value(key)); reply.insert(QLatin1String("full-environment"), outEnvObj); sendPacket(reply); } void Session::getGeneratedFilesForSources(const QJsonObject &request) { const char * const replyType = "generated-files-for-sources"; if (!checkNormalRequestPrerequisites(replyType)) return; QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String(replyType)); const QJsonArray specs = request.value(StringConstants::productsKey()).toArray(); QJsonArray resultProducts; for (const auto &p : specs) { const QJsonObject productObject = p.toObject(); const ProductData product = getProductByName( productObject.value(StringConstants::fullDisplayNameKey()).toString()); if (!product.isValid()) continue; QJsonObject resultProduct; resultProduct.insert(StringConstants::fullDisplayNameKey(), product.fullDisplayName()); QJsonArray results; const QJsonArray requests = productObject.value(QLatin1String("requests")).toArray(); for (const auto &r : requests) { const QJsonObject request = r.toObject(); const QString filePath = request.value(QLatin1String("source-file")).toString(); const QStringList tags = fromJson(request.value(QLatin1String("tags"))); const bool recursive = request.value(QLatin1String("recursive")).toBool(); const QStringList generatedFiles = m_project.generatedFiles(product, filePath, recursive, tags); if (!generatedFiles.isEmpty()) { QJsonObject result; result.insert(QLatin1String("source-file"), filePath); result.insert(QLatin1String("generated-files"), QJsonArray::fromStringList(generatedFiles)); results << result; } } if (!results.isEmpty()) { resultProduct.insert(QLatin1String("results"), results); resultProducts << resultProduct; } } reply.insert(StringConstants::productsKey(), resultProducts); sendPacket(reply); } void Session::releaseProject() { const char * const replyType = "project-released"; if (!m_project.isValid()) { sendErrorReply(replyType, tr("No open project.")); return; } if (m_currentJob) { m_currentJob->disconnect(this); m_currentJob->cancel(); m_currentJob = nullptr; } m_project = Project(); m_projectData = ProjectData(); m_resolveRequest = QJsonObject(); QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String(replyType)); sendPacket(reply); } void Session::cancelCurrentJob() { if (m_currentJob) { if (!m_resolveRequest.isEmpty()) m_resolveRequest = QJsonObject(); m_currentJob->cancel(); } } Session::ProductSelection Session::getProductSelection(const QJsonObject &request) { const QJsonValue productSelection = request.value(StringConstants::productsKey()); if (productSelection.isArray()) return {getProductsByName(fromJson(productSelection))}; return { productSelection.toString() == QLatin1String("all") ? Project::ProductSelectionWithNonDefault : Project::ProductSelectionDefaultOnly}; } template Session::FileUpdateData Session::prepareFileUpdate(const QJsonObject &request) { FileUpdateData data; const QString productName = request.value(QLatin1String("product")).toString(); data.product = getProductByName(productName); if (data.product.isValid()) { const QString groupName = request.value(QLatin1String("group")).toString(); for (const GroupData &g : data.product.groups()) { if (g.name() == groupName) { data.group = g; break; } } if (!data.group.isValid()) data.error = tr("Group '%1' not found in product '%2'.").arg(groupName, productName); } else { data.error = tr("Product '%1' not found in project.").arg(productName); } const QJsonArray filesArray = request.value(QLatin1String("files")).toArray(); for (const auto &v : filesArray) if constexpr (std::is_same_v) { data.filePaths << v.toString(); } else if constexpr (std::is_same_v) { const QJsonObject file = v.toObject(); data.filePaths << std::make_pair( file.value(QLatin1String("source-path")).toString(), file.value(QLatin1String("target-path")).toString()); } if (m_currentJob) data.error = tr("Cannot update the list of source files while a job is running."); if (!m_project.isValid()) data.error = tr("No valid project. You need to resolve first."); return data; } void Session::insertProjectDataIfNecessary(QJsonObject &reply, ProjectDataMode dataMode, const ProjectData &oldProjectData, bool includeTopLevelData) { const bool sendProjectData = dataMode == ProjectDataMode::Always || (dataMode == ProjectDataMode::OnlyIfChanged && m_projectData != oldProjectData); if (!sendProjectData) return; QJsonObject projectData = m_projectData.toJson(m_moduleProperties); if (includeTopLevelData) { QJsonArray buildSystemFiles; for (const QString &f : m_project.buildSystemFiles()) buildSystemFiles.push_back(f); projectData.insert(StringConstants::buildDirectoryKey(), m_projectData.buildDirectory()); projectData.insert(QLatin1String("build-system-files"), buildSystemFiles); const Project::BuildGraphInfo bgInfo = m_project.getBuildGraphInfo(); projectData.insert(QLatin1String("build-graph-file-path"), bgInfo.bgFilePath); projectData.insert(QLatin1String("profile-data"), QJsonObject::fromVariantMap(bgInfo.profileData)); projectData.insert(QLatin1String("overridden-properties"), QJsonObject::fromVariantMap(bgInfo.overriddenProperties)); } reply.insert(QLatin1String("project-data"), projectData); } void Session::setLogLevelFromRequest(const QJsonObject &request) { const QString logLevelString = request.value(QLatin1String("log-level")).toString(); if (logLevelString.isEmpty()) return; for (const LoggerLevel l : {LoggerError, LoggerWarning, LoggerInfo, LoggerDebug, LoggerTrace}) { if (logLevelString == logLevelName(l)) { m_logSink.setLogLevel(l); return; } } } bool Session::checkNormalRequestPrerequisites(const char *replyType) { if (m_currentJob) { sendErrorReply(replyType, tr("Another job is still running.")); return false; } if (!m_project.isValid()) { sendErrorReply(replyType, tr("No valid project. You need to resolve first.")); return false; } return true; } QStringList Session::modulePropertiesFromRequest(const QJsonObject &request) { return fromJson(request.value(StringConstants::modulePropertiesKey())); } void Session::sendErrorReply(const char *replyType, const ErrorInfo &error) { QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String(replyType)); insertErrorInfoIfNecessary(reply, error); sendPacket(reply); } void Session::sendErrorReply(const char *replyType, const QString &message) { sendErrorReply(replyType, ErrorInfo(message)); } void Session::insertErrorInfoIfNecessary(QJsonObject &reply, const ErrorInfo &error) { if (error.hasError()) reply.insert(QLatin1String("error"), error.toJson()); } void Session::quitSession() { m_logSink.disconnect(this); m_packetReader.disconnect(this); if (m_currentJob) { m_currentJob->disconnect(this); connect(m_currentJob, &AbstractJob::finished, qApp, QCoreApplication::quit); m_currentJob->cancel(); } else { qApp->quit(); } } template QJsonObject Session::FileUpdateData::createErrorReply( const char *type, const QString &mainMessage) const { QBS_ASSERT(error.hasError(), return QJsonObject()); ErrorInfo error(mainMessage); for (const ErrorItem &ei : error.items()) error.append(ei); QJsonObject reply; reply.insert(StringConstants::type(), QLatin1String(type)); reply.insert(QLatin1String("error"), error.toJson()); QStringList failedFiles; if constexpr (std::is_same_v) { failedFiles = filePaths; } else if constexpr (std::is_same_v) { failedFiles = transformed(filePaths, [](const FilePair &fp) { return fp.first; }); } reply.insert(QLatin1String("failed-files"), QJsonArray::fromStringList(failedFiles)); return reply; } } // namespace Internal } // namespace qbs #include qbs-src-2.5.1/src/app/qbs/sessionpacketreader.cpp0000644000175100001660000000702314744424375021352 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #include "sessionpacketreader.h" #include "sessionpacket.h" #include "stdinreader.h" #include namespace qbs { namespace Internal { class SessionPacketReader::Private { public: QByteArray incomingData; SessionPacket currentPacket; }; SessionPacketReader::SessionPacketReader(QObject *parent) : QObject(parent) , d(std::make_unique()) { } SessionPacketReader::~SessionPacketReader() = default; void SessionPacketReader::start() { StdinReader * const stdinReader = StdinReader::create(this); connect(stdinReader, &StdinReader::errorOccurred, this, &SessionPacketReader::errorOccurred); connect(stdinReader, &StdinReader::dataAvailable, this, [this](const QByteArray &data) { /* Because this SessionPacketReader can be destroyed in the emit packetReceived, * use a `QPointer self(this)` to check whether this instance still exists. * When self evaluates to false, this instance should no longer be referenced, * so the parent QObject and d should no longer be used in any way. */ QPointer self(this); d->incomingData += data; while (self && !d->incomingData.isEmpty()) { switch (d->currentPacket.parseInput(d->incomingData)) { case SessionPacket::Status::Invalid: emit errorOccurred(tr("Received invalid input.")); return; case SessionPacket::Status::Complete: emit packetReceived(d->currentPacket.retrievePacket()); break; case SessionPacket::Status::Incomplete: return; } } }); stdinReader->start(); } } // namespace Internal } // namespace qbs qbs-src-2.5.1/src/app/qbs/stdinreader.h0000644000175100001660000000451114744424375017264 0ustar runnerdocker/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** 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$ ** ****************************************************************************/ #ifndef QBS_STDINREADER_H #define QBS_STDINREADER_H #include namespace qbs { namespace Internal { class StdinReader : public QObject { Q_OBJECT public: static StdinReader *create(QObject *parent); virtual void start() = 0; signals: void errorOccurred(const QString &error); void dataAvailable(const QByteArray &data); protected: explicit StdinReader(QObject *parent); }; } // namespace Internal } // namespace qbs #endif // Include guard qbs-src-2.5.1/src/3rdparty/0000755000175100001660000000000014744424375015011 5ustar runnerdockerqbs-src-2.5.1/src/3rdparty/python/0000755000175100001660000000000014744424375016332 5ustar runnerdockerqbs-src-2.5.1/src/3rdparty/python/.gitignore0000644000175100001660000000003514744424375020320 0ustar runnerdocker*.pyc *.dist-info *.egg-info qbs-src-2.5.1/src/3rdparty/python/lib/0000755000175100001660000000000014744424375017100 5ustar runnerdockerqbs-src-2.5.1/src/3rdparty/python/lib/python3.9/0000755000175100001660000000000014744424375020653 5ustar runnerdockerqbs-src-2.5.1/src/3rdparty/python/lib/python3.9/site-packages/0000755000175100001660000000000014744424375023373 5ustar runnerdockerqbs-src-2.5.1/src/3rdparty/python/lib/python3.9/site-packages/mac_alias/0000755000175100001660000000000014744424375025304 5ustar runnerdockerqbs-src-2.5.1/src/3rdparty/python/lib/python3.9/site-packages/mac_alias/LICENSE0000644000175100001660000000204514744424375026312 0ustar runnerdockerCopyright (c) 2014 Alastair Houghton Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. qbs-src-2.5.1/src/3rdparty/python/lib/python3.9/site-packages/mac_alias/osx.py0000644000175100001660000007723214744424375026502 0ustar runnerdockerimport datetime import os import uuid from ctypes import ( POINTER, Structure, Union, byref, c_byte, c_char, c_char_p, c_int, c_long, c_longlong, c_short, c_uint, c_ulong, c_ulonglong, c_ushort, c_void_p, cdll, create_string_buffer, sizeof, ) from .utils import unix_epoch libc = cdll.LoadLibrary("/usr/lib/libc.dylib") # Constants FSOPT_NOFOLLOW = 0x00000001 FSOPT_NOINMEMUPDATE = 0x00000002 FSOPT_REPORT_FULLSIZE = 0x00000004 FSOPT_PACK_INVAL_ATTRS = 0x00000008 FSOPT_ATTR_CMN_EXTENDED = 0x00000020 FSOPT_RETURN_REALDEV = 0x00000200 VOL_CAPABILITIES_FORMAT = 0 VOL_CAPABILITIES_INTERFACES = 1 VOL_CAP_FMT_PERSISTENTOBJECTIDS = 0x00000001 VOL_CAP_FMT_SYMBOLICLINKS = 0x00000002 VOL_CAP_FMT_HARDLINKS = 0x00000004 VOL_CAP_FMT_JOURNAL = 0x00000008 VOL_CAP_FMT_JOURNAL_ACTIVE = 0x00000010 VOL_CAP_FMT_NO_ROOT_TIMES = 0x00000020 VOL_CAP_FMT_SPARSE_FILES = 0x00000040 VOL_CAP_FMT_ZERO_RUNS = 0x00000080 VOL_CAP_FMT_CASE_SENSITIVE = 0x00000100 VOL_CAP_FMT_CASE_PRESERVING = 0x00000200 VOL_CAP_FMT_FAST_STATFS = 0x00000400 VOL_CAP_FMT_2TB_FILESIZE = 0x00000800 VOL_CAP_FMT_OPENDENYMODES = 0x00001000 VOL_CAP_FMT_HIDDEN_FILES = 0x00002000 VOL_CAP_FMT_PATH_FROM_ID = 0x00004000 VOL_CAP_FMT_NO_VOLUME_SIZES = 0x00008000 VOL_CAP_FMT_DECMPFS_COMPRESSION = 0x00010000 VOL_CAP_FMT_64BIT_OBJECT_IDS = 0x00020000 VOL_CAP_INT_SEARCHFS = 0x00000001 VOL_CAP_INT_ATTRLIST = 0x00000002 VOL_CAP_INT_NFSEXPORT = 0x00000004 VOL_CAP_INT_READDIRATTR = 0x00000008 VOL_CAP_INT_EXCHANGEDATA = 0x00000010 VOL_CAP_INT_COPYFILE = 0x00000020 VOL_CAP_INT_ALLOCATE = 0x00000040 VOL_CAP_INT_VOL_RENAME = 0x00000080 VOL_CAP_INT_ADVLOCK = 0x00000100 VOL_CAP_INT_FLOCK = 0x00000200 VOL_CAP_INT_EXTENDED_SECURITY = 0x00000400 VOL_CAP_INT_USERACCESS = 0x00000800 VOL_CAP_INT_MANLOCK = 0x00001000 VOL_CAP_INT_NAMEDSTREAMS = 0x00002000 VOL_CAP_INT_EXTENDED_ATTR = 0x00004000 VOL_CAP_INT_CLONE = 0x00010000 VOL_CAP_INT_SNAPSHOT = 0x00020000 VOL_CAP_INT_RENAME_SWAP = 0x00040000 VOL_CAP_INT_RENAME_EXCL = 0x00080000 VOL_CAP_INT_RENAME_OPENFAIL = 0x00100000 ATTR_CMN_NAME = 0x00000001 ATTR_CMN_DEVID = 0x00000002 ATTR_CMN_FSID = 0x00000004 ATTR_CMN_OBJTYPE = 0x00000008 ATTR_CMN_OBJTAG = 0x00000010 ATTR_CMN_OBJID = 0x00000020 ATTR_CMN_OBJPERMANENTID = 0x00000040 ATTR_CMN_PAROBJID = 0x00000080 ATTR_CMN_SCRIPT = 0x00000100 ATTR_CMN_CRTIME = 0x00000200 ATTR_CMN_MODTIME = 0x00000400 ATTR_CMN_CHGTIME = 0x00000800 ATTR_CMN_ACCTIME = 0x00001000 ATTR_CMN_BKUPTIME = 0x00002000 ATTR_CMN_FNDRINFO = 0x00004000 ATTR_CMN_OWNERID = 0x00008000 ATTR_CMN_GRPID = 0x00010000 ATTR_CMN_ACCESSMASK = 0x00020000 ATTR_CMN_FLAGS = 0x00040000 ATTR_CMN_GEN_COUNT = 0x00080000 ATTR_CMN_DOCUMENT_ID = 0x00100000 ATTR_CMN_USERACCESS = 0x00200000 ATTR_CMN_EXTENDED_SECURITY = 0x00400000 ATTR_CMN_UUID = 0x00800000 ATTR_CMN_GRPUUID = 0x01000000 ATTR_CMN_FILEID = 0x02000000 ATTR_CMN_PARENTID = 0x04000000 ATTR_CMN_FULLPATH = 0x08000000 ATTR_CMN_ADDEDTIME = 0x10000000 ATTR_CMN_ERROR = 0x20000000 ATTR_CMN_DATA_PROTECT_FLAGS = 0x40000000 ATTR_CMN_RETURNED_ATTRS = 0x80000000 ATTR_CMN_ALL_ATTRS = 0xFFFFFFFF ATTR_CMN_VALIDMASK = 0xFFFFFFFF ATTR_CMN_SETMASK = 0x51C7FF00 ATTR_CMN_VOLSETMASK = 0x00006700 ATTR_VOL_FSTYPE = 0x00000001 ATTR_VOL_SIGNATURE = 0x00000002 ATTR_VOL_SIZE = 0x00000004 ATTR_VOL_SPACEFREE = 0x00000008 ATTR_VOL_SPACEAVAIL = 0x00000010 ATTR_VOL_MINALLOCATION = 0x00000020 ATTR_VOL_ALLOCATIONCLUMP = 0x00000040 ATTR_VOL_IOBLOCKSIZE = 0x00000080 ATTR_VOL_OBJCOUNT = 0x00000100 ATTR_VOL_FILECOUNT = 0x00000200 ATTR_VOL_DIRCOUNT = 0x00000400 ATTR_VOL_MAXOBJCOUNT = 0x00000800 ATTR_VOL_MOUNTPOINT = 0x00001000 ATTR_VOL_NAME = 0x00002000 ATTR_VOL_MOUNTFLAGS = 0x00004000 ATTR_VOL_MOUNTEDDEVICE = 0x00008000 ATTR_VOL_ENCODINGSUSED = 0x00010000 ATTR_VOL_CAPABILITIES = 0x00020000 ATTR_VOL_UUID = 0x00040000 ATTR_VOL_QUOTA_SIZE = 0x10000000 ATTR_VOL_RESERVED_SIZE = 0x20000000 ATTR_VOL_ATTRIBUTES = 0x40000000 ATTR_VOL_INFO = 0x80000000 ATTR_VOL_ALL_ATTRS = 0xF007FFFF ATTR_DIR_LINKCOUNT = 0x00000001 ATTR_DIR_ENTRYCOUNT = 0x00000002 ATTR_DIR_MOUNTSTATUS = 0x00000004 DIR_MNTSTATUS_MNTPOINT = 0x00000001 DIR_MNTSTATUS_TRIGGER = 0x00000002 ATTR_DIR_ALLOCSIZE = 0x00000008 ATTR_DIR_IOBLOCKSIZE = 0x00000010 ATTR_DIR_DATALENGTH = 0x00000020 ATTR_DIR_ALL_ATTRS = 0x0000003F ATTR_DIR_VALIDMASK = 0x0000003F ATTR_DIR_SETMASK = 0x00000000 ATTR_FILE_LINKCOUNT = 0x00000001 ATTR_FILE_TOTALSIZE = 0x00000002 ATTR_FILE_ALLOCSIZE = 0x00000004 ATTR_FILE_IOBLOCKSIZE = 0x00000008 ATTR_FILE_DEVTYPE = 0x00000020 ATTR_FILE_FORKCOUNT = 0x00000080 ATTR_FILE_FORKLIST = 0x00000100 ATTR_FILE_DATALENGTH = 0x00000200 ATTR_FILE_DATAALLOCSIZE = 0x00000400 ATTR_FILE_RSRCLENGTH = 0x00001000 ATTR_FILE_RSRCALLOCSIZE = 0x00002000 ATTR_FILE_ALL_ATTRS = 0x000037FF ATTR_FILE_VALIDMASK = 0x000037FF ATTR_FILE_SETMASK = 0x00000020 # These are deprecated ATTR_FORK_TOTALSIZE = 0x00000001 ATTR_FORK_ALLOCSIZE = 0x00000002 ATTR_FORK_ALL_ATTRS = 0x00000003 # These go in the fork attribute field ATTR_CMNEXT_RELPATH = 0x00000004 ATTR_CMNEXT_PRIVATESIZE = 0x00000008 ATTR_CMNEXT_LINKID = 0x0000010 ATTR_CMNEXT_NOFIRMLINKPATH = 0x00000020 ATTR_CMNEXT_REALDEVID = 0x00000040 ATTR_CMNEXT_REALFSID = 0x00000080 ATTR_CMNEXT_CLONEID = 0x00000100 ATTR_CMNEXT_EXT_FLAGS = 0x00000200 ATTR_CMNEXT_RECURSIVE_GENCOUNT = 0x00000400 ATTR_CMNEXT_ALL_ATTRS = 0x000007FC ATTR_CMNEXT_VALIDMASK = 0x000007FC ATTR_CMNEXT_SETMASK = 0x00000000 ATTR_FORK_VALIDMASK = 0x00000003 ATTR_FORK_SETMASK = 0x00000000 # These can't be used ATTR_CMN_NAMEDATTRCOUNT = 0x00080000 ATTR_CMN_NAMEDATTRLIST = 0x00100000 ATTR_FILE_CLUMPSIZE = 0x00000010 ATTR_FILE_FILETYPE = 0x00000040 ATTR_FILE_DATAEXTENTS = 0x00000800 ATTR_FILE_RSRCEXTENTS = 0x00004000 class attrlist(Structure): _fields_ = [ ("bitmapcount", c_ushort), ("reserved", c_ushort), ("commonattr", c_uint), ("volattr", c_uint), ("dirattr", c_uint), ("fileattr", c_uint), ("forkattr", c_uint), ] class attribute_set_t(Structure): _fields_ = [ ("commonattr", c_uint), ("volattr", c_uint), ("dirattr", c_uint), ("fileattr", c_uint), ("forkattr", c_uint), ] class fsobj_id_t(Structure): _fields_ = [ ("fid_objno", c_uint), ("fid_generation", c_uint), ] class timespec(Structure): _fields_ = [ ("tv_sec", c_long), ("tv_nsec", c_long), ] class attrreference_t(Structure): _fields_ = [ ("attr_dataoffset", c_int), ("attr_length", c_uint), ] class fsid_t(Structure): _fields_ = [ ("val", c_uint * 2), ] class guid_t(Structure): _fields_ = [ ("g_guid", c_byte * 16), ] class kauth_ace(Structure): _fields_ = [ ("ace_applicable", guid_t), ("ace_flags", c_uint), ] class kauth_acl(Structure): _fields_ = [ ("acl_entrycount", c_uint), ("acl_flags", c_uint), ("acl_ace", kauth_ace * 128), ] class kauth_filesec(Structure): _fields_ = [ ("fsec_magic", c_uint), ("fsec_owner", guid_t), ("fsec_group", guid_t), ("fsec_acl", kauth_acl), ] class diskextent(Structure): _fields_ = [ ("startblock", c_uint), ("blockcount", c_uint), ] OSType = c_uint UInt16 = c_ushort SInt16 = c_short SInt32 = c_int class Point(Structure): _fields_ = [ ("x", SInt16), ("y", SInt16), ] class Rect(Structure): _fields_ = [ ("x", SInt16), ("y", SInt16), ("w", SInt16), ("h", SInt16), ] class FileInfo(Structure): _fields_ = [ ("fileType", OSType), ("fileCreator", OSType), ("finderFlags", UInt16), ("location", Point), ("reservedField", UInt16), ("reserved1", SInt16 * 4), ("extendedFinderFlags", UInt16), ("reserved2", SInt16), ("putAwayFolderID", SInt32), ] class FolderInfo(Structure): _fields_ = [ ("windowBounds", Rect), ("finderFlags", UInt16), ("location", Point), ("reservedField", UInt16), ("scrollPosition", Point), ("reserved1", SInt32), ("extendedFinderFlags", UInt16), ("reserved2", SInt16), ("putAwayFolderID", SInt32), ] class FinderInfo(Union): _fields_ = [ ("fileInfo", FileInfo), ("folderInfo", FolderInfo), ] extentrecord = diskextent * 8 vol_capabilities_set_t = c_uint * 4 class vol_capabilities_attr_t(Structure): _fields_ = [ ("capabilities", vol_capabilities_set_t), ("valid", vol_capabilities_set_t), ] class vol_attributes_attr_t(Structure): _fields_ = [ ("validattr", attribute_set_t), ("nativeattr", attribute_set_t), ] dev_t = c_uint fsobj_type_t = c_uint VNON = 0 VREG = 1 VDIR = 2 VBLK = 3 VCHR = 4 VLNK = 5 VSOCK = 6 VFIFO = 7 VBAD = 8 VSTR = 9 VCPLX = 10 fsobj_tag_t = c_uint VT_NON = 0 VT_UFS = 1 VT_NFS = 2 VT_MFS = 3 VT_MSDOSFS = 4 VT_LFS = 5 VT_LOFS = 6 VT_FDESC = 7 VT_PORTAL = 8 VT_NULL = 9 VT_UMAP = 10 VT_KERNFS = 11 VT_PROCFS = 12 VT_AFS = 13 VT_ISOFS = 14 VT_UNION = 15 VT_HFS = 16 VT_ZFS = 17 VT_DEVFS = 18 VT_WEBDAV = 19 VT_UDF = 20 VT_AFP = 21 VT_CDDA = 22 VT_CIFS = 23 VT_OTHER = 24 fsfile_type_t = c_uint fsvolid_t = c_uint text_encoding_t = c_uint uid_t = c_uint gid_t = c_uint int32_t = c_int uint32_t = c_uint int64_t = c_longlong uint64_t = c_ulonglong off_t = c_long size_t = c_ulong uuid_t = c_byte * 16 NAME_MAX = 255 PATH_MAX = 1024 FSTYPE_MAX = 16 class struct_statfs(Structure): _fields_ = [ ("f_bsize", uint32_t), ("f_iosize", int32_t), ("f_blocks", uint64_t), ("f_bfree", uint64_t), ("f_bavail", uint64_t), ("f_files", uint64_t), ("f_ffree", uint64_t), ("f_fsid", fsid_t), ("f_owner", uid_t), ("f_type", uint32_t), ("f_flags", uint32_t), ("f_fssubtype", uint32_t), ("f_fstypename", c_char * FSTYPE_MAX), ("f_mntonname", c_char * PATH_MAX), ("f_mntfromname", c_char * PATH_MAX), ("f_flags_ext", uint32_t), ("f_reserved", uint32_t * 7), ] # Calculate the maximum number of bytes required for the attribute buffer _attr_info = ( # Common attributes (0, ATTR_CMN_RETURNED_ATTRS, sizeof(attribute_set_t)), (0, ATTR_CMN_NAME, sizeof(attrreference_t) + NAME_MAX * 3 + 1), (0, ATTR_CMN_DEVID, sizeof(dev_t)), (0, ATTR_CMN_FSID, sizeof(fsid_t)), (0, ATTR_CMN_OBJTYPE, sizeof(fsobj_type_t)), (0, ATTR_CMN_OBJTAG, sizeof(fsobj_tag_t)), (0, ATTR_CMN_OBJID, sizeof(fsobj_id_t)), (0, ATTR_CMN_OBJPERMANENTID, sizeof(fsobj_id_t)), (0, ATTR_CMN_PAROBJID, sizeof(fsobj_id_t)), (0, ATTR_CMN_SCRIPT, sizeof(text_encoding_t)), (0, ATTR_CMN_CRTIME, sizeof(timespec)), (0, ATTR_CMN_MODTIME, sizeof(timespec)), (0, ATTR_CMN_CHGTIME, sizeof(timespec)), (0, ATTR_CMN_ACCTIME, sizeof(timespec)), (0, ATTR_CMN_BKUPTIME, sizeof(timespec)), (0, ATTR_CMN_FNDRINFO, sizeof(FinderInfo)), (0, ATTR_CMN_OWNERID, sizeof(uid_t)), (0, ATTR_CMN_GRPID, sizeof(gid_t)), (0, ATTR_CMN_ACCESSMASK, sizeof(uint32_t)), (0, ATTR_CMN_NAMEDATTRCOUNT, None), (0, ATTR_CMN_NAMEDATTRLIST, None), (0, ATTR_CMN_FLAGS, sizeof(uint32_t)), (0, ATTR_CMN_GEN_COUNT, sizeof(uint32_t)), (0, ATTR_CMN_DOCUMENT_ID, sizeof(uint32_t)), (0, ATTR_CMN_USERACCESS, sizeof(uint32_t)), (0, ATTR_CMN_EXTENDED_SECURITY, sizeof(attrreference_t) + sizeof(kauth_filesec)), (0, ATTR_CMN_UUID, sizeof(guid_t)), (0, ATTR_CMN_GRPUUID, sizeof(guid_t)), (0, ATTR_CMN_FILEID, sizeof(uint64_t)), (0, ATTR_CMN_PARENTID, sizeof(uint64_t)), (0, ATTR_CMN_FULLPATH, sizeof(attrreference_t) + PATH_MAX), (0, ATTR_CMN_ADDEDTIME, sizeof(timespec)), (0, ATTR_CMN_DATA_PROTECT_FLAGS, sizeof(uint32_t)), # Volume attributes (1, ATTR_VOL_FSTYPE, sizeof(uint32_t)), (1, ATTR_VOL_SIGNATURE, sizeof(uint32_t)), (1, ATTR_VOL_SIZE, sizeof(off_t)), (1, ATTR_VOL_SPACEFREE, sizeof(off_t)), (1, ATTR_VOL_SPACEAVAIL, sizeof(off_t)), (1, ATTR_VOL_MINALLOCATION, sizeof(off_t)), (1, ATTR_VOL_ALLOCATIONCLUMP, sizeof(off_t)), (1, ATTR_VOL_IOBLOCKSIZE, sizeof(uint32_t)), (1, ATTR_VOL_OBJCOUNT, sizeof(uint32_t)), (1, ATTR_VOL_FILECOUNT, sizeof(uint32_t)), (1, ATTR_VOL_DIRCOUNT, sizeof(uint32_t)), (1, ATTR_VOL_MAXOBJCOUNT, sizeof(uint32_t)), (1, ATTR_VOL_MOUNTPOINT, sizeof(attrreference_t) + PATH_MAX), (1, ATTR_VOL_NAME, sizeof(attrreference_t) + NAME_MAX + 1), (1, ATTR_VOL_MOUNTFLAGS, sizeof(uint32_t)), (1, ATTR_VOL_MOUNTEDDEVICE, sizeof(attrreference_t) + PATH_MAX), (1, ATTR_VOL_ENCODINGSUSED, sizeof(c_ulonglong)), (1, ATTR_VOL_CAPABILITIES, sizeof(vol_capabilities_attr_t)), (1, ATTR_VOL_UUID, sizeof(uuid_t)), (1, ATTR_VOL_QUOTA_SIZE, sizeof(off_t)), (1, ATTR_VOL_RESERVED_SIZE, sizeof(off_t)), (1, ATTR_VOL_ATTRIBUTES, sizeof(vol_attributes_attr_t)), # Directory attributes (2, ATTR_DIR_LINKCOUNT, sizeof(uint32_t)), (2, ATTR_DIR_ENTRYCOUNT, sizeof(uint32_t)), (2, ATTR_DIR_MOUNTSTATUS, sizeof(uint32_t)), (2, ATTR_DIR_ALLOCSIZE, sizeof(off_t)), (2, ATTR_DIR_IOBLOCKSIZE, sizeof(uint32_t)), (2, ATTR_DIR_DATALENGTH, sizeof(off_t)), # File attributes (3, ATTR_FILE_LINKCOUNT, sizeof(uint32_t)), (3, ATTR_FILE_TOTALSIZE, sizeof(off_t)), (3, ATTR_FILE_ALLOCSIZE, sizeof(off_t)), (3, ATTR_FILE_IOBLOCKSIZE, sizeof(uint32_t)), (3, ATTR_FILE_CLUMPSIZE, sizeof(uint32_t)), (3, ATTR_FILE_DEVTYPE, sizeof(uint32_t)), (3, ATTR_FILE_FILETYPE, sizeof(uint32_t)), (3, ATTR_FILE_FORKCOUNT, sizeof(uint32_t)), (3, ATTR_FILE_FORKLIST, None), (3, ATTR_FILE_DATALENGTH, sizeof(off_t)), (3, ATTR_FILE_DATAALLOCSIZE, sizeof(off_t)), (3, ATTR_FILE_DATAEXTENTS, sizeof(extentrecord)), (3, ATTR_FILE_RSRCLENGTH, sizeof(off_t)), (3, ATTR_FILE_RSRCALLOCSIZE, sizeof(off_t)), (3, ATTR_FILE_RSRCEXTENTS, sizeof(extentrecord)), # Fork attributes (4, ATTR_FORK_TOTALSIZE, sizeof(off_t)), (4, ATTR_FORK_ALLOCSIZE, sizeof(off_t)), # Extended common attributes (4, ATTR_CMNEXT_RELPATH, sizeof(attrreference_t) + PATH_MAX), (4, ATTR_CMNEXT_PRIVATESIZE, sizeof(off_t)), (4, ATTR_CMNEXT_LINKID, sizeof(uint64_t)), (4, ATTR_CMNEXT_NOFIRMLINKPATH, sizeof(attrreference_t) + PATH_MAX), (4, ATTR_CMNEXT_REALDEVID, sizeof(dev_t)), (4, ATTR_CMNEXT_REALFSID, sizeof(fsid_t)), (4, ATTR_CMNEXT_CLONEID, sizeof(uint64_t)), (4, ATTR_CMNEXT_EXT_FLAGS, sizeof(uint64_t)), ) def _attrbuf_size(attrs): size = 4 for entry in _attr_info: if attrs[entry[0]] & entry[1]: if entry[2] is None: raise ValueError( "Unsupported attribute (%u, %x)" % (entry[0], entry[1]) ) size += entry[2] return size _getattrlist = libc.getattrlist _getattrlist.argtypes = [c_char_p, POINTER(attrlist), c_void_p, c_ulong, c_ulong] _getattrlist.restype = c_int _fgetattrlist = libc.fgetattrlist _fgetattrlist.argtypes = [c_int, POINTER(attrlist), c_void_p, c_ulong, c_ulong] _fgetattrlist.restype = c_int try: _statfs = libc["statfs$INODE64"] except (KeyError, AttributeError): _statfs = libc["statfs"] _statfs.argtypes = [ c_char_p, POINTER(struct_statfs), ] _statfs.restype = c_int try: _fstatfs = libc["fstatfs$INODE64"] except (KeyError, AttributeError): _fstatfs = libc["fstatfs"] _fstatfs.argtypes = [ c_int, POINTER(struct_statfs), ] _fstatfs.restype = c_int def _datetime_from_timespec(ts): td = datetime.timedelta(seconds=ts.tv_sec + 1.0e-9 * ts.tv_nsec) return unix_epoch + td def _decode_utf8_nul(sz): nul = sz.find(b"\0") if nul > -1: sz = sz[:nul] return sz.decode("utf-8") def _decode_attrlist_result(buf, attrs, options): result = [] assert len(buf) >= 4 total_size = uint32_t.from_buffer(buf, 0).value assert total_size <= len(buf) offset = 4 # Common attributes if attrs[0] & ATTR_CMN_RETURNED_ATTRS: a = attribute_set_t.from_buffer(buf, offset) result.append(a) offset += sizeof(attribute_set_t) if not (options & FSOPT_PACK_INVAL_ATTRS): attrs = [a.commonattr, a.volattr, a.dirattr, a.fileattr, a.forkattr] if attrs[0] & ATTR_CMN_NAME: a = attrreference_t.from_buffer(buf, offset) ofs = offset + a.attr_dataoffset name = _decode_utf8_nul(buf[ofs : ofs + a.attr_length]) offset += sizeof(attrreference_t) result.append(name) if attrs[0] & ATTR_CMN_DEVID: a = dev_t.from_buffer(buf, offset) offset += sizeof(dev_t) result.append(a.value) if attrs[0] & ATTR_CMN_FSID: a = fsid_t.from_buffer(buf, offset) offset += sizeof(fsid_t) result.append(a) if attrs[0] & ATTR_CMN_OBJTYPE: a = fsobj_type_t.from_buffer(buf, offset) offset += sizeof(fsobj_type_t) result.append(a.value) if attrs[0] & ATTR_CMN_OBJTAG: a = fsobj_tag_t.from_buffer(buf, offset) offset += sizeof(fsobj_tag_t) result.append(a.value) if attrs[0] & ATTR_CMN_OBJID: a = fsobj_id_t.from_buffer(buf, offset) offset += sizeof(fsobj_id_t) result.append(a) if attrs[0] & ATTR_CMN_OBJPERMANENTID: a = fsobj_id_t.from_buffer(buf, offset) offset += sizeof(fsobj_id_t) result.append(a) if attrs[0] & ATTR_CMN_PAROBJID: a = fsobj_id_t.from_buffer(buf, offset) offset += sizeof(fsobj_id_t) result.append(a) if attrs[0] & ATTR_CMN_SCRIPT: a = text_encoding_t.from_buffer(buf, offset) offset += sizeof(text_encoding_t) result.append(a.value) if attrs[0] & ATTR_CMN_CRTIME: a = timespec.from_buffer(buf, offset) offset += sizeof(timespec) result.append(_datetime_from_timespec(a)) if attrs[0] & ATTR_CMN_MODTIME: a = timespec.from_buffer(buf, offset) offset += sizeof(timespec) result.append(_datetime_from_timespec(a)) if attrs[0] & ATTR_CMN_CHGTIME: a = timespec.from_buffer(buf, offset) offset += sizeof(timespec) result.append(_datetime_from_timespec(a)) if attrs[0] & ATTR_CMN_ACCTIME: a = timespec.from_buffer(buf, offset) offset += sizeof(timespec) result.append(_datetime_from_timespec(a)) if attrs[0] & ATTR_CMN_BKUPTIME: a = timespec.from_buffer(buf, offset) offset += sizeof(timespec) result.append(_datetime_from_timespec(a)) if attrs[0] & ATTR_CMN_FNDRINFO: a = FinderInfo.from_buffer(buf, offset) offset += sizeof(FinderInfo) result.append(a) if attrs[0] & ATTR_CMN_OWNERID: a = uid_t.from_buffer(buf, offset) offset += sizeof(uid_t) result.append(a.value) if attrs[0] & ATTR_CMN_GRPID: a = gid_t.from_buffer(buf, offset) offset += sizeof(gid_t) result.append(a.value) if attrs[0] & ATTR_CMN_ACCESSMASK: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[0] & ATTR_CMN_FLAGS: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[0] & ATTR_CMN_GEN_COUNT: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[0] & ATTR_CMN_DOCUMENT_ID: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[0] & ATTR_CMN_USERACCESS: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[0] & ATTR_CMN_EXTENDED_SECURITY: a = attrreference_t.from_buffer(buf, offset) ofs = offset + a.attr_dataoffset offset += sizeof(attrreference_t) ec = uint32_t.from_buffer(buf, ofs + 36).value class kauth_acl(Structure): _fields_ = [ ("acl_entrycount", c_uint), ("acl_flags", c_uint), ("acl_ace", kauth_ace * ec), ] class kauth_filesec(Structure): _fields_ = [ ("fsec_magic", c_uint), ("fsec_owner", guid_t), ("fsec_group", guid_t), ("fsec_acl", kauth_acl), ] a = kauth_filesec.from_buffer(buf, ofs) result.append(a) if attrs[0] & ATTR_CMN_UUID: result.append(uuid.UUID(bytes=buf[offset : offset + 16])) offset += sizeof(guid_t) if attrs[0] & ATTR_CMN_GRPUUID: result.append(uuid.UUID(bytes=buf[offset : offset + 16])) offset += sizeof(guid_t) if attrs[0] & ATTR_CMN_FILEID: a = uint64_t.from_buffer(buf, offset) offset += sizeof(uint64_t) result.append(a.value) if attrs[0] & ATTR_CMN_PARENTID: a = uint64_t.from_buffer(buf, offset) offset += sizeof(uint64_t) result.append(a.value) if attrs[0] & ATTR_CMN_FULLPATH: a = attrreference_t.from_buffer(buf, offset) ofs = offset + a.attr_dataoffset path = _decode_utf8_nul(buf[ofs : ofs + a.attr_length]) offset += sizeof(attrreference_t) result.append(path) if attrs[0] & ATTR_CMN_ADDEDTIME: a = timespec.from_buffer(buf, offset) offset += sizeof(timespec) result.append(_datetime_from_timespec(a)) if attrs[0] & ATTR_CMN_DATA_PROTECT_FLAGS: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) # Volume attributes if attrs[1] & ATTR_VOL_FSTYPE: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[1] & ATTR_VOL_SIGNATURE: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[1] & ATTR_VOL_SIZE: a = off_t.from_buffer(buf, offset) offset += sizeof(off_t) result.append(a.value) if attrs[1] & ATTR_VOL_SPACEFREE: a = off_t.from_buffer(buf, offset) offset += sizeof(off_t) result.append(a.value) if attrs[1] & ATTR_VOL_SPACEAVAIL: a = off_t.from_buffer(buf, offset) offset += sizeof(off_t) result.append(a.value) if attrs[1] & ATTR_VOL_MINALLOCATION: a = off_t.from_buffer(buf, offset) offset += sizeof(off_t) result.append(a.value) if attrs[1] & ATTR_VOL_ALLOCATIONCLUMP: a = off_t.from_buffer(buf, offset) offset += sizeof(off_t) result.append(a.value) if attrs[1] & ATTR_VOL_IOBLOCKSIZE: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[1] & ATTR_VOL_OBJCOUNT: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[1] & ATTR_VOL_FILECOUNT: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[1] & ATTR_VOL_DIRCOUNT: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[1] & ATTR_VOL_MAXOBJCOUNT: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[1] & ATTR_VOL_MOUNTPOINT: a = attrreference_t.from_buffer(buf, offset) ofs = offset + a.attr_dataoffset path = _decode_utf8_nul(buf[ofs : ofs + a.attr_length]) offset += sizeof(attrreference_t) result.append(path) if attrs[1] & ATTR_VOL_NAME: a = attrreference_t.from_buffer(buf, offset) ofs = offset + a.attr_dataoffset name = _decode_utf8_nul(buf[ofs : ofs + a.attr_length]) offset += sizeof(attrreference_t) result.append(name) if attrs[1] & ATTR_VOL_MOUNTFLAGS: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[1] & ATTR_VOL_MOUNTEDDEVICE: a = attrreference_t.from_buffer(buf, offset) ofs = offset + a.attr_dataoffset path = _decode_utf8_nul(buf[ofs : ofs + a.attr_length]) offset += sizeof(attrreference_t) result.append(path) if attrs[1] & ATTR_VOL_ENCODINGSUSED: a = c_ulonglong.from_buffer(buf, offset) offset += sizeof(c_ulonglong) result.append(a.value) if attrs[1] & ATTR_VOL_CAPABILITIES: a = vol_capabilities_attr_t.from_buffer(buf, offset) offset += sizeof(vol_capabilities_attr_t) result.append(a) if attrs[1] & ATTR_VOL_UUID: result.append(uuid.UUID(bytes=buf[offset : offset + 16])) offset += sizeof(uuid_t) if attrs[1] & ATTR_VOL_QUOTA_SIZE: a = off_t.from_buffer(buf, offset) offset += sizeof(off_t) result.append(a.value) if attrs[1] & ATTR_VOL_RESERVED_SIZE: a = off_t.from_buffer(buf, offset) offset += sizeof(off_t) result.append(a.value) if attrs[1] & ATTR_VOL_ATTRIBUTES: a = vol_attributes_attr_t.from_buffer(buf, offset) offset += sizeof(vol_attributes_attr_t) result.append(a) # Directory attributes if attrs[2] & ATTR_DIR_LINKCOUNT: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[2] & ATTR_DIR_ENTRYCOUNT: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[2] & ATTR_DIR_MOUNTSTATUS: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[2] & ATTR_DIR_ALLOCSIZE: a = off_t.from_buffer(buf, offset) offset += sizeof(off_t) result.append(a.value) if attrs[2] & ATTR_DIR_IOBLOCKSIZE: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[2] & ATTR_DIR_DATALENGTH: a = off_t.from_buffer(buf, offset) offset += sizeof(off_t) result.append(a.value) # File attributes if attrs[3] & ATTR_FILE_LINKCOUNT: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[3] & ATTR_FILE_TOTALSIZE: a = off_t.from_buffer(buf, offset) offset += sizeof(off_t) result.append(a.value) if attrs[3] & ATTR_FILE_ALLOCSIZE: a = off_t.from_buffer(buf, offset) offset += sizeof(off_t) result.append(a.value) if attrs[3] & ATTR_FILE_IOBLOCKSIZE: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[3] & ATTR_FILE_CLUMPSIZE: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[3] & ATTR_FILE_DEVTYPE: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[3] & ATTR_FILE_FILETYPE: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[3] & ATTR_FILE_FORKCOUNT: a = uint32_t.from_buffer(buf, offset) offset += sizeof(uint32_t) result.append(a.value) if attrs[3] & ATTR_FILE_DATALENGTH: a = off_t.from_buffer(buf, offset) offset += sizeof(off_t) result.append(a.value) if attrs[3] & ATTR_FILE_DATAALLOCSIZE: a = off_t.from_buffer(buf, offset) offset += sizeof(off_t) result.append(a.value) if attrs[3] & ATTR_FILE_DATAEXTENTS: a = extentrecord.from_buffer(buf, offset) offset += sizeof(extentrecord) result.append(a.value) if attrs[3] & ATTR_FILE_RSRCLENGTH: a = off_t.from_buffer(buf, offset) offset += sizeof(off_t) result.append(a.value) if attrs[3] & ATTR_FILE_RSRCALLOCSIZE: a = off_t.from_buffer(buf, offset) offset += sizeof(off_t) result.append(a.value) if attrs[3] & ATTR_FILE_RSRCEXTENTS: a = extentrecord.from_buffer(buf, offset) offset += sizeof(extentrecord) result.append(a.value) # Fork attributes if attrs[4] & ATTR_FORK_TOTALSIZE: a = off_t.from_buffer(buf, offset) offset += sizeof(off_t) result.append(a.value) if attrs[4] & ATTR_FORK_ALLOCSIZE: a = off_t.from_buffer(buf, offset) offset += sizeof(off_t) result.append(a.value) # Extended common attributes if attrs[4] & ATTR_CMNEXT_RELPATH: a = attrreference_t.from_buffer(buf, offset) ofs = offset + a.attr_dataoffset path = _decode_utf8_nul(buf[ofs : ofs + a.attr_length]) offset += sizeof(attrreference_t) result.append(path) if attrs[4] & ATTR_CMNEXT_PRIVATESIZE: a = off_t.from_buffer(buf, offset) offset += sizeof(off_t) result.append(a.value) if attrs[4] & ATTR_CMNEXT_LINKID: a = uint64_t.from_buffer(buf, offset) offset += sizeof(uint64_t) result.append(a.value) if attrs[4] & ATTR_CMNEXT_NOFIRMLINKPATH: a = attrreference_t.from_buffer(buf, offset) ofs = offset + a.attr_dataoffset path = _decode_utf8_nul(buf[ofs : ofs + a.attr_length]) offset += sizeof(attrreference_t) result.append(path) if attrs[4] & ATTR_CMNEXT_REALDEVID: a = dev_t.from_buffer(buf, offset) offset += sizeof(dev_t) result.append(a.value) if attrs[4] & ATTR_CMNEXT_REALFSID: a = fsid_t.from_buffer(buf, offset) offset += sizeof(fsid_t) result.append(a.value) if attrs[4] & ATTR_CMNEXT_CLONEID: a = uint64_t.from_buffer(buf, offset) offset += sizeof(uint64_t) result.append(a.value) if attrs[4] & ATTR_CMNEXT_EXT_FLAGS: a = uint64_t.from_buffer(buf, offset) offset += sizeof(uint64_t) result.append(a.value) return result # Sadly, ctypes.get_errno() seems not to work __error = libc.__error __error.restype = POINTER(c_int) def _get_errno(): return __error().contents.value def getattrlist(path, attrs, options): if not isinstance(path, bytes): path = path.encode("utf-8") attrs = list(attrs) if attrs[1]: attrs[1] |= ATTR_VOL_INFO alist = attrlist( bitmapcount=5, commonattr=attrs[0], volattr=attrs[1], dirattr=attrs[2], fileattr=attrs[3], forkattr=attrs[4], ) bufsize = _attrbuf_size(attrs) buf = create_string_buffer(bufsize) ret = _getattrlist( path, byref(alist), buf, bufsize, options | FSOPT_REPORT_FULLSIZE ) if ret < 0: err = _get_errno() raise OSError(err, os.strerror(err), path) return _decode_attrlist_result(buf, attrs, options) def fgetattrlist(fd, attrs, options): if hasattr(fd, "fileno"): fd = fd.fileno() attrs = list(attrs) if attrs[1]: attrs[1] |= ATTR_VOL_INFO alist = attrlist( bitmapcount=5, commonattr=attrs[0], volattr=attrs[1], dirattr=attrs[2], fileattr=attrs[3], forkattr=attrs[4], ) bufsize = _attrbuf_size(attrs) buf = create_string_buffer(bufsize) ret = _fgetattrlist(fd, byref(alist), buf, bufsize, options | FSOPT_REPORT_FULLSIZE) if ret < 0: err = _get_errno() raise OSError(err, os.strerror(err)) return _decode_attrlist_result(buf, attrs, options) def statfs(path): if not isinstance(path, bytes): path = path.encode("utf-8") result = struct_statfs() ret = _statfs(path, byref(result)) if ret < 0: err = _get_errno() raise OSError(err, os.strerror(err), path) return result def fstatfs(fd): if hasattr(fd, "fileno"): fd = fd.fileno() result = struct_statfs() ret = _fstatfs(fd, byref(result)) if ret < 0: err = _get_errno() raise OSError(err, os.strerror(err)) return result qbs-src-2.5.1/src/3rdparty/python/lib/python3.9/site-packages/mac_alias/qt_attribution.json0000644000175100001660000000067514744424375031257 0ustar runnerdocker{ "Id": "mac_alias", "Name": "mac_alias", "QDocModule": "qbs", "QtUsage": "Used in the qbs dmg module for building Apple disk images.", "Description": "Generate/parse Mac OS Alias records from Python", "Homepage": "https://github.com/al45tair/mac_alias", "Version": "2.0.6", "License": "MIT License", "LicenseId": "MIT", "LicenseFile": "LICENSE", "Copyright": "Copyright (c) 2014 Alastair Houghton" } qbs-src-2.5.1/src/3rdparty/python/lib/python3.9/site-packages/mac_alias/__init__.py0000644000175100001660000000210214744424375027410 0ustar runnerdocker# flake8: noqa from .alias import * from .bookmark import * __version__ = "2.2.2" __all__ = [ "__version__", "ALIAS_KIND_FILE", "ALIAS_KIND_FOLDER", "ALIAS_HFS_VOLUME_SIGNATURE", "ALIAS_FIXED_DISK", "ALIAS_NETWORK_DISK", "ALIAS_400KB_FLOPPY_DISK", "ALIAS_800KB_FLOPPY_DISK", "ALIAS_1_44MB_FLOPPY_DISK", "ALIAS_EJECTABLE_DISK", "ALIAS_NO_CNID", "kBookmarkPath", "kBookmarkCNIDPath", "kBookmarkFileProperties", "kBookmarkFileName", "kBookmarkFileID", "kBookmarkFileCreationDate", "kBookmarkTOCPath", "kBookmarkVolumePath", "kBookmarkVolumeURL", "kBookmarkVolumeName", "kBookmarkVolumeUUID", "kBookmarkVolumeSize", "kBookmarkVolumeCreationDate", "kBookmarkVolumeProperties", "kBookmarkContainingFolder", "kBookmarkUserName", "kBookmarkUID", "kBookmarkWasFileReference", "kBookmarkCreationOptions", "kBookmarkURLLengths", "kBookmarkSecurityExtension", "AppleShareInfo", "VolumeInfo", "TargetInfo", "Alias", "Bookmark", "Data", "URL", ] qbs-src-2.5.1/src/3rdparty/python/lib/python3.9/site-packages/mac_alias/utils.py0000644000175100001660000000063114744424375027016 0ustar runnerdockerimport datetime ZERO = datetime.timedelta(0) class UTC(datetime.tzinfo): def utcoffset(self, dt): return ZERO def dst(self, dt): return ZERO def tzname(self, dt): return "UTC" utc = UTC() mac_epoch = datetime.datetime(1904, 1, 1, 0, 0, 0, 0, utc) unix_epoch = datetime.datetime(1970, 1, 1, 0, 0, 0, 0, utc) osx_epoch = datetime.datetime(2001, 1, 1, 0, 0, 0, 0, utc) qbs-src-2.5.1/src/3rdparty/python/lib/python3.9/site-packages/mac_alias/alias.py0000644000175100001660000006047014744424375026756 0ustar runnerdockerimport datetime import io import os import os.path import struct import sys from unicodedata import normalize if sys.platform == "darwin": from . import osx from .utils import mac_epoch ALIAS_KIND_FILE = 0 ALIAS_KIND_FOLDER = 1 ALIAS_HFS_VOLUME_SIGNATURE = b"H+" ALIAS_FILESYSTEM_UDF = "UDF (CD/DVD)" ALIAS_FILESYSTEM_FAT32 = "FAT32" ALIAS_FILESYSTEM_EXFAT = "exFAT" ALIAS_FILESYSTEM_HFSX = "HFSX" ALIAS_FILESYSTEM_HFSPLUS = "HFS+" ALIAS_FILESYSTEM_FTP = "FTP" ALIAS_FILESYSTEM_NTFS = "NTFS" ALIAS_FILESYSTEM_UNKNOWN = "unknown" ALIAS_FIXED_DISK = 0 ALIAS_NETWORK_DISK = 1 ALIAS_400KB_FLOPPY_DISK = 2 ALIAS_800KB_FLOPPY_DISK = 3 ALIAS_1_44MB_FLOPPY_DISK = 4 ALIAS_EJECTABLE_DISK = 5 ALIAS_NO_CNID = 0xFFFFFFFF ALIAS_FSTYPE_MAP = { # Version 2 aliases b"HX": ALIAS_FILESYSTEM_HFSX, b"H+": ALIAS_FILESYSTEM_HFSPLUS, # Version 3 aliases b"BDcu": ALIAS_FILESYSTEM_UDF, b"BDIS": ALIAS_FILESYSTEM_FAT32, b"BDxF": ALIAS_FILESYSTEM_EXFAT, b"HX\0\0": ALIAS_FILESYSTEM_HFSX, b"H+\0\0": ALIAS_FILESYSTEM_HFSPLUS, b"KG\0\0": ALIAS_FILESYSTEM_FTP, b"NTcu": ALIAS_FILESYSTEM_NTFS, } def encode_utf8(s): if isinstance(s, bytes): return s return s.encode("utf-8") def decode_utf8(s): if isinstance(s, bytes): return s.decode("utf-8") return s class AppleShareInfo: def __init__(self, zone=None, server=None, user=None): #: The AppleShare zone self.zone = zone #: The AFP server self.server = server #: The username self.user = user def __repr__(self): return "AppleShareInfo({!r},{!r},{!r})".format( self.zone, self.server, self.user ) class VolumeInfo: def __init__( self, name, creation_date, fs_type, disk_type, attribute_flags, fs_id, appleshare_info=None, driver_name=None, posix_path=None, disk_image_alias=None, dialup_info=None, network_mount_info=None, ): #: The name of the volume on which the target resides self.name = name #: The creation date of the target's volume self.creation_date = creation_date #: The filesystem type #: (for v2 aliases, this is a 2-character code; for v3 aliases, a #: 4-character code). self.fs_type = fs_type #: The type of disk; should be one of #: #: * ALIAS_FIXED_DISK #: * ALIAS_NETWORK_DISK #: * ALIAS_400KB_FLOPPY_DISK #: * ALIAS_800KB_FLOPPY_DISK #: * ALIAS_1_44MB_FLOPPY_DISK #: * ALIAS_EJECTABLE_DISK self.disk_type = disk_type #: Filesystem attribute flags (from HFS volume header) self.attribute_flags = attribute_flags #: Filesystem identifier self.fs_id = fs_id #: AppleShare information (for automatic remounting of network shares) #: *(optional)* self.appleshare_info = appleshare_info #: Driver name (*probably* contains a disk driver name on older Macs) #: *(optional)* self.driver_name = driver_name #: POSIX path of the mount point of the target's volume #: *(optional)* self.posix_path = posix_path #: :class:`Alias` object pointing at the disk image on which the #: target's volume resides *(optional)* self.disk_image_alias = disk_image_alias #: Dialup information (for automatic establishment of dialup connections) self.dialup_info = dialup_info #: Network mount information (for automatic remounting) self.network_mount_info = network_mount_info @property def filesystem_type(self): return ALIAS_FSTYPE_MAP.get(self.fs_type, ALIAS_FILESYSTEM_UNKNOWN) def __repr__(self): args = [ "name", "creation_date", "fs_type", "disk_type", "attribute_flags", "fs_id", ] values = [] for a in args: v = getattr(self, a) values.append(repr(v)) kwargs = [ "appleshare_info", "driver_name", "posix_path", "disk_image_alias", "dialup_info", "network_mount_info", ] for a in kwargs: v = getattr(self, a) if v is not None: values.append(f"{a}={v!r}") return "VolumeInfo(%s)" % ",".join(values) class TargetInfo: def __init__( self, kind, filename, folder_cnid, cnid, creation_date, creator_code, type_code, levels_from=-1, levels_to=-1, folder_name=None, cnid_path=None, carbon_path=None, posix_path=None, user_home_prefix_len=None, ): #: Either ALIAS_KIND_FILE or ALIAS_KIND_FOLDER self.kind = kind #: The filename of the target self.filename = filename #: The CNID (Catalog Node ID) of the target's containing folder; #: CNIDs are similar to but different than traditional UNIX inode #: numbers self.folder_cnid = folder_cnid #: The CNID (Catalog Node ID) of the target self.cnid = cnid #: The target's *creation* date. self.creation_date = creation_date #: The target's Mac creator code (a four-character binary string) self.creator_code = creator_code #: The target's Mac type code (a four-character binary string) self.type_code = type_code #: The depth of the alias? Always seems to be -1 on OS X. self.levels_from = levels_from #: The depth of the target? Always seems to be -1 on OS X. self.levels_to = levels_to #: The (POSIX) name of the target's containing folder. *(optional)* self.folder_name = folder_name #: The path from the volume root as a sequence of CNIDs. *(optional)* self.cnid_path = cnid_path #: The Carbon path of the target *(optional)* self.carbon_path = carbon_path #: The POSIX path of the target relative to the volume root. Note #: that this may or may not have a leading '/' character, but it is #: always relative to the containing volume. *(optional)* self.posix_path = posix_path #: If the path points into a user's home folder, the number of folders #: deep that we go before we get to that home folder. *(optional)* self.user_home_prefix_len = user_home_prefix_len def __repr__(self): args = [ "kind", "filename", "folder_cnid", "cnid", "creation_date", "creator_code", "type_code", ] values = [] for a in args: v = getattr(self, a) values.append(repr(v)) if self.levels_from != -1: values.append("levels_from=%r" % self.levels_from) if self.levels_to != -1: values.append("levels_to=%r" % self.levels_to) kwargs = [ "folder_name", "cnid_path", "carbon_path", "posix_path", "user_home_prefix_len", ] for a in kwargs: v = getattr(self, a) values.append(f"{a}={v!r}") return "TargetInfo(%s)" % ",".join(values) TAG_CARBON_FOLDER_NAME = 0 TAG_CNID_PATH = 1 TAG_CARBON_PATH = 2 TAG_APPLESHARE_ZONE = 3 TAG_APPLESHARE_SERVER_NAME = 4 TAG_APPLESHARE_USERNAME = 5 TAG_DRIVER_NAME = 6 TAG_NETWORK_MOUNT_INFO = 9 TAG_DIALUP_INFO = 10 TAG_UNICODE_FILENAME = 14 TAG_UNICODE_VOLUME_NAME = 15 TAG_HIGH_RES_VOLUME_CREATION_DATE = 16 TAG_HIGH_RES_CREATION_DATE = 17 TAG_POSIX_PATH = 18 TAG_POSIX_PATH_TO_MOUNTPOINT = 19 TAG_RECURSIVE_ALIAS_OF_DISK_IMAGE = 20 TAG_USER_HOME_LENGTH_PREFIX = 21 class Alias: def __init__( self, appinfo=b"\0\0\0\0", version=2, volume=None, target=None, extra=[], ): """Construct a new :class:`Alias` object with the specified contents.""" #: Application specific information (four byte byte-string) self.appinfo = appinfo #: Version (we support versions 2 and 3) self.version = version #: A :class:`VolumeInfo` object describing the target's volume self.volume = volume #: A :class:`TargetInfo` object describing the target self.target = target #: A list of extra `(tag, value)` pairs self.extra = list(extra) @classmethod def _from_fd(cls, b): appinfo, recsize, version = struct.unpack(b">4shh", b.read(8)) if recsize < 150: raise ValueError("Incorrect alias length") if version not in (2, 3): raise ValueError("Unsupported alias version %u" % version) if version == 2: ( kind, # h volname, # 28p voldate, # I fstype, # 2s disktype, # h folder_cnid, # I filename, # 64p cnid, # I crdate, # I creator_code, # 4s type_code, # 4s levels_from, # h levels_to, # h volattrs, # I volfsid, # 2s reserved, # 10s ) = struct.unpack(b">h28pI2shI64pII4s4shhI2s10s", b.read(142)) else: ( kind, # h voldate_hr, # Q fstype, # 4s disktype, # h folder_cnid, # I cnid, # I crdate_hr, # Q volattrs, # I reserved, # 14s ) = struct.unpack(b">hQ4shIIQI14s", b.read(46)) volname = b"" filename = b"" creator_code = None type_code = None voldate = voldate_hr / 65536.0 crdate = crdate_hr / 65536.0 voldate = mac_epoch + datetime.timedelta(seconds=voldate) crdate = mac_epoch + datetime.timedelta(seconds=crdate) alias = Alias() alias.appinfo = appinfo alias.volume = VolumeInfo( volname.decode().replace("/", ":"), voldate, fstype, disktype, volattrs, volfsid, ) alias.target = TargetInfo( kind, filename.decode().replace("/", ":"), folder_cnid, cnid, crdate, creator_code, type_code, ) alias.target.levels_from = levels_from alias.target.levels_to = levels_to tag = struct.unpack(b">h", b.read(2))[0] while tag != -1: length = struct.unpack(b">h", b.read(2))[0] value = b.read(length) if length & 1: b.read(1) if tag == TAG_CARBON_FOLDER_NAME: alias.target.folder_name = value.decode().replace("/", ":") elif tag == TAG_CNID_PATH: alias.target.cnid_path = struct.unpack(">%uI" % (length // 4), value) elif tag == TAG_CARBON_PATH: alias.target.carbon_path = value elif tag == TAG_APPLESHARE_ZONE: if alias.volume.appleshare_info is None: alias.volume.appleshare_info = AppleShareInfo() alias.volume.appleshare_info.zone = value elif tag == TAG_APPLESHARE_SERVER_NAME: if alias.volume.appleshare_info is None: alias.volume.appleshare_info = AppleShareInfo() alias.volume.appleshare_info.server = value elif tag == TAG_APPLESHARE_USERNAME: if alias.volume.appleshare_info is None: alias.volume.appleshare_info = AppleShareInfo() alias.volume.appleshare_info.user = value elif tag == TAG_DRIVER_NAME: alias.volume.driver_name = value elif tag == TAG_NETWORK_MOUNT_INFO: alias.volume.network_mount_info = value elif tag == TAG_DIALUP_INFO: alias.volume.dialup_info = value elif tag == TAG_UNICODE_FILENAME: alias.target.filename = value[2:].decode("utf-16be") elif tag == TAG_UNICODE_VOLUME_NAME: alias.volume.name = value[2:].decode("utf-16be") elif tag == TAG_HIGH_RES_VOLUME_CREATION_DATE: seconds = struct.unpack(b">Q", value)[0] / 65536.0 alias.volume.creation_date = mac_epoch + datetime.timedelta( seconds=seconds ) elif tag == TAG_HIGH_RES_CREATION_DATE: seconds = struct.unpack(b">Q", value)[0] / 65536.0 alias.target.creation_date = mac_epoch + datetime.timedelta( seconds=seconds ) elif tag == TAG_POSIX_PATH: alias.target.posix_path = value.decode() elif tag == TAG_POSIX_PATH_TO_MOUNTPOINT: alias.volume.posix_path = value.decode() elif tag == TAG_RECURSIVE_ALIAS_OF_DISK_IMAGE: alias.volume.disk_image_alias = Alias.from_bytes(value) elif tag == TAG_USER_HOME_LENGTH_PREFIX: alias.target.user_home_prefix_len = struct.unpack(b">h", value)[0] else: alias.extra.append((tag, value)) tag = struct.unpack(b">h", b.read(2))[0] return alias @classmethod def from_bytes(cls, bytes): """Construct an :class:`Alias` object given binary Alias data.""" with io.BytesIO(bytes) as b: return cls._from_fd(b) @classmethod def for_file(cls, path): """Create an :class:`Alias` that points at the specified file.""" if sys.platform != "darwin": raise Exception("Not implemented (requires special support)") path = encode_utf8(path) a = Alias() # Find the filesystem st = osx.statfs(path) vol_path = st.f_mntonname # File and folder names in HFS+ are normalized to a form similar to NFD. # Must be normalized (NFD->NFC) before use to avoid unicode string comparison issues. vol_path = normalize("NFC", vol_path.decode("utf-8")).encode("utf-8") # Grab its attributes attrs = [osx.ATTR_CMN_CRTIME, osx.ATTR_VOL_NAME, 0, 0, 0] volinfo = osx.getattrlist(vol_path, attrs, 0) vol_crtime = volinfo[0] vol_name = encode_utf8(volinfo[1]) # Also grab various attributes of the file attrs = [ osx.ATTR_CMN_OBJTYPE | osx.ATTR_CMN_CRTIME | osx.ATTR_CMN_FNDRINFO | osx.ATTR_CMN_FILEID | osx.ATTR_CMN_PARENTID, 0, 0, 0, 0, ] info = osx.getattrlist(path, attrs, osx.FSOPT_NOFOLLOW) if info[0] == osx.VDIR: kind = ALIAS_KIND_FOLDER else: kind = ALIAS_KIND_FILE cnid = info[3] folder_cnid = info[4] dirname, filename = os.path.split(path) if dirname == b"" or dirname == b".": dirname = os.getcwd() foldername = os.path.basename(dirname) creation_date = info[1] if kind == ALIAS_KIND_FILE: creator_code = struct.pack(b"I", info[2].fileInfo.fileCreator) type_code = struct.pack(b"I", info[2].fileInfo.fileType) else: creator_code = b"\0\0\0\0" type_code = b"\0\0\0\0" a.target = TargetInfo( kind, filename, folder_cnid, cnid, creation_date, creator_code, type_code ) a.volume = VolumeInfo(vol_name, vol_crtime, b"H+", ALIAS_FIXED_DISK, 0, b"\0\0") a.target.folder_name = foldername a.volume.posix_path = vol_path rel_path = os.path.relpath(path, vol_path) # Leave off the initial '/' if vol_path is '/' (no idea why) if vol_path == b"/": a.target.posix_path = rel_path else: a.target.posix_path = b"/" + rel_path # Construct the Carbon and CNID paths carbon_path = [] cnid_path = [] head, tail = os.path.split(rel_path) if not tail: head, tail = os.path.split(head) while head or tail: if head: attrs = [osx.ATTR_CMN_FILEID, 0, 0, 0, 0] info = osx.getattrlist(os.path.join(vol_path, head), attrs, 0) cnid_path.append(info[0]) carbon_tail = tail.replace(b":", b"/") carbon_path.insert(0, carbon_tail) head, tail = os.path.split(head) carbon_path = vol_name + b":" + b":\0".join(carbon_path) a.target.carbon_path = carbon_path a.target.cnid_path = cnid_path return a def _to_fd(self, b): # We'll come back and fix the length when we're done pos = b.tell() b.write(struct.pack(b">4shh", self.appinfo, 0, self.version)) carbon_volname = encode_utf8(self.volume.name).replace(b":", b"/") carbon_filename = encode_utf8(self.target.filename).replace(b":", b"/") voldate = (self.volume.creation_date - mac_epoch).total_seconds() crdate = (self.target.creation_date - mac_epoch).total_seconds() if self.version == 2: # NOTE: crdate should be in local time, but that's system dependent # (so doing so is ridiculous, and nothing could rely on it). b.write( struct.pack( b">h28pI2shI64pII4s4shhI2s10s", self.target.kind, # h carbon_volname, # 28p int(voldate), # I self.volume.fs_type, # 2s self.volume.disk_type, # h self.target.folder_cnid, # I carbon_filename, # 64p self.target.cnid, # I int(crdate), # I self.target.creator_code, # 4s self.target.type_code, # 4s self.target.levels_from, # h self.target.levels_to, # h self.volume.attribute_flags, # I self.volume.fs_id, # 2s b"\0" * 10, # 10s ) ) else: b.write( struct.pack( b">hQ4shIIQI14s", self.target.kind, # h int(voldate * 65536), # Q self.volume.fs_type, # 4s self.volume.disk_type, # h self.target.folder_cnid, # I self.target.cnid, # I int(crdate * 65536), # Q self.volume.attribute_flags, # I b"\0" * 14, # 14s ) ) # Excuse the odd order; we're copying Finder if self.target.folder_name: carbon_foldername = encode_utf8(self.target.folder_name).replace(b":", b"/") b.write(struct.pack(b">hh", TAG_CARBON_FOLDER_NAME, len(carbon_foldername))) b.write(carbon_foldername) if len(carbon_foldername) & 1: b.write(b"\0") b.write( struct.pack( b">hhQhhQ", TAG_HIGH_RES_VOLUME_CREATION_DATE, 8, int(voldate * 65536), TAG_HIGH_RES_CREATION_DATE, 8, int(crdate * 65536), ) ) if self.target.cnid_path: cnid_path = struct.pack( ">%uI" % len(self.target.cnid_path), *self.target.cnid_path ) b.write(struct.pack(b">hh", TAG_CNID_PATH, len(cnid_path))) b.write(cnid_path) if self.target.carbon_path: carbon_path = encode_utf8(self.target.carbon_path) b.write(struct.pack(b">hh", TAG_CARBON_PATH, len(carbon_path))) b.write(carbon_path) if len(carbon_path) & 1: b.write(b"\0") if self.volume.appleshare_info: ai = self.volume.appleshare_info if ai.zone: b.write(struct.pack(b">hh", TAG_APPLESHARE_ZONE, len(ai.zone))) b.write(ai.zone) if len(ai.zone) & 1: b.write(b"\0") if ai.server: b.write(struct.pack(b">hh", TAG_APPLESHARE_SERVER_NAME, len(ai.server))) b.write(ai.server) if len(ai.server) & 1: b.write(b"\0") if ai.username: b.write(struct.pack(b">hh", TAG_APPLESHARE_USERNAME, len(ai.username))) b.write(ai.username) if len(ai.username) & 1: b.write(b"\0") if self.volume.driver_name: driver_name = encode_utf8(self.volume.driver_name) b.write(struct.pack(b">hh", TAG_DRIVER_NAME, len(driver_name))) b.write(driver_name) if len(driver_name) & 1: b.write(b"\0") if self.volume.network_mount_info: b.write( struct.pack( b">hh", TAG_NETWORK_MOUNT_INFO, len(self.volume.network_mount_info) ) ) b.write(self.volume.network_mount_info) if len(self.volume.network_mount_info) & 1: b.write(b"\0") if self.volume.dialup_info: b.write( struct.pack( b">hh", TAG_DIALUP_INFO, len(self.volume.network_mount_info) ) ) b.write(self.volume.network_mount_info) if len(self.volume.network_mount_info) & 1: b.write(b"\0") utf16 = decode_utf8(self.target.filename).replace(":", "/").encode("utf-16-be") b.write( struct.pack(b">hhh", TAG_UNICODE_FILENAME, len(utf16) + 2, len(utf16) // 2) ) b.write(utf16) utf16 = decode_utf8(self.volume.name).replace(":", "/").encode("utf-16-be") b.write( struct.pack( b">hhh", TAG_UNICODE_VOLUME_NAME, len(utf16) + 2, len(utf16) // 2 ) ) b.write(utf16) if self.target.posix_path: posix_path = encode_utf8(self.target.posix_path) b.write(struct.pack(b">hh", TAG_POSIX_PATH, len(posix_path))) b.write(posix_path) if len(posix_path) & 1: b.write(b"\0") if self.volume.posix_path: posix_path = encode_utf8(self.volume.posix_path) b.write(struct.pack(b">hh", TAG_POSIX_PATH_TO_MOUNTPOINT, len(posix_path))) b.write(posix_path) if len(posix_path) & 1: b.write(b"\0") if self.volume.disk_image_alias: d = self.volume.disk_image_alias.to_bytes() b.write(struct.pack(b">hh", TAG_RECURSIVE_ALIAS_OF_DISK_IMAGE, len(d))) b.write(d) if len(d) & 1: b.write(b"\0") if self.target.user_home_prefix_len is not None: b.write( struct.pack( b">hhh", TAG_USER_HOME_LENGTH_PREFIX, 2, self.target.user_home_prefix_len, ) ) for t, v in self.extra: b.write(struct.pack(b">hh", t, len(v))) b.write(v) if len(v) & 1: b.write(b"\0") b.write(struct.pack(b">hh", -1, 0)) blen = b.tell() - pos b.seek(pos + 4, os.SEEK_SET) b.write(struct.pack(b">h", blen)) def to_bytes(self): """Returns the binary representation for this :class:`Alias`.""" with io.BytesIO() as b: self._to_fd(b) return b.getvalue() def __str__(self): return "" % self.target.filename def __repr__(self): values = [] if self.appinfo != b"\0\0\0\0": values.append("appinfo=%r" % self.appinfo) if self.version != 2: values.append("version=%r" % self.version) if self.volume is not None: values.append("volume=%r" % self.volume) if self.target is not None: values.append("target=%r" % self.target) if self.extra: values.append("extra=%r" % self.extra) return "Alias(%s)" % ",".join(values) qbs-src-2.5.1/src/3rdparty/python/lib/python3.9/site-packages/mac_alias/bookmark.py0000644000175100001660000005454714744424375027502 0ustar runnerdocker# This file implements the Apple "bookmark" format, which is the replacement # for the old-fashioned alias format. The details of this format were # reverse engineered; some things are still not entirely clear. # import datetime import os import struct import sys import uuid from urllib.parse import urljoin if sys.platform == "darwin": from . import osx from .utils import osx_epoch BMK_DATA_TYPE_MASK = 0xFFFFFF00 BMK_DATA_SUBTYPE_MASK = 0x000000FF BMK_STRING = 0x0100 BMK_DATA = 0x0200 BMK_NUMBER = 0x0300 BMK_DATE = 0x0400 BMK_BOOLEAN = 0x0500 BMK_ARRAY = 0x0600 BMK_DICT = 0x0700 BMK_UUID = 0x0800 BMK_URL = 0x0900 BMK_NULL = 0x0A00 BMK_ST_ZERO = 0x0000 BMK_ST_ONE = 0x0001 BMK_BOOLEAN_ST_FALSE = 0x0000 BMK_BOOLEAN_ST_TRUE = 0x0001 # Subtypes for BMK_NUMBER are really CFNumberType values kCFNumberSInt8Type = 1 kCFNumberSInt16Type = 2 kCFNumberSInt32Type = 3 kCFNumberSInt64Type = 4 kCFNumberFloat32Type = 5 kCFNumberFloat64Type = 6 kCFNumberCharType = 7 kCFNumberShortType = 8 kCFNumberIntType = 9 kCFNumberLongType = 10 kCFNumberLongLongType = 11 kCFNumberFloatType = 12 kCFNumberDoubleType = 13 kCFNumberCFIndexType = 14 kCFNumberNSIntegerType = 15 kCFNumberCGFloatType = 16 # Resource property flags (from CFURLPriv.h) kCFURLResourceIsRegularFile = 0x00000001 kCFURLResourceIsDirectory = 0x00000002 kCFURLResourceIsSymbolicLink = 0x00000004 kCFURLResourceIsVolume = 0x00000008 kCFURLResourceIsPackage = 0x00000010 kCFURLResourceIsSystemImmutable = 0x00000020 kCFURLResourceIsUserImmutable = 0x00000040 kCFURLResourceIsHidden = 0x00000080 kCFURLResourceHasHiddenExtension = 0x00000100 kCFURLResourceIsApplication = 0x00000200 kCFURLResourceIsCompressed = 0x00000400 kCFURLResourceIsSystemCompressed = 0x00000400 kCFURLCanSetHiddenExtension = 0x00000800 kCFURLResourceIsReadable = 0x00001000 kCFURLResourceIsWriteable = 0x00002000 kCFURLResourceIsExecutable = 0x00004000 kCFURLIsAliasFile = 0x00008000 kCFURLIsMountTrigger = 0x00010000 # Volume property flags (from CFURLPriv.h) kCFURLVolumeIsLocal = 0x1 kCFURLVolumeIsAutomount = 0x2 kCFURLVolumeDontBrowse = 0x4 kCFURLVolumeIsReadOnly = 0x8 kCFURLVolumeIsQuarantined = 0x10 kCFURLVolumeIsEjectable = 0x20 kCFURLVolumeIsRemovable = 0x40 kCFURLVolumeIsInternal = 0x80 kCFURLVolumeIsExternal = 0x100 kCFURLVolumeIsDiskImage = 0x200 kCFURLVolumeIsFileVault = 0x400 kCFURLVolumeIsLocaliDiskMirror = 0x800 kCFURLVolumeIsiPod = 0x1000 kCFURLVolumeIsiDisk = 0x2000 kCFURLVolumeIsCD = 0x4000 kCFURLVolumeIsDVD = 0x8000 kCFURLVolumeIsDeviceFileSystem = 0x10000 kCFURLVolumeSupportsPersistentIDs = 0x100000000 kCFURLVolumeSupportsSearchFS = 0x200000000 kCFURLVolumeSupportsExchange = 0x400000000 # reserved 0x800000000 kCFURLVolumeSupportsSymbolicLinks = 0x1000000000 kCFURLVolumeSupportsDenyModes = 0x2000000000 kCFURLVolumeSupportsCopyFile = 0x4000000000 kCFURLVolumeSupportsReadDirAttr = 0x8000000000 kCFURLVolumeSupportsJournaling = 0x10000000000 kCFURLVolumeSupportsRename = 0x20000000000 kCFURLVolumeSupportsFastStatFS = 0x40000000000 kCFURLVolumeSupportsCaseSensitiveNames = 0x80000000000 kCFURLVolumeSupportsCasePreservedNames = 0x100000000000 kCFURLVolumeSupportsFLock = 0x200000000000 kCFURLVolumeHasNoRootDirectoryTimes = 0x400000000000 kCFURLVolumeSupportsExtendedSecurity = 0x800000000000 kCFURLVolumeSupports2TBFileSize = 0x1000000000000 kCFURLVolumeSupportsHardLinks = 0x2000000000000 kCFURLVolumeSupportsMandatoryByteRangeLocks = 0x4000000000000 kCFURLVolumeSupportsPathFromID = 0x8000000000000 # reserved 0x10000000000000 kCFURLVolumeIsJournaling = 0x20000000000000 kCFURLVolumeSupportsSparseFiles = 0x40000000000000 kCFURLVolumeSupportsZeroRuns = 0x80000000000000 kCFURLVolumeSupportsVolumeSizes = 0x100000000000000 kCFURLVolumeSupportsRemoteEvents = 0x200000000000000 kCFURLVolumeSupportsHiddenFiles = 0x400000000000000 kCFURLVolumeSupportsDecmpFSCompression = 0x800000000000000 kCFURLVolumeHas64BitObjectIDs = 0x1000000000000000 kCFURLVolumePropertyFlagsAll = 0xFFFFFFFFFFFFFFFF BMK_URL_ST_ABSOLUTE = 0x0001 BMK_URL_ST_RELATIVE = 0x0002 # Bookmark keys kBookmarkURL = 0x1003 # A URL kBookmarkPath = 0x1004 # Array of path components kBookmarkCNIDPath = 0x1005 # Array of CNIDs kBookmarkFileProperties = ( 0x1010 # (CFURL rp flags, CFURL rp flags asked for, 8 bytes NULL) ) kBookmarkFileName = 0x1020 kBookmarkFileID = 0x1030 kBookmarkFileCreationDate = 0x1040 # = 0x1054 # ? # = 0x1055 # ? # = 0x1056 # ? # = 0x1101 # ? # = 0x1102 # ? kBookmarkTOCPath = 0x2000 # A list of (TOC id, ?) pairs kBookmarkVolumePath = 0x2002 kBookmarkVolumeURL = 0x2005 kBookmarkVolumeName = 0x2010 kBookmarkVolumeUUID = 0x2011 # Stored (perversely) as a string kBookmarkVolumeSize = 0x2012 kBookmarkVolumeCreationDate = 0x2013 kBookmarkVolumeProperties = ( 0x2020 # (CFURL vp flags, CFURL vp flags asked for, 8 bytes NULL) ) kBookmarkVolumeIsRoot = 0x2030 # True if volume is FS root kBookmarkVolumeBookmark = 0x2040 # Embedded bookmark for disk image (TOC id) kBookmarkVolumeMountPoint = 0x2050 # A URL # = 0x2070 kBookmarkContainingFolder = 0xC001 # Index of containing folder in path kBookmarkUserName = 0xC011 # User that created bookmark kBookmarkUID = 0xC012 # UID that created bookmark kBookmarkWasFileReference = 0xD001 # True if the URL was a file reference kBookmarkCreationOptions = 0xD010 kBookmarkURLLengths = 0xE003 # See below kBookmarkDisplayName = 0xF017 kBookmarkIconData = 0xF020 kBookmarkIconRef = 0xF021 kBookmarkTypeBindingData = 0xF022 kBookmarkCreationTime = 0xF030 kBookmarkSandboxRwExtension = 0xF080 kBookmarkSandboxRoExtension = 0xF081 kBookmarkAliasData = 0xFE00 # Alias for backwards compatibility kBookmarkSecurityExtension = kBookmarkSandboxRwExtension # kBookmarkURLLengths is an array that is set if the URL encoded by the # bookmark had a base URL; in that case, each entry is the length of the # base URL in question. Thus a URL # # file:///foo/bar/baz blam/blat.html # # will result in [3, 2], while the URL # # file:///foo bar/baz blam blat.html # # would result in [1, 2, 1, 1] class Data: def __init__(self, bytedata=None): #: The bytes, stored as a byte string self.bytes = bytes(bytedata) def __repr__(self): return "Data(%r)" % self.bytes class URL: def __init__(self, base, rel=None): if rel is not None: #: The base URL, if any (a :class:`URL`) self.base = base #: The rest of the URL (a string) self.relative = rel else: self.base = None self.relative = base @property def absolute(self): """Return an absolute URL.""" if self.base is None: return self.relative else: return urljoin(self.base.absolute, self.relative) def __repr__(self): return "URL(%r)" % self.absolute class Bookmark: def __init__(self, tocs=None): if tocs is None: #: The TOCs for this Bookmark self.tocs = [] else: self.tocs = tocs @classmethod def _get_item(cls, data, hdrsize, offset): offset += hdrsize if offset > len(data) - 8: raise ValueError("Offset out of range") length, typecode = struct.unpack(b"d", databytes)[0]) return osx_epoch + secs elif dtype == BMK_BOOLEAN: if dsubtype == BMK_BOOLEAN_ST_TRUE: return True elif dsubtype == BMK_BOOLEAN_ST_FALSE: return False elif dtype == BMK_UUID: return uuid.UUID(bytes=databytes) elif dtype == BMK_URL: if dsubtype == BMK_URL_ST_ABSOLUTE: return URL(databytes.decode("utf-8")) elif dsubtype == BMK_URL_ST_RELATIVE: baseoff, reloff = struct.unpack(b" size: raise ValueError("Not a bookmark file (header size too large)") if size != len(data): raise ValueError("Not a bookmark file (truncated)") (tocoffset,) = struct.unpack(b" size - hdrsize) or (size - tocbase < 20): raise ValueError("TOC offset out of range") (tocsize, tocmagic, tocid, nexttoc, toccount) = struct.unpack( b" -0x80000000 and item < 0x7FFFFFFF: result = struct.pack(b"d", float(secs.total_seconds()) ) elif isinstance(item, uuid.UUID): result = struct.pack(b"