-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathNinjaBuildTools.lua
More file actions
304 lines (240 loc) · 10.7 KB
/
Copy pathNinjaBuildTools.lua
File metadata and controls
304 lines (240 loc) · 10.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
local ffi = require("ffi")
local format = string.format
local isWindows = (ffi.os == "Windows")
local isMacOS = (ffi.os == "OSX")
local GCC_RELEASE_FLAGS = "-O0 -DNDEBUG"
local GCC_DEBUG_FLAGS = "" -- None, for now (add -g -ggdb here as needed)
local GCC_DIAGNOSTICS_FLAGS =
"-Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter -fvisibility=hidden -fno-strict-aliasing -fdiagnostics-color -Wfatal-errors"
local DEFAULT_COMPILER_FLAGS = format("%s %s %s", GCC_RELEASE_FLAGS, GCC_DEBUG_FLAGS, GCC_DIAGNOSTICS_FLAGS)
local C_BuildTools = {
OBJECT_FILE_EXTENSION = (isWindows and "obj" or "o"),
STATIC_LIBRARY_EXTENSION = (isWindows and ".lib" or ".a"),
SHARED_LIBRARY_EXTENSION = (isWindows and ".dll" or ".so"),
EXECUTABLE_FILE_EXTENSION = (isWindows and ".exe" or ""),
DEFAULT_BUILD_DIRECTORY_NAME = "ninjabuild-" .. (isWindows and "windows" or "unix"),
GCC_COMPILATION_SETTINGS = {
displayName = "GNU Compiler Collection",
C_COMPILER = "gcc",
CPP_COMPILER = "g++",
COMPILER_FLAGS_CPP = DEFAULT_COMPILER_FLAGS .. " -std=c++20",
-- Forced ObjC compilation should be removed once glfw3webgpu is merged into the GLFW core library
COMPILER_FLAGS_C = DEFAULT_COMPILER_FLAGS .. " -std=c11" .. (isMacOS and " -ObjC" or ""),
C_LINKER = "gcc",
CPP_LINKER = "g++",
-- Must export the entry point of bytecode objects so that LuaJIT can load them via require()
LINKER_FLAGS = isWindows and "-Wl,--export-all-symbols" or "-rdynamic",
C_ARCHIVER = "ar",
CPP_ARCHIVER = "ar",
ARCHIVER_FLAGS = "-rcs",
},
SEMANTIC_VERSION_STRING_PATTERN = "(v(%d+)%.(%d+)%.(%d+).*)", --vMAJOR.MINOR.PATCH-optionalGitDescribeSuffix
GITHUB_REPOSITORY_URL = "https://github.com/evo-lua/evo-runtime",
CHANGELOG_FILE_PATH = "CHANGELOG.MD",
PROJECT_AUTHORS = {
-- Commits with these names won't be listed as external contributions in the auto-generated changelog
"Duckwhale",
"RDW",
"rdw-software",
},
}
function C_BuildTools.GetStaticLibraryName(libraryBaseName)
return (isWindows and "" or "lib") .. libraryBaseName .. C_BuildTools.STATIC_LIBRARY_EXTENSION
end
function C_BuildTools.GetSharedLibraryName(libraryBaseName)
return (isWindows and "" or "lib") .. libraryBaseName .. C_BuildTools.SHARED_LIBRARY_EXTENSION
end
function C_BuildTools.GetExecutableName(libraryBaseName)
return libraryBaseName .. C_BuildTools.EXECUTABLE_FILE_EXTENSION
end
function C_BuildTools.GetOutputFromShellCommand(shellCommand)
local file = assert(io.popen(shellCommand, "r"))
file:flush() -- Required to prevent receiving only partial output
local output = file:read("*all")
file:close()
return output
end
local function explode(inputString, delimiter)
delimiter = delimiter or "%s"
local tokens = {}
for token in string.gmatch(inputString, "([^" .. delimiter .. "]+)") do
table.insert(tokens, token)
end
return tokens
end
function C_BuildTools.DiscoverSharedLibraries(packageNames)
local pkgConfigCommand = "pkg-config --libs-only-l " .. packageNames
local output = C_BuildTools.GetOutputFromShellCommand(pkgConfigCommand)
return output
end
function C_BuildTools.DiscoverIncludeDirectories(packageNames)
local pkgConfigCommand = "pkg-config --cflags-only-I " .. packageNames .. ' | tr " " "\n" | sed \'s/^-I//\''
local output = C_BuildTools.GetOutputFromShellCommand(pkgConfigCommand)
return explode(output, "\n")
end
function C_BuildTools.DiscoverPreviousGitVersionTag()
-- Need to exclude non-versioned tags, but git tag can't do the filtering by itself...
local gitDescribeCommand = 'git describe --tags --abbrev=0 --match "v[0-9]*.[0-9]*.[0-9]*" HEAD~1'
local versionTag = C_BuildTools.GetOutputFromShellCommand(gitDescribeCommand)
-- Strip final newline since that's not very useful outside of the shell
versionTag = string.sub(versionTag, 0, string.len(versionTag) - 1)
return versionTag
end
function C_BuildTools.DiscoverGitVersionTag()
-- Need to exclude non-versioned tags
local gitDescribeCommand = "git describe --tags --match='v[0-9]*.[0-9]*.[0-9]*'"
local versionTag = C_BuildTools.GetOutputFromShellCommand(gitDescribeCommand)
-- Strip final newline since that's not very useful outside of the shell
versionTag = string.sub(versionTag, 0, string.len(versionTag) - 1)
return versionTag
end
function C_BuildTools.DiscoverMergeCommitsBetween(oldVersion, newVersion)
if oldVersion == newVersion then
return {}
end
-- This is the format string used by NodeJS changelogs, but modified to display shorter hashes
local gitDescribeCommand = "git log "
.. oldVersion
.. "..."
.. newVersion
.. " --merges --pretty='format:* \\[[`%h`]("
.. C_BuildTools.GITHUB_REPOSITORY_URL
.. "/commit/%H)] - %b'"
local commits = C_BuildTools.GetOutputFromShellCommand(gitDescribeCommand)
commits = string.explode(commits, "\n") -- By default, Git outputs one commit per line
return commits
end
function C_BuildTools.DiscoverCommitAuthorsBetween(oldVersion, newVersion)
local gitLogCommand = 'git log --pretty=format:"%an" ' .. oldVersion .. ".." .. newVersion .. " | sort | uniq"
local committers = C_BuildTools.GetOutputFromShellCommand(gitLogCommand)
committers = string.explode(committers, "\n") -- By default, git log outputs one entry per line
return committers
end
-- This would be cleaner if we kept the PROJECT_AUTHORS as an array, but then we'd still need to iterate and check the values...
local function convertArrayToSet(arrayTable)
local setTable = {}
for index, value in ipairs(arrayTable) do
setTable[value] = true
end
return setTable
end
function C_BuildTools.DiscoverExternalContributorsBetween(oldVersion, newVersion)
local committers = C_BuildTools.DiscoverCommitAuthorsBetween(oldVersion, newVersion)
local externalContributors = {}
for index, authorName in ipairs(committers) do -- Conveniently already sorted alphabetically if we use ipairs after piping to sort
local isProjectAuthor = convertArrayToSet(C_BuildTools.PROJECT_AUTHORS)[authorName]
-- The changelog should list all external contributors, to show appreciation for their work
-- No point in self-aggrandizing by adding the project authors (i.e., myself) to every change log...
if not isProjectAuthor then
externalContributors[#externalContributors + 1] = authorName
end
end
return externalContributors
end
function C_BuildTools.GetChangelogEntry(oldVersion, newVersion)
local notableChanges = C_BuildTools.FetchNotableChanges(newVersion)
if not notableChanges then
return {}
end
local changelogEntry = {
versionTag = newVersion,
newFeatures = notableChanges.newFeatures or {},
improvements = notableChanges.improvements or {},
breakingChanges = notableChanges.breakingChanges or {},
pullRequests = C_BuildTools.DiscoverMergeCommitsBetween(oldVersion, newVersion) or {},
contributors = notableChanges.contributors
or C_BuildTools.DiscoverExternalContributorsBetween(oldVersion, newVersion),
}
return changelogEntry
end
function C_BuildTools.FetchNotableChanges(versionTag)
-- Defer loading since this isn't generally useful and might take up more space eventually
local notableChanges = require("changelog")
return notableChanges[versionTag] or {}
end
-- This is screaming to get out and become its own class, but for the time being it shall remain imprisoned...
local function markdownFile_AddCategory(markdownFile, category)
if #category.entries == 0 then
-- We don't want to list empty categories now, do we?
return markdownFile
end
markdownFile = markdownFile .. format("### %s\n\n", category.name)
for k, v in ipairs(category.entries) do
markdownFile = markdownFile .. "* " .. v .. "\n"
end
markdownFile = markdownFile .. "\n"
return markdownFile
end
function C_BuildTools.StringifyChangelogContents(changelogEntry)
local markdownFile = "# " .. changelogEntry.versionTag .. "\n\n"
local changelogCategories = {
-- The order that categories appear in is important, so this has to be an array (even if it's more verbose)
{
name = "Breaking Changes",
entries = changelogEntry.breakingChanges,
},
{
name = "New Features",
entries = changelogEntry.newFeatures,
},
{
name = "Improvements",
entries = changelogEntry.improvements,
},
}
for index, category in ipairs(changelogCategories) do
markdownFile = markdownFile_AddCategory(markdownFile, category)
end
-- The format for pull requests is derived from git console output, so let's not touch that (fow now)
markdownFile = markdownFile .. "### Pull Requests\n\n" .. table.concat(changelogEntry.pullRequests, "\n") .. "\n\n"
markdownFile = markdownFile .. "#### Contributors (in alphabetical order)\n\n"
if #changelogEntry.contributors == 0 then
markdownFile = markdownFile .. "* No external contributors"
end
-- This is also somewhat messy due to the PRs needing to be displayed first - for now it'll have to do though
local contributors = { name = "Contributors (in alphabetical order)", entries = changelogEntry.contributors }
markdownFile = markdownFile_AddCategory(markdownFile, contributors)
return markdownFile
end
function C_BuildTools.GenerateChangeLog(from, to)
local transform = require("transform")
local currentVersionTag = C_BuildTools.DiscoverGitVersionTag()
local previousVersionTag = C_BuildTools.DiscoverPreviousGitVersionTag()
previousVersionTag = from or previousVersionTag
currentVersionTag = to or currentVersionTag
print("Generating changelog for release " .. transform.green(currentVersionTag))
print(
"Including changes from " .. transform.green(previousVersionTag) .. " to " .. transform.green(currentVersionTag)
)
local changes = C_BuildTools.GetChangelogEntry(previousVersionTag, currentVersionTag)
local markdownChanges = C_BuildTools.StringifyChangelogContents(changes)
print("Changelog summary:")
local numPullRequests = #changes.pullRequests
if numPullRequests == 0 then
numPullRequests = "NO"
end
local numFeatures = #changes.newFeatures
if numFeatures == 0 then
numFeatures = "NO"
end
local numImprovements = #changes.improvements
if numImprovements == 0 then
numImprovements = "NO"
end
local numBreakingChanges = #changes.breakingChanges
if numBreakingChanges == 0 then
numBreakingChanges = "NO"
end
local numContributors = #changes.contributors
if numContributors == 0 then
numContributors = "NO"
end
printf("* %s new feature%s", numFeatures, numFeatures == 1 and "" or "s")
printf("* %s improvement%s", numImprovements, numImprovements == 1 and "" or "s")
printf("* %s breaking change%s", numBreakingChanges, numBreakingChanges == 1 and "" or "s")
printf("* %s pull request%s", numPullRequests, numPullRequests == 1 and "" or "s")
printf("* %s external contributor%s", numContributors, numContributors == 1 and "" or "s")
print("Saving changelog as " .. transform.green(C_BuildTools.CHANGELOG_FILE_PATH))
C_FileSystem.WriteFile(C_BuildTools.CHANGELOG_FILE_PATH, markdownChanges)
end
return C_BuildTools