Commit 40779ea8 authored by Nirbheek Chauhan's avatar Nirbheek Chauhan 🐜 Committed by Sebastian Dröge
Browse files

LibtoolLibrary: Auto-detect libraries and versions

Instead of requiring recipes to hard-code the major/minor/micro versions in the
recipe, auto-detect them based on the platform-specific filesprovider regular
expressions.

This reduces maintenance burden greatly and we now generate more accurate .la
files. A bunch of recipes were already wrong (openh264, taglib, etc).
parent 274c852e
......@@ -17,9 +17,11 @@
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
import re
import os
from cerbero.config import Platform
from cerbero.build.filesprovider import find_shlib_regex, FilesProvider
from cerbero.errors import FatalError
class LibtoolLibrary(object):
'''
......@@ -27,7 +29,7 @@ class LibtoolLibrary(object):
'''
LIBTOOL_TPL = '''\
# %(libname)s - a libtool library file
# %(laname)s - a libtool library file
# Generated by libtool (GNU libtool) 2.4.2 Debian-2.4.2-1ubuntu1
#
# Please DO NOT delete this file!
......@@ -51,7 +53,7 @@ dependency_libs='%(dependency_libs)s'
# Names of additional weak libraries provided by this library
weak_library_names=''
# Version information for libglib-2.0.
# Version information for %(libname)s.
current=%(current)s
age=%(age)s
revision=%(revision)s
......@@ -70,10 +72,10 @@ dlpreopen=''
libdir='%(libdir)s'
'''
def __init__(self, libname, major, minor, micro, libdir, platform,
deps=None):
def __init__(self, libname, libdir, platform, deps=None):
self.libtool_vars = {
'libname': '',
'laname': '',
'dlname': '',
'library_names': '',
'old_library': '',
......@@ -83,48 +85,64 @@ libdir='%(libdir)s'
'revision': '',
'libdir': ''}
if platform == Platform.WINDOWS:
shared_ext = 'dll.a'
elif platform in [Platform.DARWIN, Platform.IOS]:
shared_ext = 'dylib'
else:
shared_ext = 'so'
if not libname.startswith('lib'):
libname = 'lib%s' % libname
if deps is None:
deps = ''
self.libname = libname
self.libdir = libdir
self.laname = '%s.la' % libname
dlname_base = '%s.%s' % (libname, shared_ext)
dlname = dlname_base
dlname_all = dlname_base
major_str = ''
minor_str = ''
micro_str = ''
if major is not None:
dlname = '%s.%s' % (dlname_base, major)
major_str = major
if minor is not None:
dlname_all = '%s.%s' % (dlname, minor)
minor_str = minor
if micro is not None:
dlname_all = '%s.%s' % (dlname_all, micro)
micro_str = micro
old_library = '%s.a' % libname
self.change_value('libname', self.laname)
self.laname = 'lib{}.la'.format(libname)
regex = FilesProvider.EXTENSIONS[platform]['sregex']
regex = regex.format(re.escape(self.libname))
# Find shared libraries
shlibs = self._find_shlibs(regex, platform)
# libfoo.so.2 or libfoo.so (if no versioning at all)
try:
dlname = shlibs[-2] or shlibs[-1]
except IndexError:
# No shared library was installed by the recipe
dlname = ''
# Auto-detect major/minor/micro versions
major, minor, micro = self._autodetect_versions(regex, shlibs)
old_library = 'lib{}.a'.format(libname)
self.change_value('laname', self.laname)
self.change_value('libname', 'lib' + self.libname)
self.change_value('dlname', dlname)
self.change_value('library_names', '%s %s %s' % (dlname_all, dlname,
dlname_base))
self.change_value('library_names', ' '.join(shlibs))
self.change_value('old_library', old_library)
self.change_value('current', minor_str)
self.change_value('age', minor_str)
self.change_value('revision', micro_str)
self.change_value('current', minor)
self.change_value('age', minor)
self.change_value('revision', micro)
self.change_value('libdir', libdir)
self.change_value('dependency_libs', self._parse_deps(deps))
def _find_shlibs(self, regex, platform):
if self.libdir.endswith('/'):
self.libdir = self.libdir[:-1]
prefix = os.path.dirname(self.libdir)
libdir = os.path.basename(self.libdir)
ext = FilesProvider.EXTENSIONS[platform]['srext']
libs = find_shlib_regex(self.libname, prefix, libdir, ext, regex)
# Return in order from most version components to least. F.ex:
# ['libfoo.so.2.4800.1', 'libfoo.so.2', 'libfoo.so']
return sorted([os.path.basename(lib) for lib in libs], reverse=True)
def _autodetect_versions(self, regex, libs):
"Auto-detect major/minor/micro versions"
if not libs:
return [''] * 3
# Find the library with the most version components
# So if we have:
# ['lib/libfoo.so.0.11.0', 'lib/libfoo.so', 'lib/libfoo.so.0']
# This will yield
# 'libfoo.so.0.11.0'
# Usually, this is the actual library and the rest are symlinks
actual_lib = os.path.basename(sorted(libs, reverse=True)[0])
# Get the version components. This would yield:
# ('0', '11', '0')
# For libfoo.2.6, this will yield:
# ('2', '6', '')
return [v[1:] if v else '' for v in re.match(regex, actual_lib).groups()]
def save(self):
path = os.path.join(self.libdir, self.laname)
with open(path, 'w') as f:
......
......@@ -29,17 +29,14 @@ class Recipe(recipe.Recipe):
(shared_makefile, self.config.prefix, extension, self.config.prefix)
def post_install(self):
libtool_la = LibtoolLibrary('bz2', 1, 0, 6, self.config.libdir,
self.config.target_platform)
libtool_la.save()
src = None
dst = None
libdir = os.path.join(self.config.prefix, 'lib')
if self.config.target_platform in [Platform.LINUX, Platform.ANDROID]:
src = 'libbz2.so.1.0.6'
src = 'libbz2.so.{}'.format(self.version)
dst = 'libbz2.so'
elif self.config.target_platform == Platform.DARWIN:
src = 'libbz2.1.0.6.dylib'
src = 'libbz2.{}.dylib'.format(self.version)
dst = 'libbz2.dylib'
elif self.config.target_platform == Platform.IOS:
src = 'libbz2.dylib'
......@@ -49,3 +46,7 @@ class Recipe(recipe.Recipe):
if os.path.exists(p) or os.path.islink(p):
os.remove(p)
shell.call('ln -s %s %s' % (src, dst), libdir)
libtool_la = LibtoolLibrary('bz2', self.config.libdir,
self.config.target_platform)
libtool_la.save()
......@@ -54,9 +54,8 @@ class Recipe(recipe.Recipe):
# Create a libtool library for gnustl (libgnustl.la)
lib = LibtoolLibrary('gnustl', None, None, None, libdir,
self.config.target_platform)
lib.change_value('dependency_libs', ' -lstdc++')
lib = LibtoolLibrary('gnustl', libdir, self.config.target_platform,
deps=['-lstdc++'])
lib.save()
# Create pkg-config file (gnustl.pc)
......
......@@ -89,10 +89,8 @@ class Recipe(custom.GStreamerStatic):
deps += ['avutil']
if n == 'avfilter':
deps += ['avutil', 'avcodec', 'avformat']
libtool_la = LibtoolLibrary(n, None, None, None, self.config.libdir,
libtool_la = LibtoolLibrary(n, self.config.libdir,
self.config.target_platform, deps)
libtool_la.change_value ('dlname', '')
libtool_la.change_value ('library_names', '')
libtool_la.save()
super(Recipe, self).post_install()
gstlibavlib = os.path.join(self.config.prefix, 'lib', 'gstreamer-1.0',
......
......@@ -33,7 +33,6 @@ class Recipe(recipe.Recipe):
self.make_install = 'make install SYS=%s prefix=$CERBERO_PREFIX CRYPTO=GNUTLS XLDFLAGS="$LDFLAGS" XCFLAGS="$CFLAGS" CC="$CC" LD="$LD"' % (system)
def post_install(self):
deps = ['gnutls']
libtool_la = LibtoolLibrary('rtmp', 0, None, None, self.config.libdir,
self.config.target_platform, deps)
libtool_la = LibtoolLibrary('rtmp', self.config.libdir,
self.config.target_platform, deps=['gnutls'])
libtool_la.save()
......@@ -27,7 +27,6 @@ class Recipe(recipe.Recipe):
shutil.copy(os.path.join(self.build_dir, 'srtp.def'), libdir)
def post_install(self):
# XXX: Don't forget to keep this in sync with the library version!
libtool_la = LibtoolLibrary('srtp', 1, None, None, self.config.libdir,
libtool_la = LibtoolLibrary('srtp', self.config.libdir,
self.config.target_platform)
libtool_la.save()
......@@ -32,7 +32,7 @@ class Recipe(recipe.Recipe):
def post_install(self):
# Create libtool libraries (.la)
libtool_la = LibtoolLibrary('nettle', 6, 2, None, self.config.libdir,
libtool_la = LibtoolLibrary('nettle', self.config.libdir,
self.config.target_platform)
libtool_la.save()
deps = ['nettle', 'gmp']
......@@ -43,7 +43,7 @@ class Recipe(recipe.Recipe):
if self.config.target_platform != Platform.WINDOWS:
deps += ['-lc']
libtool_la = LibtoolLibrary('hogweed', 4, 2, None, self.config.libdir,
libtool_la = LibtoolLibrary('hogweed', self.config.libdir,
self.config.target_platform, deps)
libtool_la.save()
......
......@@ -107,7 +107,7 @@ class Recipe(recipe.Recipe):
else:
raise NotImplementedError
libtool_la = LibtoolLibrary('openh264', 0, None, None, self.config.libdir,
libtool_la = LibtoolLibrary('openh264', self.config.libdir,
self.config.target_platform,
deps=dependency_libs)
libtool_la.save()
......@@ -37,9 +37,8 @@ class Recipe(recipe.Recipe):
# Create a libtool library for stlport (libstlport.la)
lib = LibtoolLibrary('stlport', None, None, None, libdir,
self.config.target_platform)
lib.change_value('dependency_libs', ' -lstdc++')
lib = LibtoolLibrary('stlport', libdir, self.config.target_platform,
deps=['-lstdc++'])
lib.save()
# Create pkg-config file (stlport.pc)
......
......@@ -40,9 +40,8 @@ class Recipe(recipe.Recipe):
os.path.join(self.config.prefix, 'lib', 'libtag.a'))
def post_install(self):
deps = ['z']
if self.config.target_platform == Platform.ANDROID:
deps.append('gnustl')
libtool_la = LibtoolLibrary('tag', 1, 7, None, self.config.libdir,
self.config.target_platform, deps)
libtool_la = LibtoolLibrary('tag', self.config.libdir,
self.config.target_platform, deps=['z'])
libtool_la.save()
......@@ -54,6 +54,6 @@ class Recipe(recipe.Recipe):
self.configure_options += ' --disable-asm '
def post_install(self):
libtool_la = LibtoolLibrary('x264', 148, None, None, self.config.libdir,
libtool_la = LibtoolLibrary('x264', self.config.libdir,
self.config.target_platform)
libtool_la.save()
......@@ -36,7 +36,7 @@ class Recipe(recipe.Recipe):
self.configure_options += " --uname=arm-linux-androideabi "
def post_install(self):
libtool_la = LibtoolLibrary('z', 1, 2, 8, self.config.libdir,
libtool_la = LibtoolLibrary('z', self.config.libdir,
self.config.target_platform)
libtool_la.save()
# FIXME This is to workaround a build issue trying to ld to libz.so
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment