Skip to content

Commit 1b36378

Browse files
committed
Ninja exporter: C, C++, and multiple project types
1 parent 9d5bbf6 commit 1b36378

File tree

12 files changed

+2845
-533
lines changed

12 files changed

+2845
-533
lines changed

contrib/mbedtls/Makefile

Lines changed: 663 additions & 198 deletions
Large diffs are not rendered by default.

modules/ninja/_manifest.lua

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1+
--
2+
-- _manifest.lua
3+
-- Define the ninja manifest
4+
-- Author: Nick Clark
5+
-- Copyright (c) 2025 Jess Perkins and the Premake project
6+
--
7+
8+
19
return {
2-
"_preload.lua",
3-
"ninja.lua",
4-
'ninja_cpp.lua',
5-
'ninja_workspace.lua',
10+
"_preload.lua",
11+
"ninja.lua",
12+
'ninja_cpp.lua',
13+
'ninja_workspace.lua',
614
}

modules/ninja/_preload.lua

Lines changed: 56 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,71 +2,73 @@
22
-- _preload.lua
33
-- Define the ninja actions
44
-- Author: Nick Clark
5-
-- Copyright (c) Jess Perkins and the Premake project
5+
-- Copyright (c) 2025 Jess Perkins and the Premake project
66
--
77

88
local p = premake
99
local project = p.project
10+
local getrelative = p.tools.getrelative
1011

1112
newaction {
12-
trigger = "ninja",
13-
shortname = "Ninja",
14-
description = "Generate Ninja build files",
13+
trigger = "ninja",
14+
shortname = "Ninja",
15+
description = "Generate Ninja build files",
1516

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)(),
17+
-- Action Capabilities
18+
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "None" },
19+
valid_languages = { "C", "C++" },
20+
valid_tools = {
21+
cc = {
22+
"gcc",
23+
"clang",
24+
"msc",
25+
"emcc",
26+
"cosmocc",
27+
}
28+
},
29+
toolset = (function()
30+
local target = os.target()
31+
if target == p.MACOSX then
32+
return "clang"
33+
elseif target == p.EMSCRIPTEN then
34+
return "emcc"
35+
elseif target == p.WINDOWS then
36+
return "v143"
37+
else
38+
return "gcc"
39+
end
40+
end)(),
4041

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)
42+
onInitialize = function()
43+
require("ninja")
44+
end,
45+
onWorkspace = function(wks)
46+
p.tools.getrelative = p.modules.ninja.getrelative
47+
p.escaper(p.modules.ninja.esc)
48+
wks.projects = table.filter(wks.projects, function(prj)
49+
return p.action.supports(prj.kind) and prj.kind ~= p.NONE
50+
end)
51+
p.generate(wks, p.modules.ninja.getninjafilename(wks, false), p.modules.ninja.wks.generate)
52+
p.tools.getrelative = getrelative
53+
end,
54+
onProject = function(prj)
55+
p.tools.getrelative = p.modules.ninja.getrelative
56+
p.escaper(p.modules.ninja.esc)
5457

55-
if not p.action.supports(prj.kind) or prj.kind == p.NONE then
56-
return
57-
end
58+
if not p.action.supports(prj.kind) or prj.kind == p.NONE then
59+
return
60+
end
5861

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,
62+
if project.isc(prj) or project.iscpp(prj) then
63+
p.oven.assignObjectSequences(prj)
64+
p.generate(prj, p.modules.ninja.getprjconfigfilename(prj), p.modules.ninja.cpp.generate)
65+
else
66+
p.warn("Ninja does not support the '%s' language. No build file generated for project '%s'.", prj.language, prj.name)
67+
end
68+
p.tools.getrelative = getrelative
69+
end,
6870
}
6971

7072
return function(cfg)
71-
return (_ACTION == "ninja")
73+
return (_ACTION == "ninja")
7274
end

modules/ninja/ninja.lua

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
-- ninja.lua
33
-- Utilities for generating Ninja build files
44
-- Author: Nick Clark
5-
-- Copyright (c) Jess Perkins and the Premake project
5+
-- Copyright (c) 2025 Jess Perkins and the Premake project
66
--
77

88
local p = premake
@@ -14,12 +14,18 @@ local ninja = p.modules.ninja
1414

1515
--
1616
-- Escape a string so it can be written to a Ninja build file.
17+
-- Ninja variables are expanded into shell commands, so we need to escape
18+
-- shell special characters as well as Ninja special characters.
1719
--
1820
function ninja.esc(value)
1921
value = value:gsub("%$", "$$")
2022
value = value:gsub(":", "$:")
2123
value = value:gsub("\n", "$\n")
2224
value = value:gsub(" ", "$ ")
25+
value = value:gsub('%(', '\\(')
26+
value = value:gsub('%)', '\\)')
27+
value = value:gsub('"', '\\"')
28+
2329
return value
2430
end
2531

@@ -32,15 +38,16 @@ end
3238

3339
function ninja.key(cfg)
3440
local name = cfg.project.name
41+
local buildcfg = cfg.buildcfg
3542
if cfg.platform then
36-
return name .. "_" .. cfg.buildcfg .. "_" .. cfg.platform
43+
return name .. "_" .. (buildcfg or "") .. "_" .. cfg.platform
3744
else
38-
return name .. "_" .. cfg.buildcfg
45+
return name .. (buildcfg and ("_" .. buildcfg) or "")
3946
end
4047
end
4148

42-
function ninja.getprjconfigfilename(cfg)
43-
return ninja.key(cfg) .. ".ninja"
49+
function ninja.getprjconfigfilename(prj)
50+
return prj.name .. ".ninja"
4451
end
4552

4653
function ninja.getninjafilename(target, searchprjs)
@@ -62,7 +69,7 @@ function ninja.getninjafilename(target, searchprjs)
6269
if count == 1 then
6370
return "build.ninja"
6471
else
65-
return ".ninja"
72+
return target.name .. ".ninja"
6673
end
6774
end
6875

@@ -75,6 +82,36 @@ function ninja.gettoolset(cfg)
7582
return toolset
7683
end
7784

85+
function ninja.list(value)
86+
if #value > 0 then
87+
return " " .. table.concat(value, " ")
88+
else
89+
return ""
90+
end
91+
end
92+
93+
-- Override tools.getrelative to use workspace-relative paths for Ninja
94+
-- Ninja builds are always executed from the workspace root, so all paths
95+
-- must be relative to the workspace, not the project
96+
function ninja.getrelative(prj, value)
97+
if type(value) == "table" then
98+
local result = {}
99+
for i, name in ipairs(value) do
100+
result[i] = ninja.getrelative(prj, name)
101+
end
102+
return result
103+
else
104+
if value then
105+
local result = value
106+
if path.hasdeferredjoin(result) then
107+
result = path.resolvedeferredjoin(result)
108+
end
109+
-- Use workspace location instead of project location for Ninja
110+
return path.getrelative(prj.workspace.location, result)
111+
end
112+
end
113+
end
114+
78115
include("ninja_cpp.lua")
79116
include("ninja_workspace.lua")
80117

0 commit comments

Comments
 (0)