Skip to content

Commit

Permalink
Factor out invoking compiler to link to a separate class
Browse files Browse the repository at this point in the history
Usually, we invoke a compiler driver for a final link, as it has
knowledge of standard libraries to use etc., but in some cases we use
the linker.

(MSVC embeds 'linker directives' into the output objects which tell the
linker what standard libraries are needed)

Also drop redundant checking of type of vs_module_defs:, it been done in
the interpreter, as it should be, for a while now.

(This is needed because the linker that clang invokes varies depending
on the target, and so requires different syntax)
  • Loading branch information
jon-turney committed Jan 11, 2019
1 parent 7e8f8aa commit 8bac869
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 109 deletions.
91 changes: 24 additions & 67 deletions mesonbuild/compilers/c.py
Expand Up @@ -28,6 +28,7 @@
for_windows, for_darwin, for_cygwin, for_haiku, for_openbsd,
)
from .c_function_attributes import C_FUNC_ATTRIBUTES
from .linker import VisualStudioLinker

from .compilers import (
get_largefile_args,
Expand Down Expand Up @@ -138,7 +139,7 @@ def get_exelist(self):
return self.exelist[:]

def get_linker_exelist(self):
return self.exelist[:]
return self.linker.get_linker_exelist()

def get_preprocess_only_args(self):
return ['-E', '-P']
Expand All @@ -160,7 +161,7 @@ def get_output_args(self, target):
return ['-o', target]

def get_linker_output_args(self, outputname):
return ['-o', outputname]
return self.linker.get_linker_output_args(outputname)

def get_coverage_args(self):
return ['--coverage']
Expand All @@ -182,7 +183,7 @@ def get_include_args(self, path, is_system):
return ['-I' + path]

def get_std_shared_lib_link_args(self):
return ['-shared']
return self.linker.get_std_shared_lib_link_args()

@functools.lru_cache()
def _get_search_dirs(self, env):
Expand Down Expand Up @@ -293,14 +294,6 @@ def gen_export_dynamic_link_args(self, env):
else:
return ['-Wl,-export-dynamic']

def gen_import_library_args(self, implibname):
"""
The name of the outputted import library
This implementation is used only on Windows by compilers that use GNU ld
"""
return ['-Wl,--out-implib=' + implibname]

def sanity_check_impl(self, work_dir, environment, sname, code):
mlog.debug('Sanity testing ' + self.get_display_language() + ' compiler:', ' '.join(self.exelist))
mlog.debug('Is cross compiler: %s.' % str(self.is_cross))
Expand Down Expand Up @@ -1138,6 +1131,12 @@ def get_options(self):
['none', 'c89', 'c99', 'c11',
'gnu89', 'gnu99', 'gnu11'],
'none')})

if self.compiler_type.is_windows_compiler:
opts.update({'c_winlibs': coredata.UserArrayOption('c_winlibs',
'Windows libs to link against.',
gnu_winlibs)})

return opts

def get_option_compile_args(self, options):
Expand All @@ -1148,14 +1147,10 @@ def get_option_compile_args(self, options):
return args

def get_option_link_args(self, options):
return []
return self.linker.get_option_link_args(options)

def get_linker_always_args(self):
basic = super().get_linker_always_args()
if self.compiler_type.is_osx_compiler:
return basic + ['-Wl,-headerpad_max_install_names']
return basic

return self.linker.get_linker_always_args()

class ArmclangCCompiler(ArmclangCompiler, CCompiler):
def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, **kwargs):
Expand Down Expand Up @@ -1214,9 +1209,7 @@ def get_option_compile_args(self, options):
return args

def get_option_link_args(self, options):
if self.compiler_type.is_windows_compiler:
return options['c_winlibs'].value[:]
return []
return self.linker.get_option_link_args(options)

def get_pch_use_args(self, pch_dir, header):
return ['-fpch-preprocess', '-include', os.path.basename(header)]
Expand Down Expand Up @@ -1302,6 +1295,7 @@ def __init__(self, exelist, version, is_cross, exe_wrap, target):
self.base_options = ['b_pch', 'b_ndebug', 'b_vscrt'] # FIXME add lto, pgo and the like
self.target = target
self.is_64 = ('x64' in target) or ('x86_64' in target)
self.linker = VisualStudioLinker(self)

# Override CCompiler.get_always_args
def get_always_args(self):
Expand Down Expand Up @@ -1367,21 +1361,16 @@ def get_dependency_gen_args(self, outtarget, outfile):
return []

def get_linker_exelist(self):
# FIXME, should have same path as compiler.
# FIXME, should be controllable via cross-file.
if self.id == 'clang-cl':
return ['lld-link']
else:
return ['link']
return self.linker.get_linker_exelist()

def get_linker_always_args(self):
return ['/nologo']
return self.linker.get_linker_always_args()

def get_linker_output_args(self, outputname):
return ['/OUT:' + outputname]
return self.linker.get_linker_output_args(outputname)

def get_linker_search_args(self, dirname):
return ['/LIBPATH:' + dirname]
return self.linker.get_linker_search_args(dirname)

def linker_to_compiler_args(self, args):
return ['/link'] + args
Expand All @@ -1401,23 +1390,15 @@ def gen_export_dynamic_link_args(self, env):
return [] # Not applicable with MSVC

def get_std_shared_lib_link_args(self):
return ['/DLL']
return self.linker.get_std_shared_lib_link_args()

def gen_vs_module_defs_args(self, defsfile):
if not isinstance(defsfile, str):
raise RuntimeError('Module definitions file should be str')
# With MSVC, DLLs only export symbols that are explicitly exported,
# so if a module defs file is specified, we use that to export symbols
return ['/DEF:' + defsfile]
return self.linker.gen_vs_module_defs_args(defsfile)

def gen_pch_args(self, header, source, pchname):
objname = os.path.splitext(pchname)[0] + '.obj'
return objname, ['/Yc' + header, '/Fp' + pchname, '/Fo' + objname]

def gen_import_library_args(self, implibname):
"The name of the outputted import library"
return ['/IMPLIB:' + implibname]

def build_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
return []

Expand All @@ -1439,32 +1420,10 @@ def get_options(self):
return opts

def get_option_link_args(self, options):
return options['c_winlibs'].value[:]
return self.linker.get_option_link_args(options)

@classmethod
def unix_args_to_native(cls, args):
result = []
for i in args:
# -mms-bitfields is specific to MinGW-GCC
# -pthread is only valid for GCC
if i in ('-mms-bitfields', '-pthread'):
continue
if i.startswith('-L'):
i = '/LIBPATH:' + i[2:]
# Translate GNU-style -lfoo library name to the import library
elif i.startswith('-l'):
name = i[2:]
if name in cls.ignore_libs:
# With MSVC, these are provided by the C runtime which is
# linked in by default
continue
else:
i = name + '.lib'
# -pthread in link flags is only used on Linux
elif i == '-pthread':
continue
result.append(i)
return result
def unix_args_to_native(self, args):
return self.linker.unix_args_to_native(args)

def get_werror_args(self):
return ['/WX']
Expand Down Expand Up @@ -1516,9 +1475,7 @@ def get_link_debugfile_args(self, targetfile):
return ['/DEBUG', '/PDB:' + '.'.join(pdbarr)]

def get_link_whole_for(self, args):
# Only since VS2015
args = listify(args)
return ['/WHOLEARCHIVE:' + x for x in args]
return self.linker.get_link_whole_for(args)

def get_instruction_set_args(self, instruction_set):
if self.is_64:
Expand Down
41 changes: 12 additions & 29 deletions mesonbuild/compilers/compilers.py
Expand Up @@ -23,6 +23,7 @@
EnvironmentException, MesonException, OrderedSet, version_compare,
Popen_safe
)
from .linker import Linker, ClangLinker

"""This file contains the data files of all compilers Meson knows
about. To support a new compiler, add its information below.
Expand Down Expand Up @@ -852,6 +853,7 @@ def __init__(self, exelist, version, **kwargs):
else:
self.full_version = None
self.base_options = []
self.linker = Linker(self)

def __repr__(self):
repr_str = "<{0}: v{1} `{2}`>"
Expand Down Expand Up @@ -915,17 +917,13 @@ def can_linker_accept_rsp(self):
return mesonlib.is_windows()

def get_linker_always_args(self):
return []
return self.linker.get_linker_always_args()

def get_linker_lib_prefix(self):
return ''

def gen_import_library_args(self, implibname):
"""
Used only on Windows for libraries that need an import library.
This currently means C, C++, Fortran.
"""
return []
return self.linker.gen_import_library_args(implibname)

def get_preproc_flags(self):
if self.get_language() in ('c', 'cpp', 'objc', 'objcpp'):
Expand Down Expand Up @@ -1024,10 +1022,8 @@ def alignment(self, *args, **kwargs):
def has_function(self, *args, **kwargs):
raise EnvironmentException('Language %s does not support function checks.' % self.get_display_language())

@classmethod
def unix_args_to_native(cls, args):
"Always returns a copy that can be independently mutated"
return args[:]
def unix_args_to_native(self, args):
return self.linker.unix_args_to_native(args)

def find_library(self, *args, **kwargs):
raise EnvironmentException('Language {} does not support library finding.'.format(self.get_display_language()))
Expand Down Expand Up @@ -1149,7 +1145,7 @@ def get_std_shared_lib_link_args(self):
return []

def get_std_shared_module_link_args(self, options):
return self.get_std_shared_lib_link_args()
return self.linker.get_std_shared_module_link_args(options)

def get_link_whole_for(self, args):
if isinstance(args, list) and not args:
Expand Down Expand Up @@ -1487,20 +1483,13 @@ def get_soname_args(self, *args):
return get_gcc_soname_args(self.compiler_type, *args)

def get_std_shared_lib_link_args(self):
return ['-shared']
return self.linker.get_std_shared_lib_link_args()

def get_std_shared_module_link_args(self, options):
if self.compiler_type.is_osx_compiler:
return ['-bundle', '-Wl,-undefined,dynamic_lookup']
return ['-shared']
return self.linker.get_std_shared_module_link_args(options)

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']
return self.linker.get_link_whole_for(args)

def get_instruction_set_args(self, instruction_set):
return gnulike_instruction_set_args.get(instruction_set, None)
Expand All @@ -1516,14 +1505,7 @@ def gnu_symbol_visibility_args(self, vistype):
return gnu_symbol_visibility_args[vistype]

def gen_vs_module_defs_args(self, defsfile):
if not isinstance(defsfile, str):
raise RuntimeError('Module definitions file should be str')
# On Windows targets, .def files may be specified on the linker command
# line like an object file.
if self.compiler_type.is_windows_compiler:
return [defsfile]
# For other targets, discard the .def file.
return []
return self.linker.gen_vs_module_defs_args(defsfile)

def get_argument_syntax(self):
return 'gcc'
Expand Down Expand Up @@ -1646,6 +1628,7 @@ def __init__(self, compiler_type):
self.base_options.append('b_bitcode')
# All Clang backends can also do LLVM IR
self.can_compile_suffixes.add('ll')
self.linker = ClangLinker(self)

def get_colorout_args(self, colortype):
return clang_color_args[colortype][:]
Expand Down
3 changes: 0 additions & 3 deletions mesonbuild/compilers/d.py
Expand Up @@ -264,9 +264,6 @@ def get_buildtype_linker_args(self, buildtype):
def get_std_exe_link_args(self):
return []

def gen_import_library_args(self, implibname):
return ['-Wl,--out-implib=' + implibname]

def build_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
if is_windows():
return []
Expand Down

0 comments on commit 8bac869

Please sign in to comment.