diff options
author | Leander Beernaert <leander.beernaert@qt.io> | 2020-03-04 13:44:24 +0100 |
---|---|---|
committer | Leander Beernaert <leander.beernaert@qt.io> | 2020-03-06 12:32:48 +0100 |
commit | 8ffb9053ad300b1fc00b2dd4e808c99d03a3d7a4 (patch) | |
tree | 31ad95ba45cfe0abb1237eebbf7cc6b29f92da9b | |
parent | 8bdbb7f2267516905531f719902168c036329646 (diff) |
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 <alexandru.croitor@qt.io>
-rwxr-xr-x | util/cmake/configurejson2cmake.py | 300 | ||||
-rw-r--r-- | 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 <future>", @@ -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 |