diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index c226a0910..3ef18e886 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -1152,9 +1152,6 @@ class GnuCCompiler(GnuCompiler, CCompiler): return options['c_winlibs'].value[:] return [] - def get_std_shared_lib_link_args(self): - return ['-shared'] - def get_pch_use_args(self, pch_dir, header): return ['-fpch-preprocess', '-include', os.path.basename(header)] @@ -1211,18 +1208,6 @@ class IntelCCompiler(IntelCompiler, CCompiler): args.append('-std=' + std.value) return args - def get_std_shared_lib_link_args(self): - return ['-shared'] - - def get_std_shared_module_link_args(self, options): - if self.compiler_type.is_osx_compiler: - return ['-bundle', '-Wl,-undefined,dynamic_lookup'] - return ['-shared'] - - def has_arguments(self, args, env, code, mode): - # -diag-error 10148 is required to catch invalid -W options - return super().has_arguments(args + ['-diag-error', '10006', '-diag-error', '10148'], env, code, mode) - class VisualStudioCCompiler(CCompiler): std_warn_args = ['/W3'] diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 6f90c6afc..6fd1d28a2 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import contextlib, enum, os.path, re, tempfile, shlex +import abc, contextlib, enum, os.path, re, tempfile, shlex import subprocess from ..linkers import StaticLinker @@ -1171,13 +1171,6 @@ class CompilerType(enum.Enum): return self.name in ('GCC_MINGW', 'GCC_CYGWIN', 'CLANG_MINGW', 'ICC_WIN') -# GNU ld cannot be installed on macOS -# https://github.com/Homebrew/homebrew-core/issues/17794#issuecomment-328174395 -# Hence, we don't need to differentiate between OS and ld -# for the sake of adding as-needed support -GNU_LD_AS_NEEDED = '-Wl,--as-needed' -APPLE_LD_AS_NEEDED = '-Wl,-dead_strip_dylibs' - def get_macos_dylib_install_name(prefix, shlib_name, suffix, soversion): install_name = prefix + shlib_name if soversion is not None: @@ -1277,47 +1270,32 @@ def gnulike_default_include_dirs(compiler, lang): mlog.warning('No include directory found parsing "{cmd}" output'.format(cmd=" ".join(cmd))) return paths -class GnuCompiler: - # Functionality that is common to all GNU family compilers. - def __init__(self, compiler_type, defines): - self.id = 'gcc' + +class GnuLikeCompiler(abc.ABC): + """ + GnuLikeCompiler is a common interface to all compilers implementing + the GNU-style commandline interface. This includes GCC, Clang + and ICC. Certain functionality between them is different and requires + that the actual concrete subclass define their own implementation. + """ + def __init__(self, compiler_type): self.compiler_type = compiler_type - self.defines = defines or {} self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage', - 'b_colorout', 'b_ndebug', 'b_staticpic'] + 'b_ndebug', 'b_staticpic', 'b_asneeded'] if not self.compiler_type.is_osx_compiler: self.base_options.append('b_lundef') - self.base_options.append('b_asneeded') - # All GCC backends can do assembly + # All GCC-like backends can do assembly self.can_compile_suffixes.add('s') - # TODO: centralise this policy more globally, instead - # of fragmenting it into GnuCompiler and ClangCompiler def get_asneeded_args(self): + # GNU ld cannot be installed on macOS + # https://github.com/Homebrew/homebrew-core/issues/17794#issuecomment-328174395 + # Hence, we don't need to differentiate between OS and ld + # for the sake of adding as-needed support if self.compiler_type.is_osx_compiler: - return APPLE_LD_AS_NEEDED + return '-Wl,-dead_strip_dylibs' else: - return GNU_LD_AS_NEEDED - - def get_colorout_args(self, colortype): - if mesonlib.version_compare(self.version, '>=4.9.0'): - return gnu_color_args[colortype][:] - return [] - - def get_warn_args(self, level): - args = super().get_warn_args(level) - if mesonlib.version_compare(self.version, '<4.8.0') and '-Wpedantic' in args: - # -Wpedantic was added in 4.8.0 - # https://gcc.gnu.org/gcc-4.8/changes.html - args[args.index('-Wpedantic')] = '-pedantic' - return args - - def has_builtin_define(self, define): - return define in self.defines - - def get_builtin_define(self, define): - if define in self.defines: - return self.defines[define] + return '-Wl,--as-needed' def get_pic_args(self): if self.compiler_type.is_osx_compiler or self.compiler_type.is_windows_compiler: @@ -1327,8 +1305,9 @@ class GnuCompiler: def get_buildtype_args(self, buildtype): return gnulike_buildtype_args[buildtype] + @abc.abstractmethod def get_optimization_args(self, optimization_level): - return gnu_optimization_args[optimization_level] + raise NotImplementedError("get_optimization_args not implemented") def get_debug_args(self, is_debug): return clike_debug_args[is_debug] @@ -1338,8 +1317,9 @@ class GnuCompiler: return apple_buildtype_linker_args[buildtype] return gnulike_buildtype_linker_args[buildtype] + @abc.abstractmethod def get_pch_suffix(self): - return 'gch' + raise NotImplementedError("get_pch_suffix not implemented") def split_shlib_to_parts(self, fname): return os.path.dirname(fname), fname @@ -1363,6 +1343,57 @@ class GnuCompiler: return result return ['-Wl,--whole-archive'] + args + ['-Wl,--no-whole-archive'] + def get_instruction_set_args(self, instruction_set): + return gnulike_instruction_set_args.get(instruction_set, None) + + def get_default_include_dirs(self): + return gnulike_default_include_dirs(self.exelist, self.language) + + @abc.abstractmethod + def openmp_flags(self): + raise NotImplementedError("openmp_flags not implemented") + + def gnu_symbol_visibility_args(self, vistype): + return gnu_symbol_visibility_args[vistype] + + +class GnuCompiler(GnuLikeCompiler): + """ + GnuCompiler represents an actual GCC in its many incarnations. + Compilers imitating GCC (Clang/Intel) should use the GnuLikeCompiler ABC. + """ + def __init__(self, compiler_type, defines): + super().__init__(compiler_type) + self.id = 'gcc' + self.defines = defines or {} + self.base_options.append('b_colorout') + + def get_colorout_args(self, colortype): + if mesonlib.version_compare(self.version, '>=4.9.0'): + return gnu_color_args[colortype][:] + return [] + + def get_warn_args(self, level): + args = super().get_warn_args(level) + if mesonlib.version_compare(self.version, '<4.8.0') and '-Wpedantic' in args: + # -Wpedantic was added in 4.8.0 + # https://gcc.gnu.org/gcc-4.8/changes.html + args[args.index('-Wpedantic')] = '-pedantic' + return args + + def has_builtin_define(self, define): + return define in self.defines + + def get_builtin_define(self, define): + if define in self.defines: + return self.defines[define] + + def get_optimization_args(self, optimization_level): + return gnu_optimization_args[optimization_level] + + def get_pch_suffix(self): + return 'gch' + def gen_vs_module_defs_args(self, defsfile): if not isinstance(defsfile, str): raise RuntimeError('Module definitions file should be str') @@ -1378,17 +1409,9 @@ class GnuCompiler: return ['-mwindows'] return [] - def get_instruction_set_args(self, instruction_set): - return gnulike_instruction_set_args.get(instruction_set, None) - - def get_default_include_dirs(self): - return gnulike_default_include_dirs(self.exelist, self.language) - def openmp_flags(self): return ['-fopenmp'] - def gnu_symbol_visibility_args(self, vistype): - return gnu_symbol_visibility_args[vistype] class ElbrusCompiler(GnuCompiler): # Elbrus compiler is nearly like GCC, but does not support @@ -1428,50 +1451,23 @@ class ElbrusCompiler(GnuCompiler): break return paths -class ClangCompiler: + +class ClangCompiler(GnuLikeCompiler): def __init__(self, compiler_type): + super().__init__(compiler_type) self.id = 'clang' - self.compiler_type = compiler_type - self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage', - 'b_ndebug', 'b_staticpic', 'b_colorout'] + self.base_options.append('b_colorout') if self.compiler_type.is_osx_compiler: self.base_options.append('b_bitcode') - else: - self.base_options.append('b_lundef') - self.base_options.append('b_asneeded') - # All Clang backends can do assembly and LLVM IR - self.can_compile_suffixes.update(['ll', 's']) - - # TODO: centralise this policy more globally, instead - # of fragmenting it into GnuCompiler and ClangCompiler - def get_asneeded_args(self): - if self.compiler_type.is_osx_compiler: - return APPLE_LD_AS_NEEDED - else: - return GNU_LD_AS_NEEDED - - def get_pic_args(self): - if self.compiler_type.is_osx_compiler or self.compiler_type.is_windows_compiler: - return [] # On Window and OS X, pic is always on. - return ['-fPIC'] + # All Clang backends can also do LLVM IR + self.can_compile_suffixes.add('ll') def get_colorout_args(self, colortype): return clang_color_args[colortype][:] - def get_buildtype_args(self, buildtype): - return gnulike_buildtype_args[buildtype] - - def get_buildtype_linker_args(self, buildtype): - if self.compiler_type.is_osx_compiler: - return apple_buildtype_linker_args[buildtype] - return gnulike_buildtype_linker_args[buildtype] - def get_optimization_args(self, optimization_level): return clike_optimization_args[optimization_level] - def get_debug_args(self, is_debug): - return clike_debug_args[is_debug] - def get_pch_suffix(self): return 'pch' @@ -1481,9 +1477,6 @@ class ClangCompiler: # so it might change semantics at any time. return ['-include-pch', os.path.join(pch_dir, self.get_pch_name(header))] - def get_soname_args(self, *args): - return get_gcc_soname_args(self.compiler_type, *args) - def has_multi_arguments(self, args, env): myargs = ['-Werror=unknown-warning-option', '-Werror=unused-command-line-argument'] if mesonlib.version_compare(self.version, '>=3.6.0'): @@ -1503,25 +1496,6 @@ class ClangCompiler: extra_args.append('-Wl,-no_weak_imports') return super().has_function(funcname, prefix, env, extra_args, dependencies) - def get_std_shared_module_link_args(self, options): - if self.compiler_type.is_osx_compiler: - return ['-bundle', '-Wl,-undefined,dynamic_lookup'] - return ['-shared'] - - def get_link_whole_for(self, args): - if self.compiler_type.is_osx_compiler: - result = [] - for a in args: - result += ['-Wl,-force_load', a] - return result - return ['-Wl,--whole-archive'] + args + ['-Wl,--no-whole-archive'] - - def get_instruction_set_args(self, instruction_set): - return gnulike_instruction_set_args.get(instruction_set, None) - - def get_default_include_dirs(self): - return gnulike_default_include_dirs(self.exelist, self.language) - def openmp_flags(self): if version_compare(self.version, '>=3.8.0'): return ['-fopenmp'] @@ -1531,8 +1505,6 @@ class ClangCompiler: # Shouldn't work, but it'll be checked explicitly in the OpenMP dependency. return [] - def gnu_symbol_visibility_args(self, vistype): - return gnu_symbol_visibility_args[vistype] class ArmclangCompiler: def __init__(self): @@ -1609,37 +1581,15 @@ class ArmclangCompiler: # Tested on linux for ICC 14.0.3, 15.0.6, 16.0.4, 17.0.1 -class IntelCompiler: +class IntelCompiler(GnuLikeCompiler): def __init__(self, compiler_type): + super().__init__(compiler_type) self.id = 'intel' - self.compiler_type = compiler_type self.lang_header = 'none' - self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage', - 'b_colorout', 'b_ndebug', 'b_staticpic', 'b_asneeded'] - if not self.compiler_type.is_osx_compiler: - self.base_options.append('b_lundef') - # Assembly - self.can_compile_suffixes.add('s') - - def get_pic_args(self): - if self.compiler_type.is_osx_compiler or self.compiler_type.is_windows_compiler: - return [] # On Window and OS X, pic is always on. - return ['-fPIC'] - - def get_buildtype_args(self, buildtype): - return gnulike_buildtype_args[buildtype] - - def get_buildtype_linker_args(self, buildtype): - if self.compiler_type.is_osx_compiler: - return apple_buildtype_linker_args[buildtype] - return gnulike_buildtype_linker_args[buildtype] def get_optimization_args(self, optimization_level): return gnu_optimization_args[optimization_level] - def get_debug_args(self, is_debug): - return clike_debug_args[is_debug] - def get_pch_suffix(self): return 'pchi' @@ -1650,40 +1600,15 @@ class IntelCompiler: def get_pch_name(self, header_name): return os.path.basename(header_name) + '.' + self.get_pch_suffix() - def split_shlib_to_parts(self, fname): - return os.path.dirname(fname), fname - - def get_soname_args(self, *args): - return get_gcc_soname_args(self.compiler_type, *args) - - # TODO: centralise this policy more globally, instead - # of fragmenting it into GnuCompiler and ClangCompiler - def get_asneeded_args(self): - if self.compiler_type.is_osx_compiler: - return APPLE_LD_AS_NEEDED - else: - return GNU_LD_AS_NEEDED - - def get_std_shared_lib_link_args(self): - # FIXME: Don't know how icc works on OSX - # if self.compiler_type.is_osx_compiler: - # return ['-bundle'] - return ['-shared'] - - def get_default_include_dirs(self): - return gnulike_default_include_dirs(self.exelist, self.language) - def openmp_flags(self): if version_compare(self.version, '>=15.0.0'): return ['-qopenmp'] else: return ['-openmp'] - def get_link_whole_for(self, args): - return GnuCompiler.get_link_whole_for(self, args) - - def gnu_symbol_visibility_args(self, vistype): - return gnu_symbol_visibility_args[vistype] + def has_arguments(self, args, env, code, mode): + # -diag-error 10148 is required to catch invalid -W options + return super().has_arguments(args + ['-diag-error', '10006', '-diag-error', '10148'], env, code, mode) class ArmCompiler: diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 6220b9395..c68c529b5 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -301,10 +301,6 @@ class IntelCPPCompiler(IntelCompiler, CPPCompiler): def get_option_link_args(self, options): return [] - def has_arguments(self, args, env, code, mode): - # -diag-error 10148 is required to catch invalid -W options - return super().has_arguments(args + ['-diag-error', '10006', '-diag-error', '10148'], env, code, mode) - class VisualStudioCPPCompiler(VisualStudioCCompiler, CPPCompiler): def __init__(self, exelist, version, is_cross, exe_wrap, is_64):