From cd15112b620feadafe8fd3531043870a5c19a4a6 Mon Sep 17 00:00:00 2001 From: yuangongji <82787816@qq.com> Date: Thu, 14 Nov 2019 18:28:31 +0800 Subject: [PATCH] cmake: test for find_package() --- .gitignore | 1 + test-export/CMakeLists.txt | 15 +++ test-export/test-export.c | 122 +++++++++++++++++++++++ test-export/test-export.py | 199 +++++++++++++++++++++++++++++++++++++ 4 files changed, 337 insertions(+) create mode 100644 test-export/CMakeLists.txt create mode 100644 test-export/test-export.c create mode 100644 test-export/test-export.py diff --git a/.gitignore b/.gitignore index ab7965c9..9614740e 100644 --- a/.gitignore +++ b/.gitignore @@ -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 index 00000000..89c1806c --- /dev/null +++ b/test-export/CMakeLists.txt @@ -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 index 00000000..90917775 --- /dev/null +++ b/test-export/test-export.c @@ -0,0 +1,122 @@ +#include +#if defined(EVENT_EXPORT_TEST_COMPONENT_EXTRA) +#include "event2/http.h" +#include "event2/rpc.h" +#include +#elif defined(EVENT_EXPORT_TEST_COMPONENT_PTHREADS) +#include +#elif defined(EVENT_EXPORT_TEST_COMPONENT_OPENSSL) +#include +#include +#include +#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 index 00000000..3be8193f --- /dev/null +++ b/test-export/test-export.py @@ -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 .. && 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") -- 2.40.0