cmake: test for find_package()
authoryuangongji <82787816@qq.com>
Thu, 14 Nov 2019 10:28:31 +0000 (18:28 +0800)
committeryuangongji <82787816@qq.com>
Thu, 14 Nov 2019 10:28:31 +0000 (18:28 +0800)
.gitignore
test-export/CMakeLists.txt [new file with mode: 0644]
test-export/test-export.c [new file with mode: 0644]
test-export/test-export.py [new file with mode: 0644]

index ab7965c96ef40d07d4ec2723103d593629bd85a6..9614740e7dfa1b5dbdea34f11249687935c6654e 100644 (file)
@@ -149,6 +149,7 @@ event_extra.dir
 *.sln
 *.filters
 install_manifest.txt
+test-export/build
 
 # ninja
 build.ninja
diff --git a/test-export/CMakeLists.txt b/test-export/CMakeLists.txt
new file mode 100644 (file)
index 0000000..89c1806
--- /dev/null
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.1.2)
+if (POLICY CMP0074)
+    cmake_policy(SET CMP0074 NEW)
+endif()
+project(verify)
+# set(CMAKE_VERBOSE_MAKEFILE 1)
+if(NOT ${EVENT__CODE_COMPONENT} STREQUAL "")
+    string(TOUPPER ${EVENT__CODE_COMPONENT} _UPPER_COMPONENT)
+endif()
+find_package(Libevent 2.2.0 REQUIRED COMPONENTS ${EVENT__LINK_COMPONENT})
+add_definitions(-DEVENT_EXPORT_TEST_COMPONENT_${_UPPER_COMPONENT})
+add_executable(test-export test-export.c)
+target_link_libraries(test-export ${LIBEVENT_LIBRARIES})
+enable_testing()
+add_test(test-export test-export)
diff --git a/test-export/test-export.c b/test-export/test-export.c
new file mode 100644 (file)
index 0000000..9091777
--- /dev/null
@@ -0,0 +1,122 @@
+#include <event2/event.h>
+#if defined(EVENT_EXPORT_TEST_COMPONENT_EXTRA)
+#include "event2/http.h"
+#include "event2/rpc.h"
+#include <event2/dns.h>
+#elif defined(EVENT_EXPORT_TEST_COMPONENT_PTHREADS)
+#include <event2/thread.h>
+#elif defined(EVENT_EXPORT_TEST_COMPONENT_OPENSSL)
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <event2/bufferevent_ssl.h>
+#endif
+
+#if defined(EVENT_EXPORT_TEST_COMPONENT_EXTRA)
+static int
+test()
+{
+       struct event_base *base = NULL;
+       struct evhttp *http = NULL;
+       struct evdns_base *dns_base = NULL;
+       struct evrpc_base *rpc_base = NULL;
+
+       base = event_base_new();
+       if (base) {
+               http = evhttp_new(base);
+               dns_base = evdns_base_new(base,
+                       EVDNS_BASE_DISABLE_WHEN_INACTIVE);
+       }
+       if (http)
+               rpc_base = evrpc_init(http);
+
+       if (base)
+               event_base_free(base);
+       if (http)
+               evhttp_free(http);
+       if (rpc_base)
+               evrpc_free(rpc_base);
+       if (dns_base)
+               evdns_base_free(dns_base, 0);
+
+       return 0;
+}
+#elif defined(EVENT_EXPORT_TEST_COMPONENT_PTHREADS)
+static int
+test()
+{
+       return evthread_use_pthreads();
+}
+#elif defined(EVENT_EXPORT_TEST_COMPONENT_OPENSSL)
+static int
+test()
+{
+       struct event_base *base = NULL;
+       SSL_CTX *ssl_ctx = NULL;
+       SSL *ssl = NULL;
+       struct bufferevent *bev;
+       int r = 1;
+
+       SSL_library_init();
+       ERR_load_crypto_strings();
+       SSL_load_error_strings();
+       OpenSSL_add_all_algorithms();
+
+       base = event_base_new();
+       if (!base) {
+               goto error;
+       }
+
+       ssl_ctx = SSL_CTX_new(SSLv23_method());
+       if (!ssl_ctx) {
+               goto error;
+       }
+       ssl = SSL_new(ssl_ctx);
+       if (ssl == NULL) {
+               goto error;
+       }
+       bev = bufferevent_openssl_socket_new(base, -1, ssl,
+               BUFFEREVENT_SSL_CONNECTING,
+               BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
+       if (bev == NULL) {
+               goto error;
+       }
+       r = 0;
+error:
+       if (base)
+               event_base_free(base);
+       if (ssl_ctx)
+               SSL_CTX_free(ssl_ctx);
+       if (ssl)
+               SSL_free(ssl);
+       return r;
+}
+#else
+static int
+test()
+{
+       struct event_base *base = NULL;
+
+       base = event_base_new();
+       if (base)
+               event_base_free(base);
+
+       return 0;
+}
+#endif
+
+int
+main(int argc, char const *argv[])
+{
+       int r = 0;
+#ifdef _WIN32
+       {
+               WSADATA wsaData;
+               WSAStartup(MAKEWORD(2, 2), &wsaData);
+       }
+#endif
+       r = test();
+#ifdef _WIN32
+       WSACleanup();
+#endif
+       return r;
+}
diff --git a/test-export/test-export.py b/test-export/test-export.py
new file mode 100644 (file)
index 0000000..3be8193
--- /dev/null
@@ -0,0 +1,199 @@
+#!/usr/bin/env python3
+#
+# Check if find_package(Libevent COMPONENTS xxx) can get the correct library.
+# Note: this script has only been tested on python3.
+# Usage:
+#   cd cmake-build-dir
+#   cmake <options> .. && cmake --build .
+#   python /path/to/test-export.py [static|shared]
+
+import sys
+import os
+import shutil
+import platform
+import subprocess
+import tempfile
+
+results = ("success", "failure")
+FNULL = open(os.devnull, 'wb')
+script_dir = os.path.split(os.path.realpath(sys.argv[0]))[0]
+# working_dir is cmake build dir
+working_dir = os.getcwd()
+if len(sys.argv) > 1 and sys.argv[1] == "static":
+    link_type = sys.argv[1]
+else:
+    link_type = "shared"
+
+
+def exec_cmd(cmd, silent):
+    if silent:
+        p = subprocess.Popen(cmd, stdout=FNULL, stderr=FNULL, shell=True)
+    else:
+        p = subprocess.Popen(cmd, shell=True)
+    p.communicate()
+    return p.poll()
+
+
+def link_and_run(link, code):
+    """Check if the source code matches the library component.
+
+    Compile source code relative to one component and link to another component.
+    Then run the generated executor.
+
+    Args:
+        link: The name of component that the source code will link with.
+        code: The source code related component name.
+
+    Returns:
+        Returns 0 if links and runs successfully, otherwise 1.
+    """
+    exec_cmd("cmake --build . --target clean", True)
+    generator = ''
+    if platform.system() == "Windows":
+        generator = '-G "Visual Studio 15 2017 Win64"'
+    cmd = 'cmake .. %s -DEVENT__LINK_COMPONENT=%s -DEVENT__CODE_COMPONENT=%s' % (
+        generator, link, code)
+    if link_type == "static":
+        cmd = "".join([cmd, " -DLIBEVENT_STATIC_LINK=1"])
+    r = exec_cmd(cmd, True)
+    if r == 0:
+        r = exec_cmd('cmake --build .', True)
+        if r == 0:
+            r = exec_cmd('ctest', True)
+    if r != 0:
+        r = 1
+    return r
+
+# expect  0:success 1:failure
+def testcase(link, code, expect):
+    r = link_and_run(link, code)
+    if link == "":
+        link = "all"
+    if code == "":
+        code = "all"
+    if r != expect:
+        print('[test-export] fail: link %s and run %s expects %s but gets %s.' %
+              (link, code, results[expect], results[r]))
+        sys.exit(1)
+    else:
+        print('[test-export] success: link %s and run %s expects and gets %s.' %
+              (link, code, results[r]))
+
+# Dependency relationships between libevent libraries:
+#   core:        none
+#   extra:       core
+#   pthreads:    core,pthread
+#   openssl:     core,openssl
+def test_group():
+    testcase("core", "core", 0)
+    testcase("extra", "extra", 0)
+    testcase("openssl", "openssl", 0)
+    testcase("", "", 0)
+    testcase("extra", "core", 0)
+    testcase("openssl", "core", 0)
+    testcase("core", "extra", 1)
+    testcase("core", "openssl", 1)
+    testcase("extra", "openssl", 1)
+    testcase("openssl", "extra", 1)
+    if platform.system() != "Windows":
+        testcase("pthreads", "pthreads", 0)
+        testcase("pthreads", "core", 0)
+        testcase("core", "pthreads", 1)
+        testcase("extra", "pthreads", 1)
+        testcase("pthreads", "extra", 1)
+        testcase("pthreads", "openssl", 1)
+        testcase("openssl", "pthreads", 1)
+
+
+def config_restore():
+    if os.path.isfile("tempconfig") and not os.path.isfile("LibeventConfig.cmake"):
+        os.rename("tempconfig", "LibeventConfig.cmake")
+
+
+def config_backup():
+    if os.path.isfile("tempconfig"):
+        os.remove("tempconfig")
+    if os.path.isfile("LibeventConfig.cmake"):
+        os.rename("LibeventConfig.cmake", "tempconfig")
+
+
+shutil.rmtree(os.path.join(script_dir, "build"), ignore_errors=True)
+
+
+def run_test_group():
+    os.chdir(script_dir)
+    if not os.path.isdir("build"):
+        os.mkdir("build")
+    os.chdir("build")
+    test_group()
+    os.chdir(working_dir)
+
+
+need_exportdll = False
+if link_type == "shared" and platform.system() == "Windows":
+    need_exportdll = True
+
+# On Windows, we need to add the directory containing the dll to the
+# 'PATH' environment variable so that the program can call it.
+def export_dll(dir):
+    if need_exportdll:
+        os.environ["PATH"] += os.pathsep + dir
+
+
+def unexport_dll(dir):
+    if need_exportdll:
+        paths = os.environ["PATH"].split(os.pathsep)
+        paths = list(set(paths))
+        if dir in paths:
+            paths.remove(dir)
+        os.environ["PATH"] = os.pathsep.join(paths)
+
+
+print("[test-export] use %s library" % link_type)
+
+# Test for build tree.
+print("[test-export] test for build tree")
+dllpath = os.path.join(working_dir, "bin", "Debug")
+config_restore()
+os.environ["CMAKE_PREFIX_PATH"] = working_dir
+export_dll(dllpath)
+run_test_group()
+del os.environ["CMAKE_PREFIX_PATH"]
+unexport_dll(dllpath)
+
+# Install libevent libraries to system path. Remove LibeventConfig.cmake
+# from build directory to avoid confusion when using find_package().
+print("[test-export] test for install tree(in system-wide path)")
+if platform.system() == "Windows":
+    prefix = "C:\\Program Files\\libevent"
+    dllpath = os.path.join(prefix, "lib")
+else:
+    prefix = "/usr/local"
+exec_cmd('cmake -DCMAKE_INSTALL_PREFIX="%s" ..' % prefix, True)
+exec_cmd('cmake --build . --target install', True)
+config_backup()
+os.environ["CMAKE_PREFIX_PATH"] = os.path.join(prefix, "lib/cmake/libevent")
+export_dll(dllpath)
+run_test_group()
+unexport_dll(dllpath)
+del os.environ["CMAKE_PREFIX_PATH"]
+
+# Uninstall the libraries installed in the above steps. Install the libraries
+# into a temporary directory. Same as above, remove LibeventConfig.cmake from
+# build directory to avoid confusion when using find_package().
+print("[test-export] test for install tree(in non-system-wide path)")
+exec_cmd("cmake --build . --target uninstall", True)
+tempdir = tempfile.TemporaryDirectory()
+cmd = 'cmake -DCMAKE_INSTALL_PREFIX="%s" ..' % tempdir.name
+exec_cmd(cmd, True)
+exec_cmd("cmake --build . --target install", True)
+config_backup()
+os.environ["CMAKE_PREFIX_PATH"] = os.path.join(tempdir.name, "lib/cmake/libevent")
+dllpath = os.path.join(tempdir.name, "lib")
+export_dll(dllpath)
+run_test_group()
+unexport_dll(dllpath)
+del os.environ["CMAKE_PREFIX_PATH"]
+config_restore()
+
+print("[test-export] all testcases have run successfully")