Fix MSVC /link argument ordering (#5598)

* correct handling of LDFLAGS in find_library and sanity_check on MSVC (fixes #3629)

The MSVC compiler requires all linker flags to be placed after the compiler flags, separated by a "/link" argument. This was already handled for regular linking commands, but not yet for the aforementioned special code paths.

* on MSVC, add /link separator between compiler and linker flags when it is missing

* avoid unnecessary /link argument
pull/5591/head
Norbert Nemec 5 years ago committed by Jussi Pakkanen
parent 19cda6b7c9
commit 555847f20f
  1. 51
      mesonbuild/compilers/clike.py

@ -255,7 +255,8 @@ class CLikeCompiler:
# a ton of compiler flags to differentiate between # a ton of compiler flags to differentiate between
# arm and x86_64. So just compile. # arm and x86_64. So just compile.
mode = 'compile' mode = 'compile'
extra_flags = self._get_basic_compiler_args(environment, mode) cargs, largs = self._get_basic_compiler_args(environment, mode)
extra_flags = cargs + self.linker_to_compiler_args(largs)
# Is a valid executable output for all toolchains and platforms # Is a valid executable output for all toolchains and platforms
binname += '.exe' binname += '.exe'
@ -264,7 +265,9 @@ class CLikeCompiler:
with open(source_name, 'w') as ofile: with open(source_name, 'w') as ofile:
ofile.write(code) ofile.write(code)
# Compile sanity check # Compile sanity check
cmdlist = self.exelist + extra_flags + [source_name] + self.get_output_args(binary_name) # NOTE: extra_flags must be added at the end. On MSVC, it might contain a '/link' argument
# after which all further arguments will be passed directly to the linker
cmdlist = self.exelist + [source_name] + self.get_output_args(binary_name) + extra_flags
pc, stdo, stde = mesonlib.Popen_safe(cmdlist, cwd=work_dir) pc, stdo, stde = mesonlib.Popen_safe(cmdlist, cwd=work_dir)
mlog.debug('Sanity check compiler command line:', ' '.join(cmdlist)) mlog.debug('Sanity check compiler command line:', ' '.join(cmdlist))
mlog.debug('Sanity check compile stdout:') mlog.debug('Sanity check compile stdout:')
@ -329,10 +332,10 @@ class CLikeCompiler:
dependencies=dependencies) dependencies=dependencies)
def _get_basic_compiler_args(self, env, mode): def _get_basic_compiler_args(self, env, mode):
args = [] cargs, largs = [], []
# Select a CRT if needed since we're linking # Select a CRT if needed since we're linking
if mode == 'link': if mode == 'link':
args += self.get_linker_debug_crt_args() cargs += self.get_linker_debug_crt_args()
# Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS and CPPFLAGS from the env # Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS and CPPFLAGS from the env
sys_args = env.coredata.get_external_args(self.for_machine, self.language) sys_args = env.coredata.get_external_args(self.for_machine, self.language)
@ -341,17 +344,17 @@ class CLikeCompiler:
# also used during linking. These flags can break # also used during linking. These flags can break
# argument checks. Thanks, Autotools. # argument checks. Thanks, Autotools.
cleaned_sys_args = self.remove_linkerlike_args(sys_args) cleaned_sys_args = self.remove_linkerlike_args(sys_args)
args += cleaned_sys_args cargs += cleaned_sys_args
if mode == 'link': if mode == 'link':
# Add LDFLAGS from the env # Add LDFLAGS from the env
sys_ld_args = env.coredata.get_external_link_args(self.for_machine, self.language) sys_ld_args = env.coredata.get_external_link_args(self.for_machine, self.language)
# CFLAGS and CXXFLAGS go to both linking and compiling, but we want them # CFLAGS and CXXFLAGS go to both linking and compiling, but we want them
# to only appear on the command line once. Remove dupes. # to only appear on the command line once. Remove dupes.
args += [x for x in sys_ld_args if x not in sys_args] largs += [x for x in sys_ld_args if x not in sys_args]
args += self.get_compiler_args_for_mode(mode) cargs += self.get_compiler_args_for_mode(mode)
return args return cargs, largs
def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'): def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'):
if extra_args is None: if extra_args is None:
@ -365,19 +368,27 @@ class CLikeCompiler:
elif not isinstance(dependencies, list): elif not isinstance(dependencies, list):
dependencies = [dependencies] dependencies = [dependencies]
# Collect compiler arguments # Collect compiler arguments
args = compilers.CompilerArgs(self) cargs = compilers.CompilerArgs(self)
largs = []
for d in dependencies: for d in dependencies:
# Add compile flags needed by dependencies # Add compile flags needed by dependencies
args += d.get_compile_args() cargs += d.get_compile_args()
if mode == 'link': if mode == 'link':
# Add link flags needed to find dependencies # Add link flags needed to find dependencies
args += d.get_link_args() largs += d.get_link_args()
ca, la = self._get_basic_compiler_args(env, mode)
cargs += ca
largs += la
cargs += self.get_compiler_check_args()
args += self._get_basic_compiler_args(env, mode) # on MSVC compiler and linker flags must be separated by the "/link" argument
# at this point, the '/link' argument may already be part of extra_args, otherwise, it is added here
if self.linker_to_compiler_args([]) == ['/link'] and largs != [] and not ('/link' in extra_args):
extra_args += ['/link']
args += self.get_compiler_check_args() args = cargs + extra_args + largs
# extra_args must override all other arguments, so we add them last
args += extra_args
return args return args
def compiles(self, code, env, *, extra_args=None, dependencies=None, mode='compile', disable_cache=False): def compiles(self, code, env, *, extra_args=None, dependencies=None, mode='compile', disable_cache=False):
@ -964,10 +975,12 @@ class CLikeCompiler:
# search for .a. This is only allowed if libtype is LibType.PREFER_SHARED # search for .a. This is only allowed if libtype is LibType.PREFER_SHARED
if ((not extra_dirs and libtype is LibType.PREFER_SHARED) or if ((not extra_dirs and libtype is LibType.PREFER_SHARED) or
libname in self.internal_libs): libname in self.internal_libs):
args = ['-l' + libname] cargs = ['-l' + libname]
largs = self.linker_to_compiler_args(self.get_allow_undefined_link_args()) largs = self.get_allow_undefined_link_args()
if self.links(code, env, extra_args=(args + largs), disable_cache=True)[0]: extra_args = cargs + self.linker_to_compiler_args(largs)
return args
if self.links(code, env, extra_args=extra_args, disable_cache=True)[0]:
return cargs
# Don't do a manual search for internal libs # Don't do a manual search for internal libs
if libname in self.internal_libs: if libname in self.internal_libs:
return None return None

Loading…
Cancel
Save