Get Apple clang version and corresponding upstream LLVM version

前端 未结 9 2150
梦如初夏
梦如初夏 2020-12-05 06:25

I want to understand which version of clang Apple installed in my macbook, to see with c++11 and/or c++14 features are available. I typed this command:

clang         


        
9条回答
  •  悲哀的现实
    2020-12-05 06:38

    First, I want to say that Daniel Frey's answer is absolutely correct; you really should be using __has_feature, __has_extension, etc. when possible. The Clang Language Extensions page documents the different things you can check for, and that should be your go-to solution.

    That said, sometimes you really do need to check the version. For example, sometimes it is necessary to work around compiler bugs which have been fixed in newer versions, or which only appear in newer versions. Sometimes new functionality is added; for example, prior to clang 9 __builtin_constant_p didn't work correctly with the diagnose_if attribute. Sometimes a feature is added but there is no corresponding check.

    I really wish clang would just expose the upstream version numbers as preprocessor macros so we could reliably handle cases like that, but they don't. You could manually create a map of Apple version numbers to upstream, which is what several other answers have proposed, but that has some pretty obvious drawbacks. For me, the fatal flaw is that it doesn't really work for compilers other than Apple clang; there are a lot of compilers based on clang these days (IBM XL C/C++, some newer PGI/NVIDIA compilers, next-gen Intel C/C++, etc.).

    My work-around is to use feature detection macros to estimate a version number. For example, -Wimplicit-const-int-float-conversion was added in clang 11, so if __has_warning("-Wimplicit-const-int-float-conversion") is true we can assume the upstream clang version is >= 11. Similarly, clang 10 added -Wmisleading-indentation, clang 9 started definining the __FILE_NAME__ preprocessor macro, etc.

    I've created a small header which contains the necessary logic. It's public domain (CC0), and even though it is part of one of my projects (SIMDe) it doesn't depend on anything else from any other files, so you're free to steal it for your own projects without copying all of SIMDe.

    Obviously the file needs a new test for each version of clang, so it does require occasional updates if you need to be able to check for newer compilers, so I'd suggest grabbing the latest version from the SIMDe git repository (I'm not likely to keep this answer up to date), but here is what the checks look like right now:

    #if defined(__clang__) && !defined(SIMDE_DETECT_CLANG_VERSION)
    #  if __has_warning("-Wimplicit-const-int-float-conversion")
    #    define SIMDE_DETECT_CLANG_VERSION 110000
    #  elif __has_warning("-Wmisleading-indentation")
    #    define SIMDE_DETECT_CLANG_VERSION 100000
    #  elif defined(__FILE_NAME__)
    #    define SIMDE_DETECT_CLANG_VERSION 90000
    #  elif __has_warning("-Wextra-semi-stmt") || __has_builtin(__builtin_rotateleft32)
    #    define SIMDE_DETECT_CLANG_VERSION 80000
    #  elif __has_warning("-Wc++98-compat-extra-semi")
    #    define SIMDE_DETECT_CLANG_VERSION 70000
    #  elif __has_warning("-Wpragma-pack")
    #    define SIMDE_DETECT_CLANG_VERSION 60000
    #  elif __has_warning("-Wbitfield-enum-conversion")
    #    define SIMDE_DETECT_CLANG_VERSION 50000
    #  elif __has_attribute(diagnose_if)
    #    define SIMDE_DETECT_CLANG_VERSION 40000
    #  elif __has_warning("-Wcast-calling-convention")
    #    define SIMDE_DETECT_CLANG_VERSION 30900
    #  elif __has_warning("-WCL4")
    #    define SIMDE_DETECT_CLANG_VERSION 30800
    #  elif __has_warning("-WIndependentClass-attribute")
    #    define SIMDE_DETECT_CLANG_VERSION 30700
    #  elif __has_warning("-Wambiguous-ellipsis")
    #    define SIMDE_DETECT_CLANG_VERSION 30600
    #  else
    #    define SIMDE_DETECT_CLANG_VERSION 1
    #  endif
    #endif /* defined(__clang__) && !defined(SIMDE_DETECT_CLANG_VERSION) */
    

    I think the biggest problem with this method is actually shared with all other attempts to detect the upstream clang version that I'm aware of: there isn't necessarily a clang release that corresponds to the code in question. As far as I can tell, most compilers based on clang aren't actually based on releases, but rather some random commit (probably whatever is the latest commit for the branch they want to base their work on). That means that, for example, if an issue is was fixed late in the clang $N development cycle, Apple's fork may generally be the same as clang $N but not contain the bug fix. Conversely, maybe Apple will back-port a fix from clang $N+1 and a bug present in clang $N will be fixed in Apple's version.

提交回复
热议问题