Ejemplo n.º 1
0
def parseFeature(ctx, feature, data, cm_fh):
    feature_mapping = get_feature_mapping()
    mapping = feature_mapping.get(feature, {})

    if mapping is None:
        print(f"    **** Skipping features {feature}: masked.")
        return

    handled = {
        "autoDetect",
        "comment",
        "condition",
        "description",
        "disable",
        "emitIf",
        "enable",
        "label",
        "output",
        "purpose",
        "section",
    }
    label = mapping.get("label", data.get("label", ""))
    purpose = mapping.get("purpose",
                          data.get("purpose", data.get("description", label)))
    autoDetect = map_condition(
        mapping.get("autoDetect", data.get("autoDetect", "")))
    condition = map_condition(
        mapping.get("condition", data.get("condition", "")))
    output = mapping.get("output", data.get("output", []))
    comment = mapping.get("comment", data.get("comment", ""))
    section = mapping.get("section", data.get("section", ""))
    enable = map_condition(mapping.get("enable", data.get("enable", "")))
    disable = map_condition(mapping.get("disable", data.get("disable", "")))
    emitIf = map_condition(mapping.get("emitIf", data.get("emitIf", "")))

    for k in [k for k in data.keys() if k not in handled]:
        print(f"    XXXX UNHANDLED KEY {k} in feature description")

    if not output:
        # feature that is only used in the conditions of other features
        output = ["internalFeature"]

    publicFeature = False  # #define QT_FEATURE_featurename in public header
    privateFeature = False  # #define QT_FEATURE_featurename in private header
    negativeFeature = False  # #define QT_NO_featurename in public header
    internalFeature = False  # No custom or QT_FEATURE_ defines
    publicDefine = False  # #define MY_CUSTOM_DEFINE in public header
    publicConfig = False  # add to CONFIG in public pri file
    privateConfig = False  # add to CONFIG in private pri file
    publicQtConfig = False  # add to QT_CONFIG in public pri file

    for o in output:
        outputType = o
        if isinstance(o, dict):
            outputType = o["type"]

        if outputType in ["varAssign", "varAppend", "varRemove"]:
            continue
        elif outputType == "define":
            publicDefine = True
        elif outputType == "feature":
            negativeFeature = True
        elif outputType == "publicFeature":
            publicFeature = True
        elif outputType == "privateFeature":
            privateFeature = True
        elif outputType == "internalFeature":
            internalFeature = True
        elif outputType == "publicConfig":
            publicConfig = True
        elif outputType == "privateConfig":
            privateConfig = True
        elif outputType == "publicQtConfig":
            publicQtConfig = True
        else:
            print(
                f"    XXXX UNHANDLED OUTPUT TYPE {outputType} in feature {feature}."
            )
            continue

    if not any([
            publicFeature,
            privateFeature,
            internalFeature,
            publicDefine,
            negativeFeature,
            publicConfig,
            privateConfig,
            publicQtConfig,
    ]):
        print(f"    **** Skipping feature {feature}: Not relevant for C++.")
        return

    normalized_feature_name = featureName(feature)

    def writeFeature(
        name,
        publicFeature=False,
        privateFeature=False,
        labelAppend="",
        superFeature=None,
        autoDetect="",
    ):
        if comment:
            cm_fh.write(f"# {comment}\n")

        cm_fh.write(f'qt_feature("{name}"')
        if publicFeature:
            cm_fh.write(" PUBLIC")
        if privateFeature:
            cm_fh.write(" PRIVATE")
        cm_fh.write("\n")

        cm_fh.write(lineify("SECTION", section))
        cm_fh.write(lineify("LABEL", label + labelAppend))
        if purpose != label:
            cm_fh.write(lineify("PURPOSE", purpose))
        cm_fh.write(lineify("AUTODETECT", autoDetect, quote=False))
        if superFeature:
            feature_condition = f"QT_FEATURE_{superFeature}"
        else:
            feature_condition = condition
        cm_fh.write(lineify("CONDITION", feature_condition, quote=False))
        cm_fh.write(lineify("ENABLE", enable, quote=False))
        cm_fh.write(lineify("DISABLE", disable, quote=False))
        cm_fh.write(lineify("EMIT_IF", emitIf, quote=False))
        cm_fh.write(")\n")

    # Write qt_feature() calls before any qt_feature_definition() calls

    # Default internal feature case.
    featureCalls = {}
    featureCalls[feature] = {
        "name": feature,
        "labelAppend": "",
        "autoDetect": autoDetect
    }

    # Go over all outputs to compute the number of features that have to be declared
    for o in output:
        outputType = o
        name = feature

        # The label append is to provide a unique label for features that have more than one output
        # with different names.
        labelAppend = ""

        if isinstance(o, dict):
            outputType = o["type"]
            if "name" in o:
                name = o["name"]
                labelAppend = f": {o['name']}"

        if outputType not in ["feature", "publicFeature", "privateFeature"]:
            continue
        if name not in featureCalls:
            featureCalls[name] = {"name": name, "labelAppend": labelAppend}

        if name != feature:
            featureCalls[name]["superFeature"] = normalized_feature_name

        if outputType in ["feature", "publicFeature"]:
            featureCalls[name]["publicFeature"] = True
        elif outputType == "privateFeature":
            featureCalls[name]["privateFeature"] = True
        elif outputType == "publicConfig":
            featureCalls[name]["publicConfig"] = True
        elif outputType == "privateConfig":
            featureCalls[name]["privateConfig"] = True
        elif outputType == "publicQtConfig":
            featureCalls[name]["publicQtConfig"] = True

    # Write the qt_feature() calls from the computed feature map
    for _, args in featureCalls.items():
        writeFeature(**args)

    # Write qt_feature_definition() calls
    for o in output:
        outputType = o
        outputArgs = {}
        if isinstance(o, dict):
            outputType = o["type"]
            outputArgs = o

        # Map negative feature to define:
        if outputType == "feature":
            outputType = "define"
            outputArgs = {
                "name": f"QT_NO_{normalized_feature_name.upper()}",
                "negative": True,
                "value": 1,
                "type": "define",
            }

        if outputType != "define":
            continue

        if outputArgs.get("name") is None:
            print(f"    XXXX DEFINE output without name in feature {feature}.")
            continue

        out_name = outputArgs.get("name")
        cm_fh.write(f'qt_feature_definition("{feature}" "{out_name}"')
        if outputArgs.get("negative", False):
            cm_fh.write(" NEGATE")
        if outputArgs.get("value") is not None:
            cm_fh.write(f' VALUE "{outputArgs.get("value")}"')
        if outputArgs.get("prerequisite") is not None:
            cm_fh.write(f' PREREQUISITE "{outputArgs.get("prerequisite")}"')
        cm_fh.write(")\n")

    # Write qt_feature_config() calls
    for o in output:
        outputType = o
        name = feature
        modified_name = name

        outputArgs = {}
        if isinstance(o, dict):
            outputType = o["type"]
            outputArgs = o
            if "name" in o:
                modified_name = o["name"]

        if outputType not in [
                "publicConfig", "privateConfig", "publicQtConfig"
        ]:
            continue

        config_type = ""
        if outputType == "publicConfig":
            config_type = "QMAKE_PUBLIC_CONFIG"
        elif outputType == "privateConfig":
            config_type = "QMAKE_PRIVATE_CONFIG"
        elif outputType == "publicQtConfig":
            config_type = "QMAKE_PUBLIC_QT_CONFIG"

        if not config_type:
            print("    XXXX config output without type in feature {}.".format(
                feature))
            continue

        cm_fh.write('qt_feature_config("{}" {}'.format(name, config_type))
        if outputArgs.get("negative", False):
            cm_fh.write("\n    NEGATE")
        if modified_name != name:
            cm_fh.write("\n")
            cm_fh.write(lineify("NAME", modified_name, quote=True))

        cm_fh.write(")\n")
Ejemplo n.º 2
0
def parseFeature(ctx, feature, data, cm_fh):
    # This is *before* the feature name gets normalized! So keep - and + chars, etc.
    feature_mapping = {
        "alloc_h": None,  # handled by alloc target
        "alloc_malloc_h": None,
        "alloc_stdlib_h": None,
        "build_all": None,
        "c11": None,
        "c89": None,
        "c99": None,
        "ccache": None,
        "compiler-flags": None,
        "cross_compile": None,
        "debug_and_release": None,
        "debug": None,
        "dlopen": {"condition": "UNIX"},
        "doubleconversion": None,
        "enable_gdb_index": None,
        "enable_new_dtags": None,
        "force_debug_info": None,
        "framework": {"condition": "APPLE AND BUILD_SHARED_LIBS"},
        "gc_binaries": None,
        "gcc-sysroot": None,
        "gcov": None,
        "gnu-libiconv": {
            "condition": "NOT WIN32 AND NOT QNX AND NOT ANDROID AND NOT APPLE AND TEST_posix_iconv AND NOT TEST_iconv_needlib",
            "enable": "TEST_posix_iconv AND NOT TEST_iconv_needlib",
            "disable": "NOT TEST_posix_iconv OR TEST_iconv_needlib",
        },
        "GNUmake": None,
        "harfbuzz": {"condition": "harfbuzz_FOUND"},
        "host-dbus": None,
        "iconv": {
            "condition": "NOT QT_FEATURE_icu AND QT_FEATURE_textcodec AND ( TEST_posix_iconv OR TEST_sun_iconv )"
        },
        "incredibuild_xge": None,
        "jpeg": {"condition": "QT_FEATURE_imageformatplugin AND JPEG_FOUND"},
        "ltcg": None,
        "msvc_mp": None,
        "optimize_debug": None,
        "optimize_size": None,
        # special case to enable implicit feature on WIN32, until ANGLE is ported
        "opengl-desktop": {"autoDetect": ""},
        # special case to disable implicit feature on WIN32, until ANGLE is ported
        "opengl-dynamic": {"autoDetect": "OFF"},
        "opengles2": {  # special case to disable implicit feature on WIN32, until ANGLE is ported
            "condition": "NOT WIN32 AND ( NOT APPLE_WATCHOS AND NOT QT_FEATURE_opengl_desktop AND GLESv2_FOUND )"
        },
        "simulator_and_device": {"condition": "APPLE_UIKIT AND NOT QT_UIKIT_SDK"},
        "pkg-config": None,
        "posix_fallocate": None,  # Only needed for sqlite, which we do not want to build
        "posix-libiconv": {
            "condition": "NOT WIN32 AND NOT QNX AND NOT ANDROID AND NOT APPLE AND TEST_posix_iconv AND TEST_iconv_needlib",
            "enable": "TEST_posix_iconv AND TEST_iconv_needlib",
            "disable": "NOT TEST_posix_iconv OR NOT TEST_iconv_needlib",
        },
        "precompile_header": None,
        "profile": None,
        "qmakeargs": None,
        "qpa_default_platform": None,  # Not a bool!
        "release": None,
        "release_tools": None,
        "rpath_dir": None,  # rpath related
        "rpath": None,
        "sanitize_address": None,  # sanitizer
        "sanitize_memory": None,
        "sanitizer": None,
        "sanitize_thread": None,
        "sanitize_undefined": None,
        "separate_debug_info": None,
        "shared": None,
        "silent": None,
        "sql-sqlite": {"condition": "QT_FEATURE_datestring AND SQLite3_FOUND"},
        "stack-protector-strong": None,
        "static": None,
        "static_runtime": None,
        "stl": None,  # Do we really need to test for this in 2018?!
        "strip": None,
        "sun-libiconv": {
            "condition": "NOT WIN32 AND NOT QNX AND NOT ANDROID AND NOT APPLE AND TEST_sun_iconv",
            "enable": "TEST_sun_iconv",
            "disable": "NOT TEST_sun_iconv",
        },
        "system-doubleconversion": None,  # No system libraries anymore!
        "system-sqlite": None,
        "system-xcb": None,
        "tiff": {"condition": "QT_FEATURE_imageformatplugin AND TIFF_FOUND"},
        "use_gold_linker": None,
        "verifyspec": None,  # qmake specific...
        "warnings_are_errors": None,  # FIXME: Do we need these?
        "webp": {"condition": "QT_FEATURE_imageformatplugin AND WrapWebP_FOUND"},
        "xkbcommon-system": None,  # another system library, just named a bit different from the rest
    }

    mapping = feature_mapping.get(feature, {})

    if mapping is None:
        print(f"    **** Skipping features {feature}: masked.")
        return

    handled = {
        "autoDetect",
        "comment",
        "condition",
        "description",
        "disable",
        "emitIf",
        "enable",
        "label",
        "output",
        "purpose",
        "section",
    }
    label = mapping.get("label", data.get("label", ""))
    purpose = mapping.get("purpose", data.get("purpose", data.get("description", label)))
    autoDetect = map_condition(mapping.get("autoDetect", data.get("autoDetect", "")))
    condition = map_condition(mapping.get("condition", data.get("condition", "")))
    output = mapping.get("output", data.get("output", []))
    comment = mapping.get("comment", data.get("comment", ""))
    section = mapping.get("section", data.get("section", ""))
    enable = map_condition(mapping.get("enable", data.get("enable", "")))
    disable = map_condition(mapping.get("disable", data.get("disable", "")))
    emitIf = map_condition(mapping.get("emitIf", data.get("emitIf", "")))

    for k in [k for k in data.keys() if k not in handled]:
        print(f"    XXXX UNHANDLED KEY {k} in feature description")

    if not output:
        # feature that is only used in the conditions of other features
        output = ["internalFeature"]

    publicFeature = False  # #define QT_FEATURE_featurename in public header
    privateFeature = False  # #define QT_FEATURE_featurename in private header
    negativeFeature = False  # #define QT_NO_featurename in public header
    internalFeature = False  # No custom or QT_FEATURE_ defines
    publicDefine = False  # #define MY_CUSTOM_DEFINE in public header
    publicConfig = False  # add to CONFIG in public pri file
    privateConfig = False  # add to CONFIG in private pri file
    publicQtConfig = False  # add to QT_CONFIG in public pri file

    for o in output:
        outputType = o
        if isinstance(o, dict):
            outputType = o["type"]

        if outputType in ["varAssign", "varAppend", "varRemove"]:
            continue
        elif outputType == "define":
            publicDefine = True
        elif outputType == "feature":
            negativeFeature = True
        elif outputType == "publicFeature":
            publicFeature = True
        elif outputType == "privateFeature":
            privateFeature = True
        elif outputType == "internalFeature":
            internalFeature = True
        elif outputType == "publicConfig":
            publicConfig = True
        elif outputType == "privateConfig":
            privateConfig = True
        elif outputType == "publicQtConfig":
            publicQtConfig = True
        else:
            print(f"    XXXX UNHANDLED OUTPUT TYPE {outputType} in feature {feature}.")
            continue

    if not any(
        [
            publicFeature,
            privateFeature,
            internalFeature,
            publicDefine,
            negativeFeature,
            publicConfig,
            privateConfig,
            publicQtConfig,
        ]
    ):
        print(f"    **** Skipping feature {feature}: Not relevant for C++.")
        return

    normalized_feature_name = featureName(feature)

    def writeFeature(
        name,
        publicFeature=False,
        privateFeature=False,
        labelAppend="",
        superFeature=None,
        autoDetect="",
    ):
        if comment:
            cm_fh.write(f"# {comment}\n")

        cm_fh.write(f'qt_feature("{name}"')
        if publicFeature:
            cm_fh.write(" PUBLIC")
        if privateFeature:
            cm_fh.write(" PRIVATE")
        cm_fh.write("\n")

        cm_fh.write(lineify("SECTION", section))
        cm_fh.write(lineify("LABEL", label + labelAppend))
        if purpose != label:
            cm_fh.write(lineify("PURPOSE", purpose))
        cm_fh.write(lineify("AUTODETECT", autoDetect, quote=False))
        if superFeature:
            feature_condition = f"QT_FEATURE_{superFeature}"
        else:
            feature_condition = condition
        cm_fh.write(lineify("CONDITION", feature_condition, quote=False))
        cm_fh.write(lineify("ENABLE", enable, quote=False))
        cm_fh.write(lineify("DISABLE", disable, quote=False))
        cm_fh.write(lineify("EMIT_IF", emitIf, quote=False))
        cm_fh.write(")\n")

    # Write qt_feature() calls before any qt_feature_definition() calls

    # Default internal feature case.
    featureCalls = {}
    featureCalls[feature] = {"name": feature, "labelAppend": "", "autoDetect": autoDetect}

    # Go over all outputs to compute the number of features that have to be declared
    for o in output:
        outputType = o
        name = feature

        # The label append is to provide a unique label for features that have more than one output
        # with different names.
        labelAppend = ""

        if isinstance(o, dict):
            outputType = o["type"]
            if "name" in o:
                name = o["name"]
                labelAppend = f": {o['name']}"

        if outputType not in ["feature", "publicFeature", "privateFeature"]:
            continue
        if name not in featureCalls:
            featureCalls[name] = {"name": name, "labelAppend": labelAppend}

        if name != feature:
            featureCalls[name]["superFeature"] = normalized_feature_name

        if outputType in ["feature", "publicFeature"]:
            featureCalls[name]["publicFeature"] = True
        elif outputType == "privateFeature":
            featureCalls[name]["privateFeature"] = True
        elif outputType == "publicConfig":
            featureCalls[name]["publicConfig"] = True
        elif outputType == "privateConfig":
            featureCalls[name]["privateConfig"] = True
        elif outputType == "publicQtConfig":
            featureCalls[name]["publicQtConfig"] = True

    # Write the qt_feature() calls from the computed feature map
    for _, args in featureCalls.items():
        writeFeature(**args)

    # Write qt_feature_definition() calls
    for o in output:
        outputType = o
        outputArgs = {}
        if isinstance(o, dict):
            outputType = o["type"]
            outputArgs = o

        # Map negative feature to define:
        if outputType == "feature":
            outputType = "define"
            outputArgs = {
                "name": f"QT_NO_{normalized_feature_name.upper()}",
                "negative": True,
                "value": 1,
                "type": "define",
            }

        if outputType != "define":
            continue

        if outputArgs.get("name") is None:
            print(f"    XXXX DEFINE output without name in feature {feature}.")
            continue

        out_name = outputArgs.get("name")
        cm_fh.write(f'qt_feature_definition("{feature}" "{out_name}"')
        if outputArgs.get("negative", False):
            cm_fh.write(" NEGATE")
        if outputArgs.get("value") is not None:
            cm_fh.write(f' VALUE "{outputArgs.get("value")}"')
        cm_fh.write(")\n")

    # Write qt_feature_config() calls
    for o in output:
        outputType = o
        name = feature
        modified_name = name

        outputArgs = {}
        if isinstance(o, dict):
            outputType = o["type"]
            outputArgs = o
            if "name" in o:
                modified_name = o["name"]

        if outputType not in ["publicConfig", "privateConfig", "publicQtConfig"]:
            continue

        config_type = ""
        if outputType == "publicConfig":
            config_type = "QMAKE_PUBLIC_CONFIG"
        elif outputType == "privateConfig":
            config_type = "QMAKE_PRIVATE_CONFIG"
        elif outputType == "publicQtConfig":
            config_type = "QMAKE_PUBLIC_QT_CONFIG"

        if not config_type:
            print("    XXXX config output without type in feature {}.".format(feature))
            continue

        cm_fh.write('qt_feature_config("{}" {}'.format(name, config_type))
        if outputArgs.get("negative", False):
            cm_fh.write("\n    NEGATE")
        if modified_name != name:
            cm_fh.write("\n")
            cm_fh.write(lineify("NAME", modified_name, quote=True))

        cm_fh.write(")\n")
Ejemplo n.º 3
0
def write_compile_test(ctx,
                       name,
                       details,
                       data,
                       cm_fh,
                       manual_library_list=None,
                       is_library_test=False):

    if manual_library_list is None:
        manual_library_list = []

    inherited_test_name = details["inherit"] if "inherit" in details else None
    inherit_details = None
    if inherited_test_name and is_library_test:
        inherit_details = data["libraries"][inherited_test_name]["test"]
        if not inherit_details:
            print(
                f"    XXXX Failed to locate inherited library test {inherited_test_name}"
            )

    if isinstance(details, str):
        write_standalone_compile_test(cm_fh, ctx, data, details,
                                      is_library_test)
        return

    def resolve_head(detail):
        head = detail.get("head", "")
        if isinstance(head, list):
            head = "\n".join(head)
        return head

    head = ""
    if inherit_details:
        head += resolve_head(inherit_details)
    head += resolve_head(details)

    sourceCode = head + "\n"

    def resolve_include(detail, keyword):
        include = detail.get(keyword, "")
        if isinstance(include, list):
            include = "#include <" + ">\n#include <".join(include) + ">"
        elif include:
            include = f"#include <{include}>"
        return include

    include = ""
    if is_library_test:
        if inherit_details:
            inherited_lib_data = data["libraries"][inherited_test_name]
            include += resolve_include(inherited_lib_data, "headers")
        this_lib_data = data["libraries"][name]
        include += resolve_include(this_lib_data, "headers")
    else:
        if inherit_details:
            include += resolve_include(inherit_details, "include")
        include += resolve_include(details, "include")

    sourceCode += include + "\n"

    def resolve_tail(detail):
        tail = detail.get("tail", "")
        if isinstance(tail, list):
            tail = "\n".join(tail)
        return tail

    tail = ""
    if inherit_details:
        tail += resolve_tail(inherit_details)
    tail += resolve_tail(details)

    sourceCode += tail + "\n"

    sourceCode += "int main(int argc, char **argv)\n"
    sourceCode += "{\n"
    sourceCode += "    (void)argc; (void)argv;\n"
    sourceCode += "    /* BEGIN TEST: */\n"

    def resolve_main(detail):
        main = detail.get("main", "")
        if isinstance(main, list):
            main = "\n".join(main)
        return main

    main = ""
    if inherit_details:
        main += resolve_main(inherit_details)
    main += resolve_main(details)

    sourceCode += main + "\n"

    sourceCode += "    /* END TEST: */\n"
    sourceCode += "    return 0;\n"
    sourceCode += "}\n"

    sourceCode = sourceCode.replace('"', '\\"')

    librariesCmakeName = ""
    languageStandard = ""
    compileOptions = ""
    qmakeFixme = ""

    cm_fh.write(f"# {name}\n")

    if "qmake" in details:  # We don't really have many so we can just enumerate them all
        if details["qmake"] == "unix:LIBS += -lpthread":
            librariesCmakeName = format(featureName(name)) + "_TEST_LIBRARIES"
            cm_fh.write("if (UNIX)\n")
            cm_fh.write("    set(" + librariesCmakeName + " pthread)\n")
            cm_fh.write("endif()\n")
        elif details["qmake"] == "linux: LIBS += -lpthread -lrt":
            librariesCmakeName = format(featureName(name)) + "_TEST_LIBRARIES"
            cm_fh.write("if (LINUX)\n")
            cm_fh.write("    set(" + librariesCmakeName + " pthread rt)\n")
            cm_fh.write("endif()\n")
        elif details["qmake"] == "!winrt: LIBS += runtimeobject.lib":
            librariesCmakeName = format(featureName(name)) + "_TEST_LIBRARIES"
            cm_fh.write("if (NOT WINRT)\n")
            cm_fh.write("    set(" + librariesCmakeName + " runtimeobject)\n")
            cm_fh.write("endif()\n")
        elif details["qmake"] == "CONFIG += c++11":
            # do nothing we're always in c++11 mode
            pass
        elif details["qmake"] == "CONFIG += c++11 c++14":
            languageStandard = "CXX_STANDARD 14"
        elif details["qmake"] == "CONFIG += c++11 c++14 c++17":
            languageStandard = "CXX_STANDARD 17"
        elif details["qmake"] == "CONFIG += c++11 c++14 c++17 c++2a":
            languageStandard = "CXX_STANDARD 20"
        elif details["qmake"] == "QMAKE_CXXFLAGS += -fstack-protector-strong":
            compileOptions = details["qmake"][18:]
        else:
            qmakeFixme = f"# FIXME: qmake: {details['qmake']}\n"

    library_list = []
    test_libraries = manual_library_list

    if "use" in data:
        test_libraries += data["use"].split(" ")

    for library in test_libraries:
        if len(library) == 0:
            continue

        adjusted_library = get_compile_test_dependent_library_mapping(
            name, library)
        library_usage = get_library_usage_for_compile_test(adjusted_library)
        if "fixme" in library_usage:
            qmakeFixme += library_usage["fixme"]
            continue
        else:
            library_list.append(library_usage["target_name"])

    cm_fh.write(f"qt_config_compile_test({featureName(name)}\n")
    cm_fh.write(lineify("LABEL", data.get("label", "")))
    if librariesCmakeName != "" or len(library_list) != 0:
        cm_fh.write("    LIBRARIES\n")
        if librariesCmakeName != "":
            cm_fh.write(lineify("", "${" + librariesCmakeName + "}"))
        if len(library_list) != 0:
            cm_fh.write("        ")
            cm_fh.write("\n        ".join(library_list))
            cm_fh.write("\n")
    if compileOptions != "":
        cm_fh.write(f"    COMPILE_OPTIONS {compileOptions}\n")
    cm_fh.write("    CODE\n")
    cm_fh.write('"' + sourceCode + '"')
    if qmakeFixme != "":
        cm_fh.write(qmakeFixme)
    if languageStandard != "":
        cm_fh.write(f"\n    {languageStandard}\n")
    cm_fh.write(")\n\n")
Ejemplo n.º 4
0
def parseTest(ctx, test, data, cm_fh):
    skip_tests = {
        "c11",
        "c99",
        "gc_binaries",
        "posix-iconv",
        "sun-iconv",
        "precomile_header",
        "reduce_exports",
        "separate_debug_info",  # FIXME: see if cmake can do this
        "gc_binaries",
        "libinput_axis_api",
        "wayland-scanner",
        "xlib",
    }

    if test in skip_tests:
        print(f"    **** Skipping features {test}: masked.")
        return

    if data["type"] == "compile":
        knownTests.add(test)

        details = data["test"]

        if isinstance(details, str):
            if not ctx["test_dir"]:
                print(f"    XXXX UNHANDLED TEST SUB-TYPE {details} in test description")
                return

            cm_fh.write(
                f"""
if(EXISTS "${{CMAKE_CURRENT_SOURCE_DIR}}/{ctx['test_dir']}/{data['test']}/CMakeLists.txt")
    qt_config_compile_test("{data['test']}"
                           LABEL "{data['label']}"
                           PROJECT_PATH "${{CMAKE_CURRENT_SOURCE_DIR}}/{ctx['test_dir']}/{data['test']}")
endif()
"""
            )
            return

        head = details.get("head", "")
        if isinstance(head, list):
            head = "\n".join(head)

        sourceCode = head + "\n"

        include = details.get("include", "")
        if isinstance(include, list):
            include = "#include <" + ">\n#include <".join(include) + ">"
        elif include:
            include = f"#include <{include}>"

        sourceCode += include + "\n"

        tail = details.get("tail", "")
        if isinstance(tail, list):
            tail = "\n".join(tail)

        sourceCode += tail + "\n"

        sourceCode += "int main(int argc, char **argv)\n"
        sourceCode += "{\n"
        sourceCode += "    (void)argc; (void)argv;\n"
        sourceCode += "    /* BEGIN TEST: */\n"

        main = details.get("main", "")
        if isinstance(main, list):
            main = "\n".join(main)

        sourceCode += main + "\n"

        sourceCode += "    /* END TEST: */\n"
        sourceCode += "    return 0;\n"
        sourceCode += "}\n"

        sourceCode = sourceCode.replace('"', '\\"')

        librariesCmakeName = ""
        languageStandard = ""
        qmakeFixme = ""

        cm_fh.write(f"# {test}\n")
        if "qmake" in details:  # We don't really have many so we can just enumerate them all
            if details["qmake"] == "unix:LIBS += -lpthread":
                librariesCmakeName = format(featureName(test)) + "_TEST_LIBRARIES"
                cm_fh.write("if (UNIX)\n")
                cm_fh.write("    set(" + librariesCmakeName + " pthread)\n")
                cm_fh.write("endif()\n")
            elif details["qmake"] == "linux: LIBS += -lpthread -lrt":
                librariesCmakeName = format(featureName(test)) + "_TEST_LIBRARIES"
                cm_fh.write("if (LINUX)\n")
                cm_fh.write("    set(" + librariesCmakeName + " pthread rt)\n")
                cm_fh.write("endif()\n")
            elif details["qmake"] == "!winrt: LIBS += runtimeobject.lib":
                librariesCmakeName = format(featureName(test)) + "_TEST_LIBRARIES"
                cm_fh.write("if (NOT WINRT)\n")
                cm_fh.write("    set(" + librariesCmakeName + " runtimeobject)\n")
                cm_fh.write("endif()\n")
            elif details["qmake"] == "CONFIG += c++11":
                # do nothing we're always in c++11 mode
                pass
            elif details["qmake"] == "CONFIG += c++11 c++14":
                languageStandard = "CXX_STANDARD 14"
            elif details["qmake"] == "CONFIG += c++11 c++14 c++17":
                languageStandard = "CXX_STANDARD 17"
            elif details["qmake"] == "CONFIG += c++11 c++14 c++17 c++2a":
                languageStandard = "CXX_STANDARD 20"
            else:
                qmakeFixme = f"# FIXME: qmake: {details['qmake']}\n"

        library_list = []
        if "use" in data:
            for library in data["use"].split(" "):
                if len(library) == 0:
                    continue

                mapped_library = find_3rd_party_library_mapping(library)
                if not mapped_library:
                    qmakeFixme += f"# FIXME: use: unmapped library: {library}\n"
                    continue
                library_list.append(mapped_library.targetName)

        cm_fh.write(f"qt_config_compile_test({featureName(test)}\n")
        cm_fh.write(lineify("LABEL", data.get("label", "")))
        if librariesCmakeName != "" or len(library_list) != 0:
            cm_fh.write("    LIBRARIES\n")
            if librariesCmakeName != "":
                cm_fh.write(lineify("", "${" + librariesCmakeName + "}"))
            if len(library_list) != 0:
                cm_fh.write("        ")
                cm_fh.write("\n        ".join(library_list))
                cm_fh.write("\n")
        cm_fh.write("    CODE\n")
        cm_fh.write('"' + sourceCode + '"')
        if qmakeFixme != "":
            cm_fh.write(qmakeFixme)
        if languageStandard != "":
            cm_fh.write(f"\n    {languageStandard}\n")
        cm_fh.write(")\n\n")

    elif data["type"] == "libclang":
        knownTests.add(test)

        cm_fh.write(f"# {test}\n")
        lib_clang_lib = find_3rd_party_library_mapping("libclang")
        cm_fh.write(generate_find_package_info(lib_clang_lib))
        cm_fh.write(
            dedent(
                """
        if(TARGET WrapLibClang::WrapLibClang)
            set(TEST_libclang "ON" CACHE BOOL "Required libclang version found." FORCE)
        endif()
        """
            )
        )
        cm_fh.write("\n")

    elif data["type"] == "x86Simd":
        knownTests.add(test)

        label = data["label"]

        cm_fh.write(f"# {test}\n")
        cm_fh.write(f'qt_config_compile_test_x86simd({test} "{label}")\n')
        cm_fh.write("\n")

    #    "features": {
    #        "android-style-assets": {
    #            "label": "Android Style Assets",
    #            "condition": "config.android",
    #            "output": [ "privateFeature" ],
    #            "comment": "This belongs into gui, but the license check needs it here already."
    #        },
    else:
        print(f"    XXXX UNHANDLED TEST TYPE {data['type']} in test description")