Merge pull request #5128 from Ericson2314/sanity-check-with-flags

Sanity check with external args
pull/5196/head
Jussi Pakkanen 6 years ago committed by GitHub
commit 75219989ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 17
      docs/markdown/snippets/sanity-check.md
  2. 51
      mesonbuild/compilers/c.py
  3. 15
      mesonbuild/compilers/fortran.py
  4. 10
      mesonbuild/compilers/objc.py
  5. 13
      mesonbuild/compilers/objcpp.py
  6. 16
      mesonbuild/compilers/swift.py
  7. 21
      mesonbuild/compilers/vala.py
  8. 2
      run_project_tests.py
  9. 9
      run_unittests.py
  10. 2
      test cases/common/177 initial c_args/meson.build
  11. 2
      test cases/common/177 initial c_args/test_args.txt

@ -0,0 +1,17 @@
## Sanity checking compilers with user flags
Sanity checks previously only used user-specified flags for cross compilers, but
now do in all cases.
All compilers meson might decide to use for the build are "sanity checked"
before other tests are run. This usually involves building simple executable and
trying to run it. Previously user flags (compilation and/or linking flags) were
used for sanity checking cross compilers, but not native compilers. This is
because such flags might be essential for a cross binary to succeed, but usually
aren't for a native compiler.
In recent releases, there has been an effort to minimize the special-casing of
cross or native builds so as to make building more predictable in less-tested
cases. Since this the user flags are necessary for cross, but not harmful for
native, it makes more sense to use them in all sanity checks than use them in no
sanity checks, so this is what we now do.

@ -309,9 +309,9 @@ class CCompiler(Compiler):
mlog.debug('Sanity testing ' + self.get_display_language() + ' compiler:', ' '.join(self.exelist))
mlog.debug('Is cross compiler: %s.' % str(self.is_cross))
extra_flags = []
source_name = os.path.join(work_dir, sname)
binname = sname.rsplit('.', 1)[0]
mode = 'link'
if self.is_cross:
binname += '_cross'
if self.exe_wrapper is None:
@ -320,7 +320,9 @@ class CCompiler(Compiler):
# on OSX the compiler binary is the same but you need
# a ton of compiler flags to differentiate between
# arm and x86_64. So just compile.
extra_flags += self.get_compile_only_args()
mode = 'compile'
extra_flags = self._get_basic_compiler_args(environment, mode)
# Is a valid executable output for all toolchains and platforms
binname += '.exe'
# Write binary check source
@ -392,6 +394,29 @@ class CCompiler(Compiler):
return self.compiles(t.format(**fargs), env, extra_args=extra_args,
dependencies=dependencies)
def _get_basic_compiler_args(self, env, mode):
args = []
# Select a CRT if needed since we're linking
if mode == 'link':
args += self.get_linker_debug_crt_args()
if env.is_cross_build() and not self.is_cross:
for_machine = MachineChoice.BUILD
else:
for_machine = MachineChoice.HOST
if mode in {'compile', 'preprocess'}:
# Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS and CPPFLAGS from the env
sys_args = env.coredata.get_external_args(for_machine, self.language)
# Apparently it is a thing to inject linker flags both
# via CFLAGS _and_ LDFLAGS, even though the former are
# also used during linking. These flags can break
# argument checks. Thanks, Autotools.
cleaned_sys_args = self.remove_linkerlike_args(sys_args)
args += cleaned_sys_args
elif mode == 'link':
# Add LDFLAGS from the env
args += env.coredata.get_external_link_args(for_machine, self.language)
return args
def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'):
if extra_args is None:
extra_args = []
@ -415,25 +440,9 @@ class CCompiler(Compiler):
args += d.get_link_args()
if d.need_threads():
args += self.thread_link_flags(env)
# Select a CRT if needed since we're linking
if mode == 'link':
args += self.get_linker_debug_crt_args()
if env.is_cross_build() and not self.is_cross:
for_machine = MachineChoice.BUILD
else:
for_machine = MachineChoice.HOST
if mode in {'compile', 'preprocess'}:
# Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS and CPPFLAGS from the env
sys_args = env.coredata.get_external_args(for_machine, self.language)
# Apparently it is a thing to inject linker flags both
# via CFLAGS _and_ LDFLAGS, even though the former are
# also used during linking. These flags can break
# argument checks. Thanks, Autotools.
cleaned_sys_args = self.remove_linkerlike_args(sys_args)
args += cleaned_sys_args
elif mode == 'link':
# Add LDFLAGS from the env
args += env.coredata.get_external_link_args(for_machine, self.language)
args += self._get_basic_compiler_args(env, mode)
args += self.get_compiler_check_args()
# extra_args must override all other arguments, so we add them last
args += extra_args

@ -31,7 +31,9 @@ from .compilers import (
PGICompiler
)
from mesonbuild.mesonlib import EnvironmentException, is_osx, LibType
from mesonbuild.mesonlib import (
EnvironmentException, MachineChoice, is_osx, LibType
)
class FortranCompiler(Compiler):
@ -79,7 +81,13 @@ class FortranCompiler(Compiler):
binary_name = os.path.join(work_dir, 'sanitycheckf')
with open(source_name, 'w') as ofile:
ofile.write('print *, "Fortran compilation is working."; end')
pc = subprocess.Popen(self.exelist + [source_name, '-o', binary_name])
if environment.is_cross_build() and not self.is_cross:
for_machine = MachineChoice.BUILD
else:
for_machine = MachineChoice.HOST
extra_flags = environment.coredata.get_external_args(for_machine, self.language)
extra_flags += environment.coredata.get_external_link_args(for_machine, self.language)
pc = subprocess.Popen(self.exelist + extra_flags + [source_name, '-o', binary_name])
pc.wait()
if pc.returncode != 0:
raise EnvironmentException('Compiler %s can not compile programs.' % self.name_string())
@ -223,6 +231,9 @@ class FortranCompiler(Compiler):
def gen_import_library_args(self, implibname):
return CCompiler.gen_import_library_args(self, implibname)
def _get_basic_compiler_args(self, env, mode):
return CCompiler._get_basic_compiler_args(self, env, mode)
def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'):
return CCompiler._get_compiler_check_args(self, env, extra_args, dependencies, mode='compile')

@ -14,7 +14,7 @@
import os.path, subprocess
from ..mesonlib import EnvironmentException
from ..mesonlib import EnvironmentException, MachineChoice
from .c import CCompiler
from .compilers import ClangCompiler, GnuCompiler
@ -31,9 +31,15 @@ class ObjCCompiler(CCompiler):
# TODO try to use sanity_check_impl instead of duplicated code
source_name = os.path.join(work_dir, 'sanitycheckobjc.m')
binary_name = os.path.join(work_dir, 'sanitycheckobjc')
extra_flags = []
if environment.is_cross_build() and not self.is_cross:
for_machine = MachineChoice.BUILD
else:
for_machine = MachineChoice.HOST
extra_flags = environment.coredata.get_external_args(for_machine, self.language)
if self.is_cross:
extra_flags += self.get_compile_only_args()
else:
extra_flags += environment.coredata.get_external_link_args(for_machine, self.language)
with open(source_name, 'w') as ofile:
ofile.write('#import<stdio.h>\n'
'int main(int argc, char **argv) { return 0; }\n')

@ -14,7 +14,7 @@
import os.path, subprocess
from ..mesonlib import EnvironmentException
from ..mesonlib import EnvironmentException, MachineChoice
from .cpp import CPPCompiler
from .compilers import ClangCompiler, GnuCompiler
@ -31,11 +31,20 @@ class ObjCPPCompiler(CPPCompiler):
# TODO try to use sanity_check_impl instead of duplicated code
source_name = os.path.join(work_dir, 'sanitycheckobjcpp.mm')
binary_name = os.path.join(work_dir, 'sanitycheckobjcpp')
if environment.is_cross_build() and not self.is_cross:
for_machine = MachineChoice.BUILD
else:
for_machine = MachineChoice.HOST
extra_flags = environment.coredata.get_external_args(for_machine, self.language)
if self.is_cross:
extra_flags += self.get_compile_only_args()
else:
extra_flags += environment.coredata.get_external_link_args(for_machine, self.language)
with open(source_name, 'w') as ofile:
ofile.write('#import<stdio.h>\n'
'class MyClass;'
'int main(int argc, char **argv) { return 0; }\n')
pc = subprocess.Popen(self.exelist + [source_name, '-o', binary_name])
pc = subprocess.Popen(self.exelist + extra_flags + [source_name, '-o', binary_name])
pc.wait()
if pc.returncode != 0:
raise EnvironmentException('ObjC++ compiler %s can not compile programs.' % self.name_string())

@ -14,7 +14,7 @@
import subprocess, os.path
from ..mesonlib import EnvironmentException
from ..mesonlib import EnvironmentException, MachineChoice
from .compilers import Compiler, swift_buildtype_args, clike_debug_args
@ -102,13 +102,25 @@ class SwiftCompiler(Compiler):
src = 'swifttest.swift'
source_name = os.path.join(work_dir, src)
output_name = os.path.join(work_dir, 'swifttest')
if environment.is_cross_build() and not self.is_cross:
for_machine = MachineChoice.BUILD
else:
for_machine = MachineChoice.HOST
extra_flags = environment.coredata.get_external_args(for_machine, self.language)
if self.is_cross:
extra_flags += self.get_compile_only_args()
else:
extra_flags += environment.coredata.get_external_link_args(for_machine, self.language)
with open(source_name, 'w') as ofile:
ofile.write('''print("Swift compilation is working.")
''')
pc = subprocess.Popen(self.exelist + ['-emit-executable', '-o', output_name, src], cwd=work_dir)
pc = subprocess.Popen(self.exelist + extra_flags + ['-emit-executable', '-o', output_name, src], cwd=work_dir)
pc.wait()
if pc.returncode != 0:
raise EnvironmentException('Swift compiler %s can not compile programs.' % self.name_string())
if self.is_cross:
# Can't check if the binaries run so we have to assume they do
return
if subprocess.call(output_name) != 0:
raise EnvironmentException('Executables created by Swift compiler %s are not runnable.' % self.name_string())

@ -15,7 +15,7 @@
import os.path
from .. import mlog
from ..mesonlib import EnvironmentException, version_compare
from ..mesonlib import EnvironmentException, MachineChoice, version_compare
from .compilers import Compiler
@ -87,7 +87,16 @@ class ValaCompiler(Compiler):
def sanity_check(self, work_dir, environment):
code = 'class MesonSanityCheck : Object { }'
with self.compile(code, [], 'compile') as p:
if environment.is_cross_build() and not self.is_cross:
for_machine = MachineChoice.BUILD
else:
for_machine = MachineChoice.HOST
extra_flags = environment.coredata.get_external_args(for_machine, self.language)
if self.is_cross:
extra_flags += self.get_compile_only_args()
else:
extra_flags += environment.coredata.get_external_link_args(for_machine, self.language)
with self.compile(code, extra_flags, 'compile') as p:
if p.returncode != 0:
msg = 'Vala compiler {!r} can not compile programs' \
''.format(self.name_string())
@ -105,8 +114,14 @@ class ValaCompiler(Compiler):
# no extra dirs are specified.
if not extra_dirs:
code = 'class MesonFindLibrary : Object { }'
if env.is_cross_build() and not self.is_cross:
for_machine = MachineChoice.BUILD
else:
for_machine = MachineChoice.HOST
args = env.coredata.get_external_args(for_machine, self.language)
vapi_args = ['--pkg', libname]
with self.compile(code, vapi_args, 'compile') as p:
args += vapi_args
with self.compile(code, args, 'compile') as p:
if p.returncode == 0:
return vapi_args
# Not found? Try to find the vapi file itself.

@ -460,6 +460,7 @@ def have_objc_compiler():
return False
if not objc_comp:
return False
env.coredata.process_new_compilers('objc', objc_comp, None, env)
try:
objc_comp.sanity_check(env.get_scratch_dir(), env)
except mesonlib.MesonException:
@ -475,6 +476,7 @@ def have_objcpp_compiler():
return False
if not objcpp_comp:
return False
env.coredata.process_new_compilers('objcpp', objcpp_comp, None, env)
try:
objcpp_comp.sanity_check(env.get_scratch_dir(), env)
except mesonlib.MesonException:

@ -4373,12 +4373,11 @@ class LinuxlikeTests(BasePlatformTests):
cmd_std = '-std=FAIL'
env_flags = p.upper() + 'FLAGS'
os.environ[env_flags] = cmd_std
with self.assertRaises((subprocess.CalledProcessError, mesonbuild.mesonlib.EnvironmentException),
msg='C compiler should have failed with -std=FAIL'):
self.init(testdir)
cmd = self.get_compdb()[0]['command']
qcmd_std = " {} ".format(cmd_std)
self.assertIn(qcmd_std, cmd)
with self.assertRaises(subprocess.CalledProcessError,
msg='{} should have failed'.format(qcmd_std)):
# ICC won't fail in the above because additional flags are needed to
# make unknown -std=... options errors.
self.build()
def test_compiler_c_stds(self):

@ -3,5 +3,5 @@ project('options', 'c')
# Test passing c_args and c_link_args options from the command line.
assert(get_option('c_args') == ['-funroll-loops'],
'Incorrect value for c_args option.')
assert(get_option('c_link_args') == ['-random_linker_option'],
assert(get_option('c_link_args') == ['-Dtest_harmless_but_useless_link_arg'],
'Incorrect value for c_link_args option.')

@ -1,4 +1,4 @@
# This file is not read by meson itself, but by the test framework.
# It is not possible to pass arguments to meson from a file.
['-Dc_args=-march=native', '-Dc_args=-funroll-loops',
'-Dc_link_args=-random_linker_option']
'-Dc_link_args=-Dtest_harmless_but_useless_link_arg']

Loading…
Cancel
Save