From 30b17746280d34fae71714ef6081e4a5a33c70a7 Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Tue, 20 Sep 2022 22:53:40 -0400 Subject: 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 5b109c9ad27aea39ce49d1da8ef0c957ccaef3b9 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 d6be7822a0a7391c9d2a22c053cd4fc61b5a71e4 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. --- mesonbuild/compilers/fortran.py | 49 ++++++++---------------------------- mesonbuild/compilers/mixins/clike.py | 5 ++-- 2 files changed, 14 insertions(+), 40 deletions(-) diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index 263b46b..af9d1e7 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.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] diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index d1a3ba2..87f5dcf 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -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: -- cgit v1.1