From fca2f7be8c8950355726f11431195a47da4b6042 Mon Sep 17 00:00:00 2001 From: Meagan Lang Date: Wed, 22 May 2024 21:57:04 -0400 Subject: [PATCH] Added missing aliases for clang linker Handle case where gcc/g++ is actually clang Catch tool errors in CompiledModelDriver and raise NotImplementedError to match ModelDriver --- tests/drivers/test_ModelDriver.py | 4 +++ yggdrasil/drivers/CModelDriver.py | 39 ++++++++++++++++++++---- yggdrasil/drivers/CPPModelDriver.py | 8 ++++- yggdrasil/drivers/CompiledModelDriver.py | 28 ++++++++++------- 4 files changed, 61 insertions(+), 18 deletions(-) diff --git a/tests/drivers/test_ModelDriver.py b/tests/drivers/test_ModelDriver.py index 4d07d95f8..cbad912d1 100644 --- a/tests/drivers/test_ModelDriver.py +++ b/tests/drivers/test_ModelDriver.py @@ -22,6 +22,10 @@ def test_ModelDriver_implementation(): ModelDriver.is_library_installed(None) with pytest.raises(InvalidCompilationTool): CompiledModelDriver.get_tool('compiler') + with pytest.raises(NotImplementedError): + CompiledModelDriver.language_executable() + with pytest.raises(NotImplementedError): + CompiledModelDriver.executable_command(None) with pytest.raises(NotImplementedError): InterpretedModelDriver.get_interpreter() diff --git a/yggdrasil/drivers/CModelDriver.py b/yggdrasil/drivers/CModelDriver.py index 8426b02de..614e669ae 100755 --- a/yggdrasil/drivers/CModelDriver.py +++ b/yggdrasil/drivers/CModelDriver.py @@ -10,7 +10,7 @@ from yggdrasil import platform, tools, constants, rapidjson from yggdrasil.drivers.CompiledModelDriver import ( CompiledModelDriver, CompilerBase, LinkerBase, ArchiverBase, - _osx_sysroot) + _osx_sysroot, InvalidCompilationTool) from yggdrasil.languages import get_language_dir logger = logging.getLogger(__name__) if platform._is_win: @@ -103,6 +103,22 @@ class GCCCompiler(CCompilerBase): 'specialization': 'with_asan'}, } + @classmethod + def is_clang(cls): + r"""Determine if this tool is actually an alias for clang. + + Returns: + bool: True if gcc actually points to clang. + + """ + if platform._is_mac: + try: + ver = cls.tool_version() + return ('clang' in ver) + except InvalidCompilationTool: + pass + return False + @classmethod def is_installed(cls): r"""Determine if this tool is installed by looking for the executable. @@ -113,10 +129,8 @@ def is_installed(cls): """ out = super(GCCCompiler, cls).is_installed() # Disable gcc when it is an alias for clang - if out and platform._is_mac: # pragma: debug - ver = cls.tool_version() - if 'clang' in ver: - out = False + if out and cls.is_clang(): # pragma: debug + out = False return out @classmethod @@ -160,6 +174,16 @@ class ClangCompiler(CCompilerBase): 'specialization': 'with_asan'}, } + @staticmethod + def before_registration(cls): + r"""Operations that should be performed to modify class attributes prior + to registration including things like platform dependent properties and + checking environment variables for default settings. + """ + if GCCCompiler.is_clang() and 'gcc' not in cls.aliases: + cls.aliases.append('gcc') + CCompilerBase.before_registration(cls) + @classmethod def get_flags(cls, *args, **kwargs): r"""Get a list of compiler flags.""" @@ -255,7 +279,10 @@ class GCCLinker(LDLinker): class ClangLinker(LDLinker): r"""Interface class for clang linker (calls to ld).""" toolname = ClangCompiler.toolname - aliases = ClangCompiler.aliases + aliases = ClangCompiler.aliases + ( + [os.path.basename(ClangCompiler.default_executable).replace( + ClangCompiler.toolname, 'ld')] + if ClangCompiler.default_executable else []) languages = ClangCompiler.languages platforms = ClangCompiler.platforms default_executable = ClangCompiler.default_executable diff --git a/yggdrasil/drivers/CPPModelDriver.py b/yggdrasil/drivers/CPPModelDriver.py index 1f6a809c8..e4a158f8d 100644 --- a/yggdrasil/drivers/CPPModelDriver.py +++ b/yggdrasil/drivers/CPPModelDriver.py @@ -1,3 +1,4 @@ +import os import logging from yggdrasil import platform from yggdrasil.drivers.CModelDriver import ( @@ -95,6 +96,8 @@ def before_registration(cls): """ if platform._is_win: # pragma: windows cls.default_executable = 'clang' + if GPPCompiler.is_clang() and 'g++' not in cls.aliases: + cls.aliases.append('g++') CPPCompilerBase.before_registration(cls) @classmethod @@ -174,7 +177,10 @@ class GPPLinker(GCCLinker): class ClangPPLinker(ClangLinker): r"""Interface class for clang++ linker (calls to ld).""" toolname = ClangPPCompiler.toolname - aliases = ClangPPCompiler.aliases + aliases = ClangPPCompiler.aliases + ( + [os.path.basename(ClangCompiler.default_executable).replace( + ClangCompiler.toolname, 'ld')] + if ClangCompiler.default_executable else []) languages = ClangPPCompiler.languages default_executable = ClangPPCompiler.default_executable toolset = ClangPPCompiler.toolset diff --git a/yggdrasil/drivers/CompiledModelDriver.py b/yggdrasil/drivers/CompiledModelDriver.py index e07c52b56..ffcabb748 100644 --- a/yggdrasil/drivers/CompiledModelDriver.py +++ b/yggdrasil/drivers/CompiledModelDriver.py @@ -6479,7 +6479,10 @@ def language_executable(cls, toolname=None): to run the compiler/interpreter from the command line. """ - return cls.get_tool('basetool', toolname=toolname).get_executable() + try: + return cls.get_tool('basetool', toolname=toolname).get_executable() + except InvalidCompilationTool as e: + raise NotImplementedError(e) @classmethod def language_version(cls, toolname=None, **kwargs): @@ -6541,16 +6544,19 @@ def executable_command(cls, args, exec_type='compiler', toolname=None, ValueError: If exec_type is not 'compiler', 'linker', or 'direct'. """ - if exec_type == 'direct': - unused_kwargs = kwargs.pop('unused_kwargs', {}) - unused_kwargs.update(kwargs) - return args - elif exec_type == 'linker': - exec_cls = cls.get_tool('linker', toolname=toolname) - elif exec_type == 'compiler': - exec_cls = cls.get_tool('compiler', toolname=toolname) - else: - raise ValueError("Invalid exec_type '%s'" % exec_type) + try: + if exec_type == 'direct': + unused_kwargs = kwargs.pop('unused_kwargs', {}) + unused_kwargs.update(kwargs) + return args + elif exec_type == 'linker': + exec_cls = cls.get_tool('linker', toolname=toolname) + elif exec_type == 'compiler': + exec_cls = cls.get_tool('compiler', toolname=toolname) + else: + raise ValueError("Invalid exec_type '%s'" % exec_type) + except InvalidCompilationTool as e: + raise NotImplementedError(e) return exec_cls.get_executable_command(args, **kwargs) @classmethod