summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2026-01-04 22:34:55 +0800
committerGitHub <[email protected]>2026-01-04 22:34:55 +0800
commit5631b98caa40ad06994f983a7c2a500be4b0e2b2 (patch)
tree1c2df51151ec76c4ee5af6ad231523be62a583f6
parentc24679f43a3fae814cf8e807a3756eb67b1d75dc (diff)
parent8ff9ac175a2ee4e4a994b571e585f610c86de5c3 (diff)
Merge pull request #7178 from 24bit-xjkp/dev
refactor(rules/verilator): Switch from cmake to json format for Verilator build file parsing
-rw-r--r--xmake/rules/verilator/verilator.lua218
1 files changed, 150 insertions, 68 deletions
diff --git a/xmake/rules/verilator/verilator.lua b/xmake/rules/verilator/verilator.lua
index 2867d1e09..4631c5886 100644
--- a/xmake/rules/verilator/verilator.lua
+++ b/xmake/rules/verilator/verilator.lua
@@ -22,7 +22,9 @@
import("utils.progress")
import("core.base.hashset")
import("core.project.depend")
-import("private.action.build.object", {alias = "build_objectfiles"})
+import("private.action.build.object", { alias = "build_objectfiles" })
+import("core.base.json")
+import("lib.detect.find_tool")
-- parse sourcefiles from cmakefile
function _get_sourcefiles_from_cmake(target, cmakefile)
@@ -33,7 +35,7 @@ function _get_sourcefiles_from_cmake(target, cmakefile)
local supportfiles_fast = {}
local targetname = target:name()
local verilator_root = assert(target:data("verilator.root"), "no verilator_root!")
- io.gsub(cmakefile, "set%((%S-) (.-)%)", function (key, values)
+ io.gsub(cmakefile, "set%((%S-) (.-)%)", function(key, values)
if key == targetname .. "_GLOBAL" then
-- get global class source files
-- set(hello_GLOBAL "${VERILATOR_ROOT}/include/verilated.cpp" "${VERILATOR_ROOT}/include/verilated_threads.cpp")
@@ -63,14 +65,31 @@ function _get_sourcefiles_from_cmake(target, cmakefile)
end)
-- get compiled source files
- local sourcefiles = table.join(global_classes, classefiles_slow, classefiles_fast, supportfiles_slow, supportfiles_fast)
+ local sourcefiles = table.join(global_classes, classefiles_slow, classefiles_fast, supportfiles_slow,
+ supportfiles_fast)
+ return sourcefiles
+end
+
+-- parse sourcefiles from jsonfile
+function _get_sourcefiles_from_json(jsonfile)
+ local json_table = json.loadfile(jsonfile)
+ local sources_table = assert(json_table["sources"], "No sources field found in json file: %s.", jsonfile)
+ local global_classes = sources_table["global"] or {}
+ local classefiles_slow = sources_table["classes_slow"] or {}
+ local classefiles_fast = sources_table["classes_fast"] or {}
+ local supportfiles_slow = sources_table["support_slow"] or {}
+ local supportfiles_fast = sources_table["support_fast"] or {}
+
+ -- get compiled source files
+ local sourcefiles = table.join(global_classes, classefiles_slow, classefiles_fast, supportfiles_slow,
+ supportfiles_fast)
return sourcefiles
end
-- get languages
--
-- Select the Verilog language generation to support in the compiler.
--- This selects between v1364-1995, v1364-2001, v1364-2005, v1800-2005, v1800-2009, v1800-2012.
+-- This selects between v1364-1995, v1364-2001, v1364-2005, v1800-2005, v1800-2009, v1800-2012, v1800-2017, v1800-2023.
--
function _get_lanuage_flags(target)
local language_v
@@ -94,6 +113,7 @@ function _get_lanuage_flags(target)
["v1800-2009"] = "+1800-2009ext+v",
["v1800-2012"] = "+1800-2012ext+v",
["v1800-2017"] = "+1800-2017ext+v",
+ ["v1800-2023"] = "+1800-2023ext+v",
}
local flag = maps[language_v]
if flag then
@@ -104,16 +124,27 @@ function _get_lanuage_flags(target)
end
end
+function _get_makefile_type(verilator)
+ local tool = assert(find_tool("verilator", { program = verilator, version = true }), "verilator not found!")
+ local version = tool.version
+ local support_json = version >= "5.036"
+ local makefile_type = support_json and "json" or "cmake"
+ return support_json, makefile_type
+end
+
function config(target)
- local toolchain = assert(target:toolchain("verilator"), 'we need to set_toolchains("verilator") in target("%s")', target:name())
+ local toolchain = assert(target:toolchain("verilator"), 'we need to set_toolchains("verilator") in target("%s")',
+ target:name())
local verilator = assert(toolchain:config("verilator"), "verilator not found!")
+ local support_json, makefile_type = _get_makefile_type(verilator)
local autogendir = path.join(target:autogendir(), "rules", "verilator")
local tmpdir = os.tmpfile() .. ".dir"
- local cmakefile = path.join(tmpdir, "test.cmake")
+ local makefile = path.join(tmpdir, "test." .. makefile_type)
local sourcefile = path.join(tmpdir, "main.v")
- local argv = {"--cc", "--make", "cmake", "--prefix", "test", "--Mdir", tmpdir, "main.v"}
+ local argv = { "--cc", "--make", makefile_type, "--prefix", "test", "--Mdir", tmpdir, "main.v" }
local flags = target:values("verilator.flags")
- local switches_flags = hashset.of( "sc", "coverage", "timing", "trace", "trace-fst", "threads")
+ local switches_flags = hashset.of("sc", "coverage", "timing", "trace", "trace-vcd", "trace-fst", "trace-saif",
+ "threads")
if flags then
for idx, flag in ipairs(flags) do
if flag:startswith("--") and switches_flags:has(flag:sub(3)) then
@@ -134,39 +165,55 @@ endmodule]])
os.mkdir(tmpdir)
-- we just pass relative sourcefile path to solve this issue on windows.
-- @see https://github.com/verilator/verilator/issues/3873
- os.runv(verilator, argv, {curdir = tmpdir, envs = toolchain:runenvs()})
+ os.runv(verilator, argv, { curdir = tmpdir, envs = toolchain:runenvs() })
- -- parse some configurations from cmakefile
+ -- parse some configurations from makefile
local verilator_root
local switches = {}
- local targetname = target:name()
- io.gsub(cmakefile, "set%((%S-) (.-)%)", function (key, values)
- if key == "VERILATOR_ROOT" then
- verilator_root = values:match("\"(.-)\" CACHE PATH")
- if not verilator_root then
- verilator_root = values:match("(.-) CACHE PATH")
+ local options_table = {}
+
+ if support_json then
+ local json_table = json.loadfile(makefile)
+ local system_table = assert(json_table["system"], "No system field found in json file: %s.", makefile)
+ verilator_root = system_table["verilator_root"]
+ options_table = assert(json_table["options"], "No options field found in json file: %s.", makefile)
+ switches.SC = options_table["system_c"] and "1" or "0"
+ switches.COVERAGE = options_table["coverage"] and "1" or "0"
+ switches.TIMING = options_table["use_timing"] and "1" or "0"
+ -- The thread field is a integer in float format, we need to convert it to string.
+ switches.THREADS = string.format("%d", options_table["threads"] or 1)
+ switches.TRACE_VCD = options_table["trace_vcd"] and "1" or "0"
+ switches.TRACE_FST = options_table["trace_fst"] and "1" or "0"
+ switches.TRACE_SAIF = options_table["trace_saif"] and "1" or "0"
+ else
+ io.gsub(makefile, "set%((%S-) (.-)%)", function(key, values)
+ if key == "VERILATOR_ROOT" then
+ verilator_root = values:match("\"(.-)\" CACHE PATH")
+ if not verilator_root then
+ verilator_root = values:match("(.-) CACHE PATH")
+ end
+ elseif key == "test_SC" then
+ -- SystemC output mode? 0/1 (from --sc)
+ switches.SC = values:trim()
+ elseif key == "test_COVERAGE" then
+ -- Coverage output mode? 0/1 (from --coverage)
+ switches.COVERAGE = values:trim()
+ elseif key == "test_TIMING" then
+ -- Timing mode? 0/1 (from --timing)
+ switches.TIMING = values:trim()
+ elseif key == "test_THREADS" then
+ -- Threaded output mode? 1/N threads (from --threads)
+ switches.THREADS = values:trim()
+ elseif key == "test_TRACE_VCD" then
+ -- VCD Tracing output mode? 0/1 (from --trace)
+ switches.TRACE_VCD = values:trim()
+ elseif key == "test_TRACE_FST" then
+ -- FST Tracing output mode? 0/1 (from --trace-fst)
+ switches.TRACE_FST = values:trim()
end
- elseif key == "test_SC" then
- -- SystemC output mode? 0/1 (from --sc)
- switches.SC = values:trim()
- elseif key == "test_COVERAGE" then
- -- Coverage output mode? 0/1 (from --coverage)
- switches.COVERAGE = values:trim()
- elseif key == "test_TIMING" then
- -- Timing mode? 0/1 (from --timing)
- switches.TIMING = values:trim()
- elseif key == "test_THREADS" then
- -- Threaded output mode? 1/N threads (from --threads)
- switches.THREADS = values:trim()
- elseif key == "test_TRACE_VCD" then
- -- VCD Tracing output mode? 0/1 (from --trace)
- switches.TRACE_VCD = values:trim()
- elseif key == "test_TRACE_FST" then
- -- FST Tracing output mode? 0/1 (from --trace-fst)
- switches.TRACE_FST = values:trim()
- end
+ end)
+ end
- end)
assert(verilator_root, "the verilator root directory not found!")
target:data_set("verilator.root", verilator_root)
@@ -174,49 +221,68 @@ endmodule]])
if not os.isfile(autogendir) then
os.mkdir(autogendir)
end
- target:add("includedirs", autogendir, {public = true})
- target:add("includedirs", path.join(verilator_root, "include"), {public = true})
- target:add("includedirs", path.join(verilator_root, "include", "vltstd"), {public = true})
+ target:add("includedirs", autogendir, { public = true })
+ target:add("includedirs", path.join(verilator_root, "include"), { public = true })
+ target:add("includedirs", path.join(verilator_root, "include", "vltstd"), { public = true })
-- set languages
local languages = target:get("languages")
local cxxlang = false
for _, lang in ipairs(languages) do
- if lang:startswith("xx") or lang:startswith("++") then
+ if lang:find("xx", 1, true) or lang:find("++", 1, true) then
cxxlang = true
break
end
end
if not cxxlang then
- target:add("languages", "c++20", {public = true})
+ target:add("languages", "c++20", { public = true })
end
-- add definitions for switches
for k, v in table.orderpairs(switches) do
- target:add("defines", "VM_" .. k .. "=" .. v, {public = true})
+ target:add("defines", "VM_" .. k .. "=" .. v, { public = true })
+ end
+ if support_json then
+ local cflags = options_table["cflags"] or {}
+ for _, flag in ipairs(cflags) do
+ if flag:startswith("-D") then
+ target:add("defines", flag:sub(3), { public = true })
+ end
+ end
end
-- add syslinks
- if target:is_plat("linux", "macosx") and switches.THREADS == "1" then
- target:add("syslinks", "pthread")
- end
- if target:is_plat("linux", "macosx") and switches.TRACE_FST == "1" then
- target:add("syslinks", "z")
+ if support_json then
+ local ldflags = options_table["ldflags"] or {}
+ for _, flag in ipairs(ldflags) do
+ if flag:startswith("-l") then
+ target:add("syslinks", flag:sub(3))
+ end
+ end
+ else
+ if target:is_plat("linux", "macosx") and switches.THREADS == "1" then
+ target:add("syslinks", "pthread")
+ end
+ if target:is_plat("linux", "macosx") and switches.TRACE_FST == "1" then
+ target:add("syslinks", "z")
+ end
end
os.rm(tmpdir)
end
function build_cppfiles(target, jobgraph, sourcebatch, opt)
- local toolchain = assert(target:toolchain("verilator"), 'we need to set_toolchains("verilator") in target("%s")', target:name())
+ local toolchain = assert(target:toolchain("verilator"), 'we need to set_toolchains("verilator") in target("%s")',
+ target:name())
local verilator = assert(toolchain:config("verilator"), "verilator not found!")
+ local support_json, makefile_type = _get_makefile_type(verilator)
local autogendir = path.join(target:autogendir(), "rules", "verilator")
local targetname = target:name()
- local cmakefile = path.join(autogendir, targetname .. ".cmake")
+ local makefile = path.join(autogendir, targetname .. "." .. makefile_type)
-- build verilog files
depend.on_changed(function()
- local argv = {"--cc", "--make", "cmake", "--prefix", targetname, "--Mdir", autogendir}
+ local argv = { "--cc", "--make", makefile_type, "--prefix", targetname, "--Mdir", autogendir }
local flags = target:values("verilator.flags")
if flags then
table.join2(argv, flags)
@@ -237,15 +303,21 @@ function build_cppfiles(target, jobgraph, sourcebatch, opt)
end
-- generate c++ sourcefiles
- os.vrunv(verilator, argv, {envs = toolchain:runenvs()})
-
- end, {dependfile = cmakefile .. ".d",
- files = sourcebatch.sourcefiles,
- changed = target:is_rebuilt(),
- lastmtime = os.mtime(cmakefile)})
+ os.vrunv(verilator, argv, { envs = toolchain:runenvs() })
+ end, {
+ dependfile = makefile .. ".d",
+ files = sourcebatch.sourcefiles,
+ changed = target:is_rebuilt(),
+ lastmtime = os.mtime(makefile)
+ })
-- get compiled source files
- local sourcefiles = _get_sourcefiles_from_cmake(target, cmakefile)
+ local sourcefiles
+ if support_json then
+ sourcefiles = _get_sourcefiles_from_json(makefile)
+ else
+ sourcefiles = _get_sourcefiles_from_cmake(target, makefile)
+ end
-- do build
local sourcebatch_cpp = {
@@ -253,7 +325,8 @@ function build_cppfiles(target, jobgraph, sourcebatch, opt)
sourcekind = "cxx",
sourcefiles = sourcefiles,
objectfiles = {},
- dependfiles = {}}
+ dependfiles = {}
+ }
for _, sourcefile in ipairs(sourcefiles) do
local objectfile = target:objectfile(sourcefile)
local dependfile = target:dependfile(objectfile)
@@ -265,14 +338,16 @@ function build_cppfiles(target, jobgraph, sourcebatch, opt)
end
function buildcmd_vfiles(target, batchcmds, sourcebatch, opt)
- local toolchain = assert(target:toolchain("verilator"), 'we need to set_toolchains("verilator") in target("%s")', target:name())
+ local toolchain = assert(target:toolchain("verilator"), 'we need to set_toolchains("verilator") in target("%s")',
+ target:name())
local verilator = assert(toolchain:config("verilator"), "verilator not found!")
+ local _, makefile_type = _get_makefile_type(verilator)
local autogendir = path.join(target:autogendir(), "rules", "verilator")
local targetname = target:name()
- local cmakefile = path.join(autogendir, targetname .. ".cmake")
- local dependfile = cmakefile .. ".d"
+ local makefile = path.join(autogendir, targetname .. "." .. makefile_type)
+ local dependfile = makefile .. ".d"
- local argv = {"--cc", "--make", "cmake", "--prefix", targetname, "--Mdir", path(autogendir)}
+ local argv = { "--cc", "--make", makefile_type, "--prefix", targetname, "--Mdir", path(autogendir) }
local flags = target:values("verilator.flags")
if flags then
table.join2(argv, flags)
@@ -284,7 +359,7 @@ function buildcmd_vfiles(target, batchcmds, sourcebatch, opt)
local sourcefiles = sourcebatch.sourcefiles
for _, sourcefile in ipairs(sourcefiles) do
batchcmds:show_progress(opt.progress, "${color.build.object}compiling.verilog %s", sourcefile)
- table.insert(argv, path(sourcefile, function (v)
+ table.insert(argv, path(sourcefile, function(v)
-- we need to use slashes to fix it on windows
-- @see https://github.com/verilator/verilator/issues/3873
if is_host("windows") then
@@ -295,22 +370,29 @@ function buildcmd_vfiles(target, batchcmds, sourcebatch, opt)
end
-- generate c++ sourcefiles
- batchcmds:vrunv(verilator, argv, {envs = toolchain:runenvs()})
+ batchcmds:vrunv(verilator, argv, { envs = toolchain:runenvs() })
batchcmds:add_depfiles(sourcefiles)
- batchcmds:set_depmtime(os.mtime(cmakefile))
+ batchcmds:set_depmtime(os.mtime(makefile))
batchcmds:set_depcache(dependfile)
end
function buildcmd_cppfiles(target, batchcmds, sourcebatch, opt)
- local toolchain = assert(target:toolchain("verilator"), 'we need set_toolchains("verilator") in target("%s")', target:name())
+ local toolchain = assert(target:toolchain("verilator"), 'we need set_toolchains("verilator") in target("%s")',
+ target:name())
local verilator = assert(toolchain:config("verilator"), "verilator not found!")
+ local support_json, makefile_type = _get_makefile_type(verilator)
local autogendir = path.join(target:autogendir(), "rules", "verilator")
local targetname = target:name()
- local cmakefile = path.join(autogendir, targetname .. ".cmake")
+ local makefile = path.join(autogendir, targetname .. "." .. makefile_type)
local dependfile = path.join(autogendir, targetname .. ".build.d")
-- get compiled source files
- local sourcefiles = _get_sourcefiles_from_cmake(target, cmakefile)
+ local sourcefiles
+ if support_json then
+ sourcefiles = _get_sourcefiles_from_json(makefile)
+ else
+ sourcefiles = _get_sourcefiles_from_cmake(target, makefile)
+ end
-- do build
for _, sourcefile in ipairs(sourcefiles) do