Skip to content

Commit 590cb76

Browse files
authored
Merge pull request #6097 from Doekin/cross-qt
Add `qt_host` Option to Enable Cross-Platform Qt Builds Using Host SDK Tools
2 parents 2443dcf + bb89dfc commit 590cb76

File tree

17 files changed

+155
-70
lines changed

17 files changed

+155
-70
lines changed

xmake/modules/detect/sdks/find_qt.lua

+56-9
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,21 @@ function _find_qmake(sdkdir, sdkver)
190190
end
191191

192192
-- get qt environment
193-
function _get_qtenvs(qmake)
193+
function _get_qtenvs(qmake, sdkdir)
194194
local envs = {}
195+
local run_args = {"-query"}
196+
if sdkdir then
197+
local conf_paths = {path.join(sdkdir, "bin", "target_qt.conf"), path.join(sdkdir, "bin", "qt.conf")}
198+
for _, conf_path in ipairs(conf_paths) do
199+
if os.isfile(conf_path) then
200+
table.join2(run_args, {"-qtconf", conf_path})
201+
break
202+
end
203+
end
204+
end
195205
local results = try {
196206
function ()
197-
return os.iorunv(qmake, {"-query"})
207+
return os.iorunv(qmake, run_args)
198208
end,
199209
catch {
200210
function (errors)
@@ -215,24 +225,44 @@ function _get_qtenvs(qmake)
215225
end
216226
end
217227

228+
-- Verify and correct the Qt SDK version for cross-compiling.
229+
-- qmake reports its own version (QT_VERSION), not the version specified in the SDK's configuration files.
230+
function _tryfix_sdkver_for_cross(sdkdir, sdkver)
231+
local qconfig_path = sdkdir and path.join(sdkdir, "mkspecs", "qconfig.pri")
232+
if not sdkver or not os.isfile(qconfig_path) then
233+
return sdkver
234+
end
235+
-- Extract the actual SDK version from qconfig.pri
236+
local qconfig = io.readfile(qconfig_path)
237+
local actual_sdkver = qconfig and qconfig:match("QT_VERSION%s*=%s*(%S+)") -- Expected format: QT_VERSION = x.y.z
238+
if not actual_sdkver then
239+
return sdkver
240+
end
241+
if sdkver ~= actual_sdkver then
242+
wprint("Host Qt SDK version (%s) differs from Target Qt SDK version (%s). To prevent build issues, please ensure both use the same version.", sdkver, actual_sdkver);
243+
end
244+
return actual_sdkver
245+
end
246+
218247
-- find qt sdk toolchains
219-
function _find_qt(sdkdir, sdkver)
248+
function _find_qt(sdkdir, sdkver, sdkdir_host)
220249

221250
-- find qmake
222-
local qmake = _find_qmake(sdkdir, sdkver)
251+
local qmake = _find_qmake(sdkdir_host or sdkdir, sdkver)
223252
if not qmake then
224253
return
225254
end
226255

227256
-- get qt environments
228-
local qtenvs = _get_qtenvs(qmake)
257+
local located_sdkdir = sdkdir and _find_sdkdir(sdkdir, sdkver)
258+
local qtenvs = _get_qtenvs(qmake, located_sdkdir or sdkdir)
229259
if not qtenvs then
230260
return
231261
end
232262

233263
-- get qt toolchains
234264
sdkdir = qtenvs.QT_INSTALL_PREFIX
235-
local sdkver = qtenvs.QT_VERSION
265+
local sdkver = _tryfix_sdkver_for_cross(sdkdir, qtenvs.QT_VERSION)
236266
local bindir = qtenvs.QT_INSTALL_BINS
237267
local libexecdir = qtenvs.QT_INSTALL_LIBEXECS
238268
local qmldir = qtenvs.QT_INSTALL_QML
@@ -259,6 +289,16 @@ function _find_qt(sdkdir, sdkver)
259289
-- TODO
260290
end
261291
end
292+
293+
if sdkdir_host then
294+
local located_sdkdir_host = _find_sdkdir(sdkdir_host, sdkver)
295+
local qtenvs_host = _get_qtenvs(qmake, located_sdkdir_host or sdkdir_host)
296+
if qtenvs_host then
297+
bindir_host = qtenvs_host.QT_HOST_BINS or qtenvs_host.QT_INSTALL_BINS or bindir_host
298+
libexecdir_host = qtenvs_host.QT_HOST_LIBEXECS or qtenvs_host.QT_INSTALL_LIBEXECS or libexecdir_host
299+
end
300+
end
301+
262302
return {sdkdir = sdkdir, bindir = bindir, bindir_host = bindir_host, libexecdir = libexecdir, libexecdir_host = libexecdir_host, libdir = libdir, includedir = includedir, qmldir = qmldir, pluginsdir = pluginsdir, mkspecsdir = mkspecsdir, sdkver = sdkver}
263303
end
264304

@@ -282,13 +322,16 @@ function main(sdkdir, opt)
282322

283323
-- attempt to load cache first
284324
local key = "detect.sdks.find_qt"
285-
local cacheinfo = detectcache:get(key) or {}
325+
local cacheinfo = (sdkdir and detectcache:get2(key, sdkdir)) or detectcache:get(key) or {}
286326
if not opt.force and cacheinfo.qt and cacheinfo.qt.sdkdir and os.isdir(cacheinfo.qt.sdkdir) then
287327
return cacheinfo.qt
288328
end
289329

290330
-- find qt
291-
local qt = _find_qt(sdkdir or config.get("qt") or global.get("qt") or config.get("sdk"), opt.version or config.get("qt_sdkver"))
331+
local sdkdir = sdkdir or config.get("qt") or global.get("qt") or config.get("sdk")
332+
local sdkver = opt.version or config.get("qt_sdkver")
333+
local sdkdir_host = opt.sdkdir_host or config.get("qt_host") or global.get("qt_host")
334+
local qt = _find_qt(sdkdir, sdkver, sdkdir_host)
292335
if qt then
293336

294337
-- save to config
@@ -314,7 +357,11 @@ function main(sdkdir, opt)
314357

315358
-- save to cache
316359
cacheinfo.qt = qt or false
317-
detectcache:set(key, cacheinfo)
360+
if sdkdir then
361+
detectcache:set2(key, sdkdir, cacheinfo)
362+
else
363+
detectcache:set(key, cacheinfo)
364+
end
318365
detectcache:save()
319366
return qt
320367
end

xmake/platforms/bsd/xmake.lua

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ platform("bsd")
3939
, {nil, "cuda", "kv", "auto", "The Cuda SDK Directory" }
4040
, {category = "Qt SDK Configuration" }
4141
, {nil, "qt", "kv", "auto", "The Qt SDK Directory" }
42+
, {nil, "qt_host", "kv", "auto", "The Qt Host SDK Directory" }
4243
, {nil, "qt_sdkver", "kv", "auto", "The Qt SDK Version" }
4344
}
4445

@@ -48,6 +49,7 @@ platform("bsd")
4849
, {nil, "cuda", "kv", "auto", "The Cuda SDK Directory" }
4950
, {category = "Qt SDK Configuration" }
5051
, {nil, "qt", "kv", "auto", "The Qt SDK Directory" }
52+
, {nil, "qt_host", "kv", "auto", "The Qt Host SDK Directory" }
5153
}
5254
}
5355

xmake/platforms/haiku/xmake.lua

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ platform("haiku")
3737
, {nil, "cuda", "kv", "auto", "The Cuda SDK Directory" }
3838
, {category = "Qt SDK Configuration" }
3939
, {nil, "qt", "kv", "auto", "The Qt SDK Directory" }
40+
, {nil, "qt_host", "kv", "auto", "The Qt Host SDK Directory" }
4041
, {nil, "qt_sdkver", "kv", "auto", "The Qt SDK Version" }
4142
}
4243

@@ -46,6 +47,7 @@ platform("haiku")
4647
, {nil, "cuda", "kv", "auto", "The Cuda SDK Directory" }
4748
, {category = "Qt SDK Configuration" }
4849
, {nil, "qt", "kv", "auto", "The Qt SDK Directory" }
50+
, {nil, "qt_host", "kv", "auto", "The Qt Host SDK Directory" }
4951
}
5052
}
5153

xmake/platforms/linux/xmake.lua

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ platform("linux")
3838
, {nil, "cuda", "kv", "auto", "The Cuda SDK Directory" }
3939
, {category = "Qt SDK Configuration" }
4040
, {nil, "qt", "kv", "auto", "The Qt SDK Directory" }
41+
, {nil, "qt_host", "kv", "auto", "The Qt Host SDK Directory" }
4142
, {nil, "qt_sdkver", "kv", "auto", "The Qt SDK Version" }
4243
, {category = "Vcpkg Configuration" }
4344
, {nil, "vcpkg", "kv", "auto", "The Vcpkg Directory" }
@@ -49,6 +50,7 @@ platform("linux")
4950
, {nil, "cuda", "kv", "auto", "The Cuda SDK Directory" }
5051
, {category = "Qt SDK Configuration" }
5152
, {nil, "qt", "kv", "auto", "The Qt SDK Directory" }
53+
, {nil, "qt_host", "kv", "auto", "The Qt Host SDK Directory" }
5254
, {category = "Vcpkg Configuration" }
5355
, {nil, "vcpkg", "kv", "auto", "The Vcpkg Directory" }
5456
}

xmake/platforms/macosx/xmake.lua

+2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ platform("macosx")
4747
, {nil, "cuda", "kv", "auto", "The Cuda SDK Directory" }
4848
, {category = "Qt SDK Configuration" }
4949
, {nil, "qt", "kv", "auto", "The Qt SDK Directory" }
50+
, {nil, "qt_host", "kv", "auto", "The Qt Host SDK Directory" }
5051
, {nil, "qt_sdkver", "kv", "auto", "The Qt SDK Version" }
5152
, {category = "Vcpkg Configuration" }
5253
, {nil, "vcpkg", "kv", "auto", "The Vcpkg Directory" }
@@ -63,6 +64,7 @@ platform("macosx")
6364
, {nil, "cuda", "kv", "auto", "The Cuda SDK Directory" }
6465
, {category = "Qt SDK Configuration" }
6566
, {nil, "qt", "kv", "auto", "The Qt SDK Directory" }
67+
, {nil, "qt_host", "kv", "auto", "The Qt Host SDK Directory" }
6668
, {category = "Vcpkg Configuration" }
6769
, {nil, "vcpkg", "kv", "auto", "The Vcpkg Directory" }
6870
}

xmake/platforms/windows/xmake.lua

+2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ platform("windows")
4747
, {nil, "cuda", "kv", "auto", "The Cuda SDK Directory" }
4848
, {category = "Qt SDK Configuration" }
4949
, {nil, "qt", "kv", "auto", "The Qt SDK Directory" }
50+
, {nil, "qt_host", "kv", "auto", "The Qt Host SDK Directory" }
5051
, {nil, "qt_sdkver", "kv", "auto", "The Qt SDK Version" }
5152
, {category = "WDK Configuration" }
5253
, {nil, "wdk", "kv", "auto", "The WDK Directory" }
@@ -71,6 +72,7 @@ platform("windows")
7172
, {nil, "cuda", "kv", "auto", "The Cuda SDK Directory" }
7273
, {category = "Qt SDK Configuration" }
7374
, {nil, "qt", "kv", "auto", "The Qt SDK Directory" }
75+
, {nil, "qt_host", "kv", "auto", "The Qt Host SDK Directory" }
7476
, {category = "WDK Configuration" }
7577
, {nil, "wdk", "kv", "auto", "The WDK Directory" }
7678
, {category = "Vcpkg Configuration" }

xmake/rules/qt/deploy/android.lua

+12-12
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@ function main(target, opt)
7171
end
7272

7373
-- get androiddeployqt
74-
local androiddeployqt = path.join(qt.bindir, "androiddeployqt" .. (is_host("windows") and ".exe" or ""))
75-
if not os.isexec(androiddeployqt) and qt.bindir_host then
76-
androiddeployqt = path.join(qt.bindir_host, "androiddeployqt" .. (is_host("windows") and ".exe" or ""))
77-
end
74+
local search_dirs = {}
75+
if qt.bindir_host then table.insert(search_dirs, qt.bindir_host) end
76+
if qt.bindir then table.insert(search_dirs, qt.bindir) end
77+
local androiddeployqt = find_file("androiddeployqt" .. (is_host("windows") and ".exe" or ""), search_dirs)
7878
assert(os.isexec(androiddeployqt), "androiddeployqt not found!")
7979

8080
-- get working directory
@@ -152,18 +152,18 @@ function main(target, opt)
152152
settings_file:print(' "target-architecture": "%s",', target_arch)
153153
settings_file:print(' "qml-root-path": "%s",', _escape_path(os.projectdir()))
154154
-- for 6.2.x
155-
local qmlimportscanner = path.join(qt.libexecdir, "qmlimportscanner")
156-
if not os.isexec(qmlimportscanner) and qt.libexecdir_host then
157-
qmlimportscanner = path.join(qt.libexecdir_host, "qmlimportscanner")
158-
end
155+
local search_dirs = {}
156+
if qt.libexecdir_host then table.insert(search_dirs, qt.libexecdir_host) end
157+
if qt.libexecdir then table.insert(search_dirs, qt.libexecdir) end
158+
local qmlimportscanner = find_file("qmlimportscanner" .. (is_host("windows") and ".exe" or ""), search_dirs)
159159
if os.isexec(qmlimportscanner) then
160160
settings_file:print(' "qml-importscanner-binary": "%s",', _escape_path(qmlimportscanner))
161161
end
162162
-- for 6.3.x
163-
local rcc = path.join(qt.bindir, "rcc")
164-
if not os.isexec(rcc) and qt.bindir_host then
165-
rcc = path.join(qt.bindir_host, "rcc")
166-
end
163+
local search_dirs = {}
164+
if qt.bindir_host then table.insert(search_dirs, qt.bindir_host) end
165+
if qt.bindir then table.insert(search_dirs, qt.bindir) end
166+
local rcc = find_file("rcc" .. (is_host("windows") and ".exe" or ""), search_dirs)
167167
if os.isexec(rcc) then
168168
settings_file:print(' "rcc-binary": "%s",', _escape_path(rcc))
169169
end

xmake/rules/qt/deploy/macosx.lua

+5-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import("core.base.option")
2424
import("core.project.config")
2525
import("core.project.depend")
2626
import("core.tool.toolchain")
27+
import("lib.detect.find_file")
2728
import("lib.detect.find_path")
2829
import("detect.sdks.find_qt")
2930
import("utils.progress")
@@ -91,7 +92,10 @@ function main(target, opt)
9192
local qt = assert(find_qt(), "Qt SDK not found!")
9293

9394
-- get macdeployqt
94-
local macdeployqt = path.join(qt.bindir, "macdeployqt")
95+
local search_dirs = {}
96+
if qt.bindir_host then table.insert(search_dirs, qt.bindir_host) end
97+
if qt.bindir then table.insert(search_dirs, qt.bindir) end
98+
local macdeployqt = find_file("macdeployqt" .. (is_host("windows") and ".exe" or ""), search_dirs)
9599
assert(os.isexec(macdeployqt), "macdeployqt not found!")
96100

97101
-- generate target app

xmake/rules/qt/env/xmake.lua

+6-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@ rule("qt.env")
3333

3434
local qmlimportpath = target:values("qt.env.qmlimportpath") or {}
3535
if target:is_plat("windows") or (target:is_plat("mingw") and is_host("windows")) then
36-
target:add("runenvs", "PATH", qt.bindir)
36+
if qt.bindir_host then
37+
target:add("runenvs", "PATH", qt.bindir_host)
38+
end
39+
if qt.bindir then
40+
target:add("runenvs", "PATH", qt.bindir)
41+
end
3742
table.insert(qmlimportpath, qt.qmldir)
3843
-- add targetdir in QML2_IMPORT_PATH in case of the user have qml plugins
3944
table.insert(qmlimportpath, target:targetdir())

xmake/rules/qt/install/mingw.lua

+5-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import("core.base.option")
2323
import("core.project.config")
2424
import("core.tool.toolchain")
2525
import("lib.detect.find_path")
26+
import("lib.detect.find_file")
2627
import("detect.sdks.find_qt")
2728

2829
-- get install directory
@@ -42,7 +43,10 @@ function main(target, opt)
4243
local qt = assert(find_qt(), "Qt SDK not found!")
4344

4445
-- get windeployqt
45-
local windeployqt = path.join(qt.bindir, "windeployqt.exe")
46+
local search_dirs = {}
47+
if qt.bindir_host then table.insert(search_dirs, qt.bindir_host) end
48+
if qt.bindir then table.insert(search_dirs, qt.bindir) end
49+
local windeployqt = find_file("windeployqt" .. (is_host("windows") and ".exe" or ""), search_dirs)
4650
assert(os.isexec(windeployqt), "windeployqt.exe not found!")
4751

4852
-- find qml directory

xmake/rules/qt/install/windows.lua

+13-3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import("core.base.option")
2323
import("core.project.config")
2424
import("core.tool.toolchain")
25+
import("lib.detect.find_file")
2526
import("lib.detect.find_path")
2627
import("detect.sdks.find_qt")
2728

@@ -42,7 +43,10 @@ function main(target, opt)
4243
local qt = assert(find_qt(), "Qt SDK not found!")
4344

4445
-- get windeployqt
45-
local windeployqt = path.join(qt.bindir, "windeployqt.exe")
46+
local search_dirs = {}
47+
if qt.bindir_host then table.insert(search_dirs, qt.bindir_host) end
48+
if qt.bindir then table.insert(search_dirs, qt.bindir) end
49+
local windeployqt = find_file("windeployqt" .. (is_host("windows") and ".exe" or ""), search_dirs)
4650
assert(os.isexec(windeployqt), "windeployqt.exe not found!")
4751

4852
-- find qml directory
@@ -73,9 +77,15 @@ function main(target, opt)
7377
end
7478
-- bind qt bin path
7579
-- https://github.com/xmake-io/xmake/issues/4297
76-
if qt.bindir then
80+
if qt.bindir_host or qt.bindir then
7781
envs = envs or {}
78-
envs.PATH = {qt.bindir}
82+
envs.PATH = {}
83+
if qt.bindir_host then
84+
table.insert(envs.PATH, qt.bindir_host)
85+
end
86+
if qt.bindir then
87+
table.insert(envs.PATH, qt.bindir)
88+
end
7989
local curpath = os.getenv("PATH")
8090
if curpath then
8191
table.join2(envs.PATH, path.splitenv(curpath))

xmake/rules/qt/load.lua

+6-1
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,12 @@ function main(target, opt)
449449
target:add("linkdirs", qt.libdir)
450450
target:add("syslinks", "ws2_32", "gdi32", "ole32", "advapi32", "shell32", "user32", "opengl32", "imm32", "winmm", "iphlpapi")
451451
-- for debugger, https://github.com/xmake-io/xmake-vscode/issues/225
452-
target:add("runenvs", "PATH", qt.bindir)
452+
if qt.bindir_host then
453+
target:add("runenvs", "PATH", qt.bindir_host)
454+
end
455+
if qt.bindir then
456+
target:add("runenvs", "PATH", qt.bindir)
457+
end
453458
elseif target:is_plat("mingw") then
454459
target:set("frameworks", nil)
455460
-- we need to fix it, because gcc maybe does not work on latest mingw when `-isystem D:\a\_temp\msys64\mingw64\include` is passed.

xmake/rules/qt/moc/xmake.lua

+7-7
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,16 @@ rule("qt.moc")
2424
set_extensions(".h", ".hpp")
2525
before_buildcmd_file(function (target, batchcmds, sourcefile, opt)
2626
import("core.tool.compiler")
27+
import("lib.detect.find_file")
2728

2829
-- get moc
2930
local qt = assert(target:data("qt"), "Qt not found!")
30-
local moc = path.join(qt.bindir, is_host("windows") and "moc.exe" or "moc")
31-
if not os.isexec(moc) and qt.libexecdir then
32-
moc = path.join(qt.libexecdir, is_host("windows") and "moc.exe" or "moc")
33-
end
34-
if not os.isexec(moc) and qt.libexecdir_host then
35-
moc = path.join(qt.libexecdir_host, is_host("windows") and "moc.exe" or "moc")
36-
end
31+
local search_dirs = {}
32+
if qt.bindir_host then table.insert(search_dirs, qt.bindir_host) end
33+
if qt.bindir then table.insert(search_dirs, qt.bindir) end
34+
if qt.libexecdir_host then table.insert(search_dirs, qt.libexecdir_host) end
35+
if qt.libexecdir then table.insert(search_dirs, qt.libexecdir) end
36+
local moc = find_file(is_host("windows") and "moc.exe" or "moc", search_dirs)
3737
assert(moc and os.isexec(moc), "moc not found!")
3838

3939
-- get c++ source file for moc

0 commit comments

Comments
 (0)