Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test cases/linuxlike/14 static dynamic linkage: Add matrix by static #13842

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions test cases/linuxlike/14 static dynamic linkage/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
52 changes: 25 additions & 27 deletions test cases/linuxlike/14 static dynamic linkage/meson.build
Original file line number Diff line number Diff line change
@@ -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'
Comment on lines -3 to -4
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably still explicitly skip on Solaris. Your new approach would cause test failure if SKIP_STATIC_ZLIB is not exported, even though we know that if s and host_machine.system() == 'sunos' there will not be a static library.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are perfectly right that this changes the behavior, and it's better to keep the previous logic if we don't want to break something. Nice catch!

I will do what you are asking, but let's go a little farther...

When my new approach cause test failure

As far as I know, there are no SunOS tests in the current CI. And, we both know, the green status is showing this.

So there should be some test cases outside the project, the dark matter, where people will have this issue.

When my new approach fixes problem where it could possibly cause test failure

AFAIK, SunOS could be configured to have the static zlib version in addition to the default dynamic one. In this case, keeping the old condition is a bug.

Let's ask the author of those lines @alanc

With my approach the user of this test case will be able to change his environment to adopt the usage on SunOS for his/her setup.

Symmetry / Special case

What is so special about SunOS to include it into this build script?

What about the default configuration on MS Windows (no Cygwin) or MacOS?

What about IBM i (AS/400) and BSD families?

Gentoo setup is configured for Boost with the help of SKIP_STATIC_BOOST in the GHA yaml file. Why could not SunOS be configured in the same way?

Bottom line

As I said, I will fix this to keep this special case for SunOS, but IMHO it must go.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While there is no SunOS (Solaris or illumos) instance in the CI, we run the test suite on Solaris when building the meson packages for Solaris. It is true that it is not impossible for a user to build and install a static version of libz on Solaris - but since we provide a dynamic library for libz as part of the OS packages, I don't know of anyone who bothers to build their own static version. I can't speak to other OS'es or why they didn't hit the problem - perhaps their default configuration doesn't have dynamic libz either instead of just dynamic and not static.

I'm not opposed to moving this from a line of code to a configuration file - what's the "GHA yaml file"?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$ git --no-pager grep -C3 STATIC_BOOST
.github/workflows/cygwin.yml-        env:
.github/workflows/cygwin.yml-          # Cygwin's static boost installation is broken (some static library
.github/workflows/cygwin.yml-          # variants such as boost_thread are not present)
.github/workflows/cygwin.yml:          SKIP_STATIC_BOOST: 1
.github/workflows/cygwin.yml-        shell: C:\cygwin\bin\bash.exe --noprofile --norc -o igncr -eo pipefail '{0}'
.github/workflows/cygwin.yml-
.github/workflows/cygwin.yml-      - uses: actions/upload-artifact@v4
--
ci/ciimage/fedora/image.json-  "base_image": "fedora:latest",
ci/ciimage/fedora/image.json-  "env": {
ci/ciimage/fedora/image.json-    "CI":                "1",
ci/ciimage/fedora/image.json:    "SKIP_STATIC_BOOST": "1",
ci/ciimage/fedora/image.json-    "MESON_CI_JOBNAME": "linux-fedora-gcc"
ci/ciimage/fedora/image.json-  }
ci/ciimage/fedora/image.json-}
--
ci/ciimage/gentoo/image.json-  "env": {
ci/ciimage/gentoo/image.json-    "CI": "1",
ci/ciimage/gentoo/image.json-    "MESON_CI_JOBNAME": "linux-gentoo-gcc",
ci/ciimage/gentoo/image.json:    "SKIP_STATIC_BOOST": "1"
ci/ciimage/gentoo/image.json-  }
ci/ciimage/gentoo/image.json-}
--
ci/ciimage/opensuse/image.json-  "base_image": "opensuse/tumbleweed:latest",
ci/ciimage/opensuse/image.json-  "env": {
ci/ciimage/opensuse/image.json-    "CI":                  "1",
ci/ciimage/opensuse/image.json:    "SKIP_STATIC_BOOST":   "1",
ci/ciimage/opensuse/image.json-    "SINGLE_DUB_COMPILER": "1",
ci/ciimage/opensuse/image.json-    "MESON_CI_JOBNAME": "linux-opensuse-gcc"
ci/ciimage/opensuse/image.json-  }
--
test cases/frameworks/1 boost/test.json-  "matrix": {
test cases/frameworks/1 boost/test.json-    "options": {
test cases/frameworks/1 boost/test.json-      "static": [
test cases/frameworks/1 boost/test.json:        { "val": "true", "skip_on_env": [ "SKIP_STATIC_BOOST" ] },
test cases/frameworks/1 boost/test.json-        { "val": "false" }
test cases/frameworks/1 boost/test.json-      ],
test cases/frameworks/1 boost/test.json-      "b_vscrt": [

For all our docker-based CI testing we generate the docker images themselves with /ci/env_vars.sh as a kind of "/etc/profile for CI".

For Cygwin, which isn't docker-based, we use the GitHub Actions (GHA) yaml file .github/workflows/cygwin.yml. We don't maintain any such thing for Solaris' packaging.

Copy link
Author

@dememax dememax Nov 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, @alanc !
@eli-schwartz, should we throw away the SunOS special condition, or merge the PR in the current state?

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)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
option('static', type: 'boolean', value: false)
10 changes: 10 additions & 0 deletions test cases/linuxlike/14 static dynamic linkage/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"matrix": {
"options": {
"static": [
{ "val": "true", "skip_on_env": [ "SKIP_STATIC_ZLIB" ] },
{ "val": "false" }
]
}
}
}
37 changes: 0 additions & 37 deletions test cases/linuxlike/14 static dynamic linkage/verify_static.py

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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