aboutsummaryrefslogtreecommitdiff
path: root/lua/cmake/variants.lua
blob: ce7d8a7fccbc0a08ee83705178131f3401729363 (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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
local config = require("cmake.config")
local utils = require("cmake.utils")

local uv = vim.uv

local VariantConfig = {}

VariantConfig.__index = VariantConfig

local global_variant_subs = {
  ["${workspaceFolder}"] = uv.cwd(),
  ["${userHome}"] = uv.os_homedir(),
}

local _configure_args = function(obj, build_directory)
  local args = {}
  if obj.generator then
    table.insert(args, "-G " .. '"' .. obj.generator .. '"')
  end
  table.insert(args, "-B" .. build_directory)
  if obj.buildType then
    table.insert(args, "-DCMAKE_BUILD_TYPE=" .. obj.buildType)
  end
  if obj.linkage and string.lower(obj.linkage) == "static" then
    table.insert(args, "-DCMAKE_BUILD_SHARED_LIBS=OFF")
  elseif obj.linkage and string.lower(obj.linkage) == "shared" then
    table.insert(args, "-DCMAKE_BUILD_SHARED_LIBS=ON")
  end
  for k, v in pairs(obj.settings or {}) do
    table.insert(args, "-D" .. k .. "=" .. v)
  end
  table.insert(args, "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON")
  return args
end

local _configure_command = function(obj, configure_args)
  local ret = {}
  ret.cmd = config.cmake.cmake_path
  ret.args = table.concat(configure_args, " ")
  ret.env = vim.tbl_deep_extend("keep", obj.env, config.cmake.configure_environment, config.cmake.environment)
  return ret
end

local _build_args = function(obj, build_directory)
  local args = { "--build" }
  table.insert(args, build_directory)
  if config.cmake.parallel_jobs then
    table.insert(args, "-j " .. tostring(config.cmake.parallel_jobs))
  end
  if #obj.buildArgs ~= 0 then
    for _, v in ipairs(obj.buildArgs) do
      table.insert(args, v)
    end
  elseif #config.cmake.build_args ~= 0 then
    for _, v in ipairs(config.cmake.build_args) do
      table.insert(args, v)
    end
  end
  if #obj.buildToolArgs ~= 0 or #config.cmake.build_tool_args ~= 0 then
    table.insert(args, "--")
    if #obj.buildToolArgs ~= 0 then
      for _, v in ipairs(obj.buildToolArgs) do
        table.insert(args, v)
      end
    elseif #config.cmake.build_tool_args ~= 0 then
      for _, v in ipairs(config.cmake.build_tool_args) do
        table.insert(args, v)
      end
    end
  end
  return args
end

local _build_command = function(obj, build_args)
  local ret = {}
  ret.cmd = config.cmake.cmake_path
  ret.args = table.concat(build_args, " ")
  ret.env = vim.tbl_deep_extend("keep", obj.env, config.cmake.configure_environment, config.cmake.environment)
  return ret
end

---Create configuration from variant
---@param source table
---@return CMakeGenerateOption
function VariantConfig:new(source)
  local obj = {}
  local subs = vim.tbl_deep_extend("keep", global_variant_subs, { ["${buildType}"] = source.buildType })

  obj.name = source.short
  obj.long_name = source.long
  obj.directory = utils.substitude(config.cmake.build_directory, subs)
  local configure_args = _configure_args(source, obj.directory)
  obj.generate_command = _configure_command(source, configure_args)
  local build_args = _build_args(source, obj.directory)
  obj.build_options = {
    {
      name = source.short,
      long_name = source.long,
      command = _build_command(source, build_args),
    },
  }

  setmetatable(obj, VariantConfig)
  return obj
end

function VariantConfig.cartesian_product(sets)
  local function collapse_result(res)
    local ret = {
      short = {},
      long = {},
      buildType = nil,
      linkage = nil,
      generator = nil,
      buildArgs = {},
      buildToolArgs = {},
      settings = {},
      env = {},
    }
    local is_default = true
    for _, v in ipairs(res) do
      if not v.default then
        is_default = false
      end
      ret.short[#ret.short + 1] = v.short
      ret.long[#ret.long + 1] = v.long
      ret.buildType = v.buildType or ret.buildType
      ret.linkage = v.linkage or ret.linkage
      ret.generator = v.generator or ret.generator
      ret.buildArgs = v.buildArgs or ret.buildArgs
      ret.buildToolArgs = v.buildToolArgs or ret.buildToolArgs
      for sname, sval in pairs(v.settings or {}) do
        ret.settings[sname] = sval
      end
      for ename, eres in pairs(v.env or {}) do
        ret.env[ename] = eres
      end
    end
    return VariantConfig:new(ret), is_default
  end
  local result = {}
  local set_count = #sets
  local function descend(depth)
    for k, v in pairs(sets[depth].choices) do
      if sets[depth].default ~= k then
        result.default = false
      end
      result[depth] = v
      result[depth].default = (k == sets[depth].default)
      if depth == set_count then
        coroutine.yield(collapse_result(result))
      else
        descend(depth + 1)
      end
    end
  end
  return coroutine.wrap(function()
    descend(1)
  end)
end

return VariantConfig