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.
pull/13842/head
Maxim P. DEMENTIEV 4 months ago
parent fd309fff24
commit c9157c9351
  1. 5
      test cases/linuxlike/14 static dynamic linkage/main.c
  2. 52
      test cases/linuxlike/14 static dynamic linkage/meson.build
  3. 1
      test cases/linuxlike/14 static dynamic linkage/meson_options.txt
  4. 10
      test cases/linuxlike/14 static dynamic linkage/test.json
  5. 37
      test cases/linuxlike/14 static dynamic linkage/verify_static.py
  6. 49
      test cases/linuxlike/14 static dynamic linkage/verify_zlib_linkage.py

@ -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 : "<NULL>");
return !v;
}

@ -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()],
depends: [exe], 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()],
depends: [exe], should_fail: s)

@ -0,0 +1 @@
option('static', type: 'boolean', value: false)

@ -0,0 +1,10 @@
{
"matrix": {
"options": {
"static": [
{ "val": "true", "skip_on_env": [ "SKIP_STATIC_ZLIB" ] },
{ "val": "false" }
]
}
}
}

@ -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())

@ -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())
Loading…
Cancel
Save