Skip to content

Commit a0e9d3d

Browse files
committed
Groundwork for Ninja exporter
1 parent 663eb34 commit a0e9d3d

File tree

9 files changed

+607
-9
lines changed

9 files changed

+607
-9
lines changed

modules/ninja/_manifest.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
return {
2+
"_preload.lua",
3+
"ninja.lua",
4+
'ninja_cpp.lua',
5+
'ninja_workspace.lua',
6+
}

modules/ninja/_preload.lua

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
--
2+
-- _preload.lua
3+
-- Define the ninja actions
4+
-- Author: Nick Clark
5+
-- Copyright (c) Jess Perkins and the Premake project
6+
--
7+
8+
local p = premake
9+
local project = p.project
10+
11+
newaction {
12+
trigger = "ninja",
13+
shortname = "Ninja",
14+
description = "Generate Ninja build files",
15+
16+
-- Action Capabilities
17+
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "None" },
18+
valid_languages = { "C", "C++" },
19+
valid_tools = {
20+
cc = {
21+
"gcc",
22+
"clang",
23+
"msc",
24+
"emcc",
25+
"cosmocc",
26+
}
27+
},
28+
toolset = (function()
29+
local target = os.target()
30+
if target == p.MACOSX then
31+
return "clang"
32+
elseif target == p.EMSCRIPTEN then
33+
return "emcc"
34+
elseif target == p.WINDOWS then
35+
return "v143"
36+
else
37+
return "gcc"
38+
end
39+
end)(),
40+
41+
-- Workspace and project generation functions
42+
onInitialize = function()
43+
require("ninja")
44+
end,
45+
onWorkspace = function(wks)
46+
p.escaper(p.modules.ninja.esc)
47+
wks.projects = table.filter(wks.projects, function(prj)
48+
return p.action.supports(prj.kind) and prj.kind ~= p.NONE
49+
end)
50+
p.generate(wks, p.modules.ninja.getninjafilename(wks, false), p.modules.ninja.wks.generate)
51+
end,
52+
onProject = function(prj)
53+
p.escaper(p.modules.ninja.esc)
54+
55+
if not p.action.supports(prj.kind) or prj.kind == p.NONE then
56+
return
57+
end
58+
59+
if project.isc(prj) or project.iscpp(prj) then
60+
for cfg in project.eachconfig(prj) do
61+
local filename = p.modules.ninja.getprjconfigfilename(cfg)
62+
p.generate(prj, filename, p.modules.ninja.cpp.generate)
63+
end
64+
else
65+
p.warn("Ninja does not support the '%s' language. No build file generated for project '%s'.", prj.language, prj.name)
66+
end
67+
end,
68+
}
69+
70+
return function(cfg)
71+
return (_ACTION == "ninja")
72+
end

modules/ninja/ninja.lua

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
--
2+
-- ninja.lua
3+
-- Utilities for generating Ninja build files
4+
-- Author: Nick Clark
5+
-- Copyright (c) Jess Perkins and the Premake project
6+
--
7+
8+
local p = premake
9+
10+
p.modules.ninja = {}
11+
p.modules.ninja._VERSION = p._VERSION
12+
13+
local ninja = p.modules.ninja
14+
15+
--
16+
-- Escape a string so it can be written to a Ninja build file.
17+
--
18+
function ninja.esc(value)
19+
value = value:gsub("%$", "$$")
20+
value = value:gsub(":", "$:")
21+
value = value:gsub("\n", "$\n")
22+
value = value:gsub(" ", "$ ")
23+
return value
24+
end
25+
26+
function ninja.header(target)
27+
local kind = iif(target.project, "project", "workspace")
28+
_p("# %s %s Ninja build file generated by Premake", target.name, kind)
29+
_p('ninja_required_version = 1.6')
30+
_p('')
31+
end
32+
33+
function ninja.key(cfg)
34+
local name = cfg.project.name
35+
if cfg.platform then
36+
return name .. "_" .. cfg.buildcfg .. "_" .. cfg.platform
37+
else
38+
return name .. "_" .. cfg.buildcfg
39+
end
40+
end
41+
42+
function ninja.getprjconfigfilename(cfg)
43+
return ninja.key(cfg) .. ".ninja"
44+
end
45+
46+
function ninja.getninjafilename(target, searchprjs)
47+
local count = 0
48+
for wks in p.global.eachWorkspace() do
49+
if wks.location == target.location then
50+
count = count + 1
51+
end
52+
53+
if searchprjs then
54+
for _, prj in ipairs(wks.projects) do
55+
if prj.location == target.location then
56+
count = count + 1
57+
end
58+
end
59+
end
60+
end
61+
62+
if count == 1 then
63+
return "build.ninja"
64+
else
65+
return ".ninja"
66+
end
67+
end
68+
69+
function ninja.gettoolset(cfg)
70+
local default = p.action.current().toolset
71+
local toolset, version = p.tools.canonical(cfg.toolset or default)
72+
if not toolset then
73+
error("No toolset found for '" .. tostring(cfg.toolset) .. "'")
74+
end
75+
return toolset
76+
end
77+
78+
include("ninja_cpp.lua")
79+
include("ninja_workspace.lua")
80+
81+
return ninja

modules/ninja/ninja_cpp.lua

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
local p = premake
2+
local ninja = p.modules.ninja
3+
4+
local tree = p.tree
5+
local project = p.project
6+
7+
p.modules.ninja.cpp = {}
8+
local m = p.modules.ninja.cpp
9+
10+
m.elements = function(cfg)
11+
return {
12+
ninja.header,
13+
m.ccrules,
14+
m.cxxrules,
15+
m.resourcerules,
16+
m.linkrules,
17+
m.pchrules,
18+
m.copyrules,
19+
m.prebuildcommandsrule,
20+
m.prebuildmessagerule,
21+
m.prelinkcommandsrule,
22+
m.prelinkmessagerule,
23+
m.postbuildcommandsrule,
24+
m.postbuildmessagerule,
25+
m.customcommand,
26+
m.buildfiles,
27+
m.linkfiles,
28+
m.prebuildcommands,
29+
m.prebuildmessage,
30+
m.prelinkcommands,
31+
m.prelinkmessage,
32+
m.postbuildcommands,
33+
m.postbuildmessage,
34+
m.phonies,
35+
}
36+
end
37+
38+
function m.generate(cfg)
39+
p.utf8()
40+
p.callArray(m.elements, cfg)
41+
end
42+
43+
function m.ccrules(cfg)
44+
local toolset = ninja.gettoolset(cfg)
45+
local ccname = toolset.gettoolname(cfg, "cc")
46+
_p("rule cc")
47+
48+
if toolset == p.tools.msc then
49+
_p(" command = %s $cflags /nologo /showIncludes -c /Tc$in /Fo$out", ccname)
50+
_p(" deps = msvc")
51+
else
52+
_p(" command = %s $cflags -c $in -o $out", ccname)
53+
_p(" deps = gcc")
54+
end
55+
56+
_p(" description = Compiling C source $in")
57+
_p(" depfile = $out.d")
58+
59+
_p("")
60+
end
61+
62+
function m.cxxrules(cfg)
63+
local toolset = ninja.gettoolset(cfg)
64+
local cxxname = toolset.gettoolname(cfg, "cxx")
65+
_p("rule cxx")
66+
67+
if toolset == p.tools.msc then
68+
_p(" command = %s $cxxflags /nologo /showIncludes -c /Tp$in /Fo$out", cxxname)
69+
_p(" deps = msvc")
70+
else
71+
_p(" command = %s $cxxflags -c $in -o $out", cxxname)
72+
_p(" deps = gcc")
73+
end
74+
75+
_p(" description = Compiling C++ source $in")
76+
_p(" depfile = $out.d")
77+
78+
_p("")
79+
end
80+
81+
function m.resourcerules(cfg)
82+
local toolset = ninja.gettoolset(cfg)
83+
local rcname = toolset.gettoolname(cfg, "rc")
84+
85+
_p("rule rc")
86+
87+
if toolset == p.tools.msc then
88+
_p(" command = %s /nologo /fo$out $in $resflags", rcname)
89+
else
90+
_p(" command = %s -i $in -o $out $resflags", rcname)
91+
end
92+
93+
_p(" description = Compiling resource $in")
94+
_p("")
95+
end
96+
97+
function m.linkrules(cfg)
98+
local toolset = ninja.gettoolset(cfg)
99+
100+
if toolset == p.tools.msc then
101+
if cfg.kind == p.STATICLIB then
102+
local arname = toolset.gettoolname(cfg, "ar")
103+
_p("rule ar")
104+
_p(" command = %s $in /nologo -OUT:$out", arname)
105+
_p(" description = Archiving static library $out")
106+
_p("")
107+
else
108+
local ldname = toolset.gettoolname(cfg, iif(cfg.language == "C", "cc", "cxx"))
109+
_p("rule link")
110+
_p(" command = %s $in $links /link $ldflags /nologo /out:$out", ldname)
111+
_p(" description = Linking target $out")
112+
_p("")
113+
end
114+
else
115+
if cfg.kind == p.STATICLIB then
116+
local arname = toolset.gettoolname(cfg, "ar")
117+
_p("rule ar")
118+
_p(" command = %s -rcs $out $in", arname)
119+
_p(" description = Archiving static library $out")
120+
_p("")
121+
else
122+
local ldname = toolset.gettoolname(cfg, iif(cfg.language == "C", "cc", "cxx"))
123+
local groups = iif(cfg.linkgroups == p.ON, { "-Wl,--start-group", "-Wl,--end-group" }, {"", ""})
124+
125+
-- format the link command
126+
local commands = string.format("command = %s -o $out %s $in $links $ldflags %s", ldname, groups[1], groups[2]);
127+
128+
-- remove any excess whitespace
129+
commands = commands:gsub("^%s*(.-)%s*$", "%1")
130+
commands = commands:gsub("%s+", " ")
131+
132+
_p("rule link")
133+
_p(" %s", commands)
134+
_p(" description = Linking target $out")
135+
_p("")
136+
end
137+
end
138+
end
139+
140+
function m.pchrules(cfg)
141+
end
142+
143+
function m.copyrules(cfg)
144+
end
145+
146+
function m.prebuildcommandsrule(cfg)
147+
end
148+
149+
function m.prebuildmessagerule(cfg)
150+
end
151+
152+
function m.prelinkcommandsrule(cfg)
153+
end
154+
155+
function m.prelinkmessagerule(cfg)
156+
end
157+
158+
function m.postbuildcommandsrule(cfg)
159+
end
160+
161+
function m.postbuildmessagerule(cfg)
162+
end
163+
164+
function m.customcommand(cfg)
165+
end
166+
167+
function m.buildfiles(cfg)
168+
end
169+
170+
function m.linkfiles(cfg)
171+
end
172+
173+
function m.prebuildcommands(cfg)
174+
end
175+
176+
function m.prebuildmessage(cfg)
177+
end
178+
179+
function m.prelinkcommands(cfg)
180+
end
181+
182+
function m.prelinkmessage(cfg)
183+
end
184+
185+
function m.postbuildcommands(cfg)
186+
end
187+
188+
function m.postbuildmessage(cfg)
189+
end
190+
191+
function m.phonies(cfg)
192+
end

modules/ninja/ninja_workspace.lua

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
local p = premake
2+
local ninja = p.modules.ninja
3+
4+
local tree = p.tree
5+
local project = p.project
6+
7+
p.modules.ninja.wks = {}
8+
local m = p.modules.ninja.wks
9+
10+
m.elements = function(wks)
11+
return {
12+
ninja.header,
13+
}
14+
end
15+
16+
function m.generate(wks)
17+
p.utf8()
18+
p.callArray(m.elements, wks)
19+
end

modules/ninja/tests/_tests.lua

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
require("ninja")
2+
3+
return {
4+
"test_build_rules.lua"
5+
}

0 commit comments

Comments
 (0)