aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/snippets/llvm-static-linking.md8
-rw-r--r--mesonbuild/dependencies/dev.py92
-rw-r--r--test cases/frameworks/15 llvm/meson.build36
3 files changed, 108 insertions, 28 deletions
diff --git a/docs/markdown/snippets/llvm-static-linking.md b/docs/markdown/snippets/llvm-static-linking.md
new file mode 100644
index 0000000..bb72a56
--- /dev/null
+++ b/docs/markdown/snippets/llvm-static-linking.md
@@ -0,0 +1,8 @@
+# LLVM dependency supports both dynamic and static linking
+
+The LLVM dependency has been improved to consistently use dynamic linking.
+Previously recent version (>= 3.9) would link dynamically while older versions
+would link statically.
+
+Now LLVM also accepts the `static` keyword to enable statically linking to LLVM
+modules instead of dynamically linking.
diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py
index 308ae55..2ab2847 100644
--- a/mesonbuild/dependencies/dev.py
+++ b/mesonbuild/dependencies/dev.py
@@ -16,6 +16,7 @@
# development purposes, such as testing, debugging, etc..
import os
+import re
import shlex
import shutil
@@ -136,8 +137,10 @@ class LLVMDependency(ExternalDependency):
# It's necessary for LLVM <= 3.8 to use the C++ linker. For 3.9 and 4.0
# the C linker works fine if only using the C API.
super().__init__('llvm-config', environment, 'cpp', kwargs)
- self.modules = []
+ self.provided_modules = []
+ self.required_modules = set()
self.llvmconfig = None
+ self.static = kwargs.get('static', False)
self.__best_found = None
# FIXME: Support multiple version requirements ala PkgConfigDependency
req_version = kwargs.get('version', None)
@@ -169,31 +172,90 @@ class LLVMDependency(ExternalDependency):
# for users who want the patch version.
self.version = out.strip().rstrip('svn')
- p, out = Popen_safe(
- [self.llvmconfig, '--libs', '--ldflags'])[:2]
+ p, out = Popen_safe([self.llvmconfig, '--components'])[:2]
if p.returncode != 0:
- raise DependencyException('Could not generate libs for LLVM.')
- self.link_args = strip_system_libdirs(environment, shlex.split(out))
+ raise DependencyException('Could not generate modules for LLVM.')
+ self.provided_modules = shlex.split(out)
+
+ modules = stringlistify(extract_as_list(kwargs, 'modules'))
+ self.check_components(modules)
+ opt_modules = stringlistify(extract_as_list(kwargs, 'optional_modules'))
+ self.check_components(opt_modules, required=False)
+
p, out = Popen_safe([self.llvmconfig, '--cppflags'])[:2]
if p.returncode != 0:
raise DependencyException('Could not generate includedir for LLVM.')
cargs = mesonlib.OrderedSet(shlex.split(out))
self.compile_args = list(cargs.difference(self.__cpp_blacklist))
- p, out = Popen_safe([self.llvmconfig, '--components'])[:2]
+ if version_compare(self.version, '>= 3.9'):
+ self._set_new_link_args()
+ else:
+ self._set_old_link_args()
+ self.link_args = strip_system_libdirs(environment, self.link_args)
+
+ def _set_new_link_args(self):
+ """How to set linker args for LLVM versions >= 3.9"""
+ link_args = ['--link-static', '--system-libs'] if self.static else ['--link-shared']
+ p, out = Popen_safe(
+ [self.llvmconfig, '--libs', '--ldflags'] + link_args + list(self.required_modules))[:2]
if p.returncode != 0:
- raise DependencyException('Could not generate modules for LLVM.')
- self.modules = shlex.split(out)
+ raise DependencyException('Could not generate libs for LLVM.')
+ self.link_args = shlex.split(out)
- modules = stringlistify(extract_as_list(kwargs, 'modules'))
+ def _set_old_link_args(self):
+ """Setting linker args for older versions of llvm.
+
+ Old versions of LLVM bring an extra level of insanity with them.
+ llvm-config will provide the correct arguments for static linking, but
+ not for shared-linnking, we have to figure those out ourselves, because
+ of course we do.
+ """
+ if self.static:
+ p, out = Popen_safe(
+ [self.llvmconfig, '--libs', '--ldflags', '--system-libs'] + list(self.required_modules))[:2]
+ if p.returncode != 0:
+ raise DependencyException('Could not generate libs for LLVM.')
+ self.link_args = shlex.split(out)
+ else:
+ # llvm-config will provide arguments for static linking, so we get
+ # to figure out for ourselves what to link with. We'll do that by
+ # checking in the directory provided by --libdir for a library
+ # called libLLVM-<ver>.(so|dylib|dll)
+ p, out = Popen_safe([self.llvmconfig, '--libdir'])[:2]
+ if p.returncode != 0:
+ raise DependencyException('Could not generate libs for LLVM.')
+ libdir = out.strip()
+
+ expected_name = 'libLLVM-{}'.format(self.version)
+ re_name = re.compile(r'{}.(so|dll|dylib)'.format(expected_name))
+
+ for file_ in os.listdir(libdir):
+ if re_name.match(file_):
+ self.link_args = ['-L{}'.format(libdir),
+ '-l{}'.format(os.path.splitext(file_.lstrip('lib'))[0])]
+ break
+ else:
+ raise DependencyException(
+ 'Could not find a dynamically linkable library for LLVM.')
+
+ def check_components(self, modules, required=True):
+ """Check for llvm components (modules in meson terms).
+
+ The required option is whether the module is required, not whether LLVM
+ is required.
+ """
for mod in sorted(set(modules)):
- if mod not in self.modules:
- mlog.log('LLVM module', mod, 'found:', mlog.red('NO'))
- self.is_found = False
- if self.required:
- raise DependencyException(
- 'Could not find required LLVM Component: {}'.format(mod))
+ if mod not in self.provided_modules:
+ mlog.log('LLVM module', mod, 'found:', mlog.red('NO'),
+ '(optional)' if not required else '')
+ if required:
+ self.is_found = False
+ if self.required:
+ raise DependencyException(
+ 'Could not find required LLVM Component: {}'.format(mod))
else:
+ self.required_modules.add(mod)
mlog.log('LLVM module', mod, 'found:', mlog.green('YES'))
def check_llvmconfig(self, version_req):
diff --git a/test cases/frameworks/15 llvm/meson.build b/test cases/frameworks/15 llvm/meson.build
index 468094a..eb1b8d5 100644
--- a/test cases/frameworks/15 llvm/meson.build
+++ b/test cases/frameworks/15 llvm/meson.build
@@ -1,21 +1,31 @@
project('llvmtest', ['c', 'cpp'], default_options : ['c_std=c99'])
-llvm_dep = dependency(
- 'llvm',
- modules : ['bitwriter', 'asmprinter', 'executionengine', 'target',
- 'mcjit', 'nativecodegen'],
- required : true,
-)
-
d = dependency('llvm', modules : 'not-found', required : false)
assert(d.found() == false, 'not-found llvm module found')
d = dependency('llvm', version : '<0.1', required : false)
assert(d.found() == false, 'ancient llvm module found')
-executable('sum', 'sum.c', dependencies : [
- llvm_dep,
- dependency('zlib'),
- meson.get_compiler('c').find_library('dl', required : false),
- dependency('tinfo'),
- ])
+d = dependency('llvm', optional_modules : 'not-found', required : false)
+assert(d.found() == true, 'optional module stopped llvm from being found.')
+
+foreach static : [true, false]
+ llvm_dep = dependency(
+ 'llvm',
+ modules : ['bitwriter', 'asmprinter', 'executionengine', 'target',
+ 'mcjit', 'nativecodegen'],
+ required : true,
+ static : static,
+ )
+ name = static ? 'static' : 'dynamic'
+ executable(
+ 'sum-@0@'.format(name),
+ 'sum.c',
+ dependencies : [
+ llvm_dep,
+ dependency('zlib'),
+ dependency('glib-2.0'),
+ meson.get_compiler('c').find_library('dl', required : false),
+ ]
+ )
+endforeach