compilers: unify fortran sanity check with its parent Clike handling

We *mostly* just need to do the same thing. Plug in one utility method
to make sanity_check_impl find the right compile args, and plug in
DEVNULL to the test run. It's that simple.

This solves a few inconsistencies. The main one is that fortran never
logged the sanity checks to the Meson debug log, making it hard to
debug.

There's also some interesting quirks we built up in the dedicated
fortran handling. For example:

- in commit 5b109c9ad2 we added cwd to
  building the fortran executable, with a wordy comment about how the
  compiler has defects. But the clike base has always done that on
  general principle anyway, so we would never have had that bug in the
  first place.

- in commit d6be7822a0 we added special
  deletion of an old "bad existing exe file" just for fortran. Looking
  at the PR discussion for this odd requirement, it turns out that the
  real problem is mixing WSL and native Windows without deleting the
  build directory. This is apparently fortran specific simply because
  "contemporary Windows 10 Fortran users" switch between the two?

  The actual problem is that this never used .exe as the output name, so
  Windows thinks you want to run something other than the thing you
  asked to run, because it's not even a Window executable. But... the
  common clike handling could have fixed that without needing special
  cases.
pull/10842/head
Eli Schwartz 3 years ago committed by Xavier Claessens
parent 332968da1b
commit 30b1774628
  1. 49
      mesonbuild/compilers/fortran.py
  2. 5
      mesonbuild/compilers/mixins/clike.py

@ -13,9 +13,8 @@
# limitations under the License.
from __future__ import annotations
from pathlib import Path
import typing as T
import subprocess, os
import os
from .. import coredata
from .compilers import (
@ -32,7 +31,7 @@ from .mixins.elbrus import ElbrusCompiler
from .mixins.pgi import PGICompiler
from mesonbuild.mesonlib import (
version_compare, EnvironmentException, MesonException,
version_compare, MesonException,
LibType, OptionKey,
)
@ -67,41 +66,15 @@ class FortranCompiler(CLikeCompiler, Compiler):
"meson.get_compiler('fortran').links('block; end block; end program')\n\n"
'that example is to see if the compiler has Fortran 2008 Block element.')
def sanity_check(self, work_dir_: str, environment: 'Environment') -> None:
work_dir = Path(work_dir_)
source_name = work_dir / 'sanitycheckf.f90'
binary_name = work_dir / 'sanitycheckf'
if binary_name.is_file():
binary_name.unlink()
source_name.write_text('program main; print *, "Fortran compilation is working."; end program', encoding='utf-8')
extra_flags: T.List[str] = []
extra_flags += environment.coredata.get_external_args(self.for_machine, self.language)
extra_flags += environment.coredata.get_external_link_args(self.for_machine, self.language)
extra_flags += self.get_always_args()
# %% build the test executable "sanitycheckf"
# cwd=work_dir is necessary on Windows especially for Intel compilers to avoid error: cannot write on sanitycheckf.obj
# this is a defect with how Windows handles files and ifort's object file-writing behavior vis concurrent ProcessPoolExecutor.
# This simple workaround solves the issue.
returncode = subprocess.run(self.exelist + extra_flags + [str(source_name), '-o', str(binary_name)],
cwd=work_dir).returncode
if returncode != 0:
raise EnvironmentException('Compiler %s can not compile programs.' % self.name_string())
if self.is_cross:
if self.exe_wrapper is None:
# Can't check if the binaries run so we have to assume they do
return
cmdlist = self.exe_wrapper.get_command() + [str(binary_name)]
else:
cmdlist = [str(binary_name)]
# %% Run the test executable
try:
returncode = subprocess.run(cmdlist, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode
if returncode != 0:
raise EnvironmentException('Executables created by Fortran compiler %s are not runnable.' % self.name_string())
except OSError:
raise EnvironmentException('Executables created by Fortran compiler %s are not runnable.' % self.name_string())
def _get_basic_compiler_args(self, env: 'Environment', mode: CompileCheckMode) -> T.Tuple[T.List[str], T.List[str]]:
cargs = env.coredata.get_external_args(self.for_machine, self.language)
largs = env.coredata.get_external_link_args(self.for_machine, self.language)
return cargs, largs
def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
source_name = 'sanitycheckf.f90'
code = 'program main; print *, "Fortran compilation is working."; end program\n'
return self._sanity_check_impl(work_dir, environment, source_name, code)
def get_buildtype_args(self, buildtype: str) -> T.List[str]:
return gnulike_buildtype_args[buildtype]

@ -294,7 +294,7 @@ class CLikeCompiler(Compiler):
if self.is_cross:
binname += '_cross'
if self.exe_wrapper is None:
# Linking cross built apps is painful. You can't really
# Linking cross built C/C++ apps is painful. You can't really
# tell if you should use -nostdlib or not and for example
# on OSX the compiler binary is the same but you need
# a ton of compiler flags to differentiate between
@ -332,7 +332,8 @@ class CLikeCompiler(Compiler):
cmdlist = [binary_name]
mlog.debug('Running test binary command: ', mesonlib.join_args(cmdlist))
try:
pe = subprocess.run(cmdlist)
# fortran code writes to stdout
pe = subprocess.run(cmdlist, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
except Exception as e:
raise mesonlib.EnvironmentException(f'Could not invoke sanity test executable: {e!s}.')
if pe.returncode != 0:

Loading…
Cancel
Save