1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
--!A cross-platform build utility based on Lua
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- Copyright (C) 2015-present, Xmake Open Source Community.
--
-- @author ruki
-- @file xmake.lua
--
rule("qt.moc")
add_deps("qt.env")
add_orders("qt.ui", "qt.moc")
set_extensions(".h", ".hpp")
on_config(function (target)
import("lib.detect.find_file")
-- get qt
local qt = assert(target:data("qt"), "Qt not found!")
-- get moc
local search_dirs = {}
if qt.bindir_host then table.insert(search_dirs, qt.bindir_host) end
if qt.bindir then table.insert(search_dirs, qt.bindir) end
if qt.libexecdir_host then table.insert(search_dirs, qt.libexecdir_host) end
if qt.libexecdir then table.insert(search_dirs, qt.libexecdir) end
local moc = find_file(is_host("windows") and "moc.exe" or "moc", search_dirs)
assert(moc and os.isexec(moc), "moc not found!")
-- save moc
target:data_set("qt.moc", moc)
end)
before_buildcmd_file(function (target, batchcmds, sourcefile, opt)
import("core.tool.compiler")
local moc = target:data("qt.moc")
-- get c++ source file for moc
--
-- add_files("mainwindow.h") -> moc_MainWindow.cpp
-- add_files("mainwindow.cpp", {rules = "qt.moc"}) -> mainwindow.moc, @see https://github.com/xmake-io/xmake/issues/750
--
local basename = path.basename(sourcefile)
local filename_moc = "moc_" .. basename .. ".cpp"
if sourcefile:endswith(".cpp") then
filename_moc = basename .. ".moc"
end
-- we need to retain the file directory structure, @see https://github.com/xmake-io/xmake/issues/2343
local sourcefile_moc = target:autogenfile(path.join(path.directory(sourcefile), filename_moc))
-- add objectfile
local objectfile = target:objectfile(sourcefile_moc)
table.insert(target:objectfiles(), objectfile)
-- add commands
batchcmds:show_progress(opt.progress, "${color.build.object}compiling.qt.moc %s", sourcefile)
-- get values from target
-- @see https://github.com/xmake-io/xmake/issues/3930
local function _get_values_from_target(target, name)
local values = {}
for _, value in ipairs((target:get_from(name, "*"))) do
table.join2(values, value)
end
return table.unique(values)
end
-- generate c++ source file for moc
local flags = {}
table.join2(flags, compiler.map_flags("cxx", "define", _get_values_from_target(target, "defines")))
local pathmaps = {
{"includedirs", "includedir"},
{"sysincludedirs", "includedir"}, -- for now, moc process doesn't support MSVC external includes flags and will fail
{"frameworkdirs", "frameworkdir"}
}
for _, pathmap in ipairs(pathmaps) do
for _, item in ipairs(_get_values_from_target(target, pathmap[1])) do
local item = item
local pathitem = path(item, function (p)
local item = table.unwrap(compiler.map_flags("cxx", pathmap[2], p))
if item then
-- we always need use '/' to fix it for project generator, because it will use path.translate in cl.lua
item = item:gsub("\\", "/")
end
return item
end)
if not pathitem:empty() then
table.insert(flags, pathitem)
end
end
end
local user_flags = target:get("qt.moc.flags") or {}
batchcmds:mkdir(path.directory(sourcefile_moc))
batchcmds:vrunv(moc, table.join(user_flags, flags, path(sourcefile), "-o", path(sourcefile_moc)))
-- we need to compile this moc_xxx.cpp file if exists Q_PRIVATE_SLOT, @see https://github.com/xmake-io/xmake/issues/750
local mocdata = io.readfile(sourcefile)
if mocdata and mocdata:find("Q_PRIVATE_SLOT") or sourcefile_moc:endswith(".moc") then
-- add includedirs of sourcefile_moc
target:add("includedirs", path.directory(sourcefile_moc))
-- remove the object file of sourcefile_moc
local objectfiles = target:objectfiles()
for idx, objectfile in ipairs(objectfiles) do
if objectfile == target:objectfile(sourcefile_moc) then
table.remove(objectfiles, idx)
break
end
end
batchcmds:set_depmtime(os.mtime(sourcefile_moc))
batchcmds:set_depcache(target:dependfile(sourcefile_moc))
else
-- compile c++ source file for moc
batchcmds:compile(sourcefile_moc, objectfile)
batchcmds:set_depmtime(os.mtime(objectfile))
batchcmds:set_depcache(target:dependfile(objectfile))
end
-- add deps
batchcmds:add_depfiles(sourcefile)
end)
|