--!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file rc.lua -- -- imports import("core.base.option") import("core.base.hashset") import("core.project.project") import("private.tools.vstool") -- normailize path of a dependecy function _normailize_dep(dep, projectdir) if path.is_absolute(dep) then dep = path.translate(dep) else dep = path.absolute(dep, projectdir) end if dep:startswith(projectdir) then return path.relative(dep, projectdir) else return deps end end -- parse include file function _parse_includefile(line) if line:startswith("#line") then return line:match("#line %d+ \"(.+)\"") elseif line:find("ICON", 1, true) and line:find(".ico", 1, true) then -- 101 ICON "xxx.ico" return line:match("ICON%s+\"(.+.ico)\"") elseif line:find("BITMAP", 1, true) and line:find(".bmp", 1, true) then return line:match("BITMAP%s+\"(.+.bmp)\"") end end -- init it function init(self) if self:has_flags("-nologo", "mrcflags") then -- fix vs2008 on xp, e.g. fatal error RC1106: invalid option: -ologo self:set("mrcflags", "-nologo") end end -- make the define flag function nf_define(self, macro) return {"-D" .. macro} end -- make the undefine flag function nf_undefine(self, macro) return "-U" .. macro end -- make the includedir flag function nf_includedir(self, dir) return {"-I" .. dir} end -- make the sysincludedir flag function nf_sysincludedir(self, dir) return nf_includedir(self, dir) end -- make the compile arguments list function compargv(self, sourcefile, objectfile, flags, opt) return self:program(), table.join(flags, "-Fo" .. objectfile, sourcefile) end -- compile the source file function compile(self, sourcefile, objectfile, dependinfo, flags, opt) opt = opt or {} os.mkdir(path.directory(objectfile)) try { function () -- @note we don't need to use vstool.iorunv to enable unicode output for rc.exe local program, argv = compargv(self, sourcefile, objectfile, flags, opt) local outdata, errdata = os.iorunv(program, argv, {envs = self:runenvs()}) return (outdata or "") .. (errdata or "") end, catch { function (errors) -- use stdout as errors first from vstool.iorunv() if type(errors) == "table" then local errs = errors.stdout or "" if #errs:trim() == 0 then errs = errors.stderr or "" end errors = errs end os.raise(tostring(errors)) end }, finally { function (ok, warnings) if warnings and #warnings > 0 and option.get("verbose") then cprint("${color.warning}%s", table.concat(table.slice(warnings:split('\n'), 1, 8), '\n')) end end } } -- try to use cl.exe to parse includes, but cl.exe maybe not exists in masm32 sdk -- @see https://github.com/xmake-io/xmake/issues/2562 local cl if opt.target then cl = opt.target:tool("cxx") elseif self:toolchain() then cl = self:toolchain():tool("cxx") end if cl then local outfile = os.tmpfile() .. ".rc.out" local errfile = os.tmpfile() .. ".rc.err" local includeflags = {} for _, flag in ipairs(flags) do if flag:match("^[-/]I") then table.insert(includeflags, flag) end end local ok = try {function () os.execv(cl, table.join("-E", includeflags, sourcefile), {stdout = outfile, stderr = errfile, envs = self:runenvs()}); return true end} if ok and os.isfile(outfile) then local depfiles_rc local includeset = hashset.new() local file = io.open(outfile) local projectdir = os.projectdir() for line in file:lines() do local includefile = _parse_includefile(line) if includefile then includefile = _normailize_dep(includefile, projectdir) if includefile and not includeset:has(includefile) and path.absolute(includefile) ~= path.absolute(sourcefile) and os.isfile(includefile) then depfiles_rc = (depfiles_rc or "") .. "\n" .. includefile includeset:insert(includefile) end end end file:close() if dependinfo then dependinfo.depfiles_format = "rc" dependinfo.depfiles = depfiles_rc end end os.tryrm(outfile) os.tryrm(errfile) end end