aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/backend/ninjabackend.py6
-rw-r--r--mesonbuild/environment.py63
-rw-r--r--mesonbuild/modules/gnome.py16
-rw-r--r--mesonbuild/mparser.py19
-rwxr-xr-xrun_unittests.py11
-rw-r--r--test cases/linuxlike/11 runpath rpath ldlibrarypath/meson.build2
6 files changed, 77 insertions, 40 deletions
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 3bf840d..db136c7 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -1304,7 +1304,11 @@ int dummy;
if static_linker is None:
return
rule = 'rule STATIC%s_LINKER\n' % crstr
- if mesonlib.is_windows():
+ # We don't use @file.rsp on Windows with ArLinker because llvm-ar and
+ # gcc-ar blindly pass the --plugin argument to `ar` and you cannot pass
+ # options as arguments while using the @file.rsp syntax.
+ # See: https://github.com/mesonbuild/meson/issues/1646
+ if mesonlib.is_windows() and not isinstance(static_linker, compilers.ArLinker):
command_template = ''' command = {executable} @$out.rsp
rspfile = $out.rsp
rspfile_content = $LINK_ARGS {output_args} $in
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 93a41e8..cb28897 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -262,8 +262,10 @@ class Environment:
self.default_objc = ['cc']
self.default_objcpp = ['c++']
self.default_fortran = ['gfortran', 'g95', 'f95', 'f90', 'f77']
- self.default_static_linker = 'ar'
- self.vs_static_linker = 'lib'
+ self.default_static_linker = ['ar']
+ self.vs_static_linker = ['lib']
+ self.gcc_static_linker = ['gcc-ar']
+ self.clang_static_linker = ['llvm-ar']
# Various prefixes and suffixes for import libraries, shared libraries,
# static libraries, and executables.
@@ -433,8 +435,8 @@ class Environment:
exe_wrap = None
return compilers, ccache, is_cross, exe_wrap
- def _handle_compiler_exceptions(self, exceptions, compilers):
- errmsg = 'Unknown compiler(s): ' + str(compilers)
+ def _handle_exceptions(self, exceptions, binaries, bintype='compiler'):
+ errmsg = 'Unknown {}(s): {}'.format(bintype, binaries)
if exceptions:
errmsg += '\nThe follow exceptions were encountered:'
for (c, e) in exceptions.items():
@@ -484,7 +486,7 @@ class Environment:
inteltype = ICC_STANDARD
cls = IntelCCompiler if lang == 'c' else IntelCPPCompiler
return cls(ccache + compiler, version, inteltype, is_cross, exe_wrap)
- self._handle_compiler_exceptions(popen_exceptions, compilers)
+ self._handle_exceptions(popen_exceptions, compilers)
def detect_c_compiler(self, want_cross):
return self._detect_c_or_cpp_compiler('c', 'CC', want_cross)
@@ -537,7 +539,7 @@ class Environment:
if 'NAG Fortran' in err:
return NAGFortranCompiler(compiler, version, is_cross, exe_wrap)
- self._handle_compiler_exceptions(popen_exceptions, compilers)
+ self._handle_exceptions(popen_exceptions, compilers)
def get_scratch_dir(self):
return self.scratch_dir
@@ -570,7 +572,7 @@ class Environment:
return ClangObjCCompiler(ccache + compiler, version, CLANG_OSX, is_cross, exe_wrap)
if out.startswith('clang'):
return ClangObjCCompiler(ccache + compiler, version, CLANG_STANDARD, is_cross, exe_wrap)
- self._handle_compiler_exceptions(popen_exceptions, compilers)
+ self._handle_exceptions(popen_exceptions, compilers)
def detect_objcpp_compiler(self, want_cross):
popen_exceptions = {}
@@ -596,7 +598,7 @@ class Environment:
return ClangObjCPPCompiler(ccache + compiler, version, CLANG_OSX, is_cross, exe_wrap)
if out.startswith('clang'):
return ClangObjCPPCompiler(ccache + compiler, version, CLANG_STANDARD, is_cross, exe_wrap)
- self._handle_compiler_exceptions(popen_exceptions, compilers)
+ self._handle_exceptions(popen_exceptions, compilers)
def detect_java_compiler(self):
exelist = ['javac']
@@ -693,28 +695,39 @@ class Environment:
linker = self.cross_info.config['binaries']['ar']
if isinstance(linker, str):
linker = [linker]
+ linkers = [linker]
else:
evar = 'AR'
if evar in os.environ:
- linker = shlex.split(os.environ[evar])
+ linkers = [shlex.split(os.environ[evar])]
elif isinstance(compiler, VisualStudioCCompiler):
- linker = [self.vs_static_linker]
+ linkers = [self.vs_static_linker]
+ elif isinstance(compiler, GnuCompiler):
+ # Use gcc-ar if available; needed for LTO
+ linkers = [self.gcc_static_linker, self.default_static_linker]
+ elif isinstance(compiler, ClangCompiler):
+ # Use llvm-ar if available; needed for LTO
+ linkers = [self.clang_static_linker, self.default_static_linker]
else:
- linker = [self.default_static_linker]
- if 'lib' in linker or 'lib.exe' in linker:
- arg = '/?'
- else:
- arg = '--version'
- try:
- p, out, err = Popen_safe(linker + [arg])
- except OSError:
- raise EnvironmentException('Could not execute static linker "%s".' % ' '.join(linker))
- if '/OUT:' in out or '/OUT:' in err:
- return VisualStudioLinker(linker)
- if p.returncode == 0:
- return ArLinker(linker)
- if p.returncode == 1 and err.startswith('usage'): # OSX
- return ArLinker(linker)
+ linkers = [self.default_static_linker]
+ popen_exceptions = {}
+ for linker in linkers:
+ if 'lib' in linker or 'lib.exe' in linker:
+ arg = '/?'
+ else:
+ arg = '--version'
+ try:
+ p, out, err = Popen_safe(linker + [arg])
+ except OSError as e:
+ popen_exceptions[' '.join(linker + [arg])] = e
+ continue
+ if '/OUT:' in out or '/OUT:' in err:
+ return VisualStudioLinker(linker)
+ if p.returncode == 0:
+ return ArLinker(linker)
+ if p.returncode == 1 and err.startswith('usage'): # OSX
+ return ArLinker(linker)
+ self._handle_exceptions(popen_exceptions, linkers, 'linker')
raise EnvironmentException('Unknown static linker "%s"' % ' '.join(linker))
def detect_ccache(self):
diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py
index 6921472..b4dfd12 100644
--- a/mesonbuild/modules/gnome.py
+++ b/mesonbuild/modules/gnome.py
@@ -253,6 +253,8 @@ class GnomeModule(ExtensionModule):
missing_basename = os.path.basename(missing)
for dep in dependencies:
+ if hasattr(dep, 'held_object'):
+ dep = dep.held_object
if isinstance(dep, mesonlib.File):
if dep.fname == missing_basename:
found = True
@@ -260,18 +262,20 @@ class GnomeModule(ExtensionModule):
dep_files.append(dep)
subdirs.append(dep.subdir)
break
- elif isinstance(dep, interpreter.CustomTargetHolder):
- if dep.held_object.get_basename() == missing_basename:
+ elif isinstance(dep, build.CustomTarget):
+ if dep.get_basename() == missing_basename:
found = True
dep_files.remove(missing)
dep_files.append(
mesonlib.File(
is_built=True,
- subdir=dep.held_object.get_subdir(),
- fname=dep.held_object.get_basename()))
- depends.append(dep.held_object)
- subdirs.append(dep.held_object.get_subdir())
+ subdir=dep.get_subdir(),
+ fname=dep.get_basename()))
+ depends.append(dep)
+ subdirs.append(dep.get_subdir())
break
+ else:
+ raise RuntimeError('Unreachable code.')
if not found:
raise MesonException(
diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py
index de0f12c..75985c3 100644
--- a/mesonbuild/mparser.py
+++ b/mesonbuild/mparser.py
@@ -420,6 +420,9 @@ class Parser:
except StopIteration:
self.current = Token('eof', '', self.current.line_start, self.current.lineno, self.current.colno + self.current.bytespan[1] - self.current.bytespan[0], (0, 0), None)
+ def getline(self):
+ return self.lexer.getline(self.current.line_start)
+
def accept(self, s):
if self.current.tid == s:
self.getsym()
@@ -429,12 +432,12 @@ class Parser:
def expect(self, s):
if self.accept(s):
return True
- raise ParseException('Expecting %s got %s.' % (s, self.current.tid), self.lexer.getline(self.current.line_start), self.current.lineno, self.current.colno)
+ raise ParseException('Expecting %s got %s.' % (s, self.current.tid), self.getline(), self.current.lineno, self.current.colno)
def block_expect(self, s, block_start):
if self.accept(s):
return True
- raise BlockParseException('Expecting %s got %s.' % (s, self.current.tid), self.lexer.getline(self.current.line_start), self.current.lineno, self.current.colno, self.lexer.getline(block_start.line_start), block_start.lineno, block_start.colno)
+ raise BlockParseException('Expecting %s got %s.' % (s, self.current.tid), self.getline(), self.current.lineno, self.current.colno, self.lexer.getline(block_start.line_start), block_start.lineno, block_start.colno)
def parse(self):
block = self.codeblock()
@@ -449,18 +452,18 @@ class Parser:
if self.accept('plusassign'):
value = self.e1()
if not isinstance(left, IdNode):
- raise ParseException('Plusassignment target must be an id.', left.lineno, left.colno)
+ raise ParseException('Plusassignment target must be an id.', self.getline(), left.lineno, left.colno)
return PlusAssignmentNode(left.lineno, left.colno, left.value, value)
elif self.accept('assign'):
value = self.e1()
if not isinstance(left, IdNode):
raise ParseException('Assignment target must be an id.',
- left.lineno, left.colno)
+ self.getline(), left.lineno, left.colno)
return AssignmentNode(left.lineno, left.colno, left.value, value)
elif self.accept('questionmark'):
if self.in_ternary:
raise ParseException('Nested ternary operators are not allowed.',
- left.lineno, left.colno)
+ self.getline(), left.lineno, left.colno)
self.in_ternary = True
trueblock = self.e1()
self.expect('colon')
@@ -536,7 +539,7 @@ class Parser:
self.block_expect('rparen', block_start)
if not isinstance(left, IdNode):
raise ParseException('Function call must be applied to plain id',
- left.lineno, left.colno)
+ self.getline(), left.lineno, left.colno)
left = FunctionNode(left.subdir, left.lineno, left.colno, left.value, args)
go_again = True
while go_again:
@@ -588,7 +591,7 @@ class Parser:
elif self.accept('colon'):
if not isinstance(s, IdNode):
raise ParseException('Keyword argument must be a plain identifier.',
- s.lineno, s.colno)
+ self.getline(), s.lineno, s.colno)
a.set_kwarg(s.value, self.statement())
potential = self.current
if not self.accept('comma'):
@@ -604,7 +607,7 @@ class Parser:
methodname = self.e9()
if not(isinstance(methodname, IdNode)):
raise ParseException('Method name must be plain id',
- self.current.lineno, self.current.colno)
+ self.getline(), self.current.lineno, self.current.colno)
self.expect('lparen')
args = self.args()
self.expect('rparen')
diff --git a/run_unittests.py b/run_unittests.py
index 3e98c21..20464e0 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -1060,6 +1060,17 @@ class AllPlatformTests(BasePlatformTests):
self.utime(os.path.join(testdir, f))
self.assertRebuiltTarget('prog')
+ def test_static_library_lto(self):
+ '''
+ Test that static libraries can be built with LTO and linked to
+ executables. On Linux, this requires the use of gcc-ar.
+ https://github.com/mesonbuild/meson/issues/1646
+ '''
+ testdir = os.path.join(self.common_test_dir, '5 linkstatic')
+ self.init(testdir, extra_args='-Db_lto=true')
+ self.build()
+ self.run_tests()
+
class WindowsTests(BasePlatformTests):
'''
diff --git a/test cases/linuxlike/11 runpath rpath ldlibrarypath/meson.build b/test cases/linuxlike/11 runpath rpath ldlibrarypath/meson.build
index b49da66..a3103ac 100644
--- a/test cases/linuxlike/11 runpath rpath ldlibrarypath/meson.build
+++ b/test cases/linuxlike/11 runpath rpath ldlibrarypath/meson.build
@@ -1,5 +1,7 @@
project('runpath rpath ldlibrarypath', 'c')
+error('MESON_SKIP_TEST test disabled due to bug #1635.')
+
libsrc = files('lib.c')
subdir('lib1')