summaryrefslogtreecommitdiff
path: root/xmake/rules/qt/moc/xmake.lua
blob: 509770576fcb388f840d26e9edb0230e3af99810 (plain)
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)