summaryrefslogtreecommitdiff
path: root/xmake/rules/utils/inherit_links/inherit_links.lua
blob: 641104082572ab261a27f91108f10552f181fa76 (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
--!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        inherit_links.lua
--

-- imports
import("private.utils.target", {alias = "target_utils"})

-- @note we cannot directly set `{interface = true}`, because it will overwrite the previous configuration
-- https://github.com/xmake-io/xmake/issues/1465
function _add_export_value(target, name, value)
    local has_private = false
    local private_values = target:get(name)
    if private_values then
        for _, v in ipairs(private_values) do
            if v == value then
                has_private = true
                break
            end
        end
    end
    local extraconf = target:extraconf(name, value)
    if has_private then
        target:add(name, value, table.join(extraconf or {}, {public = true}))
    else
        target:add(name, value, table.join(extraconf or {}, {interface = true}))
    end
end

-- export values as public/interface in target
function _add_export_values(target, name, values)
    for _, value in ipairs(values) do
        _add_export_value(target, name, value)
    end
end

function main(target)

    -- disable inherit.links for `add_deps()`?
    if target:data("inherit.links") == false then
        return
    end

    -- export target links and linkdirs
    if target:is_shared() or target:is_static() then
        local targetfile = target:targetfile()

        -- rust maybe will disable inherit links, only inherit linkdirs
        if target:data("inherit.links.deplink") ~= false then
            -- we need to move target link to head
            _add_export_value(target, "links", target:linkname())
            local links = target:get("links", {rawref = true})
            if links and type(links) == "table" and #links > 1 then
                table.insert(links, 1, links[#links])
                table.remove(links, #links)
            end
        end

        local implibfile = target:artifactfile("implib")
        if implibfile then
            _add_export_value(target, "linkdirs", path.directory(implibfile))
        else
            _add_export_value(target, "linkdirs", path.directory(targetfile))
        end

        if target:rule("go") then
            -- we need to add includedirs to support import modules for golang
            _add_export_value(target, "includedirs", path.directory(targetfile))
        end

        if target:rule("rust") then
            local cratetype = target:values("rust.cratetype")
            -- only bin, lib, rlib, dylib can make use of --extern CRATE[=PATH]
            if cratetype ~= "staticlib" and cratetype ~= "cdylib" then
                _add_export_value(target, "frameworks", target:targetfile())
            end
        end
    end

    -- we export all links and linkdirs in self/packages/options to the parent target by default
    --
    -- @note we only export links for static target,
    -- and we need to pass `{public = true}` to add_packages/add_links/... to export it if want to export links for shared target
    --
    if target:data("inherit.links.exportlinks") ~= false then
        if target:is_static() or target:is_object() then
            local export_values = {"rpathdirs", "frameworkdirs", "frameworks", "syslinks", "shflags"};

            if target:data("inherit.links.export_static") ~= false then
                local link_settings = {"linkdirs", "links", "ldflags"}
                for _, link_setting in ipairs(link_settings) do
                    table.insert(export_values, link_setting)
                end
            end

            for _, name in ipairs(export_values) do
                local values = target_utils.get_values_from_target(target, name)
                if values and #values > 0 then
                    _add_export_values(target, name, values)
                end
            end
        end
    end

    -- export rpathdirs for all shared library
    if target:is_binary() and target:policy("build.rpath") then
        local targetdir = target:targetdir()
        for _, dep in ipairs(target:orderdeps({inherit = true})) do
            if dep:kind() == "shared" then
                local rpathdir = "@loader_path"
                local subdir = path.relative(path.directory(dep:targetfile()), targetdir)
                if subdir and subdir ~= '.' then
                    rpathdir = path.join(rpathdir, subdir)
                end
                target:add("rpathdirs", rpathdir)
            end
        end
    end
end