Skip to content

Commit 5b2c3f7

Browse files
committed
Continued implementation of usage and use
1 parent 855d0b3 commit 5b2c3f7

File tree

9 files changed

+859
-272
lines changed

9 files changed

+859
-272
lines changed

contrib/mbedtls/Makefile

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

premake5.lua

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,11 +382,21 @@ if premake.action.supports("None") then
382382

383383
files ".github/**"
384384

385+
usage "SomeOtherUsage"
386+
defines { "SOME_OTHER" }
387+
388+
usage "DebugOnlyUsage"
389+
defines { "DEBUG_ONLY" }
390+
385391
usage "PUBLIC"
386392
defines { "PUBLIC_GITHUB" }
393+
uses { "SomeOtherUsage" }
387394
filter { "configurations:Release" }
388395
defines { "PUBLIC_GITHUB_RELEASE" }
389396
includedirs { "/test/1/2/3" }
397+
filter { "configurations:Debug" }
398+
uses { "DebugOnlyUsage" }
399+
filter {}
390400

391401
usage "RandomName"
392402
defines { "RANDOM_DANCING" }

src/_premake_init.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1185,7 +1185,7 @@
11851185
api.register {
11861186
name = "uses",
11871187
scope = "config",
1188-
kind = "table"
1188+
kind = "list:string",
11891189
}
11901190

11911191

src/base/oven.lua

Lines changed: 82 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@
356356
context.addFilter(self, "architecture", self.architecture)
357357
context.addFilter(self, "tags", self.tags)
358358

359-
self.usage = usage
359+
self.usage = self
360360

361361
self.environ = {
362362
wks = prj.workspace,
@@ -394,6 +394,8 @@
394394
local buildcfg = pairing[1]
395395
local platform = pairing[2]
396396
local cfg = oven.bakeConfig(wks, prj, buildcfg, platform, nil, self)
397+
cfg.usage = self
398+
cfg._isusage = true
397399

398400
if p.action.supportsconfig(p.action.current(), cfg) then
399401
self.configs[(buildcfg or "*") .. (platform or "")] = cfg
@@ -950,93 +952,101 @@
950952
end
951953
end
952954

953-
local function applyUsage(prj, usage)
954-
-- For each configuration in the project, apply the corresponding configuration from the usage block
955-
for cfg in p.project.eachconfig(prj) do
956-
-- Merge the usage block into the project configuration
957-
-- If the type of a field contains files, ensure the files are applied relative to the usage block's location
958-
-- instead of target configuration's location
959-
960-
-- Find the usage configuration that corresponds to the project configuration
961-
local match = p.project.findClosestMatch(usage, cfg.buildcfg, cfg.platform)
962-
if match then
963-
-- Merge the usage configuration into the project configuration
964-
verbosef(' Applying usage %s:%s:%s to %s:%s', usage.project.name, usage.name, cfg.shortname, prj.name, cfg.shortname)
965-
buildAppliedPropertyTable(prj, match)
966-
end
967-
end
968-
end
955+
local function fetchPropertiesToApply(src, tgt)
956+
local properties = {}
957+
local srcprj = src.project
969958

959+
verbosef('Applying properties from %s:%s to %s:%s', srcprj.name, src.name, tgt.project.name, tgt.shortname)
970960

971-
-- Build a table of all of the usage blocks in the workspace which are not a special
972-
-- case (public, private, interface).
961+
for k, v in pairs(src) do
962+
verbosef('key = %s, value = %s', k, v)
963+
end
973964

974-
verbosef(' Baking usages...')
975-
local usages = {}
976-
for wks in p.global.eachWorkspace() do
977-
for prj in p.workspace.eachproject(wks) do
978-
for _, usage in ipairs(prj.usages or {}) do
979-
verbosef(' Found usage %s:%s:%s', wks.name, prj.name, usage.name)
980-
981-
if not p.usage.isSpecial(usage) then
982-
-- Check if the usage block already exists in the table
983-
local existing = usages[usage.name]
984-
if not existing then
985-
usages[usage.name] = usage
986-
else
987-
p.warn('Usage with name %s already exists in the workspace.')
988-
end
965+
return properties
966+
end
967+
968+
local function collectUsages(cfg)
969+
local uses = {}
970+
971+
for _, use in ipairs(cfg.uses or {}) do
972+
-- Find a usage block that matches the usage name
973+
local namematch = p.usage.findglobal(use)
974+
for i = 1, #namematch do
975+
local usagecfg = p.project.findClosestMatch(namematch[i], cfg.buildcfg, cfg.platform)
976+
977+
if usagecfg then
978+
-- Apply the usage block to the project configuration
979+
local children = collectUsages(usagecfg)
980+
uses = table.join(uses, children)
981+
else
982+
p.warnOnce('no-such-usage:' .. use, "Usage '%s' not found in project '%s'", use, cfg.project.name)
989983
end
990984
end
985+
986+
if #namematch > 0 then
987+
table.insert(uses, use) -- Add use to the end, to preserve walking order
988+
else
989+
p.warnOnce('no-such-usage:' .. use, "Usage '%s' not found in project '%s'", use, cfg.project.name)
990+
end
991991
end
992+
993+
return uses
992994
end
993995

996+
local function collectSpecialUsages(usage, cfg)
997+
local usagecfg = p.project.findClosestMatch(usage, cfg.buildcfg, cfg.platform)
998+
if usagecfg then
999+
local result = {}
1000+
local children = collectUsages(usagecfg)
1001+
1002+
local uses = table.translate(children, function(use)
1003+
return p.usage.findglobal(use)
1004+
end)
1005+
1006+
result = table.join(result, uses)
1007+
result = table.insert(result, usage)
1008+
1009+
return result
1010+
end
1011+
1012+
return {}
1013+
end
1014+
1015+
verbosef(' Baking usages...')
1016+
9941017
for wks in p.global.eachWorkspace() do
9951018
for prj in p.workspace.eachproject(wks) do
996-
-- Check if the project has a PRIVATE or PUBLIC block
997-
-- PUBLIC is applied to all, PRIVATE is applied to the project only
998-
local publicusage = p.project.findusage(prj, p.usage.PUBLIC)
999-
local interfaceusage = p.project.findusage(prj, p.usage.INTERFACE)
1000-
1001-
if publicusage then
1002-
applyUsage(prj, publicusage)
1003-
end
1019+
for cfg in p.project.eachconfig(prj) do
1020+
local usenames = collectUsages(cfg)
1021+
local uses = table.translate(usenames, function(use)
1022+
return p.usage.findglobal(use)
1023+
end)
1024+
1025+
-- Find a public usage block for the current project
1026+
local publicusage = p.project.findusage(prj, p.usage.PUBLIC)
1027+
if publicusage then
1028+
local children = collectSpecialUsages(publicusage, cfg)
1029+
uses = table.join(uses, children)
1030+
end
10041031

1005-
if interfaceusage then
1006-
applyUsage(prj, interfaceusage)
1007-
end
1032+
-- Find a private usage block for the current project
1033+
local privateusage = p.project.findusage(prj, p.usage.PRIVATE)
1034+
if privateusage then
1035+
local children = collectSpecialUsages(privateusage, cfg)
1036+
uses = table.join(uses, children)
1037+
end
10081038

1009-
local uses = prj.uses or {}
1010-
for _, usagename in ipairs(uses) do
1011-
-- Search priority:
1012-
-- 1. Search for a project with the same name as the usage
1013-
-- 2. Search for a usage with the same name as the usage
1014-
-- 3. Present a warning if no project or usage is found
1015-
1016-
local tgt = p.workspace.findproject(wks, usagename)
1017-
if tgt then
1018-
-- In the case of a project, search for public and interface blocks
1019-
local publicusage = p.project.findusage(tgt, p.usage.PUBLIC) -- public block
1020-
local interfaceusage = p.project.findusage(tgt, p.usage.INTERFACE) -- interface block
1021-
1022-
if publicusage then
1023-
applyUsage(prj, publicusage)
1024-
end
1039+
local allprops = {}
10251040

1026-
if interfaceusage then
1027-
applyUsage(prj, interfaceusage)
1028-
end
1029-
else
1030-
local usage = usages[usagename]
1031-
if usage then
1032-
applyUsage(prj, usage)
1033-
else
1034-
-- Present a warning if no project or usage is found
1035-
p.warn('Project %s uses %s, but no project or usage with that name was found', prj.name, usagename)
1041+
for _, usage in ipairs(uses) do
1042+
local props = fetchPropertiesToApply(usage[1], cfg)
1043+
1044+
-- Handle duplicate properties
1045+
for key, value in pairs(props) do
1046+
allprops[key] = p.field.store(p.fields[key], allprops[key], value)
10361047
end
10371048
end
10381049
end
10391050
end
1040-
10411051
end
10421052
end

src/base/project.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@
575575
function project.findusage(self, name)
576576
name = name:lower()
577577

578-
for _, usage in ipairs(self.usages) do
578+
for _, usage in ipairs(self.usages or self.project.usages) do
579579
if name == usage.name:lower() then
580580
return usage
581581
end

src/base/usage.lua

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,39 @@
4242
function usage.isSpecial(self)
4343
return self.name == usage.PUBLIC or self.name == usage.PRIVATE or self.name == usage.INTERFACE
4444
end
45+
46+
47+
function usage.findglobal(name)
48+
-- First, try to find a project with the provided name in the global scope
49+
for wks in p.global.eachWorkspace() do
50+
-- For each workspace, check if a project with the provided name exists
51+
local prj = p.workspace.findproject(wks, name)
52+
if prj then
53+
-- Check if the project has a public or interface usage
54+
local publicUsage = p.project.findusage(prj, usage.PUBLIC)
55+
local interfaceUsage = p.project.findusage(prj, usage.INTERFACE)
56+
57+
local result = {}
58+
if publicUsage then
59+
table.insert(result, publicUsage)
60+
end
61+
62+
if interfaceUsage then
63+
table.insert(result, interfaceUsage)
64+
end
65+
66+
return result
67+
end
68+
69+
-- If no project with a matching name was found, check each project to see if it has a usage
70+
-- with the provided name
71+
for prj in p.workspace.eachproject(wks) do
72+
local usage = p.project.findusage(prj, name)
73+
if usage then
74+
return { usage }
75+
end
76+
end
77+
end
78+
79+
return {}
80+
end

website/docs/usage.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
Specifies a reusable block of configuration to be consumed at a later point.
2+
3+
```lua
4+
usage 'MyUsage'
5+
defines { 'MY_DEFINE' }
6+
```
7+
8+
The `usage` API is used to define configuration to be consumed by the `uses` API. Usages must have unique names, except for magic usage block names (as described below).
9+
10+
### Magic Usage Blocks ###
11+
12+
1. `PRIVATE` - Private specifies a configuration to be automatically applied to the project defining the `usage` block. This block is inaccessible to be consumed by `uses`.
13+
2. `INTERFACE` - Interface has the opposite meaning as private usages. An interface usage is applied only to those projects consuming it via `uses`. Interface usage blocks are consumed by specfiying the containing project's name in the `uses` list.
14+
3. `PUBLIC` - Public specifies a configuration to be automatically applied to the project defining the `usage` block and any project consuming it via `uses`. Like `INTERFACE`, it is consumed by specifying the name of the project it is defined in.
15+
16+
If projects define both an `INTERFACE` and `PUBLIC` usage block, both blocks will be applied to any project consuming that project.
17+
18+
### Example ###
19+
20+
```lua
21+
project 'A'
22+
usage 'PRIVATE'
23+
defines { 'A_PRIVATE' }
24+
usage 'PUBLIC'
25+
defines { 'A_PUBLIC' }
26+
usage 'NotMagic'
27+
defines { 'A_NOT_MAGIC' }
28+
29+
project 'B'
30+
uses { 'NotMagic' } -- Applies usage NotMagic from A
31+
32+
usage 'PUBLIC'
33+
uses { 'A' } -- Applies PUBLIC from A to self and to any project consuming B
34+
```
35+
36+
### Applies To ###
37+
38+
Project configurations.
39+
40+
### See Also ###
41+
42+
* [uses](uses.md)

website/docs/uses.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Specifies which usage blocks a project should consume.
2+
3+
```lua
4+
uses { "ProjectA" }
5+
```
6+
7+
The `uses` API is used to consume `usage` blocks from within a project.
8+
9+
### Usage resolve priority ###
10+
11+
1. `PUBLIC` and `INTERFACE` usage scopes within a project of the corresponding name.
12+
2. `usage` blocks with the corresponding name in any scopes.
13+
14+
Note: If there are duplicate usage blocks with the same resolved name, the selected usage block is unspecified. `usage` blocks should have unique names if they are not specified as `PUBLIC`, `PRIVATE`, or `INTERFACE`.
15+
16+
### Applies To ###
17+
18+
Projects and usage configurations.
19+
20+
### See Also ###
21+
22+
* [usage](usage.md)

website/sidebars.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,10 @@ module.exports = {
271271
'toolset',
272272
'toolsversion',
273273
'undefines',
274+
'usage',
274275
'unsignedchar',
275276
'usefullpaths',
277+
'uses',
276278
'usestandardpreprocessor',
277279
'usingdirs',
278280
'uuid',

0 commit comments

Comments
 (0)