aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Compiler-properties.md21
-rw-r--r--docs/markdown/Reference-tables.md2
-rw-r--r--docs/markdown/snippets/lcc.md23
-rw-r--r--mesonbuild/backend/ninjabackend.py89
-rw-r--r--mesonbuild/compilers/__init__.py6
-rw-r--r--mesonbuild/compilers/c.py31
-rw-r--r--mesonbuild/compilers/compilers.py36
-rw-r--r--mesonbuild/compilers/cpp.py24
-rw-r--r--mesonbuild/compilers/fortran.py7
-rw-r--r--mesonbuild/environment.py50
-rw-r--r--mesonbuild/modules/rpm.py7
-rwxr-xr-xrun_unittests.py77
-rw-r--r--test cases/common/13 pch/meson.build6
-rw-r--r--test cases/common/132 dependency file generation/meson.build10
-rw-r--r--test cases/common/22 header in file list/meson.build10
-rw-r--r--test cases/common/64 custom header generator/meson.build10
-rw-r--r--test cases/unit/13 reconfigure/meson.build4
-rw-r--r--test cases/unit/26 guessed linker dependencies/exe/app.c6
-rw-r--r--test cases/unit/26 guessed linker dependencies/exe/meson.build7
-rw-r--r--test cases/unit/26 guessed linker dependencies/lib/lib.c20
-rw-r--r--test cases/unit/26 guessed linker dependencies/lib/meson.build11
-rw-r--r--test cases/unit/26 guessed linker dependencies/lib/meson_options.txt1
-rw-r--r--test cases/unit/29 cross file overrides always args/meson.build3
-rw-r--r--test cases/unit/29 cross file overrides always args/test.c8
-rw-r--r--test cases/unit/29 cross file overrides always args/ubuntu-armhf-overrides.txt19
25 files changed, 455 insertions, 33 deletions
diff --git a/docs/markdown/Compiler-properties.md b/docs/markdown/Compiler-properties.md
index 579417a..1228f42 100644
--- a/docs/markdown/Compiler-properties.md
+++ b/docs/markdown/Compiler-properties.md
@@ -160,15 +160,30 @@ Does a function exist?
Just having a header doesn't say anything about its
contents. Sometimes you need to explicitly check if some function
-exists. This is how we would check whether the function `somefunc`
-exists in header `someheader.h`
+exists. This is how we would check whether the function `open_memstream`
+exists in header `stdio.h`
```meson
-if compiler.has_function('somefunc', prefix : '#include<someheader.h>')
+if compiler.has_function('open_memstream', prefix : '#include <stdio.h>')
# function exists, do whatever is required.
endif
```
+Note that, on macOS programs can be compiled targeting older macOS
+versions than the one that the program is compiled on. It can't be
+assumed that the OS version that is compiled on matches the OS
+version that the binary will run on.
+
+Therefore when detecting function availability with `has_function`, it
+is important to specify the correct header in the prefix argument.
+
+In the example above, the function `open_memstream` is detected, which
+was introduced in macOS 10.13. When the user builds on macOS 10.13, but
+targeting macOS 10.11 (`-mmacosx-version-min=10.11`), this will correctly
+report the function as missing. Without the header however, it would lack
+the necessary availability information and incorrectly report the function
+as available.
+
Does a structure contain a member?
==
diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md
index 7611232..5b4d7f0 100644
--- a/docs/markdown/Reference-tables.md
+++ b/docs/markdown/Reference-tables.md
@@ -21,6 +21,7 @@ These are return values of the `get_id` method in a compiler object.
| g95 | The G95 Fortran compiler |
| open64 | The Open64 Fortran Compiler |
| nagfor | The NAG Fortran compiler |
+| lcc | Elbrus C/C++/Fortran Compiler |
## Script environment variables
@@ -42,6 +43,7 @@ set in the cross file.
| x86 | 32 bit x86 processor |
| x86_64 | 64 bit x86 processor |
| arm | 32 bit ARM processor |
+| e2k | MCST Elbrus processor |
Any cpu family not listed in the above list is not guaranteed to
remain stable in future releases.
diff --git a/docs/markdown/snippets/lcc.md b/docs/markdown/snippets/lcc.md
new file mode 100644
index 0000000..2ce300d
--- /dev/null
+++ b/docs/markdown/snippets/lcc.md
@@ -0,0 +1,23 @@
+## Support for lcc compiler for e2k (Elbrus) architecture
+
+In this version, a support for lcc compiler for Elbrus processors
+based on [e2k microarchitecture](https://en.wikipedia.org/wiki/Elbrus_2000)
+has been added.
+
+Examples of such CPUs:
+* [Elbrus-8S](https://en.wikipedia.org/wiki/Elbrus-8S);
+* Elbrus-4S;
+* [Elbrus-2S+](https://en.wikipedia.org/wiki/Elbrus-2S%2B).
+
+Such compiler have a similar behavior as gcc (basic option compatibility),
+but, in is not strictly compatible with gcc as of current version.
+
+Major differences as of version 1.21.22:
+* it does not support LTO and PCH;
+* it suffers from the same dependency file creation error as icc;
+* it has minor differences in output, especially version output;
+* it differently reacts to lchmod() detection;
+* some backend messages are produced in ru_RU.KOI8-R even if LANG=C;
+* its preprocessor treats some characters differently.
+
+So every noted difference is properly handled now in meson. \ No newline at end of file
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index cee1434..41f840d 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -1156,7 +1156,7 @@ int dummy;
abs_vala_file = os.path.join(self.environment.get_build_dir(), vala_file)
if PurePath(os.path.commonpath((abs_srcbasedir, abs_vala_file))) == PurePath(abs_srcbasedir):
vala_c_subdir = PurePath(abs_vala_file).parent.relative_to(abs_srcbasedir)
- vala_c_file = os.path.join(vala_c_subdir, vala_c_file)
+ vala_c_file = os.path.join(str(vala_c_subdir), vala_c_file)
else:
path_to_target = os.path.join(self.build_to_src, target.get_subdir())
if vala_file.startswith(path_to_target):
@@ -1660,9 +1660,9 @@ rule FORTRAN_DEP_HACK
if mesonlib.is_windows():
command_template = ' command = {executable} @$out.rsp\n' \
' rspfile = $out.rsp\n' \
- ' rspfile_content = {cross_args} $ARGS {output_args} {compile_only_args} $in\n'
+ ' rspfile_content = $ARGS{cross_args} {output_args} {compile_only_args} $in\n'
else:
- command_template = ' command = {executable} {cross_args} $ARGS {output_args} {compile_only_args} $in\n'
+ command_template = ' command = {executable} $ARGS {cross_args} {output_args} {compile_only_args} $in\n'
command = command_template.format(
executable=' '.join([ninja_quote(i) for i in compiler.get_exelist()]),
cross_args=' '.join(self.get_cross_info_lang_args(compiler.language, is_cross)),
@@ -1721,10 +1721,10 @@ rule FORTRAN_DEP_HACK
if mesonlib.is_windows():
command_template = ''' command = {executable} @$out.rsp
rspfile = $out.rsp
- rspfile_content = {cross_args} $ARGS {dep_args} {output_args} {compile_only_args} $in
+ rspfile_content = $ARGS {cross_args} {dep_args} {output_args} {compile_only_args} $in
'''
else:
- command_template = ' command = {executable} {cross_args} $ARGS {dep_args} {output_args} {compile_only_args} $in\n'
+ command_template = ' command = {executable} $ARGS {cross_args} {dep_args} {output_args} {compile_only_args} $in\n'
command = command_template.format(
executable=' '.join([ninja_quote(i) for i in compiler.get_exelist()]),
cross_args=' '.join(cross_args),
@@ -1769,7 +1769,7 @@ rule FORTRAN_DEP_HACK
output = ''
else:
output = ' '.join(compiler.get_output_args('$out'))
- command = " command = {executable} {cross_args} $ARGS {dep_args} {output_args} {compile_only_args} $in\n".format(
+ command = " command = {executable} $ARGS {cross_args} {dep_args} {output_args} {compile_only_args} $in\n".format(
executable=' '.join(compiler.get_exelist()),
cross_args=' '.join(cross_args),
dep_args=' '.join(quoted_depargs),
@@ -2410,6 +2410,74 @@ rule FORTRAN_DEP_HACK
target_args = self.build_target_link_arguments(linker, target.link_whole_targets)
return linker.get_link_whole_for(target_args) if len(target_args) else []
+ def guess_library_absolute_path(self, libname, search_dirs, prefixes, suffixes):
+ for directory in search_dirs:
+ for suffix in suffixes:
+ for prefix in prefixes:
+ trial = os.path.join(directory, prefix + libname + '.' + suffix)
+ if os.path.isfile(trial):
+ return trial
+
+ def guess_external_link_dependencies(self, linker, target, commands, internal):
+ # Ideally the linker would generate dependency information that could be used.
+ # But that has 2 problems:
+ # * currently ld can not create dependency information in a way that ninja can use:
+ # https://sourceware.org/bugzilla/show_bug.cgi?id=22843
+ # * Meson optimizes libraries from the same build using the symbol extractor.
+ # Just letting ninja use ld generated dependencies would undo this optimization.
+ search_dirs = []
+ libs = []
+ absolute_libs = []
+
+ build_dir = self.environment.get_build_dir()
+ # the following loop sometimes consumes two items from command in one pass
+ it = iter(commands)
+ for item in it:
+ if item in internal and not item.startswith('-'):
+ continue
+
+ if item.startswith('-L'):
+ if len(item) > 2:
+ path = item[2:]
+ else:
+ try:
+ path = next(it)
+ except StopIteration:
+ mlog.warning("Generated linker command has -L argument without following path")
+ break
+ if not os.path.isabs(path):
+ path = os.path.join(build_dir, path)
+ search_dirs.append(path)
+ elif item.startswith('-l'):
+ if len(item) > 2:
+ libs.append(item[2:])
+ else:
+ try:
+ libs.append(next(it))
+ except StopIteration:
+ mlog.warning("Generated linker command has '-l' argument without following library name")
+ break
+ elif os.path.isabs(item) and self.environment.is_library(item) and os.path.isfile(item):
+ absolute_libs.append(item)
+
+ guessed_dependencies = []
+ # TODO The get_library_naming requirement currently excludes link targets that use d or fortran as their main linker
+ if hasattr(linker, 'get_library_naming'):
+ search_dirs += linker.get_library_dirs()
+ prefixes_static, suffixes_static = linker.get_library_naming(self.environment, 'static', strict=True)
+ prefixes_shared, suffixes_shared = linker.get_library_naming(self.environment, 'shared', strict=True)
+ for libname in libs:
+ # be conservative and record most likely shared and static resolution, because we don't know exactly
+ # which one the linker will prefer
+ static_resolution = self.guess_library_absolute_path(libname, search_dirs, prefixes_static, suffixes_static)
+ shared_resolution = self.guess_library_absolute_path(libname, search_dirs, prefixes_shared, suffixes_shared)
+ if static_resolution:
+ guessed_dependencies.append(os.path.realpath(static_resolution))
+ if shared_resolution:
+ guessed_dependencies.append(os.path.realpath(shared_resolution))
+
+ return guessed_dependencies + absolute_libs
+
def generate_link(self, target, outfile, outname, obj_list, linker, extra_args=[]):
if isinstance(target, build.StaticLibrary):
linker_base = 'STATIC'
@@ -2476,7 +2544,8 @@ rule FORTRAN_DEP_HACK
dependencies = []
else:
dependencies = target.get_dependencies()
- commands += self.build_target_link_arguments(linker, dependencies)
+ internal = self.build_target_link_arguments(linker, dependencies)
+ commands += internal
# For 'automagic' deps: Boost and GTest. Also dependency('threads').
# pkg-config puts the thread flags itself via `Cflags:`
for d in target.external_deps:
@@ -2500,6 +2569,10 @@ rule FORTRAN_DEP_HACK
# symbols from those can be found here. This is needed when the
# *_winlibs that we want to link to are static mingw64 libraries.
commands += linker.get_option_link_args(self.environment.coredata.compiler_options)
+
+ dep_targets = []
+ dep_targets.extend(self.guess_external_link_dependencies(linker, target, commands, internal))
+
# Set runtime-paths so we can run executables without needing to set
# LD_LIBRARY_PATH, etc in the environment. Doesn't work on Windows.
if has_path_sep(target.name):
@@ -2523,7 +2596,7 @@ rule FORTRAN_DEP_HACK
# Convert from GCC-style link argument naming to the naming used by the
# current compiler.
commands = commands.to_native()
- dep_targets = [self.get_dependency_filename(t) for t in dependencies]
+ dep_targets.extend([self.get_dependency_filename(t) for t in dependencies])
dep_targets.extend([self.get_dependency_filename(t)
for t in target.link_depends])
elem = NinjaBuildElement(self.all_outputs, outname, linker_rule, obj_list)
diff --git a/mesonbuild/compilers/__init__.py b/mesonbuild/compilers/__init__.py
index 84c87fb..89b46b5 100644
--- a/mesonbuild/compilers/__init__.py
+++ b/mesonbuild/compilers/__init__.py
@@ -54,10 +54,13 @@ __all__ = [
'FortranCompiler',
'G95FortranCompiler',
'GnuCCompiler',
+ 'ElbrusCCompiler',
'GnuCompiler',
'GnuCPPCompiler',
+ 'ElbrusCPPCompiler',
'GnuDCompiler',
'GnuFortranCompiler',
+ 'ElbrusFortranCompiler',
'GnuObjCCompiler',
'GnuObjCPPCompiler',
'IntelCompiler',
@@ -118,6 +121,7 @@ from .c import (
CCompiler,
ClangCCompiler,
GnuCCompiler,
+ ElbrusCCompiler,
IntelCCompiler,
VisualStudioCCompiler,
)
@@ -125,6 +129,7 @@ from .cpp import (
CPPCompiler,
ClangCPPCompiler,
GnuCPPCompiler,
+ ElbrusCPPCompiler,
IntelCPPCompiler,
VisualStudioCPPCompiler,
)
@@ -139,6 +144,7 @@ from .fortran import (
FortranCompiler,
G95FortranCompiler,
GnuFortranCompiler,
+ ElbrusFortranCompiler,
IntelFortranCompiler,
NAGFortranCompiler,
Open64FortranCompiler,
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index dee5125..71fff05 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -36,6 +36,7 @@ from .compilers import (
CompilerArgs,
CrossNoRunException,
GnuCompiler,
+ ElbrusCompiler,
IntelCompiler,
RunResult,
)
@@ -754,7 +755,7 @@ class CCompiler(Compiler):
return False
raise RuntimeError('BUG: {!r} check failed unexpectedly'.format(n))
- def get_library_naming(self, env, libtype):
+ def get_library_naming(self, env, libtype, strict=False):
'''
Get library prefixes and suffixes for the target platform ordered by
priority
@@ -762,7 +763,10 @@ class CCompiler(Compiler):
stlibext = ['a']
# We've always allowed libname to be both `foo` and `libfoo`,
# and now people depend on it
- prefixes = ['lib', '']
+ if strict and self.id != 'msvc': # lib prefix is not usually used with msvc
+ prefixes = ['lib']
+ else:
+ prefixes = ['lib', '']
# Library suffixes and prefixes
if for_darwin(env.is_cross_build(), env):
shlibext = ['dylib']
@@ -916,6 +920,29 @@ class GnuCCompiler(GnuCompiler, CCompiler):
return ['-fpch-preprocess', '-include', os.path.basename(header)]
+class ElbrusCCompiler(GnuCCompiler, ElbrusCompiler):
+ def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None, **kwargs):
+ GnuCCompiler.__init__(self, exelist, version, gcc_type, is_cross, exe_wrapper, defines, **kwargs)
+ ElbrusCompiler.__init__(self, gcc_type, defines)
+
+ # It does support some various ISO standards and c/gnu 90, 9x, 1x in addition to those which GNU CC supports.
+ def get_options(self):
+ opts = {'c_std': coredata.UserComboOption('c_std', 'C language standard to use',
+ ['none', 'c89', 'c90', 'c9x', 'c99', 'c1x', 'c11',
+ 'gnu89', 'gnu90', 'gnu9x', 'gnu99', 'gnu1x', 'gnu11',
+ 'iso9899:2011', 'iso9899:1990', 'iso9899:199409', 'iso9899:1999'],
+ 'none')}
+ return opts
+
+ # Elbrus C compiler does not have lchmod, but there is only linker warning, not compiler error.
+ # So we should explicitly fail at this case.
+ def has_function(self, funcname, prefix, env, extra_args=None, dependencies=None):
+ if funcname == 'lchmod':
+ return False
+ else:
+ return super().has_function(funcname, prefix, env, extra_args, dependencies)
+
+
class IntelCCompiler(IntelCompiler, CCompiler):
def __init__(self, exelist, version, icc_type, is_cross, exe_wrapper=None, **kwargs):
CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs)
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index 480baa9..417cbae 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -55,7 +55,6 @@ for _l in clike_langs:
clike_suffixes += lang_suffixes[_l]
clike_suffixes += ('h', 'll', 's')
-# XXX: Use this in is_library()?
soregex = re.compile(r'.*\.so(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?$')
# All these are only for C-like languages; see `clike_langs` above.
@@ -102,6 +101,10 @@ def is_object(fname):
def is_library(fname):
if hasattr(fname, 'fname'):
fname = fname.fname
+
+ if soregex.match(fname):
+ return True
+
suffix = fname.split('.')[-1]
return suffix in lib_suffixes
@@ -941,9 +944,11 @@ def get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, i
sostr = ''
else:
sostr = '.' + soversion
- if gcc_type in (GCC_STANDARD, GCC_MINGW, GCC_CYGWIN):
- # Might not be correct for mingw but seems to work.
+ if gcc_type == GCC_STANDARD:
return ['-Wl,-soname,%s%s.%s%s' % (prefix, shlib_name, suffix, sostr)]
+ elif gcc_type in (GCC_MINGW, GCC_CYGWIN):
+ # For PE/COFF the soname argument has no effect with GNU LD
+ return []
elif gcc_type == GCC_OSX:
if is_shared_module:
return []
@@ -1007,7 +1012,7 @@ def gnulike_default_include_dirs(compiler, lang):
stdout=subprocess.PIPE,
env=env
)
- stderr = p.stderr.read().decode('utf-8')
+ stderr = p.stderr.read().decode('utf-8', errors='replace')
parse_state = 0
paths = []
for line in stderr.split('\n'):
@@ -1120,6 +1125,29 @@ class GnuCompiler:
return gnulike_default_include_dirs(self.exelist, self.language)
+class ElbrusCompiler(GnuCompiler):
+ # Elbrus compiler is nearly like GCC, but does not support
+ # PCH, LTO, sanitizers and color output as of version 1.21.x.
+ def __init__(self, gcc_type, defines):
+ GnuCompiler.__init__(self, gcc_type, defines)
+ self.id = 'lcc'
+ self.base_options = ['b_pgo', 'b_coverage',
+ 'b_ndebug', 'b_staticpic',
+ 'b_lundef', 'b_asneeded']
+
+ def get_library_dirs(self):
+ env = os.environ.copy()
+ env['LC_ALL'] = 'C'
+ stdo = Popen_safe(self.exelist + ['--print-search-dirs'], env=env)[1]
+ for line in stdo.split('\n'):
+ if line.startswith('libraries:'):
+ # lcc does not include '=' in --print-search-dirs output.
+ libstr = line.split(' ', 1)[1]
+ return libstr.split(':')
+ return []
+
+
+
class ClangCompiler:
def __init__(self, clang_type):
self.id = 'clang'
diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py
index 1fa6f15..3804059 100644
--- a/mesonbuild/compilers/cpp.py
+++ b/mesonbuild/compilers/cpp.py
@@ -25,6 +25,7 @@ from .compilers import (
msvc_winlibs,
ClangCompiler,
GnuCompiler,
+ ElbrusCompiler,
IntelCompiler,
)
@@ -133,6 +134,29 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler):
return ['-fpch-preprocess', '-include', os.path.basename(header)]
+class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler):
+ def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None, **kwargs):
+ GnuCPPCompiler.__init__(self, exelist, version, gcc_type, is_cross, exe_wrapper, defines, **kwargs)
+ ElbrusCompiler.__init__(self, gcc_type, defines)
+
+ # It does not support c++/gnu++ 17 and 1z, but still does support 0x, 1y, and gnu++98.
+ def get_options(self):
+ opts = super().get_options()
+ opts['cpp_std'] = coredata.UserComboOption('cpp_std', 'C++ language standard to use',
+ ['none', 'c++98', 'c++03', 'c++0x', 'c++11', 'c++14', 'c++1y',
+ 'gnu++98', 'gnu++03', 'gnu++0x', 'gnu++11', 'gnu++14', 'gnu++1y'],
+ 'none')
+ return opts
+
+ # Elbrus C++ compiler does not have lchmod, but there is only linker warning, not compiler error.
+ # So we should explicitly fail at this case.
+ def has_function(self, funcname, prefix, env, extra_args=None, dependencies=None):
+ if funcname == 'lchmod':
+ return False
+ else:
+ return super().has_function(funcname, prefix, env, extra_args, dependencies)
+
+
class IntelCPPCompiler(IntelCompiler, CPPCompiler):
def __init__(self, exelist, version, icc_type, is_cross, exe_wrap, **kwargs):
CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap, **kwargs)
diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py
index f9fcc1c..e61c976 100644
--- a/mesonbuild/compilers/fortran.py
+++ b/mesonbuild/compilers/fortran.py
@@ -27,6 +27,7 @@ from .compilers import (
gnulike_buildtype_args,
gnulike_buildtype_linker_args,
Compiler,
+ ElbrusCompiler,
IntelCompiler,
)
@@ -180,6 +181,12 @@ class GnuFortranCompiler(FortranCompiler):
return ['-Wl,--out-implib=' + implibname]
+class ElbrusFortranCompiler(GnuFortranCompiler, ElbrusCompiler):
+ def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None, **kwargs):
+ GnuFortranCompiler.__init__(self, exelist, version, gcc_type, is_cross, exe_wrapper, defines, **kwargs)
+ ElbrusCompiler.__init__(self, gcc_type, defines)
+
+
class G95FortranCompiler(FortranCompiler):
def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags):
super().__init__(exelist, version, is_cross, exe_wrapper=None, **kwags)
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 0115fb3..cd8d92c 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -48,6 +48,9 @@ from .compilers import (
GnuFortranCompiler,
GnuObjCCompiler,
GnuObjCPPCompiler,
+ ElbrusCCompiler,
+ ElbrusCPPCompiler,
+ ElbrusFortranCompiler,
IntelCCompiler,
IntelCPPCompiler,
IntelFortranCompiler,
@@ -223,6 +226,9 @@ def detect_cpu(compilers):
except mesonlib.MesonException:
pass
return 'x86_64'
+ if trial == 'e2k':
+ # Make more precise CPU detection for Elbrus platform.
+ trial = platform.processor().lower()
# Add fixes here as bugs are reported.
return trial
@@ -421,6 +427,15 @@ class Environment:
return dot.join((major, minor, patch))
@staticmethod
+ def get_lcc_version_from_defines(defines):
+ dot = '.'
+ generation_and_major = defines.get('__LCC__', '100')
+ generation = generation_and_major[:1]
+ major = generation_and_major[1:]
+ minor = defines.get('__LCC_MINOR__', '0')
+ return dot.join((generation, major, minor))
+
+ @staticmethod
def get_gnu_compiler_type(defines):
# Detect GCC type (Apple, MinGW, Cygwin, Unix)
if '__APPLE__' in defines:
@@ -513,15 +528,27 @@ class Environment:
continue
version = search_version(out)
full_version = out.split('\n', 1)[0]
+
+ guess_gcc_or_lcc = False
if 'Free Software Foundation' in out:
+ guess_gcc_or_lcc = 'gcc'
+ if 'e2k' in out and 'lcc' in out:
+ guess_gcc_or_lcc = 'lcc'
+
+ if guess_gcc_or_lcc:
defines = self.get_gnu_compiler_defines(compiler)
if not defines:
popen_exceptions[' '.join(compiler)] = 'no pre-processor defines'
continue
gtype = self.get_gnu_compiler_type(defines)
- version = self.get_gnu_version_from_defines(defines)
- cls = GnuCCompiler if lang == 'c' else GnuCPPCompiler
+ if guess_gcc_or_lcc == 'lcc':
+ version = self.get_lcc_version_from_defines(defines)
+ cls = ElbrusCCompiler if lang == 'c' else ElbrusCPPCompiler
+ else:
+ version = self.get_gnu_version_from_defines(defines)
+ cls = GnuCCompiler if lang == 'c' else GnuCPPCompiler
return cls(ccache + compiler, version, gtype, is_cross, exe_wrap, defines, full_version=full_version)
+
if 'clang' in out:
if 'Apple' in out or mesonlib.for_darwin(want_cross, self):
cltype = CLANG_OSX
@@ -574,14 +601,25 @@ class Environment:
version = search_version(out)
full_version = out.split('\n', 1)[0]
+ guess_gcc_or_lcc = False
if 'GNU Fortran' in out:
+ guess_gcc_or_lcc = 'gcc'
+ if 'e2k' in out and 'lcc' in out:
+ guess_gcc_or_lcc = 'lcc'
+
+ if guess_gcc_or_lcc:
defines = self.get_gnu_compiler_defines(compiler)
if not defines:
popen_exceptions[' '.join(compiler)] = 'no pre-processor defines'
continue
gtype = self.get_gnu_compiler_type(defines)
- version = self.get_gnu_version_from_defines(defines)
- return GnuFortranCompiler(compiler, version, gtype, is_cross, exe_wrap, defines, full_version=full_version)
+ if guess_gcc_or_lcc == 'lcc':
+ version = self.get_lcc_version_from_defines(defines)
+ cls = ElbrusFortranCompiler
+ else:
+ version = self.get_gnu_version_from_defines(defines)
+ cls = GnuFortranCompiler
+ return cls(compiler, version, gtype, is_cross, exe_wrap, defines, full_version=full_version)
if 'G95' in out:
return G95FortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version)
@@ -626,7 +664,7 @@ class Environment:
popen_exceptions[' '.join(compiler + arg)] = e
continue
version = search_version(out)
- if 'Free Software Foundation' in out:
+ if 'Free Software Foundation' in out or ('e2k' in out and 'lcc' in out):
defines = self.get_gnu_compiler_defines(compiler)
if not defines:
popen_exceptions[' '.join(compiler)] = 'no pre-processor defines'
@@ -653,7 +691,7 @@ class Environment:
popen_exceptions[' '.join(compiler + arg)] = e
continue
version = search_version(out)
- if 'Free Software Foundation' in out:
+ if 'Free Software Foundation' in out or ('e2k' in out and 'lcc' in out):
defines = self.get_gnu_compiler_defines(compiler)
if not defines:
popen_exceptions[' '.join(compiler)] = 'no pre-processor defines'
diff --git a/mesonbuild/modules/rpm.py b/mesonbuild/modules/rpm.py
index a2a7929..ba5bcaa 100644
--- a/mesonbuild/modules/rpm.py
+++ b/mesonbuild/modules/rpm.py
@@ -32,10 +32,17 @@ class RPMModule(ExtensionModule):
def generate_spec_template(self, state, args, kwargs):
compiler_deps = set()
for compiler in state.compilers.values():
+ # Elbrus has one 'lcc' package for every compiler
if isinstance(compiler, compilers.GnuCCompiler):
compiler_deps.add('gcc')
elif isinstance(compiler, compilers.GnuCPPCompiler):
compiler_deps.add('gcc-c++')
+ elif isinstance(compiler, compilers.ElbrusCCompiler):
+ compiler_deps.add('lcc')
+ elif isinstance(compiler, compilers.ElbrusCPPCompiler):
+ compiler_deps.add('lcc')
+ elif isinstance(compiler, compilers.ElbrusFortranCompiler):
+ compiler_deps.add('lcc')
elif isinstance(compiler, compilers.ValaCompiler):
compiler_deps.add('vala')
elif isinstance(compiler, compilers.GnuFortranCompiler):
diff --git a/run_unittests.py b/run_unittests.py
index 0f9a50b..19a8c87 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -482,6 +482,7 @@ class BasePlatformTests(unittest.TestCase):
self.backend = getattr(Backend, os.environ.get('MESON_UNIT_TEST_BACKEND', 'ninja'))
self.meson_mainfile = os.path.join(src_root, 'meson.py')
self.meson_args = ['--backend=' + self.backend.name]
+ self.meson_cross_file = None
self.meson_command = meson_command + self.meson_args
self.mconf_command = meson_command + ['configure']
self.mintro_command = meson_command + ['introspect']
@@ -567,6 +568,8 @@ class BasePlatformTests(unittest.TestCase):
if default_args:
args += ['--prefix', self.prefix,
'--libdir', self.libdir]
+ if self.meson_cross_file:
+ args += ['--cross-file', self.meson_cross_file]
self.privatedir = os.path.join(self.builddir, 'meson-private')
if inprocess:
try:
@@ -1346,7 +1349,8 @@ class AllPlatformTests(BasePlatformTests):
# \n is never substituted by the GNU pre-processor via a -D define
# ' and " confuse shlex.split() even when they are escaped
# % and # confuse the MSVC preprocessor
- value = 'spaces and fun!@$^&*()-=_+{}[]:;<>?,./~`'
+ # !, ^, *, and < confuse lcc preprocessor
+ value = 'spaces and fun@$&()-=_+{}[]:;>?,./~`'
os.environ['CPPFLAGS'] = '-D{}="{}"'.format(define, value)
os.environ['CFLAGS'] = '-DMESON_FAIL_VALUE=cflags-read'.format(define)
self.init(testdir, ['-D{}={}'.format(define, value)])
@@ -1949,6 +1953,55 @@ recommended as it can lead to undefined behaviour on some platforms''')
exe = os.path.join(self.builddir, 'main')
self.assertEqual(b'NDEBUG=0', subprocess.check_output(exe).strip())
+ def test_guessed_linker_dependencies(self):
+ '''
+ Test that meson adds dependencies for libraries based on the final
+ linker command line.
+ '''
+ # build library
+ testdirbase = os.path.join(self.unit_test_dir, '26 guessed linker dependencies')
+ testdirlib = os.path.join(testdirbase, 'lib')
+ extra_args = None
+ env = Environment(testdirlib, self.builddir, self.meson_command,
+ get_fake_options(self.prefix), [])
+ if env.detect_c_compiler(False).get_id() != 'msvc':
+ # static libraries are not linkable with -l with msvc because meson installs them
+ # as .a files which unix_args_to_native will not know as it expects libraries to use
+ # .lib as extension. For a DLL the import library is installed as .lib. Thus for msvc
+ # this tests needs to use shared libraries to test the path resolving logic in the
+ # dependency generation code path.
+ extra_args = ['--default-library', 'static']
+ self.init(testdirlib, extra_args=extra_args)
+ self.build()
+ self.install()
+ libbuilddir = self.builddir
+ installdir = self.installdir
+ libdir = os.path.join(self.installdir, self.prefix.lstrip('/').lstrip('\\'), 'lib')
+
+ # build user of library
+ self.new_builddir()
+ # replace is needed because meson mangles platform pathes passed via LDFLAGS
+ os.environ["LDFLAGS"] = '-L{}'.format(libdir.replace('\\', '/'))
+ self.init(os.path.join(testdirbase, 'exe'))
+ del os.environ["LDFLAGS"]
+ self.build()
+ self.assertBuildIsNoop()
+
+ # rebuild library
+ exebuilddir = self.builddir
+ self.installdir = installdir
+ self.builddir = libbuilddir
+ # Microsoft's compiler is quite smart about touching import libs on changes,
+ # so ensure that there is actually a change in symbols.
+ self.setconf('-Dmore_exports=true')
+ self.build()
+ self.install()
+ # no ensure_backend_detects_changes needed because self.setconf did that already
+
+ # assert user of library will be rebuild
+ self.builddir = exebuilddir
+ self.assertRebuiltTarget('app')
+
class FailureTests(BasePlatformTests):
'''
@@ -2764,11 +2817,12 @@ cpu = 'armv7' # Not sure if correct.
endian = 'little'
''' % os.path.join(testdir, 'some_cross_tool.py'))
crossfile.flush()
- self.init(testdir, ['--cross-file=' + crossfile.name])
+ self.meson_cross_file = crossfile.name
+ self.init(testdir)
def test_reconfigure(self):
testdir = os.path.join(self.unit_test_dir, '13 reconfigure')
- self.init(testdir, ['-Db_lto=true'], default_args=False)
+ self.init(testdir, ['-Db_coverage=true'], default_args=False)
self.build('reconfigure')
def test_vala_generated_source_buildir_inside_source_tree(self):
@@ -2870,7 +2924,7 @@ class LinuxArmCrossCompileTests(BasePlatformTests):
def setUp(self):
super().setUp()
src_root = os.path.dirname(__file__)
- self.meson_command += ['--cross=' + os.path.join(src_root, 'cross', 'ubuntu-armhf.txt')]
+ self.meson_cross_file = os.path.join(src_root, 'cross', 'ubuntu-armhf.txt')
def test_cflags_cross_environment_pollution(self):
'''
@@ -2884,6 +2938,21 @@ class LinuxArmCrossCompileTests(BasePlatformTests):
compdb = self.get_compdb()
self.assertNotIn('-DBUILD_ENVIRONMENT_ONLY', compdb[0]['command'])
+ def test_cross_file_overrides_always_args(self):
+ '''
+ Test that $lang_args in cross files always override get_always_args().
+ Needed for overriding the default -D_FILE_OFFSET_BITS=64 on some
+ architectures such as some Android versions and Raspbian.
+ https://github.com/mesonbuild/meson/issues/3049
+ https://github.com/mesonbuild/meson/issues/3089
+ '''
+ testdir = os.path.join(self.unit_test_dir, '29 cross file overrides always args')
+ self.meson_cross_file = os.path.join(self.unit_test_dir, 'ubuntu-armhf-overrides.txt')
+ self.init(testdir)
+ compdb = self.get_compdb()
+ self.assertRegex(compdb[0]['command'], '-D_FILE_OFFSET_BITS=64.*-U_FILE_OFFSET_BITS')
+ self.build()
+
class RewriterTests(unittest.TestCase):
diff --git a/test cases/common/13 pch/meson.build b/test cases/common/13 pch/meson.build
index 9ed6512..e144aa5 100644
--- a/test cases/common/13 pch/meson.build
+++ b/test cases/common/13 pch/meson.build
@@ -1,4 +1,10 @@
project('pch test', 'c')
+cc = meson.get_compiler('c')
+cc_id = cc.get_id()
+if cc_id == 'lcc'
+ error('MESON_SKIP_TEST: Elbrus compiler does not support PCH.')
+endif
+
exe = executable('prog', 'prog.c',
c_pch : ['pch/prog_pch.c', 'pch/prog.h'])
diff --git a/test cases/common/132 dependency file generation/meson.build b/test cases/common/132 dependency file generation/meson.build
index dcfdcd9..cd66cb7 100644
--- a/test cases/common/132 dependency file generation/meson.build
+++ b/test cases/common/132 dependency file generation/meson.build
@@ -1,11 +1,13 @@
project('dep file gen', 'c')
-cc_id = meson.get_compiler('c').get_id()
-if cc_id == 'intel'
- # ICC does not escape spaces in paths in the dependency file, so Ninja
+cc_id = meson.get_compiler('c').get_id()
+cc_ver = meson.get_compiler('c').version()
+
+if cc_id == 'intel' or (cc_id == 'lcc' and cc_ver.version_compare('<=1.23.08')
+ # ICC and LCC <= 1.23.08 do not escape spaces in paths in the dependency file, so Ninja
# (correctly) thinks that the rule has multiple outputs and errors out:
# 'depfile has multiple output paths'
- error('MESON_SKIP_TEST: Skipping test with Intel compiler because it generates broken dependency files')
+ error('MESON_SKIP_TEST: Skipping test because your compiler is known to generate broken dependency files')
endif
e = executable('main file', 'main .c')
diff --git a/test cases/common/22 header in file list/meson.build b/test cases/common/22 header in file list/meson.build
index cc30c71..ff42cc4 100644
--- a/test cases/common/22 header in file list/meson.build
+++ b/test cases/common/22 header in file list/meson.build
@@ -1,4 +1,14 @@
project('header in file list', 'c')
+cc_id = meson.get_compiler('c').get_id()
+cc_ver = meson.get_compiler('c').version()
+
+if cc_id == 'intel' or (cc_id == 'lcc' and cc_ver.version_compare('<=1.23.08')
+ # ICC and LCC <= 1.23.08 do not escape spaces in paths in the dependency file, so Ninja
+ # (correctly) thinks that the rule has multiple outputs and errors out:
+ # 'depfile has multiple output paths'
+ error('MESON_SKIP_TEST: Skipping test because your compiler is known to generate broken dependency files')
+endif
+
exe = executable('prog', 'prog.c', 'header.h')
test('basic', exe)
diff --git a/test cases/common/64 custom header generator/meson.build b/test cases/common/64 custom header generator/meson.build
index 33ba4c5..2279513 100644
--- a/test cases/common/64 custom header generator/meson.build
+++ b/test cases/common/64 custom header generator/meson.build
@@ -1,5 +1,15 @@
project('custom header generator', 'c')
+cc_id = meson.get_compiler('c').get_id()
+cc_ver = meson.get_compiler('c').version()
+
+if cc_id == 'intel' or (cc_id == 'lcc' and cc_ver.version_compare('<=1.23.08')
+ # ICC and LCC <= 1.23.08 do not escape spaces in paths in the dependency file, so Ninja
+ # (correctly) thinks that the rule has multiple outputs and errors out:
+ # 'depfile has multiple output paths'
+ error('MESON_SKIP_TEST: Skipping test because your compiler is known to generate broken dependency files')
+endif
+
gen = find_program('makeheader.py')
generated_h = custom_target('makeheader.py',
diff --git a/test cases/unit/13 reconfigure/meson.build b/test cases/unit/13 reconfigure/meson.build
index 102180e..453644a 100644
--- a/test cases/unit/13 reconfigure/meson.build
+++ b/test cases/unit/13 reconfigure/meson.build
@@ -1,5 +1,5 @@
project('reconfigure test', ['c'])
-if get_option('b_lto') != true
- error('b_lto not set')
+if get_option('b_coverage') != true
+ error('b_coverage not set')
endif
diff --git a/test cases/unit/26 guessed linker dependencies/exe/app.c b/test cases/unit/26 guessed linker dependencies/exe/app.c
new file mode 100644
index 0000000..1031a42
--- /dev/null
+++ b/test cases/unit/26 guessed linker dependencies/exe/app.c
@@ -0,0 +1,6 @@
+void liba_func();
+
+int main() {
+ liba_func();
+ return 0;
+}
diff --git a/test cases/unit/26 guessed linker dependencies/exe/meson.build b/test cases/unit/26 guessed linker dependencies/exe/meson.build
new file mode 100644
index 0000000..8bb1bd7
--- /dev/null
+++ b/test cases/unit/26 guessed linker dependencies/exe/meson.build
@@ -0,0 +1,7 @@
+project('exe', ['c'])
+
+executable('app',
+ 'app.c',
+ # Use uninterpreted strings to avoid path finding by dependency or compiler.find_library
+ link_args: ['-ltest-lib']
+ )
diff --git a/test cases/unit/26 guessed linker dependencies/lib/lib.c b/test cases/unit/26 guessed linker dependencies/lib/lib.c
new file mode 100644
index 0000000..1a8f94d
--- /dev/null
+++ b/test cases/unit/26 guessed linker dependencies/lib/lib.c
@@ -0,0 +1,20 @@
+#if defined _WIN32
+ #define DLL_PUBLIC __declspec(dllexport)
+#else
+ #if defined __GNUC__
+ #define DLL_PUBLIC __attribute__ ((visibility("default")))
+ #else
+ #pragma message ("Compiler does not support symbol visibility.")
+ #define DLL_PUBLIC
+ #endif
+#endif
+
+void DLL_PUBLIC liba_func() {
+}
+
+#ifdef MORE_EXPORTS
+
+void DLL_PUBLIC libb_func() {
+}
+
+#endif
diff --git a/test cases/unit/26 guessed linker dependencies/lib/meson.build b/test cases/unit/26 guessed linker dependencies/lib/meson.build
new file mode 100644
index 0000000..36df112
--- /dev/null
+++ b/test cases/unit/26 guessed linker dependencies/lib/meson.build
@@ -0,0 +1,11 @@
+project('lib1', ['c'])
+
+c_args = []
+
+# Microsoft's compiler is quite smart about touching import libs on changes,
+# so ensure that there is actually a change in symbols.
+if get_option('more_exports')
+ c_args += '-DMORE_EXPORTS'
+endif
+
+a = library('test-lib', 'lib.c', c_args: c_args, install: true)
diff --git a/test cases/unit/26 guessed linker dependencies/lib/meson_options.txt b/test cases/unit/26 guessed linker dependencies/lib/meson_options.txt
new file mode 100644
index 0000000..2123e45
--- /dev/null
+++ b/test cases/unit/26 guessed linker dependencies/lib/meson_options.txt
@@ -0,0 +1 @@
+option('more_exports', type : 'boolean', value : false)
diff --git a/test cases/unit/29 cross file overrides always args/meson.build b/test cases/unit/29 cross file overrides always args/meson.build
new file mode 100644
index 0000000..ef6556e
--- /dev/null
+++ b/test cases/unit/29 cross file overrides always args/meson.build
@@ -0,0 +1,3 @@
+project('cross compile args override always args', 'c')
+
+executable('no-file-offset-bits', 'test.c')
diff --git a/test cases/unit/29 cross file overrides always args/test.c b/test cases/unit/29 cross file overrides always args/test.c
new file mode 100644
index 0000000..315f92e
--- /dev/null
+++ b/test cases/unit/29 cross file overrides always args/test.c
@@ -0,0 +1,8 @@
+#ifdef _FILE_OFFSET_BITS
+ #error "_FILE_OFFSET_BITS should not be set"
+#endif
+
+int main(int argc, char *argv[])
+{
+ return 0;
+}
diff --git a/test cases/unit/29 cross file overrides always args/ubuntu-armhf-overrides.txt b/test cases/unit/29 cross file overrides always args/ubuntu-armhf-overrides.txt
new file mode 100644
index 0000000..a00a7d1
--- /dev/null
+++ b/test cases/unit/29 cross file overrides always args/ubuntu-armhf-overrides.txt
@@ -0,0 +1,19 @@
+[binaries]
+# we could set exe_wrapper = qemu-arm-static but to test the case
+# when cross compiled binaries can't be run we don't do that
+c = '/usr/bin/arm-linux-gnueabihf-gcc'
+cpp = '/usr/bin/arm-linux-gnueabihf-g++'
+rust = ['rustc', '--target', 'arm-unknown-linux-gnueabihf', '-C', 'linker=/usr/bin/arm-linux-gnueabihf-gcc-7']
+ar = '/usr/arm-linux-gnueabihf/bin/ar'
+strip = '/usr/arm-linux-gnueabihf/bin/strip'
+pkgconfig = '/usr/bin/arm-linux-gnueabihf-pkg-config'
+
+[properties]
+root = '/usr/arm-linux-gnueabihf'
+c_args = ['-U_FILE_OFFSET_BITS']
+
+[host_machine]
+system = 'linux'
+cpu_family = 'arm'
+cpu = 'armv7' # Not sure if correct.
+endian = 'little'