From 8ffb9053ad300b1fc00b2dd4e808c99d03a3d7a4 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Wed, 4 Mar 2020 13:44:24 +0100 Subject: Handle configure.json library tests This patch updates configurejson2cmake.py to generate compile tests for library entries. The test also support the inherit keyword, which is currently limited to one level of inheritance. LibraryMapping has been extended with a test_library_overwrite as a means to overwrite the mapped library during a compile test. Certain tests such as openssl_headers form src/network are mapped with *_nolink libraries which do not exist when the test is run. Failing to do so will cause the test to run as it is skipped when the library target isn't found. To avoid redundant checks, the library tests need to be opt in by setting run_library_test to True on an instance of LibraryMapping. Change-Id: I607b24eda389fa67afad301c616e31bb7ab38d20 Reviewed-by: Alexandru Croitor --- util/cmake/configurejson2cmake.py | 300 +++++++++++++++++++++++--------------- util/cmake/helper.py | 15 +- 2 files changed, 197 insertions(+), 118 deletions(-) diff --git a/util/cmake/configurejson2cmake.py b/util/cmake/configurejson2cmake.py index 6eea6e0be8..f0fb4f0817 100755 --- a/util/cmake/configurejson2cmake.py +++ b/util/cmake/configurejson2cmake.py @@ -222,6 +222,15 @@ def parseLib(ctx, lib, data, cm_fh, cmake_find_packages_set): cm_fh.write(generate_find_package_info(newlib, **find_package_kwargs)) + 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) + def lineify(label, value, quote=True): if value: @@ -491,6 +500,180 @@ def parseInput(ctx, sinput, data, cm_fh): return +def write_compile_test(ctx, name, details, data, cm_fh, manual_library_list = None, is_library_test = False): + + if manual_library_list == 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 {inherit}") + + 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") + + + # "tests": { # "cxx11_future": { # "label": "C++11 ", @@ -532,122 +715,7 @@ def parseTest(ctx, test, data, cm_fh): else: details = test - 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 - - 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 = "" - compileOptions = "" - 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" - elif details["qmake"] == "QMAKE_CXXFLAGS += -fstack-protector-strong": - compileOptions = details["qmake"][18:] - 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") - 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") + write_compile_test(ctx, test, details, data, cm_fh) elif data["type"] == "libclang": knownTests.add(test) diff --git a/util/cmake/helper.py b/util/cmake/helper.py index 9b9f347fff..bac0bdb725 100644 --- a/util/cmake/helper.py +++ b/util/cmake/helper.py @@ -42,6 +42,8 @@ class LibraryMapping: appendFoundSuffix: bool = True, emit_if: str = "", is_bundled_with_qt: bool = False, + test_library_overwrite: str = "", + run_library_test: bool = False ) -> None: self.soName = soName self.packageName = packageName @@ -57,6 +59,13 @@ class LibraryMapping: # for a library will be surrounded by this condition. self.emit_if = emit_if + # Allow overwriting library name when used with tests. E.g.: _nolink + # targets do not exist when used during compile tests + self.test_library_overwrite = test_library_overwrite + + # Run the library compile test of configure.json + self.run_library_test = run_library_test + def is_qt(self) -> bool: return self.packageName == "Qt" or self.packageName == "Qt5" or self.packageName == "Qt6" @@ -437,10 +446,12 @@ _library_map = [ "openssl_headers", "OpenSSL", "OpenSSL::SSL_nolink", - resultVariable="OPENSSL_INCLUDE_DIR", + resultVariable="TEST_openssl_headers", appendFoundSuffix=False, + test_library_overwrite = "OpenSSL::SSL", + run_library_test=True ), - LibraryMapping("openssl", "OpenSSL", "OpenSSL::SSL"), + LibraryMapping("openssl", "OpenSSL", "OpenSSL::SSL", resultVariable="TEST_openssl", appendFoundSuffix=False, run_library_test=True), LibraryMapping("oci", "Oracle", "Oracle::OCI"), LibraryMapping( "pcre2", "WrapPCRE2", "WrapPCRE2::WrapPCRE2", extra=["REQUIRED"], is_bundled_with_qt=True -- cgit v1.2.3