summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Shienkov <denis.shienkov@gmail.com>2021-11-05 16:13:03 +0300
committerDenis Shienkov <denis.shienkov@gmail.com>2022-02-04 11:29:03 +0000
commitcb3d7e862c69c59e3b0111e19ace157be07acb88 (patch)
tree216be539d04d3819fefb6f21e7d46c334570ac84
parent38757a783a5a89f35a12184e77550017ee52d32e (diff)
downloadqbs-cb3d7e862c69c59e3b0111e19ace157be07acb88.tar.gz
Long live Open Watcom toolchain
This patch adds basic support for the Open Watcom toolchain. This patch uses the `owcc` compiler (supplied with the toolchain), which is a wrapper that supports the POSIX standard. Reason is that the native OW compiler and linker has a limitations in the command line arguments (e.g. they have wrong quotes handling and so on). This patch supports both the latest official version v1.9 and also its fork v2.0. Also added the CI autotests for the version v2.0 for the Windows host. These autotests only perform a limited number of tests (only the bare-metal tests) due to the following toolchain limitations: * The toolchain does not have STL support (there seems to be some kind of the partial support in the form of separate legacy STL ports). * The toolchain support something compatible with the C++98 standard. * The toolchain does not support the shared libraries on Linux hosts. These limitations make it impossible or unjustified to reuse most of the available tests (it requires a lot of work). There was also an attempt to set up CI for tests on Linux host, but for some reason the toolchain installer crashes on CI (although it works fine on a local PC with Ubuntu). Change-Id: Iecf76f51f0b09d31a89683f786b9cd7a825f235e Reviewed-by: Ivan Komissarov <ABBAPOH@gmail.com>
-rw-r--r--.github/actions/download-ow/action.yml15
-rw-r--r--.github/workflows/main.yml49
-rw-r--r--doc/reference/cli/cli-options.qdocinc1
-rw-r--r--doc/reference/items/probe/watcom-probe.qdoc129
-rw-r--r--doc/reference/modules/qbs-module.qdoc3
-rwxr-xr-xscripts/install-ow.sh193
-rw-r--r--share/qbs/imports/qbs/ModUtils/utils.js4
-rw-r--r--share/qbs/imports/qbs/Probes/WatcomProbe.qbs94
-rw-r--r--share/qbs/modules/cpp/cpp.js10
-rw-r--r--share/qbs/modules/cpp/watcom.js509
-rw-r--r--share/qbs/modules/cpp/watcom.qbs195
-rw-r--r--src/app/qbs-setup-toolchains/CMakeLists.txt2
-rw-r--r--src/app/qbs-setup-toolchains/probe.cpp6
-rw-r--r--src/app/qbs-setup-toolchains/probe.h2
-rw-r--r--src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro2
-rw-r--r--src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs2
-rw-r--r--src/app/qbs-setup-toolchains/watcomprobe.cpp200
-rw-r--r--src/app/qbs-setup-toolchains/watcomprobe.h58
-rw-r--r--tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/compiler-defines-by-language.qbs2
19 files changed, 1470 insertions, 6 deletions
diff --git a/.github/actions/download-ow/action.yml b/.github/actions/download-ow/action.yml
new file mode 100644
index 000000000..a93a229cc
--- /dev/null
+++ b/.github/actions/download-ow/action.yml
@@ -0,0 +1,15 @@
+name: 'Download OpenWatcom'
+description: 'Downloads OpenWatcom'
+inputs:
+ version:
+ description: 'OpenWatcom version'
+ required: false
+ default: '2.0'
+runs:
+ using: "composite"
+ steps:
+ - name: Install OpenWatcom
+ run: |
+ OW_DIR=$(./scripts/install-ow.sh -d $HOME/watcom --version ${{ inputs.version }})
+ (cygpath -w ${OW_DIR} 2>/dev/null || echo ${OW_DIR}) >> ${GITHUB_PATH}
+ shell: bash
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 81a3e4721..8dd4d1dfb 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -787,3 +787,52 @@ jobs:
- name: Run Tests
run: ${{ matrix.config.script }} ./release/install-root/bin
shell: bash
+
+ test-windows-extra:
+ name: ${{ matrix.config.name }}
+ runs-on: windows-latest
+ timeout-minutes: 60
+ needs: build-windows
+ strategy:
+ fail-fast: false
+ matrix:
+ config:
+ - {
+ name: 'Run Windows tests (OpenWatcom)',
+ testProfile: 'watcom-2_0_0-x86',
+ script: './scripts/test-baremetal.sh',
+ }
+ env:
+ QTEST_FUNCTION_TIMEOUT: 9000000
+ QBS_AUTOTEST_PROFILE: 'extra'
+ QBS_TEST_SOURCE_ROOT: 'tests'
+ QT_ASSUME_STDERR_HAS_CONSOLE: 1
+ steps:
+ - uses: actions/checkout@v1
+ - name: Download artifact
+ uses: actions/download-artifact@v1
+ with:
+ name: qbs-windows-${{ github.run_id }}.zip
+ path: ./
+ - name: Unpack artifact
+ run: |
+ mkdir -p release/install-root
+ cd release/install-root
+ 7z x ../../qbs-windows-${{ github.run_id }}.zip
+ shell: bash
+ - name: Update PATH
+ run: echo "./release/install-root/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
+ - name: Install required packages
+ run: choco install -y pkgconfiglite --download-checksum=6004df17818f5a6dbf19cb335cc92702
+ - name: Install OpenWatcom
+ uses: ./.github/actions/download-ow
+ - name: Setup Qbs
+ run: |
+ qbs setup-toolchains --detect
+ qbs config profiles.extra.baseProfile ${{ matrix.config.testProfile }}
+ qbs config defaultProfile extra
+ qbs config --list
+ shell: bash
+ - name: Run Tests
+ run: ${{ matrix.config.script }} ./release/install-root/bin
+ shell: bash
diff --git a/doc/reference/cli/cli-options.qdocinc b/doc/reference/cli/cli-options.qdocinc
index a993f6d12..db8eeae48 100644
--- a/doc/reference/cli/cli-options.qdocinc
+++ b/doc/reference/cli/cli-options.qdocinc
@@ -501,6 +501,7 @@
\li \c sdcc
\li \c cosmic
\li \c dmc
+ \li \c watcom
\endlist
//! [type]
diff --git a/doc/reference/items/probe/watcom-probe.qdoc b/doc/reference/items/probe/watcom-probe.qdoc
new file mode 100644
index 000000000..9c1c7486c
--- /dev/null
+++ b/doc/reference/items/probe/watcom-probe.qdoc
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \qmltype WatcomProbe
+ \inqmlmodule QbsProbes
+ \ingroup list-of-items
+ \keyword QML.WatcomProbe
+ \inherits PathProbe
+ \brief Collects Oopen Watcom toolchain compiler information.
+ \since Qbs 1.22
+ \internal
+
+ Detects the version, supported architecture, the platform
+ endianness, and other stuff for the specified compiler executable
+ from the \l{https://github.com/open-watcom}{Open Watcom} toolchain.
+*/
+
+/*!
+ \qmlproperty string WatcomProbe::compilerFilePath
+
+ An input property which is a full path to the Digital Mars compiler
+ executable.
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty string WatcomProbe::architecture
+
+ Detected architecture of the target platform's processor.
+
+ The only possible value is \c "x86".
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty string WatcomProbe::endianness
+
+ Detected endianness of the target platform's processor architecture.
+
+ The possible values are \c "big" and \c "little".
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty string WatcomProbe::targetPlatform
+
+ Detected target platform.
+
+ The possible values are \c "windows" and \c "linux".
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty int WatcomProbe::versionMajor
+
+ Detected major compiler version.
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty int WatcomProbe::versionMinor
+
+ Detected minor compiler version.
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty int WatcomProbe::versionPatch
+
+ Detected patch compiler version.
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty stringList WatcomProbe::includePaths
+
+ Detected compiler include paths.
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty var WatcomProbe::compilerDefinesByLanguage
+
+ Detected set of compiler pre-defined macros depending
+ on the \c "C" or \c "C++" language.
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty var WatcomProbe::environment
+
+ Detected compiler run environment.
+
+ \nodefaultvalue
+*/
diff --git a/doc/reference/modules/qbs-module.qdoc b/doc/reference/modules/qbs-module.qdoc
index 06f68cf5f..029f6f2cd 100644
--- a/doc/reference/modules/qbs-module.qdoc
+++ b/doc/reference/modules/qbs-module.qdoc
@@ -536,6 +536,9 @@
\li \c{"sdcc"}
\li \c{["sdcc"]}
\row
+ \li \c{"watcom"}
+ \li \c{["watcom"]}
+ \row
\li \c{"xcode"}
\li \c{["xcode", "clang", "llvm", "gcc"]}
\endtable
diff --git a/scripts/install-ow.sh b/scripts/install-ow.sh
new file mode 100755
index 000000000..4c8784277
--- /dev/null
+++ b/scripts/install-ow.sh
@@ -0,0 +1,193 @@
+#!/usr/bin/env bash
+#############################################################################
+##
+## Copyright (C) 2022 Denis Shienkov <denis.shienkov@gmail.com>
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qbs.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+set -eu
+
+function show_help() {
+ cat <<EOF
+usage: install-ow [options] [components]
+
+Examples
+ ./install-ow.sh --platform win --architecture x64
+
+Options
+ -d, --directory <directory>
+ Root directory where to install the components.
+ Maps to c:/watcom on Windows, /opt/watcom on Linux
+ by default.
+
+ --platform <platform-os>
+ The host platform. Can be one of linux, win. Auto-detected by default.
+
+ --architecture <architecture-os>
+ The host architecture. Can be one of x86, x64. Auto-detected by default.
+
+ --version <version>
+ The desired toolchain version. Currently supported only
+ 1.9 and 2.0 versions.
+
+EOF
+}
+
+VERSION=2.0 # Default latest version (a fork of original toolchain)..
+
+case "$OSTYPE" in
+ *linux*)
+ PLATFORM="linux"
+ INSTALL_DIR="/opt/watcom"
+ EXE_SUFFIX=
+ ;;
+ msys)
+ PLATFORM="win"
+ INSTALL_DIR="/c/watcom"
+ EXE_SUFFIX=".exe"
+ ;;
+ *)
+ PLATFORM=
+ INSTALL_DIR=
+ EXE_SUFFIX=
+ ;;
+esac
+
+case "$HOSTTYPE" in
+ x86_64)
+ ARCHITECTURE="x64"
+ ;;
+ x86)
+ ARCHITECTURE="x86"
+ ;;
+ *)
+ ARCHITECTURE=
+ ;;
+esac
+
+while [ $# -gt 0 ]; do
+ case "$1" in
+ --directory|-d)
+ INSTALL_DIR="$2"
+ shift
+ ;;
+ --platform)
+ PLATFORM="$2"
+ shift
+ ;;
+ --architecture)
+ ARCHITECTURE="$2"
+ shift
+ ;;
+ --version)
+ VERSION="$2"
+ shift
+ ;;
+ --help|-h)
+ show_help
+ exit 0
+ ;;
+ *)
+ ;;
+ esac
+ shift
+done
+
+if [ -z "${INSTALL_DIR}" ]; then
+ echo "No --directory specified or auto-detection failed." >&2
+ exit 1
+fi
+
+if [ -z "${PLATFORM}" ]; then
+ echo "No --platform specified or auto-detection failed." >&2
+ exit 1
+fi
+
+if [ -z "${ARCHITECTURE}" ]; then
+ echo "No --architecture specified or auto-detection failed." >&2
+ exit 1
+fi
+
+if [ -z "${VERSION}" ]; then
+ echo "No --version specified." >&2
+ exit 1
+fi
+
+DOWNLOAD_DIR=`mktemp -d 2>/dev/null || mktemp -d -t 'ow-installer'`
+
+BASE_URL_PREFIX="https://github.com/open-watcom/open-watcom-"
+
+if [[ "${VERSION}" == "1.9" ]]; then
+ # Original old OW v1.9 release supports only the 32-bit packages!
+ if [[ "${PLATFORM}" =~ "linux" ]]; then
+ BIN_DIR="binl"
+ HOST="linux"
+ elif [[ "${PLATFORM}" =~ "win" ]]; then
+ HOST="win32"
+ BIN_DIR="binnt"
+ fi
+ URL="${BASE_URL_PREFIX}${VERSION}/releases/download/ow1.9/open-watcom-c-${HOST}-1.9${EXE_SUFFIX}"
+else
+ if [[ "${PLATFORM}" =~ "linux" ]]; then
+ if [[ "${ARCHITECTURE}" =~ "x86" ]]; then
+ BIN_DIR="binl"
+ elif [[ "${ARCHITECTURE}" =~ "x64" ]]; then
+ BIN_DIR="binl"
+ fi
+ elif [[ "${PLATFORM}" =~ "win" ]]; then
+ if [[ "${ARCHITECTURE}" =~ "x86" ]]; then
+ BIN_DIR="binnt"
+ elif [[ "${ARCHITECTURE}" =~ "x64" ]]; then
+ BIN_DIR="binnt64"
+ fi
+ fi
+ # Default URL for the latest OW v2.0 fork.
+ URL="${BASE_URL_PREFIX}v2/releases/download/Current-build/open-watcom-2_0-c-${PLATFORM}-${ARCHITECTURE}${EXE_SUFFIX}"
+fi
+
+INSTALLER="${DOWNLOAD_DIR}/setup${EXE_SUFFIX}"
+
+echo "Downloading from ${URL}..." >&2
+curl --progress-bar -L -o ${INSTALLER} ${URL} >&2
+
+echo "Installing to ${INSTALL_DIR}..." >&2
+if [[ "${PLATFORM}" =~ "linux" ]]; then
+ chmod +777 ${INSTALLER}
+fi
+
+${INSTALLER} -dDstDir=${INSTALL_DIR} -i -np -ns
+echo "${INSTALL_DIR}/${BIN_DIR}"
+
+rm -f ${INSTALLER}
diff --git a/share/qbs/imports/qbs/ModUtils/utils.js b/share/qbs/imports/qbs/ModUtils/utils.js
index f01ee1070..0745c4588 100644
--- a/share/qbs/imports/qbs/ModUtils/utils.js
+++ b/share/qbs/imports/qbs/ModUtils/utils.js
@@ -538,7 +538,7 @@ function guessArchitecture(m) {
break;
}
}
- } else if (hasAnyOf(m, ["__i386", "__i386__", "_M_IX86"])) {
+ } else if (hasAnyOf(m, ["__i386", "__i386__", "_M_IX86", "__386__"])) {
architecture = "x86";
} else if (hasAnyOf(m, ["__x86_64", "__x86_64__", "__amd64", "_M_X64", "_M_AMD64"])) {
architecture = "x86_64";
@@ -618,7 +618,7 @@ function guessTargetPlatform(m) {
return "hpux";
if (hasAnyOf(m, ["__sun", "sun"]))
return "solaris";
- if (hasAnyOf(m, ["__linux__", "__linux"]))
+ if (hasAnyOf(m, ["__linux__", "__linux", "__LINUX__"]))
return "linux";
if (hasAnyOf(m, ["__FreeBSD__", "__DragonFly__", "__FreeBSD_kernel__"]))
return "freebsd";
diff --git a/share/qbs/imports/qbs/Probes/WatcomProbe.qbs b/share/qbs/imports/qbs/Probes/WatcomProbe.qbs
new file mode 100644
index 000000000..34be235b1
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/WatcomProbe.qbs
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs.File
+import qbs.ModUtils
+import "../../../modules/cpp/watcom.js" as WATCOM
+
+PathProbe {
+ // Inputs
+ property string compilerFilePath
+ property stringList enableDefinesByLanguage
+
+ property string _pathListSeparator
+ property string _toolchainInstallPath
+ property string _targetPlatform
+
+ // Outputs
+ property string architecture
+ property string endianness
+ property string targetPlatform
+ property int versionMajor
+ property int versionMinor
+ property int versionPatch
+ property stringList includePaths
+ property var compilerDefinesByLanguage
+ property var environment
+
+ configure: {
+ compilerDefinesByLanguage = {};
+
+ if (!File.exists(compilerFilePath)) {
+ found = false;
+ return;
+ }
+
+ var languages = enableDefinesByLanguage;
+ if (!languages || languages.length === 0)
+ languages = ["c"];
+
+ environment = WATCOM.guessEnvironment(_targetPlatform, _toolchainInstallPath,
+ _pathListSeparator);
+
+ includePaths = environment["INCLUDE"].split(_pathListSeparator).filter(function(path) {
+ return File.exists(path);
+ });
+
+ for (var i = 0; i < languages.length; ++i) {
+ var tag = languages[i];
+ compilerDefinesByLanguage[tag] = WATCOM.dumpMacros(environment, compilerFilePath, tag);
+ }
+
+ var macros = compilerDefinesByLanguage["c"]
+ || compilerDefinesByLanguage["cpp"];
+
+ endianness = macros["__BIG_ENDIAN"] ? "big" : "little";
+ architecture = ModUtils.guessArchitecture(macros);
+ targetPlatform = ModUtils.guessTargetPlatform(macros);
+
+ var version = WATCOM.guessVersion(macros);
+ if (version) {
+ versionMajor = version.major;
+ versionMinor = version.minor;
+ versionPatch = version.patch;
+ found = !!version.found && !!architecture && !!targetPlatform;
+ }
+ }
+}
diff --git a/share/qbs/modules/cpp/cpp.js b/share/qbs/modules/cpp/cpp.js
index 315b902ee..846a4cfad 100644
--- a/share/qbs/modules/cpp/cpp.js
+++ b/share/qbs/modules/cpp/cpp.js
@@ -51,9 +51,15 @@ function languageVersion(versionArray, knownValues, lang) {
return version;
}
-function extractMacros(output) {
+function extractMacros(output, regexp) {
var m = {};
- output.trim().split(/\r?\n/g).map(function (line) {
+ output.trim().split(/\r?\n/g).map(function(line) {
+ if (regexp) {
+ var match = regexp.exec(line);
+ if (!match)
+ return;
+ line = match[1];
+ }
var prefix = "#define ";
if (!line.startsWith(prefix))
return;
diff --git a/share/qbs/modules/cpp/watcom.js b/share/qbs/modules/cpp/watcom.js
new file mode 100644
index 000000000..c186fe814
--- /dev/null
+++ b/share/qbs/modules/cpp/watcom.js
@@ -0,0 +1,509 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+var Cpp = require("cpp.js");
+var Environment = require("qbs.Environment");
+var File = require("qbs.File");
+var FileInfo = require("qbs.FileInfo");
+var ModUtils = require("qbs.ModUtils");
+var PathTools = require("qbs.PathTools");
+var Process = require("qbs.Process");
+var TemporaryDir = require("qbs.TemporaryDir");
+var TextFile = require("qbs.TextFile");
+var Utilities = require("qbs.Utilities");
+
+function toolchainDetails(qbs) {
+ var targetPlatform = qbs.targetPlatform;
+ var details = {};
+ if (targetPlatform.contains("windows")) {
+ details.imageFormat = "pe";
+ details.executableSuffix = ".exe";
+ details.dynamicLibrarySuffix = ".dll";
+ } else if (targetPlatform.contains("linux")) {
+ details.imageFormat = "elf";
+ details.executableSuffix = "";
+ details.dynamicLibrarySuffix = ".so";
+ }
+ return details;
+}
+
+function languageFlag(tag) {
+ if (tag === "c")
+ return "-xc";
+ else if (tag === "cpp")
+ return "-xc++";
+}
+
+function guessVersion(macros) {
+ var version = parseInt(macros["__WATCOMC__"], 10)
+ || parseInt(macros["__WATCOM_CPLUSPLUS__"], 10);
+ if (version) {
+ return { major: parseInt((version - 1100) / 100),
+ minor: parseInt(version / 10) % 10,
+ patch: ((version % 10) > 0) ? parseInt(version % 10) : 0 }
+ }
+}
+
+function guessEnvironment(targetPlatform, toolchainInstallPath, pathListSeparator) {
+ var toolchainRootPath = FileInfo.path(toolchainInstallPath);
+ if (!File.exists(toolchainRootPath)) {
+ throw "Unable to deduce environment due to compiler root directory: '"
+ + toolchainRootPath + "' does not exist";
+ }
+
+ var env = {};
+
+ function setVariable(key, properties, path, separator) {
+ var values = [];
+ for (var i = 0; i < properties.length; ++i) {
+ if (path) {
+ var fullpath = FileInfo.joinPaths(path, properties[i]);
+ values.push(FileInfo.toNativeSeparators(fullpath));
+ } else {
+ values.push(properties[i]);
+ }
+ }
+ env[key] = values.join(separator);
+ }
+
+ setVariable("WATCOM", [toolchainRootPath], undefined, pathListSeparator);
+ setVariable("EDPATH", ["eddat"], toolchainRootPath, pathListSeparator);
+ if (targetPlatform === "windows") {
+ setVariable("WIPFC", ["wipfc"], toolchainRootPath, pathListSeparator);
+ setVariable("PATH", ["binw", "binnt", "binnt64"], toolchainRootPath, pathListSeparator);
+ setVariable("INCLUDE", ["h", "h/nt", "h/nt/directx", "h/nt/ddk"],
+ toolchainRootPath, pathListSeparator);
+ setVariable("WHTMLHELP", ["binnt/help"], toolchainRootPath, pathListSeparator);
+ } else if (targetPlatform === "linux") {
+ setVariable("PATH", ["binl64", "binl"], toolchainRootPath, pathListSeparator);
+ setVariable("INCLUDE", ["lh"], toolchainRootPath, pathListSeparator);
+ } else {
+ throw "Unable to deduce environment for unsupported target platform: '"
+ + targetPlatform + "'";
+ }
+ return env;
+}
+
+function dumpMacros(environment, compilerPath, tag) {
+ // Note: The Open Watcom compiler does not support the predefined
+ // macros dumping. So, we do it with the following trick, where we try
+ // to create and compile a special temporary file and to parse the console
+ // output with the own magic pattern: #define <key> <value>.
+
+ var outputDirectory = new TemporaryDir();
+ var outputFilePath = FileInfo.joinPaths(outputDirectory.path(), "dump-macros.c");
+ var outputFile = new TextFile(outputFilePath, TextFile.WriteOnly);
+ outputFile.writeLine("#define VALUE_TO_STRING(x) #x");
+ outputFile.writeLine("#define VALUE(x) VALUE_TO_STRING(x)");
+ outputFile.writeLine("#define VAR_NAME_VALUE(var) \"#define \"#var\" \"VALUE(var)");
+ // Declare all available pre-defined macros of Watcon compiler.
+ var keys = [
+ // Prepare the DOS target macros.
+ "__DOS__", "_DOS", "MSDOS",
+ // Prepare the OS/2 target macros.
+ "__OS2__",
+ // Prepare the QNX target macros.
+ "__QNX__",
+ // Prepare the Netware target macros.
+ "__NETWARE__", "__NETWARE_386__",
+ // Prepare the Windows target macros.
+ "__NT__", "__WINDOWS__", "_WINDOWS", "__WINDOWS_386__",
+ // Prepare the Linux and Unix target macros.
+ "__LINUX__", "__UNIX__",
+ // Prepare the 16-bit target specific macros.
+ "__I86__", "M_I86", "_M_I86", "_M_IX86",
+ // Prepare the 32-bit target specific macros.
+ "__386__", "M_I386", "_M_I386", "_M_IX86",
+ // Prepare the indicated options macros.
+ "_MT", "_DLL", "__FPI__", "__CHAR_SIGNED__", "__INLINE_FUNCTIONS__",
+ "_CPPRTTI", "_CPPUNWIND", "NO_EXT_KEYS",
+ // Prepare the common memory model macros.
+ "__FLAT__", "__SMALL__", "__MEDIUM__",
+ "__COMPACT__", "__LARGE__", "__HUGE__",
+ // Prepare the 16-bit memory model macros.
+ "M_I86SM", "_M_I86SM", "M_I86MM", "_M_I86MM", "M_I86CM",
+ "_M_I86CM", "M_I86LM", "_M_I86LM", "M_I86HM", "_M_I86HM",
+ // Prepare the 32-bit memory model macros.
+ "M_386FM", "_M_386FM", "M_386SM", "M_386MM", "_M_386MM",
+ "M_386CM", "_M_386CM", "M_386LM", "_M_386LM",
+ // Prepare the compiler macros.
+ "__X86__", "__cplusplus", "__WATCOMC__", "__WATCOM_CPLUSPLUS__",
+ "_INTEGRAL_MAX_BITS", "_PUSHPOP_SUPPORTED", "_STDCALL_SUPPORTED",
+ // Prepare the other macros.
+ "__3R__", "_based", "_cdecl", "cdecl", "_export", "_far16", "_far", "far",
+ "_fastcall", "_fortran", "fortran", "_huge", "huge", "_inline", "_interrupt",
+ "interrupt", "_loadds", "_near", "near", "_pascal", "pascal", "_saveregs",
+ "_segment", "_segname", "_self", "SOMDLINK", "_STDCALL_SUPPORTED", "__SW_0",
+ "__SW_3R", "__SW_5", "__SW_FP287", "__SW_FP2", "__SW_FP387", "__SW_FP3",
+ "__SW_FPI", "__SW_MF", "__SW_MS", "__SW_ZDP", "__SW_ZFP", "__SW_ZGF",
+ "__SW_ZGP", "_stdcall", "_syscall", "__BIG_ENDIAN"
+ ];
+ for (var i = 0; i < keys.length; ++i) {
+ var key = keys[i];
+ outputFile.writeLine("#if defined(" + key + ")");
+ outputFile.writeLine("#pragma message (VAR_NAME_VALUE(" + key + "))");
+ outputFile.writeLine("#endif");
+ }
+ outputFile.close();
+
+ var process = new Process();
+ process.setWorkingDirectory(outputDirectory.path());
+ for (var envkey in environment)
+ process.setEnv(envkey, environment[envkey]);
+
+ var args = [ outputFilePath ].concat(languageFlag(tag));
+ process.exec(compilerPath, args, false);
+ var m = Cpp.extractMacros(process.readStdOut(), /"?(#define(\s\w+){1,2})"?$/);
+ if (tag === "cpp" && m["__cplusplus"] === "1")
+ return m;
+ else if (tag === "c")
+ return m;
+}
+
+function effectiveLinkerPath(product) {
+ if (product.cpp.linkerMode === "automatic") {
+ var compilerPath = product.cpp.compilerPath;
+ if (compilerPath)
+ return compilerPath;
+ console.log("Found no C-language objects, choosing system linker for " + product.name);
+ }
+ return product.cpp.linkerPath;
+}
+
+function useCompilerDriverLinker(product) {
+ var linker = effectiveLinkerPath(product);
+ var compiler = product.cpp.compilerPath;
+ return linker === compiler;
+}
+
+function escapeLinkerFlags(useCompilerDriver, linkerFlags) {
+ if (!linkerFlags || linkerFlags.length === 0)
+ return [];
+
+ if (useCompilerDriver) {
+ var sep = ",";
+ return [["-Wl"].concat(linkerFlags).join(sep)];
+ }
+ return linkerFlags;
+}
+
+function assemblerFlags(project, product, input, outputs, explicitlyDependsOn) {
+ var args = [FileInfo.toNativeSeparators(input.filePath)];
+ args.push("-fo=" + FileInfo.toNativeSeparators(outputs.obj[0].filePath));
+
+ args = args.concat(Cpp.collectPreincludePaths(input).map(function(path) {
+ return "-fi" + FileInfo.toNativeSeparators(path);
+ }));
+
+ args = args.concat(Cpp.collectDefinesArguments(input, "-d"));
+
+ var includePaths = [].concat(Cpp.collectIncludePaths(input)).concat(
+ Cpp.collectSystemIncludePaths(input));
+ args = args.concat(includePaths.map(function(path) {
+ return "-i" + FileInfo.toNativeSeparators(path);
+ }));
+
+ if (input.cpp.debugInformation)
+ args.push("-d1");
+
+ var warnings = input.cpp.warningLevel
+ if (warnings === "none")
+ args.push("-w0");
+ else if (warnings === "all")
+ args.push("-wx");
+ if (input.cpp.treatWarningsAsErrors)
+ args.push("-we");
+
+ args.push("-zq"); // Silent.
+ args = args.concat(Cpp.collectMiscAssemblerArguments(input));
+ return args;
+}
+
+function compilerFlags(project, product, input, outputs, explicitlyDependsOn) {
+ var args = ["-g" + (input.cpp.debugInformation ? "3" : "0")];
+
+ var targetPlatform = product.qbs.targetPlatform;
+ if (product.type.contains("application")) {
+ if (targetPlatform === "windows") {
+ var consoleApplication = product.consoleApplication;
+ args.push(consoleApplication ? "-mconsole" : "-mwindows");
+ }
+ } else if (product.type.contains("dynamiclibrary")) {
+ args.push("-shared");
+ }
+
+ var optimization = input.cpp.optimization
+ if (optimization === "fast")
+ args.push("-Ot");
+ else if (optimization === "small")
+ args.push("-Os");
+ else if (optimization === "none")
+ args.push("-O0");
+
+ var warnings = input.cpp.warningLevel
+ if (warnings === "none") {
+ args.push("-w");
+ } else if (warnings === "all") {
+ args.push("-Wall");
+ args.push("-Wextra");
+ }
+ if (input.cpp.treatWarningsAsErrors)
+ args.push("-Werror");
+
+ var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(outputs.obj[0].fileTags));
+
+ var langFlag = languageFlag(tag);
+ if (langFlag)
+ args.push(langFlag);
+
+ if (tag === "cpp") {
+ var enableExceptions = input.cpp.enableExceptions;
+ if (enableExceptions) {
+ var ehModel = input.cpp.exceptionHandlingModel;
+ switch (ehModel) {
+ case "direct":
+ args.push("-feh-direct");
+ break;
+ case "table":
+ args.push("-feh-table");
+ break;
+ default:
+ args.push("-feh");
+ break;
+ }
+ } else {
+ args.push("-fno-eh");
+ }
+
+ var enableRtti = input.cpp.enableRtti;
+ args.push(enableRtti ? "-frtti" : "-fno-rtti");
+ } else if (tag === "c") {
+ var knownValues = ["c99", "c89"];
+ var cLanguageVersion = Cpp.languageVersion(input.cpp.cLanguageVersion, knownValues, "C");
+ switch (cLanguageVersion) {
+ case "c89":
+ args.push("-std=c89");
+ break;
+ case "c99":
+ args.push("-std=c99");
+ break;
+ }
+ }
+
+ var preincludePaths = Cpp.collectPreincludePaths(input);
+ for (var i = 0; i < preincludePaths.length; ++i)
+ args.push(input.cpp.preincludeFlag, preincludePaths[i]);
+
+ args = args.concat(Cpp.collectDefinesArguments(input));
+
+ args = args.concat(Cpp.collectIncludePaths(input).map(function(path) {
+ return input.cpp.includeFlag + FileInfo.toNativeSeparators(path);
+ }));
+ args = args.concat(Cpp.collectSystemIncludePaths(input).map(function(path) {
+ return input.cpp.systemIncludeFlag + FileInfo.toNativeSeparators(path);
+ }));
+
+ args = args.concat(Cpp.collectMiscCompilerArguments(input, tag),
+ Cpp.collectMiscDriverArguments(input));
+
+ args.push("-o", FileInfo.toNativeSeparators(outputs.obj[0].filePath));
+ args.push("-c", FileInfo.toNativeSeparators(input.filePath));
+
+ return args;
+}
+
+function resourceCompilerFlags(project, product, input, outputs) {
+ var args = [input.filePath];
+ args.push("-fo=" + FileInfo.toNativeSeparators(outputs.res[0].filePath));
+ args = args.concat(Cpp.collectDefinesArguments(input, "-d"));
+
+ args = args.concat(Cpp.collectIncludePaths(input).map(function(path) {
+ return input.cpp.includeFlag + FileInfo.toNativeSeparators(path);
+ }));
+ args = args.concat(Cpp.collectSystemIncludePaths(input).map(function(path) {
+ return input.cpp.includeFlag + FileInfo.toNativeSeparators(path);
+ }));
+ args.push("-q", "-ad", "-r");
+ return args;
+}
+
+function linkerFlags(project, product, inputs, outputs) {
+ var args = [];
+ var useCompilerDriver = useCompilerDriverLinker(product);
+ if (useCompilerDriver) {
+ var targetPlatform = product.qbs.targetPlatform;
+ if (product.type.contains("application")) {
+ if (targetPlatform === "windows")
+ args.push("-bnt")
+ else if (targetPlatform === "linux")
+ args.push("-blinux")
+ args.push("-o", FileInfo.toNativeSeparators(outputs.application[0].filePath));
+ if (product.cpp.generateLinkerMapFile)
+ args.push("-fm=" + FileInfo.toNativeSeparators(outputs.mem_map[0].filePath));
+ } else if (product.type.contains("dynamiclibrary")) {
+ if (targetPlatform === "windows") {
+ args.push("-bnt_dll")
+ args.push("-Wl, option implib=" + FileInfo.toNativeSeparators(
+ outputs.dynamiclibrary_import[0].filePath));
+ }
+ args.push("-o", FileInfo.toNativeSeparators(outputs.dynamiclibrary[0].filePath))
+ }
+
+ var escapableLinkerFlags = [];
+ var targetLinkerFlags = product.cpp.targetLinkerFlags;
+ if (targetLinkerFlags)
+ escapableLinkerFlags = escapableLinkerFlags.concat(targetLinkerFlags);
+
+ escapableLinkerFlags = escapableLinkerFlags.concat(
+ Cpp.collectMiscEscapableLinkerArguments(product));
+
+ var escapedLinkerFlags = escapeLinkerFlags(useCompilerDriver, escapableLinkerFlags);
+ if (escapedLinkerFlags)
+ args = args.concat(escapedLinkerFlags);
+
+ args = args.concat(Cpp.collectLibraryPaths(product).map(function(path) {
+ return product.cpp.libraryPathFlag + FileInfo.toNativeSeparators(path);
+ }));
+ args = args.concat(Cpp.collectLinkerObjectPaths(inputs).map(function(path) {
+ return FileInfo.toNativeSeparators(path);
+ }));
+
+ var libraryDependencies = Cpp.collectLibraryDependencies(product);
+ for (var i = 0; i < libraryDependencies.length; ++i) {
+ var lib = libraryDependencies[i].filePath;
+ if (FileInfo.isAbsolutePath(lib) || lib.startsWith('@'))
+ args.push(FileInfo.toNativeSeparators(lib));
+ else
+ args.push("-Wl, libfile " + lib);
+ }
+
+ var resourcePaths = Cpp.collectResourceObjectPaths(inputs).map(function(path) {
+ return FileInfo.toNativeSeparators(path);
+ });
+ if (resourcePaths.length > 0)
+ args = args.concat("-Wl, resource " + resourcePaths.join(","));
+ }
+
+ args = args.concat(Cpp.collectMiscLinkerArguments(product),
+ Cpp.collectMiscDriverArguments(product));
+ return args;
+}
+
+function libraryManagerFlags(project, product, inputs, outputs) {
+ var args = ["-b", "-n", "-q"];
+ args = args.concat(Cpp.collectLinkerObjectPaths(inputs).map(function(path) {
+ return "+" + FileInfo.toNativeSeparators(path);
+ }));
+ args.push("-o", FileInfo.toNativeSeparators(outputs.staticlibrary[0].filePath));
+ return args;
+}
+
+function disassemblerFlags(project, product, inputs, outputs) {
+ var objectPath = Cpp.relativePath(product.buildDirectory, outputs.obj[0].filePath);
+ var listingPath = Cpp.relativePath(product.buildDirectory, outputs.lst[0].filePath);
+ var args = [];
+ args.push(FileInfo.toNativeSeparators(objectPath));
+ args.push("-l=" + FileInfo.toNativeSeparators(listingPath));
+ args.push("-s", "-a");
+ return args;
+}
+
+function generateCompilerListing(project, product, inputs, outputs, input, output) {
+ var args = disassemblerFlags(project, product, input, outputs);
+ var cmd = new Command(input.cpp.disassemblerPath, args);
+ cmd.workingDirectory = product.buildDirectory;
+ cmd.silent = true;
+ cmd.jobPool = "watcom_job_pool";
+ return cmd;
+}
+
+function prepareAssembler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
+ var cmds = [];
+ var args = assemblerFlags(project, product, input, outputs);
+ var cmd = new Command(input.cpp.assemblerPath, args);
+ cmd.workingDirectory = product.buildDirectory;
+ cmd.description = "assembling " + input.fileName;
+ cmd.highlight = "compiler";
+ cmd.jobPool = "watcom_job_pool";
+ cmds.push(cmd);
+ if (input.cpp.generateAssemblerListingFiles)
+ cmds.push(generateCompilerListing(project, product, inputs, outputs, input, output));
+ return cmds;
+}
+
+function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
+ var cmds = [];
+ var args = compilerFlags(project, product, input, outputs, explicitlyDependsOn);
+ var cmd = new Command(input.cpp.compilerPath, args);
+ cmd.workingDirectory = product.buildDirectory;
+ cmd.description = "compiling " + input.fileName;
+ cmd.highlight = "compiler";
+ cmd.jobPool = "watcom_job_pool";
+ cmds.push(cmd);
+ if (input.cpp.generateCompilerListingFiles)
+ cmds.push(generateCompilerListing(project, product, inputs, outputs, input, output));
+ return cmds;
+}
+
+function prepareResourceCompiler(project, product, inputs, outputs, input, output,
+ explicitlyDependsOn) {
+ var args = resourceCompilerFlags(project, product, input, outputs);
+ var cmd = new Command(input.cpp.resourceCompilerPath, args);
+ // Set working directory to source directory as a workaround
+ // to make the resources compilable by resource compiler (it is magic).
+ cmd.workingDirectory = product.sourceDirectory;
+ cmd.description = "compiling " + input.fileName;
+ cmd.highlight = "compiler";
+ cmd.jobPool = "watcom_job_pool";
+ return [cmd];
+}
+
+function prepareLinker(project, product, inputs, outputs, input, output) {
+ var primaryOutput = outputs.dynamiclibrary ? outputs.dynamiclibrary[0]
+ : outputs.application[0];
+ var args = linkerFlags(project, product, inputs, outputs);
+ var linkerPath = effectiveLinkerPath(product);
+ var cmd = new Command(linkerPath, args);
+ cmd.workingDirectory = product.buildDirectory;
+ cmd.description = "linking " + primaryOutput.fileName;
+ cmd.highlight = "linker";
+ cmd.jobPool = "watcom_job_pool";
+ return [cmd];
+}
+
+function prepareLibraryManager(project, product, inputs, outputs, input, output) {
+ var args = libraryManagerFlags(project, product, inputs, outputs);
+ var cmd = new Command(product.cpp.libraryManagerPath, args);
+ cmd.workingDirectory = product.buildDirectory;
+ cmd.description = "linking " + outputs.staticlibrary[0].fileName;
+ cmd.highlight = "linker";
+ cmd.jobPool = "watcom_job_pool";
+ return [cmd];
+}
diff --git a/share/qbs/modules/cpp/watcom.qbs b/share/qbs/modules/cpp/watcom.qbs
new file mode 100644
index 000000000..d180b1455
--- /dev/null
+++ b/share/qbs/modules/cpp/watcom.qbs
@@ -0,0 +1,195 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs 1.0
+import qbs.File
+import qbs.FileInfo
+import qbs.ModUtils
+import qbs.Probes
+import "cpp.js" as Cpp
+import "watcom.js" as WATCOM
+
+CppModule {
+ condition: qbs.toolchain && qbs.toolchain.contains("watcom")
+
+ Probes.BinaryProbe {
+ id: compilerPathProbe
+ condition: !toolchainInstallPath && !_skipAllChecks
+ names: ["owcc"]
+ }
+
+ Probes.WatcomProbe {
+ id: watcomProbe
+ condition: !_skipAllChecks
+ compilerFilePath: compilerPath
+ enableDefinesByLanguage: enableCompilerDefinesByLanguage
+ _pathListSeparator: qbs.pathListSeparator
+ _toolchainInstallPath: toolchainInstallPath
+ _targetPlatform: qbs.targetPlatform
+ }
+
+ qbs.architecture: watcomProbe.found ? watcomProbe.architecture : original
+ qbs.targetPlatform: watcomProbe.found ? watcomProbe.targetPlatform : original
+
+ compilerVersionMajor: watcomProbe.versionMajor
+ compilerVersionMinor: watcomProbe.versionMinor
+ compilerVersionPatch: watcomProbe.versionPatch
+ endianness: watcomProbe.endianness
+
+ compilerDefinesByLanguage: watcomProbe.compilerDefinesByLanguage
+ compilerIncludePaths: watcomProbe.includePaths
+
+ toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path : undefined
+
+ /* Work-around for QtCreator which expects these properties to exist. */
+ property string cCompilerName: compilerName
+ property string cxxCompilerName: compilerName
+
+ compilerName: "owcc" + compilerExtension
+ compilerPath: FileInfo.joinPaths(toolchainInstallPath, compilerName)
+
+ assemblerName: "wasm" + compilerExtension
+ assemblerPath: FileInfo.joinPaths(toolchainInstallPath, assemblerName)
+
+ linkerName: "wlink" + compilerExtension
+ linkerPath: FileInfo.joinPaths(toolchainInstallPath, linkerName)
+
+ property string disassemblerName: "wdis" + compilerExtension
+ property string disassemblerPath: FileInfo.joinPaths(toolchainInstallPath,
+ disassemblerName)
+ property string resourceCompilerName: "wrc" + compilerExtension
+ property string resourceCompilerPath: FileInfo.joinPaths(toolchainInstallPath,
+ resourceCompilerName)
+ property string libraryManagerName: "wlib" + compilerExtension
+ property string libraryManagerPath: FileInfo.joinPaths(toolchainInstallPath,
+ libraryManagerName)
+
+ runtimeLibrary: "dynamic"
+
+ staticLibrarySuffix: ".lib"
+ dynamicLibrarySuffix: toolchainDetails.dynamicLibrarySuffix
+ executableSuffix: toolchainDetails.executableSuffix
+ objectSuffix: ".obj"
+
+ imageFormat: toolchainDetails.imageFormat
+
+ defineFlag: "-D"
+ includeFlag: "-I"
+ systemIncludeFlag: "-I"
+ preincludeFlag: "-include"
+ libraryDependencyFlag: "-l"
+ libraryPathFlag: "-L"
+ linkerScriptFlag: ""
+
+ toolchainDetails: WATCOM.toolchainDetails(qbs)
+
+ knownArchitectures: ["x86"]
+
+ property var buildEnv: watcomProbe.environment
+ setupBuildEnvironment: {
+ for (var key in product.cpp.buildEnv) {
+ var v = new ModUtils.EnvironmentVariable(key, product.qbs.pathListSeparator);
+ v.prepend(product.cpp.buildEnv[key]);
+ v.set();
+ }
+ }
+
+ Rule {
+ id: assembler
+ inputs: ["asm"]
+ outputFileTags: Cpp.assemblerOutputTags(generateAssemblerListingFiles)
+ outputArtifacts: Cpp.assemblerOutputArtifacts(input)
+ prepare: WATCOM.prepareAssembler.apply(WATCOM, arguments)
+ }
+
+ FileTagger {
+ patterns: ["*.asm"]
+ fileTags: ["asm"]
+ }
+
+ Rule {
+ id: compiler
+ inputs: ["cpp", "c"]
+ auxiliaryInputs: ["hpp"]
+ outputFileTags: Cpp.compilerOutputTags(generateCompilerListingFiles)
+ outputArtifacts: Cpp.compilerOutputArtifacts(input)
+ prepare: WATCOM.prepareCompiler.apply(WATCOM, arguments)
+ }
+
+ Rule {
+ id: rccCompiler
+ inputs: ["rc"]
+ auxiliaryInputs: ["hpp"]
+ outputFileTags: Cpp.resourceCompilerOutputTags()
+ outputArtifacts: Cpp.resourceCompilerOutputArtifacts(input)
+ prepare: WATCOM.prepareResourceCompiler.apply(WATCOM, arguments)
+ }
+
+ FileTagger {
+ patterns: ["*.rc"]
+ fileTags: ["rc"]
+ }
+
+ Rule {
+ id: applicationLinker
+ multiplex: true
+ inputs: ["obj", "res", "linkerscript"]
+ inputsFromDependencies: ["staticlibrary", "dynamiclibrary_import"]
+ outputFileTags: Cpp.applicationLinkerOutputTags(generateLinkerMapFile)
+ outputArtifacts: Cpp.applicationLinkerOutputArtifacts(product)
+ prepare: WATCOM.prepareLinker.apply(WATCOM, arguments)
+ }
+
+ Rule {
+ id: dynamicLibraryLinker
+ condition: qbs.targetOS.contains("windows")
+ multiplex: true
+ inputs: ["obj", "res"]
+ inputsFromDependencies: ["staticlibrary", "dynamiclibrary_import"]
+ outputFileTags: Cpp.dynamicLibraryLinkerOutputTags();
+ outputArtifacts: Cpp.dynamicLibraryLinkerOutputArtifacts(product)
+ prepare: WATCOM.prepareLinker.apply(WATCOM, arguments)
+ }
+
+ Rule {
+ id: libraryManager
+ multiplex: true
+ inputs: ["obj"]
+ inputsFromDependencies: ["staticlibrary", "dynamiclibrary_import"]
+ outputFileTags: Cpp.staticLibraryLinkerOutputTags()
+ outputArtifacts: Cpp.staticLibraryLinkerOutputArtifacts(product)
+ prepare: WATCOM.prepareLibraryManager.apply(WATCOM, arguments)
+ }
+
+ JobLimit {
+ jobPool: "watcom_job_pool"
+ jobCount: 1
+ }
+}
diff --git a/src/app/qbs-setup-toolchains/CMakeLists.txt b/src/app/qbs-setup-toolchains/CMakeLists.txt
index bb287be52..64347cd6c 100644
--- a/src/app/qbs-setup-toolchains/CMakeLists.txt
+++ b/src/app/qbs-setup-toolchains/CMakeLists.txt
@@ -20,6 +20,8 @@ set(SOURCES
probe.h
sdccprobe.cpp
sdccprobe.h
+ watcomprobe.cpp
+ watcomprobe.h
xcodeprobe.cpp
xcodeprobe.h
)
diff --git a/src/app/qbs-setup-toolchains/probe.cpp b/src/app/qbs-setup-toolchains/probe.cpp
index 5a04232e1..ceb95948b 100644
--- a/src/app/qbs-setup-toolchains/probe.cpp
+++ b/src/app/qbs-setup-toolchains/probe.cpp
@@ -46,6 +46,7 @@
#include "keilprobe.h"
#include "msvcprobe.h"
#include "sdccprobe.h"
+#include "watcomprobe.h"
#include "xcodeprobe.h"
#include <logging/translator.h>
@@ -123,6 +124,8 @@ QString toolchainTypeFromCompilerName(const QString &compilerName)
return QStringLiteral("cosmic");
if (isDmcCompiler(compilerName))
return QStringLiteral("dmc");
+ if (isWatcomCompiler(compilerName))
+ return QStringLiteral("watcom");
return {};
}
@@ -144,6 +147,7 @@ void probe(Settings *settings)
sdccProbe(settings, profiles);
cosmicProbe(settings, profiles);
dmcProbe(settings, profiles);
+ watcomProbe(settings, profiles);
if (profiles.empty()) {
qStderr << Tr::tr("Could not detect any toolchains. No profile created.") << Qt::endl;
@@ -187,6 +191,8 @@ void createProfile(const QString &profileName, const QString &toolchainType,
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."));
}
diff --git a/src/app/qbs-setup-toolchains/probe.h b/src/app/qbs-setup-toolchains/probe.h
index e97530285..827171fb2 100644
--- a/src/app/qbs-setup-toolchains/probe.h
+++ b/src/app/qbs-setup-toolchains/probe.h
@@ -80,8 +80,6 @@ int extractVersion(const QByteArray &macroDump, const QByteArray &keyToken);
bool isSameExecutable(const QString &exe1, const QString &exe2);
using MacrosMap = QMap<QString, QString>;
-using DefinesList = QVector<QByteArray>;
-
MacrosMap dumpMacros(const std::function<QStringList()> &func);
#endif // Header guard
diff --git a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro
index 1ae1c710d..69d6552ee 100644
--- a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro
+++ b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro
@@ -13,6 +13,7 @@ HEADERS += \
msvcprobe.h \
probe.h \
sdccprobe.h \
+ watcomprobe.h \
xcodeprobe.h \
SOURCES += \
@@ -27,6 +28,7 @@ SOURCES += \
msvcprobe.cpp \
probe.cpp \
sdccprobe.cpp \
+ watcomprobe.cpp \
xcodeprobe.cpp \
mingw {
diff --git a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs
index 2daf916e9..6987f3717 100644
--- a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs
+++ b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs
@@ -23,6 +23,8 @@ QbsApp {
"probe.h",
"sdccprobe.cpp",
"sdccprobe.h",
+ "watcomprobe.cpp",
+ "watcomprobe.h",
"xcodeprobe.cpp",
"xcodeprobe.h",
]
diff --git a/src/app/qbs-setup-toolchains/watcomprobe.cpp b/src/app/qbs-setup-toolchains/watcomprobe.cpp
new file mode 100644
index 000000000..9765f7424
--- /dev/null
+++ b/src/app/qbs-setup-toolchains/watcomprobe.cpp
@@ -0,0 +1,200 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "watcomprobe.h"
+#include "probe.h"
+
+#include "../shared/logging/consolelogger.h"
+
+#include <logging/translator.h>
+
+#include <tools/hostosinfo.h>
+#include <tools/profile.h>
+
+#include <QtCore/qdir.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qprocess.h>
+#include <QtCore/qregularexpression.h>
+#include <QtCore/qsettings.h>
+#include <QtCore/qtemporaryfile.h>
+
+using namespace qbs;
+using Internal::HostOsInfo;
+using Internal::Tr;
+
+static QStringList knownWatcomCompilerNames()
+{
+ return {QStringLiteral("owcc")};
+}
+
+static QStringList dumpOutput(const QFileInfo &compiler, const QStringList &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 QStringList{};
+ }
+ 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 QString &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;
+ p.start(compiler.absoluteFilePath(), {QDir::toNativeSeparators(filePath)});
+ p.waitForFinished(3000);
+ fakeIn.remove();
+ const QStringList lines = QString::fromUtf8(p.readAllStandardOutput())
+ .split(QRegularExpression(QLatin1String("\\r?\\n")));
+ return lines;
+}
+
+static QString guessWatcomArchitecture(const QFileInfo &compiler)
+{
+ const QStringList keys = {QStringLiteral("__I86__"), QStringLiteral("__386__")};
+ const auto macros = dumpMacros([&compiler, &keys]() { return dumpOutput(compiler, keys); });
+ for (auto index = 0; index < keys.count(); ++index) {
+ const auto &key = keys.at(index);
+ if (macros.contains(key) && macros.value(key) == QLatin1String("1")) {
+ switch (index) {
+ case 0:
+ return QLatin1String("x86_16");
+ case 1:
+ return QLatin1String("x86");
+ default:
+ break;
+ }
+ }
+ }
+ return QLatin1String("unknown");
+}
+
+static Profile createWatcomProfileHelper(const ToolchainInstallInfo &info,
+ Settings *settings,
+ QString profileName = QString())
+{
+ const QFileInfo compiler = info.compilerPath;
+ const QString architecture = guessWatcomArchitecture(compiler);
+
+ // In case the profile is auto-detected.
+ if (profileName.isEmpty()) {
+ if (!info.compilerVersion.isValid()) {
+ profileName = QStringLiteral("watcom-unknown-%1").arg(architecture);
+ } else {
+ const QString version = info.compilerVersion.toString(QLatin1Char('_'),
+ QLatin1Char('_'));
+ profileName = QStringLiteral("watcom-%1-%2").arg(version, architecture);
+ }
+ }
+
+ Profile profile(profileName, settings);
+ profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath());
+ profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("watcom"));
+ 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 dumpWatcomVersion(const QFileInfo &compiler)
+{
+ const QStringList keys = {QStringLiteral("__WATCOMC__"),
+ QStringLiteral("__WATCOM_CPLUSPLUS__")};
+ const auto macros = dumpMacros([&compiler, &keys]() { return dumpOutput(compiler, keys); });
+ for (const auto &macro : 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<ToolchainInstallInfo> installedWatcomsFromPath()
+{
+ std::vector<ToolchainInstallInfo> 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, QString profileName)
+{
+ const ToolchainInstallInfo info = {compiler, Version{}};
+ createWatcomProfileHelper(info, settings, std::move(profileName));
+}
+
+void watcomProbe(Settings *settings, std::vector<Profile> &profiles)
+{
+ qbsInfo() << Tr::tr("Trying to detect WATCOM toolchains...");
+
+ const std::vector<ToolchainInstallInfo> allInfos = installedWatcomsFromPath();
+ if (allInfos.empty()) {
+ qbsInfo() << Tr::tr("No WATCOM toolchains found.");
+ return;
+ }
+
+ qbs::Internal::transform(allInfos, profiles, [settings](const auto &info) {
+ return createWatcomProfileHelper(info, settings); });
+}
diff --git a/src/app/qbs-setup-toolchains/watcomprobe.h b/src/app/qbs-setup-toolchains/watcomprobe.h
new file mode 100644
index 000000000..26e75bbc3
--- /dev/null
+++ b/src/app/qbs-setup-toolchains/watcomprobe.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBS_SETUPTOOLCHAINS_WATCOMPROBE_H
+#define QBS_SETUPTOOLCHAINS_WATCOMPROBE_H
+
+#include <QtCore/qlist.h>
+
+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, QString profileName);
+void watcomProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles);
+
+#endif // Header guard
diff --git a/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/compiler-defines-by-language.qbs b/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/compiler-defines-by-language.qbs
index bfd10106d..7eb2af6db 100644
--- a/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/compiler-defines-by-language.qbs
+++ b/tests/auto/blackbox/testdata-baremetal/compiler-defines-by-language/compiler-defines-by-language.qbs
@@ -38,6 +38,7 @@ Project {
name: "cpp_language"
files: ["app.c", "cpptest.cpp"]
cpp.enableCompilerDefinesByLanguage: ["cpp"]
+ cpp.enableExceptions: false
property var foo: {
if (!cpp.compilerDefinesByLanguage)
throw "ASSERT cpp.compilerDefinesByLanguage: "
@@ -56,6 +57,7 @@ Project {
name: "c_and_cpp_language"
files: ["app.c", "ctest.c", "cpptest.cpp"]
cpp.enableCompilerDefinesByLanguage: ["c", "cpp"]
+ cpp.enableExceptions: false
property var foo: {
if (!cpp.compilerDefinesByLanguage)
throw "ASSERT cpp.compilerDefinesByLanguage: "