xmake.lua 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. package("qtbase")
  2. set_kind("template")
  3. set_homepage("https://www.qt.io")
  4. set_description("Qt is the faster, smarter way to create innovative devices, modern UIs & applications for multiple screens. Cross-platform software development at its best.")
  5. set_license("LGPL-3")
  6. add_configs("shared", {description = "Download shared binaries.", default = true, type = "boolean", readonly = true})
  7. add_configs("runtimes", {description = "Set compiler runtimes.", default = "MD", readonly = true})
  8. add_deps("aqt")
  9. on_load(function (package)
  10. package:addenv("PATH", "bin")
  11. end)
  12. on_fetch(function (package, opt)
  13. import("core.base.semver")
  14. import("detect.sdks.find_qt")
  15. local qt = package:data("qt")
  16. if qt then
  17. return qt
  18. end
  19. local sdkdir
  20. if not opt.system then
  21. sdkdir = package:installdir()
  22. end
  23. local qt = find_qt(sdkdir, {force = opt.force})
  24. if not qt then
  25. return
  26. end
  27. local qtversion = semver.new(qt.sdkver)
  28. if not qtversion:ge(package:version()) then
  29. return
  30. end
  31. qt.version = qt.sdkver
  32. package:data_set("qt", qt)
  33. return qt
  34. end)
  35. on_install(function (package)
  36. import("core.base.semver")
  37. import("core.project.config")
  38. import("core.tool.toolchain")
  39. local version = package:version()
  40. local versionstr = version:shortstr()
  41. local host
  42. if is_host("windows") or package:is_plat("mingw") then
  43. host = "windows"
  44. elseif is_host("linux") then
  45. host = "linux"
  46. elseif is_host("macosx") then
  47. host = "mac"
  48. else
  49. raise("unhandled host " .. os.host())
  50. end
  51. local target
  52. if package:is_plat("windows", "mingw", "linux", "macosx") then
  53. target = "desktop"
  54. elseif package:is_plat("android") then
  55. target = "android"
  56. elseif package:is_plat("iphoneos") then
  57. target = "ios"
  58. else
  59. raise("unhandled plat " .. package:plat())
  60. end
  61. local arch
  62. if package:is_plat("windows", "mingw") then
  63. local winarch
  64. if package:is_arch("x64", "x86_64", "arm64") then
  65. winarch = "64"
  66. elseif version:lt("6.0") and package:is_arch("x86", "i386") then -- 32bits support was removed in Qt6
  67. winarch = "32"
  68. else
  69. raise("unhandled arch " .. package:targetarch())
  70. end
  71. local compiler_version
  72. if package:is_plat("windows") then
  73. local vs = package:toolchain("msvc"):config("vs")
  74. if version:ge("6.8") then
  75. compiler_version = "msvc2022"
  76. elseif tonumber(vs) >= 2019 or version:ge("6.0") then
  77. compiler_version = "msvc2019"
  78. elseif vs == "2017" or vs == "2015" then
  79. compiler_version = "msvc" .. vs
  80. else
  81. raise("unhandled msvc version " .. vs)
  82. end
  83. if package:is_arch("x64", "x86_64") then
  84. compiler_version = compiler_version .. "_64"
  85. elseif package:is_arch("arm64") then -- arm64 support was added in Qt6.2
  86. compiler_version = compiler_version .. "_arm64"
  87. end
  88. else
  89. local cc = package:tool("cc")
  90. local ccversion = os.iorunv(cc, {"-dumpversion"}):trim()
  91. local mingw_version = semver.new(ccversion)
  92. if version:ge("6.2.2") then
  93. compiler_version = "mingw"
  94. elseif mingw_version:ge("8.1") then
  95. compiler_version = "mingw81"
  96. elseif mingw_version:ge("7.3") then
  97. compiler_version = "mingw73"
  98. elseif mingw_version:ge("5.3") then
  99. compiler_version = "mingw53"
  100. else
  101. raise("unhandled mingw version " .. version)
  102. end
  103. end
  104. arch = "win" .. winarch .. "_" .. compiler_version
  105. elseif package:is_plat("linux") then
  106. if version:ge("6.7.0") then
  107. arch = "linux_gcc_64"
  108. else
  109. arch = "gcc_64"
  110. end
  111. elseif package:is_plat("macosx") then
  112. arch = "clang_64"
  113. elseif package:is_plat("android") then
  114. if version:le("5.13") or version:ge("6.0") then
  115. if package:is_arch("x86_64", "x64") then
  116. arch = "android_x86_64"
  117. elseif package:is_arch("arm64", "arm64-v8a") then
  118. arch = "android_arm64_v8a"
  119. elseif package:is_arch("armv7", "armv7-a", "armeabi", "armeabi-v7a") then
  120. arch = "android_armv7"
  121. elseif package:is_arch("x86") then
  122. arch = "android_x86"
  123. else
  124. raise("unhandled arch " .. package:targetarch())
  125. end
  126. else
  127. arch = "android"
  128. end
  129. end
  130. local installdir = package:installdir()
  131. os.vrunv("aqt", {"install-qt", "-O", installdir, host, target, versionstr, arch})
  132. -- move files to root
  133. os.mv(path.join(installdir, versionstr, "*", "*"), installdir)
  134. os.rmdir(path.join(installdir, versionstr))
  135. -- special case for cross-compilation since we need binaries we can run on the host
  136. if package:is_cross() then
  137. local runhost
  138. if is_host("windows") then
  139. runhost = "windows"
  140. elseif is_host("linux") then
  141. runhost = "linux"
  142. elseif is_host("macosx") then
  143. runhost = "mac"
  144. else
  145. raise("unhandled host " .. os.host())
  146. end
  147. local hostarch
  148. if is_host("windows") then
  149. local winarch
  150. if os.arch():find("64", 1, true) then
  151. winarch = "64"
  152. else
  153. winarch = "32"
  154. end
  155. local compiler_version
  156. local vs = package:toolchain("msvc"):config("vs")
  157. if version:ge("6.8") then
  158. compiler_version = "msvc2022"
  159. elseif tonumber(vs) >= 2019 or version:ge("6.0") then
  160. compiler_version = "msvc2019"
  161. elseif vs == "2017" or vs == "2015" then
  162. compiler_version = "msvc" .. vs
  163. else
  164. raise("unhandled msvc version " .. vs)
  165. end
  166. if os.arch() == "x64" then
  167. compiler_version = compiler_version .. "_64"
  168. elseif os.arch() == "arm64" then
  169. compiler_version = compiler_version .. "_arm64"
  170. end
  171. hostarch = "win" .. winarch .. "_" .. compiler_version
  172. elseif is_host("linux") then
  173. if version:ge("6.7.0") then
  174. arch = "linux_gcc_64"
  175. else
  176. arch = "gcc_64"
  177. end
  178. elseif is_host("macosx") then
  179. hostarch = "clang_64"
  180. end
  181. -- download qtbase to bin_host folder
  182. os.vrunv("aqt", {"install-qt", "-O", path.join(installdir, "bin_host"), runhost, "desktop", versionstr, hostarch})
  183. -- add symbolic links for useful tools
  184. local tool_folders = {}
  185. if version:ge("6.0") then
  186. tool_folders.bin = {
  187. qmake = true,
  188. qmake6 = true
  189. }
  190. tool_folders.libexec = {
  191. moc = true,
  192. rcc = true,
  193. uic = true
  194. }
  195. else
  196. tool_folders.bin = {
  197. qmake = true,
  198. moc = true,
  199. rcc = true,
  200. uic = true
  201. }
  202. end
  203. for folder, tools in pairs(tool_folders) do
  204. for _, file in ipairs(os.files(path.join(installdir, "bin_host", versionstr, "*", folder, "*"))) do
  205. local filename = path.filename(file)
  206. if tools[filename] then
  207. local targetpath = path.join(installdir, folder, filename)
  208. os.rm(targetpath)
  209. if is_host("windows") then
  210. os.cp(file, targetpath)
  211. else
  212. os.ln(file, targetpath)
  213. end
  214. -- some tools like CMake will try to run moc.exe even on Linux, trick them (ln bin/moc.exe => bin_host/bin/moc)
  215. if package:is_plat("mingw") then
  216. os.rm(targetpath .. ".exe")
  217. if is_host("windows") then
  218. os.cp(file, targetpath .. ".exe")
  219. else
  220. os.ln(file, targetpath .. ".exe")
  221. end
  222. end
  223. end
  224. end
  225. end
  226. end
  227. end)
  228. on_test(function (package)
  229. local qt = assert(package:data("qt"))
  230. local function getbin(name)
  231. if is_host("windows") then
  232. name = name .. ".exe"
  233. end
  234. local exec = path.join(qt.bindir, name)
  235. if not os.isexec(exec) and qt.libexecdir then
  236. exec = path.join(qt.libexecdir, name)
  237. end
  238. if not os.isexec(exec) and qt.libexecdir_host then
  239. exec = path.join(qt.libexecdir_host, name)
  240. end
  241. assert(os.isexec(exec), name .. " not found!")
  242. return exec
  243. end
  244. os.vrun(getbin("qmake") .. " -v")
  245. os.vrun(getbin("moc") .. " -v")
  246. -- rcc -v and uic -v seems to hang CI forever
  247. --os.vrun(getbin("rcc") .. " -v") -- rcc -v hangs CI
  248. --os.vrun(getbin("uic") .. " -v") -- uic -v seems to hang on CI
  249. end)