diff options
| author | Jake Petroules <jake.petroules@theqtcompany.com> | 2016-03-14 20:59:01 -0700 |
|---|---|---|
| committer | Jake Petroules <jake.petroules@qt.io> | 2016-04-14 12:10:20 +0000 |
| commit | a235900a7368fd2edf269454016c7577cb674323 (patch) | |
| tree | ad086fd5435f5adb5184385681dd400371216bff | |
| parent | 60a2203b9cf41f352e418d611d7953f1edddec2e (diff) | |
| download | qbs-a235900a7368fd2edf269454016c7577cb674323.tar.gz | |
Implement properties to control use of exception handling.
Task-number: QBS-387
Change-Id: Ia3d8bfe30b0362f1e7b6892cba32ddfb569bdbc4
Reviewed-by: Christian Kandeler <christian.kandeler@theqtcompany.com>
19 files changed, 157 insertions, 14 deletions
diff --git a/doc/reference/modules/android-ndk-module.qdoc b/doc/reference/modules/android-ndk-module.qdoc index 0d9e10e52..533e3183a 100644 --- a/doc/reference/modules/android-ndk-module.qdoc +++ b/doc/reference/modules/android-ndk-module.qdoc @@ -97,12 +97,6 @@ \li undefined \li Whether to use the hard floating point variant of the armeabi-v7a ABI. \row - \li enableExceptions - \li bool - \li 1.4 - \li \c{appStl !== "system"} - \li Whether to enable exceptions in C++ code. - \row \li enableRtti \li bool \li 1.4 diff --git a/doc/reference/modules/cpp-module.qdoc b/doc/reference/modules/cpp-module.qdoc index 49d681260..25a3a8467 100644 --- a/doc/reference/modules/cpp-module.qdoc +++ b/doc/reference/modules/cpp-module.qdoc @@ -329,7 +329,20 @@ toolchain is used. \note For MSVC the default value is \c{"dynamic"}. \note At the moment this property is only functional for MSVC. - + \row + \li enableExceptions + \li \c{bool} + \li 1.5 + \li \c{undefined} + \li Whether to enable exceptions in C++ code. + \row + \li exceptionHandlingModel + \li \c{string} + \li 1.5 + \li \c{"default"} + \li The exception handling model to use. For MSVC, this can be \c{"default"}, \c{"seh"} or + \c{"externc"}. For all other compilers, \c{"default"} indicates the default or only + exception handling model. \row \li enableReproducibleBuilds \li \c{bool} diff --git a/share/qbs/modules/Android/ndk/ndk.qbs b/share/qbs/modules/Android/ndk/ndk.qbs index d9ea534d5..030293ebf 100644 --- a/share/qbs/modules/Android/ndk/ndk.qbs +++ b/share/qbs/modules/Android/ndk/ndk.qbs @@ -77,7 +77,6 @@ Module { return cpp.toolchainPrefix + toolchainVersionNumber; } - property bool enableExceptions: appStl !== "system" property bool enableRtti: appStl !== "system" property bool hardFloat property string ndkDir: ndkProbe.path @@ -206,16 +205,14 @@ Module { qbs.optimization: cpp.targetAbi === "androideabi" ? "small" : base + cpp.enableExceptions: appStl !== "system" + cpp.commonCompilerFlags: NdkUtils.commonCompilerFlags(qbs.buildVariant, abi, hardFloat, armMode) cpp.linkerFlags: NdkUtils.commonLinkerFlags(abi, hardFloat) cpp.cxxFlags: { var flags = []; - if (enableExceptions) - flags.push("-fexceptions"); - else - flags.push("-fno-exceptions"); if (enableRtti) flags.push("-frtti"); else diff --git a/share/qbs/modules/cpp/CppModule.qbs b/share/qbs/modules/cpp/CppModule.qbs index df10fd1dc..58bac982a 100644 --- a/share/qbs/modules/cpp/CppModule.qbs +++ b/share/qbs/modules/cpp/CppModule.qbs @@ -271,6 +271,9 @@ Module { description: "version of the C++ standard library to use" } + property bool enableExceptions + property string exceptionHandlingModel: "default" + // Platform properties. Those are intended to be set by the toolchain setup // and are prepended to the corresponding user properties. property stringList platformAssemblerFlags diff --git a/share/qbs/modules/cpp/GenericGCC.qbs b/share/qbs/modules/cpp/GenericGCC.qbs index 1424e5297..28f2652bd 100644 --- a/share/qbs/modules/cpp/GenericGCC.qbs +++ b/share/qbs/modules/cpp/GenericGCC.qbs @@ -137,6 +137,26 @@ CppModule { return versionParts.join('.'); } + exceptionHandlingModel: { + if (qbs.toolchain.contains("mingw")) { + // https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html claims + // __USING_SJLJ_EXCEPTIONS__ is defined as 1 when using SJLJ exceptions, but there don't + // seem to be defines for the other models, so use the presence of the DLLs for now. + var prefix = toolchainInstallPath; + if (!qbs.hostOS.contains("windows")) + prefix = FileInfo.joinPaths(toolchainInstallPath, "..", "lib", "gcc", + toolchainPrefix, + [compilerVersionMajor, compilerVersionMinor].join(".")); + var models = ["seh", "sjlj", "dw2"]; + for (var i = 0; i < models.length; ++i) { + if (File.exists(FileInfo.joinPaths(prefix, "libgcc_s_" + models[i] + "-1.dll"))) { + return models[i]; + } + } + } + return base; + } + validate: { var validator = new ModUtils.PropertyValidator("cpp"); validator.setRequiredProperty("architecture", architecture, diff --git a/share/qbs/modules/cpp/gcc.js b/share/qbs/modules/cpp/gcc.js index 8c1a3160f..0154c8ac4 100644 --- a/share/qbs/modules/cpp/gcc.js +++ b/share/qbs/modules/cpp/gcc.js @@ -420,6 +420,18 @@ function compilerFlags(product, input, output) { args.push(useArc ? "-fobjc-arc" : "-fno-objc-arc"); } + var enableExceptions = ModUtils.moduleProperty(input, "enableExceptions"); + if (enableExceptions !== undefined) { + if (tag === "cpp" || tag === "objcpp") + args.push(enableExceptions ? "-fexceptions" : "-fno-exceptions"); + + if (tag === "objc" || tag === "objcpp") { + args.push(enableExceptions ? "-fobjc-exceptions" : "-fno-objc-exceptions"); + if (useArc !== undefined) + args.push(useArc ? "-fobjc-arc-exceptions" : "-fno-objc-arc-exceptions"); + } + } + var visibility = ModUtils.moduleProperty(input, 'visibility'); if (!product.type.contains('staticlibrary') && !product.moduleProperty("qbs", "toolchain").contains("mingw")) { diff --git a/share/qbs/modules/cpp/msvc.js b/share/qbs/modules/cpp/msvc.js index aff810c27..70636aa3b 100644 --- a/share/qbs/modules/cpp/msvc.js +++ b/share/qbs/modules/cpp/msvc.js @@ -47,8 +47,22 @@ function prepareCompiler(project, product, inputs, outputs, input, output) { // Whether we're compiling a precompiled header or normal source file var pchOutput = outputs[tag + "_pch"] ? outputs[tag + "_pch"][0] : undefined; - // enable unwind semantics - args.push("/EHsc") + var enableExceptions = ModUtils.moduleProperty(input, "enableExceptions"); + if (enableExceptions) { + var ehModel = ModUtils.moduleProperty(input, "exceptionHandlingModel"); + switch (ehModel) { + case "default": + args.push("/EHsc"); // "Yes" in VS + break; + case "seh": + args.push("/EHa"); // "Yes with SEH exceptions" in VS + break; + case "externc": + args.push("/EHs"); // "Yes with Extern C functions" in VS + break; + } + } + // optimization: if (optimization === 'small') args.push('/Os') diff --git a/tests/auto/blackbox/testdata/enableExceptions/empty.m b/tests/auto/blackbox/testdata/enableExceptions/empty.m new file mode 100644 index 000000000..d3714dc09 --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/empty.m @@ -0,0 +1 @@ +int main2() { return 0; } diff --git a/tests/auto/blackbox/testdata/enableExceptions/empty.mm b/tests/auto/blackbox/testdata/enableExceptions/empty.mm new file mode 100644 index 000000000..fe94a49a3 --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/empty.mm @@ -0,0 +1 @@ +int main3() { return 0; } diff --git a/tests/auto/blackbox/testdata/enableExceptions/emptymain.cpp b/tests/auto/blackbox/testdata/enableExceptions/emptymain.cpp new file mode 100644 index 000000000..76e819701 --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/emptymain.cpp @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/tests/auto/blackbox/testdata/enableExceptions/exceptions-objc.qbs b/tests/auto/blackbox/testdata/enableExceptions/exceptions-objc.qbs new file mode 100644 index 000000000..74738ad12 --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/exceptions-objc.qbs @@ -0,0 +1,6 @@ +import qbs + +CppApplication { + files: ["main.m"] + cpp.frameworks: ["Foundation"] +} diff --git a/tests/auto/blackbox/testdata/enableExceptions/exceptions-objcpp-cpp.qbs b/tests/auto/blackbox/testdata/enableExceptions/exceptions-objcpp-cpp.qbs new file mode 100644 index 000000000..679cdebbe --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/exceptions-objcpp-cpp.qbs @@ -0,0 +1,6 @@ +import qbs + +CppApplication { + files: ["main.cpp"] + fileTags: ["objcpp"] +} diff --git a/tests/auto/blackbox/testdata/enableExceptions/exceptions-objcpp.qbs b/tests/auto/blackbox/testdata/enableExceptions/exceptions-objcpp.qbs new file mode 100644 index 000000000..6856f53bb --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/exceptions-objcpp.qbs @@ -0,0 +1,7 @@ +import qbs + +CppApplication { + files: ["main.m"] + fileTags: ["objcpp"] + cpp.frameworks: ["Foundation"] +} diff --git a/tests/auto/blackbox/testdata/enableExceptions/exceptions.qbs b/tests/auto/blackbox/testdata/enableExceptions/exceptions.qbs new file mode 100644 index 000000000..da6fdbc2d --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/exceptions.qbs @@ -0,0 +1,7 @@ +import qbs + +CppApplication { + files: ["main.cpp"] + cpp.treatWarningsAsErrors: true + cpp.defines: qbs.toolchain.contains("msvc") && !cpp.enableExceptions ? ["FORCE_FAIL_VS"] : [] +} diff --git a/tests/auto/blackbox/testdata/enableExceptions/main.cpp b/tests/auto/blackbox/testdata/enableExceptions/main.cpp new file mode 100644 index 000000000..1b99ea96d --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/main.cpp @@ -0,0 +1,8 @@ +#include <stdexcept> + +int main() { +#ifdef FORCE_FAIL_VS +#error "Microsoft Visual C++ cannot disable exceptions at compile-time" +#endif + throw std::runtime_error("failed"); +} diff --git a/tests/auto/blackbox/testdata/enableExceptions/main.m b/tests/auto/blackbox/testdata/enableExceptions/main.m new file mode 100644 index 000000000..86b45fc37 --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/main.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> + +int main() { + @throw [NSError new]; +} diff --git a/tests/auto/blackbox/testdata/enableExceptions/none.qbs b/tests/auto/blackbox/testdata/enableExceptions/none.qbs new file mode 100644 index 000000000..102e4c261 --- /dev/null +++ b/tests/auto/blackbox/testdata/enableExceptions/none.qbs @@ -0,0 +1,5 @@ +import qbs + +CppApplication { + files: ["emptymain.cpp", "empty.m", "empty.mm"] +} diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp index 98765d9e1..dc34aeb28 100644 --- a/tests/auto/blackbox/tst_blackbox.cpp +++ b/tests/auto/blackbox/tst_blackbox.cpp @@ -3171,6 +3171,47 @@ void TestBlackbox::embedInfoPlist() QVERIFY(getEmbeddedBinaryPlist(defaultInstallRoot + "/mod.bundle").isEmpty()); } +void TestBlackbox::enableExceptions() +{ + QFETCH(QString, file); + QFETCH(bool, enable); + QFETCH(bool, expectSuccess); + + QDir::setCurrent(testDataDir + QStringLiteral("/enableExceptions")); + + QbsRunParameters params; + params.arguments = QStringList() << "-f" << file << (QStringLiteral("cpp.enableExceptions:") + + (enable ? "true" : "false")); + params.expectFailure = !expectSuccess; + rmDirR(relativeBuildDir()); + if (!params.expectFailure) + QCOMPARE(runQbs(params), 0); + else + QVERIFY(runQbs(params) != 0); +} + +void TestBlackbox::enableExceptions_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<bool>("enable"); + QTest::addColumn<bool>("expectSuccess"); + + QTest::newRow("no exceptions, enabled") << "none.qbs" << true << true; + QTest::newRow("no exceptions, disabled") << "none.qbs" << false << true; + + QTest::newRow("C++ exceptions, enabled") << "exceptions.qbs" << true << true; + QTest::newRow("C++ exceptions, disabled") << "exceptions.qbs" << false << false; + + if (HostOsInfo::isOsxHost()) { + QTest::newRow("Objective-C exceptions, enabled") << "exceptions-objc.qbs" << true << true; + QTest::newRow("Objective-C exceptions in Objective-C++ source, enabled") << "exceptions-objcpp.qbs" << true << true; + QTest::newRow("C++ exceptions in Objective-C++ source, enabled") << "exceptions-objcpp-cpp.qbs" << true << true; + QTest::newRow("Objective-C, disabled") << "exceptions-objc.qbs" << false << false; + QTest::newRow("Objective-C exceptions in Objective-C++ source, disabled") << "exceptions-objcpp.qbs" << false << false; + QTest::newRow("C++ exceptions in Objective-C++ source, disabled") << "exceptions-objcpp-cpp.qbs" << false << false; + } +} + void TestBlackbox::frameworkStructure() { if (!HostOsInfo::isOsxHost()) diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h index 770ffed5f..0ac257b88 100644 --- a/tests/auto/blackbox/tst_blackbox.h +++ b/tests/auto/blackbox/tst_blackbox.h @@ -120,6 +120,8 @@ private slots: void dynamicMultiplexRule(); void dynamicRuleOutputs(); void embedInfoPlist(); + void enableExceptions(); + void enableExceptions_data(); void erroneousFiles_data(); void erroneousFiles(); void exportRule(); |
