def parseLib(ctx, lib, data, cm_fh, cmake_find_packages_set): newlib = find_3rd_party_library_mapping(lib) if not newlib: print(f' XXXX Unknown library "{lib}".') return if newlib.packageName is None: print(f' **** Skipping library "{lib}" -- was masked.') return print(f" mapped library {lib} to {newlib.targetName}.") # Avoid duplicate find_package calls. if newlib.targetName in cmake_find_packages_set: return # If certain libraries are used within a feature, but the feature # is only emitted conditionally with a simple condition (like # 'on Windows' or 'on Linux'), we should enclose the find_package # call for the library into the same condition. emit_if = newlib.emit_if # Only look through features if a custom emit_if wasn't provided. if not emit_if: for feature in data["features"]: feature_data = data["features"][feature] if ( "condition" in feature_data and f"libs.{lib}" in feature_data["condition"] and "emitIf" in feature_data and "config." in feature_data["emitIf"] ): emit_if = feature_data["emitIf"] break if emit_if: emit_if = map_condition(emit_if) cmake_find_packages_set.add(newlib.targetName) find_package_kwargs = {"emit_if": emit_if} if newlib.is_bundled_with_qt: # If a library is bundled with Qt, it has 2 FindFoo.cmake # modules: WrapFoo and WrapSystemFoo. # FindWrapSystemFoo.cmake will try to find the 'Foo' library in # the usual CMake locations, and will create a # WrapSystemFoo::WrapSystemFoo target pointing to the library. # # FindWrapFoo.cmake will create a WrapFoo::WrapFoo target which # will link either against the WrapSystemFoo or QtBundledFoo # target depending on certain feature values. # # Because the following qt_find_package call is for # configure.cmake consumption, we make the assumption that # configure.cmake is interested in finding the system library # for the purpose of enabling or disabling a system_foo feature. find_package_kwargs["use_system_package_name"] = True cm_fh.write(generate_find_package_info(newlib, **find_package_kwargs))
def get_library_usage_for_compile_test(library): result = {} mapped_library = find_3rd_party_library_mapping(library) if not mapped_library: result["fixme"] = f"# FIXME: use: unmapped library: {library}\n" return result if mapped_library.test_library_overwrite: target_name = mapped_library.test_library_overwrite else: target_name = mapped_library.targetName result["target_name"] = target_name result["package_name"] = mapped_library.packageName result["extra"] = mapped_library.extra return result
def parseLib(ctx, lib, data, cm_fh, cmake_find_packages_set): newlib = find_3rd_party_library_mapping(lib) if not newlib: print(f' XXXX Unknown library "{lib}".') return if newlib.packageName is None: print(f' **** Skipping library "{lib}" -- was masked.') return print(f" mapped library {lib} to {newlib.targetName}.") # Avoid duplicate find_package calls. if newlib.targetName in cmake_find_packages_set: return # If certain libraries are used within a feature, but the feature # is only emitted conditionally with a simple condition (like # 'on Windows' or 'on Linux'), we should enclose the find_package # call for the library into the same condition. emit_if = newlib.emit_if # Only look through features if a custom emit_if wasn't provided. if not emit_if: for feature in data["features"]: feature_data = data["features"][feature] if ("condition" in feature_data and f"libs.{lib}" in feature_data["condition"] and "emitIf" in feature_data and "config." in feature_data["emitIf"]): emit_if = feature_data["emitIf"] break if emit_if: emit_if = map_condition(emit_if) cmake_find_packages_set.add(newlib.targetName) cm_fh.write(generate_find_package_info(newlib, emit_if=emit_if))
def parseTest(ctx, test, data, cm_fh): skip_tests = { "c11", "c99", "gc_binaries", "posix-iconv", "sun-iconv", "precomile_header", "reduce_exports", "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) if "test" in data: details = data["test"] else: details = test write_compile_test(ctx, test, details, data, cm_fh) 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")
def map_condition(condition): # Handle NOT: if isinstance(condition, list): condition = "(" + ") AND (".join(condition) + ")" if isinstance(condition, bool): if condition: return "ON" else: return "OFF" assert isinstance(condition, str) mapped_features = {"gbm": "gbm_FOUND"} # Turn foo != "bar" into (NOT foo STREQUAL 'bar') condition = re.sub(r"([^ ]+)\s*!=\s*('.*?')", "(! \\1 == \\2)", condition) condition = condition.replace("!", "NOT ") condition = condition.replace("&&", " AND ") condition = condition.replace("||", " OR ") condition = condition.replace("==", " STREQUAL ") # explicitly handle input.sdk == '': condition = re.sub(r"input\.sdk\s*==\s*''", "NOT INPUT_SDK", condition) last_pos = 0 mapped_condition = "" has_failed = False for match in re.finditer(r"([a-zA-Z0-9_]+)\.([a-zA-Z0-9_+-]+)", condition): substitution = None # appendFoundSuffix = True if match.group(1) == "libs": libmapping = find_3rd_party_library_mapping(match.group(2)) if libmapping and libmapping.packageName: substitution = libmapping.packageName if libmapping.resultVariable: substitution = libmapping.resultVariable if libmapping.appendFoundSuffix: substitution += "_FOUND" # Assume that feature conditions are interested whether # a system library is found, rather than the bundled one # which we always know we can build. if libmapping.is_bundled_with_qt: substitution = substitution.replace("Wrap", "WrapSystem") elif match.group(1) == "features": feature = match.group(2) if feature in mapped_features: substitution = mapped_features.get(feature) else: substitution = f"QT_FEATURE_{featureName(match.group(2))}" elif match.group(1) == "subarch": substitution = f"TEST_arch_{'${TEST_architecture_arch}'}_subarch_{match.group(2)}" elif match.group(1) == "call": if match.group(2) == "crossCompile": substitution = "CMAKE_CROSSCOMPILING" elif match.group(1) == "tests": substitution = map_tests(match.group(2)) elif match.group(1) == "input": substitution = f"INPUT_{featureName(match.group(2))}" elif match.group(1) == "config": substitution = map_platform(match.group(2)) elif match.group(1) == "module": substitution = f"TARGET {map_qt_library(match.group(2))}" elif match.group(1) == "arch": if match.group(2) == "i386": # FIXME: Does this make sense? substitution = "(TEST_architecture_arch STREQUAL i386)" elif match.group(2) == "x86_64": substitution = "(TEST_architecture_arch STREQUAL x86_64)" elif match.group(2) == "arm": # FIXME: Does this make sense? substitution = "(TEST_architecture_arch STREQUAL arm)" elif match.group(2) == "arm64": # FIXME: Does this make sense? substitution = "(TEST_architecture_arch STREQUAL arm64)" elif match.group(2) == "mips": # FIXME: Does this make sense? substitution = "(TEST_architecture_arch STREQUAL mips)" if substitution is None: print(f' XXXX Unknown condition "{match.group(0)}"') has_failed = True else: mapped_condition += condition[last_pos:match. start(1)] + substitution last_pos = match.end(2) mapped_condition += condition[last_pos:] # Space out '(' and ')': mapped_condition = mapped_condition.replace("(", " ( ") mapped_condition = mapped_condition.replace(")", " ) ") # Prettify: condition = re.sub("\\s+", " ", mapped_condition) condition = condition.strip() # Special case for WrapLibClang in qttools condition = condition.replace("TEST_libclang.has_clangcpp", "TEST_libclang") if has_failed: condition += " OR FIXME" return condition
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): rel_test_project_path = f"{ctx['test_dir']}/{details}" if posixpath.exists(f"{ctx['project_dir']}/{rel_test_project_path}/CMakeLists.txt"): cm_fh.write( f""" qt_config_compile_test("{details}" LABEL "{data['label']}" PROJECT_PATH "${{CMAKE_CURRENT_SOURCE_DIR}}/{rel_test_project_path}") """ ) 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 mapped_library = find_3rd_party_library_mapping(library) if not mapped_library: qmakeFixme += f"# FIXME: use: unmapped library: {library}\n" continue if mapped_library.test_library_overwrite: library_list.append(mapped_library.test_library_overwrite) else: library_list.append(mapped_library.targetName) 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")
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")
def parseLib(ctx, lib, data, cm_fh, cmake_find_packages_set): newlib = find_3rd_party_library_mapping(lib) if not newlib: print(f' XXXX Unknown library "{lib}".') return if newlib.packageName is None: print(f' **** Skipping library "{lib}" -- was masked.') return print(f" mapped library {lib} to {newlib.targetName}.") # Avoid duplicate find_package calls. if newlib.targetName in cmake_find_packages_set: return # If certain libraries are used within a feature, but the feature # is only emitted conditionally with a simple condition (like # 'on Windows' or 'on Linux'), we should enclose the find_package # call for the library into the same condition. emit_if = newlib.emit_if # Only look through features if a custom emit_if wasn't provided. if not emit_if: for feature in data["features"]: feature_data = data["features"][feature] if ("condition" in feature_data and f"libs.{lib}" in feature_data["condition"] and "emitIf" in feature_data and "config." in feature_data["emitIf"]): emit_if = feature_data["emitIf"] break if emit_if: emit_if = map_condition(emit_if) cmake_find_packages_set.add(newlib.targetName) find_package_kwargs = {"emit_if": emit_if} if newlib.is_bundled_with_qt: # If a library is bundled with Qt, it has 2 FindFoo.cmake # modules: WrapFoo and WrapSystemFoo. # FindWrapSystemFoo.cmake will try to find the 'Foo' library in # the usual CMake locations, and will create a # WrapSystemFoo::WrapSystemFoo target pointing to the library. # # FindWrapFoo.cmake will create a WrapFoo::WrapFoo target which # will link either against the WrapSystemFoo or QtBundledFoo # target depending on certain feature values. # # Because the following qt_find_package call is for # configure.cmake consumption, we make the assumption that # configure.cmake is interested in finding the system library # for the purpose of enabling or disabling a system_foo feature. find_package_kwargs["use_system_package_name"] = True find_package_kwargs["module"] = ctx["module"] cm_fh.write(generate_find_package_info(newlib, **find_package_kwargs)) if "use" in data["libraries"][lib]: use_entry = data["libraries"][lib]["use"] if isinstance(use_entry, str): print(f"1use: {use_entry}") cm_fh.write( f"qt_add_qmake_lib_dependency({newlib.soName} {use_entry})\n") else: for use in use_entry: print(f"2use: {use}") indentation = "" has_condition = False if "condition" in use: has_condition = True indentation = " " condition = map_condition(use["condition"]) cm_fh.write(f"if({condition})\n") cm_fh.write( f"{indentation}qt_add_qmake_lib_dependency({newlib.soName} {use['lib']})\n" ) if has_condition: cm_fh.write("endif()\n") run_library_test = False mapped_library = find_3rd_party_library_mapping(lib) if mapped_library: run_library_test = mapped_library.run_library_test if run_library_test and "test" in data["libraries"][lib]: test = data["libraries"][lib]["test"] write_compile_test(ctx, lib, test, data, cm_fh, manual_library_list=[lib], is_library_test=True)