Merge pull request #1102 from mesonbuild/soname

Fix soname symlink generation
pull/1132/head
Jussi Pakkanen 8 years ago committed by GitHub
commit 3276bdd23d
  1. 11
      mesonbuild/backend/ninjabackend.py
  2. 6
      mesonbuild/build.py
  3. 51
      run_unittests.py
  4. 26
      test cases/unit/1 soname/CMakeLists.txt
  5. 18
      test cases/unit/1 soname/meson.build
  6. 3
      test cases/unit/1 soname/versioned.c

@ -2004,14 +2004,21 @@ rule FORTRAN_DEP_HACK
def generate_shlib_aliases(self, target, outdir): def generate_shlib_aliases(self, target, outdir):
basename = target.get_filename() basename = target.get_filename()
aliases = target.get_aliaslist() aliases = target.get_aliaslist()
for alias in aliases: for i, alias in enumerate(aliases):
aliasfile = os.path.join(self.environment.get_build_dir(), outdir, alias) aliasfile = os.path.join(self.environment.get_build_dir(), outdir, alias)
try: try:
os.remove(aliasfile) os.remove(aliasfile)
except Exception: except Exception:
pass pass
# If both soversion and version are set and to different values,
# the .so symlink must point to the soversion symlink rather than the
# original file.
if i == 0 and len(aliases) > 1:
pointed_to_filename = aliases[1]
else:
pointed_to_filename = basename
try: try:
os.symlink(basename, aliasfile) os.symlink(pointed_to_filename, aliasfile)
except NotImplementedError: except NotImplementedError:
mlog.debug("Library versioning disabled because symlinks are not supported.") mlog.debug("Library versioning disabled because symlinks are not supported.")
except OSError: except OSError:

@ -1069,12 +1069,10 @@ class SharedLibrary(BuildTarget):
self.soversion = str(self.soversion) self.soversion = str(self.soversion)
if not isinstance(self.soversion, str): if not isinstance(self.soversion, str):
raise InvalidArguments('Shared library soversion is not a string or integer.') raise InvalidArguments('Shared library soversion is not a string or integer.')
try:
int(self.soversion)
except ValueError:
raise InvalidArguments('Shared library soversion must be a valid integer')
elif self.ltversion: elif self.ltversion:
# library version is defined, get the soversion from that # library version is defined, get the soversion from that
# We replicate what Autotools does here and take the first
# number of the version by default.
self.soversion = self.ltversion.split('.')[0] self.soversion = self.ltversion.split('.')[0]
# Visual Studio module-definitions file # Visual Studio module-definitions file
if 'vs_module_defs' in kwargs: if 'vs_module_defs' in kwargs:

@ -17,6 +17,7 @@ import unittest, os, sys, shutil, time
import subprocess import subprocess
import re, json import re, json
import tempfile import tempfile
from glob import glob
import mesonbuild.environment import mesonbuild.environment
from mesonbuild.environment import detect_ninja from mesonbuild.environment import detect_ninja
from mesonbuild.dependencies import PkgConfigDependency, Qt5Dependency from mesonbuild.dependencies import PkgConfigDependency, Qt5Dependency
@ -52,6 +53,7 @@ class LinuxlikeTests(unittest.TestCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
src_root = os.path.dirname(__file__) src_root = os.path.dirname(__file__)
src_root = os.path.join(os.getcwd(), src_root)
self.builddir = tempfile.mkdtemp() self.builddir = tempfile.mkdtemp()
self.meson_command = [sys.executable, os.path.join(src_root, 'meson.py')] self.meson_command = [sys.executable, os.path.join(src_root, 'meson.py')]
self.mconf_command = [sys.executable, os.path.join(src_root, 'mesonconf.py')] self.mconf_command = [sys.executable, os.path.join(src_root, 'mesonconf.py')]
@ -60,6 +62,7 @@ class LinuxlikeTests(unittest.TestCase):
self.common_test_dir = os.path.join(src_root, 'test cases/common') self.common_test_dir = os.path.join(src_root, 'test cases/common')
self.vala_test_dir = os.path.join(src_root, 'test cases/vala') self.vala_test_dir = os.path.join(src_root, 'test cases/vala')
self.framework_test_dir = os.path.join(src_root, 'test cases/frameworks') self.framework_test_dir = os.path.join(src_root, 'test cases/frameworks')
self.unit_test_dir = os.path.join(src_root, 'test cases/unit')
self.output = b'' self.output = b''
self.orig_env = os.environ.copy() self.orig_env = os.environ.copy()
@ -211,5 +214,53 @@ class LinuxlikeTests(unittest.TestCase):
mesonlog = self.get_meson_log() mesonlog = self.get_meson_log()
self.assertTrue(msg in mesonlog or msg2 in mesonlog) self.assertTrue(msg in mesonlog or msg2 in mesonlog)
def get_soname(self, fname):
output = subprocess.check_output(['readelf', '-a', fname])
for line in output.decode('utf-8', errors='ignore').split('\n'):
if 'SONAME' in line:
return line.split('[')[1].split(']')[0]
raise RuntimeError('Readelf gave no SONAME.')
def test_soname(self):
testdir = os.path.join(self.unit_test_dir, '1 soname')
self.init(testdir)
self.build()
# File without aliases set.
nover = os.path.join(self.builddir, 'libnover.so')
self.assertTrue(os.path.exists(nover))
self.assertFalse(os.path.islink(nover))
self.assertEqual(self.get_soname(nover), 'libnover.so')
self.assertEqual(len(glob(nover[:-3] + '*')), 1)
# File with version set
verset = os.path.join(self.builddir, 'libverset.so')
self.assertTrue(os.path.exists(verset + '.4.5.6'))
self.assertEqual(os.readlink(verset), 'libverset.so.4')
self.assertEqual(self.get_soname(verset), 'libverset.so.4')
self.assertEqual(len(glob(verset[:-3] + '*')), 3)
# File with soversion set
soverset = os.path.join(self.builddir, 'libsoverset.so')
self.assertTrue(os.path.exists(soverset + '.1.2.3'))
self.assertEqual(os.readlink(soverset), 'libsoverset.so.1.2.3')
self.assertEqual(self.get_soname(soverset), 'libsoverset.so.1.2.3')
self.assertEqual(len(glob(soverset[:-3] + '*')), 2)
# File with version and soversion set to same values
settosame = os.path.join(self.builddir, 'libsettosame.so')
self.assertTrue(os.path.exists(settosame + '.7.8.9'))
self.assertEqual(os.readlink(settosame), 'libsettosame.so.7.8.9')
self.assertEqual(self.get_soname(settosame), 'libsettosame.so.7.8.9')
self.assertEqual(len(glob(settosame[:-3] + '*')), 2)
# File with version and soversion set to different values
bothset = os.path.join(self.builddir, 'libbothset.so')
self.assertTrue(os.path.exists(bothset + '.1.2.3'))
self.assertEqual(os.readlink(bothset), 'libbothset.so.1.2.3')
self.assertEqual(os.readlink(bothset + '.1.2.3'), 'libbothset.so.4.5.6')
self.assertEqual(self.get_soname(bothset), 'libbothset.so.1.2.3')
self.assertEqual(len(glob(bothset[:-3] + '*')), 3)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

@ -0,0 +1,26 @@
# This is a CMake version of this test. It behaves slightly differently
# so in case you ever need to debug this, here it is.
#
# The biggest difference is that if SOVERSION is not set, it
# is set to VERSION. Autotools sets it to the first number
# of VERSION. That is, for version number 1.2.3 CMake sets
# soname to 1.2.3 but Autotools sets it to 1.
project(vertest C)
cmake_minimum_required(VERSION 3.5)
add_library(nover SHARED versioned.c)
add_library(verset SHARED versioned.c)
set_target_properties(verset PROPERTIES VERSION 4.5.6)
add_library(soverset SHARED versioned.c)
set_target_properties(soverset PROPERTIES SOVERSION 1.2.3)
add_library(bothset SHARED versioned.c)
set_target_properties(bothset PROPERTIES SOVERSION 1.2.3)
set_target_properties(bothset PROPERTIES VERSION 4.5.6)
add_library(settosame SHARED versioned.c)
set_target_properties(settosame PROPERTIES SOVERSION 7.8.9)
set_target_properties(settosame PROPERTIES VERSION 7.8.9)

@ -0,0 +1,18 @@
project('vertest', 'c')
shared_library('nover', 'versioned.c')
shared_library('verset', 'versioned.c',
version : '4.5.6')
shared_library('soverset', 'versioned.c',
soversion : '1.2.3')
shared_library('bothset', 'versioned.c',
soversion : '1.2.3',
version : '4.5.6')
shared_library('settosame', 'versioned.c',
soversion : '7.8.9',
version : '7.8.9')

@ -0,0 +1,3 @@
int versioned_func() {
return 0;
}
Loading…
Cancel
Save