How to get all included files used by batchcmds:compile(file.cpp) command to fill a batchcmds:add_depfiles(h1.hpp, h2.hpp....) ? #5946
-
Hi, I need some help to understand depfiles and batchcmds. I'm building an UnrealEngine-like header tool that generates reflection headers. To achieve this, I'm using a custom xmake rule that will compile the generated rule("generated_cpp", function (rule)
set_extensions(".hpp")
before_buildcmd_file(function (target, batchcmds, source_header, opt)
-- Guess generated source file path
local generated_path = string.sub(os.projectdir().."/"..source_header, string.len(target:scriptdir()) + 2)
-- replace .hpp extension with .gen.cpp
local generated_source = target:autogendir().."/"..string.sub(generated_path, 1, string.len(generated_path) - 3).."gen.cpp"
-- generated classes are always private
generated_source = generated_source:gsub("public", "private", 1)
-- check if the header tool generated reflection data for our input file
if (os.exists(generated_source)) then
local test_str = tostring(generated_source)
local objectfile = target:objectfile(generated_source)
--batchcmds:vrunv(TODO : make the header tool works for one header at a time)
batchcmds:compile(generated_source, objectfile)
batchcmds:show_progress(opt.progress, "${color.build.object}Compiling.reflection %s", generated_source)
batchcmds:add_depfiles(source_header) -- The problem is here (explanations bellow)
batchcmds:set_depmtime(os.mtime(objectfile))
batchcmds:set_depcache(target:dependfile(objectfile))
end
end)
end) My problem occurs when the input header file includes other headers : xmake will not track updates of subdependencies // foo.hpp
#include "foo.gen.hpp"
class foo {} // bar.hpp
#include "foo.hpp" // if I update "foo.hpp", "bar.gen.cpp" will not be recompiled
#include "bar.gen.hpp"
class bar : public foo {} Using the previous rule, xmake won't be able to know when However, I've seen that xmake is able to parse includes somehow and build a complete recursive list of dependencies for each class, so I guess there is a way to solve my problem by adding the list of all dependencies recursively included by my source file in Thanks in advance for your help ! |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 1 reply
-
xmake/xmake/rules/swig/xmake.lua Line 119 in 46b9951 xmake/xmake/rules/swig/build_module_file.lua Lines 163 to 187 in 46b9951 xmake/xmake/modules/private/action/build/object.lua Lines 91 to 114 in 46b9951 |
Beta Was this translation helpful? Give feedback.
-
Thanks for the hint ! (I'm not familiar with lua at all, so I may have missed something obvious ?) |
Beta Was this translation helpful? Give feedback.
-
Update : I finally figured out how to use the compiler instance ! 🥳 import("core.tool.compiler")
local compinst = compiler.load("cxx", {target = target})
local compflags = compinst:compflags({target = target, sourcefile = generated_source, configs = opt.configs})
assert(compinst:compile(generated_source, objectfile, {dependinfo = dependinfo, compflags = compflags})) So that worked, now I just need a way to find a way to make it works seamlessly with my batchcmd 👍 |
Beta Was this translation helpful? Give feedback.
-
Yay found the solution 🥳 rule("generated_cpp", function (rule)
set_extensions(".hpp")
before_buildcmd_file(function (target, batchcmds, source_header, opt)
-- Guess generated source file path
local generated_path = string.sub(os.projectdir().."/"..source_header, string.len(target:scriptdir()) + 2)
-- replace .hpp extension with .gen.cpp
local generated_source = target:autogendir().."/"..string.sub(generated_path, 1, string.len(generated_path) - 3).."gen.cpp"
-- generated classes are always private
generated_source = generated_source:gsub("public", "private", 1)
if (os.exists(generated_source)) then
local objectfile = target:objectfile(generated_source)
--batchcmds:vrunv(TODO : make the header tool works for one header at a time)
import("core.tool.compiler")
import("core.project.depend")
local compinst = compiler.load("cxx", {target = target})
local compflags = compinst:compflags({target = target, sourcefile = generated_source, configs = opt.configs})
local dependfile = target:dependfile(objectfile)
-- Load existing dep infos (or create if not exists)
local dependinfo = target:is_rebuilt() and {} or (depend.load(dependfile, {target = target}) or {})
local depvalues = {compinst:program(), compflags}
local lastmtime = os.isfile(objectfile) and os.mtime(objectfile) or 0
-- Test if source file was modified
if not depend.is_changed(dependinfo, {lastmtime = lastmtime, values = depvalues}) then
return
end
batchcmds:show_progress(opt.progress, "${color.build.object}Compiling.Reflection %s", generated_source)
-- Compile and fill the dependency list into dependinfo
assert(compinst:compile(generated_source, objectfile, {dependinfo = dependinfo, compflags = compflags}))
-- store build depvalues to detect depvalues changes
dependinfo.values = depvalues
depend.save(dependinfo, dependfile)
end
end)
end) |
Beta Was this translation helpful? Give feedback.
Yay found the solution 🥳
Thanks @waruqi !