aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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: "