From edabf58e77312fe1fc3bc4e28abd492d5e9c9fb5 Mon Sep 17 00:00:00 2001 From: "Maxim P. DEMENTIEV" Date: Wed, 30 Oct 2024 11:59:34 +0100 Subject: [PATCH] test cases/linuxlike/14 static dynamic linkage: Add matrix by static Not only Solaris doesn't ship static libraries, it's common practice for Linux distributions in general (security updates, size/space, etc.). See, for example 'test cases/frameworks/1 boost'. Enhancements: * Added flexibility: Introduced the SKIP_STATIC_ZLIB environment variable to optionally skip static linkage (similar to SKIP_STATIC_BOOST). * Expanded testing: Included testing for dynamic linkage, which was previously limited to static in verify_static.py (renamed to verify_zlib_linkage.py). * Improved test coverage: Ensured that each case is tested for its specific linkage type and the opposite case fails. * Addressed Cygwin issue: Ensured that the corresponding symbol is present on Cygwin. Renames, comments, etc. --- .../14 static dynamic linkage/main.c | 5 +- .../14 static dynamic linkage/meson.build | 52 +++++++++---------- .../meson_options.txt | 1 + .../14 static dynamic linkage/test.json | 10 ++++ .../verify_static.py | 37 ------------- .../verify_zlib_linkage.py | 49 +++++++++++++++++ 6 files changed, 88 insertions(+), 66 deletions(-) create mode 100644 test cases/linuxlike/14 static dynamic linkage/meson_options.txt create mode 100644 test cases/linuxlike/14 static dynamic linkage/test.json delete mode 100755 test cases/linuxlike/14 static dynamic linkage/verify_static.py create mode 100755 test cases/linuxlike/14 static dynamic linkage/verify_zlib_linkage.py diff --git a/test cases/linuxlike/14 static dynamic linkage/main.c b/test cases/linuxlike/14 static dynamic linkage/main.c index 09d1509bb316..58208521a956 100644 --- a/test cases/linuxlike/14 static dynamic linkage/main.c +++ b/test cases/linuxlike/14 static dynamic linkage/main.c @@ -2,6 +2,7 @@ #include "zlib.h" int main(void) { - printf("%s\n", zlibVersion()); - return 0; + const char * const v = zlibVersion(); + printf("%s\n", v ? v : ""); + return !v; } diff --git a/test cases/linuxlike/14 static dynamic linkage/meson.build b/test cases/linuxlike/14 static dynamic linkage/meson.build index fb0e3537a94f..b1688d330375 100644 --- a/test cases/linuxlike/14 static dynamic linkage/meson.build +++ b/test cases/linuxlike/14 static dynamic linkage/meson.build @@ -1,36 +1,34 @@ +# This test uses zlib to verify static and dynamic linkages. +# A C program is used to call a single zlib function (zlibVersion). +# The nm utility is then used to check for the existence of this symbol +# in the resulting binary. + project('static dynamic', 'c') -# Solaris does not ship static libraries -if host_machine.system() == 'sunos' - has_static = false -else - has_static = true +s = get_option('static') + +if s and host_machine.system() == 'sunos' + error('MESON_SKIP_TEST: static zlib linkage is not supported on SunOS by default') endif cc = meson.get_compiler('c') -z_default = cc.find_library('z') -if has_static - z_static = cc.find_library('z', static: true) -endif -z_dynamic = cc.find_library('z', static: false) +z = cc.find_library('z', static: s) -exe_default = executable('main_default', 'main.c', dependencies: [z_default]) -if has_static - exe_static = executable('main_static', 'main.c', dependencies: [z_static]) -endif -exe_dynamic = executable('main_dynamic', 'main.c', dependencies: [z_dynamic]) +exe = executable('print_zlib_version', 'main.c', dependencies: [z]) -test('test default', exe_default) -if has_static - test('test static', exe_static) -endif -test('test dynamic', exe_dynamic) +# first step: the executable should compile and work +test('test zlib', exe) -if has_static - test('verify static linking', find_program('verify_static.py'), - args: ['--platform=' + host_machine.system(), exe_static.full_path()]) -endif -test('verify dynamic linking', find_program('verify_static.py'), - args: ['--platform=' + host_machine.system(), exe_dynamic.full_path()], - should_fail: true) +# to check the zlib static/dynamic symbols in the resulting binary +find_program('nm') + +# second step: static linkage +test('verify static zlib linking', find_program('verify_zlib_linkage.py'), + args: ['--platform=' + host_machine.system(), '--static', exe.full_path()], + should_fail: not s) + +# third step: dynamic linkage +test('verify dynamic zlib linking', find_program('verify_zlib_linkage.py'), + args: ['--platform=' + host_machine.system(), exe.full_path()], + should_fail: s) diff --git a/test cases/linuxlike/14 static dynamic linkage/meson_options.txt b/test cases/linuxlike/14 static dynamic linkage/meson_options.txt new file mode 100644 index 000000000000..019feaf383f6 --- /dev/null +++ b/test cases/linuxlike/14 static dynamic linkage/meson_options.txt @@ -0,0 +1 @@ +option('static', type: 'boolean', value: false) diff --git a/test cases/linuxlike/14 static dynamic linkage/test.json b/test cases/linuxlike/14 static dynamic linkage/test.json new file mode 100644 index 000000000000..da2162b0786d --- /dev/null +++ b/test cases/linuxlike/14 static dynamic linkage/test.json @@ -0,0 +1,10 @@ +{ + "matrix": { + "options": { + "static": [ + { "val": "true", "skip_on_env": [ "SKIP_STATIC_ZLIB" ] }, + { "val": "false" } + ] + } + } +} diff --git a/test cases/linuxlike/14 static dynamic linkage/verify_static.py b/test cases/linuxlike/14 static dynamic linkage/verify_static.py deleted file mode 100755 index 25e97f368bb1..000000000000 --- a/test cases/linuxlike/14 static dynamic linkage/verify_static.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python3 -"""Test script that checks if zlib was statically linked to executable""" -import subprocess -import sys - -def handle_common(path): - """Handle the common case.""" - try: - output = subprocess.check_output(['nm', '--defined-only', '-P', '-A', path]).decode('utf-8') - except subprocess.CalledProcessError: - # some NMs only support -U. Older binutils only supports --defined-only. - output = subprocess.check_output(['nm', '-UPA', path]).decode('utf-8') - # POSIX format. Prints all *defined* symbols, looks like this: - # builddir/main_static: zlibVersion T 1190 39 - # or - # builddir/main_static: zlibVersion D 1fde0 30 - if ': zlibVersion ' in output: - return 0 - return 1 - -def handle_cygwin(path): - """Handle the Cygwin case.""" - output = subprocess.check_output(['nm', path]).decode('utf-8') - if (('I __imp_zlibVersion' in output) or ('D __imp_zlibVersion' in output)): - return 1 - return 0 - -def main(): - """Main function""" - if len(sys.argv) > 2 and sys.argv[1] == '--platform=cygwin': - return handle_cygwin(sys.argv[2]) - else: - return handle_common(sys.argv[2]) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/test cases/linuxlike/14 static dynamic linkage/verify_zlib_linkage.py b/test cases/linuxlike/14 static dynamic linkage/verify_zlib_linkage.py new file mode 100755 index 000000000000..1782eb144187 --- /dev/null +++ b/test cases/linuxlike/14 static dynamic linkage/verify_zlib_linkage.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +"""Test script that checks if zlib was statically or dynamically linked to executable""" +import subprocess +import sys +import argparse + +def check_zlib_symbol_common(path, is_static): + """Tests if the binary contains zlibVersion symbol (non-Cygwin version).""" + try: + sym_opt = '--defined-only' if is_static else '--undefined-only' + output = subprocess.check_output(['nm', sym_opt, '-P', '-A', path]).decode('utf-8') + except subprocess.CalledProcessError: + # some NMs only support -U. Older binutils only supports --defined-only. + opts = '-UPA' if is_static else '-uPA' + output = subprocess.check_output(['nm', opts, path]).decode('utf-8') + # POSIX format. Prints all *defined* symbols, looks like this: + # builddir/main_static: zlibVersion T 1190 39 + # or + # builddir/main_static: zlibVersion D 1fde0 30 + if ': zlibVersion ' in output: + return 0 + return 1 + +def check_zlib_symbol_cygwin(path, is_static): + """Tests if the binary contains zlibVersion symbol (Cygwin case).""" + output = subprocess.check_output(['nm', path]).decode('utf-8') + # No matter static or dynamic, the name must exist in nm output + if ' zlibVersion' not in output: + return 2 + is_dynamic = ('I __imp_zlibVersion' in output) or ('D __imp_zlibVersion' in output) + if is_dynamic == is_static: # expected/got mismatch? + return 3 + return 0 + +def main(): + """Main function""" + parser = argparse.ArgumentParser() + parser.add_argument('path', help='executable path') + parser.add_argument('-p', '--platform') + parser.add_argument('-s', '--static', action='store_true', default=False) + args = parser.parse_args() + if args.platform == 'cygwin': + return check_zlib_symbol_cygwin(args.path, args.static) + else: + return check_zlib_symbol_common(args.path, args.static) + + +if __name__ == '__main__': + sys.exit(main())