mirror of
https://github.com/gbdev/rgbds.git
synced 2026-08-24 15:54:33 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
307846b03e | ||
|
|
e7e671b249 | ||
|
|
0c772ea049 | ||
|
|
6f64fd00f6 | ||
|
|
4384223951 | ||
|
|
4e87f61656 | ||
|
|
9d854114ea | ||
|
|
70d8d67ffc | ||
|
|
ca2b8e4cde | ||
|
|
80c8e77b19 | ||
|
|
604c69e048 | ||
|
|
ec5e6cbabb | ||
|
|
50678d0942 | ||
|
|
c691ec6607 | ||
|
|
c3073f4318 | ||
|
|
e5b03e3cb1 | ||
|
|
0d379e9016 | ||
|
|
9cbfec30c7 | ||
|
|
9def9c9aa8 | ||
|
|
b5681c0d34 | ||
|
|
ec43f06bd9 | ||
|
|
106ec399d5 | ||
|
|
d9c0d37fd5 | ||
|
|
3b1606c63c | ||
|
|
fa49e238a9 | ||
|
|
3426f685a0 | ||
|
|
c0e2f8340b | ||
|
|
8883251bf9 | ||
|
|
f27a8132d9 | ||
|
|
0af28de791 | ||
|
|
8d2275dc48 | ||
|
|
7e11ab4d8f | ||
|
|
e84bcf83b4 | ||
|
|
57c9bab3a5 | ||
|
|
4ada3e85d8 | ||
|
|
ba4a7f2e6a | ||
|
|
b0948566bb | ||
|
|
5aa7067876 | ||
|
|
dff176791c | ||
|
|
07f5969005 | ||
|
|
d61c0561c1 | ||
|
|
b13b0c8eb8 | ||
|
|
ca2de0f429 | ||
|
|
a821badc3e | ||
|
|
cb34fe18f7 | ||
|
|
1ed22cc518 | ||
|
|
9a15b723f2 | ||
|
|
7e2a3491a5 | ||
|
|
e7855ea1b8 | ||
|
|
19e60d9864 | ||
|
|
c0ff3d92ad | ||
|
|
e4583e7ac2 | ||
|
|
5869e0dc60 | ||
|
|
196d50c1d7 | ||
|
|
8b951bc047 | ||
|
|
59b6b15106 | ||
|
|
304cbb464f | ||
|
|
ea3a8ee171 | ||
|
|
f0419eb183 | ||
|
|
4a6ea35299 | ||
|
|
08354cf573 | ||
|
|
417b5212d4 | ||
|
|
66312f55dd | ||
|
|
21eaa2d2cc | ||
|
|
e9fa1e4e94 | ||
|
|
8ab6190f96 | ||
|
|
22bd8a9bd5 | ||
|
|
96bc58b7f7 | ||
|
|
4857ad1e00 | ||
|
|
3b33c942ae | ||
|
|
5525dd902b | ||
|
|
4350a3252d | ||
|
|
a8442bccc7 | ||
|
|
00006a9d00 | ||
|
|
a383bec96e | ||
|
|
226031c18b | ||
|
|
24a896f60a | ||
|
|
a6f5e3efd1 | ||
|
|
c02b234bb1 | ||
|
|
be4c1161bd | ||
|
|
0e1e5e80f6 | ||
|
|
118f1f7543 | ||
|
|
eaa35ed26d | ||
|
|
7b39bcd412 | ||
|
|
255cd7f7f6 | ||
|
|
b8011947a8 | ||
|
|
39e7e064c9 | ||
|
|
7b97d7ce15 | ||
|
|
c667bac93a | ||
|
|
db96144d49 | ||
|
|
276a1a7952 | ||
|
|
b219e03b38 | ||
|
|
824ebd80f9 | ||
|
|
5aedf31b46 | ||
|
|
d94d0bcc2f | ||
|
|
ed8e3e4d02 | ||
|
|
30fd4514dc | ||
|
|
08e83601f5 | ||
|
|
e606f4e997 | ||
|
|
9008d8391c | ||
|
|
21682e8814 | ||
|
|
f82b0838a1 | ||
|
|
dabd0a08d2 | ||
|
|
c3e10dbb03 | ||
|
|
3883c2a2b8 | ||
|
|
cd0caaaceb | ||
|
|
1e4a060d9e | ||
|
|
fe3b238dea | ||
|
|
46a6966b70 | ||
|
|
be3fc61859 | ||
|
|
0adbb92e50 | ||
|
|
09da4e001a | ||
|
|
3eb8c7e8f2 | ||
|
|
189c679e13 | ||
|
|
5d5000011a | ||
|
|
f81f5fe63c | ||
|
|
6e643406a2 | ||
|
|
de36a11be7 | ||
|
|
799c55b4dd | ||
|
|
ddd8f37508 | ||
|
|
c55dec254d | ||
|
|
0996a2f5ed | ||
|
|
e3c594c250 | ||
|
|
daba94b495 | ||
|
|
2f604bfa9a | ||
|
|
9bbb2247a7 | ||
|
|
9b4df11473 | ||
|
|
4a77c42ed7 | ||
|
|
b12eac356e | ||
|
|
82702d8149 | ||
|
|
1f9cc9651a | ||
|
|
04b9c7fa3d | ||
|
|
5e8a6cde20 | ||
|
|
d59081a918 | ||
|
|
250a94c588 | ||
|
|
37818a1847 | ||
|
|
0e3d1df129 | ||
|
|
586c3073f9 | ||
|
|
e3fc46f933 | ||
|
|
3941a28661 | ||
|
|
a829e6c067 | ||
|
|
b252877b05 | ||
|
|
22a3625144 | ||
|
|
6cba5518e9 | ||
|
|
caf561457d | ||
|
|
fc7d9ad573 | ||
|
|
0b91bf654b | ||
|
|
6b2b6e6000 | ||
|
|
f72a4d53e2 | ||
|
|
998f636495 | ||
|
|
075f132d77 | ||
|
|
31e1d2ec87 | ||
|
|
673c62414f | ||
|
|
007672f080 | ||
|
|
7eaca1577d | ||
|
|
996469ee28 | ||
|
|
55db252a8f | ||
|
|
cfa0adf295 | ||
|
|
ed19806434 | ||
|
|
a0d96a0856 | ||
|
|
4b992bfea5 | ||
|
|
141a7fe22b | ||
|
|
43ffc89bb4 | ||
|
|
72a410c007 | ||
|
|
090768e2c9 | ||
|
|
5f2ee530b8 | ||
|
|
4a173130b9 | ||
|
|
ef2f021892 | ||
|
|
dce14fd4b8 | ||
|
|
728bed39d5 | ||
|
|
48fcd9a0ca | ||
|
|
1871b0a0b8 | ||
|
|
d56dbbb4bf | ||
|
|
728d14879b | ||
|
|
0ed8c2f8ee | ||
|
|
d5186b088b | ||
|
|
fee177d0b9 | ||
|
|
42e3da837c | ||
|
|
358e8fe636 | ||
|
|
c50a849757 | ||
|
|
57111b219a | ||
|
|
be2d028ae6 | ||
|
|
1af8bdda16 | ||
|
|
fa22b78e7d | ||
|
|
f0161b41c8 | ||
|
|
ca23210f18 | ||
|
|
85e044f5be | ||
|
|
60e76b2da4 | ||
|
|
3c7488c131 | ||
|
|
9fd0c0297f | ||
|
|
c1c7e64249 | ||
|
|
a18b2f1049 | ||
|
|
3f144b7713 | ||
|
|
eeb3a73210 | ||
|
|
37d39f91f6 | ||
|
|
d5ce5329ea | ||
|
|
6bcd79b997 | ||
|
|
decc5f7153 | ||
|
|
a3c953ea46 | ||
|
|
d43049c84d | ||
|
|
b6ff54acc3 | ||
|
|
71fc449452 | ||
|
|
59dd1fbbf8 | ||
|
|
2502d130eb | ||
|
|
a78a268cb4 | ||
|
|
0553491107 | ||
|
|
6edac50cc4 | ||
|
|
77dceaf43a | ||
|
|
cfec017fed | ||
|
|
12186fdccc | ||
|
|
71dfab3365 | ||
|
|
20b11039c9 | ||
|
|
eb9e9c0f33 | ||
|
|
ac2a022124 | ||
|
|
1249c4ef58 | ||
|
|
aeedfb35a6 | ||
|
|
63609871f4 | ||
|
|
393eaa9dc1 | ||
|
|
b3c3981a90 | ||
|
|
185a5c5369 | ||
|
|
4ea15ed85a | ||
|
|
b218fd65a0 | ||
|
|
81edc27b6e | ||
|
|
dc52487d31 | ||
|
|
6b994b1737 | ||
|
|
0849eb801e | ||
|
|
e6916360f4 | ||
|
|
a802bcb320 | ||
|
|
846aa975f1 | ||
|
|
b65649ca73 | ||
|
|
62ddabb570 | ||
|
|
d48d6fe5d9 | ||
|
|
ac0f93ffda | ||
|
|
a1712cb6d9 | ||
|
|
2968bee86f | ||
|
|
dec7a74166 | ||
|
|
9c4e53d1c4 | ||
|
|
463edc3c01 | ||
|
|
73941c3249 | ||
|
|
7596ae67b5 | ||
|
|
fc08ab6aee | ||
|
|
c7663423d6 | ||
|
|
1ff73cd5e0 | ||
|
|
65ec1af1e8 | ||
|
|
bc3572ec37 | ||
|
|
78281a4aaa | ||
|
|
6e51ab6f55 | ||
|
|
52aaf7e3b3 | ||
|
|
09db4f25dd | ||
|
|
fed5db7743 | ||
|
|
c6dbec7830 | ||
|
|
017b0119e6 | ||
|
|
0e6e91d048 | ||
|
|
df0b557638 | ||
|
|
123201ecc6 | ||
|
|
422e8eec20 | ||
|
|
49a4da2235 | ||
|
|
4577ff16bc | ||
|
|
b430d5a8b8 | ||
|
|
a5be1d886e | ||
|
|
c3b47abcc8 | ||
|
|
2cfb2b2533 | ||
|
|
187e1a55b8 | ||
|
|
143d503c6c | ||
|
|
6e13779b8b | ||
|
|
ace2f3e613 | ||
|
|
8d1a60d6b5 | ||
|
|
11ac22d8f5 | ||
|
|
812e1f6d4b | ||
|
|
8dc052475b | ||
|
|
133eaa4e92 | ||
|
|
57f1894fbd | ||
|
|
021fe01eb0 | ||
|
|
9b4b4a581b | ||
|
|
bcff14b596 | ||
|
|
11f6278d95 | ||
|
|
ede9405daf | ||
|
|
25bf0e9e2c | ||
|
|
167a7ee80c | ||
|
|
4ce4162da4 | ||
|
|
18b074711e | ||
|
|
44b6a2c453 | ||
|
|
3fc3130364 | ||
|
|
5090395ca7 | ||
|
|
efd4373a56 | ||
|
|
92a31ff7df | ||
|
|
8025c2ae66 | ||
|
|
f7831ce8da | ||
|
|
b736fa22ff | ||
|
|
0692d1d28c | ||
|
|
4b69d5cc8a | ||
|
|
52aa518e20 | ||
|
|
919a5dba89 | ||
|
|
d9932b9031 | ||
|
|
66e521e9e5 | ||
|
|
b8e425b41d | ||
|
|
6b0658fb59 | ||
|
|
91fdfcd179 | ||
|
|
5abebcf61f | ||
|
|
145473d9bd | ||
|
|
2fb64816a9 | ||
|
|
7cf330e3f9 | ||
|
|
2e66515096 | ||
|
|
c93f377bfb | ||
|
|
d6d1844d60 | ||
|
|
fd38a3dbc4 | ||
|
|
60d58723aa | ||
|
|
a9b6cda77b | ||
|
|
091452d591 | ||
|
|
df1d909853 | ||
|
|
fb4e08ce71 | ||
|
|
7244b9d17e | ||
|
|
5c4ca36c5a | ||
|
|
292c297518 | ||
|
|
a5bb431d47 | ||
|
|
10e1c9d187 | ||
|
|
d8722b6705 | ||
|
|
2d0ac7eeb0 | ||
|
|
d5033a2bd9 | ||
|
|
45fff0fd58 | ||
|
|
c963c7b1c7 | ||
|
|
63c7835e71 | ||
|
|
35af3185eb | ||
|
|
db9d9c7653 | ||
|
|
9e5a9107f2 | ||
|
|
275fcf8fcf | ||
|
|
bc37b0ece6 | ||
|
|
e63ce24e48 | ||
|
|
d524884799 | ||
|
|
34e1f8dcc5 | ||
|
|
cd64de9323 | ||
|
|
a01b805e4b | ||
|
|
a139cbc744 | ||
|
|
06e5386d93 | ||
|
|
37f57a752f | ||
|
|
670bdf2095 | ||
|
|
6270f654a1 | ||
|
|
676db46c01 | ||
|
|
8979b54281 | ||
|
|
a6f03530ed | ||
|
|
b56b56a695 | ||
|
|
dc5fc9f327 | ||
|
|
3d35457eeb | ||
|
|
aea39ec8c8 | ||
|
|
9293068370 | ||
|
|
d054f07703 | ||
|
|
65b0b49720 | ||
|
|
48d58ba095 | ||
|
|
af0505b4cd | ||
|
|
7c1e1fe515 | ||
|
|
d053025070 | ||
|
|
ade898d815 | ||
|
|
e738b90c69 | ||
|
|
a91d26192d | ||
|
|
92bfe5d930 | ||
|
|
41fe1d8f25 | ||
|
|
63a911e657 | ||
|
|
a9ab248fed | ||
|
|
9b22ff3491 | ||
|
|
a4af81f250 | ||
|
|
e08de399db | ||
|
|
d4e0ca5f90 | ||
|
|
2666dcbc26 | ||
|
|
27dca5680c | ||
|
|
b0e0dfc56e | ||
|
|
33475e2c36 | ||
|
|
c8161be23a | ||
|
|
2c5c453ab8 | ||
|
|
c3e245c13e | ||
|
|
3631fab63c | ||
|
|
1c00123b33 | ||
|
|
131bb97ebc | ||
|
|
8d6c617875 | ||
|
|
752e2b3620 | ||
|
|
ad3188f038 | ||
|
|
a6eb6457d8 | ||
|
|
0d3276975e | ||
|
|
d961c697d7 | ||
|
|
1eb4eb3339 | ||
|
|
a3d3e1525a | ||
|
|
3553c9c4da | ||
|
|
5c2c893ced | ||
|
|
0f266d1c66 | ||
|
|
8ab4602ae5 | ||
|
|
04e3a904c2 | ||
|
|
395b03e88e | ||
|
|
fb9fa6038c | ||
|
|
35e5808423 | ||
|
|
558d3ca0fc | ||
|
|
df5162edca | ||
|
|
2519d1e698 | ||
|
|
ca383c91ca | ||
|
|
8bedd710d7 | ||
|
|
efb5a88edb | ||
|
|
f065243cd2 | ||
|
|
a0bb830679 | ||
|
|
7654c6e27a | ||
|
|
400375b2e5 | ||
|
|
7462bccb72 | ||
|
|
2873e0b8c8 | ||
|
|
1badba03d8 | ||
|
|
64bcef99bd | ||
|
|
aa672bbec9 | ||
|
|
651877e094 | ||
|
|
26c48cc409 | ||
|
|
23b9039716 | ||
|
|
711fba5e35 | ||
|
|
089fc11e31 | ||
|
|
837f552987 | ||
|
|
cb8c973453 | ||
|
|
cca3794dd0 | ||
|
|
02c2408f58 | ||
|
|
fba0562650 | ||
|
|
0c9920d4a6 | ||
|
|
7733ccdeb6 | ||
|
|
13e85b5151 | ||
|
|
268b586c9d | ||
|
|
85d3b5df58 | ||
|
|
eea277ae9c | ||
|
|
538395b92c | ||
|
|
3108fb5297 | ||
|
|
f99591bf6f | ||
|
|
0297da4d4c | ||
|
|
96b953fe51 | ||
|
|
0670c03bc2 | ||
|
|
09ef5b7e06 | ||
|
|
d5bb462f25 | ||
|
|
b0727e9779 | ||
|
|
ca4b890273 | ||
|
|
96a75500d3 | ||
|
|
634fd853d1 | ||
|
|
c8d22d8744 | ||
|
|
3ece61b103 | ||
|
|
a82fd17529 | ||
|
|
e7f5ab3f55 | ||
|
|
595c87b2f8 | ||
|
|
c49a7d1e2f | ||
|
|
d8aff148bb | ||
|
|
e31bcabbaa | ||
|
|
67741ab428 | ||
|
|
e0a6199f83 | ||
|
|
6cffd991f7 | ||
|
|
1fdeb34e50 | ||
|
|
9f16881d64 | ||
|
|
223b3d1921 | ||
|
|
65d408eb5d | ||
|
|
3677ab2ebf | ||
|
|
d404621e0d | ||
|
|
c8a088f281 | ||
|
|
94ed28acf8 | ||
|
|
00b5077b2a | ||
|
|
024b33b63a | ||
|
|
dcc10cebc3 | ||
|
|
1fc9ba86c4 | ||
|
|
e569e0c200 | ||
|
|
f7fb3af615 | ||
|
|
1dfc1d3231 | ||
|
|
891e6f98df | ||
|
|
bdc885bd69 | ||
|
|
5b67dc94b6 | ||
|
|
4f702a4be8 | ||
|
|
c5d437ab3c | ||
|
|
c5c2800f17 | ||
|
|
c798500563 | ||
|
|
590d113e94 | ||
|
|
ee1db0a582 | ||
|
|
5701d747d4 | ||
|
|
2110aaca20 | ||
|
|
8df88f92ba | ||
|
|
534a4efee4 | ||
|
|
cc96b4d517 | ||
|
|
0ccdbf509a | ||
|
|
531278961f | ||
|
|
85176ef10a | ||
|
|
02b880e1b0 | ||
|
|
c6997fe73c | ||
|
|
c578a7b761 | ||
|
|
8564df51e5 | ||
|
|
62d3b44768 | ||
|
|
ead5337fe0 | ||
|
|
0d509aa65c | ||
|
|
fcfc931867 | ||
|
|
3d155d5695 | ||
|
|
92ed6ece53 | ||
|
|
e0e9ef190a | ||
|
|
386fb5f398 | ||
|
|
94e9ef5213 | ||
|
|
0c4c25b2d2 | ||
|
|
f7167d8115 | ||
|
|
b7e0783ae7 | ||
|
|
77a105e189 | ||
|
|
a16dcc0ea5 | ||
|
|
9f373d49ac | ||
|
|
272019beb0 | ||
|
|
db6793f444 | ||
|
|
ea1358bbe6 | ||
|
|
2bdf61da70 | ||
|
|
92826a726a | ||
|
|
9c3ce69180 | ||
|
|
50d0b101c3 | ||
|
|
1bf1219e07 | ||
|
|
7b405513d9 | ||
|
|
7df9c12a6c | ||
|
|
30a8503dcd | ||
|
|
02310489c6 | ||
|
|
5f8b7474b4 | ||
|
|
92a9c73ee7 | ||
|
|
7ade3e74b3 | ||
|
|
978e832914 | ||
|
|
2130a5ba1f | ||
|
|
9fc83efe06 | ||
|
|
e41ce49698 | ||
|
|
1574b5b1f7 | ||
|
|
3f6db080b4 | ||
|
|
f9a55bd5cd | ||
|
|
a4a830776b | ||
|
|
34d99b273c | ||
|
|
feb8365812 | ||
|
|
bf66e346f0 | ||
|
|
3a0a4b7f90 | ||
|
|
39f0f9edc0 | ||
|
|
a3983b7b0f | ||
|
|
504a45a4ed | ||
|
|
98c5c7f776 | ||
|
|
7020cf7188 | ||
|
|
70d129fcd7 | ||
|
|
2d5f4d8910 | ||
|
|
26c6911c8f | ||
|
|
f1fd3abcff | ||
|
|
2cae47a5a2 | ||
|
|
ac75a085fa | ||
|
|
0c1b422c36 | ||
|
|
23ce888d65 | ||
|
|
d992b21141 | ||
|
|
903492cce2 | ||
|
|
fc9b614225 | ||
|
|
543b7fa6c2 | ||
|
|
5a7ffd19b0 | ||
|
|
7be7483571 | ||
|
|
2eeb333be0 | ||
|
|
fe8baaec50 | ||
|
|
752b273aec | ||
|
|
b51056f743 | ||
|
|
ee1aed51d8 | ||
|
|
db2cda790c | ||
|
|
86b43ea14f | ||
|
|
d1829ed923 | ||
|
|
6d53bc4121 | ||
|
|
32b5ef5095 | ||
|
|
a36f2b3b7d | ||
|
|
cd4be6aa07 | ||
|
|
499edaecd0 | ||
|
|
225490163e | ||
|
|
d388a60daa | ||
|
|
6d05de9d4d | ||
|
|
5d6e571338 | ||
|
|
308d488833 | ||
|
|
cecbf0aa0e | ||
|
|
d21e6669ce | ||
|
|
2341d1ee50 | ||
|
|
53949761a7 | ||
|
|
f7eb986313 | ||
|
|
75aed1afd5 | ||
|
|
d16751f56a | ||
|
|
8b1a5244f7 | ||
|
|
b2747dfbd8 | ||
|
|
16e16cdf51 | ||
|
|
a353637a90 | ||
|
|
f3cbfcecf4 | ||
|
|
3bc8b1ff7c | ||
|
|
aa46c79db6 | ||
|
|
92acb6e547 | ||
|
|
ac632d9223 | ||
|
|
0df5b7b86d | ||
|
|
87c10988ed | ||
|
|
d6a28a6259 | ||
|
|
c6d0e8de63 | ||
|
|
ded4ef4072 | ||
|
|
1849a35e61 | ||
|
|
18e35053fa | ||
|
|
7e151f16c3 | ||
|
|
2ce4cdbff6 | ||
|
|
eea532ded1 | ||
|
|
c83b87e0a0 | ||
|
|
8d268e8a8a | ||
|
|
ee0f311c10 | ||
|
|
61730be6ce | ||
|
|
5f333d9753 | ||
|
|
d1493a9f96 | ||
|
|
d652212857 | ||
|
|
0cd60ea1e6 | ||
|
|
a0e23ee911 | ||
|
|
ad81c74cda | ||
|
|
9ef32e405c | ||
|
|
89ca6a325c | ||
|
|
9e0e7ef9a1 | ||
|
|
2dc948fefb | ||
|
|
e3a5290dad | ||
|
|
cfe1f60e47 | ||
|
|
0eed237517 | ||
|
|
68ffb01cac | ||
|
|
169ac61e14 | ||
|
|
0681110647 | ||
|
|
8d1b111692 | ||
|
|
2935942667 | ||
|
|
9a4593e823 | ||
|
|
250e08043b | ||
|
|
14f5e16ae8 | ||
|
|
bf69043a1d | ||
|
|
7086b8aeff | ||
|
|
53c39d01d4 | ||
|
|
4a2f9fc744 | ||
|
|
e7d63f5f6b | ||
|
|
b80b30fba1 | ||
|
|
8e84850679 | ||
|
|
e31256c0d4 | ||
|
|
9a9fd6603c | ||
|
|
e99ff5ac45 | ||
|
|
60cec85638 | ||
|
|
39f2ed1339 | ||
|
|
4c8724899b | ||
|
|
0c96234532 | ||
|
|
9dddd87893 | ||
|
|
5eb093f13e | ||
|
|
529989bde5 | ||
|
|
776e37980b | ||
|
|
7f24d46d44 | ||
|
|
cf6e5fec63 | ||
|
|
d8fc25ee43 | ||
|
|
a0eccceb01 | ||
|
|
2720224890 | ||
|
|
8bebab1db0 | ||
|
|
ee29579d3e | ||
|
|
5aec36350b | ||
|
|
1fecf80659 | ||
|
|
b6d77fbb9e | ||
|
|
8a19c5c30a | ||
|
|
0149122cd0 | ||
|
|
35335aadbe | ||
|
|
80df858ee3 | ||
|
|
eafc32fd68 | ||
|
|
2adeda0318 | ||
|
|
21a6d35b8b | ||
|
|
ce78280af3 | ||
|
|
041b86b8dd | ||
|
|
611b0041c4 | ||
|
|
ddb2acb652 | ||
|
|
da133baf17 | ||
|
|
d32b1912ed | ||
|
|
82513e5255 | ||
|
|
f2708ce967 | ||
|
|
01a5c94c7e | ||
|
|
e7a05b1db8 | ||
|
|
510a4aa99d | ||
|
|
3f4e8396aa | ||
|
|
276a200590 | ||
|
|
a40109e4e4 | ||
|
|
34cf959c9d | ||
|
|
bf6875f160 | ||
|
|
44f5b47bf0 | ||
|
|
41ab5dff5a | ||
|
|
5e43ece578 | ||
|
|
9acba4b412 | ||
|
|
8c50839109 | ||
|
|
6736d2ec66 | ||
|
|
6869e4807c | ||
|
|
5de05e2e4b | ||
|
|
fda54fd0c3 | ||
|
|
35962dedc4 | ||
|
|
991b74dd0d | ||
|
|
1a77667409 | ||
|
|
c9765ec158 | ||
|
|
202c91471c | ||
|
|
e14f68d1d7 | ||
|
|
185a3b29e6 | ||
|
|
d7b1569ee6 | ||
|
|
468f1cd912 | ||
|
|
965288de38 | ||
|
|
008920f533 | ||
|
|
20ed6a52ee | ||
|
|
8b85875b67 | ||
|
|
7054d81650 | ||
|
|
5942117ac3 | ||
|
|
e7a3b9d90e | ||
|
|
b13d623ad4 | ||
|
|
37bf9fae01 | ||
|
|
612cf3b7dd | ||
|
|
089e366ddc | ||
|
|
fa9e29e4ce | ||
|
|
fa3d83a3d1 | ||
|
|
804db4e073 | ||
|
|
5d998ef483 | ||
|
|
126b1e5726 | ||
|
|
4f2400c15b | ||
|
|
063d284cbf | ||
|
|
205bf5a11d | ||
|
|
41c94aa448 | ||
|
|
d413870e6d | ||
|
|
e95ac6fb06 | ||
|
|
e1ae92709c |
@@ -71,6 +71,7 @@ Language: Cpp
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
PPIndentWidth: -1
|
||||
PenaltyBreakScopeResolution: 1000
|
||||
PointerAlignment: Right
|
||||
QualifierAlignment: Right
|
||||
ReflowComments: true
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
Checks: ''
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: ''
|
||||
FormatStyle: none
|
||||
SystemHeaders: false
|
||||
+11
-2
@@ -1,9 +1,18 @@
|
||||
[*]
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
indent_size = tab
|
||||
tab_width = 8
|
||||
tab_width = 4
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
end_of_line = lf
|
||||
|
||||
[{CMakeLists.txt,*.cmake}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.yml]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# This file contains a list of commits that are probably not what you
|
||||
# are looking for in a `git blame`, such as mass reformatting or renaming.
|
||||
#
|
||||
# You can set this file as a default ignore file for `git blame` by running
|
||||
# the following command:
|
||||
#
|
||||
# $ git config blame.ignoreRevsFile .git-blame-ignore-revs
|
||||
|
||||
# 2024-03-04: Run `clang-format` on everything
|
||||
e74073e4805fa3cce90a99946fc9994ae2970f9b
|
||||
|
||||
# 2009-06-11: Run `indent' on the whole tree
|
||||
b6c749ffbd30138de7beef13fb9265372a461a96
|
||||
|
||||
# 2009-06-11: Switch line terminators from CRLF to LF
|
||||
94fad97aedcd8bd85c53a505db28390e3f82577b
|
||||
|
||||
# 2009-06-11: Use spaces instead of tabs after CPP directives
|
||||
0d9739535e313b0a2ad19c89b9c85fc7b75237a3
|
||||
@@ -1,6 +1,7 @@
|
||||
# Shell scripts need Unix line endings (see https://github.com/gbdev/rgbds/issues/841)
|
||||
*.sh text eol=lf
|
||||
*.bash text eol=lf
|
||||
*.cfg text eol=lf
|
||||
|
||||
# Flags also need Unix line endings (see https://github.com/gbdev/rgbds/issues/955)
|
||||
*.flags text eol=lf
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
name: Update to RGBDS
|
||||
about: Suggest a feature or report a bug in RGBDS.
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: GBDev Discord
|
||||
url: https://discord.gg/RjJKA8wrD4
|
||||
about: If you have questions about the RGBDS code or its organization, join our Discord server!
|
||||
@@ -0,0 +1,19 @@
|
||||
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "quarterly" # We do not need *immediate* bumps, only frequent enough to avoid falling out of support range.
|
||||
cooldown: # Avoid bumping deps immediately, to give time for security audits to be conducted
|
||||
default-days: 15
|
||||
include: [ "*" ]
|
||||
groups:
|
||||
actions:
|
||||
patterns: [ "*" ]
|
||||
ignore:
|
||||
- dependency-name: "*"
|
||||
update-types:
|
||||
- "version-update:semver-minor"
|
||||
- "version-update:semver-patch"
|
||||
labels: [ builds ] # Since those are CI-related updates...
|
||||
@@ -1,27 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
pngver=1.6.45
|
||||
|
||||
## Grab sources and check them
|
||||
|
||||
curl -LOJ "http://prdownloads.sourceforge.net/libpng/libpng-$pngver.tar.xz?download"
|
||||
# Brew doesn't provide any sha256sum, so we're making do with `sha2` instead.
|
||||
if [ "$(sha2 -q -256 libpng-$pngver.tar.xz)" != 926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 ]; then
|
||||
sha2 -256 libpng-$pngver.tar.xz
|
||||
echo Checksum mismatch! Aborting. >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
## Extract sources and patch them
|
||||
|
||||
tar -xvf libpng-$pngver.tar.xz
|
||||
|
||||
## Start building!
|
||||
|
||||
mkdir -p build
|
||||
cd build
|
||||
../libpng-$pngver/configure --disable-shared --enable-static \
|
||||
CFLAGS="-O3 -flto -DNDEBUG -mmacosx-version-min=10.9 -arch x86_64 -arch arm64 -fno-exceptions"
|
||||
make -kj
|
||||
make install prefix="$PWD/../libpng-staging"
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
|
||||
bash --version
|
||||
zsh --version
|
||||
|
||||
find contrib -type f \( -name '*.sh' -o -name '*.bash' \) -exec bash --norc -n {} \;
|
||||
find contrib/zsh_compl -type f -name '_rgb*' -exec zsh -n {} \;
|
||||
@@ -3,17 +3,17 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
declare -A FILES
|
||||
while read -r -d '' file; do
|
||||
FILES["$file"]="true"
|
||||
while IFS= read -r -d '' file; do
|
||||
FILES["$file"]=true
|
||||
done < <(git diff --name-only -z "$1" HEAD)
|
||||
|
||||
edited () {
|
||||
${FILES["$1"]:-"false"}
|
||||
${FILES["$1"]:-false}
|
||||
}
|
||||
|
||||
dependency () {
|
||||
if edited "$1" && ! edited "$2"; then
|
||||
echo "'$1' was modified, but not '$2'! $3" | xargs
|
||||
echo "'$1' was modified, but not '$2'! $3"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -26,11 +26,23 @@ dependency include/linkdefs.hpp man/rgbds.5 \
|
||||
dependency src/asm/parser.y man/rgbasm.5 \
|
||||
"Was the rgbasm grammar changed?"
|
||||
|
||||
dependency src/asm/actions.cpp man/rgbasm.5 \
|
||||
"Was the rgbasm grammar changed?"
|
||||
|
||||
dependency src/link/script.y man/rgblink.5 \
|
||||
"Was the linker script grammar changed?"
|
||||
|
||||
dependency include/asm/warning.hpp man/rgbasm.1 \
|
||||
dependency src/link/layout.cpp man/rgblink.5 \
|
||||
"Was the linker script grammar changed?"
|
||||
|
||||
dependency include/asm/warning.hpp man/rgbasm.1 \
|
||||
"Were the rgbasm warnings changed?"
|
||||
dependency include/link/warning.hpp man/rgblink.1 \
|
||||
"Were the rgblink warnings changed?"
|
||||
dependency include/fix/warning.hpp man/rgbfix.1 \
|
||||
"Were the rgbfix warnings changed?"
|
||||
dependency include/gfx/warning.hpp man/rgbgfx.1 \
|
||||
"Were the rgbgfx warnings changed?"
|
||||
|
||||
dependency src/asm/object.cpp include/linkdefs.hpp \
|
||||
"Should the object file revision be bumped?"
|
||||
@@ -67,15 +79,15 @@ dependency src/gfx/main.cpp contrib/zsh_compl/_rgbgfx \
|
||||
dependency src/gfx/main.cpp contrib/bash_compl/_rgbgfx.bash \
|
||||
"Did the rgbgfx CLI change?"
|
||||
|
||||
dependency test/fetch-test-deps.sh CONTRIBUTING.md \
|
||||
dependency test/external/fetch-repos.sh docs/CONTRIBUTING.md \
|
||||
"Did the test protocol change?"
|
||||
dependency test/run-tests.sh CONTRIBUTING.md \
|
||||
dependency test/run-tests.sh docs/CONTRIBUTING.md \
|
||||
"Did the test protocol change?"
|
||||
dependency test/asm/test.sh CONTRIBUTING.md \
|
||||
dependency test/asm/test.sh docs/CONTRIBUTING.md \
|
||||
"Did the RGBASM test protocol change?"
|
||||
dependency test/link/test.sh CONTRIBUTING.md \
|
||||
dependency test/link/test.sh docs/CONTRIBUTING.md \
|
||||
"Did the RGBLINK test protocol change?"
|
||||
dependency test/fix/test.sh CONTRIBUTING.md \
|
||||
dependency test/fix/test.sh docs/CONTRIBUTING.md \
|
||||
"Did the RGBFIX test protocol change?"
|
||||
dependency test/gfx/test.sh CONTRIBUTING.md \
|
||||
dependency test/gfx/test.sh docs/CONTRIBUTING.md \
|
||||
"Did the RGBGFX test protocol change?"
|
||||
@@ -1,15 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
clang-format --version
|
||||
|
||||
find . -type f \( -iname '*.hpp' -o -iname '*.cpp' \) -exec clang-format -i {} +
|
||||
find . -type f -iname '*.[ch]pp' -exec clang-format -i {} +
|
||||
|
||||
if ! git diff-index --quiet HEAD --; then
|
||||
echo 'Unformatted files:'
|
||||
git diff-index --name-only HEAD --
|
||||
echo
|
||||
git diff HEAD --
|
||||
return 1
|
||||
exit 1
|
||||
fi
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
tag=$1
|
||||
[ $# -eq 1 ]
|
||||
|
||||
flags=(--draft --fail-on-no-commits --verify-tag)
|
||||
if [[ "$tag" = v*-rc* ]]; then
|
||||
flags+=(--prerelease)
|
||||
fi
|
||||
|
||||
files=(
|
||||
win64/rgbds-win64.zip
|
||||
win32/rgbds-win32.zip
|
||||
macos/rgbds-macos.zip
|
||||
linux/rgbds-linux-x86_64.tar.xz
|
||||
rgbds-source.tar.gz
|
||||
)
|
||||
|
||||
set -x
|
||||
gh release create "${flags[@]}" --notes-file - "$tag" "${files[@]}" <<"EOF"
|
||||
Please ensure that the packages below work properly.
|
||||
Once that's done, replace this text with the changelog, un-draft the release, and update the `release` branch.
|
||||
By the way, if you forgot to update `include/version.hpp`, RGBASM's version test is going to fail in the tag's regression testing! (Use `git push --delete origin <tag>` to delete it)
|
||||
EOF
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
local_bin_dir="$PWD/.local/bin"
|
||||
|
||||
mkdir -p "$local_bin_dir"
|
||||
|
||||
# Alias `make` to `gmake` and `python` to `python3` for use by external tests.
|
||||
ln -s "$(which gmake)" "$local_bin_dir/make"
|
||||
ln -s "$(which python3)" "$local_bin_dir/python"
|
||||
|
||||
export PATH="$local_bin_dir:$PATH"
|
||||
@@ -1,23 +0,0 @@
|
||||
function getlibrary ([string] $URI, [string] $filename, [string] $hash, [string] $destdir) {
|
||||
$wc = New-Object Net.WebClient
|
||||
[string] $downloadhash = $null
|
||||
try {
|
||||
$wc.DownloadFile($URI, $filename)
|
||||
$downloadhash = $(Get-FileHash $filename -Algorithm SHA256).Hash
|
||||
} catch {
|
||||
Write-Host "${filename}: failed to download"
|
||||
exit 1
|
||||
}
|
||||
if ($hash -ne $downloadhash) {
|
||||
Write-Host "${filename}: SHA256 mismatch ($downloadhash)"
|
||||
exit 1
|
||||
}
|
||||
Expand-Archive -DestinationPath $destdir $filename
|
||||
}
|
||||
|
||||
getlibrary 'https://www.zlib.net/zlib131.zip' 'zlib.zip' '72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17' .
|
||||
getlibrary 'https://github.com/glennrp/libpng/archive/refs/tags/v1.6.45.zip' 'libpng.zip' '1b3d94b2f1d137db1bf1842cb9f03df179772a517f7b86e26351742190632785' .
|
||||
getlibrary 'https://github.com/lexxmark/winflexbison/releases/download/v2.5.25/win_flex_bison-2.5.25.zip' 'winflexbison.zip' '8d324b62be33604b2c45ad1dd34ab93d722534448f55a16ca7292de32b6ac135' install_dir
|
||||
|
||||
Move-Item zlib-1.3.1 zlib
|
||||
Move-Item libpng-1.6.45 libpng
|
||||
Executable
+102
@@ -0,0 +1,102 @@
|
||||
#!/bin/sh
|
||||
# This script requires `sh` instead of `bash` because the latter is not always installed on FreeBSD.
|
||||
set -eu
|
||||
|
||||
# Python and the Pillow library are dependencies for libbet, a repo built by our external tests.
|
||||
# Other dependencies are for building rgbds itself.
|
||||
|
||||
case $# in
|
||||
1) OS="$1"; TOOLSET= ;;
|
||||
2) OS="$1"; TOOLSET="$2" ;;
|
||||
*) echo >&2 "Usage: $0 <os> [<toolset>]" && exit 1 ;;
|
||||
esac
|
||||
|
||||
case "${OS%%-*}" in
|
||||
ubuntu|debian)
|
||||
pkgs=bison
|
||||
case "$TOOLSET" in
|
||||
mingw32)
|
||||
pkgs="$pkgs libz-mingw-w64-dev g++-mingw-w64-i686-win32"
|
||||
TOOLSET=
|
||||
;;
|
||||
mingw64)
|
||||
pkgs="$pkgs libz-mingw-w64-dev g++-mingw-w64-x86-64-win32"
|
||||
TOOLSET=
|
||||
;;
|
||||
g++-10 | lcov)
|
||||
pkgs="$pkgs libpng-dev pkgconf python3-pil $TOOLSET"
|
||||
TOOLSET=
|
||||
;;
|
||||
'' | g++ | clang++)
|
||||
pkgs="$pkgs libpng-dev pkgconf python3-pil"
|
||||
TOOLSET=
|
||||
;;
|
||||
esac
|
||||
sudo apt-get update -qq
|
||||
# shellcheck disable=SC2086 # (This word splitting is intentional.)
|
||||
sudo apt-get install -yq $pkgs
|
||||
;;
|
||||
macos)
|
||||
pkgs="bison make pillow"
|
||||
case "$TOOLSET" in
|
||||
lld)
|
||||
pkgs="$pkgs $TOOLSET"
|
||||
TOOLSET=
|
||||
;;
|
||||
clang++)
|
||||
TOOLSET=
|
||||
;;
|
||||
esac
|
||||
# macOS bundles GNU Make 3.81, which doesn't support synced output.
|
||||
# We leave it as the default in `PATH`, to test that our Makefile works with it.
|
||||
# However, CMake automatically uses Homebrew's `gmake`, so our CI has synced output.
|
||||
# shellcheck disable=SC2086 # (This word splitting is intentional.)
|
||||
brew install $pkgs
|
||||
# Export `bison` to allow using the version we install from Homebrew,
|
||||
# instead of the outdated one preinstalled on macOS (which doesn't even support `-Wall`...).
|
||||
export PATH="$(brew --prefix)/opt/bison/bin:$PATH"
|
||||
printf 'PATH=%s\n' "$PATH" >>"$GITHUB_ENV" # Make it available to later CI steps too.
|
||||
;;
|
||||
freebsd)
|
||||
# GNU `gmake` and `gcc` are dependencies for most repos built by our external tests.
|
||||
pkg install -y bash bison cmake ninja git png gmake lang/gcc python3 py312-pillow
|
||||
;;
|
||||
windows)
|
||||
# GitHub Actions' hosted runners ship CMake 3.x, but versions prior to 4.0.0 ignore `CPACK_PACKAGE_FILE_NAME`.
|
||||
choco install -y winflexbison3 cmake
|
||||
# The version-printing code below will invoke `bison`, not the Windows-specific name `win_bison`.
|
||||
bison() { win_bison "$@"; } # An alias doesn't work, so we use a function instead.
|
||||
py -3 -m pip install pillow
|
||||
;;
|
||||
windowsmingw)
|
||||
py -3 -m pip install pillow
|
||||
;;
|
||||
*)
|
||||
echo "Cannot install deps for OS '$1'"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -n "$TOOLSET" ]; then
|
||||
printf >&2 'Unknown toolset `%s` for OS `%s`\n' "$TOOLSET" "$OS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# We do not build RGBDS *in* MinGW on Windows, so skip printing build tool info.
|
||||
if [ "$OS" = "windowsmingw" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Print some system info, for easier debugging.
|
||||
# https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-commands#grouping-log-lines
|
||||
|
||||
echo ::group::PATH
|
||||
echo "PATH=($PATH)" | sed 's/:/\n /g'
|
||||
echo ::endgroup::
|
||||
|
||||
for prog in bison make cmake; do
|
||||
printf '::group::' # No line terminator, the next command's first line becomes the group's title.
|
||||
$prog --version
|
||||
type $prog
|
||||
echo ::endgroup::
|
||||
done
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
install -d /usr/local/bin/ /usr/local/share/man/man1/ /usr/local/share/man/man5/ /usr/local/share/man/man7/
|
||||
install -s -m 755 rgbasm rgblink rgbfix rgbgfx /usr/local/bin/
|
||||
install -m 644 rgbasm.1 rgblink.1 rgbfix.1 rgbgfx.1 /usr/local/share/man/man1/
|
||||
install -m 644 rgbds.5 rgbasm.5 rgblink.5 rgbasm-old.5 /usr/local/share/man/man5/
|
||||
install -m 644 rgbds.7 gbz80.7 /usr/local/share/man/man7/
|
||||
@@ -1,23 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
case "${1%-*}" in
|
||||
ubuntu)
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get install -yq bison libpng-dev pkg-config
|
||||
;;
|
||||
macos)
|
||||
brew install bison sha2 md5sha1sum
|
||||
# Export `bison` to allow using the version we install from Homebrew,
|
||||
# instead of the outdated one preinstalled on macOS (which doesn't even support `-Wall`...)
|
||||
export PATH="/opt/homebrew/opt/bison/bin:$PATH"
|
||||
printf 'PATH=%s\n' "$PATH" >>"$GITHUB_ENV" # Make it available to later CI steps too
|
||||
;;
|
||||
*)
|
||||
echo "WARNING: Cannot install deps for OS '$1'"
|
||||
;;
|
||||
esac
|
||||
|
||||
bison --version
|
||||
make --version
|
||||
cmake --version
|
||||
@@ -1,33 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
pngver=1.6.45
|
||||
arch="$1"
|
||||
|
||||
## Grab sources and check them
|
||||
|
||||
wget http://downloads.sourceforge.net/project/libpng/libpng16/$pngver/libpng-$pngver.tar.xz
|
||||
wget http://downloads.sourceforge.net/project/apng/libpng/libpng16/libpng-$pngver-apng.patch.gz
|
||||
sha256sum -c .github/scripts/mingw-w64-libpng-dev.sha256sums
|
||||
|
||||
## Extract sources and patch them
|
||||
|
||||
tar -xf libpng-$pngver.tar.xz
|
||||
gunzip libpng-$pngver-apng.patch.gz
|
||||
|
||||
# Patch in apng support
|
||||
env -C libpng-$pngver patch -p0 ../libpng-$pngver-apng.patch
|
||||
|
||||
## Start building!
|
||||
|
||||
mkdir -p build
|
||||
cd build
|
||||
../libpng-$pngver/configure \
|
||||
--host="$arch" --target="$arch" \
|
||||
--prefix="/usr/$arch" \
|
||||
--enable-shared --disable-static \
|
||||
CPPFLAGS="-D_FORTIFY_SOURCE=2" \
|
||||
CFLAGS="-O2 -pipe -fno-plt -fno-exceptions --param=ssp-buffer-size=4" \
|
||||
LDFLAGS="-Wl,-O1,--sort-common,--as-needed -fstack-protector"
|
||||
make -kj
|
||||
sudo make install
|
||||
@@ -1,2 +0,0 @@
|
||||
f7caa3b55f003ce23d6a087b1c2a643262647bfd1a1b31afdc9b18eabf1bbc7e libpng-1.6.45-apng.patch.gz
|
||||
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-1.6.45.tar.xz
|
||||
@@ -0,0 +1,4 @@
|
||||
@rem From https://github.com/microsoft/vswhere/wiki/Start-Developer-Command-Prompt#using-batch
|
||||
for /f "delims=" %%p in ('vswhere.exe -prerelease -latest -property installationPath') do set vspath=%%p
|
||||
@rem From https://learn.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-170#developer_command_file_locations
|
||||
call "%vspath%\VC\Auxiliary\Build\vcvars%1.bat"
|
||||
@@ -1,18 +0,0 @@
|
||||
name: Static analysis
|
||||
on:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
- name: Install deps
|
||||
shell: bash
|
||||
run: |
|
||||
./.github/scripts/install_deps.sh ubuntu-latest
|
||||
- name: Static analysis
|
||||
run: | # Silence warnings with too many false positives (https://stackoverflow.com/a/73913076)
|
||||
make -kj CXX=g++-14 CXXFLAGS="-fanalyzer -fanalyzer-verbosity=0 -Wno-analyzer-use-of-uninitialized-value -DNDEBUG" Q=
|
||||
@@ -6,6 +6,12 @@ on:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
env:
|
||||
# Force colored output (see https://bixense.com/clicolors/ and https://force-color.org/)
|
||||
TERM: xterm-256color
|
||||
CLICOLOR: 1
|
||||
CLICOLOR_FORCE: 1
|
||||
|
||||
jobs:
|
||||
publish-docker-image:
|
||||
if: github.repository_owner == 'gbdev'
|
||||
@@ -14,10 +20,10 @@ jobs:
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -37,11 +43,13 @@ jobs:
|
||||
TAG_NAME=${GITHUB_REF#refs/tags/}
|
||||
sed -i "2i LABEL org.opencontainers.image.description=\"RGBDS container image for the release version $TAG_NAME\"" Dockerfile
|
||||
docker build . --tag ghcr.io/gbdev/rgbds:$TAG_NAME
|
||||
docker tag ghcr.io/gbdev/rgbds:$TAG_NAME ghcr.io/gbdev/rgbds:latest
|
||||
docker push ghcr.io/gbdev/rgbds:$TAG_NAME
|
||||
docker push ghcr.io/gbdev/rgbds:latest
|
||||
|
||||
- name: Delete untagged container images
|
||||
if: github.repository_owner == 'gbdev'
|
||||
uses: Chizkiyahu/delete-untagged-ghcr-action@v5
|
||||
uses: Chizkiyahu/delete-untagged-ghcr-action@v6
|
||||
with:
|
||||
# Requires a personal access token with delete:packages permissions
|
||||
token: ${{ secrets.PAT_TOKEN }}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
name: Contrib script syntax checking
|
||||
on:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
env:
|
||||
# Force colored output (see https://bixense.com/clicolors/ and https://force-color.org/)
|
||||
TERM: xterm-256color
|
||||
CLICOLOR: 1
|
||||
CLICOLOR_FORCE: 1
|
||||
|
||||
jobs:
|
||||
check-contrib:
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v7
|
||||
- name: Install zsh
|
||||
run: |
|
||||
sudo apt install -Uyq zsh
|
||||
- name: Check contrib scripts
|
||||
run: |
|
||||
.github/scripts/check-contrib.sh
|
||||
@@ -0,0 +1,27 @@
|
||||
name: Diff completeness check
|
||||
on: pull_request
|
||||
|
||||
env:
|
||||
# Force colored output (see https://bixense.com/clicolors/ and https://force-color.org/)
|
||||
TERM: xterm-256color
|
||||
CLICOLOR: 1
|
||||
CLICOLOR_FORCE: 1
|
||||
|
||||
jobs:
|
||||
check-diff:
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- name: Clone repo
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Check diff
|
||||
shell: bash # Bash is the default, but specifying it explicitly enables `-o pipefail`.
|
||||
run: |
|
||||
MERGE_BASE=$(gh api "/repos/{owner}/{repo}/compare/$BASE_SHA...$HEAD_SHA" --jq '.merge_base_commit.sha')
|
||||
git fetch origin "$MERGE_BASE"
|
||||
.github/scripts/check-diff.bash "$MERGE_BASE" | sed -E 's/^/::warning::/'
|
||||
env:
|
||||
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
@@ -0,0 +1,21 @@
|
||||
name: Code format checking
|
||||
on: pull_request
|
||||
|
||||
env:
|
||||
# Force colored output (see https://bixense.com/clicolors/ and https://force-color.org/)
|
||||
TERM: xterm-256color
|
||||
CLICOLOR: 1
|
||||
CLICOLOR_FORCE: 1
|
||||
|
||||
jobs:
|
||||
check-format:
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v7
|
||||
- name: Install clang-format
|
||||
run: |
|
||||
sudo apt install -Uyq clang-format
|
||||
- name: Check format
|
||||
run: |
|
||||
.github/scripts/check-format.sh
|
||||
@@ -1,17 +0,0 @@
|
||||
name: Code coverage checking
|
||||
on: pull_request
|
||||
|
||||
jobs:
|
||||
checkdiff:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up repo
|
||||
run: |
|
||||
git clone -b "${{ github.event.pull_request.head.ref }}" "${{ github.event.pull_request.head.repo.clone_url }}" rgbds
|
||||
cd rgbds
|
||||
git remote add upstream "${{ github.event.pull_request.base.repo.clone_url }}"
|
||||
git fetch upstream
|
||||
- name: Check diff
|
||||
working-directory: rgbds
|
||||
run: |
|
||||
make checkdiff "BASE_REF=${{ github.event.pull_request.base.sha }}" Q= | tee log
|
||||
@@ -1,12 +0,0 @@
|
||||
name: Code format checking
|
||||
on: pull_request
|
||||
|
||||
jobs:
|
||||
checkformat:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
- name: Check format
|
||||
run: |
|
||||
./contrib/checkformat.bash
|
||||
@@ -0,0 +1,33 @@
|
||||
name: Code coverage report
|
||||
on:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
env:
|
||||
# Force colored output (see https://bixense.com/clicolors/ and https://force-color.org/)
|
||||
TERM: xterm-256color
|
||||
CLICOLOR: 1
|
||||
CLICOLOR_FORCE: 1
|
||||
|
||||
jobs:
|
||||
coverage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v7
|
||||
- name: Install deps
|
||||
run: |
|
||||
.github/scripts/install-deps.sh ubuntu-latest lcov
|
||||
- name: Generate coverage report
|
||||
run: |
|
||||
contrib/coverage.bash --os ubuntu-latest --jobs "$(getconf _NPROCESSORS_ONLN)"
|
||||
- name: Upload coverage report
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: coverage-report
|
||||
# Workaround for keeping the top-level coverage/ directory
|
||||
# https://github.com/actions/upload-artifact/issues/174
|
||||
path: |
|
||||
coverage
|
||||
dummy-file-to-keep-directory-structure.txt
|
||||
if-no-files-found: error
|
||||
@@ -4,162 +4,122 @@ on:
|
||||
tags:
|
||||
- v[0-9]*
|
||||
|
||||
env:
|
||||
# Force colored output (see https://bixense.com/clicolors/ and https://force-color.org/)
|
||||
TERM: xterm-256color
|
||||
CLICOLOR: 1
|
||||
CLICOLOR_FORCE: 1
|
||||
|
||||
CMAKE_COLOR_DIAGNOSTICS: ON # Tells CMake-generated build systems to have colored output.
|
||||
CMAKE_BUILD_TYPE: Release # `cmake -S` now implies `-DCMAKE_BUILD_TYPE=Release`.
|
||||
CMAKE_CONFIG_TYPE: Release # `cmake --build` now implies `--config Release`.
|
||||
|
||||
# We instruct CMake to download and build third-party projects in the same place as in `testing.yml`
|
||||
# to prevent divergence between testing and release workflows.
|
||||
DEPS_ROOT_DIR: ~/_deps
|
||||
|
||||
# We use Ninja as the generator for CMake below because it provides synchronous output by default,
|
||||
# and only shows full command lines when they fail.
|
||||
|
||||
jobs:
|
||||
windows:
|
||||
runs-on: windows-2022
|
||||
strategy:
|
||||
matrix:
|
||||
bits: [32, 64]
|
||||
include:
|
||||
- bits: 32
|
||||
arch: x86
|
||||
platform: Win32
|
||||
- bits: 64
|
||||
arch: x86_x64
|
||||
platform: x64
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: Get version from tag
|
||||
shell: bash
|
||||
run: | # Turn "vX.Y.Z" into "X.Y.Z"
|
||||
VERSION="${{ github.ref_name }}"
|
||||
echo "version=${VERSION#v}" >> $GITHUB_ENV
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
- name: Install deps
|
||||
run: .github/scripts/get_win_deps.ps1
|
||||
- name: Check libraries cache
|
||||
id: cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
zbuild
|
||||
pngbuild
|
||||
key: ${{ matrix.arch }}-${{ hashFiles('zlib/**', 'libpng/**') }}
|
||||
- name: Build zlib
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll`
|
||||
cmake -S zlib -B zbuild -A ${{ matrix.platform }} -Wno-dev -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
|
||||
cmake --build zbuild --config Release -j
|
||||
- name: Install zlib
|
||||
run: |
|
||||
cmake --install zbuild
|
||||
- name: Build libpng
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
cmake -S libpng -B pngbuild -A ${{ matrix.platform }} -Wno-dev -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=OFF -DPNG_TESTS=OFF
|
||||
cmake --build pngbuild --config Release -j
|
||||
- name: Install libpng
|
||||
run: |
|
||||
cmake --install pngbuild
|
||||
bash .github/scripts/install-deps.sh windows
|
||||
- name: Build Windows binaries
|
||||
shell: bash
|
||||
shell: cmd
|
||||
run: |
|
||||
cmake -S . -B build -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build build --config Release -j --verbose
|
||||
cmake --install build --verbose --prefix install_dir --strip
|
||||
call .github\scripts\msvc-env.bat ${{ matrix.bits }}
|
||||
cmake -B build -G Ninja -DFETCHCONTENT_BASE_DIR="${{ env.DEPS_ROOT_DIR }}" -DCMAKE_C_FLAGS="/nologo"
|
||||
cmake --build build -- -k 0
|
||||
- name: Package binaries
|
||||
working-directory: build
|
||||
run: |
|
||||
Compress-Archive -LiteralPath @("install_dir/bin/rgbasm.exe", "install_dir/bin/rgblink.exe", "install_dir/bin/rgbfix.exe", "install_dir/bin/rgbgfx.exe", "install_dir/bin/zlib1.dll", "install_dir/bin/libpng16.dll") "rgbds-${{ env.version }}-win${{ matrix.bits }}.zip"
|
||||
cpack -DCPACK_PACKAGE_FILE_NAME=rgbds-win${{ matrix.bits }} -G ZIP --verbose
|
||||
- name: Upload Windows binaries
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: win${{ matrix.bits }}
|
||||
path: rgbds-${{ env.version }}-win${{ matrix.bits }}.zip
|
||||
path: build/rgbds-win${{ matrix.bits }}.zip
|
||||
if-no-files-found: error
|
||||
|
||||
macos:
|
||||
runs-on: macos-14
|
||||
runs-on: macos-26
|
||||
steps:
|
||||
- name: Get version from tag
|
||||
shell: bash
|
||||
run: | # Turn "refs/tags/vX.Y.Z" into "X.Y.Z"
|
||||
VERSION="${{ github.ref_name }}"
|
||||
echo "version=${VERSION#v}" >> $GITHUB_ENV
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
- name: Install deps
|
||||
shell: bash
|
||||
run: |
|
||||
./.github/scripts/install_deps.sh macos
|
||||
- name: Build libpng
|
||||
run: |
|
||||
./.github/scripts/build_libpng.sh
|
||||
# We force linking libpng statically; the other libs are provided by macOS itself
|
||||
./.github/scripts/install-deps.sh macos lld
|
||||
- name: Build binaries
|
||||
run: |
|
||||
make -kj CXXFLAGS="-O3 -flto -DNDEBUG -mmacosx-version-min=10.9 -arch x86_64 -arch arm64" PNGCFLAGS="-I libpng-staging/include" PNGLDLIBS="libpng-staging/lib/libpng.a -lz" Q=
|
||||
cmake -B build -G Ninja --preset macos-static -DFETCHCONTENT_BASE_DIR="${{ env.DEPS_ROOT_DIR }}"
|
||||
cmake --build build -- -k 0
|
||||
strip rgb{asm,link,fix,gfx}
|
||||
env:
|
||||
LDFLAGS: -fuse-ld=lld # cmake/macos-static.cmake comments explain why we use lld.
|
||||
- name: Create install script
|
||||
run: |
|
||||
make install.sh
|
||||
- name: Package binaries
|
||||
run: |
|
||||
zip --junk-paths rgbds-${{ env.version }}-macos.zip rgb{asm,link,fix,gfx} man/* .github/scripts/install.sh
|
||||
zip --junk-paths rgbds-macos.zip rgb{asm,link,fix,gfx} man/* install.sh
|
||||
- name: Upload macOS binaries
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: macos
|
||||
path: rgbds-${{ env.version }}-macos.zip
|
||||
path: rgbds-macos.zip
|
||||
if-no-files-found: error
|
||||
|
||||
linux:
|
||||
runs-on: ubuntu-22.04 # Oldest supported, for best glibc compatibility.
|
||||
steps:
|
||||
- name: Get version from tag
|
||||
shell: bash
|
||||
run: | # Turn "refs/tags/vX.Y.Z" into "X.Y.Z"
|
||||
VERSION="${{ github.ref_name }}"
|
||||
echo "version=${VERSION#v}" >> $GITHUB_ENV
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
- name: Install deps
|
||||
shell: bash
|
||||
run: |
|
||||
./.github/scripts/install_deps.sh ubuntu-22.04
|
||||
./.github/scripts/install-deps.sh ubuntu-22.04
|
||||
- name: Build binaries
|
||||
run: |
|
||||
make -kj WARNFLAGS="-Wall -Wextra -pedantic -static" PKG_CONFIG="pkg-config --static" Q=
|
||||
make -k -j "$(getconf _NPROCESSORS_ONLN)" WARNFLAGS="-Wall -Wextra -pedantic -static" PKG_CONFIG="pkg-config --static" Q=
|
||||
strip rgb{asm,link,fix,gfx}
|
||||
- name: Create install script
|
||||
run: |
|
||||
make install.sh Q=
|
||||
- name: Package binaries
|
||||
run: |
|
||||
tar caf rgbds-${{ env.version }}-linux-x86_64.tar.xz --transform='s#.*/##' rgb{asm,link,fix,gfx} man/* .github/scripts/install.sh
|
||||
tar caf rgbds-linux-x86_64.tar.xz --transform='s#.*/##' rgb{asm,link,fix,gfx} man/* install.sh
|
||||
- name: Upload Linux binaries
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: linux
|
||||
path: rgbds-${{ env.version }}-linux-x86_64.tar.xz
|
||||
path: rgbds-linux-x86_64.tar.xz
|
||||
if-no-files-found: error
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-slim
|
||||
needs: [windows, macos, linux]
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Get version from tag
|
||||
shell: bash
|
||||
run: | # Turn "refs/tags/vX.Y.Z" into "X.Y.Z"
|
||||
VERSION="${{ github.ref_name }}"
|
||||
echo "version=${VERSION#v}" >> $GITHUB_ENV
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
- name: Package sources
|
||||
run: |
|
||||
make dist Q=
|
||||
ls
|
||||
- name: Download Linux binaries
|
||||
uses: actions/download-artifact@v4
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
body: |
|
||||
Please ensure that the packages below work properly.
|
||||
Once that's done, replace this text with the changelog, un-draft the release, and update the `release` branch.
|
||||
By the way, if you forgot to update `include/version.hpp`, RGBASM's version test is gonna fail in the tag's regression testing! (Use `git push --delete origin <tag>` to delete it)
|
||||
draft: true # Don't publish the release quite yet...
|
||||
prerelease: ${{ contains(github.ref, '-rc') }}
|
||||
files: |
|
||||
win32/rgbds-${{ env.version }}-win32.zip
|
||||
win64/rgbds-${{ env.version }}-win64.zip
|
||||
macos/rgbds-${{ env.version }}-macos.zip
|
||||
linux/rgbds-${{ env.version }}-linux-x86_64.tar.xz
|
||||
rgbds-${{ env.version }}.tar.gz
|
||||
fail_on_unmatched_files: true
|
||||
- name: Download all binary packages
|
||||
uses: actions/download-artifact@v8
|
||||
- name: Draft the release
|
||||
run: |
|
||||
.github/scripts/draft-release.sh "${ref#refs/tags/}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ref: ${{ github.ref_name }}
|
||||
GH_TOKEN: ${{ github.token }} # Required by the `gh` command.
|
||||
|
||||
@@ -4,24 +4,32 @@ on:
|
||||
types:
|
||||
- released # This avoids triggering on pre-releases
|
||||
|
||||
env:
|
||||
# Force colored output (see https://bixense.com/clicolors/ and https://force-color.org/)
|
||||
TERM: xterm-256color
|
||||
CLICOLOR: 1
|
||||
CLICOLOR_FORCE: 1
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: github.repository_owner == 'gbdev'
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- name: Checkout rgbds@release
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
path: rgbds
|
||||
- name: Checkout rgbds-www@master
|
||||
uses: actions/checkout@v4
|
||||
sparse-checkout: man # Avoid checking out other files, we don't use them here.
|
||||
- name: Checkout rgbds-www
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
repository: ${{ github.repository_owner }}/rgbds-www
|
||||
path: rgbds-www
|
||||
repository: ${{ github.repository_owner }}/rgbds-www
|
||||
ref: master # Need to check out the branch to be able to commit on and push it.
|
||||
ssh-key: !!str ${{ secrets.SSH_KEY_SECRET }}
|
||||
- name: Install groff and mandoc
|
||||
run: |
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get install -yq groff mandoc
|
||||
sudo apt install -Uyq groff mandoc -o APT::Color=yes -o Acquire::Queue-Mode=access
|
||||
- name: Update pages
|
||||
working-directory: rgbds/man
|
||||
run: | # The ref appears to be in the format "refs/tags/<version>", so strip that
|
||||
@@ -29,19 +37,12 @@ jobs:
|
||||
../../rgbds-www/maintainer/new_release.sh ${GITHUB_REF##*/}
|
||||
- name: Push new pages
|
||||
working-directory: rgbds-www
|
||||
env:
|
||||
GIT_AUTHOR_NAME: !!str ${{ github.actor }}
|
||||
GIT_AUTHOR_EMAIL: !!str ${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com
|
||||
GIT_COMMITTER_NAME: github-actions[bot]
|
||||
GIT_COMMITTER_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
|
||||
run: |
|
||||
mkdir -p -m 700 ~/.ssh
|
||||
cat > ~/.ssh/id_ed25519 <<<"${{ secrets.SSH_KEY_SECRET }}"
|
||||
chmod 0600 ~/.ssh/id_ed25519
|
||||
eval $(ssh-agent -s)
|
||||
ssh-add ~/.ssh/id_ed25519
|
||||
git config --global user.name "GitHub Action"
|
||||
git config --global user.email "[email protected]"
|
||||
git add -A
|
||||
git commit -m "Create RGBDS ${GITHUB_REF##*/} documentation"
|
||||
if git remote | grep -q origin; then
|
||||
git remote set-url origin [email protected]:${{ github.repository_owner }}/rgbds-www.git
|
||||
else
|
||||
git remote add origin [email protected]:${{ github.repository_owner }}/rgbds-www.git
|
||||
fi
|
||||
git push origin master
|
||||
git push
|
||||
|
||||
+252
-189
@@ -3,57 +3,102 @@ on:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
env:
|
||||
# Force colored output (see https://bixense.com/clicolors/ and https://force-color.org/)
|
||||
TERM: xterm-256color
|
||||
CLICOLOR: 1
|
||||
CLICOLOR_FORCE: 1
|
||||
|
||||
CMAKE_COLOR_DIAGNOSTICS: ON # Tells CMake-generated build systems to have colored output.
|
||||
CMAKE_CONFIG_TYPE: Debug # `cmake --build` now implies `--config Debug`.
|
||||
|
||||
CTEST_PARALLEL_LEVEL: "" # `ctest` now implies `--parallel` (default number of logical CPUs).
|
||||
CTEST_NO_TESTS_ACTION: error # Make CTest fail if it cannot find any tests. (That should never happen.)
|
||||
CTEST_OUTPUT_ON_FAILURE: ON # CTest reports test program output on failure.
|
||||
|
||||
GIT_CONFIG_COUNT: 1
|
||||
GIT_CONFIG_KEY_0: color.ui
|
||||
GIT_CONFIG_VALUE_0: always # Colorful output is helpful even though CI is not considered to be a terminal.
|
||||
|
||||
# We instruct CMake to download and build third-party projects outside of our source tree,
|
||||
# otherwise they can trigger `-Werror=dev` (from the `develop` preset).
|
||||
DEPS_ROOT_DIR: ~/_deps # Note that this needs to be used in a position where Bash will trigger tilde expansion!
|
||||
|
||||
# We use bash syntax across OSes for consistency unless otherwise specified
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
# We use Ninja as the generator for CMake below because it provides synchronous output by default,
|
||||
# and only shows full command lines when they fail.
|
||||
|
||||
jobs:
|
||||
unix:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-22.04, macos-14]
|
||||
os: [ubuntu-22.04, macos-15-intel, macos-26]
|
||||
cxx: [g++, clang++]
|
||||
buildsys: [make, cmake]
|
||||
exclude:
|
||||
# Don't use `g++` on macOS; it's just an alias to `clang++`.
|
||||
- os: macos-14
|
||||
cxx: g++
|
||||
exclude: # Don't use `g++` on macOS; it's just an alias to `clang++`.
|
||||
- { os: macos-15-intel, cxx: g++ }
|
||||
- { os: macos-26, cxx: g++ }
|
||||
include: # Use `g++-10`, the earliest GCC version we support, on the earliest Ubuntu runner.
|
||||
- { os: ubuntu-22.04, cxx: g++-10, buildsys: make }
|
||||
- { os: ubuntu-22.04, cxx: g++-10, buildsys: cmake }
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
- name: Install deps
|
||||
shell: bash
|
||||
run: |
|
||||
./.github/scripts/install_deps.sh ${{ matrix.os }}
|
||||
- name: Build & install using Make
|
||||
.github/scripts/install-deps.sh ${{ matrix.os }} ${{ matrix.cxx }}
|
||||
- name: Build using Make
|
||||
if: matrix.buildsys == 'make'
|
||||
run: |
|
||||
make develop -kj Q= CXX=${{ matrix.cxx }}
|
||||
sudo make install -j Q=
|
||||
- name: Build & install using CMake
|
||||
make develop -k -j "$(getconf _NPROCESSORS_ONLN)" Q= CXX=${{ matrix.cxx }}
|
||||
- name: Install using Make
|
||||
if: matrix.buildsys == 'make'
|
||||
run: |
|
||||
sudo make install Q=
|
||||
type rgbasm rgblink rgbfix rgbgfx
|
||||
man -w 1 rgbasm rgblink rgbfix rgbgfx
|
||||
- name: Build using CMake
|
||||
if: matrix.buildsys == 'cmake'
|
||||
# Since GitHub's runners are basically kitchen sinks,
|
||||
# the Mono framework exposes a libpng 1.4.x header, breaking everything.
|
||||
# Searching frameworks last makes Homebrew's libpng be discovered first, which works.
|
||||
# Note that since this is specific to our CI environment, the workaround is
|
||||
# better applied here than in our CMakeLists, where it could affect and break someone else.
|
||||
run: |
|
||||
CXX=${{ matrix.cxx }} cmake -B build -G Ninja --preset develop -DCMAKE_FIND_FRAMEWORK=LAST
|
||||
cmake --build build -- -k 0
|
||||
- name: Install using CMake
|
||||
if: matrix.buildsys == 'cmake'
|
||||
run: |
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} -DSANITIZERS=ON -DMORE_WARNINGS=ON
|
||||
cmake --build build -j --verbose
|
||||
sudo cmake --install build --verbose
|
||||
type rgbasm rgblink rgbfix rgbgfx
|
||||
man -w 1 rgbasm rgblink rgbfix rgbgfx
|
||||
- name: Package binaries
|
||||
run: |
|
||||
mkdir bins
|
||||
cp rgb{asm,link,fix,gfx} bins
|
||||
- name: Upload binaries
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: rgbds-canary-${{ matrix.os }}-${{ matrix.cxx }}-${{ matrix.buildsys }}
|
||||
path: bins
|
||||
if-no-files-found: error
|
||||
- name: Compute test dependency cache params
|
||||
id: test-deps-cache-params
|
||||
shell: bash
|
||||
run: |
|
||||
paths=$(test/fetch-test-deps.sh --get-paths)
|
||||
hash=$(test/fetch-test-deps.sh --get-hash)
|
||||
paths=$(test/external/fetch-repos.sh --get-paths)
|
||||
hash=$(test/external/fetch-repos.sh --get-hash)
|
||||
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
|
||||
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
|
||||
- name: Check test dependency repositories cache
|
||||
id: test-deps-cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
|
||||
key: ${{ matrix.os }}-${{ steps.test-deps-cache-params.outputs.hash }}
|
||||
@@ -61,328 +106,346 @@ jobs:
|
||||
if: steps.test-deps-cache.outputs.cache-hit != 'true'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
test/fetch-test-deps.sh
|
||||
- name: Install test dependency dependencies
|
||||
shell: bash
|
||||
test/external/fetch-repos.sh
|
||||
- name: Run tests using our script
|
||||
if: matrix.buildsys == 'make'
|
||||
run: |
|
||||
test/fetch-test-deps.sh --get-deps ${{ matrix.os }}
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
CXX=${{ matrix.cxx }} test/run-tests.sh --os ${{ matrix.os }} --jobs "$(getconf _NPROCESSORS_ONLN)"
|
||||
- name: Run tests using CTest
|
||||
if: matrix.buildsys == 'cmake'
|
||||
run: |
|
||||
CXX=${{ matrix.cxx }} test/run-tests.sh
|
||||
ctest --test-dir build --schedule-random
|
||||
|
||||
macos-static:
|
||||
runs-on: macos-14
|
||||
runs-on: macos-26
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
- name: Install deps
|
||||
shell: bash
|
||||
run: |
|
||||
./.github/scripts/install_deps.sh macos
|
||||
- name: Build libpng
|
||||
.github/scripts/install-deps.sh macos lld
|
||||
- name: Cache library deps
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ env.DEPS_ROOT_DIR }}/*-tmp/
|
||||
key: dep-srcs-${{ hashFiles('cmake/deps.cmake') }}
|
||||
enableCrossOsArchive: true
|
||||
- name: Build
|
||||
run: |
|
||||
./.github/scripts/build_libpng.sh
|
||||
- name: Build & install
|
||||
cmake -B build -G Ninja --preset macos-static -DFETCHCONTENT_BASE_DIR="${{ env.DEPS_ROOT_DIR }}"
|
||||
cmake --build build -- -k 0
|
||||
env:
|
||||
LDFLAGS: -fuse-ld=lld # cmake/macos-static.cmake comments explain why we use lld.
|
||||
- name: Install
|
||||
run: |
|
||||
make -kj CXXFLAGS="-O3 -flto -DNDEBUG -mmacosx-version-min=10.9 -arch x86_64 -arch arm64" PNGCFLAGS="-I libpng-staging/include" PNGLDLIBS="libpng-staging/lib/libpng.a -lz" Q=
|
||||
sudo cmake --install build --verbose
|
||||
type rgbasm rgblink rgbfix rgbgfx
|
||||
man -w 1 rgbasm rgblink rgbfix rgbgfx
|
||||
- name: Package binaries
|
||||
run: |
|
||||
mkdir bins
|
||||
cp rgb{asm,link,fix,gfx} bins
|
||||
- name: Upload binaries
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: rgbds-canary-macos-static
|
||||
path: bins
|
||||
if-no-files-found: error
|
||||
- name: Compute test dependency cache params
|
||||
id: test-deps-cache-params
|
||||
shell: bash
|
||||
run: |
|
||||
paths=$(test/fetch-test-deps.sh --get-paths)
|
||||
hash=$(test/fetch-test-deps.sh --get-hash)
|
||||
paths=$(test/external/fetch-repos.sh --get-paths)
|
||||
hash=$(test/external/fetch-repos.sh --get-hash)
|
||||
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
|
||||
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
|
||||
- name: Check test dependency repositories cache
|
||||
id: test-deps-cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
|
||||
key: ${{ matrix.os }}-${{ steps.test-deps-cache-params.outputs.hash }}
|
||||
key: macos-26-${{ steps.test-deps-cache-params.outputs.hash }}
|
||||
- name: Fetch test dependency repositories
|
||||
if: steps.test-deps-cache.outputs.cache-hit != 'true'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
test/fetch-test-deps.sh
|
||||
- name: Install test dependency dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
test/fetch-test-deps.sh --get-deps macos
|
||||
test/external/fetch-repos.sh
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: |
|
||||
test/run-tests.sh
|
||||
ctest --test-dir build --schedule-random
|
||||
|
||||
windows:
|
||||
strategy:
|
||||
matrix:
|
||||
bits: [32, 64]
|
||||
os: [windows-2019, windows-2022]
|
||||
include:
|
||||
- bits: 32
|
||||
arch: x86
|
||||
platform: Win32
|
||||
- bits: 64
|
||||
arch: x86_x64
|
||||
platform: x64
|
||||
os: [windows-2022, windows-2025]
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
- name: Install deps
|
||||
run: .github/scripts/get_win_deps.ps1
|
||||
- name: Check libraries cache
|
||||
id: cache
|
||||
uses: actions/cache@v4
|
||||
run: |
|
||||
bash .github/scripts/install-deps.sh ${{ matrix.os }}
|
||||
- name: Cache library deps
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
zbuild
|
||||
pngbuild
|
||||
key: ${{ matrix.arch }}-${{ hashFiles('zlib/**', 'libpng/**') }}
|
||||
- name: Build zlib
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll`
|
||||
cmake -S zlib -B zbuild -A ${{ matrix.platform }} -Wno-dev -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
|
||||
cmake --build zbuild --config Release -j
|
||||
- name: Install zlib
|
||||
path: ${{ env.DEPS_ROOT_DIR }}/*-tmp/
|
||||
key: dep-srcs-${{ hashFiles('cmake/deps.cmake') }}
|
||||
enableCrossOsArchive: true
|
||||
- name: Build
|
||||
shell: cmd
|
||||
run: | # ASan seems to be broken on Windows, so we disable it.
|
||||
call .github\scripts\msvc-env.bat ${{ matrix.bits }}
|
||||
cmake -B build -G Ninja --preset develop -DFETCHCONTENT_BASE_DIR="${{ env.DEPS_ROOT_DIR }}" ^
|
||||
-DSANITIZERS=OFF -DCMAKE_C_FLAGS="/nologo"
|
||||
cmake --build build -- -k 0
|
||||
- name: Install
|
||||
shell: cmd
|
||||
run: |
|
||||
cmake --install zbuild
|
||||
- name: Build libpng
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
cmake -S libpng -B pngbuild -A ${{ matrix.platform }} -Wno-dev -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=OFF -DPNG_TESTS=OFF
|
||||
cmake --build pngbuild --config Release -j
|
||||
- name: Install libpng
|
||||
run: |
|
||||
cmake --install pngbuild
|
||||
- name: Build Windows binaries
|
||||
shell: bash
|
||||
run: |
|
||||
cmake -S . -B build -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build build --config Release -j --verbose
|
||||
cmake --install build --verbose --prefix install_dir
|
||||
cmake --install build --verbose
|
||||
where rgbasm rgblink rgbfix rgbgfx
|
||||
- name: Package binaries
|
||||
shell: bash
|
||||
working-directory: build
|
||||
run: |
|
||||
mkdir bins
|
||||
cp install_dir/bin/{rgbasm.exe,rgblink.exe,rgbfix.exe,rgbgfx.exe,zlib1.dll,libpng16.dll} bins
|
||||
cpack -DCPACK_PACKAGE_FILE_NAME=rgbds-win${{ matrix.bits }} -G ZIP --verbose
|
||||
- name: Upload Windows binaries
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: rgbds-canary-w${{ matrix.bits }}-${{ matrix.os }}
|
||||
path: bins
|
||||
path: build/rgbds-win${{ matrix.bits }}.zip
|
||||
if-no-files-found: error
|
||||
- name: Compute test dependency cache params
|
||||
id: test-deps-cache-params
|
||||
shell: bash
|
||||
run: |
|
||||
paths=$(test/fetch-test-deps.sh --get-paths)
|
||||
hash=$(test/fetch-test-deps.sh --get-hash)
|
||||
paths=$(test/external/fetch-repos.sh --get-paths)
|
||||
hash=$(test/external/fetch-repos.sh --get-hash)
|
||||
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
|
||||
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
|
||||
- name: Check test dependency repositories cache
|
||||
id: test-deps-cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
|
||||
key: ${{ matrix.os }}-${{ matrix.bits }}-${{ steps.test-deps-cache-params.outputs.hash }}
|
||||
- name: Fetch test dependency repositories
|
||||
if: steps.test-deps-cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
continue-on-error: true
|
||||
run: |
|
||||
test/fetch-test-deps.sh
|
||||
- name: Install test dependency dependencies
|
||||
shell: bash
|
||||
test/external/fetch-repos.sh
|
||||
- name: Run tests using CTest
|
||||
run: |
|
||||
test/fetch-test-deps.sh --get-deps ${{ matrix.os }}
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: |
|
||||
cp bins/* .
|
||||
cp bins/*.dll test/gfx
|
||||
test/run-tests.sh
|
||||
ctest --test-dir build --schedule-random
|
||||
|
||||
windows-mingw-build:
|
||||
strategy:
|
||||
matrix:
|
||||
bits: [32, 64]
|
||||
include:
|
||||
- bits: 32
|
||||
arch: i686
|
||||
triplet: i686-w64-mingw32
|
||||
- bits: 64
|
||||
arch: x86-64
|
||||
triplet: x86_64-w64-mingw32
|
||||
fail-fast: false
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
DIST_DIR: win${{ matrix.bits }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
- name: Install deps
|
||||
shell: bash
|
||||
run: |
|
||||
./.github/scripts/install_deps.sh ubuntu
|
||||
- name: Install MinGW
|
||||
run: | # dpkg-dev is apparently required for pkg-config for cross-building
|
||||
sudo apt-get install g++-mingw-w64-${{ matrix.arch }}-win32 mingw-w64-tools libz-mingw-w64-dev dpkg-dev
|
||||
- name: Install libpng dev headers for MinGW
|
||||
run: |
|
||||
./.github/scripts/mingw-w64-libpng-dev.sh ${{ matrix.triplet }}
|
||||
.github/scripts/install-deps.sh ubuntu mingw${{ matrix.bits }}
|
||||
- name: Cache library deps
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ env.DEPS_ROOT_DIR }}/*-tmp/
|
||||
key: dep-srcs-${{ hashFiles('cmake/deps.cmake') }}
|
||||
enableCrossOsArchive: true
|
||||
- name: Cross-build Windows binaries
|
||||
run: | # MinGW doesn't support `--preset develop` sanitizers ASan or UBSan, so we disable them.
|
||||
dll_search_dir=$(printf '%s\n' /usr/lib/gcc/*-w64-mingw32/*-win32 | tee -a /dev/stderr)
|
||||
cmake -B build -G Ninja --preset develop -DFETCHCONTENT_BASE_DIR="${{ env.DEPS_ROOT_DIR }}" \
|
||||
-DSANITIZERS=OFF -DDLL_SEARCH_DIRS="$dll_search_dir" \
|
||||
--toolchain cmake/toolchain-mingw${{ matrix.bits }}.cmake
|
||||
cmake --build build -- -k 0
|
||||
- name: Package Windows binaries
|
||||
run: |
|
||||
make mingw${{ matrix.bits }} -kj Q=
|
||||
- name: Package binaries
|
||||
run: | # DLL dependencies can be figured out using e.g. Dependency Walker or objdump -p
|
||||
mkdir bins
|
||||
mv -v rgb{asm,link,fix,gfx}.exe bins/
|
||||
cp -v /usr/${{ matrix.triplet }}/lib/zlib1.dll bins
|
||||
cp -v /usr/${{ matrix.triplet }}/bin/libpng16-16.dll bins
|
||||
cp -v /usr/lib/gcc/${{ matrix.triplet }}/10-win32/lib{ssp-0,stdc++-6}.dll bins
|
||||
[ "${{ matrix.bits }}" -ne 32 ] || cp -v /usr/lib/gcc/${{ matrix.triplet }}/10-win32/libgcc_s_dw2-1.dll bins
|
||||
cmake --install build --prefix . --verbose --component binaries
|
||||
cmake --install build --prefix . --verbose --component shared-libs
|
||||
- name: Upload Windows binaries
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: rgbds-canary-mingw-win${{ matrix.bits }}
|
||||
path: bins
|
||||
path: bin
|
||||
if-no-files-found: error
|
||||
- name: Upload Windows test binaries
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: testing-programs-mingw-win${{ matrix.bits }}
|
||||
path: |
|
||||
test/gfx/randtilegen.exe
|
||||
test/gfx/rgbgfx_test.exe
|
||||
if-no-files-found: error
|
||||
|
||||
windows-mingw-testing:
|
||||
needs: windows-mingw-build
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-2019, windows-2022]
|
||||
os: [windows-2022, windows-2025]
|
||||
bits: [32, 64]
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
- name: Install test deps
|
||||
run: |
|
||||
.github/scripts/install-deps.sh windowsmingw
|
||||
- name: Retrieve binaries
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: rgbds-canary-mingw-win${{ matrix.bits }}
|
||||
path: bins
|
||||
- name: Retrieve test binaries
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: testing-programs-mingw-win${{ matrix.bits }}
|
||||
path: test/gfx
|
||||
- name: Extract binaries
|
||||
shell: bash
|
||||
run: |
|
||||
cp bins/* .
|
||||
cp bins/*.dll test/gfx
|
||||
- name: Compute test dependency cache params
|
||||
id: test-deps-cache-params
|
||||
shell: bash
|
||||
run: |
|
||||
paths=$(test/fetch-test-deps.sh --get-paths)
|
||||
hash=$(test/fetch-test-deps.sh --get-hash)
|
||||
paths=$(test/external/fetch-repos.sh --get-paths)
|
||||
hash=$(test/external/fetch-repos.sh --get-hash)
|
||||
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
|
||||
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
|
||||
- name: Check test dependency repositories cache
|
||||
id: test-deps-cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
|
||||
key: mingw-${{ matrix.bits }}-${{ steps.test-deps-cache-params.outputs.hash }}
|
||||
- name: Fetch test dependency repositories
|
||||
if: steps.test-deps-cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
continue-on-error: true
|
||||
run: |
|
||||
test/fetch-test-deps.sh
|
||||
- name: Install test dependency dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
test/fetch-test-deps.sh --get-deps ${{ matrix.os }}
|
||||
test/external/fetch-repos.sh
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: |
|
||||
test/run-tests.sh
|
||||
test/run-tests.sh --os ${{ matrix.os }} --jobs "$(getconf _NPROCESSORS_ONLN)"
|
||||
|
||||
cygwin:
|
||||
strategy:
|
||||
matrix:
|
||||
bits: [32, 64]
|
||||
include:
|
||||
- bits: 32
|
||||
arch: x86
|
||||
- bits: 64
|
||||
arch: x86_64
|
||||
arch: [x86, x86_64]
|
||||
fail-fast: false
|
||||
runs-on: windows-2019
|
||||
runs-on: windows-2022
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
CYGWIN_NOWINPATH: 1
|
||||
CHERE_INVOKING: 1
|
||||
defaults:
|
||||
run:
|
||||
shell: C:\cygwin\bin\bash.exe -leo igncr '{0}'
|
||||
steps:
|
||||
- name: Save Windows git location for the PATH
|
||||
shell: pwsh
|
||||
run: | # The `cygwin/cygwin-install-action` step will override the PATH with Cygwin's binaries
|
||||
"ORIGINAL_GIT_DIR=$(Split-Path (Get-Command git).Source)" >> $env:GITHUB_ENV
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
uses: actions/checkout@v7
|
||||
- name: Setup Cygwin
|
||||
uses: cygwin/cygwin-install-action@v4
|
||||
uses: cygwin/cygwin-install-action@v6
|
||||
with:
|
||||
platform: ${{ matrix.arch }}
|
||||
packages: >-
|
||||
bison
|
||||
cmake
|
||||
gcc-g++
|
||||
git
|
||||
libpng-devel
|
||||
make
|
||||
ninja
|
||||
pkg-config
|
||||
- name: Build & install using Make
|
||||
shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -o igncr '{0}'
|
||||
run: | # Cygwin does not support `make develop` sanitizers ASan or UBSan
|
||||
make -kj Q=
|
||||
make install -j Q=
|
||||
- name: Run tests
|
||||
shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -o igncr '{0}'
|
||||
python3
|
||||
python-imaging
|
||||
- name: Build using Make
|
||||
if: matrix.arch == 'x86'
|
||||
run: | # Cygwin doesn't support `make develop` sanitizers ASan or UBSan, so we don't use it.
|
||||
make -k -j "$(getconf _NPROCESSORS_ONLN)" Q=
|
||||
- name: Install using Make
|
||||
if: matrix.arch == 'x86'
|
||||
run: |
|
||||
test/run-tests.sh --only-internal
|
||||
make install Q=
|
||||
type rgbasm rgblink rgbfix rgbgfx
|
||||
man -w 1 rgbasm rgblink rgbfix rgbgfx
|
||||
- name: Build using CMake
|
||||
if: matrix.arch == 'x86_64'
|
||||
run: | # Cygwin doesn't support `--preset develop` sanitizers ASan or UBSan, so we disable them.
|
||||
cmake -B build -G Ninja --preset develop -DSANITIZERS=OFF
|
||||
cmake --build build -- -k 0
|
||||
- name: Install using CMake
|
||||
if: matrix.arch == 'x86_64'
|
||||
run: |
|
||||
cmake --install build --verbose
|
||||
type rgbasm rgblink rgbfix rgbgfx
|
||||
man -w 1 rgbasm rgblink rgbfix rgbgfx
|
||||
- name: Compute test dependency cache params
|
||||
id: test-deps-cache-params
|
||||
run: |
|
||||
paths=$(test/external/fetch-repos.sh --get-paths)
|
||||
hash=$(test/external/fetch-repos.sh --get-hash)
|
||||
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
|
||||
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
|
||||
- name: Check test dependency repositories cache
|
||||
id: test-deps-cache
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
|
||||
key: cygwin-${{ matrix.bits }}-${{ steps.test-deps-cache-params.outputs.hash }}
|
||||
- name: Fetch test dependency repositories
|
||||
if: steps.test-deps-cache.outputs.cache-hit != 'true'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
test/external/fetch-repos.sh
|
||||
- name: Run tests using our script
|
||||
if: matrix.arch == 'x86'
|
||||
run: | # 32-bit Cygwin's `git` 2.38 doesn't support `git clone --revision`, so we don't fetch/run external tests.
|
||||
test/run-tests.sh --os cygwin --only-internal --jobs "$(getconf _NPROCESSORS_ONLN)"
|
||||
- name: Run tests using CTest
|
||||
if: matrix.arch == 'x86_64'
|
||||
run: |
|
||||
ctest --test-dir build --schedule-random
|
||||
- name: Use Windows git location in the PATH
|
||||
shell: pwsh
|
||||
run: | # Prevents the `actions/checkout` post-job cleanup from using Cygwin's git binary
|
||||
"$env:ORIGINAL_GIT_DIR" >> $env:GITHUB_PATH
|
||||
|
||||
freebsd:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
uses: actions/checkout@v7
|
||||
- name: Build & test using CMake on FreeBSD
|
||||
uses: vmactions/freebsd-vm@v1
|
||||
with:
|
||||
release: "15.0"
|
||||
envs: >-
|
||||
TERM CLICOLOR CLICOLOR_FORCE
|
||||
CMAKE_COLOR_DIAGNOSTICS CMAKE_CONFIG_TYPE
|
||||
CTEST_PARALLEL_LEVEL
|
||||
CTEST_NO_TESTS_ACTION CTEST_OUTPUT_ON_FAILURE
|
||||
GIT_CONFIG_COUNT GIT_CONFIG_KEY_0 GIT_CONFIG_VALUE_0
|
||||
release: "15.1"
|
||||
usesh: true
|
||||
copyback: false
|
||||
prepare: |
|
||||
pkg install -y \
|
||||
bash \
|
||||
bison \
|
||||
cmake \
|
||||
git \
|
||||
png
|
||||
run: | # FreeBSD `c++` compiler does not support `make develop` sanitizers ASan or UBSan
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=c++ -DUSE_EXTERNAL_TESTS=OFF
|
||||
cmake --build build -j4 --verbose
|
||||
.github/scripts/install-deps.sh freebsd
|
||||
run: |
|
||||
: # Build
|
||||
cmake -B build -G Ninja --preset develop
|
||||
cmake --build build -- -k 0
|
||||
: # Install
|
||||
cmake --install build --verbose
|
||||
cmake --build build --target test
|
||||
type rgbasm rgblink rgbfix rgbgfx
|
||||
man -w 1 rgbasm rgblink rgbfix rgbgfx
|
||||
: # Run tests
|
||||
: # Leak detection is not supported on FreeBSD, so we disable it.
|
||||
. .github/scripts/freebsd-env.sh
|
||||
ASAN_OPTIONS=detect_leaks=0 ctest --test-dir build --schedule-random
|
||||
|
||||
@@ -4,57 +4,47 @@ on:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- man/gbz80.7
|
||||
- man/rgbds.5
|
||||
- man/rgbds.7
|
||||
- man/rgbasm.1
|
||||
- man/rgbasm.5
|
||||
- man/rgbasm-old.5
|
||||
- man/rgblink.1
|
||||
- man/rgblink.5
|
||||
- man/rgbfix.1
|
||||
- man/rgbgfx.1
|
||||
- man/*
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
# Force colored output (see https://bixense.com/clicolors/ and https://force-color.org/)
|
||||
TERM: xterm-256color
|
||||
CLICOLOR: 1
|
||||
CLICOLOR_FORCE: 1
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: github.repository_owner == 'gbdev'
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- name: Checkout rgbds@master
|
||||
uses: actions/checkout@v4
|
||||
- name: Checkout rgbds
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
repository: gbdev/rgbds
|
||||
ref: master
|
||||
path: rgbds
|
||||
- name: Checkout rgbds-www@master
|
||||
uses: actions/checkout@v4
|
||||
sparse-checkout: man # Avoid checking out other files, we don't use them here.
|
||||
- name: Checkout rgbds-www
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
repository: gbdev/rgbds-www
|
||||
ref: master
|
||||
path: rgbds-www
|
||||
repository: ${{ github.repository_owner }}/rgbds-www
|
||||
ref: master # Need to check out the branch to be able to commit on and push it.
|
||||
ssh-key: !!str ${{ secrets.SSH_KEY_SECRET }}
|
||||
- name: Install groff and mandoc
|
||||
run: |
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get install -yq groff mandoc
|
||||
sudo apt install -Uyq groff mandoc -o APT::Color=yes -o Acquire::Queue-Mode=access
|
||||
- name: Update pages
|
||||
working-directory: rgbds/man
|
||||
run: |
|
||||
../../rgbds-www/maintainer/man_to_html.sh master *
|
||||
- name: Push new pages
|
||||
working-directory: rgbds-www
|
||||
env:
|
||||
GIT_AUTHOR_NAME: !!str ${{ github.actor }}
|
||||
GIT_AUTHOR_EMAIL: !!str ${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com
|
||||
GIT_COMMITTER_NAME: github-actions[bot]
|
||||
GIT_COMMITTER_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
|
||||
run: |
|
||||
mkdir -p -m 700 ~/.ssh
|
||||
echo "${{ secrets.SSH_KEY_SECRET }}" > ~/.ssh/id_ed25519
|
||||
chmod 0600 ~/.ssh/id_ed25519
|
||||
eval $(ssh-agent -s)
|
||||
ssh-add ~/.ssh/id_ed25519
|
||||
git config --global user.name "GitHub Action"
|
||||
git config --global user.email "[email protected]"
|
||||
git add -A
|
||||
git commit -m "Update RGBDS master documentation"
|
||||
if git remote | grep -q origin; then
|
||||
git remote set-url origin [email protected]:gbdev/rgbds-www.git
|
||||
else
|
||||
git remote add origin [email protected]:gbdev/rgbds-www.git
|
||||
fi
|
||||
git push origin master
|
||||
git push
|
||||
|
||||
+4
-1
@@ -2,6 +2,7 @@
|
||||
/rgblink
|
||||
/rgbfix
|
||||
/rgbgfx
|
||||
/install.sh
|
||||
/rgbshim.sh
|
||||
/coverage/
|
||||
*.o
|
||||
@@ -10,9 +11,11 @@
|
||||
*.gcno
|
||||
*.gcda
|
||||
*.gcov
|
||||
/compile_flags.txt
|
||||
CMakeCache.txt
|
||||
CMakeFiles/
|
||||
cmake_install.cmake
|
||||
build/
|
||||
CMakeUserPresets.json
|
||||
build*/
|
||||
*.dSYM/
|
||||
callgrind.out.*
|
||||
|
||||
+191
-94
@@ -1,122 +1,199 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# 3.9 required for LTO checks
|
||||
# 3.17 optional for CMAKE_CTEST_ARGUMENTS
|
||||
cmake_minimum_required(VERSION 3.9..3.17 FATAL_ERROR)
|
||||
# - 3.24 is required for `FetchContent`'s `find_package` integration.
|
||||
# Older versions *may* work, but we can't test them; compat patches are welcome.
|
||||
# - 3.17 is required for `CHECK_*` messages to display properly, but is not essential.
|
||||
# - 3.9 is required for LTO checks.
|
||||
cmake_minimum_required(VERSION 3.24...4.3 FATAL_ERROR)
|
||||
|
||||
# Read the project version from the header (the canonical source of truth).
|
||||
file(STRINGS "include/version.hpp" version_defines REGEX "^[ \t]*#define[ \t]+PACKAGE_VERSION_")
|
||||
foreach(line IN LISTS version_defines)
|
||||
# We want the `CMAKE_MATCH_n` variables, so we just need to run *some* regex op.
|
||||
string(REGEX MATCH "PACKAGE_(VERSION_[^ \t]+)[ \t]+([0-9]+)" dummy "${line}")
|
||||
set("${CMAKE_MATCH_1}" "${CMAKE_MATCH_2}")
|
||||
endforeach()
|
||||
|
||||
project(rgbds
|
||||
LANGUAGES CXX)
|
||||
|
||||
include(CTest)
|
||||
|
||||
# get real path of source and binary directories
|
||||
get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH)
|
||||
get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH)
|
||||
|
||||
# reject in-source builds, may conflict with Makefile
|
||||
if(srcdir STREQUAL bindir)
|
||||
message("RGBDS should not be built in the source directory.")
|
||||
message("Instead, create a separate build directory and specify to CMake the path to the source directory.")
|
||||
message(FATAL_ERROR "Terminating configuration")
|
||||
VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}"
|
||||
LANGUAGES CXX
|
||||
DESCRIPTION "Game Boy assembly toolchain"
|
||||
HOMEPAGE_URL "https://rgbds.gbdev.io")
|
||||
if(DEFINED VERSION_RC)
|
||||
string(APPEND CMAKE_PROJECT_VERSION "-rc${VERSION_RC}")
|
||||
endif()
|
||||
|
||||
option(SANITIZERS "Build with sanitizers enabled" OFF) # Ignored on MSVC
|
||||
option(MORE_WARNINGS "Turn on more warnings" OFF) # Ignored on MSVC
|
||||
# Reject in-source builds, as they may conflict with the Makefile.
|
||||
get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH)
|
||||
get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH)
|
||||
if(srcdir STREQUAL bindir)
|
||||
message(FATAL_ERROR "RGBDS should not be built in the source directory.
|
||||
Instead, create a separate build directory and specify to CMake the path to the source directory.")
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
# MSVC's own standard library triggers warning C5105,
|
||||
# "macro expansion producing 'defined' has undefined behavior".
|
||||
# Warning C5030 is about unknown attributes (`[[gnu::ATTR]]`), none of ours being load-bearing.
|
||||
# Warning C4996 is about using POSIX names, which we want to do for portability.
|
||||
# We also opt into the C++20-conformant preprocessor.
|
||||
add_compile_options(/MP /wd5105 /wd5030 /wd4996 /Zc:preprocessor)
|
||||
add_definitions(/D_CRT_SECURE_NO_WARNINGS)
|
||||
include(CTest) # Note: CTest only functions properly if included from the top-level CMakeLists.
|
||||
include(GNUInstallDirs)
|
||||
include(CMakeDependentOption)
|
||||
|
||||
if(SANITIZERS)
|
||||
set(SAN_FLAGS /fsanitize=address)
|
||||
add_compile_options(${SAN_FLAGS})
|
||||
add_link_options(${SAN_FLAGS})
|
||||
endif()
|
||||
else()
|
||||
add_compile_options(-Wall -pedantic)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# C++20 allows macros to take zero variadic arguments, but Clang (aka AppleClang on macOS)
|
||||
# does not recognize this yet.
|
||||
add_compile_options(-Wno-gnu-zero-variadic-macro-arguments)
|
||||
endif()
|
||||
if(SANITIZERS)
|
||||
## Compiler switches that should apply to our deps too.
|
||||
|
||||
option(SANITIZERS "Build with sanitizers enabled" OFF)
|
||||
cmake_dependent_option(MORE_WARNINGS "Turn on more warnings" OFF "NOT MSVC" OFF)
|
||||
|
||||
if(NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY) # Allow this to be overridden from the CLI easily.
|
||||
# We link against the Microsoft C++ runtime libs statically, except the debug-mode one.
|
||||
# This is because Microsoft's license terms (through some indirection) allow us to redistribute
|
||||
# the runtime lib code *except* the debug-mode libs'.
|
||||
# Since we want to remain able to not think too hard about debug executables, we link against
|
||||
# the debug libs dynamically, shifting the burden of obtaining them onto the recipient.
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:DebugDLL>")
|
||||
endif()
|
||||
|
||||
if(SANITIZERS)
|
||||
if(MSVC)
|
||||
message(STATUS "ASan enabled")
|
||||
add_compile_options(/fsanitize=address) # Note that this shouldn't be passed to the linker.
|
||||
else() # We assume a GNU-like compiler.
|
||||
message(STATUS "ASan and UBSan enabled")
|
||||
set(SAN_FLAGS -fsanitize=address -fsanitize=undefined
|
||||
-fsanitize=float-divide-by-zero)
|
||||
add_compile_options(${SAN_FLAGS})
|
||||
add_link_options(${SAN_FLAGS})
|
||||
add_definitions(-D_GLIBCXX_ASSERTIONS)
|
||||
# A non-zero optimization level is desired in debug mode, but allow overriding it nonetheless
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-g -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls ${CMAKE_CXX_FLAGS_DEBUG}"
|
||||
CACHE STRING "" FORCE)
|
||||
add_definitions(-D_GLIBCXX_ASSERTIONS -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG)
|
||||
# A non-zero optimization level is desired even in debug mode (especially for Clang),
|
||||
# and the two codegen flags improve the sanitizers' backtraces, but we want the user to
|
||||
# be able to override these easily so we put them first.
|
||||
string(PREPEND CMAKE_CXX_FLAGS_DEBUG "-Og -fno-omit-frame-pointer -fno-optimize-sibling-calls ")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(CHECK_START "Checking if LTO is supported")
|
||||
include(CheckIPOSupported)
|
||||
check_ipo_supported(RESULT enable_lto)
|
||||
if(enable_lto)
|
||||
message(CHECK_PASS "yes (enabled only in release modes)")
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON)
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON)
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_MINSIZEREL ON)
|
||||
else()
|
||||
message(CHECK_FAIL "no")
|
||||
endif()
|
||||
|
||||
# Use versioning consistent with Makefile:
|
||||
# the git revision is used but uses the fallback in an archive.
|
||||
|
||||
message(CHECK_START "Determining RGBDS version from Git history")
|
||||
list(APPEND CMAKE_MESSAGE_INDENT " ")
|
||||
set(GIT_REV "") # This fallback is important!
|
||||
find_package(Git)
|
||||
list(POP_BACK CMAKE_MESSAGE_INDENT)
|
||||
if(NOT Git_FOUND)
|
||||
message(CHECK_FAIL "Git not found")
|
||||
else()
|
||||
execute_process(COMMAND "${GIT_EXECUTABLE}" --git-dir=.git -c safe.directory='*'
|
||||
describe --tags --dirty --always --match "v[0-9]*"
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
OUTPUT_VARIABLE GIT_REV OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_VARIABLE git_err ERROR_STRIP_TRAILING_WHITESPACE
|
||||
RESULT_VARIABLE result)
|
||||
if(NOT result EQUAL 0)
|
||||
# Note that this happens e.g. when building from a tarball, so it shouldn't fail the build!
|
||||
message(CHECK_FAIL "error ${result} from Git:")
|
||||
list(APPEND CMAKE_MESSAGE_INDENT " ")
|
||||
message("${git_err}")
|
||||
list(POP_BACK CMAKE_MESSAGE_INDENT)
|
||||
else()
|
||||
message(CHECK_PASS "${GIT_REV}")
|
||||
if(NOT "${GIT_REV}" MATCHES "^v[0-9]+\\.[0-9]+\\.[0-9]+(-rc[0-9]+)?")
|
||||
# Can't find an ancestor tag! (That passes `--match`, anyway.)
|
||||
message(WARNING "No `v*` Git tag reachable; falling back")
|
||||
elseif(NOT CMAKE_MATCH_0 STREQUAL "v${CMAKE_PROJECT_VERSION}")
|
||||
message(SEND_ERROR "\
|
||||
Version mismatch! Git says ${CMAKE_MATCH_0},
|
||||
version.hpp says v${CMAKE_PROJECT_VERSION}!")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
## Dependencies.
|
||||
|
||||
include(FetchContent)
|
||||
include(cmake/deps.cmake)
|
||||
|
||||
# Be sure to make zlib available before libpng, otherwise libpng
|
||||
# will attempt to `find_package(ZLIB)` without going through `FetchContent`.
|
||||
if(NOT DEFINED ZLIB_BUILD_TESTING) # Unless overridden (e.g. in the cache), we don't care about zlib's tests.
|
||||
set(ZLIB_BUILD_TESTING OFF)
|
||||
endif()
|
||||
FetchContent_MakeAvailable(ZLIB)
|
||||
if(NOT DEFINED ZLIB_INCLUDE_DIRS)
|
||||
set(ZLIB_INCLUDE_DIRS "${zlib_BINARY_DIR};${zlib_SOURCE_DIR}") # libpng's `genout` script relies on this variable to be set.
|
||||
endif()
|
||||
# Statically building zlib (from source) generates a target named differently.
|
||||
if(NOT TARGET ZLIB::ZLIB AND TARGET zlibstatic)
|
||||
add_library(ZLIB::ZLIB ALIAS zlibstatic)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED PNG_TESTS) # Unless overridden (e.g. in the cache), we don't care about libpng's tests.
|
||||
set(PNG_TESTS OFF)
|
||||
endif()
|
||||
FetchContent_MakeAvailable(PNG)
|
||||
if(NOT TARGET PNG::PNG)
|
||||
if(PNG_SHARED)
|
||||
add_library(PNG::PNG ALIAS png_shared)
|
||||
else()
|
||||
add_library(PNG::PNG ALIAS png_static)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
## The actual stuff.
|
||||
# Any compiler options that shouldn't apply to our dependencies go here.
|
||||
|
||||
include_directories("include")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
if(MSVC)
|
||||
add_compile_options(
|
||||
/wd5030 # Warning C5030 is about unknown attributes (`[[gnu::ATTR]]`), none of ours being load-bearing.
|
||||
/wd4996 # Warning C4996 is about using POSIX names, which we want to do for portability.
|
||||
/Zc:preprocessor # Opt into the C++20-conformant preprocessor.
|
||||
)
|
||||
add_definitions(/D_CRT_SECURE_NO_WARNINGS)
|
||||
else()
|
||||
add_compile_options(-Wall -pedantic -Wno-unknown-warning-option -fno-exceptions -fno-rtti)
|
||||
|
||||
if(MORE_WARNINGS)
|
||||
add_compile_options(-Werror -Wextra
|
||||
add_compile_options(-Wextra
|
||||
-Walloc-zero -Wcast-align -Wcast-qual -Wduplicated-branches -Wduplicated-cond
|
||||
-Wfloat-equal -Wlogical-op -Wnull-dereference -Wold-style-cast -Wshift-overflow=2
|
||||
-Wstringop-overflow=4 -Wtrampolines -Wundef -Wuninitialized -Wunused -Wshadow
|
||||
-Wformat=2 -Wformat-overflow=2 -Wformat-truncation=1
|
||||
-Wno-format-nonliteral -Wno-strict-overflow
|
||||
-Wno-unused-but-set-variable # bison's `yynerrs_` is incremented but unused
|
||||
-Wno-type-limits -Wno-tautological-constant-out-of-range-compare
|
||||
-Wvla # MSVC does not support VLAs
|
||||
-Wno-unknown-warning-option) # Clang shouldn't diagnose unknown warnings
|
||||
-Wvla) # MSVC does not support VLAs
|
||||
endif()
|
||||
|
||||
add_compile_options(-Wno-unused-but-set-variable # bison's `yynerrs_` is incremented but unused
|
||||
# C++20 allows macros to take zero variadic arguments.
|
||||
# Some versions of Clang don't recognize this, and treat them as a GNU extension.
|
||||
-Wno-gnu-zero-variadic-macro-arguments)
|
||||
|
||||
if(MINGW)
|
||||
# MinGW warns about format specifiers like `%z` and `%j`, which are missing on Windows XP and earlier.
|
||||
# We rely on runtimes more modern than that, so we can ignore those warnings.
|
||||
# If this is a problem for you: use Microsoft's equivalents, or define `__USE_MINGW_ANSI_STDIO=1`.
|
||||
# https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/
|
||||
add_compile_options(-Wno-error=format -Wno-error=format-extra-args)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Use versioning consistent with Makefile
|
||||
# the git revision is used but uses the fallback in an archive
|
||||
|
||||
find_program(GIT git)
|
||||
if(GIT)
|
||||
execute_process(COMMAND ${GIT} --git-dir=.git -c safe.directory='*' describe --tags --dirty --always
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_REV OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET)
|
||||
message(STATUS "RGBDS version: ${GIT_REV}")
|
||||
else(GIT)
|
||||
message(STATUS "Cannot determine RGBDS version (Git not installed), falling back")
|
||||
endif(GIT)
|
||||
|
||||
find_package(PkgConfig)
|
||||
if(MSVC OR NOT PKG_CONFIG_FOUND)
|
||||
# fallback to find_package
|
||||
# cmake's FindPNG is very fragile; it breaks when multiple versions are installed
|
||||
# this is most evident on macOS but can occur on Linux too
|
||||
find_package(PNG REQUIRED)
|
||||
else()
|
||||
pkg_check_modules(LIBPNG REQUIRED libpng)
|
||||
endif()
|
||||
|
||||
include_directories("${PROJECT_SOURCE_DIR}/include")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
add_subdirectory(src)
|
||||
set(CMAKE_CTEST_ARGUMENTS "--verbose")
|
||||
add_subdirectory(test)
|
||||
|
||||
# By default, build in Release mode; Debug mode must be explicitly requested
|
||||
# (You may want to augment it with the options above)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
message(CHECK_START "Checking if LTO is supported")
|
||||
include(CheckIPOSupported)
|
||||
check_ipo_supported(RESULT enable_lto)
|
||||
if(enable_lto)
|
||||
message(CHECK_PASS "yes")
|
||||
set_property(TARGET rgbasm rgblink rgbfix rgbgfx PROPERTY INTERPROCEDURAL_OPTIMIZATION ON)
|
||||
else()
|
||||
message(CHECK_FAIL "no")
|
||||
endif()
|
||||
if(BUILD_TESTING) # This option is defined implicitly by `include(CTest)`.
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
set(MANDIR "share/man")
|
||||
set(man1 "man/rgbasm.1"
|
||||
"man/rgbfix.1"
|
||||
"man/rgbgfx.1"
|
||||
@@ -129,6 +206,26 @@ set(man7 "man/gbz80.7"
|
||||
"man/rgbds.7")
|
||||
|
||||
foreach(SECTION "man1" "man5" "man7")
|
||||
set(DEST "${MANDIR}/${SECTION}")
|
||||
install(FILES ${${SECTION}} DESTINATION ${DEST})
|
||||
install(FILES ${${SECTION}} DESTINATION "${CMAKE_INSTALL_MANDIR}/${SECTION}" COMPONENT man)
|
||||
endforeach()
|
||||
|
||||
## Packaging.
|
||||
|
||||
# We only specify here the package-agnostic options;
|
||||
# the rest is rather convention from our side, and thus more appropriate for presets or CLI flags.
|
||||
## CPACK_PACKAGE_NAME: copied from `project()`
|
||||
set(CPACK_PACKAGE_VENDOR "GBDev")
|
||||
set(CPACK_PACKAGE_VERSION "${CMAKE_PROJECT_VERSION}") # The individual components are defined implicitly.
|
||||
set(CPACK_PACKAGE_DESCRIPTION "An assembly toolchain for the Nintendo Game Boy and Game Boy Color") # Same as our repo's description.
|
||||
## CPACK_PACKAGE_DESCRIPTION_SUMMARY: copied from `project()`
|
||||
set(CPACK_PACKAGE_HOMEPAGE_URL "https://rgbds.gbdev.io")
|
||||
## CPACK_PACKAGE_FILE_NAME: should be provided at runtime (`cpack -P`)
|
||||
set(CPACK_PACKAGE_CHECKSUM SHA256)
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
|
||||
set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.md")
|
||||
set(CPACK_STRIP_FILES ON) # Only applies to binary packages, not sources.
|
||||
set(CPACK_VERBATIM_VARIABLES ON)
|
||||
set(CPACK_THREADS 0) # Use all available CPU cores.
|
||||
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)
|
||||
|
||||
include(CPack)
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"version": 3,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "develop",
|
||||
"description": "Debugging config for maintainers",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": true,
|
||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true,
|
||||
"CMAKE_LINK_WARNING_AS_ERROR": true,
|
||||
"MORE_WARNINGS": true,
|
||||
"SANITIZERS": true
|
||||
},
|
||||
"warnings": { "uninitialized": true },
|
||||
"errors": { "dev": true }
|
||||
},
|
||||
{
|
||||
"name": "develop-msbuild32",
|
||||
"inherits": ["develop", "msbuild32"]
|
||||
},
|
||||
{
|
||||
"name": "develop-msbuild64",
|
||||
"inherits": ["develop", "msbuild64"]
|
||||
},
|
||||
|
||||
{
|
||||
"name": "msbuild32",
|
||||
"description": "Flags for building 32-bit executables with MSBuild",
|
||||
"architecture": "Win32"
|
||||
},
|
||||
{
|
||||
"name": "msbuild64",
|
||||
"description": "Flags for building 64-bit executables with MSBuild",
|
||||
"architecture": "x64"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "macos-static",
|
||||
"description": "Flags for building an executable compatible with old macOS",
|
||||
"cacheVariables": {
|
||||
"CMAKE_PROJECT_TOP_LEVEL_INCLUDES": "cmake/macos-static.cmake"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+16
-5
@@ -1,14 +1,25 @@
|
||||
FROM debian:12-slim
|
||||
FROM debian:13-slim
|
||||
LABEL org.opencontainers.image.source=https://github.com/gbdev/rgbds
|
||||
ARG version=0.9.2
|
||||
ARG version=1.0.3
|
||||
WORKDIR /rgbds
|
||||
|
||||
COPY . .
|
||||
|
||||
# Install dependencies
|
||||
RUN apt-get update && \
|
||||
apt-get install sudo make cmake gcc build-essential -y
|
||||
RUN ./.github/scripts/install-deps.sh debian
|
||||
|
||||
RUN ./.github/scripts/install_deps.sh ubuntu-22.04
|
||||
RUN make -j CXXFLAGS="-O3 -flto -DNDEBUG -static" PKG_CONFIG="pkg-config --static" Q=
|
||||
# Build RGBDS
|
||||
RUN make -j "$(getconf _NPROCESSORS_ONLN)" CXXFLAGS="-O3 -flto -DNDEBUG -static" PKG_CONFIG="pkg-config --static" Q=
|
||||
|
||||
RUN tar caf rgbds-${version}-linux-x86_64.tar.xz --transform='s#.*/##' rgbasm rgblink rgbfix rgbgfx man/* .github/scripts/install.sh
|
||||
# Create the install script
|
||||
RUN make install.sh Q=
|
||||
|
||||
# Create an archive with the compiled executables, man pages, and install script,
|
||||
# so it can be copied outside of the container and installed/used in another system
|
||||
RUN tar caf rgbds-linux-x86_64.tar.xz --transform='s#.*/##' rgbasm rgblink rgbfix rgbgfx man/* install.sh
|
||||
|
||||
# Install RGBDS on the container so all the executables will be available in the PATH
|
||||
RUN cp man/* .
|
||||
RUN make install Q=
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 1997-2024, Carsten Sørensen and RGBDS contributors.
|
||||
Copyright (c) 1996-2025, Carsten Sørensen and RGBDS contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .cpp .y .o
|
||||
|
||||
.PHONY: all clean install checkdiff develop debug profile coverage iwyu mingw32 mingw64 wine-shim dist
|
||||
.PHONY: all clean install develop debug profile coverage format tidy iwyu wine-shim dist
|
||||
|
||||
# User-defined variables
|
||||
|
||||
@@ -15,6 +15,7 @@ SUFFIX :=
|
||||
STRIP := -s
|
||||
BINMODE := 755
|
||||
MANMODE := 644
|
||||
MANSRC := man/
|
||||
|
||||
# Other variables
|
||||
|
||||
@@ -26,34 +27,45 @@ PNGLDLIBS := `${PKG_CONFIG} --libs-only-l libpng`
|
||||
# Note: if this comes up empty, `version.cpp` will automatically fall back to last release number
|
||||
VERSION_STRING := `git --git-dir=.git -c safe.directory='*' describe --tags --dirty --always 2>/dev/null`
|
||||
|
||||
WARNFLAGS := -Wall -pedantic -Wno-unknown-warning-option -Wno-gnu-zero-variadic-macro-arguments
|
||||
WARNFLAGS := -Wall -pedantic -Wno-unknown-warning-option \
|
||||
-Wno-gnu-zero-variadic-macro-arguments -Wno-unused-but-set-variable
|
||||
|
||||
# Overridable CXXFLAGS
|
||||
CXXFLAGS ?= -O3 -flto -DNDEBUG
|
||||
# Non-overridable CXXFLAGS
|
||||
REALCXXFLAGS := ${CXXFLAGS} ${WARNFLAGS} -std=c++2a -I include -fno-exceptions -fno-rtti
|
||||
REQUIREDCXXFLAGS := -std=c++20 -I include -fno-exceptions -fno-rtti
|
||||
REALCXXFLAGS := ${CXXFLAGS} ${WARNFLAGS} ${REQUIREDCXXFLAGS}
|
||||
# Overridable LDFLAGS
|
||||
LDFLAGS ?=
|
||||
# Non-overridable LDFLAGS
|
||||
REALLDFLAGS := ${LDFLAGS} ${WARNFLAGS} -DBUILD_VERSION_STRING=\"${VERSION_STRING}\"
|
||||
REQUIREDLDFLAGS := -DBUILD_VERSION_STRING=\"${VERSION_STRING}\"
|
||||
REALLDFLAGS := ${LDFLAGS} ${WARNFLAGS} ${REQUIREDLDFLAGS}
|
||||
|
||||
# Wrapper around bison that passes flags depending on what the version supports
|
||||
BISON := src/bison.sh
|
||||
|
||||
RM := rm -rf
|
||||
|
||||
# Used for checking pull requests
|
||||
BASE_REF := origin/master
|
||||
|
||||
# Rules to build the RGBDS binaries
|
||||
|
||||
all: rgbasm rgblink rgbfix rgbgfx
|
||||
|
||||
common_obj := \
|
||||
src/extern/getopt.o \
|
||||
src/cli.o \
|
||||
src/diagnostics.o \
|
||||
src/style.o \
|
||||
src/usage.o \
|
||||
src/util.o
|
||||
|
||||
rgbasm_obj := \
|
||||
${common_obj} \
|
||||
src/asm/actions.o \
|
||||
src/asm/charmap.o \
|
||||
src/asm/fixpoint.o \
|
||||
src/asm/format.o \
|
||||
src/asm/fstack.o \
|
||||
src/asm/intern.o \
|
||||
src/asm/lexer.o \
|
||||
src/asm/macro.o \
|
||||
src/asm/main.o \
|
||||
@@ -64,17 +76,20 @@ rgbasm_obj := \
|
||||
src/asm/section.o \
|
||||
src/asm/symbol.o \
|
||||
src/asm/warning.o \
|
||||
src/extern/getopt.o \
|
||||
src/extern/utf8decoder.o \
|
||||
src/error.o \
|
||||
src/backtrace.o \
|
||||
src/linkdefs.o \
|
||||
src/opmath.o \
|
||||
src/util.o
|
||||
src/verbosity.o
|
||||
|
||||
src/asm/lexer.o src/asm/main.o: src/asm/parser.hpp
|
||||
|
||||
rgblink_obj := \
|
||||
${common_obj} \
|
||||
src/link/assign.o \
|
||||
src/link/fstack.o \
|
||||
src/link/lexer.o \
|
||||
src/link/layout.o \
|
||||
src/link/main.o \
|
||||
src/link/object.o \
|
||||
src/link/output.o \
|
||||
@@ -83,34 +98,39 @@ rgblink_obj := \
|
||||
src/link/sdas_obj.o \
|
||||
src/link/section.o \
|
||||
src/link/symbol.o \
|
||||
src/extern/getopt.o \
|
||||
src/link/warning.o \
|
||||
src/extern/utf8decoder.o \
|
||||
src/error.o \
|
||||
src/backtrace.o \
|
||||
src/linkdefs.o \
|
||||
src/opmath.o \
|
||||
src/util.o
|
||||
src/verbosity.o
|
||||
|
||||
src/link/main.o: src/link/script.hpp
|
||||
src/link/lexer.o src/link/main.o: src/link/script.hpp
|
||||
|
||||
rgbfix_obj := \
|
||||
${common_obj} \
|
||||
src/fix/fix.o \
|
||||
src/fix/main.o \
|
||||
src/extern/getopt.o \
|
||||
src/error.o
|
||||
src/fix/mbc.o \
|
||||
src/fix/warning.o
|
||||
|
||||
rgbgfx_obj := \
|
||||
${common_obj} \
|
||||
src/gfx/color_set.o \
|
||||
src/gfx/main.o \
|
||||
src/gfx/pal_packing.o \
|
||||
src/gfx/pal_sorting.o \
|
||||
src/gfx/pal_spec.o \
|
||||
src/gfx/palette.o \
|
||||
src/gfx/png.o \
|
||||
src/gfx/process.o \
|
||||
src/gfx/proto_palette.o \
|
||||
src/gfx/reverse.o \
|
||||
src/gfx/rgba.o \
|
||||
src/extern/getopt.o \
|
||||
src/error.o
|
||||
src/gfx/warning.o \
|
||||
src/verbosity.o
|
||||
|
||||
rgbasm: ${rgbasm_obj}
|
||||
$Q${CXX} ${REALLDFLAGS} -o $@ ${rgbasm_obj} ${REALCXXFLAGS} src/version.cpp -lm
|
||||
$Q${CXX} ${REALLDFLAGS} -o $@ ${rgbasm_obj} ${REALCXXFLAGS} src/version.cpp
|
||||
|
||||
rgblink: ${rgblink_obj}
|
||||
$Q${CXX} ${REALLDFLAGS} -o $@ ${rgblink_obj} ${REALCXXFLAGS} src/version.cpp
|
||||
@@ -142,6 +162,8 @@ src/link/script.hpp: src/link/script.cpp
|
||||
$Qtouch $@
|
||||
|
||||
# Only RGBGFX uses libpng (POSIX make doesn't support pattern rules to cover all these)
|
||||
src/gfx/color_set.o: src/gfx/color_set.cpp
|
||||
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $<
|
||||
src/gfx/main.o: src/gfx/main.cpp
|
||||
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $<
|
||||
src/gfx/pal_packing.o: src/gfx/pal_packing.cpp
|
||||
@@ -150,9 +172,9 @@ src/gfx/pal_sorting.o: src/gfx/pal_sorting.cpp
|
||||
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $<
|
||||
src/gfx/pal_spec.o: src/gfx/pal_spec.cpp
|
||||
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $<
|
||||
src/gfx/process.o: src/gfx/process.cpp
|
||||
src/gfx/png.o: src/gfx/png.cpp
|
||||
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $<
|
||||
src/gfx/proto_palette.o: src/gfx/proto_palette.cpp
|
||||
src/gfx/process.o: src/gfx/process.cpp
|
||||
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $<
|
||||
src/gfx/reverse.o: src/gfx/reverse.cpp
|
||||
$Q${CXX} ${REALCXXFLAGS} ${PNGCFLAGS} -c -o $@ $<
|
||||
@@ -162,8 +184,12 @@ src/gfx/rgba.o: src/gfx/rgba.cpp
|
||||
.cpp.o:
|
||||
$Q${CXX} ${REALCXXFLAGS} -c -o $@ $<
|
||||
|
||||
# Target used to remove all files generated by other Makefile targets
|
||||
install.sh:
|
||||
$Qecho '#!/usr/bin/env bash' > $@
|
||||
$Q${MAKE} -s -n install MANSRC= >> $@
|
||||
$Qchmod +x $@
|
||||
|
||||
# Target used to remove all files generated by other Makefile targets
|
||||
clean:
|
||||
$Q${RM} rgbasm rgbasm.exe
|
||||
$Q${RM} rgblink rgblink.exe
|
||||
@@ -171,33 +197,26 @@ clean:
|
||||
$Q${RM} rgbgfx rgbgfx.exe
|
||||
$Qfind src/ -name "*.o" -exec rm {} \;
|
||||
$Qfind . -type f \( -name "*.gcno" -o -name "*.gcda" -o -name "*.gcov" \) -exec rm {} \;
|
||||
$Q${RM} rgbshim.sh
|
||||
$Q${RM} install.sh rgbshim.sh
|
||||
$Q${RM} src/asm/parser.cpp src/asm/parser.hpp src/asm/stack.hh
|
||||
$Q${RM} src/link/script.cpp src/link/script.hpp src/link/stack.hh
|
||||
$Q${RM} test/gfx/randtilegen test/gfx/rgbgfx_test
|
||||
|
||||
# Target used to install the binaries and man pages.
|
||||
|
||||
install: all
|
||||
$Qinstall -d ${DESTDIR}${bindir}/ ${DESTDIR}${mandir}/man1/ ${DESTDIR}${mandir}/man5/ ${DESTDIR}${mandir}/man7/
|
||||
$Qinstall ${STRIP} -m ${BINMODE} rgbasm ${DESTDIR}${bindir}/rgbasm${SUFFIX}
|
||||
$Qinstall ${STRIP} -m ${BINMODE} rgblink ${DESTDIR}${bindir}/rgblink${SUFFIX}
|
||||
$Qinstall ${STRIP} -m ${BINMODE} rgbfix ${DESTDIR}${bindir}/rgbfix${SUFFIX}
|
||||
$Qinstall ${STRIP} -m ${BINMODE} rgbgfx ${DESTDIR}${bindir}/rgbgfx${SUFFIX}
|
||||
$Qinstall -m ${MANMODE} man/rgbasm.1 man/rgblink.1 man/rgbfix.1 man/rgbgfx.1 ${DESTDIR}${mandir}/man1/
|
||||
$Qinstall -m ${MANMODE} man/rgbds.5 man/rgbasm.5 man/rgbasm-old.5 man/rgblink.5 ${DESTDIR}${mandir}/man5/
|
||||
$Qinstall -m ${MANMODE} man/rgbds.7 man/gbz80.7 ${DESTDIR}${mandir}/man7/
|
||||
$Qinstall -m ${MANMODE} ${MANSRC}rgbasm.1 ${MANSRC}rgblink.1 ${MANSRC}rgbfix.1 ${MANSRC}rgbgfx.1 ${DESTDIR}${mandir}/man1/
|
||||
$Qinstall -m ${MANMODE} ${MANSRC}rgbds.5 ${MANSRC}rgbasm.5 ${MANSRC}rgbasm-old.5 ${MANSRC}rgblink.5 ${DESTDIR}${mandir}/man5/
|
||||
$Qinstall -m ${MANMODE} ${MANSRC}rgbds.7 ${MANSRC}gbz80.7 ${DESTDIR}${mandir}/man7/
|
||||
|
||||
# Target used to check for suspiciously missing changed files.
|
||||
|
||||
checkdiff:
|
||||
$Qcontrib/checkdiff.bash `git merge-base HEAD ${BASE_REF}`
|
||||
|
||||
# This target is used during development in order to prevent adding new issues
|
||||
# to the source code. All warnings are treated as errors in order to block the
|
||||
# compilation and make the continous integration infrastructure return failure.
|
||||
# Target used in development to prevent adding new issues to the source code.
|
||||
# All warnings are treated as errors to block the compilation and make the
|
||||
# continous integration infrastructure return failure.
|
||||
# The rationale for some of the flags is documented in the CMakeLists.
|
||||
|
||||
develop:
|
||||
$Q${MAKE} WARNFLAGS="${WARNFLAGS} -Werror -Wextra \
|
||||
-Walloc-zero -Wcast-align -Wcast-qual -Wduplicated-branches -Wduplicated-cond \
|
||||
@@ -206,51 +225,45 @@ develop:
|
||||
-Wformat=2 -Wformat-overflow=2 -Wformat-truncation=1 \
|
||||
-Wno-format-nonliteral -Wno-strict-overflow -Wno-unused-but-set-variable \
|
||||
-Wno-type-limits -Wno-tautological-constant-out-of-range-compare -Wvla \
|
||||
-D_GLIBCXX_ASSERTIONS -fsanitize=address -fsanitize=undefined \
|
||||
-fsanitize=float-divide-by-zero" \
|
||||
-D_GLIBCXX_ASSERTIONS -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG \
|
||||
-fsanitize=address -fsanitize=undefined -fsanitize=float-divide-by-zero" \
|
||||
CXXFLAGS="-ggdb3 -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls"
|
||||
|
||||
# This target is used during development in order to more easily debug with gdb.
|
||||
|
||||
# Target used in development to debug with gdb.
|
||||
debug:
|
||||
$Qenv ${MAKE} \
|
||||
CXXFLAGS="-ggdb3 -O0 -fno-omit-frame-pointer -fno-optimize-sibling-calls"
|
||||
|
||||
# This target is used during development in order to more easily profile with callgrind.
|
||||
|
||||
# Target used in development to profile with callgrind.
|
||||
# Use `valgrind --tool=callgrind --dump-instr=yes --simulate-cache=yes --collect-jumps=yes ./rgbasm ...`.
|
||||
profile:
|
||||
$Qenv ${MAKE} \
|
||||
CXXFLAGS="-ggdb3 -O3 -fno-omit-frame-pointer -fno-optimize-sibling-calls"
|
||||
|
||||
# This target is used during development in order to inspect code coverage with gcov.
|
||||
|
||||
# Target used in development to inspect code coverage with gcov.
|
||||
# Use `./contrib/coverage.bash`.
|
||||
coverage:
|
||||
$Qenv ${MAKE} \
|
||||
CXXFLAGS="-ggdb3 -Og --coverage -fno-omit-frame-pointer -fno-optimize-sibling-calls"
|
||||
|
||||
# This target is used during development in order to remove unused `#include` headers.
|
||||
# Target used in development to format source code with clang-format.
|
||||
format:
|
||||
$Qclang-format -i $$(git ls-files '*.[hc]pp')
|
||||
|
||||
# Target used in development to check code with clang-tidy.
|
||||
# Requires Bison-generated header files to exist.
|
||||
tidy: src/asm/parser.hpp src/link/script.hpp compile_flags.txt
|
||||
$Qclang-tidy -p . $$(git ls-files '*.[hc]pp')
|
||||
compile_flags.txt:
|
||||
$Qprintf '%s\n' ${REQUIREDCXXFLAGS} ${REQUIREDLDFLAGS} >$@
|
||||
|
||||
# Target used in development to remove unused `#include` headers.
|
||||
iwyu:
|
||||
$Qenv ${MAKE} \
|
||||
CXX="include-what-you-use" \
|
||||
REALCXXFLAGS="-std=c++2a -I include"
|
||||
|
||||
# Targets for the project maintainer to easily create Windows exes.
|
||||
# This is not for Windows users!
|
||||
# If you're building on Windows with Cygwin or MinGW, just follow the Unix
|
||||
# install instructions instead.
|
||||
|
||||
mingw32:
|
||||
$Q${MAKE} all test/gfx/randtilegen test/gfx/rgbgfx_test \
|
||||
CXX=i686-w64-mingw32-g++ \
|
||||
CXXFLAGS="-O3 -flto -DNDEBUG -static-libgcc -static-libstdc++" \
|
||||
PKG_CONFIG="PKG_CONFIG_SYSROOT_DIR=/usr/i686-w64-mingw32 pkg-config"
|
||||
|
||||
mingw64:
|
||||
$Q${MAKE} all test/gfx/randtilegen test/gfx/rgbgfx_test \
|
||||
CXX=x86_64-w64-mingw32-g++ \
|
||||
PKG_CONFIG="PKG_CONFIG_SYSROOT_DIR=/usr/x86_64-w64-mingw32 pkg-config"
|
||||
REALCXXFLAGS="-std=c++20 -I include"
|
||||
|
||||
# Target used in development to conveniently invoke RGBDS binaries with Wine.
|
||||
wine-shim:
|
||||
$Qecho '#!/usr/bin/env bash' > rgbshim.sh
|
||||
$Qecho 'WINEDEBUG=-all wine $$0.exe "$${@:1}"' >> rgbshim.sh
|
||||
@@ -262,7 +275,6 @@ wine-shim:
|
||||
|
||||
# Target for the project maintainer to produce distributable release tarballs
|
||||
# of the source code.
|
||||
|
||||
dist:
|
||||
$Qgit ls-files | sed s~^~$${PWD##*/}/~ \
|
||||
| tar -czf rgbds-`git -c safe.directory='*' describe --tags | cut -c 2-`.tar.gz -C .. -T -
|
||||
| tar -czf rgbds-source.tar.gz -C .. -T -
|
||||
|
||||
@@ -1,33 +1,39 @@
|
||||
# RGBDS
|
||||
|
||||
RGBDS (Rednex Game Boy Development System) is a free assembler/linker package
|
||||
for the Game Boy and Game Boy Color. It consists of:
|
||||
[RGBDS](https://github.com/gbdev/rgbds) (Rednex Game Boy Development System) is
|
||||
a free assembler/linker package for the Game Boy and Game Boy Color.
|
||||
|
||||
- RGBASM (assembler)
|
||||
- RGBLINK (linker)
|
||||
- RGBFIX (checksum/header fixer)
|
||||
- RGBGFX (PNG‐to‐Game Boy graphics converter)
|
||||
It consists of four tools:
|
||||
|
||||
This is a fork of the original RGBDS which aims to make the programs more like
|
||||
other UNIX tools.
|
||||
- **RGBASM:** assembler
|
||||
- **RGBLINK:** linker
|
||||
- **RGBFIX:** ROM checksum/header fixer
|
||||
- **RGBGFX:** PNG-to-Game Boy graphics converter
|
||||
|
||||
## Documentation
|
||||
|
||||
This toolchain is maintained [on GitHub](https://github.com/gbdev/rgbds).
|
||||
The [full documentation](https://rgbds.gbdev.io/docs/) is available online,
|
||||
including the [development history](https://rgbds.gbdev.io/docs/rgbds.7) and
|
||||
[version history](https://rgbds.gbdev.io/versions), generated from the man pages
|
||||
in this repository.
|
||||
|
||||
The documentation of this toolchain can be [viewed online](https://rgbds.gbdev.io/docs/).
|
||||
It is generated from the man pages found in this repository.
|
||||
The source code of the website itself is on GitHub as well under the repository
|
||||
[rgbds-www](https://github.com/gbdev/rgbds-www).
|
||||
The documentation website's own source code is available in the
|
||||
[rgbds-www](https://github.com/gbdev/rgbds-www) repository.
|
||||
|
||||
If you want to contribute or maintain RGBDS, or you have questions regarding the code, its
|
||||
organization, etc. you can find the maintainers [on the gbdev community channels](https://gbdev.io/chat)
|
||||
or via mail at `rgbds at gbdev dot io`.
|
||||
## Community
|
||||
|
||||
## 1. Installing RGBDS
|
||||
If you have questions about the RGBDS code or its organization, you can contact
|
||||
the maintainers on the [GBDev Discord server](https://discord.gg/RjJKA8wrD4) or
|
||||
[other community channels](https://gbdev.io/chat), or via email at
|
||||
`rgbds at gbdev dot io`.
|
||||
|
||||
The [installation procedure](https://rgbds.gbdev.io/install) is available
|
||||
online for various platforms. [Building from source](https://rgbds.gbdev.io/install/source)
|
||||
is possible using `make` or `cmake`; follow the link for more detailed instructions.
|
||||
If you want to help maintain RGBDS, please read [the contribution guide](/docs/CONTRIBUTING.md).
|
||||
|
||||
## Installing
|
||||
|
||||
The [platform-specific installation instructions](https://rgbds.gbdev.io/install/)
|
||||
are available online. To [build from source](https://rgbds.gbdev.io/install/source)
|
||||
using `make` or `cmake`, briefly:
|
||||
|
||||
```sh
|
||||
make
|
||||
@@ -40,8 +46,8 @@ cmake --build build
|
||||
cmake --install build
|
||||
```
|
||||
|
||||
Two parameters available when building are a prefix (e.g. to put the executables in a directory)
|
||||
and a suffix (e.g. to append the version number or commit ID).
|
||||
Both build systems support a prefix (e.g. to install into a specific directory)
|
||||
and a suffix (e.g. to append the version number or commit ID):
|
||||
|
||||
```sh
|
||||
make
|
||||
@@ -54,111 +60,4 @@ cmake --build build
|
||||
cmake --install build --prefix install_dir
|
||||
```
|
||||
|
||||
(If you set a `SUFFIX`, it should include the `.exe` extension on Windows.)
|
||||
|
||||
## 2. RGBDS Folder Organization
|
||||
|
||||
The RGBDS source code file structure is as follows:
|
||||
|
||||
```
|
||||
.
|
||||
├── .github/
|
||||
│ ├── scripts/
|
||||
│ │ └── ...
|
||||
│ └── workflows/
|
||||
│ └── ...
|
||||
├── contrib/
|
||||
│ ├── zsh_compl/
|
||||
│ │ └── ...
|
||||
│ └── ...
|
||||
├── include/
|
||||
│ └── ...
|
||||
├── man/
|
||||
│ └── ...
|
||||
├── src/
|
||||
│ ├── asm/
|
||||
│ │ └── ...
|
||||
│ ├── extern/
|
||||
│ │ └── ...
|
||||
│ ├── fix/
|
||||
│ │ └── ...
|
||||
│ ├── gfx/
|
||||
│ │ └── ...
|
||||
│ ├── link/
|
||||
│ │ └── ...
|
||||
│ ├── CMakeLists.txt
|
||||
│ └── ...
|
||||
├── test/
|
||||
│ ├── ...
|
||||
│ └── run-tests.sh
|
||||
├── .clang-format
|
||||
├── CMakeLists.txt
|
||||
├── Dockerfile
|
||||
├── Makefile
|
||||
└── README.md
|
||||
```
|
||||
|
||||
- `.github/` - files and scripts related to the integration of the RGBDS codebase with
|
||||
GitHub.
|
||||
* `scripts/` - scripts used by workflow files.
|
||||
* `workflows/` - CI workflow description files.
|
||||
- `contrib/` - scripts and other resources which may be useful to users and developers of
|
||||
RGBDS.
|
||||
* `zsh_compl` contains tab completion scripts for use with zsh. Put them somewhere in
|
||||
your `fpath`, and they should auto-load.
|
||||
* `bash_compl` contains tab completion scripts for use with bash. Run them with `source`
|
||||
somewhere in your `.bashrc`, and they should load every time you open a shell.
|
||||
- `include/` - header files for the respective source files in `src`.
|
||||
- `man/` - manual pages.
|
||||
- `src/` - source code of RGBDS.
|
||||
* Note that the code unique to each RGBDS tool is stored in its respective subdirectory
|
||||
(RGBASM's code is in `src/asm/`, for example). `src/extern/` contains code imported from
|
||||
external sources.
|
||||
- `test/` - testing framework used to verify that changes to the code don't break or
|
||||
modify the behavior of RGBDS.
|
||||
- `.clang-format` - code style for automated C++ formatting with
|
||||
[`clang-format`](https://clang.llvm.org/docs/ClangFormat.html).
|
||||
- `Dockerfile` - defines how to build RGBDS with Docker.
|
||||
|
||||
## 3. History
|
||||
|
||||
- 1996-10-01: Carsten Sørensen (a.k.a. SurfSmurf) releases
|
||||
[xAsm](http://otakunozoku.com/RGBDSdocs/asm.htm),
|
||||
[xLink](http://otakunozoku.com/RGBDSdocs/link.htm), and
|
||||
[RGBFix](http://otakunozoku.com/RGBDSdocs/fix.htm),
|
||||
a Game Boy SM83 (GBZ80) assembler/linker system for DOS/Win32.
|
||||
- 1997-07-03: Sørensen releases [ASMotor](http://otakunozoku.com/RGBDSdocs/geninfo.htm),
|
||||
packaging the three programs together and moving towards making them a
|
||||
general-purpose target-independent system.
|
||||
- 1999-08-01: Justin Lloyd (a.k.a. Otaku no Zoku) adapts ASMotor to re-focus
|
||||
on SM83 assembly/machine code, and releases this version as
|
||||
[RGBDS](http://otakunozoku.com/rednex-gameboy-development-system/).
|
||||
- 2009-06-11: Vegard Nossum adapts the code to be more UNIX-like and releases
|
||||
this version as [rgbds-linux](https://github.com/vegard/rgbds-linux).
|
||||
- 2010-01-12: Anthony J. Bentley [forks](https://github.com/bentley) Nossum's
|
||||
repository. The fork becomes the reference implementation of RGBDS.
|
||||
- 2010-09-25: Sørensen continues development of
|
||||
[ASMotor](https://github.com/asmotor/asmotor) to this day.
|
||||
- 2015-01-18: stag019 begins implementing [RGBGFX](https://github.com/stag019/rgbgfx),
|
||||
a PNG‐to‐Game Boy graphics converter, for eventual integration into RGBDS.
|
||||
- 2016-09-05: RGBGFX is
|
||||
[integrated](https://github.com/gbdev/rgbds/commit/c3c31138ddbd8680d4e67957e387f2816798a71b)
|
||||
into Bentley's repository.
|
||||
- 2017-02-23: Bentley's repository is moved to the [rednex](https://github.com/rednex)
|
||||
organization.
|
||||
- 2018-01-26: The codebase is [relicensed](https://github.com/gbdev/rgbds/issues/128)
|
||||
under the MIT license.
|
||||
- 2020-09-15: The repository is [moved](https://github.com/gbdev/rgbds/issues/567)
|
||||
to the [gbdev](https://github.com/gbdev) organization.
|
||||
- 2022-05-17: The [rgbds.gbdev.io](https://rgbds.gbdev.io) website for RGBDS
|
||||
documentation and downloads is published.
|
||||
|
||||
## 4. Acknowledgements
|
||||
|
||||
RGBGFX generates palettes using algorithms found in the paper
|
||||
["Algorithms for the Pagination Problem, a Bin Packing with Overlapping Items"](https://arxiv.org/abs/1605.00558)
|
||||
([GitHub](https://github.com/pagination-problem/pagination), MIT license),
|
||||
by Aristide Grange, Imed Kacem, and Sébastien Martin.
|
||||
|
||||
RGBGFX's color palette was taken from [SameBoy](https://sameboy.github.io), with permission and help
|
||||
by [LIJI](https://github.com/LIJI32).
|
||||
On Windows, any `SUFFIX` should include the `.exe` extension.
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# This file declares the dependencies we use, using `FetchContent`.
|
||||
# https://cmake.org/cmake.help/latest/guide/using-dependencies/index.html#downloading-and-building-from-source-with-fetchcontent
|
||||
# These are kept in a separate file so that it can be hashed as a key for our CI's `actions/cache`.
|
||||
|
||||
FetchContent_Declare(PNG
|
||||
URL https://download.sourceforge.net/libpng/libpng-1.6.58.tar.xz
|
||||
URL_HASH SHA256=28eb403f51f0f7405249132cecfe82ea5c0ef97f1b32c5a65828814ae0d34775
|
||||
EXCLUDE_FROM_ALL # We only install the runtime dependencies, and do so separately.
|
||||
FIND_PACKAGE_ARGS 1.5.4)
|
||||
|
||||
set(PNG_TESTS OFF CACHE INTERNAL "") # We do not need libpng's tests or tools
|
||||
set(PNG_TOOLS OFF CACHE INTERNAL "") # (and they can even cause compile errors!)
|
||||
set(PNG_SHARED OFF CACHE INTERNAL "")
|
||||
set(PNG_STATIC ON CACHE INTERNAL "")
|
||||
|
||||
FetchContent_Declare(ZLIB
|
||||
URL https://www.zlib.net/zlib-1.3.2.tar.xz
|
||||
URL_HASH SHA256=d7a0654783a4da529d1bb793b7ad9c3318020af77667bcae35f95d0e42a792f3
|
||||
EXCLUDE_FROM_ALL # We only install the runtime dependencies, and do so separately.
|
||||
# libpng documents requiring "zlib 1.0.4 or later (1.2.13 or later recommended for performance and security reasons)".
|
||||
# We thus enforce 1.0.4, but note that the libpng source code mentions that "it may work with versions as old as zlib 0.95".
|
||||
FIND_PACKAGE_ARGS 1.0.4)
|
||||
|
||||
set(ZLIB_BUILD_SHARED OFF CACHE INTERNAL "")
|
||||
set(ZLIB_BUILD_STATIC ON CACHE INTERNAL "")
|
||||
@@ -0,0 +1,33 @@
|
||||
# This file is meant to be included at the project level,
|
||||
# in order to generate executables compatible with old macOS versions.
|
||||
# See our `macos-static` CMake preset for how it's meant to be used.
|
||||
|
||||
# Note that targeting old enough versions of Mac OS X on recent enough versions of macOS
|
||||
# triggers some poorly-tested code paths within Apple's linker, which then crashes.
|
||||
# This can be worked around by using LLVM's LLD linker and passing `-fuse-ld=lld` when linking.
|
||||
|
||||
# The `-mmacosx-version-min=10.4` flag ensures that the binary only uses APIs available on Mac OS X 10.4 Tiger.
|
||||
# The `-arch` flags build a "fat binary" that works on both Apple architectures:
|
||||
# older Intel x64 Macs and newer ARM "Apple Silicon" ones.
|
||||
set(secret_sauce -mmacosx-version-min=10.4 "SHELL:-arch x86_64" "SHELL:-arch arm64") # Avoid `-arch` being dedup'd.
|
||||
add_compile_options(${secret_sauce})
|
||||
add_link_options(${secret_sauce})
|
||||
set(PNG_HARDWARE_OPTIMIZATIONS OFF) # These do not play well with a dual-arch build.
|
||||
|
||||
# Mac OS X has always provided zlib, so we can safely link dynamically against it.
|
||||
# However, libpng is *not* provided by default, so we link it statically, which requires downloading and building it from source.
|
||||
set(PNG_SHARED OFF)
|
||||
set(PNG_STATIC ON)
|
||||
# If libpng is already available (e.g. via Homebrew), we ignore that and still build our own.
|
||||
set(FETCHCONTENT_TRY_FIND_PACKAGE_MODE NEVER)
|
||||
# But we still want to attempt linking against the system's zlib.
|
||||
function(rgbds_provide_dependency method dep_name)
|
||||
if(dep_name STREQUAL "ZLIB")
|
||||
find_package(ZLIB)
|
||||
if(ZLIB_FOUND)
|
||||
FetchContent_SetPopulated(ZLIB)
|
||||
endif()
|
||||
endif()
|
||||
endfunction(rgbds_provide_dependency)
|
||||
cmake_language(SET_DEPENDENCY_PROVIDER rgbds_provide_dependency
|
||||
SUPPORTED_METHODS FETCHCONTENT_MAKEAVAILABLE_SERIAL)
|
||||
@@ -0,0 +1,22 @@
|
||||
# From https://www.mingw-w64.org/build-systems/cmake/
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(CMAKE_SYSTEM_PROCESSOR i686)
|
||||
|
||||
# Specify the cross-compiler.
|
||||
set(CMAKE_C_COMPILER i686-w64-mingw32-gcc)
|
||||
set(CMAKE_CXX_COMPILER i686-w64-mingw32-g++)
|
||||
set(CMAKE_RC_COMPILER i686-w64-mingw32-windres)
|
||||
|
||||
# Specify the target environment.
|
||||
set(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32)
|
||||
|
||||
# Search for programs in the build host directories.
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
# Search for libraries and headers in the target directories.
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
||||
# CMake determines how to examine dependencies based on the *host* system, leading to
|
||||
# a "file unknown error" unless the target platform is explicitly specified.
|
||||
set(CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM "windows+pe")
|
||||
@@ -0,0 +1,22 @@
|
||||
# From https://www.mingw-w64.org/build-systems/cmake/
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
||||
|
||||
# Specify the cross-compiler.
|
||||
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
|
||||
set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
|
||||
set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
|
||||
|
||||
# Specify the target environment.
|
||||
set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)
|
||||
|
||||
# Search for programs in the build host directories.
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
# Search for libraries and headers in the target directories.
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
||||
# CMake determines how to examine dependencies based on the *host* system, leading to
|
||||
# a "file unknown error" unless the target platform is explicitly specified.
|
||||
set(CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM "windows+pe")
|
||||
@@ -24,13 +24,14 @@ _rgbasm_completions() {
|
||||
# Empty long opt = it doesn't exit
|
||||
# See the `state` variable below for info about `state_after`
|
||||
declare -A opts=(
|
||||
[V]="version:normal"
|
||||
[h]="help:normal"
|
||||
[E]="export-all:normal"
|
||||
[v]="verbose:normal"
|
||||
[V]="version:normal"
|
||||
[W]="warning:warning"
|
||||
[w]=":normal"
|
||||
[B]="backtrace:unk"
|
||||
[b]="binary-digits:unk"
|
||||
[D]="define:unk"
|
||||
[E]="export-all:normal"
|
||||
[g]="gfx-chars:unk"
|
||||
[I]="include:dir"
|
||||
[M]="dependfile:glob-*.mk *.d"
|
||||
@@ -40,7 +41,7 @@ _rgbasm_completions() {
|
||||
[Q]="q-precision:unk"
|
||||
[r]="recursion-depth:unk"
|
||||
[s]="state:unk"
|
||||
[W]="warning:warning"
|
||||
[v]="verbose:normal"
|
||||
[X]="max-errors:unk"
|
||||
)
|
||||
# Parse command-line up to current word
|
||||
@@ -61,7 +62,7 @@ _rgbasm_completions() {
|
||||
parse_short_opt() {
|
||||
# These options act like a long option (= takes up the entire word), but only use a single dash
|
||||
# So, they need some special handling
|
||||
if [[ "$1" = "-M"[GP] ]]; then
|
||||
if [[ "$1" = "-M"[CGP] ]]; then
|
||||
state=normal
|
||||
optlen=${#1}
|
||||
return;
|
||||
@@ -146,7 +147,7 @@ _rgbasm_completions() {
|
||||
# It is, try to complete one
|
||||
mapfile -t COMPREPLY < <(compgen -W "${opts[*]%%:*}" -P '--' -- "${cur_word#--}")
|
||||
return 0
|
||||
elif [[ "$cur_word" = '-M'[GPQT] ]]; then
|
||||
elif [[ "$cur_word" = '-M'[CGPQT] ]]; then
|
||||
# These options act like long opts with no arguments, so return them and exactly them
|
||||
COMPREPLY=( "$cur_word" )
|
||||
return 0
|
||||
@@ -155,7 +156,7 @@ _rgbasm_completions() {
|
||||
parse_short_opt "$cur_word"
|
||||
|
||||
if [[ "$state" = 'normal' ]]; then
|
||||
mapfile -t COMPREPLY < <(compgen -W "${!opts[*]}" -P "$cur_word" ''; compgen -W '-MG -MP -MQ -MT' "$cur_word")
|
||||
mapfile -t COMPREPLY < <(compgen -W "${!opts[*]}" -P "$cur_word" ''; compgen -W '-MC -MG -MP -MQ -MT' "$cur_word")
|
||||
return 0
|
||||
elif [[ "$optlen" = "${#cur_word}" && "$state" != "warning" ]]; then
|
||||
# This short option group only awaits its argument!
|
||||
@@ -183,6 +184,7 @@ _rgbasm_completions() {
|
||||
empty-data-directive
|
||||
empty-macro-arg
|
||||
empty-strrpl
|
||||
export-undefined
|
||||
large-constant
|
||||
macro-shift
|
||||
nested-comment
|
||||
|
||||
@@ -7,15 +7,15 @@ _rgbfix_completions() {
|
||||
# Empty long opt = it doesn't exit
|
||||
# See the `state` variable below for info about `state_after`
|
||||
declare -A opts=(
|
||||
[V]="version:normal"
|
||||
[h]="help:normal"
|
||||
[j]="non-japanese:normal"
|
||||
[s]="sgb-compatible:normal"
|
||||
[v]="validate:normal"
|
||||
[V]="version:normal"
|
||||
[W]="warning:warning"
|
||||
[w]=":normal"
|
||||
[C]="color-only:normal"
|
||||
[c]="color-compatible:normal"
|
||||
[f]="fix-spec:fix-spec"
|
||||
[i]="game-id:unk"
|
||||
[j]="non-japanese:normal"
|
||||
[k]="new-licensee:unk"
|
||||
[L]="custom-logo:glob-*.1bpp"
|
||||
[l]="old-licensee:unk"
|
||||
@@ -24,7 +24,9 @@ _rgbfix_completions() {
|
||||
[o]="output:glob-*.gb *.gbc *.sgb"
|
||||
[p]="pad-value:unk"
|
||||
[r]="ram-size:unk"
|
||||
[s]="sgb-compatible:normal"
|
||||
[t]="title:unk"
|
||||
[v]="validate:normal"
|
||||
)
|
||||
# Parse command-line up to current word
|
||||
local opt_ena=true
|
||||
@@ -140,6 +142,17 @@ _rgbfix_completions() {
|
||||
case "$state" in
|
||||
unk) # Return with no replies: no idea what to complete!
|
||||
;;
|
||||
warning)
|
||||
mapfile -t COMPREPLY < <(compgen -W "
|
||||
mbc
|
||||
obsolete
|
||||
overwrite
|
||||
sgb
|
||||
truncation
|
||||
all
|
||||
everything
|
||||
error" -P "${cur_word:0:$optlen}" -- "${cur_word:$optlen}")
|
||||
;;
|
||||
fix-spec)
|
||||
COMPREPLY=( "${cur_word}"{l,h,g,L,H,G} )
|
||||
;;
|
||||
|
||||
@@ -7,36 +7,38 @@ _rgbgfx_completions() {
|
||||
# Empty long opt = it doesn't exit
|
||||
# See the `state` variable below for info about `state_after`
|
||||
declare -A opts=(
|
||||
[V]="version:normal"
|
||||
[h]="help:normal"
|
||||
[C]="color-curve:normal"
|
||||
[m]="mirror-tiles:normal"
|
||||
[O]="group-outputs:normal"
|
||||
[u]="unique-tiles:normal"
|
||||
[v]="verbose:normal"
|
||||
[X]="mirror-x:normal"
|
||||
[Y]="mirror-y:normal"
|
||||
[Z]="columns:normal"
|
||||
[a]="attr-map:glob-*.attrmap"
|
||||
[V]="version:normal"
|
||||
[W]="warning:warning"
|
||||
[w]=":normal"
|
||||
[A]="auto-attr-map:normal"
|
||||
[a]="attr-map:glob-*.attrmap"
|
||||
[B]="background-color:unk"
|
||||
[b]="base-tiles:unk"
|
||||
[C]="color-curve:normal"
|
||||
[c]="colors:unk"
|
||||
[d]="depth:unk"
|
||||
[i]="input-tileset:glob-*.2bpp"
|
||||
[L]="slice:unk"
|
||||
[m]="mirror-tiles:normal"
|
||||
[N]="nb-tiles:unk"
|
||||
[n]="nb-palettes:unk"
|
||||
[O]="group-outputs:normal"
|
||||
[o]="output:glob-*.2bpp"
|
||||
[p]="palette:glob-*.pal"
|
||||
[P]="auto-palette:normal"
|
||||
[q]="palette-map:glob-*.palmap"
|
||||
[p]="palette:glob-*.pal"
|
||||
[Q]="auto-palette-map:normal"
|
||||
[q]="palette-map:glob-*.palmap"
|
||||
[r]="reverse:unk"
|
||||
[s]="palette-size:unk"
|
||||
[t]="tilemap:glob-*.tilemap"
|
||||
[T]="auto-tilemap:normal"
|
||||
[t]="tilemap:glob-*.tilemap"
|
||||
[u]="unique-tiles:normal"
|
||||
[v]="verbose:normal"
|
||||
[X]="mirror-x:normal"
|
||||
[x]="trim-end:unk"
|
||||
[Y]="mirror-y:normal"
|
||||
[Z]="columns:normal"
|
||||
)
|
||||
# Parse command-line up to current word
|
||||
local opt_ena=true
|
||||
@@ -152,6 +154,15 @@ _rgbgfx_completions() {
|
||||
case "$state" in
|
||||
unk) # Return with no replies: no idea what to complete!
|
||||
;;
|
||||
warning)
|
||||
mapfile -t COMPREPLY < <(compgen -W "
|
||||
embedded
|
||||
obsolete
|
||||
trim-nonempty
|
||||
all
|
||||
everything
|
||||
error" -P "${cur_word:0:$optlen}" -- "${cur_word:$optlen}")
|
||||
;;
|
||||
normal) # Acts like a glob...
|
||||
state="glob-*.png"
|
||||
;&
|
||||
|
||||
@@ -7,20 +7,22 @@ _rgblink_completions() {
|
||||
# Empty long opt = it doesn't exit
|
||||
# See the `state` variable below for info about `state_after`
|
||||
declare -A opts=(
|
||||
[V]="version:normal"
|
||||
[h]="help:normal"
|
||||
[d]="dmg:normal"
|
||||
[t]="tiny:normal"
|
||||
[v]="verbose:normal"
|
||||
[w]="wramx:normal"
|
||||
[x]="nopad:normal"
|
||||
[l]="linkerscript:glob-*"
|
||||
[V]="version:normal"
|
||||
[W]="warning:warning"
|
||||
[M]="no-sym-in-map:normal"
|
||||
[d]="dmg:normal"
|
||||
[B]="backtrace:unk"
|
||||
[l]="linkerscript:glob-*"
|
||||
[m]="map:glob-*.map"
|
||||
[n]="sym:glob-*.sym"
|
||||
[O]="overlay:glob-*.gb *.gbc *.sgb"
|
||||
[o]="output:glob-*.gb *.gbc *.sgb"
|
||||
[p]="pad:unk"
|
||||
[t]="tiny:normal"
|
||||
[v]="verbose:normal"
|
||||
[w]="wramx:normal"
|
||||
[x]="nopad:normal"
|
||||
)
|
||||
# Parse command-line up to current word
|
||||
local opt_ena=true
|
||||
@@ -136,6 +138,19 @@ _rgblink_completions() {
|
||||
case "$state" in
|
||||
unk) # Return with no replies: no idea what to complete!
|
||||
;;
|
||||
warning)
|
||||
mapfile -t COMPREPLY < <(compgen -W "
|
||||
assert
|
||||
div
|
||||
large-constant
|
||||
obsolete
|
||||
shift
|
||||
shift-amount
|
||||
truncation
|
||||
all
|
||||
everything
|
||||
error" -P "${cur_word:0:$optlen}" -- "${cur_word:$optlen}")
|
||||
;;
|
||||
normal) # Acts like a glob...
|
||||
state="glob-*.o *.obj"
|
||||
;&
|
||||
|
||||
+60
-11
@@ -1,26 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
set -eu
|
||||
|
||||
usage() {
|
||||
cat <<"EOF"
|
||||
Generates LCOV code coverage report for RGBDS.
|
||||
Options:
|
||||
-h, --help show this help message
|
||||
-o, --open open the HTML report in the preferred application
|
||||
--jobs <n> build RGBDS and external codebases with `make -j<n>`
|
||||
--os <os> skip tests known to fail on <os> (e.g. `macos-14`)
|
||||
EOF
|
||||
}
|
||||
|
||||
# Parse options in pure Bash because macOS `getopt` is stuck
|
||||
# in what util-linux `getopt` calls `GETOPT_COMPATIBLE` mode
|
||||
make_args=()
|
||||
runtests_args=()
|
||||
open_report=false
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
-o|--open)
|
||||
open_report=true
|
||||
;;
|
||||
--jobs)
|
||||
shift
|
||||
make_args+=(-j "$1")
|
||||
runtests_args+=(--jobs "$1")
|
||||
;;
|
||||
--os)
|
||||
shift
|
||||
runtests_args+=(--os "$1")
|
||||
;;
|
||||
*)
|
||||
echo "$(basename "$0"): unknown option '$1'"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# Build RGBDS with gcov support
|
||||
make coverage -j
|
||||
make coverage "${make_args[@]}"
|
||||
|
||||
# Run the tests
|
||||
pushd test
|
||||
./fetch-test-deps.sh
|
||||
./run-tests.sh
|
||||
external/fetch-repos.sh
|
||||
./run-tests.sh "${runtests_args[@]}"
|
||||
popd
|
||||
|
||||
# Generate coverage logs
|
||||
gcov src/**/*.cpp
|
||||
mkdir -p coverage
|
||||
|
||||
# Generate coverage report
|
||||
lcov -c --no-external -d . -o coverage/coverage.info
|
||||
genhtml -f -s -o coverage/ coverage/coverage.info
|
||||
# Generate coverage report, excluding Bison-generated files
|
||||
COVERAGE_INFO=coverage/coverage.info
|
||||
lcov -c --no-external -d . -o "$COVERAGE_INFO"
|
||||
lcov -r "$COVERAGE_INFO" src/asm/parser.{hpp,cpp} src/link/script.{hpp,cpp} -o "$COVERAGE_INFO"
|
||||
genhtml --dark-mode --num-spaces 4 -f -s -o coverage/ "$COVERAGE_INFO"
|
||||
|
||||
# Open report in web browser
|
||||
if [ "$(uname)" == "Darwin" ]; then
|
||||
open coverage/index.html
|
||||
if "$open_report"; then
|
||||
# Open the report in the preferred web browser
|
||||
if [ "$(uname)" == "Darwin" ]; then
|
||||
open coverage/index.html
|
||||
else
|
||||
xdg-open coverage/index.html
|
||||
fi
|
||||
else
|
||||
xdg-open coverage/index.html
|
||||
# Output the path to the report
|
||||
echo "Generated LCOV report at $PWD/coverage/index.html"
|
||||
fi
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -ne 2 ]]; then
|
||||
|
||||
@@ -16,6 +16,7 @@ _rgbasm_warnings() {
|
||||
'empty-data-directive:Warn on arg-less d[bwl] in ROM'
|
||||
'empty-macro-arg:Warn on empty macro arg'
|
||||
'empty-strrpl:Warn on calling STRRPL with empty pattern'
|
||||
'export-undefined:Warn on EXPORT of an undefined symbol'
|
||||
'large-constant:Warn on constants too large for a signed 32-bit int'
|
||||
'macro-shift:Warn when shifting macro args part their limits'
|
||||
'nested-comment:Warn on "/*" inside block comments'
|
||||
@@ -23,15 +24,13 @@ _rgbasm_warnings() {
|
||||
'obsolete:Warn when using deprecated features'
|
||||
'purge:Warn when purging exported symbols or labels'
|
||||
'shift:Warn when shifting negative values'
|
||||
'shift-amount:Warn when a shift'\''s operand it negative or \> 32'
|
||||
'shift-amount:Warn when a shift'\''s operand is negative or \> 32'
|
||||
'truncation:Warn when implicit truncation loses bits'
|
||||
'unmapped-char:Warn on unmapped character'
|
||||
'unmatched-directive:Warn on unmatched directive pair'
|
||||
'unterminated-load:Warn on LOAD without ENDL'
|
||||
'user:Warn when executing the WARN built-in'
|
||||
)
|
||||
# TODO: handle `no-` and `error=` somehow?
|
||||
# TODO: handle `=0|1|2` levels for `numeric-string`, `purge`, `truncation`, and `unmapped-char`?
|
||||
_describe warning warnings
|
||||
}
|
||||
|
||||
@@ -41,16 +40,19 @@ local args=(
|
||||
'(- : * options)'{-h,--help}'[Print help text and exit]'
|
||||
|
||||
'(-E --export-all)'{-E,--export-all}'[Export all symbols]'
|
||||
'(-v --verbose)'{-v,--verbose}'[Print additional messages regarding progression]'
|
||||
'(-v --verbose)'{-v,--verbose}'[Enable verbose output]'
|
||||
-w'[Disable all warnings]'
|
||||
|
||||
'(-B --backtrace)'{-B,--backtrace}'+[Set backtrace depth or style]:param:'
|
||||
'(-b --binary-digits)'{-b,--binary-digits}'+[Change chars for binary constants]:digit spec:'
|
||||
--color'[Whether to use color in output]:color:(auto always never)'
|
||||
'*'{-D,--define}'+[Define a string symbol]:name + value (default 1):'
|
||||
'(-g --gfx-chars)'{-g,--gfx-chars}'+[Change chars for gfx constants]:chars spec:'
|
||||
'(-I --include)'{-I,--include}'+[Add an include directory]:include path:_files -/'
|
||||
'(-M --dependfile)'{-M,--dependfile}"+[Write deps in make format]:output file:_files -g '*.{d,mk}'"
|
||||
-MG'[Assume missing files should be generated]'
|
||||
-MP'[Add phony targets to all deps]'
|
||||
'(-M --dependfile)'{-M,--dependfile}"+[Write dependencies in Makefile format]:output file:_files -g '*.{d,mk}'"
|
||||
-MC'[Continue after missing dependencies]'
|
||||
-MG'[Assume missing dependencies should be generated]'
|
||||
-MP'[Add phony targets to all dependencies]'
|
||||
'*'-MT"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'"
|
||||
'*'-MQ"+[Add a target to the rules]:target:_files -g '*.{d,mk,o}'"
|
||||
'(-o --output)'{-o,--output}'+[Output file]:output file:_files'
|
||||
|
||||
@@ -34,6 +34,22 @@ _mbc_names() {
|
||||
_describe "MBC name" mbc_names
|
||||
}
|
||||
|
||||
_rgbfix_warnings() {
|
||||
local warnings=(
|
||||
'error:Turn all warnings into errors'
|
||||
|
||||
'all:Enable most warning messages'
|
||||
'everything:Enable literally everything'
|
||||
|
||||
'mbc:Warn about issues with MBC specs'
|
||||
'obsolete:Warn when using deprecated features'
|
||||
'overwrite:Warn when overwriting non-zero bytes'
|
||||
'sgb:Warn when SGB flag conflicts with old licensee code'
|
||||
'truncation:Warn when values are truncated to fit'
|
||||
)
|
||||
_describe warning warnings
|
||||
}
|
||||
|
||||
local args=(
|
||||
# Arguments are listed here in the same order as in the manual, except for the version and help
|
||||
'(- : * options)'{-V,--version}'[Print version number and exit]'
|
||||
@@ -45,7 +61,9 @@ local args=(
|
||||
'(-O --overwrite)'{-O,--overwrite}'[Allow overwriting non-zero bytes]'
|
||||
'(-s --sgb-compatible)'{-s,--sgb-compatible}'[Set the SGB flag]'
|
||||
'(-f --fix-spec -v --validate)'{-v,--validate}'[Shorthand for -f lhg]'
|
||||
-w'[Disable all warnings]'
|
||||
|
||||
--color'[Whether to use color in output]:color:(auto always never)'
|
||||
'(-f --fix-spec -v --validate)'{-f,--fix-spec}'+[Fix or trash some header values]:fix spec:'
|
||||
'(-i --game-id)'{-i,--game-id}'+[Set game ID string]:4-char game ID:'
|
||||
'(-k --new-licensee)'{-k,--new-licensee}'+[Set new licensee string]:2-char licensee ID:'
|
||||
@@ -57,6 +75,7 @@ local args=(
|
||||
'(-p --pad-value)'{-p,--pad-value}'+[Pad to next valid size using this byte as padding]:padding byte:'
|
||||
'(-r --ram-size)'{-r,--ram-size}'+[Set RAM size]:ram size byte:'
|
||||
'(-t --title)'{-t,--title}'+[Set title string]:11-char title string:'
|
||||
'(-W --warning)'{-W,--warning}'+[Toggle warning flags]:warning flag:_rgbfix_warnings'
|
||||
|
||||
'*'":ROM files:_files -g '*.{gb,sgb,gbc}'"
|
||||
)
|
||||
|
||||
@@ -9,6 +9,20 @@ _depths() {
|
||||
_describe 'bit depth' depths
|
||||
}
|
||||
|
||||
_rgbgfx_warnings() {
|
||||
local warnings=(
|
||||
'error:Turn all warnings into errors'
|
||||
|
||||
'all:Enable most warning messages'
|
||||
'everything:Enable literally everything'
|
||||
|
||||
'embedded:Warn when using embedded PLTE without "-c embedded"'
|
||||
'obsolete:Warn when using deprecated features'
|
||||
'trim-nonempty:Warn when "-x" trims nonempty tiles'
|
||||
)
|
||||
_describe warning warnings
|
||||
}
|
||||
|
||||
local args=(
|
||||
# Arguments are listed here in the same order as in the manual, except for the version and help
|
||||
'(- : * options)'{-V,--version}'[Print version number and exit]'
|
||||
@@ -22,7 +36,8 @@ local args=(
|
||||
'(-q --palette-map -Q --auto-palette-map)'{-Q,--auto-palette-map}'[Shortcut for -p <file>.palmap]'
|
||||
'(-t --tilemap -T --auto-tilemap)'{-T,--auto-tilemap}'[Shortcut for -t <file>.tilemap]'
|
||||
'(-u --unique-tiles)'{-u,--unique-tiles}'[Eliminate redundant tiles]'
|
||||
{-v,--verbose}'[Enable verbose output]'
|
||||
'(-v --verbose)'{-v,--verbose}'[Enable verbose output]'
|
||||
-w'[Disable all warnings]'
|
||||
'(-X --mirror-x)'{-X,--mirror-x}'[Eliminate horizontally mirrored tiles from output]'
|
||||
'(-Y --mirror-y)'{-Y,--mirror-y}'[Eliminate vertically mirrored tiles from output]'
|
||||
'(-Z --columns)'{-Z,--columns}'[Read the image in column-major order]'
|
||||
@@ -30,6 +45,7 @@ local args=(
|
||||
'(-a --attr-map -A --auto-attr-map)'{-a,--attr-map}'+[Generate a map of tile attributes (mirroring)]:attrmap file:_files'
|
||||
'(-B --background-color)'{-B,--background-color}'+[Ignore tiles containing only specified color]:color:'
|
||||
'(-b --base-tiles)'{-b,--base-tiles}'+[Base tile IDs for tile map output]:base tile IDs:'
|
||||
--color'[Whether to use color in output]:color:(auto always never)'
|
||||
'(-c --colors)'{-c,--colors}'+[Specify color palettes]:palette spec:'
|
||||
'(-d --depth)'{-d,--depth}'+[Set bit depth]:bit depth:_depths'
|
||||
'(-i --input-tileset)'{-i,--input-tileset}'+[Use specific tiles]:tileset file:_files -g "*.2bpp"'
|
||||
@@ -42,6 +58,7 @@ local args=(
|
||||
'(-r --reverse)'{-r,--reverse}'+[Yield an image from binary data]:image width (in tiles):'
|
||||
'(-s --palette-size)'{-s,--palette-size}'+[Limit palette size]:palette size:'
|
||||
'(-t --tilemap -T --auto-tilemap)'{-t,--tilemap}'+[Generate a map of tile indices]:tilemap file:_files'
|
||||
'(-W --warning)'{-W,--warning}'+[Toggle warning flags]:warning flag:_rgbgfx_warnings'
|
||||
'(-x --trim-end)'{-x,--trim-end}'+[Trim end of output by this many tiles]:tile count:'
|
||||
|
||||
":input png file:_files -g '*.png'"
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
#compdef rgblink
|
||||
|
||||
_rgblink_warnings() {
|
||||
local warnings=(
|
||||
'error:Turn all warnings into errors'
|
||||
|
||||
'all:Enable most warning messages'
|
||||
'everything:Enable literally everything'
|
||||
|
||||
'assert:Warn when WARN-type asserts fail'
|
||||
'div:Warn when dividing the smallest int by -1'
|
||||
'large-constant:Warn on constants too large for a signed 32-bit int'
|
||||
'obsolete:Warn when using deprecated features'
|
||||
'shift:Warn when shifting negative values'
|
||||
'shift-amount:Warn when a shift'\''s operand is negative or \> 32'
|
||||
'truncation:Warn when implicit truncation loses bits'
|
||||
)
|
||||
_describe warning warnings
|
||||
}
|
||||
|
||||
local args=(
|
||||
# Arguments are listed here in the same order as in the manual, except for the version and help
|
||||
'(- : * options)'{-V,--version}'[Print version number and exit]'
|
||||
@@ -11,6 +29,8 @@ local args=(
|
||||
'(-w --wramx)'{-w,--wramx}'[Disable WRAM banking]'
|
||||
'(-x --nopad)'{-x,--nopad}'[Disable padding the end of the final file]'
|
||||
|
||||
'(-B --backtrace)'{-B,--backtrace}'+[Set backtrace depth or style]:param:'
|
||||
--color'[Whether to use color in output]:color:(auto always never)'
|
||||
'(-l --linkerscript)'{-l,--linkerscript}"+[Use a linker script]:linker script:_files -g '*.link'"
|
||||
'(-M --no-sym-in-map)'{-M,--no-sym-in-map}'[Do not output symbol names in map file]'
|
||||
'(-m --map)'{-m,--map}"+[Produce a map file]:map file:_files -g '*.map'"
|
||||
@@ -19,6 +39,7 @@ local args=(
|
||||
'(-o --output)'{-o,--output}"+[Write ROM image to this file]:rom file:_files -g '*.{gb,sgb,gbc}'"
|
||||
'(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:'
|
||||
'(-S --scramble)'{-s,--scramble}'+[Activate scrambling]:scramble spec'
|
||||
'(-W --warning)'{-W,--warning}'+[Toggle warning flags]:warning flag:_rgblink_warnings'
|
||||
|
||||
'*'":object files:_files -g '*.o'"
|
||||
)
|
||||
|
||||
@@ -0,0 +1,301 @@
|
||||
# RGBDS Architecture
|
||||
|
||||
The RGBDS package consists of four programs: RGBASM, RGBLINK, RGBFIX, and RGBGFX.
|
||||
|
||||
- RGBASM is the assembler. It takes assembly code as input, and produces an RGB object file as output (and optionally a state file, logging the final state of variables and constants).
|
||||
- RGBLINK is the linker. It takes object files as input, and produces a ROM file as output (and optionally a symbol and/or map file, logging where the assembly declarations got placed in the ROM).
|
||||
- RGBFIX is the checksum/header fixer. It takes a ROM file as input, and outputs the same ROM file (or modifies it in-place) with the cartridge header's checksum and other metadata fixed for consistency.
|
||||
- RGBGFX is the graphics converter. It takes a PNG image file as input, and outputs the tile data, palettes, tilemap, attribute map, and/or palette map in formats that the Game Boy can use.
|
||||
|
||||
In the simplest case, a single pipeline can turn an assembly file into a ROM:
|
||||
|
||||
```console
|
||||
(rgbasm -o - - | rgblink -o - - | rgbfix -v -p 0) < game.asm > game.gb
|
||||
```
|
||||
|
||||
This document describes how these four programs are structured. It goes over each source code file, noting which data is *global* (and thus scoped in all files), *owned* by that file (i.e. that is where the data's memory is managed, via [RAII](https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization)) or *referenced* by that file (i.e. there are non-owning pointers to some data, and care must be taken to not dereference those pointers after the data's owner has moved or deleted the data).
|
||||
|
||||
We assume that the programs are single-threaded; data structures and operations may not be thread-safe.
|
||||
|
||||
## Folder Organization
|
||||
|
||||
The RGBDS source code file structure is as follows:
|
||||
|
||||
```
|
||||
rgbds/
|
||||
├── .github/
|
||||
│ ├── scripts/
|
||||
│ │ └── ...
|
||||
│ └── workflows/
|
||||
│ └── ...
|
||||
├── cmake/
|
||||
│ └── ...
|
||||
├── contrib/
|
||||
│ ├── bash_compl/
|
||||
│ ├── zsh_compl/
|
||||
│ │ └── ...
|
||||
│ └── ...
|
||||
├── docs/
|
||||
│ └── ...
|
||||
├── include/
|
||||
│ └── ...
|
||||
├── man/
|
||||
│ └── ...
|
||||
├── src/
|
||||
│ ├── asm/
|
||||
│ │ └── ...
|
||||
│ ├── extern/
|
||||
│ │ └── ...
|
||||
│ ├── fix/
|
||||
│ │ └── ...
|
||||
│ ├── gfx/
|
||||
│ │ └── ...
|
||||
│ ├── link/
|
||||
│ │ └── ...
|
||||
│ ├── CMakeLists.txt
|
||||
│ ├── bison.sh
|
||||
│ └── ...
|
||||
├── test/
|
||||
│ ├── run-tests.sh
|
||||
│ ├── external/
|
||||
│ │ ├── fetch-repos.sh
|
||||
│ │ └── ...
|
||||
│ └── ...
|
||||
├── .clang-format
|
||||
├── .clang-tidy
|
||||
├── CMakeLists.txt
|
||||
├── CMakePresets.json
|
||||
├── Dockerfile
|
||||
└── Makefile
|
||||
```
|
||||
|
||||
- **`.github/`:**
|
||||
Files related to the integration of the RGBDS codebase with GitHub features.
|
||||
* **`scripts/`:**
|
||||
Scripts used by GitHub Actions workflow files.
|
||||
* **`workflows/`:**
|
||||
GitHub Actions CI workflow description files. Used for automated testing, deployment, etc.
|
||||
- **`cmake/`**:
|
||||
Files relevant to our CMake build system that are not required to be somewhere else (e.g. `CMakePresets.json` *has* to be at the root).
|
||||
- **`contrib/`:**
|
||||
Scripts and other resources which may be useful to RGBDS users and developers.
|
||||
* **`bash_compl/`:**
|
||||
Tab completion scripts for use with `bash`. Run them with `source` somewhere in your `.bashrc`, and they should auto-load when you open a shell.
|
||||
* **`zsh_compl/`:**
|
||||
Tab completion scripts for use with `zsh`. Put them somewhere in your `fpath`, and they should auto-load when you open a shell.
|
||||
- **`docs/`:**
|
||||
Documentation related to the development and maintenance of RGBDS itself.
|
||||
(The directory's name, as well as some of its file's names, are
|
||||
[recognized by GitHub](https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/setting-guidelines-for-repository-contributors)
|
||||
and linked to in parts of its UI.)
|
||||
Documentation for RGBDS itself exists as manual pages in `man/`.
|
||||
- **`include/`:**
|
||||
Header files for the respective source files in `src`.
|
||||
- **`man/`:**
|
||||
Manual pages to be read with `man`, written in the [`mandoc`](https://mandoc.bsd.lv) dialect.
|
||||
- **`src/`:**
|
||||
Source code of RGBDS.
|
||||
* **`asm/`:**
|
||||
Source code of RGBASM.
|
||||
* **`extern/`:**
|
||||
Source code copied from external sources.
|
||||
* **`fix/`:**
|
||||
Source code of RGBFIX.
|
||||
* **`gfx/`:**
|
||||
Source code of RGBGFX.
|
||||
* **`link/`:**
|
||||
Source code of RGBLINK.
|
||||
* **`CMakeLists.txt`:**
|
||||
Defines how to build individual RGBDS programs with CMake, including the source files that each program depends on.
|
||||
* **`bison.sh`:**
|
||||
Script used to run the Bison parser generator with the latest flags that the user's version supports.
|
||||
- **`test/`:**
|
||||
Testing framework used to verify that changes to the code don't break or modify the behavior of RGBDS.
|
||||
The `test.sh` scripts inside each of the subdirectories are the individual test drivers.
|
||||
* **`run-tests.sh`:**
|
||||
Script used to run tests, including internal test cases and external repositories. `run-tests.sh --help` describes its options.
|
||||
* **`external/`:**
|
||||
Directory for third-party repos making use of RGBDS, which get cloned here and built during testing.
|
||||
- **`fetch-repos.sh`:**
|
||||
Script used to clone the external repositories. `fetch-repos.sh --help` describes its options.
|
||||
- **`*.cfg`:**
|
||||
Each `.cfg` file defines the parameters to clone, build, and verify an external repository.
|
||||
- **`.clang-format`:**
|
||||
Code style for automated C++ formatting with [`clang-format`](https://clang.llvm.org/docs/ClangFormat.html) (for which we define the shortcut `make format`).
|
||||
- **`.clang-tidy`:**
|
||||
Configuration for C++ static analysis with [`clang-tidy`](https://clang.llvm.org/extra/clang-tidy/) (for which we define the shortcut `make tidy`).
|
||||
- **`CMakeLists.txt`:**
|
||||
Defines how to build RGBDS with CMake.
|
||||
- **`CMakePresets.json`:**
|
||||
Defines some [presets](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html) useful for working with our CMake.
|
||||
- **`Dockerfile`:**
|
||||
Defines how to build RGBDS with Docker (which we do in CI to provide a [container image](https://github.com/gbdev/rgbds/pkgs/container/rgbds)).
|
||||
- **`Makefile`:**
|
||||
Defines how to build RGBDS with `make`, including the source files that each program depends on.
|
||||
|
||||
## RGBDS
|
||||
|
||||
These files in the `src/` directory are shared across multiple programs: often all four (RGBASM, RGBLINK, RGBFIX, and RGBGFX), sometimes only RGBASM and RGBLINK.
|
||||
|
||||
- **`backtrace.cpp`:**
|
||||
Generic printing of location backtraces for RGBASM and RGBLINK. Allows configuring backtrace styles with a command-line flag (conventionally `-B/--backtrace`). Renders warnings in yellow, errors in red, and locations in cyan.
|
||||
- **`cli.cpp`:**
|
||||
A function for parsing command-line options, including RGBDS-specific "at-files" (a filename containing more options, prepended with an "`@`").
|
||||
This is the only file to use the extern/getopt.cpp variables and functions.
|
||||
- **`diagnostics.cpp`:**
|
||||
Generic warning/error diagnostic support for all programs. Allows command-line flags (conventionally `-W`) to have `no-`, `error=`, or `no-error=` prefixes, and `=` level suffixes; allows "meta" flags to affect groups of individual flags; and counts how many total errors there have been. Every program has its own `warning.cpp` file that uses this.
|
||||
- **`linkdefs.cpp`:**
|
||||
Constants, data, and functions related to RGBDS object files, which are used for RGBASM output and RGBLINK input.
|
||||
This file defines two *global* variables, `sectionTypeInfo` (metadata about each section type) and `sectionModNames` (names of section modifiers, for error reporting). RGBLINK may change some values in `sectionTypeInfo` depending on its command-line options (this only affects RGBLINK; `sectionTypeInfo` is immutable in RGBASM).
|
||||
- **`opmath.cpp`:**
|
||||
Functions for mathematical operations in RGBASM and RGBLINK that aren't trivially equivalent to built-in C++ ones, such as division and modulo with well-defined results for negative values.
|
||||
- **`style.cpp`:**
|
||||
Generic printing of cross-platform colored or bold text. Obeys the [`FORCE_COLOR`](https://force-color.org/) and [`NO_COLOR`](https://no-color.org/) environment variables, and allows configuring with a command-line flag (conventionally `--color`).
|
||||
- **`usage.cpp`:**
|
||||
Generic printing of usage information. Renders headings in green, flags in cyan, and URLs in blue. Every program has its own `main.cpp` file that uses this.
|
||||
- **`util.cpp`:**
|
||||
Utility functions applicable to most programs, mostly dealing with text strings, such as locale-independent character checks.
|
||||
- **`verbosity.cpp`:**
|
||||
Generic printing of messages conditionally at different verbosity levels. Allows configuring with a command-line flag (conventionally `-v/--verbose`).
|
||||
- **`version.cpp`:**
|
||||
RGBDS version number and string for all the programs.
|
||||
|
||||
## External
|
||||
|
||||
These files have been copied ("vendored") from external authors and adapted for use with RGBDS. Both of our vendored dependencies use the same MIT license as RGBDS.
|
||||
|
||||
- **`getopt.cpp`:**
|
||||
Functions for parsing command-line options, including conventional single-dash and double-dash options.
|
||||
This file defines some *global* `musl_opt*` variables, including `musl_optarg` (the argument given after an option flag) and `musl_optind` (the index of the next option in `argv`). Copied from [musl libc](https://musl.libc.org/).
|
||||
- **`utf8decoder.cpp`:**
|
||||
Function for decoding UTF-8 bytes into Unicode code points. Copied from [Björn Höhrmann](https://bjoern.hoehrmann.de/utf-8/decoder/dfa/).
|
||||
|
||||
## RGBASM
|
||||
|
||||
- **`actions.cpp`:**
|
||||
Actions taken by the assembly language parser, to avoid large amounts of code going in the parser.y file.
|
||||
- **`charmap.cpp`:**
|
||||
Functions and data related to charmaps.
|
||||
This file *owns* the `Charmap`s in its `charmaps` collection. It also maintains a static `currentCharmap` pointer, and a `charmapStack` stack of pointers to `Charmap`s within `charmaps` (which is affected by `PUSHC` and `POPC` directives).
|
||||
- **`fixpoint.cpp`:**
|
||||
Functions for fixed-point math, with configurable [Q*m*.*n*](https://en.wikipedia.org/wiki/Q_(number_format)) precision.
|
||||
- **`format.cpp`:**
|
||||
`FormatSpec` methods for parsing and applying format specs, as used by `{interpolations}` and `STRFMT`.
|
||||
- **`fstack.cpp`:**
|
||||
Functions and data related to "fstack" nodes (the contents of top-level or `INCLUDE`d files, macro expansions, or `REPT`/`FOR` loop iterations) and their "contexts" (metadata that is only relevant while a node's content is being lexed and parsed).
|
||||
This file *owns* the `Context`s in its `contextStack` collection. Each of those `Context`s *owns* its `LexerState`, and *refers* to its `FileStackNode`, `uniqueIDStr`, and `macroArgs`. Each `FileStackNode` also *references* its `parent`.
|
||||
- **`intern.cpp`:**
|
||||
[Interned strings](https://en.wikipedia.org/wiki/String_interning), which are used for the names of keywords, symbols (labels, constants, variables, string constants, macros, etc), and charmaps.
|
||||
This file *owns* the strings in its `internedStrings` collection, which its `internedIndexes` collection *references* by view and index.
|
||||
- **`lexer.cpp`:**
|
||||
Functions and data related to [lexing](https://en.wikipedia.org/wiki/Lexical_analysis) assembly source code into tokens, which can then be parsed.
|
||||
This file maintains static `lexerState` and `lexerStateEOL` pointers to `LexerState`s from the `Context`s in `fstack.cpp`.
|
||||
Each `LexerState` *owns* its `content` and its `expansionStack`'s content. Each `Expansion` (the contents of an `{interpolation}` or macro argument) in turn *owns* its `contents`.
|
||||
The lexer and parser are interdependent: when the parser reaches certain tokens, it changes the lexer's mode, which affects how characters get lexed into tokens. For example, when the parser reaches a macro name, it changes the lexer to "raw" mode, which lexes the rest of the line as a sequence of string arguments to the macro.
|
||||
- **`macro.cpp`:**
|
||||
`MacroArgs` methods related to macro arguments. Each `MacroArgs` *references* its arguments' contents.
|
||||
- **`main.cpp`:**
|
||||
The `main` function for running RGBASM, including the initial handling of command-line options.
|
||||
This file defines a *global* `options` variable with the parsed CLI options.
|
||||
- **`opt.cpp`:**
|
||||
Functions for parsing options specified by `OPT` or by certain command-line options.
|
||||
This file *owns* the `OptStackEntry`s in its `stack` collection (which is affected by `PUSHO` and `POPO` directives).
|
||||
- **`output.cpp`:**
|
||||
Functions and data related to outputting object files (with `-o/--output`) and state files (with `-s/--state`).
|
||||
This file *owns* its `assertions` (created by `ASSERT` and `STATIC_ASSERT` directives). Every assertion gets output in the object file.
|
||||
This file also *references* some `fileStackNodes`, and maintains static pointers to `Symbol`s in `objectSymbols`. Only the "registered" symbols and fstack nodes get output in the object file. The `fileStackNodes` and `objectSymbols` collections keep track of which nodes and symbols have been registered for output.
|
||||
- **`parser.y`:**
|
||||
Grammar for the RGBASM assembly language, which Bison preprocesses into a [LALR(1) parser](https://en.wikipedia.org/wiki/LALR_parser).
|
||||
The Bison-generated parser calls `yylex` (defined in `lexer.cpp`) to get the next token, and calls `yywrap` (defined in `fstack.cpp`) when the current context is out of tokens and returns `EOF`.
|
||||
- **`rpn.cpp`:**
|
||||
`Expression` methods and data related to "[RPN](https://en.wikipedia.org/wiki/Reverse_Polish_notation)" expressions. When a numeric expression is parsed, if its value cannot be calculated at assembly time, it is built up into a buffer of RPN-encoded operations to do so at link time by RGBLINK. The valid RPN operations are defined in [man/rgbds.5](/man/rgbds.5).
|
||||
- **`section.cpp`:**
|
||||
Functions and data related to `SECTION`s.
|
||||
This file *owns* the `Section`s in its `sections` collection. It also maintains various static pointers to those sections, including the `currentSection`, `currentLoadSection`, and `sectionStack` (which is affected by `PUSHS` and `POPS` directives). (Note that sections cannot be deleted.)
|
||||
- **`symbol.cpp`:**
|
||||
Functions and data related to symbols (labels, constants, variables, string constants, macros, etc).
|
||||
This file *owns* the `Symbol`s in its `symbols` collection, and the various built-in ones outside that collection (`PCSymbol` for "`@`", `NARGSymbol` for "`_NARG`", etc). It also maintains a static `purgedSymbols` collection to remember which symbol names have been `PURGE`d from `symbols`, for error reporting purposes.
|
||||
- **`warning.cpp`:**
|
||||
Functions and data for warning and error output.
|
||||
This file defines a *global* `warnings` variable using the `diagnostics.cpp` code for RGBASM-specific warning flags.
|
||||
|
||||
## RGBFIX
|
||||
|
||||
- **`fix.cpp`:**
|
||||
Functions for fixing the ROM header.
|
||||
- **`main.cpp`:**
|
||||
The `main` function for running RGBFIX, including the initial handling of command-line options.
|
||||
This file defines a *global* `options` variable with the parsed CLI options.
|
||||
- **`mbc.cpp`:**
|
||||
Functions and data related to [MBCs](https://gbdev.io/pandocs/MBCs.html), including the names of known MBC values.
|
||||
- **`warning.cpp`:**
|
||||
Functions and data for warning and error output.
|
||||
This file defines a *global* `warnings` variable using the `diagnostics.cpp` code for RGBFIX-specific warning flags.
|
||||
|
||||
## RGBGFX
|
||||
|
||||
- **`color_set.cpp`:**
|
||||
`ColorSet` methods for creating and comparing sets of colors. A color set includes the unique colors used by a single tile, and these sets are then packed into palettes.
|
||||
- **`main.cpp`:**
|
||||
The `main` function for running RGBGFX, including the initial handling of command-line options.
|
||||
This file defines a *global* `options` variable with the parsed CLI options.
|
||||
- **`pal_packing.cpp`:**
|
||||
Functions for packing color sets into palettes. This is done with an ["overload-and-remove" heuristic](https://arxiv.org/abs/1605.00558) for a pagination algorithm.
|
||||
- **`pal_sorting.cpp`:**
|
||||
Functions for sorting colors within palettes, which works differently for grayscale, RGB, or indexed-color palettes.
|
||||
- **`pal_spec.cpp`:**
|
||||
Functions for parsing various formats of palette specifications (from `-c/--colors`).
|
||||
- **`palette.cpp`:**
|
||||
`Palette` methods for working with up to four GBC-native (RGB555) colors.
|
||||
- **`png.cpp`:**
|
||||
`Png` methods for reading PNG image files, standardizing them to 8-bit RGBA pixels while also reading their indexed palette if there is one.
|
||||
- **`process.cpp`:**
|
||||
Functions related to generating and outputting files (tile data, palettes, tilemap, attribute map, and/or palette map).
|
||||
- **`reverse.cpp`:**
|
||||
Functions related to reverse-generating RGBGFX outputs into a PNG file (for `-r/--reverse`).
|
||||
- **`rgba.cpp`:**
|
||||
`Rgba` methods related to RGBA colors and their 8-bit or 5-bit representations.
|
||||
- **`warning.cpp`:**
|
||||
Functions and data for warning and error output.
|
||||
This file defines a *global* `warnings` variable using the `diagnostics.cpp` code for RGBGFX-specific warning flags.
|
||||
|
||||
## RGBLINK
|
||||
|
||||
- **`assign.cpp`:**
|
||||
Functions and data for assigning `SECTION`s to specific banks and addresses.
|
||||
This file *owns* the `memory` table of free space: each section type is associated with a list of each bank's free address ranges, which are allocated to sections using a [first-fit decreasing](https://en.wikipedia.org/wiki/Bin_packing_problem#First-fit_algorithm) bin-packing algorithm.
|
||||
- **`fstack.cpp`:**
|
||||
Functions related to "fstack" nodes (the contents of top-level or `INCLUDE`d files, macro expansions, or `REPT`/`FOR` loop iterations) read from the object files. At link time, these nodes are only needed for printing of location backtraces.
|
||||
- **`layout.cpp`:**
|
||||
Actions taken by the linker script parser, to avoid large amounts of code going in the script.y file.
|
||||
This file maintains some static data about the current bank and address layout, which get checked and updated for consistency as the linker script is parsed.
|
||||
- **`lexer.cpp`:**
|
||||
Functions and data related to [lexing](https://en.wikipedia.org/wiki/Lexical_analysis) linker script files into tokens, which can then be parsed.
|
||||
This file *owns* the `LexerStackEntry`s in its `lexerStack` collection. Each of those `LexerStackEntry`s *owns* its `file`. The stack is updated as linker scripts can `INCLUDE` other linker script pieces.
|
||||
The linker script lexer is simpler than the RGBASM one, and does not have modes.
|
||||
- **`main.cpp`:**
|
||||
The `main` function for running RGBLINK, including the initial handling of command-line options.
|
||||
This file defines a *global* `options` variable with the parsed CLI options.
|
||||
- **`object.cpp`:**
|
||||
Functions and data for reading object files generated by RGBASM.
|
||||
This file *owns* the `Symbol`s in its `symbolLists` collection, and the `FileStackNode`s in its `nodes` collection.
|
||||
- **`output.cpp`:**
|
||||
Functions and data related to outputting ROM files (with `-o/--output`), symbol files (with `-n/--sym`), and map files (with `-m/--map`).
|
||||
This file *references* some `Symbol`s and `Section`s, in collections that keep them sorted by address and name, which allows the symbol and map output to be in order.
|
||||
- **`patch.cpp`:**
|
||||
Functions and data related to "[RPN](https://en.wikipedia.org/wiki/Reverse_Polish_notation)" expression patches read from the object files, including the ones for `ASSERT` conditions. After sections have been assigned specific locations, the RPN patches can have their values calculated and applied to the ROM. The valid RPN operations are defined in [man/rgbds.5](/man/rgbds.5).
|
||||
This file *owns* the `Assertion`s in its `assertions` collection, and the `RPNStackEntry`s in its `rpnStack` collection.
|
||||
- **`script.y`:**
|
||||
Grammar for the linker script language, which Bison preprocesses into a [LALR(1) parser](https://en.wikipedia.org/wiki/LALR_parser).
|
||||
The Bison-generated parser calls `yylex` (defined in `lexer.cpp`) to get the next token, and calls `yywrap` (also defined in `lexer.cpp`) when the current context is out of tokens and returns `EOF`.
|
||||
- **`sdas_obj.cpp`:**
|
||||
Functions and data for reading object files generated by [GBDK with SDCC](https://gbdk.org/). RGBLINK support for these object files is incomplete.
|
||||
- **`section.cpp`:**
|
||||
Functions and data related to `SECTION`s read from the object files.
|
||||
This file *owns* the `Section`s in its `sections` collection.
|
||||
- **`symbol.cpp`:**
|
||||
Functions and data related to symbols read from the object files.
|
||||
This file *references* the `Symbol`s in its `symbols` and `localSymbols` collections, which allow accessing symbols by name.
|
||||
- **`warning.cpp`:**
|
||||
Functions and data for warning and error output.
|
||||
This file defines a *global* `warnings` variable using the `diagnostics.cpp` code for RGBLINK-specific warning flags.
|
||||
@@ -4,7 +4,7 @@ RGBDS was created in the late '90s and has received contributions from several
|
||||
developers since then. It wouldn't have been possible to get to this point
|
||||
without their work, and it is always open to the contributions of other people.
|
||||
|
||||
## Reporting Bugs
|
||||
## Reporting bugs
|
||||
|
||||
Bug reports are essential to improve RGBDS and they are always welcome. If you
|
||||
want to report a bug:
|
||||
@@ -35,6 +35,9 @@ implement it yourself, you can always contribute to RGBDS with your own code.
|
||||
|
||||
## Contributing code
|
||||
|
||||
Thank you! Code contributions are the most appreciated.
|
||||
You can find a description of the project's layout in [`ARCHITECTURE.md`](/ARCHITECTURE.md).
|
||||
|
||||
If you want to contribute with your own code, whether it is to fix a current
|
||||
issue or to add something that nobody had requested, you should first consider
|
||||
if your change is going to be small (and likely to be accepted as-is) or big
|
||||
@@ -51,8 +54,8 @@ but doesn't know that there's someone working on it.
|
||||
|
||||
Note that you must contribute all your changes under the MIT License. If you are
|
||||
just modifying a file, you don't need to do anything (maybe update the copyright
|
||||
years). If you are adding new files, you need to use the `SPDX-License-Identifier: MIT`
|
||||
header.
|
||||
years). If you are adding new files, you need to use the
|
||||
`SPDX-License-Identifier: MIT` header.
|
||||
|
||||
1. Fork this repository.
|
||||
2. Checkout the `master` branch.
|
||||
@@ -62,69 +65,130 @@ header.
|
||||
target checks for additional warnings. Your patches shouldn't introduce any
|
||||
new warning (but it may be possible to remove some warning checks if it makes
|
||||
the code much easier).
|
||||
|
||||
You can also use `cmake --preset develop` if you prefer.
|
||||
5. Test your changes by running `./run-tests.sh` in the `test` directory.
|
||||
(You must run `./fetch-test-deps.sh` first; if you forget to, the test suite will fail and remind you mid-way.)
|
||||
5. Format your changes according to `clang-format`, which will reformat the
|
||||
coding style according to our standards defined in `.clang-format`.
|
||||
6. Create a pull request against the branch `master`.
|
||||
7. Be prepared to get some comments about your code and to modify it. Tip: Use
|
||||
`./run-tests.sh --help` will print its available options. (You must run
|
||||
`external/fetch-repos.sh` first; if you forget to, the test suite will fail and
|
||||
remind you mid-way.)
|
||||
|
||||
You can also use `ctest --test-dir build` if you prefer.
|
||||
`ctest --test-dir build --print-labels` will print its available
|
||||
[test labels](https://cmake.org/cmake/help/latest/manual/ctest.1.html#label-matching).
|
||||
6. Format your changes according to `clang-format`, which will reformat the
|
||||
coding style according to our standards defined in `.clang-format`. You can
|
||||
use `make format` to format all the C++ files.
|
||||
7. Create a pull request against the branch `master`.
|
||||
8. Check the results of the GitHub Actions CI jobs for your pull request. The
|
||||
"Code format checking" and "Regression testing" jobs should all succeed.
|
||||
The "Diff completeness check" job should be manually checked, as it may
|
||||
output warnings which do not count as failure errors. The "Code coverage
|
||||
report" provides an [LCOV](https://github.com/linux-test-project/lcov)-generated
|
||||
report which can be downloaded and checked to see if your new code has full
|
||||
test coverage.
|
||||
9. Be prepared to get some comments about your code and to modify it. Tip: Use
|
||||
`git rebase -i origin/master` to modify chains of commits.
|
||||
|
||||
## Adding a test
|
||||
|
||||
The test suite is a little ad-hoc, so the way tests work is different for each program being tested.
|
||||
The test suite is a little ad-hoc, so the way tests work is different for each
|
||||
program being tested.
|
||||
|
||||
Feel free to modify how the test scripts work, if the thing you want to test doesn't fit the existing scheme(s).
|
||||
Feel free to modify how the test scripts work, if the thing you want to test
|
||||
doesn't fit the existing scheme(s).
|
||||
|
||||
### RGBASM
|
||||
|
||||
There are two kinds of test.
|
||||
|
||||
#### Simple tests
|
||||
|
||||
Each `.asm` file corresponds to one test.
|
||||
RGBASM will be invoked on the `.asm` file with all warnings enabled.
|
||||
|
||||
If a `.out` file exists, RGBASM's output (`print`, `println`, etc.) must match its contents.
|
||||
If a `.err` file exists, RGBASM's error output (`warn`, errors, etc.) must match its contents.
|
||||
If a `.flags` file exists, its first line contains flags to pass to RGBASM.
|
||||
(There may be more lines, which will be ignored; they can serve as comments to
|
||||
explain what the test is about.)
|
||||
|
||||
If a `.out.bin` file exists, the object file will be linked, and the generated ROM truncated to the length of the `.out.bin` file.
|
||||
If a `.out` file exists, RGBASM's output (`print`, `println`, etc.) must match
|
||||
its contents.
|
||||
If a `.err` file exists, RGBASM's error output (`warn`, errors, etc.) must match
|
||||
its contents.
|
||||
|
||||
If a `.out.bin` file exists, the object file will be linked, and the generated
|
||||
ROM truncated to the length of the `.out.bin` file.
|
||||
After that, the ROM must match the `.out.bin` file.
|
||||
|
||||
#### CLI tests
|
||||
|
||||
Each `.flags` file in `cli/` corresponds to one test.
|
||||
RGBASM will be invoked, passing it the first line of the `.flags` file.
|
||||
(There may be more lines, which will be ignored; they can serve as comments to
|
||||
explain what the test is about.)
|
||||
|
||||
If a `.out` file exists, RGBASM's output (`print`, `println`, etc.) must match
|
||||
its contents.
|
||||
If a `.err` file exists, RGBASM's error output (`warn`, errors, etc.) must match
|
||||
its contents.
|
||||
|
||||
### RGBLINK
|
||||
|
||||
Each `.asm` file corresponds to one test, or one *set* of tests.
|
||||
|
||||
All tests begin by assembling the `.asm` file into an object file, which will be linked in various ways depending on the test.
|
||||
All tests begin by assembling the `.asm` file into an object file, which will be
|
||||
linked in various ways depending on the test.
|
||||
|
||||
#### Simple tests
|
||||
|
||||
These simply check that RGBLINK's output matches some expected output.
|
||||
|
||||
A `.out` file **must** exist, and RGBLINK's output must match that file's contents.
|
||||
If a `.flags` file exists, its first line contains flags to pass to RGBLINK.
|
||||
(There may be more lines, which will be ignored; they can serve as comments to
|
||||
explain what the test is about.)
|
||||
|
||||
Additionally, if a `.out.bin` file exists, the `.gb` file generated by RGBLINK must match it.
|
||||
A `.out` file **must** exist, and RGBLINK's total output must match that file's
|
||||
contents.
|
||||
|
||||
Additionally, if a `.out.bin` file exists, the `.gb` file generated by RGBLINK
|
||||
must match it.
|
||||
|
||||
#### Linker script tests
|
||||
|
||||
These allow applying various linker scripts to the same object file.
|
||||
If one or more `.link` files exist, whose names start the same as the `.asm` file, then each of those files correspond to one test.
|
||||
If one or more `.link` files exist, whose names start the same as the `.asm`
|
||||
file, then each of those files correspond to one test.
|
||||
|
||||
Each `.link` linker script **must** be accompanied by a `.out` file, and RGBLINK's output must match that file's contents when passed the corresponding linker script.
|
||||
Each `.link` linker script **must** be accompanied by a `.out` file, and
|
||||
RGBLINK's total output must match that file's contents when passed the
|
||||
corresponding linker script.
|
||||
|
||||
#### Variant tests
|
||||
|
||||
These allow testing RGBLINK's `-d`, `-t`, and `-w` flags.
|
||||
If one or more <code>-<var><flag></var>.out</code> or <code>-no-<var><flag></var>.out</code> files exist, then each of them corresponds to one test.
|
||||
If one or more
|
||||
<code>-<var><flag></var>.out</code> or <code>-no-<var><flag></var>.out</code>
|
||||
files exist, then each of them corresponds to one test.
|
||||
|
||||
The object file will be linked with and without said flag, respectively; and in each case, RGBLINK's output must match the `.out` file's contents.
|
||||
The object file will be linked with and without said flag, respectively; and in
|
||||
each case, RGBLINK's total output must match the `.out` file's contents.
|
||||
|
||||
### RGBFIX
|
||||
|
||||
Each `.flags` file corresponds to one test.
|
||||
Each one is a text file whose first line contains flags to pass to RGBFIX.
|
||||
(There may be more lines, which will be ignored; they can serve as comments to explain what the test is about.)
|
||||
(There may be more lines, which will be ignored; they can serve as comments to
|
||||
explain what the test is about.)
|
||||
|
||||
RGBFIX will be invoked on the `.bin` file if it exists, or else on default-input.bin.
|
||||
RGBFIX will be invoked on the `.bin` file if it exists, or else on
|
||||
default-input.bin.
|
||||
|
||||
If no `.err` file exists, RGBFIX is simply expected to be able to process the file normally.
|
||||
If one *does* exist, RGBFIX's return status is ignored, but its output **must** match the `.err` file's contents.
|
||||
If no `.out` file exist, RGBFIX is not expected to output anything.
|
||||
If one *does* exist, RGBFIX's output **must** match the `.out` file's contents.
|
||||
|
||||
If no `.err` file exists, RGBFIX is simply expected to be able to process the
|
||||
file normally.
|
||||
If one *does* exist, RGBFIX's return status is ignored, but its error output
|
||||
**must** match the `.err` file's contents.
|
||||
|
||||
Additionally, if a `.gb` file exists, the output of RGBFIX must match the `.gb`.
|
||||
|
||||
@@ -136,55 +200,72 @@ There are three kinds of test.
|
||||
|
||||
Each `.png` file corresponds to one test.
|
||||
RGBGFX will be invoked on the file.
|
||||
If a `.flags` file exists, it will be used as part of the RGBGFX invocation (<code>@<var><file></var>.flags</code>).
|
||||
If a `.flags` file exists, it will be used as part of the RGBGFX invocation
|
||||
(<code>@<var><file></var>.flags</code>).
|
||||
|
||||
If `.out.1bpp`, `.out.2bpp`, `.out.pal`, `.out.tilemap`, `.out.attrmap`, or `.out.palmap` files exist, RGBGFX will create the corresponding kind of output, which must match the file's contents.
|
||||
If `.out.1bpp`, `.out.2bpp`, `.out.pal`, `.out.tilemap`, `.out.attrmap`, or
|
||||
`.out.palmap` files exist, RGBGFX will create the corresponding kind of output,
|
||||
which must match the file's contents.
|
||||
Multiple kinds of output may be tested for the same input.
|
||||
|
||||
If no `.err` file exists, RGBGFX is simply expected to be able to process the file normally.
|
||||
If one *does* exist, RGBGFX's return status is ignored, but its output **must** match the `.err` file's contents.
|
||||
If no `.err` file exists, RGBGFX is simply expected to be able to process the
|
||||
file normally.
|
||||
If one *does* exist, RGBGFX's return status is ignored, but its output **must**
|
||||
match the `.err` file's contents.
|
||||
|
||||
#### Reverse tests
|
||||
|
||||
Each `.1bpp` or `.2bpp` file corresponds to one test.
|
||||
RGBGFX will be invoked on the file with `-r 1` for reverse mode, then invoked on the output without `-r 1`.
|
||||
RGBGFX will be invoked on the file with `-r 1` for reverse mode, then invoked on
|
||||
the output without `-r 1`.
|
||||
The round-trip output must match the input file's contents.
|
||||
If a `.flags` file exists, it will be used as part of the RGBGFX invocation (<code>@<var><file></var>.flags</code>).
|
||||
If a `.flags` file exists, it will be used as part of the RGBGFX invocation
|
||||
(<code>@<var><file></var>.flags</code>).
|
||||
|
||||
#### Random seed tests
|
||||
|
||||
Each `seed*.bin` file corresponds to one test.
|
||||
Each one is a binary RNG file which is passed to the `rgbgfx_test` program.
|
||||
|
||||
### Downstream projects
|
||||
### External projects
|
||||
|
||||
1. Make sure the downstream project supports <code>make <var><target></var> RGBDS=<var><path/to/RGBDS/></var></code>.
|
||||
While the test suite supports any Make target name, only [Make](//gnu.org/software/make) is currently supported, and the Makefile must support a `RGBDS` variable to use a non-system RGBDS directory.
|
||||
Each `.cfg` file corresponds to one test.
|
||||
Each one defines the parameters for a real external project that builds using RGBDS.
|
||||
|
||||
Also, only projects hosted on GitHub are currently supported.
|
||||
2. Add the project to `test/fetch-test-deps.sh`: add a new `action` line at the bottom, following the existing pattern:
|
||||
|
||||
```sh
|
||||
action <owner> <repo> <date of last commit> <hash of last commit>
|
||||
```
|
||||
1. Ensure that the downstream project supports a `RGBDS` variable to build with
|
||||
a non-system copy of RGBDS in some directory, i.e.
|
||||
<code>make <var><target></var> RGBDS=<var><path/to/rgbds/></var></code>.
|
||||
Only [GNU Make](https://www.gnu.org/software/make/) is currently supported.
|
||||
2. Create the new `.cfg` file, following the existing ones.
|
||||
|
||||
(The date is used to avoid fetching too much history when cloning the repositories.)
|
||||
3. Add the project to `test/run-tests.sh`: add a new `test_downstream` line at the bottom, following the existing pattern:
|
||||
|
||||
```sh
|
||||
test_downstream <owner> <repo> <makefile target> <build file> <sha1 hash of build file>
|
||||
```
|
||||
If an external project does not support `make RGBDS=`, or otherwise fails to
|
||||
build with current RGBDS, then you can edit the project to build correctly, and
|
||||
create a patch with `git diff` to be committed as
|
||||
<code>test/external/patches/<var><project></var>.patch</code>.
|
||||
|
||||
## Container images
|
||||
|
||||
The CI will [take care](https://github.com/gbdev/rgbds/blob/master/.github/workflows/build-container.yml) of updating the [rgbds container](https://github.com/gbdev/rgbds/pkgs/container/rgbds) image tagged `master`.
|
||||
The CI will
|
||||
[take care](https://github.com/gbdev/rgbds/blob/master/.github/workflows/build-container.yml)
|
||||
of updating the
|
||||
[rgbds container](https://github.com/gbdev/rgbds/pkgs/container/rgbds) image
|
||||
tagged `master`.
|
||||
|
||||
When a git tag is pushed, the image is also tagged with that tag.
|
||||
|
||||
The image can be built locally and pushed to the GitHub container registry by manually running:
|
||||
The image can be built locally and pushed to the GitHub container registry by
|
||||
manually running:
|
||||
|
||||
```bash
|
||||
# e.g. to build and tag as 'master'
|
||||
docker build . --tag ghcr.io/gbdev/rgbds:master
|
||||
docker push ghcr.io/gbdev/rgbds:master
|
||||
```
|
||||
```
|
||||
|
||||
## Publishing a new release
|
||||
|
||||
Please refer to [`RELEASE.md`](/RELEASE.md).
|
||||
|
||||
## Closing remarks
|
||||
|
||||
Feel free to add yourself to `CREDITS.md`!
|
||||
@@ -32,3 +32,17 @@
|
||||
- yenatch <yenatch@gmail.com>
|
||||
- phs <phil@philhsmith.com>
|
||||
- jidoc01 <jidoc01@naver.com>
|
||||
|
||||
[<img src="https://contrib.rocks/image?repo=gbdev/rgbds">](https://github.com/gbdev/rgbds/graphs/contributors)
|
||||
|
||||
Contributor image made with [contrib.rocks](https://contrib.rocks).
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
RGBGFX generates palettes using algorithms found in the paper
|
||||
["Algorithms for the Pagination Problem, a Bin Packing with Overlapping Items"](https://arxiv.org/abs/1605.00558)
|
||||
([GitHub](https://github.com/pagination-problem/pagination), MIT license),
|
||||
by Aristide Grange, Imed Kacem, and Sébastien Martin.
|
||||
|
||||
RGBGFX's color palette was taken from [SameBoy](https://sameboy.github.io), with
|
||||
permission and help by [LIJI](https://github.com/LIJI32).
|
||||
@@ -6,23 +6,24 @@ GitHub.
|
||||
1. Update the following files, then commit and push.
|
||||
You can use <code>git commit -m "Release <i><version></i>"</code> and `git push origin master`.
|
||||
|
||||
- [include/version.hpp](include/version.hpp): set appropriate values for `PACKAGE_VERSION_MAJOR`,
|
||||
- [include/version.hpp](/include/version.hpp): set appropriate values for `PACKAGE_VERSION_MAJOR`,
|
||||
`PACKAGE_VERSION_MINOR`, `PACKAGE_VERSION_PATCH`, and `PACKAGE_VERSION_RC`.
|
||||
**Only** define `PACKAGE_VERSION_RC` if you are publishing a release candidate!
|
||||
- [Dockerfile](Dockerfile): update `ARG version`.
|
||||
- [test/fetch-test-deps.sh](test/fetch-test-deps.sh): update test dependency commits
|
||||
- [Dockerfile](/Dockerfile): update `ARG version`.
|
||||
- [test/external/\*.cfg](/test/external): update test dependency commits
|
||||
(preferably, use the latest available).
|
||||
- [man/\*](man/): update dates and authors.
|
||||
- [man/\*](/man/): update dates and authors.
|
||||
|
||||
2. Create a Git tag formatted as <code>v<i><MAJOR></i>.<i><MINOR></i>.<i><PATCH></i></code>,
|
||||
or <code>v<i><MAJOR></i>.<i><MINOR></i>.<i><PATCH></i>-rc<i><RC></i></code>
|
||||
for a release candidate. <code><i>MAJOR</i></code>, <code><i>MINOR</i></code>,
|
||||
<code><i>PATCH</i></code>, and <code><i>RC</i></code> should match their values from
|
||||
[include/version.hpp](include/version.hpp). You can use <code>git tag <i><tag></i></code>.
|
||||
[include/version.hpp](/include/version.hpp). You can use <code>git tag <i><tag></i></code>.
|
||||
|
||||
3. Push the tag to GitHub. You can use <code>git push origin <i><tag></i></code>.
|
||||
|
||||
GitHub Actions will run the [create-release-artifacts.yaml](.github/workflows/create-release-artifacts.yaml)
|
||||
GitHub Actions will run the
|
||||
[create-release-artifacts.yml](/.github/workflows/create-release-artifacts.yml)
|
||||
workflow to detect the tag starting with "`v[0-9]`" and automatically do the following:
|
||||
|
||||
1. Build 32-bit and 64-bit RGBDS binaries for Windows with `cmake`.
|
||||
@@ -38,7 +39,7 @@ GitHub.
|
||||
procedure. You can use <code>git push --delete origin <i><tag></i></code> and
|
||||
<code>git tag --delete <i><tag></i></code>.
|
||||
|
||||
4. GitHub Actions will run the [create-release-docs.yml](.github/workflows/create-release-docs.yml)
|
||||
4. GitHub Actions will run the [create-release-docs.yml](/.github/workflows/create-release-docs.yml)
|
||||
workflow to add the release documentation to [rgbds-www](https://github.com/gbdev/rgbds-www).
|
||||
|
||||
This is not done automatically for prereleases, since we do not normally publish documentation
|
||||
@@ -68,7 +69,7 @@ GitHub.
|
||||
|
||||
6. Click the "Publish release" button to publish it!
|
||||
|
||||
7. Update the `release` branch. You can use `git push origin release`.
|
||||
7. Update the `release` branch. You can use `git push origin master:release`.
|
||||
|
||||
8. Update the following related projects.
|
||||
|
||||
@@ -77,9 +78,7 @@ GitHub.
|
||||
to list the new release.
|
||||
2. [rgbds-live](https://github.com/gbdev/rgbds-live): update the `rgbds` submodule (and
|
||||
[patches/rgbds.patch](https://github.com/gbdev/rgbds-live/blob/master/patches/rgbds.patch)
|
||||
if necessary) to use the new release, and
|
||||
[index.html](https://github.com/gbdev/rgbds-live/blob/master/index.html)
|
||||
to link to the new manual version.
|
||||
if necessary) to use the new release.
|
||||
3. [rgbobj](https://github.com/gbdev/rgbobj) and [rgbds-obj](https://github.com/gbdev/rgbds-obj):
|
||||
make sure that object files created by the latest RGBASM can be parsed and displayed.
|
||||
If the object file revision has been updated, `rgbobj` will need a corresponding release.
|
||||
@@ -0,0 +1,62 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef RGBDS_ASM_ACTIONS_HPP
|
||||
#define RGBDS_ASM_ACTIONS_HPP
|
||||
|
||||
#include <optional>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "linkdefs.hpp" // AssertionType, RPNCommand
|
||||
|
||||
#include "asm/intern.hpp" // InternedStr
|
||||
#include "asm/rpn.hpp" // Expression
|
||||
|
||||
struct AlignmentSpec {
|
||||
uint8_t alignment;
|
||||
uint16_t alignOfs;
|
||||
};
|
||||
|
||||
void act_If(int32_t condition);
|
||||
void act_Elif(int32_t condition);
|
||||
void act_Else();
|
||||
void act_Endc();
|
||||
|
||||
AlignmentSpec act_Alignment(int32_t alignment, int32_t alignOfs);
|
||||
|
||||
void act_Assert(AssertionType type, Expression const &expr, std::string const &message);
|
||||
void act_StaticAssert(AssertionType type, int32_t condition, std::string const &message);
|
||||
|
||||
std::optional<std::string> act_ReadFile(std::string const &name, uint32_t maxLen);
|
||||
|
||||
uint32_t act_CharToNum(std::string const &str);
|
||||
uint32_t act_StringToNum(std::string const &str);
|
||||
|
||||
int32_t act_CharVal(std::string const &str);
|
||||
int32_t act_CharVal(std::string const &str, int32_t negIdx);
|
||||
uint8_t act_StringByte(std::string const &str, int32_t negIdx);
|
||||
|
||||
size_t act_StringLen(std::string const &str, bool printErrors);
|
||||
std::string
|
||||
act_StringSlice(std::string const &str, int32_t negStart, std::optional<int32_t> negStop);
|
||||
std::string act_StringSub(std::string const &str, int32_t negPos, std::optional<uint32_t> optLen);
|
||||
|
||||
size_t act_CharLen(std::string const &str);
|
||||
std::string act_StringChar(std::string const &str, int32_t negIdx);
|
||||
std::string act_CharSub(std::string const &str, int32_t negPos);
|
||||
int32_t act_CharCmp(std::string_view str1, std::string_view str2);
|
||||
|
||||
std::string act_StringReplace(std::string_view str, std::string const &old, std::string const &rep);
|
||||
std::string act_StringFormat(
|
||||
std::string const &spec, std::vector<std::variant<uint32_t, std::string>> const &args
|
||||
);
|
||||
|
||||
std::string act_SectionName(InternedStr symName);
|
||||
|
||||
void act_CompoundAssignment(InternedStr symName, RPNCommand op, int32_t constValue);
|
||||
|
||||
#endif // RGBDS_ASM_ACTIONS_HPP
|
||||
@@ -3,25 +3,28 @@
|
||||
#ifndef RGBDS_ASM_CHARMAP_HPP
|
||||
#define RGBDS_ASM_CHARMAP_HPP
|
||||
|
||||
#include <optional>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#define DEFAULT_CHARMAP_NAME "main"
|
||||
#include "asm/intern.hpp"
|
||||
|
||||
void charmap_Init();
|
||||
bool charmap_ForEach(
|
||||
void (*mapFunc)(std::string const &),
|
||||
void (*charFunc)(std::string const &, std::vector<int32_t>)
|
||||
void (*mapFunc)(InternedStr), void (*charFunc)(std::string const &, std::vector<int32_t>)
|
||||
);
|
||||
void charmap_New(std::string const &name, std::string const *baseName);
|
||||
void charmap_Set(std::string const &name);
|
||||
void charmap_New(InternedStr name, InternedStr const *baseName);
|
||||
void charmap_Set(InternedStr name);
|
||||
void charmap_Push();
|
||||
void charmap_Pop();
|
||||
void charmap_CheckStack();
|
||||
void charmap_Add(std::string const &mapping, std::vector<int32_t> &&value);
|
||||
bool charmap_HasChar(std::string const &mapping);
|
||||
size_t charmap_CharSize(std::string const &mapping);
|
||||
std::optional<int32_t> charmap_CharValue(std::string const &mapping, size_t idx);
|
||||
std::vector<int32_t> charmap_Convert(std::string const &input);
|
||||
size_t charmap_ConvertNext(std::string_view &input, std::vector<int32_t> *output);
|
||||
std::string charmap_Reverse(std::vector<int32_t> const &value, bool &unique);
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern uint8_t fixPrecision;
|
||||
|
||||
uint8_t fix_Precision();
|
||||
int32_t fix_Sin(int32_t i, int32_t q);
|
||||
int32_t fix_Cos(int32_t i, int32_t q);
|
||||
int32_t fix_Tan(int32_t i, int32_t q);
|
||||
|
||||
+4
-18
@@ -7,19 +7,7 @@
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
enum FormatState {
|
||||
FORMAT_SIGN, // expects '+' or ' ' (optional)
|
||||
FORMAT_EXACT, // expects '#' (optional)
|
||||
FORMAT_ALIGN, // expects '-' (optional)
|
||||
FORMAT_WIDTH, // expects '0'-'9', max 255 (optional) (leading '0' indicates pad)
|
||||
FORMAT_FRAC, // got '.', expects '0'-'9', max 255 (optional)
|
||||
FORMAT_PREC, // got 'q', expects '0'-'9', range 1-31 (optional)
|
||||
FORMAT_DONE, // got [duXxbofs] (required)
|
||||
FORMAT_INVALID, // got unexpected character
|
||||
};
|
||||
|
||||
class FormatSpec {
|
||||
FormatState state;
|
||||
int sign;
|
||||
bool exact;
|
||||
bool alignLeft;
|
||||
@@ -30,15 +18,13 @@ class FormatSpec {
|
||||
bool hasPrec;
|
||||
size_t precision;
|
||||
int type;
|
||||
bool valid;
|
||||
bool parsed;
|
||||
|
||||
public:
|
||||
bool isEmpty() const { return !state; }
|
||||
bool isValid() const { return valid || state == FORMAT_DONE; }
|
||||
bool isFinished() const { return state >= FORMAT_DONE; }
|
||||
bool isValid() const { return !!type; }
|
||||
bool isParsed() const { return parsed; }
|
||||
|
||||
void useCharacter(int c);
|
||||
void finishCharacters();
|
||||
size_t parseSpec(char const *spec);
|
||||
|
||||
void appendString(std::string &str, std::string const &value) const;
|
||||
void appendNumber(std::string &str, uint32_t value) const;
|
||||
|
||||
+28
-20
@@ -10,20 +10,22 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "either.hpp"
|
||||
#include "linkdefs.hpp"
|
||||
|
||||
#include "asm/intern.hpp"
|
||||
#include "asm/lexer.hpp"
|
||||
|
||||
struct FileStackNode {
|
||||
FileStackNodeType type;
|
||||
Either<
|
||||
std::variant<
|
||||
std::vector<uint32_t>, // NODE_REPT
|
||||
std::string // NODE_FILE, NODE_MACRO
|
||||
>
|
||||
data;
|
||||
bool isQuiet; // Whether to omit this node from error reporting
|
||||
|
||||
std::shared_ptr<FileStackNode> parent; // Pointer to parent node, for error reporting
|
||||
// Line at which the parent context was exited
|
||||
@@ -34,47 +36,53 @@ struct FileStackNode {
|
||||
uint32_t ID = UINT32_MAX;
|
||||
|
||||
// REPT iteration counts since last named node, in reverse depth order
|
||||
std::vector<uint32_t> &iters() { return data.get<std::vector<uint32_t>>(); }
|
||||
std::vector<uint32_t> const &iters() const { return data.get<std::vector<uint32_t>>(); }
|
||||
std::vector<uint32_t> &iters() { return std::get<std::vector<uint32_t>>(data); }
|
||||
std::vector<uint32_t> const &iters() const { return std::get<std::vector<uint32_t>>(data); }
|
||||
// File name for files, file::macro name for macros
|
||||
std::string &name() { return data.get<std::string>(); }
|
||||
std::string const &name() const { return data.get<std::string>(); }
|
||||
std::string &name() { return std::get<std::string>(data); }
|
||||
std::string const &name() const { return std::get<std::string>(data); }
|
||||
|
||||
FileStackNode(FileStackNodeType type_, Either<std::vector<uint32_t>, std::string> data_)
|
||||
: type(type_), data(data_) {}
|
||||
FileStackNode(
|
||||
FileStackNodeType type_,
|
||||
std::variant<std::vector<uint32_t>, std::string> data_,
|
||||
bool isQuiet_
|
||||
)
|
||||
: type(type_), data(data_), isQuiet(isQuiet_) {}
|
||||
|
||||
std::string const &dump(uint32_t curLineNo) const;
|
||||
void printBacktrace(uint32_t curLineNo) const;
|
||||
};
|
||||
|
||||
extern size_t maxRecursionDepth;
|
||||
|
||||
struct MacroArgs;
|
||||
|
||||
void fstk_DumpCurrent();
|
||||
void fstk_VerboseOutputConfig();
|
||||
|
||||
void fstk_TraceCurrent();
|
||||
std::shared_ptr<FileStackNode> fstk_GetFileStack();
|
||||
std::shared_ptr<std::string> fstk_GetUniqueIDStr();
|
||||
MacroArgs *fstk_GetCurrentMacroArgs();
|
||||
|
||||
void fstk_AddIncludePath(std::string const &path);
|
||||
void fstk_SetPreIncludeFile(std::string const &path);
|
||||
void fstk_AddPreIncludeFile(std::string const &path);
|
||||
std::optional<std::string> fstk_FindFile(std::string const &path);
|
||||
bool fstk_FileError(std::string const &path, char const *description);
|
||||
bool fstk_FailedOnMissingInclude();
|
||||
|
||||
bool yywrap();
|
||||
void fstk_RunInclude(std::string const &path, bool updateStateNow);
|
||||
void fstk_RunMacro(std::string const ¯oName, std::shared_ptr<MacroArgs> macroArgs);
|
||||
void fstk_RunRept(uint32_t count, int32_t reptLineNo, ContentSpan const &span);
|
||||
bool fstk_RunInclude(std::string const &path, bool isQuiet);
|
||||
void fstk_RunMacro(InternedStr macroName, std::shared_ptr<MacroArgs> macroArgs, bool isQuiet);
|
||||
void fstk_RunRept(uint32_t count, int32_t reptLineNo, ContentSpan const &span, bool isQuiet);
|
||||
void fstk_RunFor(
|
||||
std::string const &symName,
|
||||
InternedStr symName,
|
||||
int32_t start,
|
||||
int32_t stop,
|
||||
int32_t step,
|
||||
int32_t reptLineNo,
|
||||
ContentSpan const &span
|
||||
ContentSpan const &span,
|
||||
bool isQuiet
|
||||
);
|
||||
void fstk_StopRept();
|
||||
bool fstk_Break();
|
||||
|
||||
void fstk_NewRecursionDepth(size_t newDepth);
|
||||
void fstk_Init(std::string const &mainPath, size_t maxDepth);
|
||||
bool fstk_Init(std::string const &mainPath);
|
||||
|
||||
#endif // RGBDS_ASM_FSTACK_HPP
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef RGBDS_ASM_INTERN_HPP
|
||||
#define RGBDS_ASM_INTERN_HPP
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility> // hash
|
||||
|
||||
class InternedStr {
|
||||
size_t index;
|
||||
|
||||
public:
|
||||
constexpr InternedStr() : index(static_cast<size_t>(-1)) {}
|
||||
explicit constexpr InternedStr(size_t index_) : index(index_) {}
|
||||
|
||||
std::string const &str() const;
|
||||
char const *c_str() const { return str().c_str(); }
|
||||
|
||||
bool operator==(InternedStr const &rhs) const { return index == rhs.index; }
|
||||
|
||||
template<typename T>
|
||||
friend struct std::hash;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct std::hash<InternedStr> {
|
||||
size_t operator()(InternedStr const &str) const { return std::hash<size_t>{}(str.index); }
|
||||
};
|
||||
|
||||
InternedStr intern(std::string_view str);
|
||||
|
||||
#endif // RGBDS_ASM_INTERN_HPP
|
||||
+16
-68
@@ -6,20 +6,12 @@
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "either.hpp"
|
||||
#include "platform.hpp" // SSIZE_MAX
|
||||
|
||||
// This value is a compromise between `LexerState` allocation performance when `mmap` works, and
|
||||
// buffering performance when it doesn't/can't (e.g. when piping a file into RGBASM).
|
||||
static constexpr size_t LEXER_BUF_SIZE = 64;
|
||||
// The buffer needs to be large enough for the maximum `lexerState->peek()` lookahead distance
|
||||
static_assert(LEXER_BUF_SIZE > 1, "Lexer buffer size is too small");
|
||||
// This caps the size of buffer reads, and according to POSIX, passing more than SSIZE_MAX is UB
|
||||
static_assert(LEXER_BUF_SIZE <= SSIZE_MAX, "Lexer buffer size is too large");
|
||||
#include "asm/intern.hpp"
|
||||
|
||||
enum LexerMode {
|
||||
LEXER_NORMAL,
|
||||
@@ -31,7 +23,7 @@ enum LexerMode {
|
||||
};
|
||||
|
||||
struct Expansion {
|
||||
std::optional<std::string> name;
|
||||
std::optional<InternedStr> name;
|
||||
std::shared_ptr<std::string> contents;
|
||||
size_t offset; // Cursor into `contents`
|
||||
|
||||
@@ -44,34 +36,6 @@ struct ContentSpan {
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct ViewedContent {
|
||||
ContentSpan span; // Span of chars
|
||||
size_t offset = 0; // Cursor into `span.ptr`
|
||||
|
||||
ViewedContent(ContentSpan const &span_) : span(span_) {}
|
||||
ViewedContent(std::shared_ptr<char[]> ptr, size_t size) : span({.ptr = ptr, .size = size}) {}
|
||||
|
||||
std::shared_ptr<char[]> makeSharedContentPtr() const {
|
||||
return std::shared_ptr<char[]>(span.ptr, &span.ptr[offset]);
|
||||
}
|
||||
};
|
||||
|
||||
struct BufferedContent {
|
||||
int fd; // File from which to read chars
|
||||
char buf[LEXER_BUF_SIZE] = {}; // Circular buffer of chars
|
||||
size_t offset = 0; // Cursor into `buf`
|
||||
size_t size = 0; // Number of "fresh" chars in `buf`
|
||||
|
||||
BufferedContent(int fd_) : fd(fd_) {}
|
||||
~BufferedContent();
|
||||
|
||||
void advance(); // Increment `offset` circularly, decrement `size`
|
||||
void refill(); // Read from `fd` to fill `buf`
|
||||
|
||||
private:
|
||||
size_t readMore(size_t startIndex, size_t nbChars);
|
||||
};
|
||||
|
||||
struct IfStackEntry {
|
||||
bool ranIfBlock; // Whether an IF/ELIF/ELSE block ran already
|
||||
bool reachedElseBlock; // Whether an ELSE block ran already
|
||||
@@ -84,55 +48,39 @@ struct LexerState {
|
||||
bool atLineStart;
|
||||
uint32_t lineNo;
|
||||
int lastToken;
|
||||
int nextToken;
|
||||
|
||||
std::deque<IfStackEntry> ifStack;
|
||||
std::deque<IfStackEntry> ifStack; // Front is the innermost `IF` block
|
||||
|
||||
bool capturing; // Whether the text being lexed should be captured
|
||||
size_t captureSize; // Amount of text captured
|
||||
std::shared_ptr<std::vector<char>> captureBuf; // Buffer to send the captured text to if set
|
||||
|
||||
bool disableMacroArgs;
|
||||
bool disableInterpolation;
|
||||
size_t macroArgScanDistance; // Max distance already scanned for macro args
|
||||
bool expandStrings;
|
||||
std::deque<Expansion> expansions; // Front is the innermost current expansion
|
||||
bool enableExpansions;
|
||||
bool enableStringExpansions;
|
||||
size_t expansionScanDistance; // Max distance already scanned for expansions
|
||||
std::deque<Expansion> expansionStack; // Front is the innermost current expansion
|
||||
|
||||
Either<ViewedContent, BufferedContent> content;
|
||||
ContentSpan content; // Span of chars
|
||||
size_t offset = 0; // Cursor into `content.ptr`
|
||||
|
||||
~LexerState();
|
||||
|
||||
int peekChar();
|
||||
int peekCharAhead();
|
||||
|
||||
std::shared_ptr<char[]> makeSharedCaptureBufPtr() const {
|
||||
return std::shared_ptr<char[]>(captureBuf, captureBuf->data());
|
||||
}
|
||||
|
||||
void setAsCurrentState();
|
||||
bool setFileAsNextState(std::string const &filePath, bool updateStateNow);
|
||||
void setViewAsNextState(char const *name, ContentSpan const &span, uint32_t lineNo_);
|
||||
void setFileAsNextState(std::string const &filePath, bool updateStateNow);
|
||||
void setViewAsNextState(char const *name, ContentSpan const &content_, uint32_t lineNo_);
|
||||
|
||||
void clear(uint32_t lineNo_);
|
||||
};
|
||||
|
||||
extern char binDigits[2];
|
||||
extern char gfxDigits[4];
|
||||
|
||||
static inline void lexer_SetBinDigits(char const digits[2]) {
|
||||
binDigits[0] = digits[0];
|
||||
binDigits[1] = digits[1];
|
||||
}
|
||||
|
||||
static inline void lexer_SetGfxDigits(char const digits[4]) {
|
||||
gfxDigits[0] = digits[0];
|
||||
gfxDigits[1] = digits[1];
|
||||
gfxDigits[2] = digits[2];
|
||||
gfxDigits[3] = digits[3];
|
||||
}
|
||||
void lexer_SetBinDigits(char const digits[2]);
|
||||
void lexer_SetGfxDigits(char const digits[4]);
|
||||
|
||||
bool lexer_AtTopLevel();
|
||||
void lexer_RestartRept(uint32_t lineNo);
|
||||
void lexer_Init();
|
||||
void lexer_SetMode(LexerMode mode);
|
||||
void lexer_ToggleStringExpansion(bool enable);
|
||||
|
||||
@@ -146,7 +94,7 @@ void lexer_ReachELSEBlock();
|
||||
|
||||
void lexer_CheckRecursionDepth();
|
||||
uint32_t lexer_GetLineNo();
|
||||
void lexer_DumpStringExpansions();
|
||||
void lexer_TraceStringExpansions();
|
||||
|
||||
struct Capture {
|
||||
uint32_t lineNo;
|
||||
|
||||
@@ -13,7 +13,7 @@ struct MacroArgs {
|
||||
std::vector<std::shared_ptr<std::string>> args;
|
||||
|
||||
uint32_t nbArgs() const { return args.size() - shift; }
|
||||
std::shared_ptr<std::string> getArg(int32_t i) const;
|
||||
std::shared_ptr<std::string> getArg(int32_t num) const;
|
||||
std::shared_ptr<std::string> getAllArgs() const;
|
||||
|
||||
void appendArg(std::shared_ptr<std::string> arg);
|
||||
|
||||
+39
-7
@@ -3,16 +3,48 @@
|
||||
#ifndef RGBDS_ASM_MAIN_HPP
|
||||
#define RGBDS_ASM_MAIN_HPP
|
||||
|
||||
#include <optional>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
extern bool verbose;
|
||||
extern bool warnings; // True to enable warnings, false to disable them.
|
||||
#include "helpers.hpp" // assume
|
||||
#include "util.hpp" // xfclose
|
||||
|
||||
extern FILE *dependFile;
|
||||
extern std::string targetFileName;
|
||||
extern bool generatedMissingIncludes;
|
||||
extern bool failedOnMissingInclude;
|
||||
extern bool generatePhonyDeps;
|
||||
enum MissingInclude {
|
||||
INC_ERROR, // A missing included file is an error that halts assembly
|
||||
GEN_EXIT, // A missing included file is assumed to be generated; exit normally
|
||||
GEN_CONTINUE, // A missing included file is assumed to be generated; continue assembling
|
||||
};
|
||||
|
||||
struct Options {
|
||||
bool exportAll = false; // -E
|
||||
uint8_t fixPrecision = 16; // -Q
|
||||
size_t maxRecursionDepth = 64; // -r
|
||||
char binDigits[2] = {'0', '1'}; // -b
|
||||
char gfxDigits[4] = {'0', '1', '2', '3'}; // -g
|
||||
FILE *dependFile = nullptr; // -M
|
||||
std::optional<std::string> targetFileName{}; // -MQ, -MT
|
||||
MissingInclude missingIncludeState = INC_ERROR; // -MC, -MG
|
||||
bool generatePhonyDeps = false; // -MP
|
||||
std::optional<std::string> objectFileName{}; // -o
|
||||
uint8_t padByte = 0; // -p
|
||||
uint64_t maxErrors = 0; // -X
|
||||
|
||||
~Options() {
|
||||
if (dependFile) {
|
||||
xfclose(dependFile);
|
||||
}
|
||||
}
|
||||
|
||||
void printDep(std::string const &depName) {
|
||||
if (dependFile) {
|
||||
assume(targetFileName.has_value());
|
||||
fprintf(dependFile, "%s: %s\n", targetFileName->c_str(), depName.c_str());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
extern Options options;
|
||||
|
||||
#endif // RGBDS_ASM_MAIN_HPP
|
||||
|
||||
+3
-3
@@ -5,10 +5,10 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void opt_B(char const chars[2]);
|
||||
void opt_G(char const chars[4]);
|
||||
void opt_B(char const binDigits[2]);
|
||||
void opt_G(char const gfxDigits[4]);
|
||||
void opt_P(uint8_t padByte);
|
||||
void opt_Q(uint8_t precision);
|
||||
void opt_Q(uint8_t fixPrecision);
|
||||
void opt_W(char const *flag);
|
||||
void opt_Parse(char const *option);
|
||||
|
||||
|
||||
@@ -6,20 +6,18 @@
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "linkdefs.hpp"
|
||||
|
||||
struct Expression;
|
||||
struct FileStackNode;
|
||||
struct Symbol;
|
||||
|
||||
enum StateFeature { STATE_EQU, STATE_VAR, STATE_EQUS, STATE_CHAR, STATE_MACRO, NB_STATE_FEATURES };
|
||||
|
||||
extern std::string objectFileName;
|
||||
|
||||
void out_RegisterNode(std::shared_ptr<FileStackNode> node);
|
||||
void out_SetFileName(std::string const &name);
|
||||
void out_RegisterSymbol(Symbol &sym);
|
||||
void out_CreatePatch(uint32_t type, Expression const &expr, uint32_t ofs, uint32_t pcShift);
|
||||
void out_CreateAssert(
|
||||
AssertionType type, Expression const &expr, std::string const &message, uint32_t ofs
|
||||
|
||||
+25
-16
@@ -5,33 +5,45 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "either.hpp"
|
||||
#include "linkdefs.hpp"
|
||||
|
||||
#include "asm/intern.hpp"
|
||||
|
||||
struct Symbol;
|
||||
|
||||
struct RPNValue {
|
||||
RPNCommand command; // The RPN_* command ID
|
||||
std::variant<std::monostate, uint8_t, uint32_t, InternedStr> data; // Data after the ID, if any
|
||||
|
||||
RPNValue(RPNCommand cmd);
|
||||
RPNValue(RPNCommand cmd, uint8_t val);
|
||||
RPNValue(RPNCommand cmd, uint32_t val);
|
||||
RPNValue(RPNCommand cmd, InternedStr name);
|
||||
|
||||
void appendEncoded(std::vector<uint8_t> &buffer) const;
|
||||
};
|
||||
|
||||
struct Expression {
|
||||
Either<
|
||||
std::variant<
|
||||
int32_t, // If the expression's value is known, it's here
|
||||
std::string // Why the expression is not known, if it isn't
|
||||
>
|
||||
data = 0;
|
||||
bool isSymbol = false; // Whether the expression represents a symbol suitable for const diffing
|
||||
std::vector<uint8_t> rpn{}; // Bytes serializing the RPN expression
|
||||
uint32_t rpnPatchSize = 0; // Size the expression will take in the object file
|
||||
std::vector<RPNValue> rpn{}; // Values to be serialized into the RPN expression
|
||||
|
||||
bool isKnown() const { return data.holds<int32_t>(); }
|
||||
int32_t value() const { return data.get<int32_t>(); }
|
||||
bool isKnown() const { return std::holds_alternative<int32_t>(data); }
|
||||
int32_t value() const { return std::get<int32_t>(data); }
|
||||
|
||||
int32_t getConstVal() const;
|
||||
Symbol const *symbolOf() const;
|
||||
bool isDiffConstant(Symbol const *symName) const;
|
||||
|
||||
void makeNumber(uint32_t value);
|
||||
void makeSymbol(std::string const &symName);
|
||||
void makeBankSymbol(std::string const &symName);
|
||||
void makeSymbol(InternedStr symName);
|
||||
void makeBankSymbol(InternedStr symName);
|
||||
void makeBankSection(std::string const §Name);
|
||||
void makeSizeOfSection(std::string const §Name);
|
||||
void makeStartOfSection(std::string const §Name);
|
||||
@@ -40,16 +52,13 @@ struct Expression {
|
||||
void makeUnaryOp(RPNCommand op, Expression &&src);
|
||||
void makeBinaryOp(RPNCommand op, Expression &&src1, Expression const &src2);
|
||||
|
||||
bool makeCheckHRAM();
|
||||
void makeCheckRST();
|
||||
void makeCheckBitIndex(uint8_t mask);
|
||||
void addCheckHRAM();
|
||||
void addCheckRST();
|
||||
void addCheckBitIndex(uint8_t mask);
|
||||
|
||||
void checkNBit(uint8_t n) const;
|
||||
|
||||
private:
|
||||
void clear();
|
||||
uint8_t *reserveSpace(uint32_t size);
|
||||
uint8_t *reserveSpace(uint32_t size, uint32_t patchSize);
|
||||
void encode(std::vector<uint8_t> &buffer) const;
|
||||
};
|
||||
|
||||
bool checkNBit(int32_t v, uint8_t n, char const *name);
|
||||
|
||||
+17
-11
@@ -5,15 +5,15 @@
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "intern.hpp"
|
||||
#include "linkdefs.hpp"
|
||||
|
||||
extern uint8_t fillByte;
|
||||
|
||||
struct Expression;
|
||||
struct FileStackNode;
|
||||
struct Section;
|
||||
@@ -42,6 +42,7 @@ struct Section {
|
||||
std::deque<Patch> patches;
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
uint32_t getID() const; // ID of the section in the object file (`UINT32_MAX` if none)
|
||||
bool isSizeKnown() const;
|
||||
};
|
||||
|
||||
@@ -51,9 +52,8 @@ struct SectionSpec {
|
||||
uint16_t alignOfs;
|
||||
};
|
||||
|
||||
extern std::deque<Section> sectionList;
|
||||
extern std::unordered_map<std::string, size_t> sectionMap; // Indexes into `sectionList`
|
||||
extern Section *currentSection;
|
||||
size_t sect_CountSections();
|
||||
void sect_ForEach(void (*callback)(Section &));
|
||||
|
||||
Section *sect_FindSectionByName(std::string const &name);
|
||||
void sect_NewSection(
|
||||
@@ -76,6 +76,10 @@ void sect_CheckLoadClosed();
|
||||
Section *sect_GetSymbolSection();
|
||||
uint32_t sect_GetSymbolOffset();
|
||||
uint32_t sect_GetOutputOffset();
|
||||
std::optional<uint32_t> sect_GetOutputBank();
|
||||
|
||||
Patch *sect_AddOutputPatch();
|
||||
|
||||
uint32_t sect_GetAlignBytes(uint8_t alignment, uint16_t offset);
|
||||
void sect_AlignPC(uint8_t alignment, uint16_t offset);
|
||||
|
||||
@@ -87,21 +91,23 @@ void sect_EndUnion();
|
||||
void sect_CheckUnionClosed();
|
||||
|
||||
void sect_ConstByte(uint8_t byte);
|
||||
void sect_ByteString(std::vector<int32_t> const &string);
|
||||
void sect_WordString(std::vector<int32_t> const &string);
|
||||
void sect_LongString(std::vector<int32_t> const &string);
|
||||
void sect_ByteString(std::vector<int32_t> const &str);
|
||||
void sect_WordString(std::vector<int32_t> const &str);
|
||||
void sect_LongString(std::vector<int32_t> const &str);
|
||||
void sect_Skip(uint32_t skip, bool ds);
|
||||
void sect_RelByte(Expression const &expr, uint32_t pcShift);
|
||||
void sect_RelBytes(uint32_t n, std::vector<Expression> const &exprs);
|
||||
void sect_RelWord(Expression const &expr, uint32_t pcShift);
|
||||
void sect_RelLong(Expression const &expr, uint32_t pcShift);
|
||||
void sect_PCRelByte(Expression const &expr, uint32_t pcShift);
|
||||
void sect_BinaryFile(std::string const &name, int32_t startPos);
|
||||
void sect_BinaryFileSlice(std::string const &name, int32_t startPos, int32_t length);
|
||||
bool sect_BinaryFile(std::string const &name, uint32_t startPos);
|
||||
bool sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t length);
|
||||
|
||||
void sect_EndSection();
|
||||
void sect_PushSection();
|
||||
void sect_PopSection();
|
||||
void sect_CheckStack();
|
||||
|
||||
InternedStr sect_PushSectionFragmentLiteral();
|
||||
|
||||
#endif // RGBDS_ASM_SECTION_HPP
|
||||
|
||||
+26
-25
@@ -5,13 +5,12 @@
|
||||
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <time.h>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
#include "asm/intern.hpp"
|
||||
#include "asm/lexer.hpp"
|
||||
#include "asm/section.hpp"
|
||||
|
||||
@@ -24,14 +23,15 @@ enum SymbolType {
|
||||
SYM_REF // Forward reference to a label
|
||||
};
|
||||
|
||||
struct Symbol; // For the `sym_IsPC` forward declaration
|
||||
bool sym_IsPC(Symbol const *sym); // For the inline `getSection` method
|
||||
struct Symbol; // Forward declaration for `sym_IsPC`
|
||||
bool sym_IsPC(Symbol const *sym); // Forward declaration for `getSection`
|
||||
|
||||
struct Symbol {
|
||||
std::string name;
|
||||
InternedStr name;
|
||||
SymbolType type;
|
||||
bool isExported; // Whether the symbol is to be exported
|
||||
bool isBuiltin; // Whether the symbol is a built-in
|
||||
bool isBuiltin;
|
||||
bool isExported; // Not relevant for SYM_MACRO or SYM_EQUS
|
||||
bool isQuiet; // Only relevant for SYM_MACRO
|
||||
Section *section;
|
||||
std::shared_ptr<FileStackNode> src; // Where the symbol was defined
|
||||
uint32_t fileLine; // Line where the symbol was defined
|
||||
@@ -69,33 +69,34 @@ struct Symbol {
|
||||
uint32_t getConstantValue() const;
|
||||
};
|
||||
|
||||
bool sym_IsDotScope(InternedStr symName);
|
||||
|
||||
void sym_ForEach(void (*callback)(Symbol &));
|
||||
|
||||
void sym_SetExportAll(bool set);
|
||||
Symbol *sym_AddLocalLabel(std::string const &symName);
|
||||
Symbol *sym_AddLabel(std::string const &symName);
|
||||
Symbol *sym_AddLocalLabel(InternedStr symName);
|
||||
Symbol *sym_AddLabel(InternedStr symName);
|
||||
Symbol *sym_AddAnonLabel();
|
||||
std::string sym_MakeAnonLabelName(uint32_t ofs, bool neg);
|
||||
void sym_Export(std::string const &symName);
|
||||
Symbol *sym_AddEqu(std::string const &symName, int32_t value);
|
||||
Symbol *sym_RedefEqu(std::string const &symName, int32_t value);
|
||||
Symbol *sym_AddVar(std::string const &symName, int32_t value);
|
||||
InternedStr sym_MakeAnonLabelName(uint32_t ofs, bool neg);
|
||||
void sym_Export(InternedStr symName);
|
||||
Symbol *sym_AddEqu(InternedStr symName, int32_t value);
|
||||
Symbol *sym_RedefEqu(InternedStr symName, int32_t value);
|
||||
Symbol *sym_AddVar(InternedStr symName, int32_t value);
|
||||
int32_t sym_GetRSValue();
|
||||
void sym_SetRSValue(int32_t value);
|
||||
// Find a symbol by exact name, bypassing expansion checks
|
||||
Symbol *sym_FindExactSymbol(std::string const &symName);
|
||||
Symbol *sym_FindExactSymbol(InternedStr symName);
|
||||
// Find a symbol, possibly scoped, by name
|
||||
Symbol *sym_FindScopedSymbol(std::string const &symName);
|
||||
Symbol *sym_FindScopedSymbol(InternedStr symName);
|
||||
// Find a scoped symbol by name; do not return `@` or `_NARG` when they have no value
|
||||
Symbol *sym_FindScopedValidSymbol(std::string const &symName);
|
||||
Symbol *sym_FindScopedValidSymbol(InternedStr symName);
|
||||
Symbol const *sym_GetPC();
|
||||
Symbol *sym_AddMacro(std::string const &symName, int32_t defLineNo, ContentSpan const &span);
|
||||
Symbol *sym_Ref(std::string const &symName);
|
||||
Symbol *sym_AddString(std::string const &symName, std::shared_ptr<std::string> value);
|
||||
Symbol *sym_RedefString(std::string const &symName, std::shared_ptr<std::string> value);
|
||||
void sym_Purge(std::string const &symName);
|
||||
bool sym_IsPurgedExact(std::string const &symName);
|
||||
bool sym_IsPurgedScoped(std::string const &symName);
|
||||
Symbol *sym_AddMacro(InternedStr symName, int32_t defLineNo, ContentSpan const &span, bool isQuiet);
|
||||
Symbol *sym_Ref(InternedStr symName);
|
||||
Symbol *sym_AddString(InternedStr symName, std::shared_ptr<std::string> value);
|
||||
Symbol *sym_RedefString(InternedStr symName, std::shared_ptr<std::string> value);
|
||||
void sym_Purge(InternedStr symName);
|
||||
bool sym_IsPurgedExact(InternedStr symName);
|
||||
bool sym_IsPurgedScoped(InternedStr symName);
|
||||
void sym_Init(time_t now);
|
||||
|
||||
// Functions to save and restore the current label scopes.
|
||||
|
||||
+25
-21
@@ -3,7 +3,16 @@
|
||||
#ifndef RGBDS_ASM_WARNING_HPP
|
||||
#define RGBDS_ASM_WARNING_HPP
|
||||
|
||||
extern unsigned int nbErrors, maxErrors;
|
||||
#include <functional>
|
||||
|
||||
#include "diagnostics.hpp"
|
||||
|
||||
enum WarningLevel {
|
||||
LEVEL_DEFAULT, // Warnings that are enabled by default
|
||||
LEVEL_ALL, // Warnings that probably indicate an error
|
||||
LEVEL_EXTRA, // Warnings that are less likely to indicate an error
|
||||
LEVEL_EVERYTHING, // Literally every warning
|
||||
};
|
||||
|
||||
enum WarningID {
|
||||
WARNING_ASSERT, // Assertions
|
||||
@@ -14,6 +23,7 @@ enum WarningID {
|
||||
WARNING_EMPTY_DATA_DIRECTIVE, // `db`, `dw` or `dl` directive without data in ROM
|
||||
WARNING_EMPTY_MACRO_ARG, // Empty macro argument
|
||||
WARNING_EMPTY_STRRPL, // Empty second argument in `STRRPL`
|
||||
WARNING_EXPORT_UNDEFINED, // `EXPORT` of an undefined symbol
|
||||
WARNING_LARGE_CONSTANT, // Constants too large
|
||||
WARNING_MACRO_SHIFT, // `SHIFT` past available arguments in macro
|
||||
WARNING_NESTED_COMMENT, // Comment-start delimiter in a block comment
|
||||
@@ -43,24 +53,7 @@ enum WarningID {
|
||||
NB_WARNINGS,
|
||||
};
|
||||
|
||||
enum WarningAbled { WARNING_DEFAULT, WARNING_ENABLED, WARNING_DISABLED };
|
||||
|
||||
struct WarningState {
|
||||
WarningAbled state;
|
||||
WarningAbled error;
|
||||
|
||||
void update(WarningState other);
|
||||
};
|
||||
|
||||
struct Diagnostics {
|
||||
WarningState flagStates[NB_WARNINGS];
|
||||
WarningState metaStates[NB_WARNINGS];
|
||||
};
|
||||
|
||||
extern Diagnostics warningStates;
|
||||
extern bool warningsAreErrors;
|
||||
|
||||
void processWarningFlag(char const *flag);
|
||||
extern Diagnostics<WarningLevel, WarningID> warnings;
|
||||
|
||||
// Used to warn the user about problems that don't prevent the generation of
|
||||
// valid code.
|
||||
@@ -68,12 +61,16 @@ void processWarningFlag(char const *flag);
|
||||
void warning(WarningID id, char const *fmt, ...);
|
||||
|
||||
// Used for errors that compromise the whole assembly process by affecting the
|
||||
// following code, potencially making the assembler generate errors caused by
|
||||
// following code, potentially making the assembler generate errors caused by
|
||||
// the first one and unrelated to the code that the assembler complains about.
|
||||
// It is also used when the assembler goes into an invalid state (for example,
|
||||
// when it fails to allocate memory).
|
||||
[[gnu::format(printf, 1, 2), noreturn]]
|
||||
void fatalerror(char const *fmt, ...);
|
||||
void fatal(char const *fmt, ...);
|
||||
|
||||
// Used for fatal errors that handle their own backtrace output.
|
||||
[[noreturn]]
|
||||
void fatalNoTrace(std::function<void()> callback);
|
||||
|
||||
// Used for errors that make it impossible to assemble correctly, but don't
|
||||
// affect the following code. The code will fail to assemble but the user will
|
||||
@@ -82,4 +79,11 @@ void fatalerror(char const *fmt, ...);
|
||||
[[gnu::format(printf, 1, 2)]]
|
||||
void error(char const *fmt, ...);
|
||||
|
||||
// Used for errors that handle their own backtrace output. The code will fail
|
||||
// to assemble but the user will get a list of all errors at the end, making it
|
||||
// easier to fix all of them at once.
|
||||
void errorNoTrace(std::function<void()> callback);
|
||||
|
||||
void requireZeroErrors();
|
||||
|
||||
#endif // RGBDS_ASM_WARNING_HPP
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef RGBDS_BACKTRACE_HPP
|
||||
#define RGBDS_BACKTRACE_HPP
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
|
||||
#include "helpers.hpp" // InvocableR
|
||||
#include "style.hpp"
|
||||
|
||||
#define TRACE_SEPARATOR "<-"
|
||||
#define NODE_SEPARATOR "::"
|
||||
#define REPT_NODE_PREFIX "REPT~"
|
||||
|
||||
struct Tracing {
|
||||
uint64_t depth = 0;
|
||||
bool collapse = false;
|
||||
bool loud = false;
|
||||
};
|
||||
|
||||
extern Tracing tracing;
|
||||
|
||||
bool trace_ParseTraceDepth(char const *arg);
|
||||
|
||||
template<typename NodeT>
|
||||
void trace_PrintBacktrace(
|
||||
std::vector<NodeT> const &stack,
|
||||
InvocableR<char const *, NodeT const &> auto getName,
|
||||
InvocableR<uint32_t, NodeT const &> auto getLineNo
|
||||
) {
|
||||
size_t n = stack.size();
|
||||
if (n == 0) {
|
||||
return; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
auto printLocation = [&](size_t i) {
|
||||
NodeT const &item = stack[n - i - 1];
|
||||
style_Reset(stderr);
|
||||
if (!tracing.collapse) {
|
||||
fputs(" ", stderr); // Just three spaces; the fourth will be printed next
|
||||
}
|
||||
fprintf(stderr, " %s ", i == 0 ? "at" : TRACE_SEPARATOR);
|
||||
style_Set(stderr, STYLE_CYAN, true);
|
||||
fputs(getName(item), stderr);
|
||||
style_Set(stderr, STYLE_CYAN, false);
|
||||
fprintf(stderr, "(%" PRIu32 ")", getLineNo(item));
|
||||
if (!tracing.collapse) {
|
||||
putc('\n', stderr);
|
||||
}
|
||||
};
|
||||
|
||||
if (tracing.collapse) {
|
||||
fputs(" ", stderr); // Just three spaces; the fourth will be handled by the loop
|
||||
}
|
||||
|
||||
if (tracing.depth == 0 || static_cast<size_t>(tracing.depth) >= n) {
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
printLocation(i);
|
||||
}
|
||||
} else {
|
||||
size_t last = tracing.depth / 2;
|
||||
size_t first = tracing.depth - last;
|
||||
size_t skipped = n - tracing.depth;
|
||||
for (size_t i = 0; i < first; ++i) {
|
||||
printLocation(i);
|
||||
}
|
||||
style_Reset(stderr);
|
||||
|
||||
if (tracing.collapse) {
|
||||
fputs(" " TRACE_SEPARATOR, stderr);
|
||||
} else {
|
||||
fputs(" ", stderr); // Just three spaces; the fourth will be printed next
|
||||
}
|
||||
fprintf(stderr, " ...%zu more%s", skipped, last ? "..." : "");
|
||||
if (!tracing.collapse) {
|
||||
putc('\n', stderr);
|
||||
}
|
||||
|
||||
for (size_t i = n - last; i < n; ++i) {
|
||||
printLocation(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (tracing.collapse) {
|
||||
putc('\n', stderr);
|
||||
}
|
||||
style_Reset(stderr);
|
||||
}
|
||||
|
||||
#endif // RGBDS_BACKTRACE_HPP
|
||||
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef RGBDS_CLI_HPP
|
||||
#define RGBDS_CLI_HPP
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string>
|
||||
|
||||
#include "extern/getopt.hpp" // option
|
||||
#include "usage.hpp"
|
||||
|
||||
void cli_ParseArgs(
|
||||
int argc,
|
||||
char *argv[],
|
||||
char const *shortOpts,
|
||||
option const *longOpts,
|
||||
void (*parseArg)(int, char *),
|
||||
Usage usage
|
||||
);
|
||||
|
||||
#endif // RGBDS_CLI_HPP
|
||||
@@ -1,38 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef RGBDS_DEFAULT_INIT_ALLOC_HPP
|
||||
#define RGBDS_DEFAULT_INIT_ALLOC_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
// Allocator adaptor that interposes construct() calls to convert value-initialization
|
||||
// (which is what you get with e.g. `vector::resize`) into default-initialization (which does not
|
||||
// zero out non-class types).
|
||||
// From
|
||||
// https://stackoverflow.com/questions/21028299/is-this-behavior-of-vectorresizesize-type-n-under-c11-and-boost-container/21028912#21028912
|
||||
template<typename T, typename A = std::allocator<T>>
|
||||
class default_init_allocator : public A {
|
||||
using a_t = std::allocator_traits<A>;
|
||||
public:
|
||||
template<typename U>
|
||||
struct rebind {
|
||||
using other = default_init_allocator<U, typename a_t::template rebind_alloc<U>>;
|
||||
};
|
||||
|
||||
using A::A; // Inherit the allocator's constructors
|
||||
|
||||
template<typename U>
|
||||
void construct(U *ptr) noexcept(std::is_nothrow_default_constructible_v<U>) {
|
||||
::new (static_cast<void *>(ptr)) U;
|
||||
}
|
||||
template<typename U, typename... Args>
|
||||
void construct(U *ptr, Args &&...args) {
|
||||
a_t::construct(static_cast<A &>(*this), ptr, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using DefaultInitVec = std::vector<T, default_init_allocator<T>>;
|
||||
|
||||
#endif // RGBDS_DEFAULT_INIT_ALLOC_HPP
|
||||
@@ -0,0 +1,261 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef RGBDS_DIAGNOSTICS_HPP
|
||||
#define RGBDS_DIAGNOSTICS_HPP
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <optional>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "helpers.hpp"
|
||||
#include "itertools.hpp"
|
||||
#include "style.hpp"
|
||||
|
||||
[[gnu::format(printf, 1, 2)]]
|
||||
void warnx(char const *fmt, ...);
|
||||
[[gnu::format(printf, 1, 0)]]
|
||||
void vwarnx(char const *fmt, va_list args);
|
||||
[[gnu::format(printf, 1, 2)]]
|
||||
void errorx(char const *fmt, ...);
|
||||
[[gnu::format(printf, 1, 0)]]
|
||||
void verrorx(char const *fmt, va_list args);
|
||||
[[gnu::format(printf, 1, 2)]]
|
||||
void fatalx(char const *fmt, ...);
|
||||
[[gnu::format(printf, 1, 0)]]
|
||||
void vfatalx(char const *fmt, va_list args);
|
||||
|
||||
enum WarningAbled { WARNING_DEFAULT, WARNING_ENABLED, WARNING_DISABLED };
|
||||
|
||||
struct WarningState {
|
||||
WarningAbled state;
|
||||
WarningAbled error;
|
||||
|
||||
void update(WarningState other);
|
||||
};
|
||||
|
||||
std::pair<WarningState, std::optional<uint32_t>> getInitialWarningState(std::string &flag);
|
||||
|
||||
template<Enum LevelEnumT>
|
||||
struct WarningFlag {
|
||||
char const *name;
|
||||
LevelEnumT level;
|
||||
};
|
||||
|
||||
enum WarningBehavior { DISABLED, ENABLED, ERROR };
|
||||
|
||||
template<Enum WarningEnumT>
|
||||
struct ParamWarning {
|
||||
WarningEnumT firstID;
|
||||
WarningEnumT lastID;
|
||||
uint8_t defaultLevel;
|
||||
};
|
||||
|
||||
template<Enum WarningEnumT>
|
||||
struct DiagnosticsState {
|
||||
WarningState flagStates[WarningEnumT::NB_WARNINGS];
|
||||
WarningState metaStates[WarningEnumT::NB_WARNINGS];
|
||||
bool warningsEnabled = true;
|
||||
bool warningsAreErrors = false;
|
||||
};
|
||||
|
||||
template<Enum LevelEnumT, Enum WarningEnumT>
|
||||
struct Diagnostics {
|
||||
std::vector<WarningFlag<LevelEnumT>> metaWarnings;
|
||||
std::vector<WarningFlag<LevelEnumT>> warningFlags;
|
||||
std::vector<ParamWarning<WarningEnumT>> paramWarnings;
|
||||
DiagnosticsState<WarningEnumT> state;
|
||||
uint64_t nbErrors;
|
||||
|
||||
void incrementErrors() {
|
||||
if (nbErrors != UINT64_MAX) {
|
||||
++nbErrors;
|
||||
}
|
||||
}
|
||||
|
||||
WarningBehavior getWarningBehavior(WarningEnumT id) const;
|
||||
void processWarningFlag(char const *flag);
|
||||
};
|
||||
|
||||
template<Enum LevelEnumT, Enum WarningEnumT>
|
||||
WarningBehavior Diagnostics<LevelEnumT, WarningEnumT>::getWarningBehavior(WarningEnumT id) const {
|
||||
// Check if warnings are globally disabled
|
||||
if (!state.warningsEnabled) {
|
||||
return WarningBehavior::DISABLED;
|
||||
}
|
||||
|
||||
// Get the state of this warning flag
|
||||
WarningState const &flagState = state.flagStates[id];
|
||||
WarningState const &metaState = state.metaStates[id];
|
||||
|
||||
// If subsequent checks determine that the warning flag is enabled, this checks whether it has
|
||||
// -Werror without -Wno-error=<flag> or -Wno-error=<meta>, which makes it into an error
|
||||
bool warningIsError = state.warningsAreErrors && flagState.error != WARNING_DISABLED
|
||||
&& metaState.error != WARNING_DISABLED;
|
||||
WarningBehavior enabledBehavior =
|
||||
warningIsError ? WarningBehavior::ERROR : WarningBehavior::ENABLED;
|
||||
|
||||
// First, check the state of the specific warning flag
|
||||
if (flagState.state == WARNING_DISABLED) { // -Wno-<flag>
|
||||
return WarningBehavior::DISABLED;
|
||||
}
|
||||
if (flagState.error == WARNING_ENABLED) { // -Werror=<flag>
|
||||
return WarningBehavior::ERROR;
|
||||
}
|
||||
if (flagState.state == WARNING_ENABLED) { // -W<flag>
|
||||
return enabledBehavior;
|
||||
}
|
||||
|
||||
// If no flag is specified, check the state of the "meta" flags that affect this warning flag
|
||||
if (metaState.state == WARNING_DISABLED) { // -Wno-<meta>
|
||||
return WarningBehavior::DISABLED;
|
||||
}
|
||||
if (metaState.error == WARNING_ENABLED) { // -Werror=<meta>
|
||||
return WarningBehavior::ERROR;
|
||||
}
|
||||
if (metaState.state == WARNING_ENABLED) { // -W<meta>
|
||||
return enabledBehavior;
|
||||
}
|
||||
|
||||
// If no meta flag is specified, check the default state of this warning flag
|
||||
if (warningFlags[id].level == LevelEnumT::LEVEL_DEFAULT) { // enabled by default
|
||||
return enabledBehavior;
|
||||
}
|
||||
|
||||
// No flag enables this warning, explicitly or implicitly
|
||||
return WarningBehavior::DISABLED;
|
||||
}
|
||||
|
||||
template<Enum LevelEnumT, Enum WarningEnumT>
|
||||
void Diagnostics<LevelEnumT, WarningEnumT>::processWarningFlag(char const *flag) {
|
||||
std::string rootFlag = flag;
|
||||
|
||||
// Check for `-Werror` or `-Wno-error` to return early
|
||||
if (rootFlag == "error") {
|
||||
// `-Werror` promotes warnings to errors
|
||||
state.warningsAreErrors = true;
|
||||
return;
|
||||
} else if (rootFlag == "no-error") {
|
||||
// `-Wno-error` disables promotion of warnings to errors
|
||||
state.warningsAreErrors = false;
|
||||
return;
|
||||
}
|
||||
|
||||
auto [flagState, param] = getInitialWarningState(rootFlag);
|
||||
|
||||
// Try to match the flag against a parametric warning
|
||||
// If there was an equals sign, it will have set `param`; if not, `param` will be 0,
|
||||
// which applies to all levels
|
||||
for (ParamWarning<WarningEnumT> const ¶mWarning : paramWarnings) {
|
||||
WarningEnumT baseID = paramWarning.firstID;
|
||||
uint8_t maxParam = paramWarning.lastID - baseID + 1;
|
||||
assume(paramWarning.defaultLevel <= maxParam);
|
||||
|
||||
if (rootFlag != warningFlags[baseID].name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If making the warning an error but param is 0, set to the maximum
|
||||
// This accommodates `-Werror=<flag>`, but also `-Werror=<flag>=0`, which is
|
||||
// thus filtered out by the caller.
|
||||
// A param of 0 makes sense for disabling everything, but neither for
|
||||
// enabling nor "erroring". Use the default for those.
|
||||
if (!param.has_value() || *param == 0) {
|
||||
param = paramWarning.defaultLevel;
|
||||
} else if (*param > maxParam) {
|
||||
warnx(
|
||||
"Invalid warning flag parameter \"%s=%" PRIu32 "\"; capping at maximum %" PRIu8,
|
||||
rootFlag.c_str(),
|
||||
*param,
|
||||
maxParam
|
||||
);
|
||||
*param = maxParam;
|
||||
}
|
||||
|
||||
// Set the first <param> to enabled/error, and disable the rest
|
||||
for (uint32_t ofs = 0; ofs < maxParam; ++ofs) {
|
||||
if (WarningState &warning = state.flagStates[baseID + ofs]; ofs < *param) {
|
||||
warning.update(flagState);
|
||||
} else {
|
||||
warning.state = WARNING_DISABLED;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (param.has_value()) {
|
||||
warnx("Unknown warning flag parameter \"%s=%" PRIu32 "\"", rootFlag.c_str(), *param);
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to match against a "meta" warning
|
||||
for (WarningFlag<LevelEnumT> const &metaWarning : metaWarnings) {
|
||||
if (rootFlag != metaWarning.name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set each of the warning flags that meets this level
|
||||
for (WarningEnumT id : EnumSeq(WarningEnumT::NB_WARNINGS)) {
|
||||
if (metaWarning.level >= warningFlags[id].level) {
|
||||
state.metaStates[id].update(flagState);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to match against a "normal" flag
|
||||
for (WarningEnumT id : EnumSeq(WarningEnumT::NB_PLAIN_WARNINGS)) {
|
||||
if (rootFlag == warningFlags[id].name) {
|
||||
state.flagStates[id].update(flagState);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
warnx("Unknown warning flag \"%s\"", rootFlag.c_str());
|
||||
}
|
||||
|
||||
template<Enum LevelEnumT, Enum WarningEnumT>
|
||||
[[gnu::format(printf, 3, 0)]]
|
||||
WarningBehavior printDiagnostic(
|
||||
Diagnostics<LevelEnumT, WarningEnumT> const &warnings,
|
||||
WarningEnumT id,
|
||||
char const *fmt,
|
||||
va_list args
|
||||
) {
|
||||
char const *flag = warnings.warningFlags[id].name;
|
||||
WarningBehavior behavior = warnings.getWarningBehavior(id);
|
||||
|
||||
switch (behavior) {
|
||||
case WarningBehavior::DISABLED:
|
||||
break;
|
||||
|
||||
case WarningBehavior::ENABLED:
|
||||
style_Set(stderr, STYLE_YELLOW, true);
|
||||
fputs("warning: ", stderr);
|
||||
style_Reset(stderr);
|
||||
vfprintf(stderr, fmt, args);
|
||||
style_Set(stderr, STYLE_YELLOW, true);
|
||||
fprintf(stderr, " [-W%s]\n", flag);
|
||||
style_Reset(stderr);
|
||||
break;
|
||||
|
||||
case WarningBehavior::ERROR:
|
||||
style_Set(stderr, STYLE_RED, true);
|
||||
fputs("error: ", stderr);
|
||||
style_Reset(stderr);
|
||||
vfprintf(stderr, fmt, args);
|
||||
style_Set(stderr, STYLE_RED, true);
|
||||
fprintf(stderr, " [-Werror=%s]\n", flag);
|
||||
style_Reset(stderr);
|
||||
break;
|
||||
}
|
||||
|
||||
return behavior;
|
||||
}
|
||||
|
||||
#endif // RGBDS_DIAGNOSTICS_HPP
|
||||
@@ -1,176 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef RGBDS_EITHER_HPP
|
||||
#define RGBDS_EITHER_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "helpers.hpp" // assume
|
||||
|
||||
template<typename T1, typename T2>
|
||||
union Either {
|
||||
typedef T1 type1;
|
||||
typedef T2 type2;
|
||||
|
||||
private:
|
||||
template<typename T, unsigned V>
|
||||
struct Field {
|
||||
constexpr static unsigned tag_value = V;
|
||||
|
||||
unsigned tag = tag_value;
|
||||
T value;
|
||||
|
||||
Field() : value() {}
|
||||
Field(T &value_) : value(value_) {}
|
||||
Field(T const &value_) : value(value_) {}
|
||||
Field(T &&value_) : value(std::move(value_)) {}
|
||||
};
|
||||
|
||||
// The `_tag` unifies with the first `tag` member of each `struct`.
|
||||
constexpr static unsigned nulltag = 0;
|
||||
unsigned _tag = nulltag;
|
||||
Field<T1, 1> _t1;
|
||||
Field<T2, 2> _t2;
|
||||
|
||||
// Value accessors; the function parameters are dummies for overload resolution.
|
||||
// Only used to implement `field()` below.
|
||||
auto &pick(T1 *) { return _t1; }
|
||||
auto const &pick(T1 *) const { return _t1; }
|
||||
auto &pick(T2 *) { return _t2; }
|
||||
auto const &pick(T2 *) const { return _t2; }
|
||||
|
||||
// Generic field accessors; for internal use only.
|
||||
template<typename T>
|
||||
auto &field() {
|
||||
return pick(static_cast<T *>(nullptr));
|
||||
}
|
||||
template<typename T>
|
||||
auto const &field() const {
|
||||
return pick(static_cast<T *>(nullptr));
|
||||
}
|
||||
|
||||
public:
|
||||
// Equivalent of `std::monostate` for `std::variant`s.
|
||||
Either() : _tag() {}
|
||||
// These constructors cannot be generic over the value type, because that would prevent
|
||||
// constructible values from being inferred, e.g. a `const char *` string literal for an
|
||||
// `std::string` field value.
|
||||
Either(T1 &value) : _t1(value) {}
|
||||
Either(T2 &value) : _t2(value) {}
|
||||
Either(T1 const &value) : _t1(value) {}
|
||||
Either(T2 const &value) : _t2(value) {}
|
||||
Either(T1 &&value) : _t1(std::move(value)) {}
|
||||
Either(T2 &&value) : _t2(std::move(value)) {}
|
||||
|
||||
// Destructor manually calls the appropriate value destructor.
|
||||
~Either() {
|
||||
if (_tag == _t1.tag_value) {
|
||||
_t1.value.~T1();
|
||||
} else if (_tag == _t2.tag_value) {
|
||||
_t2.value.~T2();
|
||||
}
|
||||
}
|
||||
|
||||
// Copy assignment operators for each possible value.
|
||||
Either &operator=(T1 const &value) {
|
||||
_t1.tag = _t1.tag_value;
|
||||
new (&_t1.value) T1(value);
|
||||
return *this;
|
||||
}
|
||||
Either &operator=(T2 const &value) {
|
||||
_t2.tag = _t2.tag_value;
|
||||
new (&_t2.value) T2(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Move assignment operators for each possible value.
|
||||
Either &operator=(T1 &&value) {
|
||||
_t1.tag = _t1.tag_value;
|
||||
new (&_t1.value) T1(std::move(value));
|
||||
return *this;
|
||||
}
|
||||
Either &operator=(T2 &&value) {
|
||||
_t2.tag = _t2.tag_value;
|
||||
new (&_t2.value) T2(std::move(value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Copy assignment operator from another `Either`.
|
||||
Either &operator=(Either other) {
|
||||
if (other._tag == other._t1.tag_value) {
|
||||
*this = other._t1.value;
|
||||
} else if (other._tag == other._t2.tag_value) {
|
||||
*this = other._t2.value;
|
||||
} else {
|
||||
_tag = nulltag; // LCOV_EXCL_LINE
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Copy constructor from another `Either`; implemented in terms of value assignment operators.
|
||||
Either(Either const &other) {
|
||||
if (other._tag == other._t1.tag_value) {
|
||||
*this = other._t1.value;
|
||||
} else if (other._tag == other._t2.tag_value) {
|
||||
*this = other._t2.value;
|
||||
} else {
|
||||
_tag = nulltag;
|
||||
}
|
||||
}
|
||||
|
||||
// Move constructor from another `Either`; implemented in terms of value assignment operators.
|
||||
Either(Either &&other) {
|
||||
if (other._tag == other._t1.tag_value) {
|
||||
*this = std::move(other._t1.value);
|
||||
} else if (other._tag == other._t2.tag_value) {
|
||||
*this = std::move(other._t2.value);
|
||||
} else {
|
||||
_tag = nulltag;
|
||||
}
|
||||
}
|
||||
|
||||
// Equivalent of `.emplace<T>()` for `std::variant`s.
|
||||
template<typename T, typename... Args>
|
||||
void emplace(Args &&...args) {
|
||||
this->~Either();
|
||||
if constexpr (std::is_same_v<T, T1>) {
|
||||
_t1.tag = _t1.tag_value;
|
||||
new (&_t1.value) T1(std::forward<Args>(args)...);
|
||||
} else if constexpr (std::is_same_v<T, T2>) {
|
||||
_t2.tag = _t2.tag_value;
|
||||
new (&_t2.value) T2(std::forward<Args>(args)...);
|
||||
} else {
|
||||
_tag = nulltag;
|
||||
}
|
||||
}
|
||||
|
||||
// Equivalent of `std::holds_alternative<std::monostate>()` for `std::variant`s.
|
||||
bool empty() const { return _tag == nulltag; }
|
||||
|
||||
// Equivalent of `std::holds_alternative<T>()` for `std::variant`s.
|
||||
template<typename T>
|
||||
bool holds() const {
|
||||
if constexpr (std::is_same_v<T, T1>) {
|
||||
return _tag == _t1.tag_value;
|
||||
} else if constexpr (std::is_same_v<T, T2>) {
|
||||
return _tag == _t2.tag_value;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Equivalent of `std::get<T>()` for `std::variant`s.
|
||||
template<typename T>
|
||||
auto &get() {
|
||||
assume(holds<T>());
|
||||
return field<T>().value;
|
||||
}
|
||||
template<typename T>
|
||||
auto const &get() const {
|
||||
assume(holds<T>());
|
||||
return field<T>().value;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // RGBDS_EITHER_HPP
|
||||
@@ -1,18 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef RGBDS_ERROR_HPP
|
||||
#define RGBDS_ERROR_HPP
|
||||
|
||||
extern "C" {
|
||||
[[gnu::format(printf, 1, 2)]]
|
||||
void warn(char const *fmt...);
|
||||
[[gnu::format(printf, 1, 2)]]
|
||||
void warnx(char const *fmt, ...);
|
||||
|
||||
[[gnu::format(printf, 1, 2), noreturn]]
|
||||
void err(char const *fmt, ...);
|
||||
[[gnu::format(printf, 1, 2), noreturn]]
|
||||
void errx(char const *fmt, ...);
|
||||
}
|
||||
|
||||
#endif // RGBDS_ERROR_HPP
|
||||
Vendored
+2
-4
@@ -12,7 +12,7 @@ static constexpr int optional_argument = 2;
|
||||
// clang-format on
|
||||
|
||||
extern char *musl_optarg;
|
||||
extern int musl_optind, musl_opterr, musl_optopt, musl_optreset;
|
||||
extern int musl_optind, musl_optopt;
|
||||
|
||||
struct option {
|
||||
char const *name;
|
||||
@@ -21,8 +21,6 @@ struct option {
|
||||
int val;
|
||||
};
|
||||
|
||||
int musl_getopt_long_only(
|
||||
int argc, char **argv, char const *optstring, option const *longopts, int *idx
|
||||
);
|
||||
int musl_getopt_long_only(int argc, char **argv, char const *optstring, option const *longopts);
|
||||
|
||||
#endif // RGBDS_EXTERN_GETOPT_HPP
|
||||
|
||||
Vendored
+9
-1
@@ -5,6 +5,14 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint32_t decode(uint32_t *state, uint32_t *codep, uint8_t byte);
|
||||
#define UTF8_ACCEPT 0
|
||||
#define UTF8_REJECT 12
|
||||
|
||||
struct Utf8Decoder {
|
||||
uint32_t state = UTF8_ACCEPT;
|
||||
uint32_t codepoint = 0;
|
||||
|
||||
uint32_t update(uint8_t byte);
|
||||
};
|
||||
|
||||
#endif // RGBDS_EXTERN_UTF8DECODER_HPP
|
||||
|
||||
+12
-25
@@ -8,17 +8,14 @@
|
||||
#include <ios>
|
||||
#include <iostream>
|
||||
#include <streambuf>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include "either.hpp"
|
||||
#include "helpers.hpp" // assume
|
||||
#include "platform.hpp"
|
||||
|
||||
#include "gfx/main.hpp"
|
||||
|
||||
class File {
|
||||
Either<std::streambuf *, std::filebuf> _file;
|
||||
std::variant<std::streambuf *, std::filebuf> _file;
|
||||
|
||||
public:
|
||||
File() : _file(nullptr) {}
|
||||
@@ -27,42 +24,32 @@ public:
|
||||
// Returns `nullptr` on error, and a non-null pointer otherwise.
|
||||
File *open(std::string const &path, std::ios_base::openmode mode) {
|
||||
if (path != "-") {
|
||||
_file.emplace<std::filebuf>();
|
||||
return _file.get<std::filebuf>().open(path, mode) ? this : nullptr;
|
||||
return _file.emplace<std::filebuf>().open(path, mode) ? this : nullptr;
|
||||
} else if (mode & std::ios_base::in) {
|
||||
assume(!(mode & std::ios_base::out));
|
||||
_file.emplace<std::streambuf *>(std::cin.rdbuf());
|
||||
if (setmode(STDIN_FILENO, (mode & std::ios_base::binary) ? O_BINARY : O_TEXT) == -1) {
|
||||
fatal(
|
||||
"Failed to set stdin to %s mode: %s",
|
||||
mode & std::ios_base::binary ? "binary" : "text",
|
||||
strerror(errno)
|
||||
);
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
assume(mode & std::ios_base::out);
|
||||
_file.emplace<std::streambuf *>(std::cout.rdbuf());
|
||||
if (setmode(STDOUT_FILENO, (mode & std::ios_base::binary) ? O_BINARY : O_TEXT) == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
std::streambuf &operator*() {
|
||||
return _file.holds<std::filebuf>() ? _file.get<std::filebuf>()
|
||||
: *_file.get<std::streambuf *>();
|
||||
}
|
||||
std::streambuf const &operator*() const {
|
||||
// The non-`const` version does not perform any modifications, so it's okay.
|
||||
return **const_cast<File *>(this);
|
||||
return std::holds_alternative<std::filebuf>(_file) ? std::get<std::filebuf>(_file)
|
||||
: *std::get<std::streambuf *>(_file);
|
||||
}
|
||||
std::streambuf *operator->() { return &**this; }
|
||||
std::streambuf const *operator->() const {
|
||||
// See the `operator*` equivalent.
|
||||
return const_cast<File *>(this)->operator->();
|
||||
}
|
||||
|
||||
char const *c_str(std::string const &path) const {
|
||||
return _file.holds<std::filebuf>() ? path.c_str()
|
||||
: _file.get<std::streambuf *>() == std::cin.rdbuf() ? "<stdin>"
|
||||
: "<stdout>";
|
||||
return std::holds_alternative<std::filebuf>(_file) ? path.c_str()
|
||||
: std::get<std::streambuf *>(_file) == std::cin.rdbuf() ? "<stdin>"
|
||||
: "<stdout>";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef RGBDS_FIX_FIX_HPP
|
||||
#define RGBDS_FIX_FIX_HPP
|
||||
|
||||
bool fix_ProcessFile(char const *name, char const *outputName);
|
||||
|
||||
#endif // RGBDS_FIX_FIX_HPP
|
||||
@@ -0,0 +1,51 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef RGBDS_FIX_MAIN_HPP
|
||||
#define RGBDS_FIX_MAIN_HPP
|
||||
|
||||
#include <optional>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
#include "fix/mbc.hpp" // UNSPECIFIED, MbcType
|
||||
|
||||
// clang-format off: vertically align values
|
||||
static constexpr uint8_t FIX_LOGO = 1 << 7;
|
||||
static constexpr uint8_t TRASH_LOGO = 1 << 6;
|
||||
static constexpr uint8_t FIX_HEADER_SUM = 1 << 5;
|
||||
static constexpr uint8_t TRASH_HEADER_SUM = 1 << 4;
|
||||
static constexpr uint8_t FIX_GLOBAL_SUM = 1 << 3;
|
||||
static constexpr uint8_t TRASH_GLOBAL_SUM = 1 << 2;
|
||||
// clang-format on
|
||||
|
||||
enum Model { DMG, BOTH, CGB };
|
||||
|
||||
struct Options {
|
||||
uint8_t fixSpec = 0; // -f, -v
|
||||
Model model = DMG; // -C, -c
|
||||
bool japanese = true; // -j
|
||||
uint16_t oldLicensee = UNSPECIFIED; // -l
|
||||
uint16_t romVersion = UNSPECIFIED; // -n
|
||||
uint16_t padValue = UNSPECIFIED; // -p
|
||||
uint16_t ramSize = UNSPECIFIED; // -r
|
||||
bool sgb = false; // -s
|
||||
|
||||
std::optional<std::string> gameID; // -i
|
||||
uint8_t gameIDLen;
|
||||
|
||||
std::optional<std::string> newLicensee; // -k
|
||||
uint8_t newLicenseeLen;
|
||||
|
||||
std::optional<std::string> logoFilename; // -L
|
||||
uint8_t logo[48] = {};
|
||||
|
||||
MbcType cartridgeType = MBC_NONE; // -m
|
||||
uint8_t tpp1Rev[2];
|
||||
|
||||
std::optional<std::string> title; // -t
|
||||
uint8_t titleLen;
|
||||
};
|
||||
|
||||
extern Options options;
|
||||
|
||||
#endif // RGBDS_FIX_MAIN_HPP
|
||||
@@ -0,0 +1,79 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef RGBDS_FIX_MBC_HPP
|
||||
#define RGBDS_FIX_MBC_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
constexpr uint16_t UNSPECIFIED = 0x200;
|
||||
static_assert(UNSPECIFIED > 0xFF, "UNSPECIFIED should not be in byte range!");
|
||||
|
||||
enum MbcType {
|
||||
ROM = 0x00,
|
||||
ROM_RAM = 0x08,
|
||||
ROM_RAM_BATTERY = 0x09,
|
||||
|
||||
MBC1 = 0x01,
|
||||
MBC1_RAM = 0x02,
|
||||
MBC1_RAM_BATTERY = 0x03,
|
||||
|
||||
MBC2 = 0x05,
|
||||
MBC2_BATTERY = 0x06,
|
||||
|
||||
MMM01 = 0x0B,
|
||||
MMM01_RAM = 0x0C,
|
||||
MMM01_RAM_BATTERY = 0x0D,
|
||||
|
||||
MBC3 = 0x11,
|
||||
MBC3_TIMER_BATTERY = 0x0F,
|
||||
MBC3_TIMER_RAM_BATTERY = 0x10,
|
||||
MBC3_RAM = 0x12,
|
||||
MBC3_RAM_BATTERY = 0x13,
|
||||
|
||||
MBC5 = 0x19,
|
||||
MBC5_RAM = 0x1A,
|
||||
MBC5_RAM_BATTERY = 0x1B,
|
||||
MBC5_RUMBLE = 0x1C,
|
||||
MBC5_RUMBLE_RAM = 0x1D,
|
||||
MBC5_RUMBLE_RAM_BATTERY = 0x1E,
|
||||
|
||||
MBC6 = 0x20,
|
||||
|
||||
MBC7_SENSOR_RUMBLE_RAM_BATTERY = 0x22,
|
||||
|
||||
POCKET_CAMERA = 0xFC,
|
||||
|
||||
BANDAI_TAMA5 = 0xFD,
|
||||
|
||||
HUC3 = 0xFE,
|
||||
|
||||
HUC1_RAM_BATTERY = 0xFF,
|
||||
|
||||
// "Extended" values (still valid, but not directly actionable)
|
||||
|
||||
// A high byte of 0x01 means TPP1, the low byte is the requested features
|
||||
// This does not include SRAM, which is instead implied by a non-zero SRAM size
|
||||
// Note: Multiple rumble speeds imply rumble
|
||||
TPP1 = 0x100,
|
||||
TPP1_RUMBLE = 0x101,
|
||||
TPP1_MULTIRUMBLE_RUMBLE = 0x103,
|
||||
TPP1_TIMER = 0x104,
|
||||
TPP1_TIMER_RUMBLE = 0x105,
|
||||
TPP1_TIMER_MULTIRUMBLE_RUMBLE = 0x107,
|
||||
TPP1_BATTERY = 0x108,
|
||||
TPP1_BATTERY_RUMBLE = 0x109,
|
||||
TPP1_BATTERY_MULTIRUMBLE_RUMBLE = 0x10B,
|
||||
TPP1_BATTERY_TIMER = 0x10C,
|
||||
TPP1_BATTERY_TIMER_RUMBLE = 0x10D,
|
||||
TPP1_BATTERY_TIMER_MULTIRUMBLE_RUMBLE = 0x10F,
|
||||
|
||||
// Error values
|
||||
MBC_NONE = UNSPECIFIED, // No MBC specified, do not act on it
|
||||
};
|
||||
|
||||
bool mbc_HasRAM(MbcType type);
|
||||
char const *mbc_Name(MbcType type);
|
||||
MbcType mbc_ParseName(char const *name, uint8_t &tpp1Major, uint8_t &tpp1Minor);
|
||||
|
||||
#endif // RGBDS_FIX_MBC_HPP
|
||||
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef RGBDS_FIX_WARNING_HPP
|
||||
#define RGBDS_FIX_WARNING_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "diagnostics.hpp"
|
||||
|
||||
enum WarningLevel {
|
||||
LEVEL_DEFAULT, // Warnings that are enabled by default
|
||||
LEVEL_ALL, // Warnings that probably indicate an error
|
||||
LEVEL_EVERYTHING, // Literally every warning
|
||||
};
|
||||
|
||||
enum WarningID {
|
||||
WARNING_MBC, // Issues with MBC specs
|
||||
WARNING_OBSOLETE, // Obsolete/deprecated things
|
||||
WARNING_OVERWRITE, // Overwriting non-zero bytes
|
||||
WARNING_SGB, // SGB flag conflicts with old licensee code
|
||||
WARNING_TRUNCATION, // Truncating values to fit
|
||||
|
||||
NB_PLAIN_WARNINGS,
|
||||
|
||||
NB_WARNINGS = NB_PLAIN_WARNINGS,
|
||||
};
|
||||
|
||||
extern Diagnostics<WarningLevel, WarningID> warnings;
|
||||
|
||||
// Warns the user about problems that don't prevent fixing the ROM header
|
||||
[[gnu::format(printf, 2, 3)]]
|
||||
void warning(WarningID id, char const *fmt, ...);
|
||||
|
||||
// Prints an error, and increments the error count
|
||||
[[gnu::format(printf, 1, 2)]]
|
||||
void error(char const *fmt, ...);
|
||||
|
||||
// Prints an error, and exits with failure
|
||||
[[gnu::format(printf, 1, 2), noreturn]]
|
||||
void fatal(char const *fmt, ...);
|
||||
|
||||
uint32_t checkErrors(char const *filename);
|
||||
|
||||
#endif // RGBDS_FIX_WARNING_HPP
|
||||
@@ -1,18 +1,18 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef RGBDS_GFX_PROTO_PALETTE_HPP
|
||||
#define RGBDS_GFX_PROTO_PALETTE_HPP
|
||||
#ifndef RGBDS_GFX_COLOR_SET_HPP
|
||||
#define RGBDS_GFX_COLOR_SET_HPP
|
||||
|
||||
#include <array>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
class ProtoPalette {
|
||||
class ColorSet {
|
||||
public:
|
||||
static constexpr size_t capacity = 4;
|
||||
|
||||
private:
|
||||
// Up to 4 colors, sorted, and where SIZE_MAX means the slot is empty
|
||||
// Up to 4 colors, sorted, and where UINT16_MAX means the slot is empty
|
||||
// (OK because it's not a valid color index)
|
||||
// Sorting is done on the raw numerical values to lessen `compare`'s complexity
|
||||
std::array<uint16_t, capacity> _colorIndices{UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX};
|
||||
@@ -21,12 +21,8 @@ public:
|
||||
// Adds the specified color to the set, or **silently drops it** if the set is full.
|
||||
void add(uint16_t color);
|
||||
|
||||
enum ComparisonResult {
|
||||
NEITHER,
|
||||
WE_BIGGER,
|
||||
THEY_BIGGER = -1,
|
||||
};
|
||||
ComparisonResult compare(ProtoPalette const &other) const;
|
||||
enum ComparisonResult { INCOMPARABLE, SUBSET_OR_EQUAL, STRICT_SUPERSET };
|
||||
ComparisonResult compare(ColorSet const &other) const;
|
||||
|
||||
size_t size() const;
|
||||
bool empty() const;
|
||||
@@ -35,4 +31,4 @@ public:
|
||||
decltype(_colorIndices)::const_iterator end() const;
|
||||
};
|
||||
|
||||
#endif // RGBDS_GFX_PROTO_PALETTE_HPP
|
||||
#endif // RGBDS_GFX_COLOR_SET_HPP
|
||||
@@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef RGBDS_GFX_FLIP_HPP
|
||||
#define RGBDS_GFX_FLIP_HPP
|
||||
|
||||
#include <array>
|
||||
#include <stdint.h>
|
||||
|
||||
// Flipping tends to happen fairly often, so take a bite out of dcache to speed it up
|
||||
static std::array<uint16_t, 256> flipTable = ([]() constexpr {
|
||||
std::array<uint16_t, 256> table{};
|
||||
for (uint16_t i = 0; i < table.size(); ++i) {
|
||||
// To flip all the bits, we'll flip both nibbles, then each nibble half, etc.
|
||||
uint16_t byte = i;
|
||||
byte = (byte & 0b0000'1111) << 4 | (byte & 0b1111'0000) >> 4;
|
||||
byte = (byte & 0b0011'0011) << 2 | (byte & 0b1100'1100) >> 2;
|
||||
byte = (byte & 0b0101'0101) << 1 | (byte & 0b1010'1010) >> 1;
|
||||
table[i] = byte;
|
||||
}
|
||||
return table;
|
||||
})();
|
||||
|
||||
#endif // RGBDS_GFX_FLIP_HPP
|
||||
+14
-88
@@ -7,10 +7,9 @@
|
||||
#include <optional>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "helpers.hpp"
|
||||
#include "helpers.hpp" // assume
|
||||
|
||||
#include "gfx/rgba.hpp"
|
||||
|
||||
@@ -20,7 +19,6 @@ struct Options {
|
||||
bool allowMirroringX = false; // -X, -m
|
||||
bool allowMirroringY = false; // -Y, -m
|
||||
bool columnMajor = false; // -Z
|
||||
uint8_t verbosity = 0; // -v
|
||||
|
||||
std::string attrmap{}; // -a, -A
|
||||
std::optional<Rgba> bgColor{}; // -B
|
||||
@@ -29,8 +27,10 @@ struct Options {
|
||||
NO_SPEC,
|
||||
EXPLICIT,
|
||||
EMBEDDED,
|
||||
DMG,
|
||||
} palSpecType = NO_SPEC; // -c
|
||||
std::vector<std::array<std::optional<Rgba>, 4>> palSpec{};
|
||||
uint8_t palSpecDmg = 0;
|
||||
uint8_t bitDepth = 2; // -d
|
||||
std::string inputTileset{}; // -i
|
||||
struct {
|
||||
@@ -38,7 +38,10 @@ struct Options {
|
||||
uint16_t top;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint32_t right() const { return left + width * 8; }
|
||||
uint32_t bottom() const { return top + height * 8; }
|
||||
} inputSlice{0, 0, 0, 0}; // -L (margins in clockwise order, like CSS)
|
||||
uint8_t basePalID = 0; // -l
|
||||
std::array<uint16_t, 2> maxNbTiles{UINT16_MAX, 0}; // -N
|
||||
uint16_t nbPalettes = 8; // -n
|
||||
std::string output{}; // -o
|
||||
@@ -51,95 +54,18 @@ struct Options {
|
||||
|
||||
std::string input{}; // positional arg
|
||||
|
||||
// clang-format off: vertically align values
|
||||
static constexpr uint8_t VERB_NONE = 0; // Normal, no extra output
|
||||
static constexpr uint8_t VERB_CFG = 1; // Print configuration after parsing options
|
||||
static constexpr uint8_t VERB_LOG_ACT = 2; // Log actions before doing them
|
||||
static constexpr uint8_t VERB_INTERM = 3; // Print some intermediate results
|
||||
static constexpr uint8_t VERB_DEBUG = 4; // Internals are logged
|
||||
static constexpr uint8_t VERB_TRACE = 5; // Step-by-step algorithm details
|
||||
static constexpr uint8_t VERB_VVVVVV = 6; // What, can't I have a little fun?
|
||||
// clang-format on
|
||||
[[gnu::format(printf, 3, 4)]]
|
||||
void verbosePrint(uint8_t level, char const *fmt, ...) const;
|
||||
|
||||
mutable bool hasTransparentPixels = false;
|
||||
uint8_t maxOpaqueColors() const { return nbColorsPerPal - hasTransparentPixels; }
|
||||
|
||||
uint16_t maxNbColors() const { return nbColorsPerPal * nbPalettes; }
|
||||
|
||||
uint8_t dmgColors[4] = {};
|
||||
uint8_t dmgValue(uint8_t i) const {
|
||||
assume(i < 4);
|
||||
return (palSpecDmg >> (2 * i)) & 0b11;
|
||||
}
|
||||
};
|
||||
|
||||
extern Options options;
|
||||
|
||||
// Prints the error count, and exits with failure
|
||||
[[noreturn]]
|
||||
void giveUp();
|
||||
// If any error has been emitted thus far, calls `giveUp()`.
|
||||
void requireZeroErrors();
|
||||
// Prints a warning, and does not change the error count
|
||||
[[gnu::format(printf, 1, 2)]]
|
||||
void warning(char const *fmt, ...);
|
||||
// Prints an error, and increments the error count
|
||||
[[gnu::format(printf, 1, 2)]]
|
||||
void error(char const *fmt, ...);
|
||||
// Prints an error, and increments the error count
|
||||
// Does not take format arguments so `format_` and `-Wformat-security` won't complain about
|
||||
// calling `errorMessage(msg)`.
|
||||
void errorMessage(char const *msg);
|
||||
// Prints a fatal error, increments the error count, and gives up
|
||||
[[gnu::format(printf, 1, 2), noreturn]]
|
||||
void fatal(char const *fmt, ...);
|
||||
|
||||
struct Palette {
|
||||
// An array of 4 GBC-native (RGB555) colors
|
||||
std::array<uint16_t, 4> colors{UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX};
|
||||
|
||||
void addColor(uint16_t color);
|
||||
uint8_t indexOf(uint16_t color) const;
|
||||
uint16_t &operator[](size_t index) { return colors[index]; }
|
||||
uint16_t const &operator[](size_t index) const { return colors[index]; }
|
||||
|
||||
decltype(colors)::iterator begin();
|
||||
decltype(colors)::iterator end();
|
||||
decltype(colors)::const_iterator begin() const;
|
||||
decltype(colors)::const_iterator end() const;
|
||||
|
||||
uint8_t size() const;
|
||||
};
|
||||
|
||||
// Flipping tends to happen fairly often, so take a bite out of dcache to speed it up
|
||||
static constexpr auto flipTable = ([]() constexpr {
|
||||
std::array<uint16_t, 256> table{};
|
||||
for (uint16_t i = 0; i < table.size(); i++) {
|
||||
// To flip all the bits, we'll flip both nibbles, then each nibble half, etc.
|
||||
uint16_t byte = i;
|
||||
byte = (byte & 0b0000'1111) << 4 | (byte & 0b1111'0000) >> 4;
|
||||
byte = (byte & 0b0011'0011) << 2 | (byte & 0b1100'1100) >> 2;
|
||||
byte = (byte & 0b0101'0101) << 1 | (byte & 0b1010'1010) >> 1;
|
||||
table[i] = byte;
|
||||
}
|
||||
return table;
|
||||
})();
|
||||
|
||||
// Parsing helpers.
|
||||
|
||||
static constexpr uint8_t nibble(char c) {
|
||||
if (c >= 'a') {
|
||||
assume(c <= 'f');
|
||||
return c - 'a' + 10;
|
||||
} else if (c >= 'A') {
|
||||
assume(c <= 'F');
|
||||
return c - 'A' + 10;
|
||||
} else {
|
||||
assume(c >= '0' && c <= '9');
|
||||
return c - '0';
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr uint8_t toHex(char c1, char c2) {
|
||||
return nibble(c1) * 16 + nibble(c2);
|
||||
}
|
||||
|
||||
static constexpr uint8_t singleToHex(char c) {
|
||||
return toHex(c, c);
|
||||
}
|
||||
|
||||
#endif // RGBDS_GFX_MAIN_HPP
|
||||
|
||||
@@ -3,16 +3,14 @@
|
||||
#ifndef RGBDS_GFX_PAL_PACKING_HPP
|
||||
#define RGBDS_GFX_PAL_PACKING_HPP
|
||||
|
||||
#include <tuple>
|
||||
#include <stddef.h>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "defaultinitvec.hpp"
|
||||
|
||||
struct Palette;
|
||||
class ProtoPalette;
|
||||
class ColorSet;
|
||||
|
||||
// Returns which palette each proto-palette maps to, and how many palettes are necessary
|
||||
std::tuple<DefaultInitVec<size_t>, size_t>
|
||||
overloadAndRemove(std::vector<ProtoPalette> const &protoPalettes);
|
||||
// Returns which palette each color set maps to, and how many palettes are necessary
|
||||
std::pair<std::vector<size_t>, size_t> overloadAndRemove(std::vector<ColorSet> const &colorSets);
|
||||
|
||||
#endif // RGBDS_GFX_PAL_PACKING_HPP
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <png.h>
|
||||
#include <stddef.h>
|
||||
#include <vector>
|
||||
|
||||
#include "gfx/rgba.hpp"
|
||||
@@ -16,13 +16,7 @@ static constexpr size_t NB_COLOR_SLOTS = (1 << (5 * 3)) + 1;
|
||||
|
||||
struct Palette;
|
||||
|
||||
void sortIndexed(
|
||||
std::vector<Palette> &palettes,
|
||||
int palSize,
|
||||
png_color const *palRGB,
|
||||
int palAlphaSize,
|
||||
png_byte *palAlpha
|
||||
);
|
||||
void sortIndexed(std::vector<Palette> &palettes, std::vector<Rgba> const &embPal);
|
||||
void sortGrayscale(
|
||||
std::vector<Palette> &palettes, std::array<std::optional<Rgba>, NB_COLOR_SLOTS> const &colors
|
||||
);
|
||||
|
||||
@@ -3,7 +3,13 @@
|
||||
#ifndef RGBDS_GFX_PAL_SPEC_HPP
|
||||
#define RGBDS_GFX_PAL_SPEC_HPP
|
||||
|
||||
void parseInlinePalSpec(char const * const arg);
|
||||
#include <stdint.h>
|
||||
|
||||
void parseInlinePalSpec(char const * const rawArg);
|
||||
void parseExternalPalSpec(char const *arg);
|
||||
void parseDmgPalSpec(char const * const rawArg);
|
||||
void parseDmgPalSpec(uint8_t palSpecDmg);
|
||||
|
||||
void parseBackgroundPalSpec(char const *arg);
|
||||
|
||||
#endif // RGBDS_GFX_PAL_SPEC_HPP
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef RGBDS_GFX_PALETTE_HPP
|
||||
#define RGBDS_GFX_PALETTE_HPP
|
||||
|
||||
#include <array>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct Palette {
|
||||
// An array of 4 GBC-native (RGB555) colors
|
||||
std::array<uint16_t, 4> colors{UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX};
|
||||
|
||||
void addColor(uint16_t color);
|
||||
uint8_t indexOf(uint16_t color) const;
|
||||
uint16_t &operator[](size_t index) { return colors[index]; }
|
||||
uint16_t const &operator[](size_t index) const { return colors[index]; }
|
||||
|
||||
decltype(colors)::iterator begin();
|
||||
decltype(colors)::iterator end();
|
||||
decltype(colors)::const_iterator begin() const;
|
||||
decltype(colors)::const_iterator end() const;
|
||||
|
||||
uint8_t size() const;
|
||||
};
|
||||
|
||||
#endif // RGBDS_GFX_PALETTE_HPP
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef RGBDS_GFX_PNG_HPP
|
||||
#define RGBDS_GFX_PNG_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
#include <streambuf>
|
||||
#include <vector>
|
||||
|
||||
#include "gfx/rgba.hpp"
|
||||
|
||||
struct Png {
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
std::vector<Rgba> pixels{};
|
||||
std::vector<Rgba> palette{};
|
||||
|
||||
Png() {}
|
||||
Png(char const *filename, std::streambuf &file);
|
||||
};
|
||||
|
||||
#endif // RGBDS_GFX_PNG_HPP
|
||||
+35
-15
@@ -4,6 +4,9 @@
|
||||
#define RGBDS_GFX_RGBA_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
#include "helpers.hpp" // literal_strlen
|
||||
|
||||
struct Rgba {
|
||||
uint8_t red;
|
||||
@@ -17,32 +20,34 @@ struct Rgba {
|
||||
explicit constexpr Rgba(uint32_t rgba = 0)
|
||||
: red(rgba >> 24), green(rgba >> 16), blue(rgba >> 8), alpha(rgba) {}
|
||||
|
||||
static constexpr Rgba fromCGBColor(uint16_t cgbColor) {
|
||||
constexpr auto _5to8 = [](uint8_t fiveBpp) -> uint8_t {
|
||||
fiveBpp &= 0b11111; // For caller's convenience
|
||||
return fiveBpp << 3 | fiveBpp >> 2;
|
||||
// CGB colors are RGB555, so we use bit 15 to signify that the color is transparent instead
|
||||
// Since the rest of the bits don't matter then, we return 0x8000 (1 << 15) exactly.
|
||||
static constexpr uint16_t transparent = 0b1'00000'00000'00000;
|
||||
|
||||
static constexpr Rgba fromCGBColor(uint16_t color) {
|
||||
constexpr auto _5to8 = [](uint8_t channel) -> uint8_t {
|
||||
channel &= 0b11111; // For caller's convenience
|
||||
return channel << 3 | channel >> 2;
|
||||
};
|
||||
return {
|
||||
_5to8(cgbColor),
|
||||
_5to8(cgbColor >> 5),
|
||||
_5to8(cgbColor >> 10),
|
||||
static_cast<uint8_t>(cgbColor & 0x8000 ? 0x00 : 0xFF),
|
||||
_5to8(color),
|
||||
_5to8(color >> 5),
|
||||
_5to8(color >> 10),
|
||||
static_cast<uint8_t>(color & transparent ? 0x00 : 0xFF),
|
||||
};
|
||||
}
|
||||
|
||||
// Returns this RGBA as a 32-bit number that can be printed in hex (`%08x`) to yield its CSS
|
||||
// representation
|
||||
// Returns this RGBA as a 32-bit number that can be printed in hex (`#%08x`)
|
||||
// to yield its CSS representation (`#rrggbbaa`).
|
||||
uint32_t toCSS() const {
|
||||
auto shl = [](uint8_t val, unsigned shift) { return static_cast<uint32_t>(val) << shift; };
|
||||
constexpr auto shl = [](uint8_t val, unsigned shift) {
|
||||
return static_cast<uint32_t>(val) << shift;
|
||||
};
|
||||
return shl(red, 24) | shl(green, 16) | shl(blue, 8) | shl(alpha, 0);
|
||||
}
|
||||
|
||||
bool operator==(Rgba const &rhs) const { return toCSS() == rhs.toCSS(); }
|
||||
|
||||
// CGB colors are RGB555, so we use bit 15 to signify that the color is transparent instead
|
||||
// Since the rest of the bits don't matter then, we return 0x8000 exactly.
|
||||
static constexpr uint16_t transparent = 0b1'00000'00000'00000;
|
||||
|
||||
static constexpr uint8_t transparency_threshold = 0x10;
|
||||
bool isTransparent() const { return alpha < transparency_threshold; }
|
||||
static constexpr uint8_t opacity_threshold = 0xF0;
|
||||
@@ -54,4 +59,19 @@ struct Rgba {
|
||||
uint8_t grayIndex() const;
|
||||
};
|
||||
|
||||
// Returns a CGB color as a rendered string "GB:rr,gg,bb" or "transparent".
|
||||
std::string toCGB(uint16_t color);
|
||||
|
||||
std::string listCGBColors(auto const &list) {
|
||||
std::string buf;
|
||||
for (uint16_t color : list) {
|
||||
buf += toCGB(color) + "; ";
|
||||
}
|
||||
static constexpr size_t n = literal_strlen("; ");
|
||||
if (buf.size() >= n) {
|
||||
buf.erase(buf.size() - n, n);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif // RGBDS_GFX_RGBA_HPP
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef RGBDS_GFX_WARNING_HPP
|
||||
#define RGBDS_GFX_WARNING_HPP
|
||||
|
||||
#include "diagnostics.hpp"
|
||||
|
||||
enum WarningLevel {
|
||||
LEVEL_DEFAULT, // Warnings that are enabled by default
|
||||
LEVEL_ALL, // Warnings that probably indicate an error
|
||||
LEVEL_EVERYTHING, // Literally every warning
|
||||
};
|
||||
|
||||
enum WarningID {
|
||||
WARNING_EMBEDDED, // Using an embedded PNG palette without '-c embedded'
|
||||
WARNING_OBSOLETE, // Obsolete/deprecated things
|
||||
WARNING_TRIM_NONEMPTY, // '-x' trims nonempty tiles
|
||||
|
||||
NB_PLAIN_WARNINGS,
|
||||
|
||||
NB_WARNINGS = NB_PLAIN_WARNINGS,
|
||||
};
|
||||
|
||||
extern Diagnostics<WarningLevel, WarningID> warnings;
|
||||
|
||||
// Warns the user about problems that don't prevent valid graphics conversion
|
||||
[[gnu::format(printf, 2, 3)]]
|
||||
void warning(WarningID id, char const *fmt, ...);
|
||||
|
||||
// Prints the error count, and exits with failure
|
||||
[[noreturn]]
|
||||
void giveUp();
|
||||
|
||||
// If any error has been emitted thus far, calls `giveUp()`
|
||||
void requireZeroErrors();
|
||||
|
||||
// Prints an error, and increments the error count
|
||||
[[gnu::format(printf, 1, 2)]]
|
||||
void error(char const *fmt, ...);
|
||||
|
||||
// Prints a fatal error, increments the error count, and gives up
|
||||
[[gnu::format(printf, 1, 2), noreturn]]
|
||||
void fatal(char const *fmt, ...);
|
||||
|
||||
#endif // RGBDS_GFX_WARNING_HPP
|
||||
+46
-24
@@ -3,6 +3,8 @@
|
||||
#ifndef RGBDS_HELPERS_HPP
|
||||
#define RGBDS_HELPERS_HPP
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
// Ideally we'd use `std::unreachable`, but it has insufficient compiler support
|
||||
#ifdef __GNUC__ // GCC or compatible
|
||||
#ifdef NDEBUG
|
||||
@@ -24,7 +26,7 @@ static inline void unreachable_() {
|
||||
#ifdef _MSC_VER
|
||||
#define assume(x) __assume(x)
|
||||
#else
|
||||
// `[[gnu::assume()]]` for GCC or compatible also has insufficient support (GCC 13+ only)
|
||||
// `[[gnu::assume()]]` for GCC or compatible also has insufficient support (GCC 13+ only)
|
||||
#define assume(x) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
@@ -48,42 +50,40 @@ static inline void unreachable_() {
|
||||
#pragma intrinsic(_BitScanReverse, _BitScanForward)
|
||||
|
||||
static inline int ctz(unsigned int x) {
|
||||
unsigned long cnt;
|
||||
|
||||
assume(x != 0);
|
||||
_BitScanForward(&cnt, x);
|
||||
return cnt;
|
||||
unsigned long count;
|
||||
_BitScanForward(&count, x);
|
||||
return count;
|
||||
}
|
||||
|
||||
static inline int clz(unsigned int x) {
|
||||
unsigned long cnt;
|
||||
|
||||
assume(x != 0);
|
||||
_BitScanReverse(&cnt, x);
|
||||
return 31 - cnt;
|
||||
unsigned long count;
|
||||
_BitScanReverse(&count, x);
|
||||
return 31 - count;
|
||||
}
|
||||
|
||||
#else
|
||||
#include <limits.h>
|
||||
|
||||
static inline int ctz(unsigned int x) {
|
||||
int cnt = 0;
|
||||
|
||||
assume(x != 0);
|
||||
int count = 0;
|
||||
while (!(x & 1)) {
|
||||
x >>= 1;
|
||||
cnt++;
|
||||
++count;
|
||||
}
|
||||
return cnt;
|
||||
return count;
|
||||
}
|
||||
|
||||
static inline int clz(unsigned int x) {
|
||||
int cnt = 0;
|
||||
|
||||
assume(x != 0);
|
||||
int count = 0;
|
||||
while (x <= UINT_MAX / 2) {
|
||||
x <<= 1;
|
||||
cnt++;
|
||||
++count;
|
||||
}
|
||||
return cnt;
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -96,19 +96,41 @@ static inline int clz(unsigned int x) {
|
||||
#define EXPAND_AND_CAT(x, y) CAT(x, y)
|
||||
|
||||
// For lack of <ranges>, this adds some more brevity
|
||||
#define RANGE(s) std::begin(s), std::end(s)
|
||||
#define RANGE(s) std::begin(s), std::end(s)
|
||||
#define RRANGE(s) std::rbegin(s), std::rend(s)
|
||||
|
||||
// Macros to print-format a `std::string_view` (like <inttype.h> macros)
|
||||
#define PRI_SV ".*s"
|
||||
#define PRI_SV_ARG(sv) static_cast<int>((sv).length()), (sv).data()
|
||||
|
||||
// MSVC does not inline `strlen()` or `.length()` of a constant string
|
||||
template<int N>
|
||||
static constexpr int literal_strlen(char const (&)[N]) {
|
||||
return N - 1;
|
||||
template<int SizeOfString>
|
||||
requires(SizeOfString > 0)
|
||||
static constexpr int literal_strlen(char const (&)[SizeOfString]) {
|
||||
return SizeOfString - 1; // Don't count the ending '\0'
|
||||
}
|
||||
|
||||
// Concept for template parameters that must be an `enum` type
|
||||
template<typename EnumT>
|
||||
concept Enum = std::is_enum_v<EnumT>;
|
||||
|
||||
// Concept for template parameters that must be a function returning `void`
|
||||
template<typename ProcedureFnT, typename... Args>
|
||||
concept Procedure = std::is_void_v<std::invoke_result_t<ProcedureFnT, Args...>>;
|
||||
|
||||
// Concept for template parameters that must be a function returning a particular type
|
||||
template<typename FnT, typename ReturnT, typename... Args>
|
||||
concept InvocableR = std::is_invocable_r_v<ReturnT, FnT, Args...>;
|
||||
|
||||
// Concept for template parameters that must match a particular type modulo cv-qualifiers
|
||||
template<typename T, typename UnqualifiedT>
|
||||
concept QualifiedEquivalent = std::is_same_v<std::remove_cvref_t<T>, UnqualifiedT>;
|
||||
|
||||
// For ad-hoc RAII in place of a `defer` statement or cross-platform `__attribute__((cleanup))`
|
||||
template<typename T>
|
||||
template<Procedure DeferredFnT>
|
||||
struct Defer {
|
||||
T deferred;
|
||||
Defer(T func) : deferred(func) {}
|
||||
DeferredFnT deferred;
|
||||
Defer(DeferredFnT func) : deferred(func) {}
|
||||
~Defer() { deferred(); }
|
||||
};
|
||||
|
||||
|
||||
+108
-21
@@ -3,46 +3,127 @@
|
||||
#ifndef RGBDS_ITERTOOLS_HPP
|
||||
#define RGBDS_ITERTOOLS_HPP
|
||||
|
||||
#include <deque>
|
||||
#include <optional>
|
||||
#include <stddef.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
template<typename T>
|
||||
#include "helpers.hpp" // Enum, assume
|
||||
|
||||
// A wrapper around iterables to reverse their iteration order; used in `for`-each loops.
|
||||
template<typename IterableT>
|
||||
struct ReversedIterable {
|
||||
IterableT &_iterable;
|
||||
};
|
||||
|
||||
template<typename IterableT>
|
||||
auto begin(ReversedIterable<IterableT> r) {
|
||||
return std::rbegin(r._iterable);
|
||||
}
|
||||
|
||||
template<typename IterableT>
|
||||
auto end(ReversedIterable<IterableT> r) {
|
||||
return std::rend(r._iterable);
|
||||
}
|
||||
|
||||
template<typename IterableT>
|
||||
ReversedIterable<IterableT> reversed(IterableT &&_iterable) {
|
||||
return {_iterable};
|
||||
}
|
||||
|
||||
// A map from `KeyT` keys to `ItemT` items, iterable in the order the items were inserted.
|
||||
template<typename KeyT, typename ItemT>
|
||||
class InsertionOrderedMap {
|
||||
std::deque<ItemT> list; // `deque` does not invalidate item references
|
||||
std::unordered_map<KeyT, size_t> map; // Indexes into `list`
|
||||
|
||||
public:
|
||||
size_t size() const { return list.size(); }
|
||||
|
||||
bool empty() const { return list.empty(); }
|
||||
|
||||
bool contains(KeyT const &key) const { return map.find(key) != map.end(); }
|
||||
|
||||
ItemT &operator[](size_t i) { return list[i]; }
|
||||
|
||||
typename decltype(list)::iterator begin() { return list.begin(); }
|
||||
typename decltype(list)::iterator end() { return list.end(); }
|
||||
typename decltype(list)::const_iterator begin() const { return list.begin(); }
|
||||
typename decltype(list)::const_iterator end() const { return list.end(); }
|
||||
|
||||
// Adding a key that already exists would make the previous value unreachable.
|
||||
// `InsertionOrderedMap`s are only used for charmaps and sections, which each
|
||||
// avoid `add`ing if already present, so we can `assume` this is not a concern.
|
||||
|
||||
ItemT &add(KeyT const &key) {
|
||||
assume(!contains(key));
|
||||
map[key] = list.size();
|
||||
return list.emplace_back();
|
||||
}
|
||||
|
||||
ItemT &add(KeyT const &key, ItemT &&value) {
|
||||
assume(!contains(key));
|
||||
map[key] = list.size();
|
||||
list.emplace_back(std::move(value));
|
||||
return list.back();
|
||||
}
|
||||
|
||||
ItemT &addAnonymous() {
|
||||
// Add the new item to the list, but do not update the map
|
||||
return list.emplace_back();
|
||||
}
|
||||
|
||||
std::optional<size_t> findIndex(KeyT const &key) const {
|
||||
if (auto search = map.find(key); search != map.end()) {
|
||||
return search->second;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
// An iterable of `enum` values in the half-open range [start, stop).
|
||||
template<Enum EnumT>
|
||||
class EnumSeq {
|
||||
T _start;
|
||||
T _stop;
|
||||
EnumT _start;
|
||||
EnumT _stop;
|
||||
|
||||
class Iterator {
|
||||
T _value;
|
||||
EnumT _value;
|
||||
|
||||
public:
|
||||
explicit Iterator(T value) : _value(value) {}
|
||||
explicit Iterator(EnumT value) : _value(value) {}
|
||||
|
||||
Iterator &operator++() {
|
||||
_value = static_cast<T>(_value + 1);
|
||||
_value = static_cast<EnumT>(_value + 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto operator*() const { return _value; }
|
||||
EnumT operator*() const { return _value; }
|
||||
|
||||
bool operator==(Iterator const &rhs) const { return _value == rhs._value; }
|
||||
};
|
||||
|
||||
public:
|
||||
explicit EnumSeq(T stop) : _start(static_cast<T>(0)), _stop(stop) {}
|
||||
explicit EnumSeq(T start, T stop) : _start(start), _stop(stop) {}
|
||||
explicit EnumSeq(EnumT stop) : _start(static_cast<EnumT>(0)), _stop(stop) {}
|
||||
explicit EnumSeq(EnumT start, EnumT stop) : _start(start), _stop(stop) {}
|
||||
|
||||
Iterator begin() { return Iterator(_start); }
|
||||
Iterator end() { return Iterator(_stop); }
|
||||
};
|
||||
|
||||
// Only needed inside `ZipContainer` below.
|
||||
// This is not a fully generic implementation; its current use cases only require for-loop behavior.
|
||||
// We also assume that all iterators have the same length.
|
||||
template<typename... Ts>
|
||||
template<typename... IteratorTs>
|
||||
class ZipIterator {
|
||||
std::tuple<Ts...> _iters;
|
||||
std::tuple<IteratorTs...> _iters;
|
||||
|
||||
public:
|
||||
explicit ZipIterator(std::tuple<Ts...> &&iters) : _iters(iters) {}
|
||||
explicit ZipIterator(std::tuple<IteratorTs...> &&iters) : _iters(iters) {}
|
||||
|
||||
ZipIterator &operator++() {
|
||||
std::apply([](auto &&...it) { (++it, ...); }, _iters);
|
||||
@@ -60,12 +141,14 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Ts>
|
||||
// Only needed inside `zip` below.
|
||||
template<typename... IterableTs>
|
||||
class ZipContainer {
|
||||
std::tuple<Ts...> _containers;
|
||||
std::tuple<IterableTs...> _containers;
|
||||
|
||||
public:
|
||||
explicit ZipContainer(Ts &&...containers) : _containers(std::forward<Ts>(containers)...) {}
|
||||
explicit ZipContainer(IterableTs &&...containers)
|
||||
: _containers(std::forward<IterableTs>(containers)...) {}
|
||||
|
||||
auto begin() {
|
||||
return ZipIterator(std::apply(
|
||||
@@ -88,15 +171,19 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// Only needed inside `zip` below.
|
||||
// Take ownership of objects and rvalue refs passed to us, but not lvalue refs
|
||||
template<typename T>
|
||||
using Holder = std::
|
||||
conditional_t<std::is_lvalue_reference_v<T>, T, std::remove_cv_t<std::remove_reference_t<T>>>;
|
||||
template<typename IterableT>
|
||||
using ZipHolder = std::conditional_t<
|
||||
std::is_lvalue_reference_v<IterableT>,
|
||||
IterableT,
|
||||
std::remove_cvref_t<IterableT>>;
|
||||
|
||||
// Iterates over N containers at once, yielding tuples of N items at a time.
|
||||
// Does the same number of iterations as the first container's iterator!
|
||||
template<typename... Ts>
|
||||
static constexpr auto zip(Ts &&...cs) {
|
||||
return ZipContainer<Holder<Ts>...>(std::forward<Ts>(cs)...);
|
||||
template<typename... IterableTs>
|
||||
static constexpr auto zip(IterableTs &&...containers) {
|
||||
return ZipContainer<ZipHolder<IterableTs>...>(std::forward<IterableTs>(containers)...);
|
||||
}
|
||||
|
||||
#endif // RGBDS_ITERTOOLS_HPP
|
||||
|
||||
@@ -3,10 +3,6 @@
|
||||
#ifndef RGBDS_LINK_ASSIGN_HPP
|
||||
#define RGBDS_LINK_ASSIGN_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern uint64_t nbSectionsToAssign;
|
||||
|
||||
// Assigns all sections a slice of the address space
|
||||
void assign_AssignSections();
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef RGBDS_LINK_FSTACK_HPP
|
||||
#define RGBDS_LINK_FSTACK_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "linkdefs.hpp"
|
||||
|
||||
struct FileStackNode {
|
||||
FileStackNodeType type;
|
||||
std::variant<
|
||||
std::monostate, // Default constructed; `.type` and `.data` must be set manually
|
||||
std::vector<uint32_t>, // NODE_REPT
|
||||
std::string // NODE_FILE, NODE_MACRO
|
||||
>
|
||||
data;
|
||||
bool isQuiet; // Whether to omit this node from error reporting
|
||||
|
||||
FileStackNode *parent;
|
||||
// Line at which the parent context was exited; meaningless for the root level
|
||||
uint32_t lineNo;
|
||||
|
||||
// REPT iteration counts since last named node, in reverse depth order
|
||||
std::vector<uint32_t> &iters() { return std::get<std::vector<uint32_t>>(data); }
|
||||
std::vector<uint32_t> const &iters() const { return std::get<std::vector<uint32_t>>(data); }
|
||||
// File name for files, file::macro name for macros
|
||||
std::string &name() { return std::get<std::string>(data); }
|
||||
std::string const &name() const { return std::get<std::string>(data); }
|
||||
|
||||
void printBacktrace(uint32_t curLineNo) const;
|
||||
};
|
||||
|
||||
#endif // RGBDS_LINK_FSTACK_HPP
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user