1defineReplace(extractVersion) { return($$replace(1, ^(\\d+\\.\\d+\\.\\d+)(svn|git)?$, \\1)) } 2defineReplace(extractMajorVersion) { return($$replace(1, ^(\\d+)\\.\\d+\\.\\d+(svn|git)?$, \\1)) } 3defineReplace(extractMinorVersion) { return($$replace(1, ^\\d+\\.(\\d+)\\.\\d+(svn|git)?$, \\1)) } 4defineReplace(extractPatchVersion) { return($$replace(1, ^\\d+\\.\\d+\\.(\\d+)(svn|git)?$, \\1)) } 5 6defineTest(versionIsAtLeast) { 7 actual_major_version = $$extractMajorVersion($$1) 8 actual_minor_version = $$extractMinorVersion($$1) 9 actual_patch_version = $$extractPatchVersion($$1) 10 required_min_major_version = $$extractMajorVersion($$2) 11 required_min_minor_version = $$extractMinorVersion($$2) 12 required_min_patch_version = $$extractPatchVersion($$2) 13 14 isEqual(actual_major_version, $$required_min_major_version) { 15 isEqual(actual_minor_version, $$required_min_minor_version) { 16 isEqual(actual_patch_version, $$required_min_patch_version): return(true) 17 greaterThan(actual_patch_version, $$required_min_patch_version): return(true) 18 } 19 greaterThan(actual_minor_version, $$required_min_minor_version): return(true) 20 } 21 greaterThan(actual_major_version, $$required_min_major_version): return(true) 22 23 return(false) 24} 25 26defineReplace(findLLVMVersionFromLibDir) { 27 libdir = $$1 28 version_dirs = $$files($$libdir/clang/*) 29 for (version_dir, version_dirs) { 30 fileName = $$basename(version_dir) 31 version = $$find(fileName, ^(\\d+\\.\\d+\\.\\d+)$) 32 !isEmpty(version) { 33 isEmpty(candidateVersion): candidateVersion = $$version 34 else: versionIsAtLeast($$version, $$candidateVersion): candidateVersion = $$version 35 } 36 } 37 return($$candidateVersion) 38} 39 40defineTest(qtConfTest_libclang) { 41 isEmpty(QDOC_USE_STATIC_LIBCLANG): QDOC_USE_STATIC_LIBCLANG = $$(QDOC_USE_STATIC_LIBCLANG) 42 43 equals(QMAKE_HOST.os, Windows) { 44 # on Windows we have only two host compilers, MSVC or mingw. The former we never 45 # use for cross-compilation where it isn't also the target compiler. The latter 46 # is not detectable as this .prf file is evaluated against the target configuration 47 # and therefore checking for "mingw" won't work when the target compiler is clang (Android) 48 # or qcc (QNX). 49 msvc { 50 isEmpty(LLVM_INSTALL_DIR): LLVM_INSTALL_DIR = $$(LLVM_INSTALL_DIR_MSVC) 51 } else { 52 isEmpty(LLVM_INSTALL_DIR): LLVM_INSTALL_DIR = $$(LLVM_INSTALL_DIR_MINGW) 53 } 54 } 55 isEmpty(LLVM_INSTALL_DIR): LLVM_INSTALL_DIR = $$(LLVM_INSTALL_DIR) 56 57 # Assume libclang is installed on the target system 58 isEmpty(LLVM_INSTALL_DIR) { 59 llvmConfigCandidates = \ 60 llvm-config-10 \ 61 llvm-config-9 \ 62 llvm-config-8 \ 63 llvm-config-7 \ 64 llvm-config-6.0 \ 65 llvm-config-5.0 \ 66 llvm-config-4.0 \ 67 llvm-config-3.9 \ 68 llvm-config 69 70 for (candidate, llvmConfigCandidates) { 71 LLVM_INSTALL_DIR = $$system("$$candidate --prefix 2>$$QMAKE_SYSTEM_NULL_DEVICE") 72 !isEmpty(LLVM_INSTALL_DIR) { 73 CLANG_INCLUDEPATH = $$system("$$candidate --includedir 2>/dev/null") 74 LIBCLANG_MAIN_HEADER = $$CLANG_INCLUDEPATH/clang-c/Index.h 75 !exists($$LIBCLANG_MAIN_HEADER) { 76 !isEmpty(LLVM_INSTALL_DIR): \ 77 qtLog("Cannot find libclang's main header file, candidate: $${LIBCLANG_MAIN_HEADER}.") 78 continue 79 } else { 80 qtLog("QDoc:" \ 81 "Using Clang installation found in $${LLVM_INSTALL_DIR}." \ 82 "Set the LLVM_INSTALL_DIR environment variable to override.") 83 break() 84 } 85 } 86 } 87 } 88 LLVM_INSTALL_DIR = $$clean_path($$LLVM_INSTALL_DIR) 89 90 contains(QMAKE_HOST.arch, x86_64): \ 91 clangInstallDir = $$replace(LLVM_INSTALL_DIR, _ARCH_, 64) 92 else: \ 93 clangInstallDir = $$replace(LLVM_INSTALL_DIR, _ARCH_, 32) 94 isEmpty(LLVM_INSTALL_DIR) { 95 win32 { 96 return(false) 97 } 98 macos { 99 # Default to homebrew llvm on macOS. The CLANG_VERSION test below will complain if missing. 100 clangInstallDir = $$system("brew --prefix llvm") 101 } else { 102 clangInstallDir = /usr 103 } 104 } 105 106 # note: llvm_config only exits on unix 107 llvm_config = $$clangInstallDir/bin/llvm-config 108 exists($$llvm_config) { 109 CLANG_LIBDIR = $$system("$$llvm_config --libdir 2>/dev/null") 110 CLANG_INCLUDEPATH = $$system("$$llvm_config --includedir 2>/dev/null") 111 output = $$system("$$llvm_config --version 2>/dev/null") 112 CLANG_VERSION = $$extractVersion($$output) 113 } else { 114 CLANG_LIBDIR = $$clangInstallDir/lib 115 CLANG_INCLUDEPATH = $$clangInstallDir/include 116 CLANG_VERSION = $$findLLVMVersionFromLibDir($$CLANG_LIBDIR) 117 } 118 isEmpty(CLANG_VERSION) { 119 !isEmpty(LLVM_INSTALL_DIR): \ 120 qtLog("Cannot determine version of clang installation in $${clangInstallDir}.") 121 return(false) 122 } 123 124 LIBCLANG_MAIN_HEADER = $$CLANG_INCLUDEPATH/clang-c/Index.h 125 !exists($$LIBCLANG_MAIN_HEADER) { 126 !isEmpty(LLVM_INSTALL_DIR): \ 127 qtLog("Cannot find libclang's main header file, candidate: $${LIBCLANG_MAIN_HEADER}.") 128 return(false) 129 } 130 131 !contains(QMAKE_DEFAULT_LIBDIRS, $$CLANG_LIBDIR): CLANG_LIBS = -L$${CLANG_LIBDIR} 132 133 CLANG_DEFINES = 134 135 isEmpty(QDOC_USE_STATIC_LIBCLANG) { 136 equals(QMAKE_HOST.os, Windows): \ 137 CLANG_LIBS += -llibclang -ladvapi32 -lshell32 138 else: \ 139 CLANG_LIBS += -lclang 140 } else { 141 win32 { 142 versionIsAtLeast($$CLANG_VERSION, "10.0.0") { 143 CLANG_DEFINES += CINDEX_NO_EXPORTS 144 } else { 145 CLANG_DEFINES += CINDEX_LINKAGE= 146 } 147 } 148 !equals(QMAKE_HOST.os, Darwin):!msvc: CLANG_LIBS+=-Wl,--start-group 149 CLANG_LIBS += -lclangAnalysis \ 150 -lclangARCMigrate \ 151 -lclangAST \ 152 -lclangASTMatchers \ 153 -lclangBasic \ 154 -lclangCodeGen \ 155 -lclangCrossTU \ 156 -lclangDriver \ 157 -lclangDynamicASTMatchers \ 158 -lclangEdit \ 159 -lclangFormat \ 160 -lclangFrontend \ 161 -lclangFrontendTool \ 162 -lclangHandleCXX \ 163 -lclangIndex \ 164 -lclangLex \ 165 -lclangParse \ 166 -lclangRewrite \ 167 -lclangRewriteFrontend \ 168 -lclangSema \ 169 -lclangSerialization \ 170 -lclangStaticAnalyzerCheckers \ 171 -lclangStaticAnalyzerCore \ 172 -lclangStaticAnalyzerFrontend \ 173 -lclangTooling \ 174 -lclangToolingASTDiff \ 175 -lclangToolingCore 176 177 versionIsAtLeast($$CLANG_VERSION, "10.0.0") { 178 equals(QMAKE_HOST.os, Windows): \ 179 CLANG_LIBS += -llibclang 180 else: \ 181 CLANG_LIBS += -lclang 182 183 CLANG_LIBS += -lclangToolingInclusions 184 } else { 185 equals(QMAKE_HOST.os, Windows): \ 186 CLANG_LIBS += -llibclang_static 187 else: \ 188 CLANG_LIBS += -lclang_static 189 190 CLANG_LIBS += \ 191 -lclangApplyReplacements \ 192 -lclangChangeNamespace \ 193 -lclangDaemon \ 194 -lclangIncludeFixer \ 195 -lclangIncludeFixerPlugin \ 196 -lclangMove \ 197 -lclangQuery \ 198 -lclangReorderFields \ 199 -lclangTidy \ 200 -lclangTidyAndroidModule \ 201 -lclangTidyBoostModule \ 202 -lclangTidyBugproneModule \ 203 -lclangTidyCERTModule \ 204 -lclangTidyCppCoreGuidelinesModule \ 205 -lclangTidyFuchsiaModule \ 206 -lclangTidyGoogleModule \ 207 -lclangTidyHICPPModule \ 208 -lclangTidyLLVMModule \ 209 -lclangTidyMiscModule \ 210 -lclangTidyModernizeModule \ 211 -lclangTidyMPIModule \ 212 -lclangTidyObjCModule \ 213 -lclangTidyPerformanceModule \ 214 -lclangTidyPlugin \ 215 -lclangTidyReadabilityModule \ 216 -lclangTidyUtils \ 217 -lclangToolingRefactor \ 218 -lfindAllSymbols 219 } 220 221 msvc { 222 LLVM_LIBS_STRING += $$system("$$llvm_config --libnames") 223 } else { 224 LLVM_LIBS_STRING += $$system("$$llvm_config --libs") 225 } 226 LLVM_LIBS_STRING += $$system("$$llvm_config --system-libs") 227 CLANG_LIBS += $$split(LLVM_LIBS_STRING, " ") 228 229 !equals(QMAKE_HOST.os, Darwin):!msvc: CLANG_LIBS+=-Wl,--end-group 230 equals(QMAKE_HOST.os, Windows): CLANG_LIBS += -lversion 231 } 232 233 !versionIsAtLeast($$CLANG_VERSION, "3.9.0") { 234 log("LLVM/Clang version >= 3.9.0 required, version provided: $${CLANG_VERSION}.$$escape_expand(\\n)") 235 return(false) 236 } 237 238 $${1}.libs = $$CLANG_LIBS 239 export($${1}.libs) 240 $${1}.cache += libs 241 242 $${1}.includepath = $$CLANG_INCLUDEPATH 243 export($${1}.includepath) 244 $${1}.cache += includepath 245 246 $${1}.libdir = $$CLANG_LIBDIR 247 export($${1}.libdir) 248 $${1}.cache += libdir 249 250 $${1}.defines = $$CLANG_DEFINES 251 export($${1}.defines) 252 $${1}.cache += defines 253 254 $${1}.version = $$CLANG_VERSION 255 export($${1}.version) 256 $${1}.cache += version 257 258 export($${1}.cache) 259 260 return(true) 261} 262 263