Skip to content

Commit 822b317

Browse files
committed
Add basic implementation for kit scanner
1 parent 88e07c6 commit 822b317

2 files changed

Lines changed: 182 additions & 0 deletions

File tree

lua/cmake-tools/init.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ local const = require("cmake-tools.const")
55
local Config = require("cmake-tools.config")
66
local variants = require("cmake-tools.variants")
77
local kits = require("cmake-tools.kits")
8+
local scanner = require("cmake-tools.scanner")
89
local Presets = require("cmake-tools.presets")
910
local log = require("cmake-tools.log")
1011
local hints = require("cmake-tools.hints")

lua/cmake-tools/scanner.lua

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
local scanner = {}
2+
-- Configuration
3+
scanner.HOME = os.getenv("HOME") or os.getenv("USERPROFILE")
4+
scanner.KITS_FILE = scanner.HOME .. "/.config/cmake-tools/cmake-kits.json"
5+
6+
--Helper functions
7+
-- Simple JSON encoder
8+
function scanner.json_encode(obj, indent)
9+
indent = indent or 0
10+
local spaces = string.rep(" ", indent)
11+
12+
if type(obj) == "table" then
13+
local is_array = #obj > 0
14+
local result = "{\n"
15+
local first = true
16+
17+
for k, v in pairs(obj) do
18+
if not first then
19+
result = result .. ",\n"
20+
end
21+
first = false
22+
23+
if is_array then
24+
result = result .. spaces .. " " .. scanner.json_encode(v, indent + 1)
25+
else
26+
result = result .. spaces .. ' "' .. k .. '": ' .. scanner.json_encode(v, indent + 1)
27+
end
28+
end
29+
30+
return result .. "\n" .. spaces .. "}"
31+
elseif type(obj) == "string" then
32+
return '"' .. obj:gsub("\\", "\\\\"):gsub('"', '\\"') .. '"'
33+
elseif type(obj) == "number" or type(obj) == "boolean" then
34+
return tostring(obj)
35+
elseif obj == nil then
36+
return "null"
37+
end
38+
end
39+
40+
function scanner.execute_command(cmd)
41+
local handle = io.popen(cmd .. "2>&1")
42+
if handle == nil then
43+
return false, -1, ""
44+
end
45+
local result = handle:read("*a")
46+
if result == nil then
47+
result = ""
48+
end
49+
local success, _, exit_code = handle:close()
50+
if success == nil then
51+
success = false
52+
end
53+
return success, exit_code, result
54+
end
55+
56+
function scanner.file_exists(path)
57+
local file = io.open(path, "r")
58+
if file then
59+
file:close()
60+
return true
61+
else
62+
return false
63+
end
64+
end
65+
66+
function scanner.split_path(path_env)
67+
local paths = {}
68+
local sep = package.config:sub(1, 1) == "\\" and ";" or ":"
69+
for path in string.gmatch(path_env, "([^" .. sep .. "]+)") do
70+
table.insert(paths, path)
71+
end
72+
return paths
73+
end
74+
75+
function scanner.get_gcc_version(gcc_path)
76+
local success, exit_code, output = scanner.execute_command('"' .. gcc_path .. '" --version')
77+
if not success or exit_code ~= 0 then
78+
return nil
79+
end
80+
local version_line = output:match("gcc version ([%d%.]+)")
81+
return version_line
82+
end
83+
84+
function scanner.get_clang_version(clang_path)
85+
local success, exit_code, output = scanner.execute_command('"' .. clang_path .. '" --version')
86+
if not success or exit_code ~= 0 then
87+
return nil
88+
end
89+
local version_line = output:match("clang version ([%d%.]+)")
90+
return version_line
91+
end
92+
93+
function scanner.find_compiler_pair(dir, c_compiler)
94+
local base_name = c_compiler:match("([^/\\]+)$")
95+
local cxx_name
96+
if base_name:match("gcc") then
97+
cxx_name = base_name:gsub("gcc", "g++")
98+
elseif base_name:match("clang") then
99+
cxx_name = base_name:gsub("clang", "clang++")
100+
else
101+
return nil
102+
end
103+
local cxx_path = dir .. "/" .. cxx_name
104+
if scanner.file_exists(cxx_path) then
105+
return cxx_path
106+
end
107+
return nil
108+
end
109+
110+
function scanner.ensure_directory(path)
111+
local lfs = require("lfs")
112+
local pattern = "(.*/)"
113+
local dir = path:match(pattern)
114+
if dir then
115+
lfs.mkdir(dir)
116+
end
117+
end
118+
119+
function scanner.save_kits(kits, filepath)
120+
scanner.ensure_directory(filepath)
121+
local file = io.open(filepath, "w")
122+
if not file then
123+
error("Failed to open file for writing: " .. filepath)
124+
return false
125+
end
126+
local json_content = scanner.json_encode(kits)
127+
file:write(json_content)
128+
file:close()
129+
return true
130+
end
131+
132+
-- Main fucntion to scan for kits
133+
function scanner.scan_for_kits()
134+
local kits = {}
135+
136+
local path_env = os.getenv("PATH") or ""
137+
local paths = scanner.split_path(path_env)
138+
139+
for _, dir in ipairs(paths) do
140+
local gcc_path = dir .. "/gcc"
141+
if scanner.file_exists(gcc_path) then
142+
local gcc_version = scanner.get_gcc_version(gcc_path)
143+
local gxx_path = scanner.find_compiler_pair(dir, gcc_path)
144+
if gxx_path then
145+
local kit = {
146+
name = "GCC " .. (gcc_version or "unknown"),
147+
compilers = {
148+
C = gcc_path,
149+
CXX = gxx_path,
150+
},
151+
}
152+
table.insert(kits, kit)
153+
end
154+
end
155+
156+
local clang_path = dir .. "/clang"
157+
if scanner.file_exists(clang_path) then
158+
local clang_version = scanner.get_clang_version(clang_path)
159+
local clangxx_path = scanner.find_compiler_pair(dir, clang_path)
160+
if clangxx_path then
161+
local kit = {
162+
name = "Clang " .. (clang_version or "unknown"),
163+
compilers = {
164+
C = clang_path,
165+
CXX = clangxx_path,
166+
},
167+
}
168+
table.insert(kits, kit)
169+
end
170+
end
171+
end
172+
173+
if #kits == 0 then
174+
print("No compilers found in PATH.")
175+
return {}
176+
end
177+
scanner.save_kits(kits, scanner.KITS_FILE)
178+
return kits
179+
end
180+
181+
return scanner

0 commit comments

Comments
 (0)