mirror of
https://github.com/gbdev/rgbds.git
synced 2026-08-24 15:54:33 +00:00
Compare commits
416
Commits
v1.0.0-rc2
..
v1.0.3
| 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 |
@@ -71,6 +71,7 @@ Language: Cpp
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
PPIndentWidth: -1
|
||||
PenaltyBreakScopeResolution: 1000
|
||||
PointerAlignment: Right
|
||||
QualifierAlignment: Right
|
||||
ReflowComments: true
|
||||
|
||||
+10
-1
@@ -1,5 +1,6 @@
|
||||
[*]
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
indent_size = tab
|
||||
tab_width = 4
|
||||
@@ -7,3 +8,11 @@ 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.50
|
||||
|
||||
## 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)" != 4df396518620a7aa3651443e87d1b2862e4e88cad135a8b93423e01706232307 ]; 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
|
||||
}
|
||||
|
||||
@@ -79,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,10 +1,10 @@
|
||||
#!/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:'
|
||||
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/pnggroup/libpng/archive/refs/tags/v1.6.50.zip' 'libpng.zip' 'f6bb2544d2cf5465af3a695dee0b7eacff82f11a50aa4672ef0e19df6e16d455' .
|
||||
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.50 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,28 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
pngver=1.6.50
|
||||
arch="$1"
|
||||
|
||||
## Grab sources and check them
|
||||
|
||||
wget http://downloads.sourceforge.net/project/libpng/libpng16/$pngver/libpng-$pngver.tar.xz
|
||||
echo 4df396518620a7aa3651443e87d1b2862e4e88cad135a8b93423e01706232307 libpng-$pngver.tar.xz | sha256sum -c -
|
||||
|
||||
## Extract sources and patch them
|
||||
|
||||
tar -xf libpng-$pngver.tar.xz
|
||||
|
||||
## 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
|
||||
@@ -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 }}
|
||||
@@ -43,7 +49,7 @@ jobs:
|
||||
|
||||
- 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: Diff completeness check
|
||||
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
|
||||
@@ -3,28 +3,26 @@ 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-24.04
|
||||
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 LCOV
|
||||
run: |
|
||||
sudo apt-get install lcov
|
||||
- name: Install test dependency dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
test/fetch-test-deps.sh --get-deps ubuntu
|
||||
.github/scripts/install-deps.sh ubuntu-latest lcov
|
||||
- name: Generate coverage report
|
||||
run: |
|
||||
contrib/coverage.bash ubuntu-ci
|
||||
contrib/coverage.bash --os ubuntu-latest --jobs "$(getconf _NPROCESSORS_ONLN)"
|
||||
- name: Upload coverage report
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: coverage-report
|
||||
# Workaround for keeping the top-level coverage/ directory
|
||||
@@ -32,3 +30,4 @@ jobs:
|
||||
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-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-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-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-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-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-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 going to 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-win32.zip
|
||||
win64/rgbds-win64.zip
|
||||
macos/rgbds-macos.zip
|
||||
linux/rgbds-linux-x86_64.tar.xz
|
||||
rgbds-source.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
|
||||
|
||||
+249
-187
@@ -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,211 +106,179 @@ 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 --os ${{ matrix.os }}
|
||||
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 --os macos
|
||||
ctest --test-dir build --schedule-random
|
||||
|
||||
windows:
|
||||
strategy:
|
||||
matrix:
|
||||
bits: [32, 64]
|
||||
os: [windows-2022, windows-2025]
|
||||
include:
|
||||
- bits: 32
|
||||
arch: x86
|
||||
platform: Win32
|
||||
- bits: 64
|
||||
arch: x86_x64
|
||||
platform: x64
|
||||
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.os }}-${{ matrix.arch }}-${{ hashFiles('zlib/**', 'libpng/**') }}
|
||||
- name: Build zlib
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
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 --os ${{ matrix.os }}
|
||||
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
|
||||
@@ -277,113 +290,162 @@ jobs:
|
||||
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 --os ${{ matrix.os }}
|
||||
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-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: "14.3"
|
||||
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 -DOS=bsd
|
||||
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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+12
-8
@@ -1,21 +1,25 @@
|
||||
FROM debian:12-slim
|
||||
FROM debian:13-slim
|
||||
LABEL org.opencontainers.image.source=https://github.com/gbdev/rgbds
|
||||
ARG version=1.0.0-rc2
|
||||
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
|
||||
|
||||
# Install dependencies and compile RGBDS
|
||||
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=
|
||||
|
||||
# Create an archive with the compiled executables and all the necessary to install it,
|
||||
# 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/* .github/scripts/install.sh
|
||||
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 ./.github/scripts/install.sh
|
||||
RUN make install Q=
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .cpp .y .o
|
||||
|
||||
.PHONY: all clean install checkdiff develop debug profile coverage format tidy 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,31 +27,32 @@ 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 \
|
||||
@@ -63,6 +65,7 @@ rgbasm_obj := \
|
||||
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 \
|
||||
@@ -118,6 +121,7 @@ rgbgfx_obj := \
|
||||
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/reverse.o \
|
||||
@@ -180,6 +184,11 @@ src/gfx/rgba.o: src/gfx/rgba.cpp
|
||||
.cpp.o:
|
||||
$Q${CXX} ${REALCXXFLAGS} -c -o $@ $<
|
||||
|
||||
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
|
||||
@@ -188,7 +197,7 @@ 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
|
||||
@@ -200,13 +209,9 @@ install: all
|
||||
$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/
|
||||
|
||||
# Target used to check for suspiciously missing changed files.
|
||||
checkdiff:
|
||||
$Qcontrib/checkdiff.bash `git merge-base HEAD ${BASE_REF}`
|
||||
$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 in development to prevent adding new issues to the source code.
|
||||
# All warnings are treated as errors to block the compilation and make the
|
||||
@@ -220,8 +225,8 @@ 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"
|
||||
|
||||
# Target used in development to debug with gdb.
|
||||
@@ -230,46 +235,35 @@ debug:
|
||||
CXXFLAGS="-ggdb3 -O0 -fno-omit-frame-pointer -fno-optimize-sibling-calls"
|
||||
|
||||
# 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"
|
||||
|
||||
# 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"
|
||||
|
||||
# Target used in development to format source code with clang-format.
|
||||
format:
|
||||
$Qclang-format -i $$(git ls-files '*.hpp' '*.cpp')
|
||||
$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
|
||||
$Qclang-tidy -p . $$(git ls-files '*.hpp' '*.cpp')
|
||||
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
|
||||
@@ -281,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-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
|
||||
|
||||
This toolchain is maintained [on GitHub](https://github.com/gbdev/rgbds).
|
||||
## Documentation
|
||||
|
||||
The documentation of this toolchain can be [viewed online](https://rgbds.gbdev.io/docs/),
|
||||
including its [basic usage and development history](https://rgbds.gbdev.io/docs/rgbds.7).
|
||||
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 [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.
|
||||
|
||||
If you want to contribute or maintain RGBDS, read [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
If 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`.
|
||||
The documentation website's own source code is available in the
|
||||
[rgbds-www](https://github.com/gbdev/rgbds-www) repository.
|
||||
|
||||
## Installing RGBDS
|
||||
## Community
|
||||
|
||||
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 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`.
|
||||
|
||||
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,4 +60,4 @@ cmake --build build
|
||||
cmake --install build --prefix install_dir
|
||||
```
|
||||
|
||||
(If you set a `SUFFIX`, it should include the `.exe` extension on Windows.)
|
||||
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")
|
||||
@@ -1,6 +0,0 @@
|
||||
-std=c++2a
|
||||
-I
|
||||
include
|
||||
-fno-exceptions
|
||||
-fno-rtti
|
||||
-fno-caret-diagnostics
|
||||
@@ -142,6 +142,7 @@ _rgblink_completions() {
|
||||
mapfile -t COMPREPLY < <(compgen -W "
|
||||
assert
|
||||
div
|
||||
large-constant
|
||||
obsolete
|
||||
shift
|
||||
shift-amount
|
||||
|
||||
+57
-17
@@ -1,17 +1,55 @@
|
||||
#!/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
|
||||
if [[ $# -eq 0 ]]; then
|
||||
./run-tests.sh
|
||||
else
|
||||
./run-tests.sh --os "$1"
|
||||
fi
|
||||
external/fetch-repos.sh
|
||||
./run-tests.sh "${runtests_args[@]}"
|
||||
popd
|
||||
|
||||
# Generate coverage logs
|
||||
@@ -22,14 +60,16 @@ mkdir -p coverage
|
||||
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 -f -s -o coverage/ "$COVERAGE_INFO"
|
||||
genhtml --dark-mode --num-spaces 4 -f -s -o coverage/ "$COVERAGE_INFO"
|
||||
|
||||
# Check whether running from coverage.yml workflow
|
||||
if [ "$1" != "ubuntu-ci" ]; then
|
||||
# Open report in web browser
|
||||
if [ "$(uname)" == "Darwin" ]; then
|
||||
open coverage/index.html
|
||||
else
|
||||
xdg-open coverage/index.html
|
||||
fi
|
||||
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
|
||||
# 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
|
||||
|
||||
@@ -9,6 +9,7 @@ _rgblink_warnings() {
|
||||
|
||||
'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'
|
||||
|
||||
@@ -28,11 +28,15 @@ rgbds/
|
||||
│ │ └── ...
|
||||
│ └── workflows/
|
||||
│ └── ...
|
||||
├── cmake/
|
||||
│ └── ...
|
||||
├── contrib/
|
||||
│ ├── bash_compl/
|
||||
│ ├── zsh_compl/
|
||||
│ │ └── ...
|
||||
│ └── ...
|
||||
├── docs/
|
||||
│ └── ...
|
||||
├── include/
|
||||
│ └── ...
|
||||
├── man/
|
||||
@@ -52,13 +56,15 @@ rgbds/
|
||||
│ ├── bison.sh
|
||||
│ └── ...
|
||||
├── test/
|
||||
│ ├── fetch-test-deps.sh
|
||||
│ ├── run-tests.sh
|
||||
│ ├── external/
|
||||
│ │ ├── fetch-repos.sh
|
||||
│ │ └── ...
|
||||
│ └── ...
|
||||
├── .clang-format
|
||||
├── .clang-tidy
|
||||
├── CMakeLists.txt
|
||||
├── compile_flags.txt
|
||||
├── CMakePresets.json
|
||||
├── Dockerfile
|
||||
└── Makefile
|
||||
```
|
||||
@@ -69,12 +75,20 @@ rgbds/
|
||||
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/`:**
|
||||
@@ -97,18 +111,23 @@ rgbds/
|
||||
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.
|
||||
* **`fetch-test-deps.sh`:**
|
||||
Script used to fetch dependencies for building external repositories. `fetch-test-deps.sh --help` describes its options.
|
||||
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.
|
||||
- **`compile_flags.txt`:**
|
||||
Compiler flags for `clang-tidy`.
|
||||
- **`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`:**
|
||||
@@ -120,6 +139,9 @@ These files in the `src/` directory are shared across multiple programs: often a
|
||||
|
||||
- **`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`:**
|
||||
@@ -162,10 +184,13 @@ These files have been copied ("vendored") from external authors and adapted for
|
||||
- **`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 `expansions`' content. Each `Expansion` (the contents of an `{interpolation}` or macro argument) in turn *owns* its `contents`.
|
||||
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.
|
||||
@@ -183,7 +208,7 @@ These files have been copied ("vendored") from external authors and adapted for
|
||||
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).
|
||||
`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.)
|
||||
@@ -220,6 +245,8 @@ These files have been copied ("vendored") from external authors and adapted for
|
||||
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`:**
|
||||
@@ -256,7 +283,7 @@ These files have been copied ("vendored") from external authors and adapted for
|
||||
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).
|
||||
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).
|
||||
@@ -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
|
||||
@@ -62,20 +65,28 @@ years). If you are adding new files, you need to use the
|
||||
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. Check the results of the GitHub Actions CI jobs for your pull request. The
|
||||
`./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" and "Static analysis" jobs should be manually
|
||||
checked, as they 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.
|
||||
8. Be prepared to get some comments about your code and to modify it. Tip: Use
|
||||
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
|
||||
@@ -131,6 +142,10 @@ linked in various ways depending on the test.
|
||||
|
||||
These simply check that RGBLINK's output matches some expected output.
|
||||
|
||||
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.)
|
||||
|
||||
A `.out` file **must** exist, and RGBLINK's total output must match that file's
|
||||
contents.
|
||||
|
||||
@@ -212,30 +227,21 @@ If a `.flags` file exists, it will be used as part of the RGBGFX invocation
|
||||
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.
|
||||
|
||||
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>
|
||||
```
|
||||
|
||||
(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>
|
||||
```
|
||||
Each `.cfg` file corresponds to one test.
|
||||
Each one defines the parameters for a real external project that builds using RGBDS.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
@@ -254,4 +260,12 @@ manually running:
|
||||
# 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`!
|
||||
@@ -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
|
||||
@@ -13,7 +13,8 @@
|
||||
|
||||
#include "linkdefs.hpp" // AssertionType, RPNCommand
|
||||
|
||||
#include "asm/rpn.hpp" // Expression
|
||||
#include "asm/intern.hpp" // InternedStr
|
||||
#include "asm/rpn.hpp" // Expression
|
||||
|
||||
struct AlignmentSpec {
|
||||
uint8_t alignment;
|
||||
@@ -54,8 +55,8 @@ std::string act_StringFormat(
|
||||
std::string const &spec, std::vector<std::variant<uint32_t, std::string>> const &args
|
||||
);
|
||||
|
||||
std::string act_SectionName(std::string const &symName);
|
||||
std::string act_SectionName(InternedStr symName);
|
||||
|
||||
void act_CompoundAssignment(std::string const &symName, RPNCommand op, int32_t constValue);
|
||||
void act_CompoundAssignment(InternedStr symName, RPNCommand op, int32_t constValue);
|
||||
|
||||
#endif // RGBDS_ASM_ACTIONS_HPP
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
#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();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "linkdefs.hpp"
|
||||
|
||||
#include "asm/intern.hpp"
|
||||
#include "asm/lexer.hpp"
|
||||
|
||||
struct FileStackNode {
|
||||
@@ -63,17 +64,15 @@ MacroArgs *fstk_GetCurrentMacroArgs();
|
||||
void fstk_AddIncludePath(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 *functionName);
|
||||
bool fstk_FileError(std::string const &path, char const *description);
|
||||
bool fstk_FailedOnMissingInclude();
|
||||
|
||||
bool yywrap();
|
||||
bool fstk_RunInclude(std::string const &path, bool isQuiet);
|
||||
void fstk_RunMacro(
|
||||
std::string const ¯oName, std::shared_ptr<MacroArgs> macroArgs, 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,
|
||||
@@ -84,6 +83,6 @@ void fstk_RunFor(
|
||||
bool fstk_Break();
|
||||
|
||||
void fstk_NewRecursionDepth(size_t newDepth);
|
||||
void fstk_Init(std::string const &mainPath);
|
||||
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
|
||||
+10
-50
@@ -9,18 +9,9 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "platform.hpp" // SSIZE_MAX
|
||||
|
||||
// This value is a compromise between `LexerState` allocation performance when reading the entire
|
||||
// file works, and buffering performance when it doesn'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,
|
||||
@@ -32,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`
|
||||
|
||||
@@ -45,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
|
||||
@@ -87,31 +50,28 @@ struct LexerState {
|
||||
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 disableExpansions;
|
||||
size_t expansionScanDistance; // Max distance already scanned for expansions
|
||||
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
|
||||
|
||||
std::variant<std::monostate, 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();
|
||||
void setFileAsNextState(std::string const &filePath, bool updateStateNow);
|
||||
void setViewAsNextState(char const *name, ContentSpan const &span, uint32_t lineNo_);
|
||||
void setViewAsNextState(char const *name, ContentSpan const &content_, uint32_t lineNo_);
|
||||
|
||||
void clear(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);
|
||||
|
||||
@@ -3,10 +3,14 @@
|
||||
#ifndef RGBDS_ASM_MAIN_HPP
|
||||
#define RGBDS_ASM_MAIN_HPP
|
||||
|
||||
#include <optional>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
#include "helpers.hpp" // assume
|
||||
#include "util.hpp" // xfclose
|
||||
|
||||
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
|
||||
@@ -20,22 +24,23 @@ struct Options {
|
||||
char binDigits[2] = {'0', '1'}; // -b
|
||||
char gfxDigits[4] = {'0', '1', '2', '3'}; // -g
|
||||
FILE *dependFile = nullptr; // -M
|
||||
std::string targetFileName; // -MQ, -MT
|
||||
std::optional<std::string> targetFileName{}; // -MQ, -MT
|
||||
MissingInclude missingIncludeState = INC_ERROR; // -MC, -MG
|
||||
bool generatePhonyDeps = false; // -MP
|
||||
std::string objectFileName; // -o
|
||||
std::optional<std::string> objectFileName{}; // -o
|
||||
uint8_t padByte = 0; // -p
|
||||
uint64_t maxErrors = 0; // -X
|
||||
|
||||
~Options() {
|
||||
if (dependFile) {
|
||||
fclose(dependFile);
|
||||
xfclose(dependFile);
|
||||
}
|
||||
}
|
||||
|
||||
void printDep(std::string const &depName) {
|
||||
if (dependFile) {
|
||||
fprintf(dependFile, "%s: %s\n", targetFileName.c_str(), depName.c_str());
|
||||
assume(targetFileName.has_value());
|
||||
fprintf(dependFile, "%s: %s\n", targetFileName->c_str(), depName.c_str());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+6
-4
@@ -10,16 +10,18 @@
|
||||
|
||||
#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, std::string> data; // Data after the ID, if any
|
||||
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, std::string const &name);
|
||||
RPNValue(RPNCommand cmd, InternedStr name);
|
||||
|
||||
void appendEncoded(std::vector<uint8_t> &buffer) const;
|
||||
};
|
||||
@@ -40,8 +42,8 @@ struct Expression {
|
||||
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);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "intern.hpp"
|
||||
#include "linkdefs.hpp"
|
||||
|
||||
struct Expression;
|
||||
@@ -107,6 +108,6 @@ void sect_PushSection();
|
||||
void sect_PopSection();
|
||||
void sect_CheckStack();
|
||||
|
||||
std::string sect_PushSectionFragmentLiteral();
|
||||
InternedStr sect_PushSectionFragmentLiteral();
|
||||
|
||||
#endif // RGBDS_ASM_SECTION_HPP
|
||||
|
||||
+21
-20
@@ -10,6 +10,7 @@
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
#include "asm/intern.hpp"
|
||||
#include "asm/lexer.hpp"
|
||||
#include "asm/section.hpp"
|
||||
|
||||
@@ -26,7 +27,7 @@ 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 isBuiltin;
|
||||
bool isExported; // Not relevant for SYM_MACRO or SYM_EQUS
|
||||
@@ -68,34 +69,34 @@ struct Symbol {
|
||||
uint32_t getConstantValue() const;
|
||||
};
|
||||
|
||||
bool sym_IsDotScope(InternedStr symName);
|
||||
|
||||
void sym_ForEach(void (*callback)(Symbol &));
|
||||
|
||||
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, bool isQuiet
|
||||
);
|
||||
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.
|
||||
|
||||
@@ -61,13 +61,17 @@ extern Diagnostics<WarningLevel, WarningID> warnings;
|
||||
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 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
|
||||
// get a list of all errors at the end, making it easier to fix all of them at
|
||||
|
||||
+14
-5
@@ -9,8 +9,13 @@
|
||||
#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;
|
||||
@@ -21,20 +26,24 @@ extern Tracing tracing;
|
||||
|
||||
bool trace_ParseTraceDepth(char const *arg);
|
||||
|
||||
template<typename T, typename M, typename N>
|
||||
void trace_PrintBacktrace(std::vector<T> const &stack, M getName, N getLineNo) {
|
||||
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) {
|
||||
T const &item = stack[n - i - 1];
|
||||
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" : "<-");
|
||||
fprintf(stderr, " %s ", i == 0 ? "at" : TRACE_SEPARATOR);
|
||||
style_Set(stderr, STYLE_CYAN, true);
|
||||
fputs(getName(item), stderr);
|
||||
style_Set(stderr, STYLE_CYAN, false);
|
||||
@@ -62,7 +71,7 @@ void trace_PrintBacktrace(std::vector<T> const &stack, M getName, N getLineNo) {
|
||||
style_Reset(stderr);
|
||||
|
||||
if (tracing.collapse) {
|
||||
fputs(" <-", stderr);
|
||||
fputs(" " TRACE_SEPARATOR, stderr);
|
||||
} else {
|
||||
fputs(" ", stderr); // Just three spaces; the fourth will be printed next
|
||||
}
|
||||
|
||||
@@ -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
|
||||
+74
-24
@@ -15,9 +15,20 @@
|
||||
|
||||
#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 };
|
||||
|
||||
@@ -30,35 +41,35 @@ struct WarningState {
|
||||
|
||||
std::pair<WarningState, std::optional<uint32_t>> getInitialWarningState(std::string &flag);
|
||||
|
||||
template<typename L>
|
||||
template<Enum LevelEnumT>
|
||||
struct WarningFlag {
|
||||
char const *name;
|
||||
L level;
|
||||
LevelEnumT level;
|
||||
};
|
||||
|
||||
enum WarningBehavior { DISABLED, ENABLED, ERROR };
|
||||
|
||||
template<typename W>
|
||||
template<Enum WarningEnumT>
|
||||
struct ParamWarning {
|
||||
W firstID;
|
||||
W lastID;
|
||||
WarningEnumT firstID;
|
||||
WarningEnumT lastID;
|
||||
uint8_t defaultLevel;
|
||||
};
|
||||
|
||||
template<typename W>
|
||||
template<Enum WarningEnumT>
|
||||
struct DiagnosticsState {
|
||||
WarningState flagStates[W::NB_WARNINGS];
|
||||
WarningState metaStates[W::NB_WARNINGS];
|
||||
WarningState flagStates[WarningEnumT::NB_WARNINGS];
|
||||
WarningState metaStates[WarningEnumT::NB_WARNINGS];
|
||||
bool warningsEnabled = true;
|
||||
bool warningsAreErrors = false;
|
||||
};
|
||||
|
||||
template<typename L, typename W>
|
||||
template<Enum LevelEnumT, Enum WarningEnumT>
|
||||
struct Diagnostics {
|
||||
std::vector<WarningFlag<L>> metaWarnings;
|
||||
std::vector<WarningFlag<L>> warningFlags;
|
||||
std::vector<ParamWarning<W>> paramWarnings;
|
||||
DiagnosticsState<W> state;
|
||||
std::vector<WarningFlag<LevelEnumT>> metaWarnings;
|
||||
std::vector<WarningFlag<LevelEnumT>> warningFlags;
|
||||
std::vector<ParamWarning<WarningEnumT>> paramWarnings;
|
||||
DiagnosticsState<WarningEnumT> state;
|
||||
uint64_t nbErrors;
|
||||
|
||||
void incrementErrors() {
|
||||
@@ -67,12 +78,12 @@ struct Diagnostics {
|
||||
}
|
||||
}
|
||||
|
||||
WarningBehavior getWarningBehavior(W id) const;
|
||||
WarningBehavior getWarningBehavior(WarningEnumT id) const;
|
||||
void processWarningFlag(char const *flag);
|
||||
};
|
||||
|
||||
template<typename L, typename W>
|
||||
WarningBehavior Diagnostics<L, W>::getWarningBehavior(W id) const {
|
||||
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;
|
||||
@@ -112,7 +123,7 @@ WarningBehavior Diagnostics<L, W>::getWarningBehavior(W id) const {
|
||||
}
|
||||
|
||||
// If no meta flag is specified, check the default state of this warning flag
|
||||
if (warningFlags[id].level == L::LEVEL_DEFAULT) { // enabled by default
|
||||
if (warningFlags[id].level == LevelEnumT::LEVEL_DEFAULT) { // enabled by default
|
||||
return enabledBehavior;
|
||||
}
|
||||
|
||||
@@ -120,8 +131,8 @@ WarningBehavior Diagnostics<L, W>::getWarningBehavior(W id) const {
|
||||
return WarningBehavior::DISABLED;
|
||||
}
|
||||
|
||||
template<typename L, typename W>
|
||||
void Diagnostics<L, W>::processWarningFlag(char const *flag) {
|
||||
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
|
||||
@@ -140,8 +151,8 @@ void Diagnostics<L, W>::processWarningFlag(char const *flag) {
|
||||
// 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<W> const ¶mWarning : paramWarnings) {
|
||||
W baseID = paramWarning.firstID;
|
||||
for (ParamWarning<WarningEnumT> const ¶mWarning : paramWarnings) {
|
||||
WarningEnumT baseID = paramWarning.firstID;
|
||||
uint8_t maxParam = paramWarning.lastID - baseID + 1;
|
||||
assume(paramWarning.defaultLevel <= maxParam);
|
||||
|
||||
@@ -183,13 +194,13 @@ void Diagnostics<L, W>::processWarningFlag(char const *flag) {
|
||||
}
|
||||
|
||||
// Try to match against a "meta" warning
|
||||
for (WarningFlag<L> const &metaWarning : metaWarnings) {
|
||||
for (WarningFlag<LevelEnumT> const &metaWarning : metaWarnings) {
|
||||
if (rootFlag != metaWarning.name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set each of the warning flags that meets this level
|
||||
for (W id : EnumSeq(W::NB_WARNINGS)) {
|
||||
for (WarningEnumT id : EnumSeq(WarningEnumT::NB_WARNINGS)) {
|
||||
if (metaWarning.level >= warningFlags[id].level) {
|
||||
state.metaStates[id].update(flagState);
|
||||
}
|
||||
@@ -198,7 +209,7 @@ void Diagnostics<L, W>::processWarningFlag(char const *flag) {
|
||||
}
|
||||
|
||||
// Try to match against a "normal" flag
|
||||
for (W id : EnumSeq(W::NB_PLAIN_WARNINGS)) {
|
||||
for (WarningEnumT id : EnumSeq(WarningEnumT::NB_PLAIN_WARNINGS)) {
|
||||
if (rootFlag == warningFlags[id].name) {
|
||||
state.flagStates[id].update(flagState);
|
||||
return;
|
||||
@@ -208,4 +219,43 @@ void Diagnostics<L, W>::processWarningFlag(char const *flag) {
|
||||
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
|
||||
|
||||
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
+6
-1
@@ -8,6 +8,11 @@
|
||||
#define UTF8_ACCEPT 0
|
||||
#define UTF8_REJECT 12
|
||||
|
||||
uint32_t decode(uint32_t *state, uint32_t *codep, uint8_t byte);
|
||||
struct Utf8Decoder {
|
||||
uint32_t state = UTF8_ACCEPT;
|
||||
uint32_t codepoint = 0;
|
||||
|
||||
uint32_t update(uint8_t byte);
|
||||
};
|
||||
|
||||
#endif // RGBDS_EXTERN_UTF8DECODER_HPP
|
||||
|
||||
+3
-8
@@ -34,6 +34,9 @@ public:
|
||||
} 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;
|
||||
}
|
||||
@@ -41,15 +44,7 @@ public:
|
||||
return std::holds_alternative<std::filebuf>(_file) ? std::get<std::filebuf>(_file)
|
||||
: *std::get<std::streambuf *>(_file);
|
||||
}
|
||||
std::streambuf const &operator*() const {
|
||||
// The non-`const` version does not perform any modifications, so it's okay.
|
||||
return **const_cast<File *>(this);
|
||||
}
|
||||
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 std::holds_alternative<std::filebuf>(_file) ? path.c_str()
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
#ifndef RGBDS_FIX_MAIN_HPP
|
||||
#define RGBDS_FIX_MAIN_HPP
|
||||
|
||||
#include <optional>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
#include "fix/mbc.hpp" // UNSPECIFIED, MbcType
|
||||
|
||||
@@ -28,19 +30,19 @@ struct Options {
|
||||
uint16_t ramSize = UNSPECIFIED; // -r
|
||||
bool sgb = false; // -s
|
||||
|
||||
char const *gameID = nullptr; // -i
|
||||
std::optional<std::string> gameID; // -i
|
||||
uint8_t gameIDLen;
|
||||
|
||||
char const *newLicensee = nullptr; // -k
|
||||
std::optional<std::string> newLicensee; // -k
|
||||
uint8_t newLicenseeLen;
|
||||
|
||||
char const *logoFilename = nullptr; // -L
|
||||
std::optional<std::string> logoFilename; // -L
|
||||
uint8_t logo[48] = {};
|
||||
|
||||
MbcType cartridgeType = MBC_NONE; // -m
|
||||
uint8_t tpp1Rev[2];
|
||||
|
||||
char const *title = nullptr; // -t
|
||||
std::optional<std::string> title; // -t
|
||||
uint8_t titleLen;
|
||||
};
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ 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,11 +21,7 @@ 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,
|
||||
};
|
||||
enum ComparisonResult { INCOMPARABLE, SUBSET_OR_EQUAL, STRICT_SUPERSET };
|
||||
ComparisonResult compare(ColorSet const &other) const;
|
||||
|
||||
size_t size() const;
|
||||
|
||||
@@ -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
|
||||
+1
-33
@@ -5,12 +5,11 @@
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "helpers.hpp"
|
||||
#include "helpers.hpp" // assume
|
||||
|
||||
#include "gfx/rgba.hpp"
|
||||
|
||||
@@ -69,35 +68,4 @@ struct Options {
|
||||
|
||||
extern Options options;
|
||||
|
||||
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 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_MAIN_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
|
||||
+2
-1
@@ -10,7 +10,8 @@
|
||||
#include "gfx/rgba.hpp"
|
||||
|
||||
struct Png {
|
||||
uint32_t width, height;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
std::vector<Rgba> pixels{};
|
||||
std::vector<Rgba> palette{};
|
||||
|
||||
|
||||
+29
-8
@@ -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,18 +20,25 @@ struct Rgba {
|
||||
explicit constexpr Rgba(uint32_t rgba = 0)
|
||||
: red(rgba >> 24), green(rgba >> 16), blue(rgba >> 8), alpha(rgba) {}
|
||||
|
||||
// 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 c) -> uint8_t { return ((c & 0b11111) * 255 + 15) / 31; };
|
||||
constexpr auto _5to8 = [](uint8_t channel) -> uint8_t {
|
||||
channel &= 0b11111; // For caller's convenience
|
||||
return channel << 3 | channel >> 2;
|
||||
};
|
||||
return {
|
||||
_5to8(color),
|
||||
_5to8(color >> 5),
|
||||
_5to8(color >> 10),
|
||||
static_cast<uint8_t>(color & 0x8000 ? 0x00 : 0xFF),
|
||||
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 {
|
||||
constexpr auto shl = [](uint8_t val, unsigned shift) {
|
||||
return static_cast<uint32_t>(val) << shift;
|
||||
@@ -38,10 +48,6 @@ struct Rgba {
|
||||
|
||||
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;
|
||||
@@ -53,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
|
||||
|
||||
+43
-22
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -99,17 +99,38 @@ static inline int clz(unsigned int x) {
|
||||
#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(); }
|
||||
};
|
||||
|
||||
|
||||
+71
-33
@@ -12,86 +12,118 @@
|
||||
#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<T> list;
|
||||
std::unordered_map<std::string, size_t> map; // Indexes into `list`
|
||||
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(std::string const &name) const { return map.find(name) != map.end(); }
|
||||
bool contains(KeyT const &key) const { return map.find(key) != map.end(); }
|
||||
|
||||
T &operator[](size_t i) { return list[i]; }
|
||||
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(); }
|
||||
|
||||
T &add(std::string const &name) {
|
||||
map[name] = list.size();
|
||||
// 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();
|
||||
}
|
||||
|
||||
T &add(std::string const &name, T &&value) {
|
||||
map[name] = list.size();
|
||||
ItemT &add(KeyT const &key, ItemT &&value) {
|
||||
assume(!contains(key));
|
||||
map[key] = list.size();
|
||||
list.emplace_back(std::move(value));
|
||||
return list.back();
|
||||
}
|
||||
|
||||
T &addAnonymous() {
|
||||
ItemT &addAnonymous() {
|
||||
// Add the new item to the list, but do not update the map
|
||||
return list.emplace_back();
|
||||
}
|
||||
|
||||
std::optional<size_t> findIndex(std::string const &name) const {
|
||||
if (auto search = map.find(name); search != map.end()) {
|
||||
std::optional<size_t> findIndex(KeyT const &key) const {
|
||||
if (auto search = map.find(key); search != map.end()) {
|
||||
return search->second;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
// 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;
|
||||
}
|
||||
|
||||
T 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);
|
||||
@@ -109,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(
|
||||
@@ -137,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
|
||||
|
||||
@@ -10,6 +10,6 @@ void lexer_TraceCurrent();
|
||||
void lexer_IncludeFile(std::string &&path);
|
||||
void lexer_IncLineNo();
|
||||
|
||||
bool lexer_Init(char const *linkerScriptName);
|
||||
bool lexer_Init(std::string const &linkerScriptName);
|
||||
|
||||
#endif // RGBDS_LINK_LEXER_HPP
|
||||
|
||||
@@ -3,16 +3,18 @@
|
||||
#ifndef RGBDS_LINK_MAIN_HPP
|
||||
#define RGBDS_LINK_MAIN_HPP
|
||||
|
||||
#include <optional>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
struct Options {
|
||||
bool isDmgMode; // -d
|
||||
char const *mapFileName; // -m
|
||||
bool noSymInMap; // -M
|
||||
char const *symFileName; // -n
|
||||
char const *overlayFileName; // -O
|
||||
char const *outputFileName; // -o
|
||||
uint8_t padValue; // -p
|
||||
bool isDmgMode; // -d
|
||||
std::optional<std::string> mapFileName; // -m
|
||||
bool noSymInMap; // -M
|
||||
std::optional<std::string> symFileName; // -n
|
||||
std::optional<std::string> overlayFileName; // -O
|
||||
std::optional<std::string> outputFileName; // -o
|
||||
uint8_t padValue; // -p
|
||||
bool hasPadValue = false;
|
||||
// Setting these three to 0 disables the functionality
|
||||
uint16_t scrambleROMX; // -S
|
||||
|
||||
@@ -3,10 +3,13 @@
|
||||
#ifndef RGBDS_LINK_OBJECT_HPP
|
||||
#define RGBDS_LINK_OBJECT_HPP
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string>
|
||||
|
||||
// Read an object (.o) file, and add its info to the data structures.
|
||||
void obj_ReadFile(char const *fileName, unsigned int fileID);
|
||||
void obj_ReadFile(std::string const &filePath, size_t fileID);
|
||||
|
||||
// Sets up object file reading
|
||||
void obj_Setup(unsigned int nbFiles);
|
||||
void obj_Setup(size_t nbFiles);
|
||||
|
||||
#endif // RGBDS_LINK_OBJECT_HPP
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "helpers.hpp" // QualifiedEquivalent
|
||||
#include "linkdefs.hpp"
|
||||
|
||||
struct FileStackNode;
|
||||
@@ -49,6 +50,39 @@ struct Section {
|
||||
std::vector<Symbol> *fileSymbols;
|
||||
std::vector<Symbol *> symbols;
|
||||
std::unique_ptr<Section> nextPiece; // The next fragment or union "piece" of this section
|
||||
|
||||
private:
|
||||
// Template class for both const and non-const iterators over the "pieces" of this section
|
||||
template<QualifiedEquivalent<Section> SectionT>
|
||||
class PiecesIterable {
|
||||
SectionT *_firstPiece;
|
||||
|
||||
class Iterator {
|
||||
SectionT *_piece;
|
||||
|
||||
public:
|
||||
explicit Iterator(SectionT *piece) : _piece(piece) {}
|
||||
|
||||
Iterator &operator++() {
|
||||
_piece = _piece->nextPiece.get();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SectionT &operator*() const { return *_piece; }
|
||||
|
||||
bool operator==(Iterator const &rhs) const { return _piece == rhs._piece; }
|
||||
};
|
||||
|
||||
public:
|
||||
explicit PiecesIterable(SectionT *firstPiece) : _firstPiece(firstPiece) {}
|
||||
|
||||
Iterator begin() { return Iterator(_firstPiece); }
|
||||
Iterator end() { return Iterator(nullptr); }
|
||||
};
|
||||
|
||||
public:
|
||||
PiecesIterable<Section> pieces() { return PiecesIterable(this); }
|
||||
PiecesIterable<Section const> pieces() const { return PiecesIterable(this); }
|
||||
};
|
||||
|
||||
// Execute a callback for each section currently registered.
|
||||
|
||||
@@ -22,11 +22,12 @@ enum WarningLevel {
|
||||
};
|
||||
|
||||
enum WarningID {
|
||||
WARNING_ASSERT, // Assertions
|
||||
WARNING_DIV, // Undefined division behavior
|
||||
WARNING_OBSOLETE, // Obsolete/deprecated things
|
||||
WARNING_SHIFT, // Undefined `SHIFT` behavior
|
||||
WARNING_SHIFT_AMOUNT, // Strange `SHIFT` amount
|
||||
WARNING_ASSERT, // Assertions
|
||||
WARNING_DIV, // Undefined division behavior
|
||||
WARNING_LARGE_CONSTANT, // Constants too large
|
||||
WARNING_OBSOLETE, // Obsolete/deprecated things
|
||||
WARNING_SHIFT, // Undefined `SHIFT` behavior
|
||||
WARNING_SHIFT_AMOUNT, // Strange `SHIFT` amount
|
||||
|
||||
NB_PLAIN_WARNINGS,
|
||||
|
||||
@@ -47,6 +48,8 @@ void warning(FileStackNode const *src, uint32_t lineNo, WarningID id, char const
|
||||
void warning(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...);
|
||||
[[gnu::format(printf, 1, 2)]]
|
||||
void warning(char const *fmt, ...);
|
||||
[[gnu::format(printf, 2, 3)]]
|
||||
void scriptWarning(WarningID id, char const *fmt, ...);
|
||||
|
||||
[[gnu::format(printf, 3, 4)]]
|
||||
void error(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...);
|
||||
|
||||
@@ -120,7 +120,7 @@ enum SectionModifier { SECTION_NORMAL, SECTION_UNION, SECTION_FRAGMENT };
|
||||
|
||||
extern char const * const sectionModNames[];
|
||||
|
||||
enum ExportLevel { SYMTYPE_LOCAL, SYMTYPE_IMPORT, SYMTYPE_EXPORT };
|
||||
enum ExportLevel { SYMTYPE_LOCAL, SYMTYPE_IMPORT, SYMTYPE_EXPORT, SYMTYPE_INVALID };
|
||||
|
||||
enum PatchType {
|
||||
PATCHTYPE_BYTE,
|
||||
|
||||
@@ -55,8 +55,14 @@
|
||||
#define setmode(fd, mode) (0)
|
||||
#endif
|
||||
|
||||
// MingGW and Cygwin need POSIX functions which are not standard C explicitly enabled,
|
||||
#if defined(__MINGW32__) || defined(__CYGWIN__)
|
||||
// Windows has 32-bit `long`, which limits `fseek` and `ftell` to 2 GiB
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#define fseek _fseeki64
|
||||
#define ftell _ftelli64
|
||||
#endif
|
||||
|
||||
// MingGW and Cygwin may need POSIX functions which are not standard C explicitly enabled
|
||||
#if (defined(__MINGW32__) || defined(__CYGWIN__)) && !defined(_POSIX_C_SOURCE)
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#endif
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ struct Usage {
|
||||
std::vector<std::string> flags;
|
||||
std::vector<std::pair<std::vector<std::string>, std::vector<std::string>>> options;
|
||||
|
||||
void printVersion(bool error) const;
|
||||
|
||||
[[noreturn]]
|
||||
void printAndExit(int code) const;
|
||||
|
||||
|
||||
+56
-14
@@ -4,12 +4,12 @@
|
||||
#define RGBDS_UTIL_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <ctype.h> // toupper
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "helpers.hpp"
|
||||
@@ -22,6 +22,14 @@ enum NumberBase {
|
||||
BASE_16 = 16,
|
||||
};
|
||||
|
||||
// File-closing functions that will not close standard streams
|
||||
int xfclose(FILE *file);
|
||||
int xclose(int fd);
|
||||
|
||||
// Measure file size with `fseek` and `ftell` idiom
|
||||
std::optional<uint64_t> seekSize(FILE *file);
|
||||
|
||||
// Locale-independent character class functions
|
||||
bool isNewline(int c);
|
||||
bool isBlankSpace(int c);
|
||||
bool isWhitespace(int c);
|
||||
@@ -29,38 +37,72 @@ bool isPrintable(int c);
|
||||
bool isUpper(int c);
|
||||
bool isLower(int c);
|
||||
bool isLetter(int c);
|
||||
bool isDigit(int c);
|
||||
bool isBinDigit(int c);
|
||||
bool isOctDigit(int c);
|
||||
bool isHexDigit(int c);
|
||||
bool isAlphanumeric(int c);
|
||||
|
||||
// Locale-independent character transform functions
|
||||
char toLower(char c);
|
||||
char toUpper(char c);
|
||||
|
||||
bool startsIdentifier(int c);
|
||||
bool continuesIdentifier(int c);
|
||||
|
||||
uint8_t parseHexDigit(int c);
|
||||
template<uint32_t Base>
|
||||
inline constexpr bool ValidBaseV = Base > 0 && Base <= 36;
|
||||
|
||||
template<uint32_t Base>
|
||||
requires ValidBaseV<Base>
|
||||
bool isDigit(int c) {
|
||||
if constexpr (Base <= 10) {
|
||||
return c >= '0' && c < static_cast<int>('0' + Base);
|
||||
} else {
|
||||
return isDigit<10>(c) || (c >= 'A' && c < static_cast<int>('A' + Base - 10))
|
||||
|| (c >= 'a' && c < static_cast<int>('a' + Base - 10));
|
||||
}
|
||||
}
|
||||
|
||||
template<uint32_t Base>
|
||||
requires ValidBaseV<Base>
|
||||
uint8_t parseDigit(int c) {
|
||||
assume(isDigit<Base>(c));
|
||||
if constexpr (Base <= 10) {
|
||||
return c - '0';
|
||||
} else {
|
||||
// Check digit ranges from greatest to least ('a'-'z', then 'A'-'Z', then '0'-'9')
|
||||
if (c >= 'a') {
|
||||
return c - 'a' + 10;
|
||||
} else if (c >= 'A') {
|
||||
return c - 'A' + 10;
|
||||
} else {
|
||||
return parseDigit<10>(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<uint64_t> parseNumber(char const *&str, NumberBase base = BASE_AUTO);
|
||||
std::optional<uint64_t> parseWholeNumber(char const *str, NumberBase base = BASE_AUTO);
|
||||
|
||||
char const *printChar(int c);
|
||||
|
||||
struct Uppercase {
|
||||
using is_transparent = void;
|
||||
|
||||
// FNV-1a hash of an uppercased string
|
||||
constexpr size_t operator()(std::string const &str) const {
|
||||
return std::accumulate(RANGE(str), 0x811C9DC5, [](size_t hash, char c) {
|
||||
return (hash ^ toupper(c)) * 16777619;
|
||||
constexpr size_t operator()(std::string_view str) const {
|
||||
return std::accumulate(RANGE(str), size_t(0x811C9DC5), [](size_t hash, char c) {
|
||||
return (hash ^ toUpper(c)) * 16777619;
|
||||
});
|
||||
}
|
||||
|
||||
// Compare two strings without case-sensitivity (by converting to uppercase)
|
||||
constexpr bool operator()(std::string const &str1, std::string const &str2) const {
|
||||
constexpr bool operator()(std::string_view str1, std::string_view str2) const {
|
||||
return std::equal(RANGE(str1), RANGE(str2), [](char c1, char c2) {
|
||||
return toupper(c1) == toupper(c2);
|
||||
return toUpper(c1) == toUpper(c2);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using UpperMap = std::unordered_map<std::string, T, Uppercase, Uppercase>;
|
||||
// An unordered map from case-insensitive `std::string_view` keys to `ItemT` items
|
||||
template<typename ItemT>
|
||||
using UpperMap = std::unordered_map<std::string_view, ItemT, Uppercase, Uppercase>;
|
||||
|
||||
#endif // RGBDS_UTIL_HPP
|
||||
|
||||
+14
-3
@@ -3,17 +3,17 @@
|
||||
#ifndef RGBDS_VERBOSITY_HPP
|
||||
#define RGBDS_VERBOSITY_HPP
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "helpers.hpp" // Procedure
|
||||
#include "style.hpp"
|
||||
|
||||
// This macro does not evaluate its arguments unless the condition is true.
|
||||
#define verbosePrint(level, ...) \
|
||||
do { \
|
||||
if (checkVerbosity(level)) { \
|
||||
style_Set(stderr, STYLE_MAGENTA, false); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
style_Reset(stderr); \
|
||||
printVerbosely(__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
@@ -30,6 +30,17 @@ enum Verbosity {
|
||||
void incrementVerbosity();
|
||||
bool checkVerbosity(Verbosity level);
|
||||
|
||||
[[gnu::format(printf, 1, 2)]]
|
||||
void printVerbosely(char const *fmt, ...);
|
||||
|
||||
void verboseDo(Verbosity level, Procedure<> auto callback) {
|
||||
if (checkVerbosity(level)) {
|
||||
style_Set(stderr, STYLE_MAGENTA, false);
|
||||
callback();
|
||||
style_Reset(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void printVVVVVVerbosity();
|
||||
|
||||
#endif // RGBDS_VERBOSITY_HPP
|
||||
|
||||
+2
-2
@@ -5,8 +5,8 @@
|
||||
|
||||
#define PACKAGE_VERSION_MAJOR 1
|
||||
#define PACKAGE_VERSION_MINOR 0
|
||||
#define PACKAGE_VERSION_PATCH 0
|
||||
#define PACKAGE_VERSION_RC 2
|
||||
#define PACKAGE_VERSION_PATCH 3
|
||||
// #define PACKAGE_VERSION_RC 1
|
||||
|
||||
char const *get_package_version_string();
|
||||
|
||||
|
||||
+42
-9
@@ -1,6 +1,6 @@
|
||||
.\" SPDX-License-Identifier: MIT
|
||||
.\"
|
||||
.Dd September 30, 2025
|
||||
.Dd August 1, 2026
|
||||
.Dt GBZ80 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -11,6 +11,11 @@ This is the list of instructions supported by
|
||||
.Xr rgbasm 1 ,
|
||||
including a short description, the number of bytes needed to encode them and the number of CPU cycles at 1MHz (or 2MHz in GBC double speed mode) needed to complete them.
|
||||
.Pp
|
||||
Instructons are documented according to the syntax accepted by
|
||||
.Xr rgbasm 1 ,
|
||||
which does not always match one-to-one with the way instructions are
|
||||
.Lk https://gbdev.io/gb-opcodes/optables/ encoded .
|
||||
.Pp
|
||||
Note: All arithmetic and logic instructions that use register
|
||||
.Sy A
|
||||
as a destination can omit the destination, since it is assumed to be register
|
||||
@@ -861,11 +866,13 @@ Flags: None affected.
|
||||
Relative Jump to address
|
||||
.Ar n16 .
|
||||
.Pp
|
||||
The address is encoded as a signed 8-bit offset from the address immediately following the
|
||||
.Ic JR
|
||||
instruction, so the target address
|
||||
The target address
|
||||
.Ar n16
|
||||
must be between
|
||||
is
|
||||
.Em encoded
|
||||
as a signed 8-bit offset from the address immediately following the
|
||||
.Ic JR
|
||||
instruction, so it must be between
|
||||
.Sy -128
|
||||
and
|
||||
.Sy 127
|
||||
@@ -889,6 +896,18 @@ if condition
|
||||
.Ar cc
|
||||
is met.
|
||||
.Pp
|
||||
The target address
|
||||
.Ar n16
|
||||
is
|
||||
.Em encoded
|
||||
as a signed 8-bit offset from the address immediately following the
|
||||
.Ic JR
|
||||
instruction, so it must be between
|
||||
.Sy -128
|
||||
and
|
||||
.Sy 127
|
||||
bytes away.
|
||||
.Pp
|
||||
Cycles: 3 taken / 2 untaken
|
||||
.Pp
|
||||
Bytes: 2
|
||||
@@ -992,8 +1011,15 @@ Flags: None affected.
|
||||
Copy the value in register
|
||||
.Sy A
|
||||
into the byte at address
|
||||
.Ar n16 ,
|
||||
provided the address is between
|
||||
.Ar n16 .
|
||||
.Pp
|
||||
The destination address
|
||||
.Ar n16
|
||||
is
|
||||
.Em encoded
|
||||
as its 8-bit low byte and assumes a high byte of
|
||||
.Ad $FF ,
|
||||
so it must be between
|
||||
.Ad $FF00
|
||||
and
|
||||
.Ad $FFFF .
|
||||
@@ -1043,8 +1069,15 @@ Flags: None affected.
|
||||
Copy the byte at address
|
||||
.Ar n16
|
||||
into register
|
||||
.Sy A ,
|
||||
provided the address is between
|
||||
.Sy A .
|
||||
.Pp
|
||||
The source address
|
||||
.Ar n16
|
||||
is
|
||||
.Em encoded
|
||||
as its 8-bit low byte and assumes a high byte of
|
||||
.Ad $FF ,
|
||||
so it must be between
|
||||
.Ad $FF00
|
||||
and
|
||||
.Ad $FFFF .
|
||||
|
||||
+45
-20
@@ -2,7 +2,7 @@
|
||||
.\"
|
||||
.\" SPDX-License-Identifier: MIT
|
||||
.\"
|
||||
.Dd September 30, 2025
|
||||
.Dd August 1, 2026
|
||||
.Dt RGBASM-OLD 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -140,12 +140,55 @@ Deprecated in 0.9.0, removed in 1.0.0.
|
||||
Instead, use a multi-value
|
||||
.Ic CHARMAP ,
|
||||
or explicitly combine the values of individual characters.
|
||||
.Pp
|
||||
For example, instead of a multi-character string like:
|
||||
.Bd -literal -offset indent
|
||||
CHARMAP "X", $12
|
||||
CHARMAP "Y", $34
|
||||
LD BC, "XY"
|
||||
.Ed
|
||||
.Pp
|
||||
Either use a multi-value
|
||||
.Ic CHARMAP :
|
||||
.Bd -literal -offset indent
|
||||
CHARMAP "X", $12
|
||||
CHARMAP "Y", $34
|
||||
CHARMAP "<XY>", 'X', 'Y'
|
||||
LD BC, CHARVAL("<XY>", 0) << 8 | CHARVAL("<XY>", 1)
|
||||
.Ed
|
||||
.Pp
|
||||
Or combine the individual characters:
|
||||
.Bd -literal -offset indent
|
||||
CHARMAP "X", $12
|
||||
CHARMAP "Y", $34
|
||||
LD BC, 'X' << 8 | 'Y'
|
||||
.Ed
|
||||
.Pp
|
||||
Or use a single-value character:
|
||||
.Bd -literal -offset indent
|
||||
CHARMAP "X", $12
|
||||
CHARMAP "Y", $34
|
||||
CHARMAP "<XY>", 'X' << 8 | 'Y'
|
||||
LD BC, '<XY>'
|
||||
.Ed
|
||||
.Ss Treating strings as numbers
|
||||
Deprecated in 1.0.0.
|
||||
.Pp
|
||||
Instead, use character constants or the
|
||||
.Ic CHARVAL
|
||||
function.
|
||||
.Pp
|
||||
For example, instead of a string literal like
|
||||
.Ql LD A, \&"R" ,
|
||||
use a numeric character literal
|
||||
.Ql LD A, 'R' .
|
||||
.Pp
|
||||
And instead of a string expression like
|
||||
.Ql CP STRUPR("\e1") ,
|
||||
use a numeric
|
||||
.Ic CHARVAL
|
||||
expression
|
||||
.Ql CP CHARVAL(STRUPR("\e1")) .
|
||||
.Ss rgbgfx -f/--fix and -F/--fix-and-save
|
||||
Removed in 0.6.0.
|
||||
.Pp
|
||||
@@ -370,7 +413,7 @@ or
|
||||
Deprecated in 1.0.0.
|
||||
.Pp
|
||||
Instead, use
|
||||
.Dl -Wno-overwrite .
|
||||
.Ql -Wno-overwrite .
|
||||
.Ss rgbgfx -h/--horizontal
|
||||
Removed in 0.6.0.
|
||||
.Pp
|
||||
@@ -461,24 +504,6 @@ Previously we had
|
||||
.Pp
|
||||
Instead, now we have
|
||||
.Ql p ** q ** r == p ** (q ** r) .
|
||||
.Ss 8-bit and 5-bit color conversion
|
||||
Changed in 1.0.0.
|
||||
.Pp
|
||||
RGBGFX takes 8-bit RGB colors as its PNG input, and outputs 5-bit GBC colors.
|
||||
Its
|
||||
.Ql -r/--reverse
|
||||
mode does the opposite 5-bit to 8-bit conversion.
|
||||
Instead of the previous inaccurate conversions, we now do accurate rounding to the nearest equivalent.
|
||||
.Pp
|
||||
Previously to convert an 8-bit color channel to 5-bit, we truncated it as
|
||||
.Ql c >> 3 ;
|
||||
and to reverse a 5-bit color channel to 8-bit, we extended it as
|
||||
.Ql (c << 3) | (c >> 2) .
|
||||
.Pp
|
||||
Instead, now we round 8-bit to 5-bit as
|
||||
.Ql (c * 31 + 127) / 255 ,
|
||||
and round 5-bit to 8-bit as
|
||||
.Ql (c * 255 + 15) / 31 .
|
||||
.Sh BUGS
|
||||
These are misfeatures that may have been possible by mistake.
|
||||
They do not get deprecated, just fixed.
|
||||
|
||||
+81
-16
@@ -1,6 +1,6 @@
|
||||
.\" SPDX-License-Identifier: MIT
|
||||
.\"
|
||||
.Dd September 30, 2025
|
||||
.Dd August 1, 2026
|
||||
.Dt RGBASM 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -36,14 +36,14 @@ The
|
||||
program creates an RGB object file from an assembly source file.
|
||||
The object file format is documented in
|
||||
.Xr rgbds 5 .
|
||||
.Pp
|
||||
The input
|
||||
.Ar asmfile
|
||||
can be a path to a file, or
|
||||
.Cm \-
|
||||
to read from standard input.
|
||||
.Pp
|
||||
Note that options can be abbreviated as long as the abbreviation is unambiguous:
|
||||
.Sh ARGUMENTS
|
||||
.Nm
|
||||
accepts the usual short and long options, such as
|
||||
.Fl V
|
||||
and
|
||||
.Fl -version .
|
||||
Options later in the command line override those set earlier, except for when duplicate options are considered an error.
|
||||
Options can be abbreviated as long as the abbreviation is unambiguous:
|
||||
.Fl \-verb
|
||||
is
|
||||
.Fl \-verbose ,
|
||||
@@ -51,7 +51,52 @@ but
|
||||
.Fl \-ver
|
||||
is invalid because it could also be
|
||||
.Fl \-version .
|
||||
The arguments are as follows:
|
||||
.Pp
|
||||
Unless otherwise noted, passing
|
||||
.Ql -
|
||||
(a single dash) as a file name makes
|
||||
.Nm
|
||||
use standard input (for input files) or standard output (for output files).
|
||||
To suppress this behavior, and open a file in the current directory actually called
|
||||
.Ql - ,
|
||||
pass
|
||||
.Ql ./-
|
||||
instead.
|
||||
Using standard input or output for more than one file in a single command may produce unexpected results.
|
||||
.Pp
|
||||
.Nm
|
||||
accepts decimal, hexadecimal, octal, and binary for numeric option arguments.
|
||||
Decimal numbers are written as usual; hexadecimal numbers must be prefixed with either
|
||||
.Ql $
|
||||
or
|
||||
.Ql 0x ;
|
||||
octal numbers must be prefixed with either
|
||||
.Ql &
|
||||
or
|
||||
.Ql 0o ;
|
||||
and binary numbers must be prefixed with either
|
||||
.Ql %
|
||||
or
|
||||
.Ql 0b .
|
||||
(The prefixes
|
||||
.Ql $
|
||||
and
|
||||
.Ql &
|
||||
will likely need escaping or quoting to avoid being interpreted by the shell.)
|
||||
Leading zeros (after the base prefix, if any) are accepted, and letters are not case-sensitive.
|
||||
For example, all of these are equivalent:
|
||||
.Ql 42 ,
|
||||
.Ql 042 ,
|
||||
.Ql 0x2A ,
|
||||
.Ql 0X2A ,
|
||||
.Ql 0x2a ,
|
||||
.Ql &52 ,
|
||||
.Ql 0o52 ,
|
||||
.Ql 0O052 ,
|
||||
.Ql 0b00101010 ,
|
||||
.Ql 0B101010 .
|
||||
.Pp
|
||||
The following options are accepted:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl B Ar param , Fl \-backtrace Ar param
|
||||
Configures how location backtraces are printed if warnings or errors occur.
|
||||
@@ -132,6 +177,9 @@ or
|
||||
The defaults are 0123.
|
||||
.It Fl h , Fl \-help
|
||||
Print help text for the program and exit.
|
||||
(Help text wraps to the value of the
|
||||
.Dv COLUMNS
|
||||
environment variable if that is defined as nonzero; or else to the console window width if output is to a TTY.)
|
||||
.It Fl I Ar path , Fl \-include Ar path
|
||||
Add a new
|
||||
.Dq include path ;
|
||||
@@ -306,6 +354,23 @@ disables this behavior.
|
||||
The default is 100 if
|
||||
.Nm
|
||||
is printing errors to a terminal, and 0 otherwise.
|
||||
.It @ Ns Ar at_file
|
||||
Read more options and arguments from a file, as if its contents were given on the command line.
|
||||
Arguments are separated by whitespace or newlines.
|
||||
Lines starting with a hash sign
|
||||
.Pq Ql #
|
||||
are considered comments and ignored.
|
||||
.Pp
|
||||
No shell processing is performed, such as wildcard or variable expansion.
|
||||
There is no support for escaping or quoting whitespace to be included in arguments.
|
||||
The standard
|
||||
.Ql --
|
||||
to stop option processing also disables at-file processing.
|
||||
Note that while
|
||||
.Ql --
|
||||
can be used
|
||||
.Em inside
|
||||
an at-file, it only disables option processing within that at-file, and processing continues in the parent scope.
|
||||
.El
|
||||
.Sh DIAGNOSTICS
|
||||
Warnings are diagnostic messages that indicate possibly erroneous behavior that does not necessarily compromise the assembling process.
|
||||
@@ -344,9 +409,9 @@ Enables literally every warning.
|
||||
.Pp
|
||||
The following warnings are actual warning flags; with each description, the corresponding warning flag is included.
|
||||
Note that each of these flags also has a negation (for example,
|
||||
.Fl Wcharmap-redef
|
||||
.Fl Wobsolete
|
||||
enables the warning that
|
||||
.Fl Wno-charmap-redef
|
||||
.Fl Wno-obsolete
|
||||
disables; and
|
||||
.Fl Wall
|
||||
enables every warning that
|
||||
@@ -441,10 +506,10 @@ or
|
||||
.Fl Wno-purge
|
||||
disables this warning.
|
||||
.Fl Wpurge=1
|
||||
or just
|
||||
.Fl Wpurge
|
||||
warns when purging any exported symbol (regardless of type).
|
||||
.Fl Wpurge=2
|
||||
or just
|
||||
.Fl Wpurge
|
||||
also warns when purging any label (even if not exported).
|
||||
.It Fl Wshift
|
||||
Warn when shifting right a negative value.
|
||||
@@ -460,10 +525,10 @@ or
|
||||
.Fl Wno-truncation
|
||||
disables this warning.
|
||||
.Fl Wtruncation=1
|
||||
warns when an N-bit value is 2**N or greater, or less than -2**N.
|
||||
.Fl Wtruncation=2
|
||||
or just
|
||||
.Fl Wtruncation
|
||||
warns when an N-bit value is 2**N or greater, or less than -2**N.
|
||||
.Fl Wtruncation=2
|
||||
also warns when an N-bit value is less than -2**(N-1), which will not fit in two's complement encoding.
|
||||
.It Fl Wunmapped-char=
|
||||
Warn when a character goes through charmap conversion but has no defined mapping.
|
||||
|
||||
+143
-102
@@ -2,7 +2,7 @@
|
||||
.\"
|
||||
.\" SPDX-License-Identifier: MIT
|
||||
.\"
|
||||
.Dd September 30, 2025
|
||||
.Dd August 1, 2026
|
||||
.Dt RGBASM 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -27,10 +27,13 @@ but any program that processes RGBDS object files (described in
|
||||
can be used in its place.
|
||||
.Sh SYNTAX
|
||||
The syntax is line-based, just as in any other assembler.
|
||||
Each line may have components in this order:
|
||||
.Pp
|
||||
.Dl Oo Ar directive Oc Oo ;\ Ns Ar comment Oc
|
||||
.Dl Oo Ar label : Oc Oo Ar instruction Oo :: Ar instruction ... Oc Oc Oo ;\ Ns Ar comment Oc
|
||||
Each line may have components in either of these orders:
|
||||
.Bl -bullet -offset indent
|
||||
.It
|
||||
.Oo Ar label : Oc Oo Ar directive Oc Oo ;\ Ns Ar comment Oc
|
||||
.It
|
||||
.Oo Ar label : Oc Oo Ar instruction Oo :: Ar instruction ... Oc Oc Oo ;\ Ns Ar comment Oc
|
||||
.El
|
||||
.Pp
|
||||
Directives are commands to the assembler itself, such as
|
||||
.Ic PRINTLN ,
|
||||
@@ -41,6 +44,17 @@ or
|
||||
Labels tie a name to a specific location within a section (see
|
||||
.Sx Labels
|
||||
below).
|
||||
Labels are allowed before most directives, but not before
|
||||
.Ic IF ,
|
||||
.Ic ELIF ,
|
||||
.Ic ELSE ,
|
||||
.Ic ENDC ,
|
||||
.Ic REPT ,
|
||||
.Ic FOR ,
|
||||
.Ic ENDR ,
|
||||
.Ic MACRO ,
|
||||
or
|
||||
.Ic ENDM .
|
||||
.Pp
|
||||
Instructions are assembled into Game Boy opcodes.
|
||||
Multiple instructions on one line, as well as data directives (see
|
||||
@@ -84,8 +98,8 @@ as the opposite condition code; for example,
|
||||
for
|
||||
.Ic z .
|
||||
.Pp
|
||||
All reserved keywords (directives, register names, etc.) are case-insensitive;
|
||||
all identifiers (labels and other symbol names) are case-sensitive.
|
||||
All reserved keywords (directives, instructions, registers, built-in functions, etc.) are case-insensitive;
|
||||
all identifiers (labels, variables, etc) are case-sensitive.
|
||||
.Pp
|
||||
Comments are used to give humans information about the code, such as explanations.
|
||||
The assembler
|
||||
@@ -124,17 +138,17 @@ To do so, put a backslash at the end of the line:
|
||||
world!"\ \ \ \ \ \ \ \ \ \ \ ;\ Any leading space is included
|
||||
.Ed
|
||||
.Ss Symbol interpolation
|
||||
A funky feature is writing a symbol between
|
||||
.Ql {braces} ,
|
||||
called
|
||||
.Dq symbol interpolation .
|
||||
Symbols with string or numeric values can be
|
||||
.Dq interpolated
|
||||
by writing them inside
|
||||
.Ql {braces} .
|
||||
This will paste the symbol's contents as if they were part of the source file.
|
||||
If it is a string symbol, its characters are simply inserted as-is.
|
||||
If it is a numeric symbol, its value is converted to hexadecimal notation with a dollar sign
|
||||
.Sq $
|
||||
prepended.
|
||||
.Pp
|
||||
Symbol interpolations can be nested, too!
|
||||
Symbol interpolations can be nested, too.
|
||||
.Bd -literal -offset indent
|
||||
DEF topic EQUS "life, the universe, and \e"everything\e""
|
||||
DEF meaning EQUS "answer"
|
||||
@@ -145,27 +159,29 @@ PRINTLN "The {meaning} to {topic} is {{meaning}}"
|
||||
PURGE topic, meaning, {meaning}
|
||||
.Ed
|
||||
.Pp
|
||||
Symbols can be
|
||||
.Em interpolated
|
||||
even in the contexts that disable automatic
|
||||
.Em expansion
|
||||
of string constants:
|
||||
Symbols can be interpolated even in contexts that disable automatic expansion of string constants: that is,
|
||||
.Ql name
|
||||
will be expanded in all of
|
||||
.Ql DEF({name}) ,
|
||||
.Ql DEF {name} EQU/=/EQUS/etc ... ,
|
||||
.Ql REDEF {name} EQU/=/EQUS/etc ... ,
|
||||
.Ql FOR {name}, ... ,
|
||||
.Ql PURGE {name} ,
|
||||
and
|
||||
.Ql MACRO {name} ,
|
||||
but, for example, won't be in
|
||||
.Ql DEF(name) .
|
||||
even though it won't be in
|
||||
.Ql DEF(name) ,
|
||||
.Ql PURGE {name} ,
|
||||
etc.
|
||||
.Pp
|
||||
It's possible to change the way symbols are printed by specifying a print format like so:
|
||||
.Ql {fmt:symbol} .
|
||||
The
|
||||
.Ql fmt
|
||||
specifier consists of these parts:
|
||||
specifier consists of parts, which must be in the following order:
|
||||
.Ql <sign><exact><align><pad><width><frac><prec><type> .
|
||||
All the parts are optional except the required
|
||||
.Ql <type> .
|
||||
These parts are:
|
||||
.Bl -column "<exact>"
|
||||
.It Sy Part Ta Sy Meaning
|
||||
@@ -175,14 +191,17 @@ or
|
||||
.Ql \ .
|
||||
If specified, prints this character in front of non-negative numbers.
|
||||
.It Ql <exact> Ta May be
|
||||
.Ql # .
|
||||
If specified, prints the value in an "exact" format: with a base prefix for non-decimal integer types
|
||||
.Pq So $ Sc , So & Sc , or So % Sc ;
|
||||
.Ql #
|
||||
.Pq only allowed for non-decimal types .
|
||||
If specified, prints the value in an "exact" format: with a base prefix
|
||||
.Pq So $ Sc , So & Sc , or So % Sc
|
||||
for non-decimal integer types
|
||||
.Pq So x Sc / So X Sc , So o Sc , or So b Sc ;
|
||||
with a
|
||||
.Ql q
|
||||
precision suffix for fixed-point numbers; or with
|
||||
.Ql \e
|
||||
escape characters for strings.
|
||||
escape characters (but no enclosing quotes) for strings.
|
||||
.It Ql <align> Ta May be
|
||||
.Ql - .
|
||||
If specified, aligns left instead of right.
|
||||
@@ -208,7 +227,7 @@ followed by zero
|
||||
.Ql 0
|
||||
\[en]
|
||||
.Ql 9
|
||||
prints zero fractional digits.)
|
||||
prints zero fractional digits and no decimal point.)
|
||||
.It Ql <prec> Ta May be
|
||||
.Ql q
|
||||
followed by one or more
|
||||
@@ -222,13 +241,11 @@ option.
|
||||
.It Ql <type> Ta Specifies the type of value.
|
||||
.El
|
||||
.Pp
|
||||
All the format specifier parts are optional except the
|
||||
.Ql <type> .
|
||||
Valid print types are:
|
||||
Valid types are:
|
||||
.Bl -column -offset indent "Type" "Lowercase hexadecimal" "Example"
|
||||
.It Sy Type Ta Sy Format Ta Sy Example
|
||||
.It Ql d Ta Signed decimal Ta -42
|
||||
.It Ql u Ta Unsigned decimal Ta 42
|
||||
.It Ql u Ta Unsigned decimal Ta 4294967254
|
||||
.It Ql x Ta Lowercase hexadecimal Ta 2a
|
||||
.It Ql X Ta Uppercase hexadecimal Ta 2A
|
||||
.It Ql b Ta Binary Ta 101010
|
||||
@@ -264,9 +281,10 @@ would be more appropriate; see
|
||||
.Sx String expressions
|
||||
below.
|
||||
.Sh EXPRESSIONS
|
||||
An expression can be composed of many things.
|
||||
There are two types of expressions: numeric and string.
|
||||
.Pp
|
||||
Numeric expressions are always evaluated using signed 32-bit math.
|
||||
Zero is considered to be the only "false" number, all non-zero numbers (including negative) are "true".
|
||||
In Boolean logic contexts, zero is considered to be the only "false" number, and all non-zero numbers (including negative) are "true".
|
||||
.Pp
|
||||
An expression is said to be "constant" if
|
||||
.Nm
|
||||
@@ -278,18 +296,21 @@ However, some operators can be constant even with non-constant operands, as expl
|
||||
.Sx Operators
|
||||
below.
|
||||
.Pp
|
||||
The instructions in the macro-language generally require constant expressions.
|
||||
.Ss Numeric formats
|
||||
There are a number of numeric formats.
|
||||
.Bl -column -offset indent "Precise fixed-point" "Possible prefixes"
|
||||
.It Sy Format type Ta Sy Possible prefixes Ta Sy Accepted characters
|
||||
Directives generally require constant expressions: for example,
|
||||
.Ic REPT
|
||||
requires the number of repetitions to be known at assembly time.
|
||||
.Ss Numeric literals
|
||||
.Nm
|
||||
supports a variety of numeric literals.
|
||||
.Bl -column -offset indent "Precise fixed-point" "Prefixes" "Accepted characters"
|
||||
.It Sy Format type Ta Sy Prefixes Ta Sy Accepted characters
|
||||
.It Decimal Ta none Ta 0123456789
|
||||
.It Hexadecimal Ta Li $ , 0x , 0X Ta 0123456789ABCDEF
|
||||
.It Octal Ta Li & , 0o , 0O Ta 01234567
|
||||
.It Binary Ta Li % , 0b , 0B Ta 01
|
||||
.It Fixed-point Ta none Ta 01234.56789
|
||||
.It Precise fixed-point Ta none Ta 12.34q8
|
||||
.It Character constant Ta none Ta 'ABYZ'
|
||||
.It Character constant Ta none Ta 'A'
|
||||
.It Game Boy graphics Ta Li \` Ta 0123
|
||||
.El
|
||||
.Pp
|
||||
@@ -311,15 +332,14 @@ for information on charmaps, and
|
||||
.Sx String expressions
|
||||
for information on escape characters allowed in character constants.
|
||||
.Pp
|
||||
The last one, Game Boy graphics, is quite interesting and useful.
|
||||
After the backtick, 8 digits between 0 and 3 are expected, corresponding to pixel values.
|
||||
The resulting value is the two bytes of tile data that would produce that row of pixels.
|
||||
The last one, Game Boy graphics, expects up to eight digits between 0 and 3, corresponding to pixels' two-bit shade values.
|
||||
The resulting numeric value is the two bytes of tile data which would produce that row of pixels.
|
||||
For example,
|
||||
.Sq \`01012323
|
||||
is equivalent to
|
||||
.Sq $0F55 .
|
||||
.Pp
|
||||
You can also use symbols, which are implicitly replaced with their value.
|
||||
In place of a numeric literal, you can also use a numeric symbol's name, which is implicitly replaced with its value.
|
||||
.Ss Operators
|
||||
You can use these operators in numeric expressions (listed from highest to lowest precedence):
|
||||
.Bl -column -offset indent "!= == <= >= < >"
|
||||
@@ -327,8 +347,8 @@ You can use these operators in numeric expressions (listed from highest to lowes
|
||||
.It Li \&( \&) Ta Grouping
|
||||
.It Li FUNC() Ta Built-in function call
|
||||
.It Li ** Ta Exponentiation
|
||||
.It Li + - ~ \&! Ta Unary plus, minus (negation), complement (bitwise negation), and Boolean negation
|
||||
.It Li * / % Ta Multiplication, division, and modulo (remainder)
|
||||
.It Li + - ~ \&! Ta Unary plus, unary minus (negation), complement (bitwise negation), and Boolean negation
|
||||
.It Li * / % Ta Multiplication, division (rounding down), and modulo (remainder)
|
||||
.It Li << >> >>> Ta Bit shifts (left, sign-extended right, zero-extended right)
|
||||
.It Li & \&| ^ Ta Bitwise AND/OR/XOR
|
||||
.It Li + - Ta Addition and subtraction
|
||||
@@ -396,7 +416,7 @@ with a non-zero constant as either operand will be constant 1, even if the other
|
||||
returns 1 if the operand was 0, and 0 otherwise.
|
||||
Even a non-constant operand with any non-zero bits will return 0.
|
||||
.Ss Integer functions
|
||||
Besides operators, there are also some functions which have more specialized uses.
|
||||
Besides operators, there are also some functions which have more specialized uses:
|
||||
.Bl -column "BITWIDTH(n)"
|
||||
.It Sy Name Ta Sy Operation
|
||||
.It Fn HIGH n Ta Equivalent to Ql Po Ns Ar n No & $FF00 Pc >> 8 .
|
||||
@@ -408,12 +428,13 @@ delim $$
|
||||
.Ar n .
|
||||
Some useful formulas:
|
||||
.Ic BITWIDTH Ns ( Ar n Ns )\ \-\ 1
|
||||
equals $\[lf] log sub 2 ( n ) \[rf]$,
|
||||
equals $\[lf] log sub 2 ( n ) \[rf]$;
|
||||
.Ic BITWIDTH Ns Pq Ar n Ns \ \-\ 1
|
||||
equals $\[lc] log sub 2 ( n ) \[rc]$, and
|
||||
equals $\[lc] log sub 2 ( n ) \[rc]$; and
|
||||
.No 32\ \-\ Ns Ic BITWIDTH Ns Pq Ar n
|
||||
equals $roman clz ( n )$.
|
||||
.It Fn TZCOUNT n Ta Returns $roman ctz ( n )$, the count of trailing zero bits at the end of the binary representation of
|
||||
equals $roman clz ( n )$, the count of leading zero bits in the binary representation of
|
||||
.Ar n .
|
||||
.It Fn TZCOUNT n Ta Returns $roman ctz ( n )$, the count of trailing zero bits in the binary representation of
|
||||
.Ar n .
|
||||
.El
|
||||
.EQ
|
||||
@@ -434,21 +455,25 @@ command-line option, and/or by
|
||||
An individual fixed-point literal can specify its own precision, overriding the current default, by appending a
|
||||
.Dq q
|
||||
followed by the number of fractional bits: for example,
|
||||
.Ql 1234.5q8
|
||||
is equal to $0004d2_80
|
||||
.Ql 789.25q8
|
||||
is equal to $000315_40
|
||||
.EQ
|
||||
delim $$
|
||||
.EN
|
||||
($= 1234.5 * 2 sup 8$).
|
||||
($= 789.25 * 2 sup 8$).
|
||||
.Pp
|
||||
Since fixed-point values are still just integers, you can use them in normal integer expressions.
|
||||
You can easily truncate a fixed-point number into an integer by shifting it right by the number of fractional bits.
|
||||
It follows that you can convert an integer to a fixed-point number by shifting it left that same amount.
|
||||
You can easily truncate a fixed-point number into an integer by shifting it right by the number of fractional bits, or by dividing it by 1.0.
|
||||
It follows that you can convert an integer to a fixed-point number by shifting it left that same amount, or by multiplying it by 1.0.
|
||||
For example,
|
||||
.Ql 123.0 / 1.0 == 123 ,
|
||||
and
|
||||
.Ql 123 * 1.0 == 123.0 .
|
||||
.Pp
|
||||
Note that the current number of fractional bits can be computed as
|
||||
.Ic TZCOUNT Ns Pq 1.0 .
|
||||
.Pp
|
||||
The following functions are designed to operate with fixed-point numbers:
|
||||
The following functions are designed to operate with fixed-point numbers (which must be known constant):
|
||||
.Bl -column -offset indent "ATAN2(y, x)"
|
||||
.It Sy Name Ta Sy Operation
|
||||
.It Fn DIV x y Ta Fixed-point division
|
||||
@@ -456,7 +481,7 @@ The following functions are designed to operate with fixed-point numbers:
|
||||
.It Fn FMOD x y Ta Fixed-point modulo
|
||||
.It Fn POW x y Ta $x sup y$
|
||||
.It Fn LOG x y Ta Logarithm of $x$ to the base $y$
|
||||
.It Fn ROUND x Ta Round $x$ to the nearest integer
|
||||
.It Fn ROUND x Ta Round $x$ half away from zero to the nearest integer
|
||||
.It Fn CEIL x Ta Round $x$ up to the nearest integer
|
||||
.It Fn FLOOR x Ta Round $x$ down to the nearest integer
|
||||
.It Fn SIN x Ta Sine of $x$
|
||||
@@ -507,9 +532,7 @@ will produce a nonsensical (but technically correct) result:
|
||||
The
|
||||
.Ic FMOD
|
||||
function
|
||||
is used to get the remainder of the corresponding fixed-point division, so that
|
||||
.Ql MUL(DIV(x, y), y) + FMOD(x, y) == x
|
||||
is always true.
|
||||
is used to get the remainder of the corresponding fixed-point division.
|
||||
The result has the same sign as the
|
||||
.Em dividend ;
|
||||
this is the opposite of how the integer modulo operator
|
||||
@@ -532,14 +555,15 @@ These functions are useful for automatic generation of various tables.
|
||||
For example:
|
||||
.Bd -literal -offset indent
|
||||
; Generate a table of 128 sine values
|
||||
; from sin(0.0) to sin(0.5) excluded,
|
||||
; with amplitude scaled from [-1.0, 1.0] to [0.0, 128.0].
|
||||
; from sin(0.0) included to sin(0.5) excluded,
|
||||
; with amplitude scaled from [-1.0, 1.0] to [0.0, 128.0],
|
||||
; then divided by 1.0 to round down to integer values.
|
||||
FOR angle, 0.0, 0.5, 0.5 / 128
|
||||
db MUL(SIN(angle) + 1.0, 128.0 / 2) >> 16
|
||||
db MUL(SIN(angle) + 1.0, 128.0 / 2) / 1.0
|
||||
ENDR
|
||||
.Ed
|
||||
.Ss String expressions
|
||||
The most basic string expression is any number of characters contained in double quotes
|
||||
The most basic string expression is a string literal: any number of characters contained in double quotes
|
||||
.Pq Ql \&"for instance" .
|
||||
The backslash character
|
||||
.Ql \e
|
||||
@@ -560,14 +584,14 @@ There are a number of escape sequences you can use within a string:
|
||||
.It Ql \e0 Ta Null Pq ASCII $00
|
||||
.El
|
||||
.Pp
|
||||
Multi-line strings are contained in triple quotes
|
||||
Multi-line string literals are contained in triple quotes
|
||||
.Pq Ql \&"\&"\&"for instance""" .
|
||||
Escape sequences work the same way in multi-line strings; however, literal newline characters will be included as-is, without needing to escape them with
|
||||
.Ql \er
|
||||
or
|
||||
.Ql \en .
|
||||
.Pp
|
||||
Raw strings are prefixed by a hash
|
||||
Raw string literals are prefixed by a hash
|
||||
.Sq # .
|
||||
Inside them, backslashes and braces are treated like regular characters, so they will not be expanded as macro arguments, interpolated symbols, or escape sequences.
|
||||
For example, the raw string
|
||||
@@ -599,7 +623,7 @@ and
|
||||
is equivalent to
|
||||
.Ql STRCMP("str", \&"ing") != 0 .
|
||||
.Pp
|
||||
The following functions operate on string expressions, and return strings themselves.
|
||||
The following functions operate on string expressions, and return strings themselves:
|
||||
.Bl -column "STRSLICE(str, start, stop)"
|
||||
.It Sy Name Ta Sy Operation
|
||||
.It Fn STRCAT strs... Ta Concatenates Ar strs .
|
||||
@@ -610,7 +634,7 @@ in uppercase.
|
||||
.Pq Ql A-Z
|
||||
in lowercase.
|
||||
.It Fn STRSLICE str start stop Ta Returns a substring of Ar str No starting at Ar start No and ending at Ar stop No (exclusive). If Ar stop No is not specified, the substring continues to the end of Ar str .
|
||||
.It Fn STRRPL str old new Ta Returns Ar str No with each non-overlapping occurrence of the substring Ar old No replaced with Ar new .
|
||||
.It Fn STRRPL str old new Ta Returns Ar str No with each occurrence of the substring Ar old No replaced with Ar new .
|
||||
.It Fn STRFMT fmt args... Ta Returns the string Ar fmt No with each
|
||||
.Ql %spec
|
||||
pattern replaced by interpolating the format
|
||||
@@ -620,11 +644,15 @@ with its corresponding argument in
|
||||
.Ar args
|
||||
.Pq So %% Sc is replaced by the So % Sc character .
|
||||
.It Fn STRCHAR str idx Ta Returns the substring of Ar str No for the charmap entry at Ar idx No with the current charmap . Pq Ar idx No counts charmap entries, not characters.
|
||||
.El
|
||||
.Pp
|
||||
The following functions take varying operands, and return strings:
|
||||
.Bl -column "READFILE(name, max)"
|
||||
.It Fn REVCHAR vals... Ta Returns the string that is mapped to Ar vals No with the current charmap. If there is no unique charmap entry for Ar vals Ns , an error occurs.
|
||||
.It Fn READFILE name max Ta Returns the contents of the file Ar name No as a string. Reads up to Ar max No bytes, or the entire contents if Ar max No is not specified. If the file isn't found in the current directory, the include-path list passed to Xr rgbasm 1 Ap s Fl I No option on the command line will be searched.
|
||||
.El
|
||||
.Pp
|
||||
The following functions operate on string expressions, but return integers.
|
||||
The following functions operate on string expressions, but return integers:
|
||||
.Bl -column "STRRFIND(str, sub)"
|
||||
.It Sy Name Ta Sy Operation
|
||||
.It Fn STRLEN str Ta Returns the number of characters in Ar str .
|
||||
@@ -668,7 +696,8 @@ and
|
||||
being equivalent to
|
||||
.Ql dw 50, 53, $20ac .
|
||||
.Pp
|
||||
Any characters in a string without defined mappings will be copied directly, using the source file's encoding of characters to bytes.
|
||||
Character mappings are matched greedily, so the longest applicable one will be mapped in a string.
|
||||
Any characters in the string without defined mappings will be copied directly, using the source file's encoding of characters to bytes.
|
||||
.Pp
|
||||
It is possible to create multiple character maps and then switch between them as desired.
|
||||
This can be used to encode debug information in ASCII and use a different encoding for other purposes, for example.
|
||||
@@ -716,9 +745,14 @@ The result may be constant if
|
||||
is able to compute it.
|
||||
.It Fn SECTION symbol Ta Returns the name of the section that
|
||||
.Ar symbol
|
||||
is in.
|
||||
is defined in.
|
||||
.Ar symbol
|
||||
must have been defined already.
|
||||
If
|
||||
.Ar arg
|
||||
is the symbol
|
||||
.Ic @ ,
|
||||
this function returns the name of the current section.
|
||||
.It Fn SIZEOF arg Ta If
|
||||
.Ar arg
|
||||
is a string, this function returns the size of the section named
|
||||
@@ -741,7 +775,7 @@ The result is not constant, since only RGBLINK can compute its value.
|
||||
.El
|
||||
.Sh SECTIONS
|
||||
Before you can start writing code, you must define a section.
|
||||
This tells the assembler what kind of information follows and, if it is code, where to put it.
|
||||
This tells the assembler what kind of information follows and where to put it.
|
||||
.Pp
|
||||
.Dl SECTION Ar name , type
|
||||
.Dl SECTION Ar name , type , options
|
||||
@@ -749,9 +783,9 @@ This tells the assembler what kind of information follows and, if it is code, wh
|
||||
.Dl SECTION Ar name , type Ns Bo Ar addr Bc , Ar options
|
||||
.Pp
|
||||
.Ar name
|
||||
is a string enclosed in double quotes, and can be a new name or the name of an existing section.
|
||||
is a string enclosed in double quotes, which is the name of the section.
|
||||
If the type doesn't match, an error occurs.
|
||||
All other sections must have a unique name, even in different source files, or the linker will treat it as an error.
|
||||
Each section must have a unique name, even across different source files, or the linker will treat it as an error.
|
||||
.Pp
|
||||
Possible section
|
||||
.Ar type Ns s
|
||||
@@ -776,8 +810,6 @@ can range from
|
||||
.Ad $4000
|
||||
to
|
||||
.Ad $7FFF .
|
||||
.Ar bank
|
||||
can range from 1 to 511.
|
||||
Becomes an alias for
|
||||
.Ic ROM0
|
||||
if tiny ROM mode is enabled in the linker.
|
||||
@@ -797,8 +829,6 @@ can range from
|
||||
.Ad $A000
|
||||
to
|
||||
.Ad $BFFF .
|
||||
.Ar bank
|
||||
can range from 0 to 15.
|
||||
.It Ic WRAM0
|
||||
A general-purpose RAM section.
|
||||
.Ar addr
|
||||
@@ -839,12 +869,18 @@ to
|
||||
.Ad $FFFE .
|
||||
.El
|
||||
.Pp
|
||||
Since RGBDS produces ROMs, code and data can only be placed in
|
||||
RGBDS produces ROMs, which means that code and data can only be placed in
|
||||
.Ic ROM0
|
||||
and
|
||||
.Ic ROMX
|
||||
sections.
|
||||
To put some in RAM, have it stored in ROM, and copy it to RAM.
|
||||
The other RAM section types are for statically allocated labels.
|
||||
If you need code or data in RAM, you will need to copy it from ROM to RAM yourself.
|
||||
See
|
||||
.Sx RAM code
|
||||
for an example of how to conveniently do that with a
|
||||
.Ic LOAD
|
||||
block.
|
||||
.Pp
|
||||
.Ar option Ns s are comma-separated and may include:
|
||||
.Bl -tag -width Ds
|
||||
@@ -901,7 +937,7 @@ creating it if it doesn't already exist.
|
||||
It can end up in any ROM bank.
|
||||
Code and data may follow.
|
||||
.It
|
||||
If it is needed, the the base address of the section can be specified:
|
||||
If it is needed, the base address of the section can be specified:
|
||||
.Bd -literal -offset indent
|
||||
SECTION "Cool Stuff", ROMX[$4567]
|
||||
.Ed
|
||||
@@ -956,13 +992,12 @@ Function:
|
||||
ld [wAnswer], a
|
||||
.Ed
|
||||
.Ss RAM code
|
||||
Sometimes you want to have some code in RAM.
|
||||
But then you can't simply put it in a RAM section, you have to store it in ROM and copy it to RAM at some point.
|
||||
.Pp
|
||||
This means the code (or data) will not be stored in the place it gets executed.
|
||||
Luckily,
|
||||
Sometimes you want to have some code (or data) in RAM, e.g. for self-modifying code.
|
||||
But you can't just put it directly in a RAM section; you have to store it in ROM and copy it to RAM at some point.
|
||||
This means that the code will be executed at a different address range than where it's defined, which can be inconvenient for references to labels within that code.
|
||||
This situation is what
|
||||
.Ic LOAD
|
||||
blocks are the perfect solution to that.
|
||||
blocks are designed for.
|
||||
Here's an example of how to use them:
|
||||
.Bd -literal -offset indent
|
||||
SECTION "LOAD example", ROMX
|
||||
@@ -1047,7 +1082,7 @@ However, a
|
||||
.Ic UNION
|
||||
only works within a single file, so it can't be used e.g. to define temporary variables across several files, all of which use the same statically allocated memory.
|
||||
Unionized sections solve this problem.
|
||||
To declare an unionized section, add a
|
||||
To declare a unionized section, add a
|
||||
.Ic UNION
|
||||
keyword after the
|
||||
.Ic SECTION
|
||||
@@ -1085,9 +1120,9 @@ Different declarations of the same unionized section are not appended, but inste
|
||||
.Sx Allocating overlapping spaces in RAM .
|
||||
Similarly, the size of an unionized section is the largest of all its declarations.
|
||||
.Ss Section fragments
|
||||
Section fragments are sections with a small twist: when several of the same name are encountered, they are concatenated instead of producing an error.
|
||||
Section fragments are sections with a small twist: when several fragments with the same name are encountered, they are concatenated into one section instead of producing an error, even across multiple object files.
|
||||
This works within the same file (paralleling the behavior "plain" sections has in previous versions), but also across object files.
|
||||
To declare an section fragment, add a
|
||||
To declare a section fragment, add a
|
||||
.Ic FRAGMENT
|
||||
keyword after the
|
||||
.Ic SECTION
|
||||
@@ -1556,6 +1591,8 @@ in the C programming language.
|
||||
This expansion is disabled in a few contexts:
|
||||
.Ql DEF(name) ,
|
||||
.Ql DEF name EQU/=/EQUS/etc ... ,
|
||||
.Ql REDEF name EQU/=/EQUS/etc ... ,
|
||||
.Ql FOR name, ... ,
|
||||
.Ql PURGE name ,
|
||||
and
|
||||
.Ql MACRO name
|
||||
@@ -1705,21 +1742,24 @@ error: Undefined symbol "LabelA"
|
||||
at c.asm(2)
|
||||
Linking failed with 1 error
|
||||
.Ed
|
||||
.Pp
|
||||
Note also that only exported symbols will appear in symbol and map files produced by
|
||||
.Xr rgblink 1 .
|
||||
.Ss Purging symbols
|
||||
.Ic PURGE
|
||||
allows you to completely remove a symbol from the symbol table, as if it had never been defined.
|
||||
.Bd -literal -offset indent
|
||||
DEF value EQU 42
|
||||
PURGE value
|
||||
DEF value EQUS "I'm a string now"
|
||||
ASSERT DEF(value)
|
||||
PURGE value
|
||||
ASSERT !DEF(value)
|
||||
.Ed
|
||||
.Pp
|
||||
Be
|
||||
.Em very
|
||||
careful when purging symbols, especially labels, because it could result in unpredictable errors if something depends on the missing symbol (for example, expressions the linker needs to calculate).
|
||||
.Bd -literal -offset indent
|
||||
DEF Kamikaze EQUS "I don't want to live anymore"
|
||||
AOLer: DB "Me too lol"
|
||||
PURGE Kamikaze, AOLer
|
||||
ASSERT !DEF(Kamikaze) && !DEF(AOLer)
|
||||
.Ed
|
||||
careful when purging symbols that have been referenced in section data, or that have been exported, because it could result in unpredictable errors if something depends on the missing symbol (for example, expressions the linker needs to calculate).
|
||||
Purging labels at all is
|
||||
.Em not
|
||||
recommended.
|
||||
.Pp
|
||||
String constants are not expanded within the symbol names.
|
||||
.Ss Predeclared symbols
|
||||
@@ -1729,6 +1769,7 @@ The following symbols are defined by the assembler:
|
||||
.It Dv @ Ta Ic EQU Ta PC value (essentially, the current memory address)
|
||||
.It Dv . Ta Ic EQUS Ta The current global label scope
|
||||
.It Dv .. Ta Ic EQUS Ta The current local label scope
|
||||
.It Dv __SCOPE__ Ta Ic EQUS Ta The innermost current label scope level (empty, ".", or "..")
|
||||
.It Dv _RS Ta Ic = Ta _RS Counter
|
||||
.It Dv _NARG Ta Ic EQU Ta Number of arguments passed to macro, updated by Ic SHIFT
|
||||
.It Dv __ISO_8601_LOCAL__ Ta Ic EQUS Ta ISO 8601 timestamp (local)
|
||||
@@ -1929,7 +1970,7 @@ and
|
||||
.Sq wBonus .
|
||||
Thus, keep in mind that
|
||||
.Ql ld [wHealth], a
|
||||
assembles to the exact same thing as
|
||||
assembles to the exact same instruction as
|
||||
.Ql ld [wName], a .
|
||||
.Pp
|
||||
This whole union's total size is 20 bytes, the size of the largest block (the first one, containing
|
||||
@@ -2532,9 +2573,9 @@ The stack's number of entries is limited only by the amount of memory in your ma
|
||||
.Ic PUSHO
|
||||
can also take a comma-separated list of options, to push the current set and apply the argument set at the same time:
|
||||
.Bd -literal -offset indent
|
||||
PUSHO b.X, g.oOX
|
||||
DB %..XXXX..
|
||||
DW `..ooOOXX
|
||||
PUSHO b.#, g.oO#
|
||||
DB %..####..
|
||||
DW `..ooOO##
|
||||
POPO
|
||||
.Ed
|
||||
.Ss Excluding locations from backtraces
|
||||
|
||||
+4
-6
@@ -1,18 +1,16 @@
|
||||
.\" SPDX-License-Identifier: MIT
|
||||
.\"
|
||||
.Dd September 30, 2025
|
||||
.Dd August 1, 2026
|
||||
.Dt RGBDS 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm rgbds
|
||||
.Nd object file format documentation
|
||||
.Sh DESCRIPTION
|
||||
This is the description of the object files used by
|
||||
This is the description of the RGB object file format that is output by
|
||||
.Xr rgbasm 1
|
||||
and
|
||||
and read by
|
||||
.Xr rgblink 1 .
|
||||
.Em Please note that the specification is not stable yet.
|
||||
RGBDS is still in active development, and some new features require adding more information to the object file, or modifying some fields, both of which break compatibility with older versions.
|
||||
.Sh FILE STRUCTURE
|
||||
The following types are used:
|
||||
.Pp
|
||||
@@ -94,7 +92,7 @@ If the node is not a REPT node...
|
||||
.Pp
|
||||
.Bl -tag -width Ds -compact
|
||||
.It Cm STRING Ar Name
|
||||
The node's name: either a file name, or the macro's name prefixes by its definition's file name
|
||||
The node's name: either a file name, or the macro's name prefixed by its definition's file name
|
||||
.Pq e.g. Ql src/includes/defines.asm::error .
|
||||
.El
|
||||
.It Cm ELSE
|
||||
|
||||
+5
-1
@@ -1,6 +1,6 @@
|
||||
.\" SPDX-License-Identifier: MIT
|
||||
.\"
|
||||
.Dd September 30, 2025
|
||||
.Dd August 1, 2026
|
||||
.Dt RGBDS 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -74,4 +74,8 @@ organization.
|
||||
2022-05-17: The
|
||||
.Lk https://rgbds.gbdev.io rgbds.gbdev.io
|
||||
website for RGBDS documentation and downloads is published.
|
||||
.It
|
||||
2025-10-31: RGBDS reaches version 1.0.0 and starts adhering to
|
||||
.Lk https://semver.org/ semantic versioning
|
||||
("semver").
|
||||
.El
|
||||
|
||||
+84
-20
@@ -1,6 +1,6 @@
|
||||
.\" SPDX-License-Identifier: MIT
|
||||
.\"
|
||||
.Dd September 30, 2025
|
||||
.Dd August 1, 2026
|
||||
.Dt RGBFIX 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -39,23 +39,67 @@ Developers are advised to fill those fields with 0x00 bytes in their source code
|
||||
.Nm ,
|
||||
and to have already populated whichever fields they don't specify using
|
||||
.Nm .
|
||||
.Pp
|
||||
The input
|
||||
.Ar file
|
||||
can be a path to a file, or
|
||||
.Cm \-
|
||||
to read from standard input.
|
||||
.Pp
|
||||
Note that options can be abbreviated as long as the abbreviation is unambiguous:
|
||||
.Fl \-verb
|
||||
is
|
||||
.Fl \-verbose ,
|
||||
but
|
||||
.Sh ARGUMENTS
|
||||
.Nm
|
||||
accepts the usual short and long options, such as
|
||||
.Fl V
|
||||
and
|
||||
.Fl -version .
|
||||
Options later in the command line override those set earlier, except for when duplicate options are considered an error.
|
||||
Options can be abbreviated as long as the abbreviation is unambiguous:
|
||||
.Fl \-ver
|
||||
is
|
||||
.Fl \-version ,
|
||||
but
|
||||
.Fl \-v
|
||||
is invalid because it could also be
|
||||
.Fl \-version .
|
||||
Options later in the command line override those set earlier.
|
||||
Accepted options are as follows:
|
||||
.Fl \-validate .
|
||||
.Pp
|
||||
Unless otherwise noted, passing
|
||||
.Ql -
|
||||
(a single dash) as a file name makes
|
||||
.Nm
|
||||
use standard input (for input files) or standard output (for output files).
|
||||
To suppress this behavior, and open a file in the current directory actually called
|
||||
.Ql - ,
|
||||
pass
|
||||
.Ql ./-
|
||||
instead.
|
||||
Using standard input or output for more than one file in a single command may produce unexpected results.
|
||||
.Pp
|
||||
.Nm
|
||||
accepts decimal, hexadecimal, octal, and binary for numeric option arguments.
|
||||
Decimal numbers are written as usual; hexadecimal numbers must be prefixed with either
|
||||
.Ql $
|
||||
or
|
||||
.Ql 0x ;
|
||||
octal numbers must be prefixed with either
|
||||
.Ql &
|
||||
or
|
||||
.Ql 0o ;
|
||||
and binary numbers must be prefixed with either
|
||||
.Ql %
|
||||
or
|
||||
.Ql 0b .
|
||||
(The prefixes
|
||||
.Ql $
|
||||
and
|
||||
.Ql &
|
||||
will likely need escaping or quoting to avoid being interpreted by the shell.)
|
||||
Leading zeros (after the base prefix, if any) are accepted, and letters are not case-sensitive.
|
||||
For example, all of these are equivalent:
|
||||
.Ql 42 ,
|
||||
.Ql 042 ,
|
||||
.Ql 0x2A ,
|
||||
.Ql 0X2A ,
|
||||
.Ql 0x2a ,
|
||||
.Ql &52 ,
|
||||
.Ql 0o52 ,
|
||||
.Ql 0O052 ,
|
||||
.Ql 0b00101010 ,
|
||||
.Ql 0B101010 .
|
||||
.Pp
|
||||
The following options are accepted:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl C , Fl \-color-only
|
||||
Set the Game Boy Color\(enonly flag
|
||||
@@ -108,6 +152,9 @@ Trash the global checksum.
|
||||
.El
|
||||
.It Fl h , Fl \-help
|
||||
Print help text for the program and exit.
|
||||
(Help text wraps to the value of the
|
||||
.Dv COLUMNS
|
||||
environment variable if that is defined as nonzero; or else to the console window width if output is to a TTY.)
|
||||
.It Fl i Ar game_id , Fl \-game-id Ar game_id
|
||||
Set the game ID string
|
||||
.Pq Ad 0x13F Ns \(en Ns Ad 0x142
|
||||
@@ -199,6 +246,23 @@ See the
|
||||
section for a list of warnings.
|
||||
.It Fl w
|
||||
Disable all warning output, even when turned into errors.
|
||||
.It @ Ns Ar at_file
|
||||
Read more options and arguments from a file, as if its contents were given on the command line.
|
||||
Arguments are separated by whitespace or newlines.
|
||||
Lines starting with a hash sign
|
||||
.Pq Ql #
|
||||
are considered comments and ignored.
|
||||
.Pp
|
||||
No shell processing is performed, such as wildcard or variable expansion.
|
||||
There is no support for escaping or quoting whitespace to be included in arguments.
|
||||
The standard
|
||||
.Ql --
|
||||
to stop option processing also disables at-file processing.
|
||||
Note that while
|
||||
.Ql --
|
||||
can be used
|
||||
.Em inside
|
||||
an at-file, it only disables option processing within that at-file, and processing continues in the parent scope.
|
||||
.El
|
||||
.Sh DIAGNOSTICS
|
||||
Warnings are diagnostic messages that indicate possibly erroneous behavior that does not necessarily compromise the header-fixing process.
|
||||
@@ -212,7 +276,7 @@ to prevent turning all warnings into errors.
|
||||
.It Fl Werror=
|
||||
Make the specified warning or meta warning into an error.
|
||||
A warning's name is appended
|
||||
.Pq example: Fl Werror=overwrite ,
|
||||
.Pq example: Fl Werror=obsolete ,
|
||||
and this warning is implicitly enabled and turned into an error.
|
||||
This can be negated as
|
||||
.Fl Wno-error=
|
||||
@@ -234,10 +298,10 @@ Enables literally every warning.
|
||||
.El
|
||||
.Pp
|
||||
The following warnings are actual warning flags; with each description, the corresponding warning flag is included.
|
||||
Note that each of these flag also has a negation (for example,
|
||||
.Fl Wtruncation
|
||||
Note that each of these flags also has a negation (for example,
|
||||
.Fl Wobsolete
|
||||
enables the warning that
|
||||
.Fl Wno-truncation
|
||||
.Fl Wno-obsolete
|
||||
disables; and
|
||||
.Fl Wall
|
||||
enables every warning that
|
||||
|
||||
+92
-76
@@ -2,7 +2,7 @@
|
||||
.\"
|
||||
.\" SPDX-License-Identifier: MIT
|
||||
.\"
|
||||
.Dd September 30, 2025
|
||||
.Dd August 1, 2026
|
||||
.Dt RGBGFX 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -13,6 +13,7 @@
|
||||
.Op Fl CmhOuVwXYZ
|
||||
.Op Fl v Op Fl v No ...
|
||||
.Op Fl a Ar attrmap | Fl A
|
||||
.Op Fl B Ar color
|
||||
.Op Fl b Ar base_ids
|
||||
.Op Fl c Ar pal_spec
|
||||
.Op Fl \-color Ar when
|
||||
@@ -43,7 +44,13 @@ is to divide the input PNG into 8\[tmu]8 pixel
|
||||
convert each of those squares into 1bpp or 2bpp tile data, and save all of the tile data in a file.
|
||||
It also has options to generate a tile map, attribute map, and/or palette set as well; more on that and how the conversion process can be tweaked below.
|
||||
.Sh ARGUMENTS
|
||||
Note that options can be abbreviated as long as the abbreviation is unambiguous:
|
||||
.Nm
|
||||
accepts the usual short and long options, such as
|
||||
.Fl V
|
||||
and
|
||||
.Fl -version .
|
||||
Options later in the command line override those set earlier, except for when duplicate options are considered an error.
|
||||
Options can be abbreviated as long as the abbreviation is unambiguous:
|
||||
.Fl \-verb
|
||||
is
|
||||
.Fl \-verbose ,
|
||||
@@ -52,26 +59,6 @@ but
|
||||
is invalid because it could also be
|
||||
.Fl \-version .
|
||||
.Pp
|
||||
.Nm
|
||||
accepts decimal, binary, and hexadecimal numbers in option arguments.
|
||||
Decimal numbers are written as usual; binary numbers must be prefixed with either
|
||||
.Ql %
|
||||
or
|
||||
.Ql 0b ,
|
||||
and hexadecimal numbers must be prefixed with either
|
||||
.Ql $
|
||||
(which will likely need escaping or quoting to avoid being interpreted by the shell), or
|
||||
.Ql 0x .
|
||||
Leading zeros (after the base prefix, if any) are accepted, and letters are not case-sensitive.
|
||||
All of these are equivalent:
|
||||
.Ql 42 ,
|
||||
.Ql 042 ,
|
||||
.Ql 0b00101010 ,
|
||||
.Ql 0B101010 ,
|
||||
.Ql 0x2A ,
|
||||
.Ql 0X2A ,
|
||||
.Ql 0x2a .
|
||||
.Pp
|
||||
Unless otherwise noted, passing
|
||||
.Ql -
|
||||
(a single dash) as a file name makes
|
||||
@@ -82,7 +69,39 @@ To suppress this behavior, and open a file in the current directory actually cal
|
||||
pass
|
||||
.Ql ./-
|
||||
instead.
|
||||
Using standard input or output more than once in a single command will likely produce unexpected results.
|
||||
Using standard input or output for more than one file in a single command may produce unexpected results.
|
||||
.Pp
|
||||
.Nm
|
||||
accepts decimal, hexadecimal, octal, and binary for numeric option arguments.
|
||||
Decimal numbers are written as usual; hexadecimal numbers must be prefixed with either
|
||||
.Ql $
|
||||
or
|
||||
.Ql 0x ;
|
||||
octal numbers must be prefixed with either
|
||||
.Ql &
|
||||
or
|
||||
.Ql 0o ;
|
||||
and binary numbers must be prefixed with either
|
||||
.Ql %
|
||||
or
|
||||
.Ql 0b .
|
||||
(The prefixes
|
||||
.Ql $
|
||||
and
|
||||
.Ql &
|
||||
will likely need escaping or quoting to avoid being interpreted by the shell.)
|
||||
Leading zeros (after the base prefix, if any) are accepted, and letters are not case-sensitive.
|
||||
For example, all of these are equivalent:
|
||||
.Ql 42 ,
|
||||
.Ql 042 ,
|
||||
.Ql 0x2A ,
|
||||
.Ql 0X2A ,
|
||||
.Ql 0x2a ,
|
||||
.Ql &52 ,
|
||||
.Ql 0o52 ,
|
||||
.Ql 0O052 ,
|
||||
.Ql 0b00101010 ,
|
||||
.Ql 0B101010 .
|
||||
.Pp
|
||||
The following options are accepted:
|
||||
.Bl -tag -width Ds
|
||||
@@ -125,9 +144,17 @@ Set the base IDs for tile map output.
|
||||
should be one or two numbers between 0 and 255, separated by a comma; they are for bank 0 and bank 1 respectively.
|
||||
Both default to 0.
|
||||
.It Fl C , Fl \-color-curve
|
||||
When generating palettes, use a color curve mimicking the Game Boy Color's screen.
|
||||
The resulting colors may look closer to the input image's
|
||||
.Sy on hardware and accurate emulators .
|
||||
Modifies the color palettes
|
||||
.Pq whether they are generated from the input image or taken from an input palette specification
|
||||
with a color curve mimicking the Game Boy Color's screen.
|
||||
This adjusts the
|
||||
.Em absolute
|
||||
RGB color values so that the
|
||||
.Em perceived
|
||||
colors, when displayed on Game Boy Color hardware
|
||||
.Pq or an emulator with an accurate display filter ,
|
||||
will look like the original colors as displayed on a backlit computer screen.
|
||||
Note that GBC displays can look very different depending on the ambient light and their exact hardware model, so this color curve is only a "best effort".
|
||||
.It Fl c Ar pal_spec , Fl \-colors Ar pal_spec
|
||||
Use the specified color palettes instead of having
|
||||
.Nm
|
||||
@@ -230,6 +257,9 @@ Set the bit depth of the output tile data, in bits per pixel (bpp), either 1 or
|
||||
This changes how tile data is output, and the maximum number of colors per palette (2 and 4 respectively).
|
||||
.It Fl h , Fl \-help
|
||||
Print help text for the program and exit.
|
||||
(Help text wraps to the value of the
|
||||
.Dv COLUMNS
|
||||
environment variable if that is defined as nonzero; or else to the console window width if output is to a TTY.)
|
||||
.It Fl i Ar input_tiles , Fl \-input-tileset Ar input_tiles
|
||||
Use the specified input tiles in addition to having
|
||||
.Nm
|
||||
@@ -287,8 +317,10 @@ This is useful for example if the input image is a sheet of some sort, and you w
|
||||
The default is to process the whole image as-is.
|
||||
.Pp
|
||||
.Ar slice
|
||||
must be two number pairs, separated by a colon.
|
||||
The numbers must be separated by commas; space is allowed around all punctuation.
|
||||
must be formatted as
|
||||
.Ql Ar X , Ns Ar Y : Ns Ar W , Ns Ar H :
|
||||
two comma-separated number pairs, separated by a colon.
|
||||
Whitespace is allowed around all punctuation.
|
||||
The first number pair specifies the X and Y coordinates of the top-left pixel that will be processed (anything above it or to its left will be ignored).
|
||||
The second number pair specifies how many tiles to process horizontally and vertically, respectively.
|
||||
.Pp
|
||||
@@ -469,69 +501,53 @@ Implies
|
||||
.It Fl Z , Fl \-columns
|
||||
Read squares from the PNG in column-major order (column by column), instead of the default row-major order (line by line).
|
||||
This primarily affects tile map and attribute map output, although it may also change generated tile data and palettes.
|
||||
.It @ Ns Ar at_file
|
||||
Read more options and arguments from a file, as if its contents were given on the command line.
|
||||
Arguments are separated by whitespace or newlines.
|
||||
Lines starting with a hash sign
|
||||
.Pq Ql #
|
||||
are considered comments and ignored.
|
||||
.Pp
|
||||
No shell processing is performed, such as wildcard or variable expansion.
|
||||
There is no support for escaping or quoting whitespace to be included in arguments.
|
||||
The standard
|
||||
.Ql --
|
||||
to stop option processing also disables at-file processing.
|
||||
Note that while
|
||||
.Ql --
|
||||
can be used
|
||||
.Em inside
|
||||
an at-file, it only disables option processing within that at-file, and processing continues in the parent scope.
|
||||
.Pp
|
||||
See
|
||||
.Sx At-files
|
||||
below for an explanation of how this can be useful.
|
||||
.El
|
||||
.Ss At-files
|
||||
In a given project, many images are to be converted with different flags.
|
||||
The traditional way of solving this problem has been to specify the different flags for each image in the Makefile / build script; this can be inconvenient, as it centralizes all those flags away from the images they concern.
|
||||
The traditional way of solving this problem has been to specify the different flags for each image in the Makefile or build script; this can be inconvenient, as it centralizes all those flags away from the images they concern.
|
||||
.Pp
|
||||
To avoid these drawbacks,
|
||||
.Nm
|
||||
supports
|
||||
To avoid these drawbacks, you can use
|
||||
.Dq at-files :
|
||||
any command-line argument that begins with an at sign
|
||||
.Pq Ql @
|
||||
is interpreted as one.
|
||||
The rest of the argument (without the @, that is) is interpreted as the path to a file, whose contents are interpreted as if given on the command line.
|
||||
is interpreted as one, as documented above.
|
||||
At-files can be stored right next to the corresponding image, for example:
|
||||
.Pp
|
||||
.Dl $ rgbgfx -o image.2bpp -t image.tilemap @image.flags image.png
|
||||
.Pp
|
||||
This will read additional flags from file
|
||||
This will read additional flags from the file
|
||||
.Ql image.flags ,
|
||||
which could contains for example
|
||||
which could contain, for example,
|
||||
.Ql -b 128
|
||||
to specify a base offset for the image's tiles.
|
||||
The above command could be generated from the following
|
||||
.Xr make 1
|
||||
rule, for example:
|
||||
rule:
|
||||
.Bd -literal -offset indent
|
||||
%.2bpp %.tilemap: %.flags %.png
|
||||
rgbgfx -o $*.2bpp -t $*.tilemap @$*.flags $*.png
|
||||
rgbgfx -o $*.2bpp -t $*.tilemap @$*.flags $*.png
|
||||
.Ed
|
||||
.Pp
|
||||
Since the contents of at-files are interpreted by
|
||||
.Nm ,
|
||||
.Sy no shell processing is performed ;
|
||||
for example, shell variables are not expanded
|
||||
.Ql ( $PWD ,
|
||||
.Ql %WINDIR% ,
|
||||
etc.).
|
||||
In at-files, lines that are empty or contain only whitespace are ignored; lines that begin with a hash sign
|
||||
.Pq Ql # ,
|
||||
optionally preceded by whitespace, are considered comments and also ignored.
|
||||
Each line can contain any number of arguments, which are separated by whitespace.
|
||||
.Pq \&No quoting feature to prevent this is provided.
|
||||
.Pp
|
||||
Note that a leading
|
||||
.Ql @
|
||||
has no special meaning on option arguments, and that the standard
|
||||
.Ql --
|
||||
to stop option processing also disables at-file processing.
|
||||
For example, the following command line reads command-line options from
|
||||
.Ql tilesets/town.flags
|
||||
then
|
||||
.Ql tilesets.flags ,
|
||||
but processes
|
||||
.Ql @tilesets/town.png
|
||||
as the input image and outputs tile data to
|
||||
.Ql @tilesets/town.2bpp :
|
||||
.Pp
|
||||
.Dl $ rgbgfx -o @tilesets/town.2bpp @tilesets/town.flags @tilesets.flags -- @tilesets/town.png
|
||||
.Pp
|
||||
At-files can also specify the input image directly, and call for more at-files, both using the regular syntax.
|
||||
Note that while
|
||||
.Ql --
|
||||
can be used in an at-file (with identical semantics), it is only effective inside of it\(emnormal option processing continues in the parent scope.
|
||||
.Sh PALETTE SPECIFICATION FORMATS
|
||||
The following formats are supported:
|
||||
.Bl -tag -width Ds
|
||||
@@ -769,7 +785,7 @@ to prevent turning all warnings into errors.
|
||||
.It Fl Werror=
|
||||
Make the specified warning or meta warning into an error.
|
||||
A warning's name is appended
|
||||
.Pq example: Fl Werror=embedded ,
|
||||
.Pq example: Fl Werror=obsolete ,
|
||||
and this warning is implicitly enabled and turned into an error.
|
||||
This can be negated as
|
||||
.Fl Wno-error=
|
||||
@@ -791,10 +807,10 @@ Enables literally every warning.
|
||||
.El
|
||||
.Pp
|
||||
The following warnings are actual warning flags; with each description, the corresponding warning flag is included.
|
||||
Note that each of these flag also has a negation (for example,
|
||||
.Fl Wtrim-nonempty
|
||||
Note that each of these flags also has a negation (for example,
|
||||
.Fl Wobsolete
|
||||
enables the warning that
|
||||
.Fl Wno-trim-nonempty
|
||||
.Fl Wno-obsolete
|
||||
disables; and
|
||||
.Fl Wall
|
||||
enables every warning that
|
||||
|
||||
+92
-20
@@ -1,6 +1,6 @@
|
||||
.\" SPDX-License-Identifier: MIT
|
||||
.\"
|
||||
.Dd September 30, 2025
|
||||
.Dd August 1, 2026
|
||||
.Dt RGBLINK 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -48,14 +48,14 @@ Also, if your ROM is designed for a monochrome Game Boy, you can make sure that
|
||||
option, which implies
|
||||
.Fl w
|
||||
but also prohibits the use of banked VRAM.
|
||||
.Pp
|
||||
The input
|
||||
.Ar file
|
||||
can be a path to a file, or
|
||||
.Cm \-
|
||||
to read from standard input.
|
||||
.Pp
|
||||
Note that options can be abbreviated as long as the abbreviation is unambiguous:
|
||||
.Sh ARGUMENTS
|
||||
.Nm
|
||||
accepts the usual short and long options, such as
|
||||
.Fl V
|
||||
and
|
||||
.Fl -version .
|
||||
Options later in the command line override those set earlier, except for when duplicate options are considered an error.
|
||||
Options can be abbreviated as long as the abbreviation is unambiguous:
|
||||
.Fl \-verb
|
||||
is
|
||||
.Fl \-verbose ,
|
||||
@@ -63,7 +63,52 @@ but
|
||||
.Fl \-ver
|
||||
is invalid because it could also be
|
||||
.Fl \-version .
|
||||
The arguments are as follows:
|
||||
.Pp
|
||||
Unless otherwise noted, passing
|
||||
.Ql -
|
||||
(a single dash) as a file name makes
|
||||
.Nm
|
||||
use standard input (for input files) or standard output (for output files).
|
||||
To suppress this behavior, and open a file in the current directory actually called
|
||||
.Ql - ,
|
||||
pass
|
||||
.Ql ./-
|
||||
instead.
|
||||
Using standard input or output for more than one file in a single command may produce unexpected results.
|
||||
.Pp
|
||||
.Nm
|
||||
accepts decimal, hexadecimal, octal, and binary for numeric option arguments.
|
||||
Decimal numbers are written as usual; hexadecimal numbers must be prefixed with either
|
||||
.Ql $
|
||||
or
|
||||
.Ql 0x ;
|
||||
octal numbers must be prefixed with either
|
||||
.Ql &
|
||||
or
|
||||
.Ql 0o ;
|
||||
and binary numbers must be prefixed with either
|
||||
.Ql %
|
||||
or
|
||||
.Ql 0b .
|
||||
(The prefixes
|
||||
.Ql $
|
||||
and
|
||||
.Ql &
|
||||
will likely need escaping or quoting to avoid being interpreted by the shell.)
|
||||
Leading zeros (after the base prefix, if any) are accepted, and letters are not case-sensitive.
|
||||
For example, all of these are equivalent:
|
||||
.Ql 42 ,
|
||||
.Ql 042 ,
|
||||
.Ql 0x2A ,
|
||||
.Ql 0X2A ,
|
||||
.Ql 0x2a ,
|
||||
.Ql &52 ,
|
||||
.Ql 0o52 ,
|
||||
.Ql 0O052 ,
|
||||
.Ql 0b00101010 ,
|
||||
.Ql 0B101010 .
|
||||
.Pp
|
||||
The following options are accepted:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl B Ar param , Fl \-backtrace Ar param
|
||||
Configures how location backtraces are printed if warnings or errors occur.
|
||||
@@ -107,6 +152,9 @@ This option automatically enables
|
||||
.Fl w .
|
||||
.It Fl h , Fl \-help
|
||||
Print help text for the program and exit.
|
||||
(Help text wraps to the value of the
|
||||
.Dv COLUMNS
|
||||
environment variable if that is defined as nonzero; or else to the console window width if output is to a TTY.)
|
||||
.It Fl l Ar linker_script , Fl \-linkerscript Ar linker_script
|
||||
Specify a linker script file that tells the linker how sections must be placed in the ROM.
|
||||
The attributes assigned in the linker script must be consistent with any assigned in the code.
|
||||
@@ -190,27 +238,49 @@ You can use this to make binary files that are not a ROM.
|
||||
When making a ROM, note that not using this is not a replacement for
|
||||
.Xr rgbfix 1 Ap s Fl p
|
||||
option!
|
||||
.It @ Ns Ar at_file
|
||||
Read more options and arguments from a file, as if its contents were given on the command line.
|
||||
Arguments are separated by whitespace or newlines.
|
||||
Lines starting with a hash sign
|
||||
.Pq Ql #
|
||||
are considered comments and ignored.
|
||||
.Pp
|
||||
No shell processing is performed, such as wildcard or variable expansion.
|
||||
There is no support for escaping or quoting whitespace to be included in arguments.
|
||||
The standard
|
||||
.Ql --
|
||||
to stop option processing also disables at-file processing.
|
||||
Note that while
|
||||
.Ql --
|
||||
can be used
|
||||
.Em inside
|
||||
an at-file, it only disables option processing within that at-file, and processing continues in the parent scope.
|
||||
.El
|
||||
.Ss Scrambling algorithm
|
||||
The default section placement algorithm tries to place sections into as few banks as possible.
|
||||
(It turns out that section placement is an NP-complete problem known as "bin packing", so
|
||||
.Nm
|
||||
does not attempt to find the optimal solution, but instead uses a "first-fit" heuristic to find a good one in a reasonable amount of time.
|
||||
There are no guarantees about where this algorithm will place sections, apart from the bank, address, and alignment constraints manually specified for the sections.)
|
||||
does not attempt to find the optimal solution, but instead uses a "first-fit" heuristic to find a good one in a reasonable amount of time.)
|
||||
There are no guarantees about where this algorithm will place sections, apart from the bank, address, and alignment constraints manually specified for the sections.
|
||||
.Pp
|
||||
.Dq Scrambling
|
||||
instead places sections into a given pool of banks, trying to minimize the number of sections sharing a given bank.
|
||||
This is useful to catch broken bank assumptions, such as expecting two different sections to land in the same bank (that is not guaranteed unless both are manually assigned the same bank number).
|
||||
There are still no guarantees about where this algorithm will place sections, apart from the bank pool size and any manually specified section constraints.
|
||||
.Pp
|
||||
A scrambling spec is a comma-separated list of region specs.
|
||||
A trailing comma is allowed, as well as whitespace between all specs and their components.
|
||||
Each region spec has the following form:
|
||||
.D1 Ar region Ns Op = Ns Ar size
|
||||
.Ar region
|
||||
specifies the section type, and
|
||||
.Ar size
|
||||
specifies the number of banks in the pool for that section type.
|
||||
.Ar region
|
||||
must be one of the following (case-insensitive), while
|
||||
.Ar size
|
||||
must be a positive decimal integer between 1 and the corresponding maximum.
|
||||
Certain regions allow omitting the size, in which case it defaults to its max value.
|
||||
Certain regions allow omitting the size, in which case it defaults to its maximum value.
|
||||
.Bl -column "Region name" "Max value" "Size optional"
|
||||
Region name Ta Max size Ta Size optional
|
||||
.Cm romx Ta 65535 Ta \&No
|
||||
@@ -223,14 +293,14 @@ A
|
||||
of 0 disables scrambling for that region.
|
||||
.Pp
|
||||
For example,
|
||||
.Ql romx=64,wramx=4
|
||||
.Ql romx=64,wramx,sram=4
|
||||
will scramble
|
||||
.Ic ROMX
|
||||
sections among ROM banks 1 to 64,
|
||||
.Ic WRAMX
|
||||
sections among RAM banks 1 to 4, and will not scramble
|
||||
sections among RAM banks 1 to 7, and
|
||||
.Ic SRAM
|
||||
sections.
|
||||
sections among SRAM banks 0 to 3.
|
||||
.Pp
|
||||
Later region specs override earlier ones; for example,
|
||||
.Ql romx=42, Romx=0
|
||||
@@ -258,7 +328,7 @@ to prevent turning all warnings into errors.
|
||||
.It Fl Werror=
|
||||
Make the specified warning or meta warning into an error.
|
||||
A warning's name is appended
|
||||
.Pq example: Fl Werror=assert ,
|
||||
.Pq example: Fl Werror=obsolete ,
|
||||
and this warning is implicitly enabled and turned into an error.
|
||||
This can be negated as
|
||||
.Fl Wno-error=
|
||||
@@ -280,7 +350,7 @@ Enables literally every warning.
|
||||
.El
|
||||
.Pp
|
||||
The following warnings are actual warning flags; with each description, the corresponding warning flag is included.
|
||||
Note that each of these flag also has a negation (for example,
|
||||
Note that each of these flags also has a negation (for example,
|
||||
.Fl Wobsolete
|
||||
enables the warning that
|
||||
.Fl Wno-obsolete
|
||||
@@ -307,6 +377,8 @@ for
|
||||
Warn when dividing the smallest negative integer (-2**31) by -1, which yields itself due to integer overflow.
|
||||
This warning is enabled by
|
||||
.Fl Wall .
|
||||
.It Fl Wno-large-constant
|
||||
Warn when a constant too large to fit in a signed 32-bit integer is encountered.
|
||||
.It Fl Wno-obsolete
|
||||
Warn when obsolete features are encountered, which have been deprecated and may later be removed.
|
||||
.It Fl Wshift
|
||||
@@ -327,10 +399,10 @@ or
|
||||
.Fl Wno-truncation
|
||||
disables this warning.
|
||||
.Fl Wtruncation=1
|
||||
warns when an N-bit value is 2**N or greater, or less than -2**N.
|
||||
.Fl Wtruncation=2
|
||||
or just
|
||||
.Fl Wtruncation
|
||||
warns when an N-bit value is 2**N or greater, or less than -2**N.
|
||||
.Fl Wtruncation=2
|
||||
also warns when an N-bit value is less than -2**(N-1), which will not fit in two's complement encoding.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
.\" SPDX-License-Identifier: MIT
|
||||
.\"
|
||||
.Dd September 30, 2025
|
||||
.Dd August 1, 2026
|
||||
.Dt RGBLINK 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
# Generated by CMake
|
||||
/.version.cpp
|
||||
+80
-54
@@ -1,47 +1,44 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
configure_file(version.cpp _version.cpp ESCAPE_QUOTES)
|
||||
|
||||
set(common_src
|
||||
add_library(common OBJECT
|
||||
"extern/getopt.cpp"
|
||||
"cli.cpp"
|
||||
"diagnostics.cpp"
|
||||
"style.cpp"
|
||||
"usage.cpp"
|
||||
"util.cpp"
|
||||
"_version.cpp"
|
||||
)
|
||||
"version.cpp"
|
||||
)
|
||||
target_compile_definitions(common PRIVATE "BUILD_VERSION_STRING=\"${GIT_REV}\"")
|
||||
|
||||
find_package(BISON 3.0.0 REQUIRED)
|
||||
# BISON 4.0 deprecates passing this BISON_FLAGS string to `bison_target`'s `COMPILE_FLAGS`,
|
||||
# in favor of passing a list to `OPTIONS`, but that would require dropping support for CMake <4.0.
|
||||
set(BISON_FLAGS "-Wall -Dlr.type=ielr")
|
||||
# Set some optimization flags on versions that support them
|
||||
# Set some flags on versions that support them.
|
||||
if(BISON_VERSION VERSION_GREATER_EQUAL "3.5")
|
||||
set(BISON_FLAGS "${BISON_FLAGS} -Dparse.lac=full -Dapi.token.raw=true")
|
||||
set(BISON_FLAGS "${BISON_FLAGS} -Dparse.lac=full -Dapi.token.raw=true -Wdangling-alias")
|
||||
endif()
|
||||
if(BISON_VERSION VERSION_GREATER_EQUAL "3.6")
|
||||
set(BISON_FLAGS "${BISON_FLAGS} -Dparse.error=detailed")
|
||||
else()
|
||||
set(BISON_FLAGS "${BISON_FLAGS} -Dparse.error=verbose")
|
||||
endif()
|
||||
if(BISON_VERSION VERSION_GREATER_EQUAL "3.7")
|
||||
set(BISON_FLAGS "${BISON_FLAGS} -Wcounterexamples")
|
||||
endif()
|
||||
|
||||
BISON_TARGET(ASM_PARSER "asm/parser.y"
|
||||
"${PROJECT_SOURCE_DIR}/src/asm/parser.cpp"
|
||||
COMPILE_FLAGS "${BISON_FLAGS}"
|
||||
DEFINES_FILE "${PROJECT_SOURCE_DIR}/src/asm/parser.hpp"
|
||||
)
|
||||
|
||||
BISON_TARGET(LINKER_SCRIPT_PARSER "link/script.y"
|
||||
"${PROJECT_SOURCE_DIR}/src/link/script.cpp"
|
||||
COMPILE_FLAGS "${BISON_FLAGS}"
|
||||
DEFINES_FILE "${PROJECT_SOURCE_DIR}/src/link/script.hpp"
|
||||
)
|
||||
|
||||
set(rgbasm_src
|
||||
"${BISON_ASM_PARSER_OUTPUT_SOURCE}"
|
||||
bison_target(asm_parser "asm/parser.y"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/parser.cpp"
|
||||
COMPILE_FLAGS "${BISON_FLAGS}")
|
||||
add_executable(rgbasm $<TARGET_OBJECTS:common>
|
||||
"${BISON_asm_parser_OUTPUT_SOURCE}"
|
||||
"asm/actions.cpp"
|
||||
"asm/charmap.cpp"
|
||||
"asm/fixpoint.cpp"
|
||||
"asm/format.cpp"
|
||||
"asm/fstack.cpp"
|
||||
"asm/intern.cpp"
|
||||
"asm/lexer.cpp"
|
||||
"asm/macro.cpp"
|
||||
"asm/main.cpp"
|
||||
@@ -56,10 +53,15 @@ set(rgbasm_src
|
||||
"linkdefs.cpp"
|
||||
"opmath.cpp"
|
||||
"verbosity.cpp"
|
||||
)
|
||||
)
|
||||
cmake_path(GET BISON_asm_parser_OUTPUT_HEADER PARENT_PATH parser_header_dir)
|
||||
target_include_directories(rgbasm PRIVATE "${parser_header_dir}")
|
||||
|
||||
set(rgblink_src
|
||||
"${BISON_LINKER_SCRIPT_PARSER_OUTPUT_SOURCE}"
|
||||
bison_target(linker_script_parser "link/script.y"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/script.cpp"
|
||||
COMPILE_FLAGS "${BISON_FLAGS}")
|
||||
add_executable(rgblink $<TARGET_OBJECTS:common>
|
||||
"${BISON_linker_script_parser_OUTPUT_SOURCE}"
|
||||
"link/assign.cpp"
|
||||
"link/fstack.cpp"
|
||||
"link/lexer.cpp"
|
||||
@@ -77,53 +79,77 @@ set(rgblink_src
|
||||
"linkdefs.cpp"
|
||||
"opmath.cpp"
|
||||
"verbosity.cpp"
|
||||
)
|
||||
)
|
||||
cmake_path(GET BISON_linker_script_parser_OUTPUT_HEADER PARENT_PATH parser_header_dir)
|
||||
target_include_directories(rgblink PRIVATE "${parser_header_dir}")
|
||||
|
||||
set(rgbfix_src
|
||||
add_executable(rgbfix $<TARGET_OBJECTS:common>
|
||||
"fix/fix.cpp"
|
||||
"fix/main.cpp"
|
||||
"fix/mbc.cpp"
|
||||
"fix/warning.cpp"
|
||||
)
|
||||
)
|
||||
|
||||
set(rgbgfx_src
|
||||
add_executable(rgbgfx $<TARGET_OBJECTS:common>
|
||||
"gfx/color_set.cpp"
|
||||
"gfx/main.cpp"
|
||||
"gfx/pal_packing.cpp"
|
||||
"gfx/pal_sorting.cpp"
|
||||
"gfx/pal_spec.cpp"
|
||||
"gfx/palette.cpp"
|
||||
"gfx/png.cpp"
|
||||
"gfx/process.cpp"
|
||||
"gfx/reverse.cpp"
|
||||
"gfx/rgba.cpp"
|
||||
"gfx/warning.cpp"
|
||||
"verbosity.cpp"
|
||||
)
|
||||
)
|
||||
|
||||
foreach(PROG "asm" "fix" "gfx" "link")
|
||||
add_executable(rgb${PROG}
|
||||
${rgb${PROG}_src}
|
||||
${common_src}
|
||||
)
|
||||
install(TARGETS rgb${PROG} RUNTIME DESTINATION bin)
|
||||
# Required to run tests
|
||||
set_target_properties(rgb${PROG} PROPERTIES
|
||||
# hack for MSVC: no-op generator expression to stop generation of "per-configuration subdirectory"
|
||||
RUNTIME_OUTPUT_DIRECTORY $<1:${CMAKE_SOURCE_DIR}>)
|
||||
endforeach()
|
||||
install(TARGETS rgbasm rgblink rgbfix rgbgfx RUNTIME COMPONENT binaries)
|
||||
# Tests expect the binaries to end up in-source; this is more acceptable than the entire artifact dir.
|
||||
set_target_properties(rgbasm rgblink rgbfix rgbgfx PROPERTIES
|
||||
# The generator expression (even if a no-op) stops muti-config generators using a of "per-configuration subdirectory".
|
||||
RUNTIME_OUTPUT_DIRECTORY $<1:${CMAKE_CURRENT_SOURCE_DIR}/..>)
|
||||
target_link_libraries(rgbgfx PRIVATE PNG::PNG)
|
||||
# Copy the DLLs in the output directory so the program can be run for testing without having to `install`.
|
||||
# From https://cmake.org/cmake/help/v4.3/manual/cmake-generator-expressions.7.html#genex:TARGET_RUNTIME_DLLS.
|
||||
add_custom_command(TARGET rgbgfx POST_BUILD COMMENT "Copying rgbgfx's DLLs"
|
||||
# It would be nice to symlink instead, but that only supports one file at a time.
|
||||
COMMAND ${CMAKE_COMMAND} -E copy -t $<TARGET_FILE_DIR:rgbgfx> $<TARGET_RUNTIME_DLLS:rgbgfx>
|
||||
COMMAND_EXPAND_LISTS VERBATIM)
|
||||
|
||||
if(LIBPNG_FOUND) # pkg-config
|
||||
target_include_directories(rgbgfx PRIVATE ${LIBPNG_INCLUDE_DIRS})
|
||||
target_link_directories(rgbgfx PRIVATE ${LIBPNG_LIBRARY_DIRS})
|
||||
target_link_libraries(rgbgfx PRIVATE ${LIBPNG_LIBRARIES})
|
||||
else()
|
||||
target_compile_definitions(rgbgfx PRIVATE ${PNG_DEFINITIONS})
|
||||
target_include_directories(rgbgfx PRIVATE ${PNG_INCLUDE_DIRS})
|
||||
target_link_libraries(rgbgfx PRIVATE ${PNG_LIBRARIES})
|
||||
endif()
|
||||
|
||||
include(CheckLibraryExists)
|
||||
check_library_exists("m" "sin" "" HAS_LIBM)
|
||||
if(HAS_LIBM)
|
||||
target_link_libraries(rgbasm PRIVATE "m")
|
||||
if(WIN32)
|
||||
# CMake 3.27 is required for `$<INSTALL_PREFIX>`, but is only needed when cross-compiling for MinGW.
|
||||
if(CMAKE_VERSION VERSION_LESS "3.27")
|
||||
message(WARNING "CMake 3.27 or higher is required for `\$<INSTALL_PREFIX>` inside `install(CODE)`")
|
||||
endif()
|
||||
# On Windows, you don't link against DLLs directly, but against an import library for that DLL.
|
||||
# This leads to, sometimes, the DLL being stored in a directory far away from the import library itself!
|
||||
set(DLL_SEARCH_DIRS CACHE PATH "List of directories in which DLLs will be searched")
|
||||
cmake_path(CONVERT "${DLL_SEARCH_DIRS}" TO_CMAKE_PATH_LIST search_dirs NORMALIZE)
|
||||
# TODO: we've only tested this with MinGW, but it may not work with other uses of the variable.
|
||||
# Anyone who knows how to handle this better, feel free to submit a patch!
|
||||
if(DEFINED CMAKE_FIND_ROOT_PATH)
|
||||
list(APPEND search_dirs "${CMAKE_FIND_ROOT_PATH}/bin")
|
||||
endif()
|
||||
# Escape the search paths in a form that makes them suitable for splatting into the CMake install script.
|
||||
list(TRANSFORM search_dirs REPLACE "([\\$\"])" "\\\\1") # Neutralize escapes and variable refs...
|
||||
list(TRANSFORM search_dirs REPLACE "^(.+)\$" "\"\\1\"") # ...and quote each argument.
|
||||
list(JOIN search_dirs " " search_dirs_splat)
|
||||
# This is a modified version of the install code generated by
|
||||
# `install(TARGETS rgbgfx RUNTIME_DEPENDENCIES)`.
|
||||
# Unfortunately, that `install(TARGETS)` is outright not supported when cross-compiling,
|
||||
# and working around that has CMake fail to resolve the DLL locations with MinGW,
|
||||
# due to not specifying any `DIRECTORIES` and the system search path being ineffective.
|
||||
install(CODE "\
|
||||
file(GET_RUNTIME_DEPENDENCIES
|
||||
RESOLVED_DEPENDENCIES_VAR rgbgfx_deps
|
||||
EXECUTABLES \"$<TARGET_FILE:rgbgfx>\"
|
||||
DIRECTORIES ${search_dirs_splat} \"$<TARGET_FILE_DIR:ZLIB::ZLIB>\" \"$<TARGET_FILE_DIR:PNG::PNG>\"
|
||||
PRE_EXCLUDE_REGEXES \"^kernel32\\\\.dll$\" \"^msvcrt.?.?\\\\.dll\" \"^api-ms-win-.*\\\\.dll$\")
|
||||
foreach(rgbgfx_dep IN LISTS rgbgfx_deps)
|
||||
file(INSTALL DESTINATION \"$<INSTALL_PREFIX>/${CMAKE_INSTALL_BINDIR}\" TYPE SHARED_LIBRARY FILES \${rgbgfx_dep}
|
||||
FOLLOW_SYMLINK_CHAIN)
|
||||
endforeach()"
|
||||
COMPONENT shared-libs EXCLUDE_FROM_ALL) # Most platforms install those separately.
|
||||
endif()
|
||||
|
||||
+30
-32
@@ -18,10 +18,12 @@
|
||||
#include "extern/utf8decoder.hpp"
|
||||
#include "helpers.hpp"
|
||||
#include "linkdefs.hpp"
|
||||
#include "util.hpp" // xfclose, seekSize
|
||||
|
||||
#include "asm/charmap.hpp"
|
||||
#include "asm/format.hpp"
|
||||
#include "asm/fstack.hpp"
|
||||
#include "asm/intern.hpp"
|
||||
#include "asm/lexer.hpp"
|
||||
#include "asm/output.hpp"
|
||||
#include "asm/rpn.hpp" // Expression
|
||||
@@ -139,23 +141,22 @@ std::optional<std::string> act_ReadFile(std::string const &name, uint32_t maxLen
|
||||
file = fopen(fullPath->c_str(), "rb");
|
||||
}
|
||||
if (!file) {
|
||||
if (fstk_FileError(name, "READFILE")) {
|
||||
if (fstk_FileError(name, "`READFILE`")) {
|
||||
// If `fstk_FileError` returned true due to `-MG`, we should abort due to a
|
||||
// missing file, so return `std::nullopt`, which tells the caller to `YYACCEPT`
|
||||
return std::nullopt;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
Defer closeFile{[&] { fclose(file); }};
|
||||
Defer closeFile{[&] { xfclose(file); }};
|
||||
|
||||
size_t readSize = maxLen;
|
||||
if (fseek(file, 0, SEEK_END) == 0) {
|
||||
if (std::optional<uint64_t> fileSize = seekSize(file); fileSize.has_value()) {
|
||||
// If the file is seekable and shorter than the max length,
|
||||
// just read as many bytes as there are
|
||||
if (long fileSize = ftell(file); static_cast<size_t>(fileSize) < readSize) {
|
||||
readSize = fileSize;
|
||||
if (*fileSize < readSize) {
|
||||
readSize = *fileSize;
|
||||
}
|
||||
fseek(file, 0, SEEK_SET);
|
||||
// LCOV_EXCL_START
|
||||
} else if (errno != ESPIPE) {
|
||||
error(
|
||||
@@ -278,19 +279,18 @@ static void errorInvalidUTF8Byte(uint8_t byte, char const *functionName) {
|
||||
|
||||
size_t act_StringLen(std::string const &str, bool printErrors) {
|
||||
size_t len = 0;
|
||||
uint32_t state = UTF8_ACCEPT;
|
||||
uint32_t codepoint = 0;
|
||||
Utf8Decoder decoder;
|
||||
|
||||
for (char c : str) {
|
||||
uint8_t byte = static_cast<uint8_t>(c);
|
||||
|
||||
switch (decode(&state, &codepoint, byte)) {
|
||||
switch (decoder.update(byte)) {
|
||||
case UTF8_REJECT:
|
||||
if (printErrors) {
|
||||
errorInvalidUTF8Byte(byte, "STRLEN");
|
||||
}
|
||||
state = UTF8_ACCEPT;
|
||||
// fallthrough
|
||||
decoder.state = UTF8_ACCEPT;
|
||||
[[fallthrough]];
|
||||
case UTF8_ACCEPT:
|
||||
++len;
|
||||
break;
|
||||
@@ -298,7 +298,7 @@ size_t act_StringLen(std::string const &str, bool printErrors) {
|
||||
}
|
||||
|
||||
// Check for partial code point.
|
||||
if (state != UTF8_ACCEPT) {
|
||||
if (decoder.state != UTF8_ACCEPT) {
|
||||
if (printErrors) {
|
||||
error("STRLEN: Incomplete UTF-8 character");
|
||||
}
|
||||
@@ -316,17 +316,16 @@ std::string
|
||||
|
||||
size_t strLen = str.length();
|
||||
size_t index = 0;
|
||||
uint32_t state = UTF8_ACCEPT;
|
||||
uint32_t codepoint = 0;
|
||||
Utf8Decoder decoder;
|
||||
uint32_t curIdx = 0;
|
||||
|
||||
// Advance to starting index in source string.
|
||||
while (index < strLen && curIdx < start) {
|
||||
switch (decode(&state, &codepoint, str[index])) {
|
||||
switch (decoder.update(str[index])) {
|
||||
case UTF8_REJECT:
|
||||
errorInvalidUTF8Byte(str[index], "STRSLICE");
|
||||
state = UTF8_ACCEPT;
|
||||
// fallthrough
|
||||
decoder.state = UTF8_ACCEPT;
|
||||
[[fallthrough]];
|
||||
case UTF8_ACCEPT:
|
||||
++curIdx;
|
||||
break;
|
||||
@@ -348,11 +347,11 @@ std::string
|
||||
|
||||
// Advance to ending index in source string.
|
||||
while (index < strLen && curIdx < stop) {
|
||||
switch (decode(&state, &codepoint, str[index])) {
|
||||
switch (decoder.update(str[index])) {
|
||||
case UTF8_REJECT:
|
||||
errorInvalidUTF8Byte(str[index], "STRSLICE");
|
||||
state = UTF8_ACCEPT;
|
||||
// fallthrough
|
||||
decoder.state = UTF8_ACCEPT;
|
||||
[[fallthrough]];
|
||||
case UTF8_ACCEPT:
|
||||
++curIdx;
|
||||
break;
|
||||
@@ -361,7 +360,7 @@ std::string
|
||||
}
|
||||
|
||||
// Check for partial code point.
|
||||
if (state != UTF8_ACCEPT) {
|
||||
if (decoder.state != UTF8_ACCEPT) {
|
||||
error("STRSLICE: Incomplete UTF-8 character");
|
||||
++curIdx;
|
||||
}
|
||||
@@ -386,17 +385,16 @@ std::string act_StringSub(std::string const &str, int32_t negPos, std::optional<
|
||||
|
||||
size_t strLen = str.length();
|
||||
size_t index = 0;
|
||||
uint32_t state = UTF8_ACCEPT;
|
||||
uint32_t codepoint = 0;
|
||||
Utf8Decoder decoder;
|
||||
uint32_t curPos = 1;
|
||||
|
||||
// Advance to starting position in source string.
|
||||
while (index < strLen && curPos < pos) {
|
||||
switch (decode(&state, &codepoint, str[index])) {
|
||||
switch (decoder.update(str[index])) {
|
||||
case UTF8_REJECT:
|
||||
errorInvalidUTF8Byte(str[index], "STRSUB");
|
||||
state = UTF8_ACCEPT;
|
||||
// fallthrough
|
||||
decoder.state = UTF8_ACCEPT;
|
||||
[[fallthrough]];
|
||||
case UTF8_ACCEPT:
|
||||
++curPos;
|
||||
break;
|
||||
@@ -417,11 +415,11 @@ std::string act_StringSub(std::string const &str, int32_t negPos, std::optional<
|
||||
|
||||
// Compute the result length in bytes.
|
||||
while (index < strLen && curLen < len) {
|
||||
switch (decode(&state, &codepoint, str[index])) {
|
||||
switch (decoder.update(str[index])) {
|
||||
case UTF8_REJECT:
|
||||
errorInvalidUTF8Byte(str[index], "STRSUB");
|
||||
state = UTF8_ACCEPT;
|
||||
// fallthrough
|
||||
decoder.state = UTF8_ACCEPT;
|
||||
[[fallthrough]];
|
||||
case UTF8_ACCEPT:
|
||||
++curLen;
|
||||
break;
|
||||
@@ -430,7 +428,7 @@ std::string act_StringSub(std::string const &str, int32_t negPos, std::optional<
|
||||
}
|
||||
|
||||
// Check for partial code point.
|
||||
if (state != UTF8_ACCEPT) {
|
||||
if (decoder.state != UTF8_ACCEPT) {
|
||||
error("STRSUB: Incomplete UTF-8 character");
|
||||
++curLen;
|
||||
}
|
||||
@@ -607,7 +605,7 @@ std::string act_StringFormat(
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string act_SectionName(std::string const &symName) {
|
||||
std::string act_SectionName(InternedStr symName) {
|
||||
Symbol *sym = sym_FindScopedValidSymbol(symName);
|
||||
if (!sym) {
|
||||
if (sym_IsPurgedScoped(symName)) {
|
||||
@@ -625,7 +623,7 @@ std::string act_SectionName(std::string const &symName) {
|
||||
return section->name;
|
||||
}
|
||||
|
||||
void act_CompoundAssignment(std::string const &symName, RPNCommand op, int32_t constValue) {
|
||||
void act_CompoundAssignment(InternedStr symName, RPNCommand op, int32_t constValue) {
|
||||
Expression oldExpr, constExpr, newExpr;
|
||||
oldExpr.makeSymbol(symName);
|
||||
constExpr.makeNumber(constValue);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user