diff options
Diffstat (limited to '3rdparty/genie/src/actions/ninja/ninja_cpp.lua')
-rw-r--r-- | 3rdparty/genie/src/actions/ninja/ninja_cpp.lua | 289 |
1 files changed, 204 insertions, 85 deletions
diff --git a/3rdparty/genie/src/actions/ninja/ninja_cpp.lua b/3rdparty/genie/src/actions/ninja/ninja_cpp.lua index 4007c117948..a0134f34e54 100644 --- a/3rdparty/genie/src/actions/ninja/ninja_cpp.lua +++ b/3rdparty/genie/src/actions/ninja/ninja_cpp.lua @@ -8,6 +8,14 @@ local ninja = premake.ninja local cpp = premake.ninja.cpp local p = premake +local function wrap_ninja_cmd(c) + if os.is("windows") then + return 'cmd /c "' .. c .. '"' + else + return c + end +end + -- generate project + config build file function ninja.generate_cpp(prj) local pxy = ninja.get_proxy("prj", prj) @@ -36,7 +44,7 @@ local p = premake local flags = { defines = ninja.list(tool.getdefines(cfg.defines)), - includes = ninja.list(table.join(tool.getincludedirs(cfg.includedirs), tool.getquoteincludedirs(cfg.userincludedirs))), + includes = ninja.list(table.join(tool.getincludedirs(cfg.includedirs), tool.getquoteincludedirs(cfg.userincludedirs), tool.getsystemincludedirs(cfg.systemincludedirs))), cppflags = ninja.list(tool.getcppflags(cfg)), asmflags = ninja.list(table.join(tool.getcflags(cfg), cfg.buildoptions, cfg.buildoptions_asm)), cflags = ninja.list(table.join(tool.getcflags(cfg), cfg.buildoptions, cfg.buildoptions_c)), @@ -45,38 +53,85 @@ local p = premake } _p("") - _p("# core rules for " .. cfg.name) _p("rule cc") - _p(" command = " .. tool.cc .. " $defines $includes $flags -MMD -MF $out.d -c -o $out $in") + _p(" command = " .. wrap_ninja_cmd(tool.cc .. " $defines $includes $flags -MMD -MF $out.d -c -o $out $in")) _p(" description = cc $out") - _p(" depfile = $out.d") - _p(" deps = gcc") + _p(" depfile = $out.d") + _p(" deps = gcc") _p("") _p("rule cxx") - _p(" command = " .. tool.cxx .. " $defines $includes $flags -MMD -MF $out.d -c -o $out $in") + _p(" command = " .. wrap_ninja_cmd(tool.cxx .. " $defines $includes $flags -MMD -MF $out.d -c -o $out $in")) _p(" description = cxx $out") - _p(" depfile = $out.d") - _p(" deps = gcc") - _p("") - _p("rule ar") - _p(" command = " .. tool.ar .. " $flags $out $in $libs " .. (os.is("MacOSX") and " 2>&1 > /dev/null | sed -e '/.o) has no symbols$$/d'" or "")) - _p(" description = ar $out") + _p(" depfile = $out.d") + _p(" deps = gcc") _p("") + if cfg.flags.UseObjectResponseFile then + _p("rule ar") + _p(" command = " .. wrap_ninja_cmd(tool.ar .. " $flags $out @$out.rsp " .. (os.is("MacOSX") and " 2>&1 > /dev/null | sed -e '/.o) has no symbols$$/d'" or ""))) + _p(" description = ar $out") + _p(" rspfile = $out.rsp") + _p(" rspfile_content = $in $libs") + _p("") + else + _p("rule ar") + _p(" command = " .. wrap_ninja_cmd(tool.ar .. " $flags $out $in $libs" .. (os.is("MacOSX") and " 2>&1 > /dev/null | sed -e '/.o) has no symbols$$/d'" or ""))) + _p(" description = ar $out") + _p("") + end + local link = iif(cfg.language == "C", tool.cc, tool.cxx) _p("rule link") - _p(" command = " .. link .. " -o $out @$out.rsp $all_ldflags $libs") - _p(" rspfile = $out.rsp") - _p(" rspfile_content = $all_outputfiles") - _p(" description = link $out") + local startgroup = '' + local endgroup = '' + if (cfg.flags.LinkSupportCircularDependencies) then + startgroup = '-Wl,--start-group' + endgroup = '-Wl,--end-group' + end + + local rspfile_content = "$all_outputfiles $walibs " .. string.format("%s $libs %s", startgroup, endgroup) + if cfg.flags.UseLDResponseFile then + _p(" command = " .. wrap_ninja_cmd("$pre_link " .. link .. " -o $out @$out.rsp $all_ldflags $post_build")) + _p(" description = link $out") + _p(" rspfile = $out.rsp") + _p(" rspfile_content = %s", rspfile_content) + _p("") + else + _p(" command = " .. wrap_ninja_cmd("$pre_link " .. link .. " -o $out " .. rspfile_content .. " $all_ldflags $post_build")) + _p(" description = link $out") + _p("") + end + + _p("rule exec") + _p(" command = " .. wrap_ninja_cmd("$command")) + _p(" description = Run $type commands") _p("") + if #cfg.prebuildcommands > 0 then + _p("build __prebuildcommands_" .. premake.esc(prj.name) .. ": exec") + _p(1, "command = " .. wrap_ninja_cmd("echo Running pre-build commands && " .. table.implode(cfg.prebuildcommands, "", "", " && "))) + _p(1, "type = pre-build") + _p("") + end + + cfg.pchheader_full = cfg.pchheader + for _, incdir in ipairs(cfg.includedirs) do + -- convert this back to an absolute path for os.isfile() + local abspath = path.getabsolute(path.join(cfg.project.location, cfg.shortname, incdir)) + + local testname = path.join(abspath, cfg.pchheader_full) + if os.isfile(testname) then + cfg.pchheader_full = path.getrelative(cfg.location, testname) + break + end + end + cpp.custombuildtask(prj, cfg) cpp.dependencyRules(prj, cfg) - cpp.file_rules(cfg, flags) + cpp.file_rules(prj, cfg, flags) local objfiles = {} @@ -94,12 +149,16 @@ local p = premake function cpp.custombuildtask(prj, cfg) local cmd_index = 1 - local seen_commands = {} - local command_by_name = {} - local command_files = {} + + local ninja_rules = {} + local ninja_builds = {} + + local prebuildsuffix = #cfg.prebuildcommands > 0 and "||__prebuildcommands_" .. premake.esc(prj.name) or "" for _, custombuildtask in ipairs(prj.custombuildtask or {}) do for _, buildtask in ipairs(custombuildtask or {}) do + + local commands = {} for _, cmd in ipairs(buildtask[4] or {}) do local num = 1 @@ -113,68 +172,47 @@ local p = premake cmd = string.gsub(cmd, '%$%(<%)', '$in') cmd = string.gsub(cmd, '%$%(@%)', '$out') - local cmd_name -- shortened command name - - -- generate shortened rule names for the command, may be nonsensical - -- in some cases but it will at least be unique. - if seen_commands[cmd] == nil then - local _, _, name = string.find(cmd, '([.%w]+)%s') - name = 'cmd' .. cmd_index .. '_' .. string.gsub(name, '[^%w]', '_') - - seen_commands[cmd] = { - name = name, - index = cmd_index, - } - - cmd_index = cmd_index + 1 - cmd_name = name - else - cmd_name = seen_commands[cmd].name - end - - local index = seen_commands[cmd].index - - if command_files[index] == nil then - command_files[index] = {} - end + table.insert(commands, cmd) + end - local cmd_set = command_files[index] + ninja_rules["cmd_" .. cmd_index] = commands - table.insert(cmd_set, { - buildtask[1], - buildtask[2], - buildtask[3], - seen_commands[cmd].name, - }) + table.insert(ninja_builds, { + file_in = buildtask[1], + file_out = buildtask[2], + rule = "cmd_" .. cmd_index, + deps = buildtask[3] + }) - command_files[index] = cmd_set - command_by_name[cmd_name] = cmd - end + cmd_index = cmd_index + 1 end end _p("# custom build rules") - for command, details in pairs(seen_commands) do - _p("rule " .. details.name) - _p(1, "command = " .. command) + + for rule, commands in pairs(ninja_rules) do + _p("rule " .. rule) + _p(1, "command = " .. wrap_ninja_cmd(table.concat(commands, " && "))) end - for cmd_index, cmdsets in ipairs(command_files) do - for _, cmdset in ipairs(cmdsets) do - local file_in = path.getrelative(cfg.location, cmdset[1]) - local file_out = path.getrelative(cfg.location, cmdset[2]) - local deps = '' - for i, dep in ipairs(cmdset[3]) do - deps = deps .. path.getrelative(cfg.location, dep) .. ' ' - end - _p("build " .. file_out .. ': ' .. cmdset[4] .. ' ' .. file_in .. ' | ' .. deps) - _p("") + + for i = 1,#ninja_builds do + local build = ninja_builds[i] + + local deps = '' + for i, dep in ipairs(build.deps) do + deps = deps .. path.getrelative(cfg.location, dep) .. ' ' end + + _p("build " .. path.getrelative(cfg.location, build.file_out) .. ': ' .. build.rule .. ' ' .. path.getrelative(cfg.location, build.file_in) .. ' | ' .. deps .. prebuildsuffix) + _p("") end end function cpp.dependencyRules(prj, cfg) local extra_deps = {} + local order_deps = {} + local extra_flags = {} for _, dependency in ipairs(prj.dependency or {}) do for _, dep in ipairs(dependency or {}) do @@ -191,38 +229,90 @@ local p = premake end end + local pchfilename = cfg.pchheader_full and cpp.pchname(cfg, cfg.pchheader_full) or '' + for _, file in ipairs(cfg.files) do + local objfilename = file == cfg.pchheader and cpp.pchname(cfg, file) or cpp.objectname(cfg, file) + if path.issourcefile(file) or file == cfg.pchheader then + if #cfg.prebuildcommands > 0 then + if order_deps[objfilename] == nil then + order_deps[objfilename] = {} + end + table.insert(order_deps[objfilename], '__prebuildcommands_' .. premake.esc(prj.name)) + end + end + if path.issourcefile(file) then + if cfg.pchheader_full and not cfg.flags.NoPCH then + local nopch = table.icontains(prj.nopch, file) + if not nopch then + local suffix = path.isobjcfile(file) and '_objc' or '' + if extra_deps[objfilename] == nil then + extra_deps[objfilename] = {} + end + table.insert(extra_deps[objfilename], pchfilename .. suffix .. ".gch") + + if extra_flags[objfilename] == nil then + extra_flags[objfilename] = {} + end + table.insert(extra_flags[objfilename], '-include ' .. pchfilename .. suffix) + end + end + end + end + -- store prepared deps for file_rules() phase cfg.extra_deps = extra_deps + cfg.order_deps = order_deps + cfg.extra_flags = extra_flags end function cpp.objectname(cfg, file) return path.join(cfg.objectsdir, path.trimdots(path.removeext(file)) .. ".o") end - function cpp.file_rules(cfg, flags) + function cpp.pchname(cfg, file) + return path.join(cfg.objectsdir, path.trimdots(file)) + end + + function cpp.file_rules(prj,cfg, flags) _p("# build files") for _, file in ipairs(cfg.files) do _p("# FILE: " .. file) - if path.issourcefile(file) then + if cfg.pchheader_full == file then + local pchfilename = cpp.pchname(cfg, file) + local extra_deps = #cfg.extra_deps and '| ' .. table.concat(cfg.extra_deps[pchfilename] or {}, ' ') or '' + local order_deps = #cfg.order_deps and '|| ' .. table.concat(cfg.order_deps[pchfilename] or {}, ' ') or '' + local extra_flags = #cfg.extra_flags and ' ' .. table.concat(cfg.extra_flags[pchfilename] or {}, ' ') or '' + _p("build " .. pchfilename .. ".gch : cxx " .. file .. extra_deps .. order_deps) + _p(1, "flags = " .. flags['cxxflags'] .. extra_flags .. iif(prj.language == "C", "-x c-header", "-x c++-header")) + _p(1, "includes = " .. flags.includes) + _p(1, "defines = " .. flags.defines) + + _p("build " .. pchfilename .. "_objc.gch : cxx " .. file .. extra_deps .. order_deps) + _p(1, "flags = " .. flags['objcflags'] .. extra_flags .. iif(prj.language == "C", "-x objective-c-header", "-x objective-c++-header")) + _p(1, "includes = " .. flags.includes) + _p(1, "defines = " .. flags.defines) + elseif path.issourcefile(file) then local objfilename = cpp.objectname(cfg, file) local extra_deps = #cfg.extra_deps and '| ' .. table.concat(cfg.extra_deps[objfilename] or {}, ' ') or '' - + local order_deps = #cfg.order_deps and '|| ' .. table.concat(cfg.order_deps[objfilename] or {}, ' ') or '' + local extra_flags = #cfg.extra_flags and ' ' .. table.concat(cfg.extra_flags[objfilename] or {}, ' ') or '' + local cflags = "cflags" if path.isobjcfile(file) then - _p("build " .. objfilename .. ": cxx " .. file .. extra_deps) + _p("build " .. objfilename .. ": cxx " .. file .. extra_deps .. order_deps) cflags = "objcflags" elseif path.isasmfile(file) then - _p("build " .. objfilename .. ": cc " .. file .. extra_deps) + _p("build " .. objfilename .. ": cc " .. file .. extra_deps .. order_deps) cflags = "asmflags" elseif path.iscfile(file) and not cfg.options.ForceCPP then - _p("build " .. objfilename .. ": cc " .. file .. extra_deps) + _p("build " .. objfilename .. ": cc " .. file .. extra_deps .. order_deps) else - _p("build " .. objfilename .. ": cxx " .. file .. extra_deps) + _p("build " .. objfilename .. ": cxx " .. file .. extra_deps .. order_deps) cflags = "cxxflags" end - - _p(1, "flags = " .. flags[cflags]) + + _p(1, "flags = " .. flags[cflags] .. extra_flags) _p(1, "includes = " .. flags.includes) _p(1, "defines = " .. flags.defines) elseif path.isresourcefile(file) then @@ -234,30 +324,59 @@ local p = premake end function cpp.linker(prj, cfg, objfiles, tool) - local all_ldflags = ninja.list(table.join(tool.getlibdirflags(cfg), tool.getldflags(cfg), cfg.linkoptions)) - local lddeps = ninja.list(premake.getlinks(cfg, "siblings", "fullpath")) - local libs = lddeps .. " " .. ninja.list(tool.getlinkflags(cfg)) + local all_ldflags = ninja.list(table.join(tool.getlibdirflags(cfg), tool.getldflags(cfg), cfg.linkoptions)) + local prebuildsuffix = #cfg.prebuildcommands > 0 and ("||__prebuildcommands_" .. premake.esc(prj.name)) or "" + local libs = {} + local walibs = {} + local lddeps = {} + + if #cfg.wholearchive > 0 then + for _, linkcfg in ipairs(premake.getlinks(cfg, "siblings", "object")) do + local linkpath = path.rebase(linkcfg.linktarget.fullpath, linkcfg.location, cfg.location) + table.insert(lddeps, linkpath) + + if table.icontains(cfg.wholearchive, linkcfg.project.name) then + table.insert(walibs, table.concat(tool.wholearchive(linkpath), ' ')) + else + table.insert(libs, linkpath) + end + end + else + lddeps = premake.getlinks(cfg, "siblings", "fullpath") + libs = lddeps + end + + lddeps = ninja.list(lddeps) + libs = ninja.list(libs) .. " " .. ninja.list(tool.getlinkflags(cfg)) + walibs = ninja.list(walibs) local function writevars() - _p(1, "all_ldflags = " .. all_ldflags) - _p(1, "libs = " .. libs) + _p(1, "all_ldflags = " .. all_ldflags) + _p(1, "libs = " .. libs) + _p(1, "walibs = " .. walibs) _p(1, "all_outputfiles = " .. table.concat(objfiles, " ")) + if #cfg.prelinkcommands > 0 then + _p(1, 'pre_link = echo Running pre-link commands && ' .. table.implode(cfg.prelinkcommands, "", "", " && ") .. " && ") + end + if #cfg.postbuildcommands > 0 then + _p(1, 'post_build = && echo Running post-build commands && ' .. table.implode(cfg.postbuildcommands, "", "", " && ")) + end end if cfg.kind == "StaticLib" then local ar_flags = ninja.list(tool.getarchiveflags(cfg, cfg, false)) _p("# link static lib") - _p("build " .. cfg:getoutputfilename() .. ": ar " .. table.concat(objfiles, " ") .. " | " .. lddeps) + _p("build " .. cfg:getoutputfilename() .. ": ar " .. table.concat(objfiles, " ") .. " | " .. lddeps .. prebuildsuffix) _p(1, "flags = " .. ninja.list(tool.getarchiveflags(cfg, cfg, false))) _p(1, "all_outputfiles = " .. table.concat(objfiles, " ")) - elseif cfg.kind == "SharedLib" then + elseif cfg.kind == "SharedLib" or cfg.kind == "Bundle" then local output = cfg:getoutputfilename() _p("# link shared lib") - _p("build " .. output .. ": link " .. table.concat(objfiles, " ") .. " | " .. libs) + _p("build " .. output .. ": link " .. table.concat(objfiles, " ") .. " | " .. lddeps .. prebuildsuffix) writevars() elseif (cfg.kind == "ConsoleApp") or (cfg.kind == "WindowedApp") then _p("# link executable") - _p("build " .. cfg:getoutputfilename() .. ": link " .. table.concat(objfiles, " ") .. " | " .. lddeps) + _p("build " .. cfg:getoutputfilename() .. ": link " .. table.concat(objfiles, " ") .. " | " .. lddeps .. prebuildsuffix) writevars() else p.error("ninja action doesn't support this kind of target " .. cfg.kind) |