summaryrefslogtreecommitdiff
path: root/xmake/rules/utils/symbols/extract/xmake.lua
blob: 92abd3df313af630c520d8d523bf3eea81ea893c (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
134
135
136
137
--!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
--

-- define rule: utils.symbols.extract
rule("utils.symbols.extract")
    after_config(function(target)

        -- need generate symbols?
        local strip = target:get("strip")
        local symbols = table.wrap(target:get("symbols"))
        if table.contains(symbols, "debug") and (strip == "all" or strip == "debug")
            and not target:is_plat("windows") -- we need not to strip pdb for windows, https://github.com/xmake-io/xmake/issues/6554
            and (target:is_binary() or target:is_shared()) and target:tool("strip") then -- only for strip command
            target:data_set("utils.symbols.extract", true)
            target:set("strip", "none") -- disable strip in link stage, because we need to run separate strip commands
            target:data_set("strip.origin", strip)
        else
            target:rule_enable("utils.symbols.extract", false)
        end
    end)
    after_link(function (target, opt)

        -- need generate symbols?
        if not target:data("utils.symbols.extract") then
            return
        end

        -- imports
        import("core.base.option")
        import("core.theme.theme")
        import("core.project.depend")
        import("core.platform.platform")
        import("utils.progress")

        -- get strip
        local strip = target:tool("strip")
        if not strip then
            return
        end

        -- get dsymutil and objcopy
        local dsymutil, objcopy
        if target:is_plat("macosx", "iphoneos", "watchos") then
            dsymutil = target:tool("dsymutil")
            if not dsymutil then
                return
            end
        else
            objcopy = target:tool("objcopy")
        end

        -- @note we use dependfile(targetfile) as sourcefile/mtime instead of targetfile to ensure it's mtime less than mtime(symbolfile), because targetfile will be changed after stripping
        local targetfile = target:targetfile()
        local symbolfile = target:symbolfile()
        local dryrun = option.get("dry-run")
        depend.on_changed(function ()

            -- trace progress info
            progress.show(opt.progress, "${color.build.target}generating.$(mode) %s", path.filename(symbolfile))

            -- we remove the previous symbol file to ensure that it will be re-generated and it's mtime will be changed.
            if not dryrun then
                os.tryrm(symbolfile)
            end

            -- generate symbols file
            if dsymutil then
                local dsymutil_argv = {}
                local arch = target:arch()
                if arch then
                    table.insert(dsymutil_argv, "-arch")
                    table.insert(dsymutil_argv, arch)
                end
                table.insert(dsymutil_argv, targetfile)
                table.insert(dsymutil_argv, "-o")
                table.insert(dsymutil_argv, symbolfile)
                os.vrunv(dsymutil, dsymutil_argv, {dryrun = dryrun})
            else
                -- @see https://github.com/xmake-io/xmake/issues/4684
                if objcopy then
                    os.vrunv(objcopy, {"--only-keep-debug", targetfile, symbolfile}, {dryrun = dryrun})
                elseif not dryrun then
                    os.vcp(targetfile, symbolfile)
                end
            end

            -- strip it
            local strip_argv = {}
            if target:is_plat("macosx", "iphoneos", "watchos") and not strip:find("llvm-strip", 1, true) then
                -- do not support `-s`, we can only strip debug symbols
                local arch = target:arch()
                if arch then
                    table.insert(strip_argv, "-arch")
                    table.insert(strip_argv, arch)
                end
                table.insert(strip_argv, "-S")
            else
                -- -s/--strip-all for gnu strip
                local strip = target:data("strip.origin")
                if strip == "debug" then
                    table.insert(strip_argv, "-S")
                else
                    table.insert(strip_argv, "-s")
                end
            end
            table.insert(strip_argv, targetfile)
            os.vrunv(strip, strip_argv, {dryrun = dryrun})

            -- attach symbolfile to targetfile
            if not target:is_plat("macosx", "iphoneos", "watchos") and objcopy then
                -- @see https://github.com/xmake-io/xmake/issues/4684
                os.vrunv(objcopy, {"--add-gnu-debuglink=" .. symbolfile, targetfile}, {dryrun = dryrun})
            end

        end, {dependfile = target:dependfile(symbolfile),
              files = target:dependfile(targetfile),
              changed = target:is_rebuilt(),
              dryrun = dryrun})
    end)