rule("bin2c") set_extensions(".bin") on_load(function (target) local headerdir = path.join(target:autogendir(), "rules", "bin2c") local outputSource = table.unpack(target:extraconf("rules", "bin2c", "outputSource")) if not os.isdir(headerdir) then os.mkdir(headerdir) end target:add("includedirs", headerdir) target:add("files", outputSource) end) before_buildcmd_files(function (target, batchcmds, sourcebatch, opt) local outputHeader = table.unpack(target:extraconf("rules", "bin2c", "outputHeader")) local outputHeaderEnumContent = "" for _, filePath in ipairs(sourcebatch.sourcefiles) do local escapedName = string.gsub(filePath, "[/|.]", "_") outputHeaderEnumContent = outputHeaderEnumContent .. "\t" .. escapedName .. ",\n" end local outputHeaderContent = string.format([[ #pragma once #include #include struct Asset { const unsigned char* data; std::size_t size; }; enum class AssetName { %s }; const Asset& getResource(AssetName fileName); const Asset& getResource(const std::string& fileName); ]], outputHeaderEnumContent) local outputSource = table.unpack(target:extraconf("rules", "bin2c", "outputSource")) local relativePath = path.join(path.relative(path.directory(outputHeader), path.directory(outputSource)), path.filename(outputHeader)) local outputSourceContent = string.format([[ #include "%s" #include ]], relativePath) local outputSourceArrayVars = "" local outputSourceMapVars = "" for _, filePath in ipairs(sourcebatch.sourcefiles) do local escapedName = string.gsub(filePath, "[/|.]", "_") local varDecl = string.format("static const unsigned char %s[] = {\n\t#include <%s>\n};\n\n", escapedName, filePath .. ".h") outputSourceContent = outputSourceContent .. varDecl outputSourceArrayVars = outputSourceArrayVars .. string.format("\t{%s, sizeof(%s)},\n", escapedName, escapedName) outputSourceMapVars = outputSourceMapVars .. string.format("\t{\"%s\", AssetName::%s},\n", filePath, escapedName) end outputSourceContent = outputSourceContent .. string.format([[ static const Asset assets[] = { %s }; static const std::map assetMap = { %s }; ]], outputSourceArrayVars, outputSourceMapVars) outputSourceContent = outputSourceContent .. [[ const Asset& getResource(AssetName fileName) { return assets[static_cast(fileName)]; } const Asset& getResource(const std::string& fileName) { return getResource(assetMap.at(fileName)); } ]] for _, sourcefile_bin in ipairs(sourcebatch.sourcefiles) do -- get header file local headerdir = path.join(target:autogendir(), "rules", "bin2c") local headerfile = path.join(headerdir, sourcefile_bin .. ".h") target:add("includedirs", headerdir) -- add commands batchcmds:show_progress(opt.progress, "${color.build.object}generating.bin2c %s", sourcefile_bin) batchcmds:mkdir(headerdir) local argv = {"lua", "private.utils.bin2c", "-i", path(sourcefile_bin), "-o", path(headerfile)} local linewidth = target:extraconf("rules", "bin2c", "linewidth") if linewidth then table.insert(argv, "-w") table.insert(argv, tostring(linewidth)) end local nozeroend = target:extraconf("rules", "bin2c", "nozeroend") if nozeroend then table.insert(argv, "--nozeroend") end batchcmds:vrunv(os.programfile(), argv, {envs = {XMAKE_SKIP_HISTORY = "y"}}) -- add deps batchcmds:add_depfiles(sourcefile_bin) batchcmds:set_depmtime(os.mtime(headerfile)) batchcmds:set_depcache(target:dependfile(headerfile)) end batchcmds:show_progress(opt.progress, "${color.build.object}generating.bin2c %s", outputHeader) io.writefile(outputHeader, outputHeaderContent) batchcmds:show_progress(opt.progress, "${color.build.object}generating.bin2c %s", outputSource) io.writefile(outputSource, outputSourceContent) end)