1*baec84f2Syuangongji#!/usr/bin/env python3
2*baec84f2Syuangongji#
3*baec84f2Syuangongji# Check if find_package(Libevent COMPONENTS xxx) can get the correct library.
4*baec84f2Syuangongji# Note: this script has only been tested on python3.
5*baec84f2Syuangongji# Usage:
6*baec84f2Syuangongji#   cd cmake-build-dir
7*baec84f2Syuangongji#   cmake <options> .. && cmake --build .
8*baec84f2Syuangongji#   python /path/to/test-export.py [static|shared]
9*baec84f2Syuangongji
10*baec84f2Syuangongjiimport sys
11*baec84f2Syuangongjiimport os
12*baec84f2Syuangongjiimport shutil
13*baec84f2Syuangongjiimport platform
14*baec84f2Syuangongjiimport subprocess
15*baec84f2Syuangongjiimport tempfile
16*baec84f2Syuangongji
17*baec84f2Syuangongjiresults = ("success", "failure")
18*baec84f2SyuangongjiFNULL = open(os.devnull, 'wb')
19*baec84f2Syuangongjiscript_dir = os.path.split(os.path.realpath(sys.argv[0]))[0]
20*baec84f2Syuangongji# working_dir is cmake build dir
21*baec84f2Syuangongjiworking_dir = os.getcwd()
22*baec84f2Syuangongjiif len(sys.argv) > 1 and sys.argv[1] == "static":
23*baec84f2Syuangongji    link_type = sys.argv[1]
24*baec84f2Syuangongjielse:
25*baec84f2Syuangongji    link_type = "shared"
26*baec84f2Syuangongji
27*baec84f2Syuangongji
28*baec84f2Syuangongjidef exec_cmd(cmd, silent):
29*baec84f2Syuangongji    if silent:
30*baec84f2Syuangongji        p = subprocess.Popen(cmd, stdout=FNULL, stderr=FNULL, shell=True)
31*baec84f2Syuangongji    else:
32*baec84f2Syuangongji        p = subprocess.Popen(cmd, shell=True)
33*baec84f2Syuangongji    p.communicate()
34*baec84f2Syuangongji    return p.poll()
35*baec84f2Syuangongji
36*baec84f2Syuangongji
37*baec84f2Syuangongjidef link_and_run(link, code):
38*baec84f2Syuangongji    """Check if the source code matches the library component.
39*baec84f2Syuangongji
40*baec84f2Syuangongji    Compile source code relative to one component and link to another component.
41*baec84f2Syuangongji    Then run the generated executor.
42*baec84f2Syuangongji
43*baec84f2Syuangongji    Args:
44*baec84f2Syuangongji        link: The name of component that the source code will link with.
45*baec84f2Syuangongji        code: The source code related component name.
46*baec84f2Syuangongji
47*baec84f2Syuangongji    Returns:
48*baec84f2Syuangongji        Returns 0 if links and runs successfully, otherwise 1.
49*baec84f2Syuangongji    """
50*baec84f2Syuangongji    exec_cmd("cmake --build . --target clean", True)
51*baec84f2Syuangongji    generator = ''
52*baec84f2Syuangongji    if platform.system() == "Windows":
53*baec84f2Syuangongji        generator = '-G "Visual Studio 15 2017 Win64"'
54*baec84f2Syuangongji    cmd = 'cmake .. %s -DEVENT__LINK_COMPONENT=%s -DEVENT__CODE_COMPONENT=%s' % (
55*baec84f2Syuangongji        generator, link, code)
56*baec84f2Syuangongji    if link_type == "static":
57*baec84f2Syuangongji        cmd = "".join([cmd, " -DLIBEVENT_STATIC_LINK=1"])
58*baec84f2Syuangongji    r = exec_cmd(cmd, True)
59*baec84f2Syuangongji    if r == 0:
60*baec84f2Syuangongji        r = exec_cmd('cmake --build .', True)
61*baec84f2Syuangongji        if r == 0:
62*baec84f2Syuangongji            r = exec_cmd('ctest', True)
63*baec84f2Syuangongji    if r != 0:
64*baec84f2Syuangongji        r = 1
65*baec84f2Syuangongji    return r
66*baec84f2Syuangongji
67*baec84f2Syuangongji# expect  0:success 1:failure
68*baec84f2Syuangongjidef testcase(link, code, expect):
69*baec84f2Syuangongji    r = link_and_run(link, code)
70*baec84f2Syuangongji    if link == "":
71*baec84f2Syuangongji        link = "all"
72*baec84f2Syuangongji    if code == "":
73*baec84f2Syuangongji        code = "all"
74*baec84f2Syuangongji    if r != expect:
75*baec84f2Syuangongji        print('[test-export] fail: link %s and run %s expects %s but gets %s.' %
76*baec84f2Syuangongji              (link, code, results[expect], results[r]))
77*baec84f2Syuangongji        sys.exit(1)
78*baec84f2Syuangongji    else:
79*baec84f2Syuangongji        print('[test-export] success: link %s and run %s expects and gets %s.' %
80*baec84f2Syuangongji              (link, code, results[r]))
81*baec84f2Syuangongji
82*baec84f2Syuangongji# Dependency relationships between libevent libraries:
83*baec84f2Syuangongji#   core:        none
84*baec84f2Syuangongji#   extra:       core
85*baec84f2Syuangongji#   pthreads:    core,pthread
86*baec84f2Syuangongji#   openssl:     core,openssl
87*baec84f2Syuangongjidef test_group():
88*baec84f2Syuangongji    testcase("core", "core", 0)
89*baec84f2Syuangongji    testcase("extra", "extra", 0)
90*baec84f2Syuangongji    testcase("openssl", "openssl", 0)
91*baec84f2Syuangongji    testcase("", "", 0)
92*baec84f2Syuangongji    testcase("extra", "core", 0)
93*baec84f2Syuangongji    testcase("openssl", "core", 0)
94*baec84f2Syuangongji    testcase("core", "extra", 1)
95*baec84f2Syuangongji    testcase("core", "openssl", 1)
96*baec84f2Syuangongji    testcase("extra", "openssl", 1)
97*baec84f2Syuangongji    testcase("openssl", "extra", 1)
98*baec84f2Syuangongji    if platform.system() != "Windows":
99*baec84f2Syuangongji        testcase("pthreads", "pthreads", 0)
100*baec84f2Syuangongji        testcase("pthreads", "core", 0)
101*baec84f2Syuangongji        testcase("core", "pthreads", 1)
102*baec84f2Syuangongji        testcase("extra", "pthreads", 1)
103*baec84f2Syuangongji        testcase("pthreads", "extra", 1)
104*baec84f2Syuangongji        testcase("pthreads", "openssl", 1)
105*baec84f2Syuangongji        testcase("openssl", "pthreads", 1)
106*baec84f2Syuangongji
107*baec84f2Syuangongji
108*baec84f2Syuangongjidef config_restore():
109*baec84f2Syuangongji    if os.path.isfile("tempconfig") and not os.path.isfile("LibeventConfig.cmake"):
110*baec84f2Syuangongji        os.rename("tempconfig", "LibeventConfig.cmake")
111*baec84f2Syuangongji
112*baec84f2Syuangongji
113*baec84f2Syuangongjidef config_backup():
114*baec84f2Syuangongji    if os.path.isfile("tempconfig"):
115*baec84f2Syuangongji        os.remove("tempconfig")
116*baec84f2Syuangongji    if os.path.isfile("LibeventConfig.cmake"):
117*baec84f2Syuangongji        os.rename("LibeventConfig.cmake", "tempconfig")
118*baec84f2Syuangongji
119*baec84f2Syuangongji
120*baec84f2Syuangongjishutil.rmtree(os.path.join(script_dir, "build"), ignore_errors=True)
121*baec84f2Syuangongji
122*baec84f2Syuangongji
123*baec84f2Syuangongjidef run_test_group():
124*baec84f2Syuangongji    os.chdir(script_dir)
125*baec84f2Syuangongji    if not os.path.isdir("build"):
126*baec84f2Syuangongji        os.mkdir("build")
127*baec84f2Syuangongji    os.chdir("build")
128*baec84f2Syuangongji    test_group()
129*baec84f2Syuangongji    os.chdir(working_dir)
130*baec84f2Syuangongji
131*baec84f2Syuangongji
132*baec84f2Syuangongjineed_exportdll = False
133*baec84f2Syuangongjiif link_type == "shared" and platform.system() == "Windows":
134*baec84f2Syuangongji    need_exportdll = True
135*baec84f2Syuangongji
136*baec84f2Syuangongji# On Windows, we need to add the directory containing the dll to the
137*baec84f2Syuangongji# 'PATH' environment variable so that the program can call it.
138*baec84f2Syuangongjidef export_dll(dir):
139*baec84f2Syuangongji    if need_exportdll:
140*baec84f2Syuangongji        os.environ["PATH"] += os.pathsep + dir
141*baec84f2Syuangongji
142*baec84f2Syuangongji
143*baec84f2Syuangongjidef unexport_dll(dir):
144*baec84f2Syuangongji    if need_exportdll:
145*baec84f2Syuangongji        paths = os.environ["PATH"].split(os.pathsep)
146*baec84f2Syuangongji        paths = list(set(paths))
147*baec84f2Syuangongji        if dir in paths:
148*baec84f2Syuangongji            paths.remove(dir)
149*baec84f2Syuangongji        os.environ["PATH"] = os.pathsep.join(paths)
150*baec84f2Syuangongji
151*baec84f2Syuangongji
152*baec84f2Syuangongjiprint("[test-export] use %s library" % link_type)
153*baec84f2Syuangongji
154*baec84f2Syuangongji# Test for build tree.
155*baec84f2Syuangongjiprint("[test-export] test for build tree")
156*baec84f2Syuangongjidllpath = os.path.join(working_dir, "bin", "Debug")
157*baec84f2Syuangongjiconfig_restore()
158*baec84f2Syuangongjios.environ["CMAKE_PREFIX_PATH"] = working_dir
159*baec84f2Syuangongjiexport_dll(dllpath)
160*baec84f2Syuangongjirun_test_group()
161*baec84f2Syuangongjidel os.environ["CMAKE_PREFIX_PATH"]
162*baec84f2Syuangongjiunexport_dll(dllpath)
163*baec84f2Syuangongji
164*baec84f2Syuangongji# Install libevent libraries to system path. Remove LibeventConfig.cmake
165*baec84f2Syuangongji# from build directory to avoid confusion when using find_package().
166*baec84f2Syuangongjiprint("[test-export] test for install tree(in system-wide path)")
167*baec84f2Syuangongjiif platform.system() == "Windows":
168*baec84f2Syuangongji    prefix = "C:\\Program Files\\libevent"
169*baec84f2Syuangongji    dllpath = os.path.join(prefix, "lib")
170*baec84f2Syuangongjielse:
171*baec84f2Syuangongji    prefix = "/usr/local"
172*baec84f2Syuangongjiexec_cmd('cmake -DCMAKE_INSTALL_PREFIX="%s" ..' % prefix, True)
173*baec84f2Syuangongjiexec_cmd('cmake --build . --target install', True)
174*baec84f2Syuangongjiconfig_backup()
175*baec84f2Syuangongjios.environ["CMAKE_PREFIX_PATH"] = os.path.join(prefix, "lib/cmake/libevent")
176*baec84f2Syuangongjiexport_dll(dllpath)
177*baec84f2Syuangongjirun_test_group()
178*baec84f2Syuangongjiunexport_dll(dllpath)
179*baec84f2Syuangongjidel os.environ["CMAKE_PREFIX_PATH"]
180*baec84f2Syuangongji
181*baec84f2Syuangongji# Uninstall the libraries installed in the above steps. Install the libraries
182*baec84f2Syuangongji# into a temporary directory. Same as above, remove LibeventConfig.cmake from
183*baec84f2Syuangongji# build directory to avoid confusion when using find_package().
184*baec84f2Syuangongjiprint("[test-export] test for install tree(in non-system-wide path)")
185*baec84f2Syuangongjiexec_cmd("cmake --build . --target uninstall", True)
186*baec84f2Syuangongjitempdir = tempfile.TemporaryDirectory()
187*baec84f2Syuangongjicmd = 'cmake -DCMAKE_INSTALL_PREFIX="%s" ..' % tempdir.name
188*baec84f2Syuangongjiexec_cmd(cmd, True)
189*baec84f2Syuangongjiexec_cmd("cmake --build . --target install", True)
190*baec84f2Syuangongjiconfig_backup()
191*baec84f2Syuangongjios.environ["CMAKE_PREFIX_PATH"] = os.path.join(tempdir.name, "lib/cmake/libevent")
192*baec84f2Syuangongjidllpath = os.path.join(tempdir.name, "lib")
193*baec84f2Syuangongjiexport_dll(dllpath)
194*baec84f2Syuangongjirun_test_group()
195*baec84f2Syuangongjiunexport_dll(dllpath)
196*baec84f2Syuangongjidel os.environ["CMAKE_PREFIX_PATH"]
197*baec84f2Syuangongjiconfig_restore()
198*baec84f2Syuangongji
199*baec84f2Syuangongjiprint("[test-export] all testcases have run successfully")
200