From 874c9aa63257f578768391aea5a12601a1874ce3 Mon Sep 17 00:00:00 2001 From: ririyeye <200610237@qq.com> Date: Wed, 22 Apr 2026 23:29:47 +0800 Subject: fix linux module builds on kernel 6.12+ Keep xmake's linux module rule aligned with modern kbuild so generated .ko files retain vermagic and modversion metadata required for loading on newer kernels. --- .../rules/platform/linux/module/driver_modules.lua | 91 ++++++++++++++++++++-- 1 file changed, 86 insertions(+), 5 deletions(-) (limited to 'xmake/rules/platform/linux/module/driver_modules.lua') diff --git a/xmake/rules/platform/linux/module/driver_modules.lua b/xmake/rules/platform/linux/module/driver_modules.lua index e7a0dda49..2ddea7fc4 100644 --- a/xmake/rules/platform/linux/module/driver_modules.lua +++ b/xmake/rules/platform/linux/module/driver_modules.lua @@ -25,6 +25,36 @@ import("core.cache.memcache") import("lib.detect.find_tool") import("utils.progress") +function _get_linux_headers_builddir(linux_headers) + return linux_headers.builddir or linux_headers.sdkdir +end + +function _get_linux_headers_config(linux_headers) + local builddir = _get_linux_headers_builddir(linux_headers) + local key = table.concat({linux_headers.sdkdir, builddir or "", "config"}, "|") + local configdata = memcache.get2("linux.driver", key, "data") + if configdata == nil then + local configfile = path.join(builddir, "include", "config", "auto.conf") + if os.isfile(configfile) then + configdata = io.readfile(configfile) + else + configfile = path.join(linux_headers.includedir, "generated", "autoconf.h") + if os.isfile(configfile) then + configdata = io.readfile(configfile) + end + end + memcache.set2("linux.driver", key, "data", configdata or false) + end + return configdata or nil +end + +function _has_linux_headers_config(linux_headers, config) + local configdata = _get_linux_headers_config(linux_headers) + if configdata then + return configdata:find(config .. "=y", 1, true) or configdata:find("#define " .. config .. " 1", 1, true) + end +end + -- get linux-headers sdk function _get_linux_headers_sdk(target) local linux_headersdir = target:values("linux.driver.linux-headers") @@ -57,7 +87,7 @@ end -- get cflags from make function _get_cflags_from_make(target, sdkdir, builddir) - local key = sdkdir .. target:arch() + local key = table.concat({sdkdir, builddir or "", target:arch(), "v2"}, "|") local cflags = memcache.get2("linux.driver", key, "cflags") local ldflags_o = memcache.get2("linux.driver", key, "ldflags_o") local ldflags_ko = memcache.get2("linux.driver", key, "ldflags_ko") @@ -131,6 +161,11 @@ module_exit(hello_exit); end cflag = "-fplugin=" .. plugindir has_cflag = true + elseif cflag == "-nostdinc" or cflag == "-undef" or cflag == "-pg" + or cflag:startswith("-std=") or cflag:startswith("-O") + or cflag:startswith("-g") or cflag:startswith("-U") + or cflag:startswith("--param=") then + has_cflag = true elseif cflag:startswith("-f") or cflag:startswith("-m") or (cflag:startswith("-W") and not cflag:startswith("-Wp,-MMD,") and not cflag:startswith("-Wp,-MD,")) or (cflag:startswith("-D") and not cflag:find("KBUILD_MODNAME=") and not cflag:find("KBUILD_BASENAME=")) then @@ -251,6 +286,24 @@ function link(target, opt) local targetfile = target:targetfile() local dependfile = target:dependfile(targetfile) local objectfiles = target:objectfiles() + local linux_headers = target:data("linux.driver.linux_headers") + local builddir = linux_headers and _get_linux_headers_builddir(linux_headers) or nil + local dependfiles = table.join({}, objectfiles) + if builddir then + local kernelsymvers = path.join(builddir, "Module.symvers") + if os.isfile(kernelsymvers) then + table.insert(dependfiles, kernelsymvers) + end + end + if linux_headers then + local modulecommon = path.join(linux_headers.sdkdir, "scripts", "module-common.c") + if not os.isfile(modulecommon) and builddir and builddir ~= linux_headers.sdkdir then + modulecommon = path.join(builddir, "scripts", "module-common.c") + end + if os.isfile(modulecommon) then + table.insert(dependfiles, modulecommon) + end + end depend.on_changed(function () -- trace @@ -258,9 +311,8 @@ function link(target, opt) -- get module scripts local modpost - local linux_headers = target:data("linux.driver.linux_headers") if linux_headers then - modpost = path.join(linux_headers.builddir or linux_headers.sdkdir, "scripts", "mod", "modpost") + modpost = path.join(builddir, "scripts", "mod", "modpost") end assert(modpost and os.isfile(modpost), "scripts/mod/modpost not found!") @@ -300,7 +352,18 @@ function link(target, opt) -- generate target.mod.c local orderfile = path.join(path.directory(targetfile_o), "modules.order") local symversfile = path.join(path.directory(targetfile_o), "Module.symvers") - argv = {"-m", "-a", "-o", symversfile, "-e", "-N", "-w", "-T", orderfile} + argv = {"-m", "-a", "-o", symversfile, "-e", "-N", "-w"} + if _has_linux_headers_config(linux_headers, "CONFIG_BASIC_MODVERSIONS") then + table.insert(argv, "-b") + end + if _has_linux_headers_config(linux_headers, "CONFIG_EXTENDED_MODVERSIONS") then + table.insert(argv, "-x") + end + table.join2(argv, "-T", orderfile) + local kernelsymvers = path.join(builddir, "Module.symvers") + if os.isfile(kernelsymvers) then + table.join2(argv, "-i", kernelsymvers) + end io.writefile(orderfile, targetfile_o .. "\n") os.vrunv(modpost, argv) @@ -308,11 +371,26 @@ function link(target, opt) local targetfile_mod_c = targetfile_o:gsub("%.o$", ".mod.c") local targetfile_mod_o = targetfile_o:gsub("%.o$", ".mod.o") local compinst = target:compiler("cc") + target:fileconfig_set(targetfile_mod_c, {defines = "KBUILD_BASENAME=\"" .. path.basename(targetfile_mod_c) .. "\""}) if option.get("verbose") then print(compinst:compcmd(targetfile_mod_c, targetfile_mod_o, {target = target, rawargs = true})) end assert(compinst:compile(targetfile_mod_c, targetfile_mod_o, {target = target})) + -- compile .module-common.o for vermagic/retpoline metadata on modern kernels + local modulecommon_sourcefile = path.join(linux_headers.sdkdir, "scripts", "module-common.c") + if not os.isfile(modulecommon_sourcefile) and builddir ~= linux_headers.sdkdir then + modulecommon_sourcefile = path.join(builddir, "scripts", "module-common.c") + end + local modulecommon_objectfile + if os.isfile(modulecommon_sourcefile) then + modulecommon_objectfile = path.join(path.directory(targetfile_o), ".module-common.o") + if option.get("verbose") then + print(compinst:compcmd(modulecommon_sourcefile, modulecommon_objectfile, {target = target, rawargs = true})) + end + assert(compinst:compile(modulecommon_sourcefile, modulecommon_objectfile, {target = target})) + end + -- link target.ko argv = {} local ldflags_ko = target:data("linux.driver.ldflags_ko") @@ -321,10 +399,13 @@ function link(target, opt) end local targetfile_o = target:objectfile(targetfile) table.join2(argv, "-o", targetfile, targetfile_o, targetfile_mod_o) + if modulecommon_objectfile then + table.insert(argv, modulecommon_objectfile) + end os.mkdir(path.directory(targetfile)) os.vrunv(ld, argv) - end, {dependfile = dependfile, lastmtime = os.mtime(target:targetfile()), files = objectfiles, changed = target:is_rebuilt()}) + end, {dependfile = dependfile, lastmtime = os.mtime(target:targetfile()), files = dependfiles, changed = target:is_rebuilt()}) end function install(target) -- cgit v1.3.1 From d84515c3041e38f9fbccfab31c13e0b4b6627ddc Mon Sep 17 00:00:00 2001 From: ririyeye <200610237@qq.com> Date: Thu, 23 Apr 2026 10:17:10 +0800 Subject: fix linux module review follow-ups Tighten kernel config detection to avoid prefix matches and share module-common.c lookup so dependency tracking and compilation stay aligned. Made-with: Cursor --- .../rules/platform/linux/module/driver_modules.lua | 28 +++++++++++++--------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'xmake/rules/platform/linux/module/driver_modules.lua') diff --git a/xmake/rules/platform/linux/module/driver_modules.lua b/xmake/rules/platform/linux/module/driver_modules.lua index 2ddea7fc4..1ff19b642 100644 --- a/xmake/rules/platform/linux/module/driver_modules.lua +++ b/xmake/rules/platform/linux/module/driver_modules.lua @@ -29,6 +29,17 @@ function _get_linux_headers_builddir(linux_headers) return linux_headers.builddir or linux_headers.sdkdir end +function _get_linux_headers_modulecommon(linux_headers) + local builddir = _get_linux_headers_builddir(linux_headers) + local modulecommon = path.join(linux_headers.sdkdir, "scripts", "module-common.c") + if not os.isfile(modulecommon) and builddir ~= linux_headers.sdkdir then + modulecommon = path.join(builddir, "scripts", "module-common.c") + end + if os.isfile(modulecommon) then + return modulecommon + end +end + function _get_linux_headers_config(linux_headers) local builddir = _get_linux_headers_builddir(linux_headers) local key = table.concat({linux_headers.sdkdir, builddir or "", "config"}, "|") @@ -51,7 +62,8 @@ end function _has_linux_headers_config(linux_headers, config) local configdata = _get_linux_headers_config(linux_headers) if configdata then - return configdata:find(config .. "=y", 1, true) or configdata:find("#define " .. config .. " 1", 1, true) + local normalized = "\n" .. configdata:gsub("\r\n", "\n"):gsub("\r", "\n") .. "\n" + return normalized:find("\n" .. config .. "=y\n", 1, true) or normalized:find("\n#define " .. config .. " 1\n", 1, true) end end @@ -296,11 +308,8 @@ function link(target, opt) end end if linux_headers then - local modulecommon = path.join(linux_headers.sdkdir, "scripts", "module-common.c") - if not os.isfile(modulecommon) and builddir and builddir ~= linux_headers.sdkdir then - modulecommon = path.join(builddir, "scripts", "module-common.c") - end - if os.isfile(modulecommon) then + local modulecommon = _get_linux_headers_modulecommon(linux_headers) + if modulecommon then table.insert(dependfiles, modulecommon) end end @@ -378,12 +387,9 @@ function link(target, opt) assert(compinst:compile(targetfile_mod_c, targetfile_mod_o, {target = target})) -- compile .module-common.o for vermagic/retpoline metadata on modern kernels - local modulecommon_sourcefile = path.join(linux_headers.sdkdir, "scripts", "module-common.c") - if not os.isfile(modulecommon_sourcefile) and builddir ~= linux_headers.sdkdir then - modulecommon_sourcefile = path.join(builddir, "scripts", "module-common.c") - end + local modulecommon_sourcefile = _get_linux_headers_modulecommon(linux_headers) local modulecommon_objectfile - if os.isfile(modulecommon_sourcefile) then + if modulecommon_sourcefile then modulecommon_objectfile = path.join(path.directory(targetfile_o), ".module-common.o") if option.get("verbose") then print(compinst:compcmd(modulecommon_sourcefile, modulecommon_objectfile, {target = target, rawargs = true})) -- cgit v1.3.1 From c110d46d8cbb7ce929a98c58fc43668431f9fbe8 Mon Sep 17 00:00:00 2001 From: ririyeye <200610237@qq.com> Date: Thu, 23 Apr 2026 10:39:22 +0800 Subject: fix linux driver cross compile detection Pass ARCH and CROSS_COMPILE for same-platform cross builds and derive the toolchain prefix from versioned gcc names so kbuild flag probing uses the correct target tools. Made-with: Cursor --- .../rules/platform/linux/module/driver_modules.lua | 42 +++++++++++++++------- 1 file changed, 29 insertions(+), 13 deletions(-) (limited to 'xmake/rules/platform/linux/module/driver_modules.lua') diff --git a/xmake/rules/platform/linux/module/driver_modules.lua b/xmake/rules/platform/linux/module/driver_modules.lua index 1ff19b642..7e6e6c700 100644 --- a/xmake/rules/platform/linux/module/driver_modules.lua +++ b/xmake/rules/platform/linux/module/driver_modules.lua @@ -29,6 +29,31 @@ function _get_linux_headers_builddir(linux_headers) return linux_headers.builddir or linux_headers.sdkdir end +function _get_linux_arch(target) + if target:is_arch("arm", "armv7") then + return "arm" + elseif target:is_arch("arm64", "arm64-v8a") then + return "arm64" + elseif target:is_arch("x86", "i386") then + return "x86" + elseif target:is_arch("x86_64", "x64") then + return "x86_64" + elseif target:is_arch("mips", "mipsel", "mips64", "mips64el") then + return "mips" + elseif target:is_arch("ppc", "ppc64", "powerpc", "powerpc64") then + return "powerpc" + elseif target:is_arch("riscv64", "riscv32") then + return "riscv" + end +end + +function _get_linux_cross_compile(target) + local cc = target:tool("cc") + if cc then + return cc:match("^(.*%-)gcc[%-%d%.]*$") + end +end + function _get_linux_headers_modulecommon(linux_headers) local builddir = _get_linux_headers_builddir(linux_headers) local modulecommon = path.join(linux_headers.sdkdir, "scripts", "module-common.c") @@ -137,21 +162,12 @@ module_exit(hello_exit); if builddir then table.insert(argv, "O=" .. builddir) end - if not target:is_plat(os.subhost()) then + if not target:is_plat(os.subhost()) or not target:is_arch(os.subarch()) then -- e.g. $(MAKE) -C $(KERN_DIR) V=1 ARCH=arm64 CROSS_COMPILE=/mnt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- M=$(PWD) modules - local arch - if target:is_arch("arm", "armv7") then - arch = "arm" - elseif target:is_arch("arm64", "arm64-v8a") then - arch = "arm64" - elseif target:is_arch("mips") then - arch = "mips" - elseif target:is_arch("ppc", "ppc64", "powerpc", "powerpc64") then - arch = "powerpc" - end + local arch = _get_linux_arch(target) assert(arch, "unknown arch(%s)!", target:arch()) - local cc = target:tool("cc") - local cross = cc:gsub("%-gcc$", "-") + local cross = _get_linux_cross_compile(target) + assert(cross, "unknown cross-compile prefix for cc(%s)!", target:tool("cc")) table.insert(argv, "ARCH=" .. arch) table.insert(argv, "CROSS_COMPILE=" .. cross) end -- cgit v1.3.1 From c615accfecf3e2230b85292b92af20ee580a6252 Mon Sep 17 00:00:00 2001 From: ririyeye <200610237@qq.com> Date: Thu, 23 Apr 2026 11:51:25 +0800 Subject: fix linux driver review follow-ups Use target:is_cross() for kbuild probing, normalize module-common paths before comparing them, and check kernel configs line by line for clearer exact matches. Made-with: Cursor --- .../rules/platform/linux/module/driver_modules.lua | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'xmake/rules/platform/linux/module/driver_modules.lua') diff --git a/xmake/rules/platform/linux/module/driver_modules.lua b/xmake/rules/platform/linux/module/driver_modules.lua index 7e6e6c700..df8bd095c 100644 --- a/xmake/rules/platform/linux/module/driver_modules.lua +++ b/xmake/rules/platform/linux/module/driver_modules.lua @@ -56,11 +56,13 @@ end function _get_linux_headers_modulecommon(linux_headers) local builddir = _get_linux_headers_builddir(linux_headers) - local modulecommon = path.join(linux_headers.sdkdir, "scripts", "module-common.c") - if not os.isfile(modulecommon) and builddir ~= linux_headers.sdkdir then - modulecommon = path.join(builddir, "scripts", "module-common.c") + local sdkdir = linux_headers.sdkdir and path.normalize(linux_headers.sdkdir) or nil + local normalized_builddir = builddir and path.normalize(builddir) or nil + local modulecommon = sdkdir and path.join(sdkdir, "scripts", "module-common.c") or nil + if modulecommon and not os.isfile(modulecommon) and normalized_builddir and normalized_builddir ~= sdkdir then + modulecommon = path.join(normalized_builddir, "scripts", "module-common.c") end - if os.isfile(modulecommon) then + if modulecommon and os.isfile(modulecommon) then return modulecommon end end @@ -87,9 +89,14 @@ end function _has_linux_headers_config(linux_headers, config) local configdata = _get_linux_headers_config(linux_headers) if configdata then - local normalized = "\n" .. configdata:gsub("\r\n", "\n"):gsub("\r", "\n") .. "\n" - return normalized:find("\n" .. config .. "=y\n", 1, true) or normalized:find("\n#define " .. config .. " 1\n", 1, true) + local normalized = configdata:gsub("\r\n", "\n"):gsub("\r", "\n") + for _, line in ipairs(normalized:split("\n")) do + if line == config .. "=y" or line == "#define " .. config .. " 1" then + return true + end + end end + return false end -- get linux-headers sdk @@ -162,7 +169,7 @@ module_exit(hello_exit); if builddir then table.insert(argv, "O=" .. builddir) end - if not target:is_plat(os.subhost()) or not target:is_arch(os.subarch()) then + if target:is_cross() then -- e.g. $(MAKE) -C $(KERN_DIR) V=1 ARCH=arm64 CROSS_COMPILE=/mnt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- M=$(PWD) modules local arch = _get_linux_arch(target) assert(arch, "unknown arch(%s)!", target:arch()) -- cgit v1.3.1 From fbd947dc0138b3883e1de709a5e0d59269bdf486 Mon Sep 17 00:00:00 2001 From: ririyeye <200610237@qq.com> Date: Thu, 23 Apr 2026 15:37:04 +0800 Subject: fix linux driver final review issue Drop the redundant newline normalization in kernel config checks because io.readfile() already returns newline-split content suitable for line-based matching. Made-with: Cursor --- xmake/rules/platform/linux/module/driver_modules.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'xmake/rules/platform/linux/module/driver_modules.lua') diff --git a/xmake/rules/platform/linux/module/driver_modules.lua b/xmake/rules/platform/linux/module/driver_modules.lua index df8bd095c..0e23a0100 100644 --- a/xmake/rules/platform/linux/module/driver_modules.lua +++ b/xmake/rules/platform/linux/module/driver_modules.lua @@ -89,8 +89,7 @@ end function _has_linux_headers_config(linux_headers, config) local configdata = _get_linux_headers_config(linux_headers) if configdata then - local normalized = configdata:gsub("\r\n", "\n"):gsub("\r", "\n") - for _, line in ipairs(normalized:split("\n")) do + for _, line in ipairs(configdata:split("\n")) do if line == config .. "=y" or line == "#define " .. config .. " 1" then return true end -- cgit v1.3.1