mirror of
https://github.com/gbdev/rgbds.git
synced 2026-08-25 08:14:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
307846b03e | ||
|
|
e7e671b249 | ||
|
|
0c772ea049 | ||
|
|
6f64fd00f6 | ||
|
|
4384223951 | ||
|
|
4e87f61656 | ||
|
|
9d854114ea | ||
|
|
70d8d67ffc | ||
|
|
ca2b8e4cde | ||
|
|
80c8e77b19 | ||
|
|
604c69e048 | ||
|
|
ec5e6cbabb | ||
|
|
50678d0942 | ||
|
|
c691ec6607 | ||
|
|
c3073f4318 | ||
|
|
e5b03e3cb1 | ||
|
|
0d379e9016 | ||
|
|
9cbfec30c7 | ||
|
|
9def9c9aa8 | ||
|
|
b5681c0d34 | ||
|
|
ec43f06bd9 | ||
|
|
106ec399d5 | ||
|
|
d9c0d37fd5 | ||
|
|
3b1606c63c | ||
|
|
fa49e238a9 | ||
|
|
3426f685a0 | ||
|
|
c0e2f8340b | ||
|
|
8883251bf9 | ||
|
|
f27a8132d9 | ||
|
|
0af28de791 | ||
|
|
8d2275dc48 | ||
|
|
7e11ab4d8f | ||
|
|
e84bcf83b4 | ||
|
|
57c9bab3a5 | ||
|
|
4ada3e85d8 | ||
|
|
ba4a7f2e6a | ||
|
|
b0948566bb | ||
|
|
5aa7067876 | ||
|
|
dff176791c | ||
|
|
07f5969005 | ||
|
|
d61c0561c1 | ||
|
|
b13b0c8eb8 | ||
|
|
ca2de0f429 | ||
|
|
a821badc3e | ||
|
|
cb34fe18f7 | ||
|
|
1ed22cc518 | ||
|
|
9a15b723f2 | ||
|
|
7e2a3491a5 | ||
|
|
e7855ea1b8 | ||
|
|
19e60d9864 | ||
|
|
c0ff3d92ad | ||
|
|
e4583e7ac2 | ||
|
|
5869e0dc60 | ||
|
|
196d50c1d7 | ||
|
|
8b951bc047 | ||
|
|
59b6b15106 | ||
|
|
304cbb464f | ||
|
|
ea3a8ee171 | ||
|
|
f0419eb183 | ||
|
|
4a6ea35299 | ||
|
|
08354cf573 | ||
|
|
417b5212d4 | ||
|
|
66312f55dd | ||
|
|
21eaa2d2cc | ||
|
|
e9fa1e4e94 | ||
|
|
8ab6190f96 | ||
|
|
22bd8a9bd5 | ||
|
|
96bc58b7f7 | ||
|
|
4857ad1e00 | ||
|
|
3b33c942ae | ||
|
|
5525dd902b | ||
|
|
4350a3252d | ||
|
|
a8442bccc7 | ||
|
|
00006a9d00 | ||
|
|
a383bec96e | ||
|
|
226031c18b | ||
|
|
24a896f60a | ||
|
|
a6f5e3efd1 | ||
|
|
c02b234bb1 | ||
|
|
be4c1161bd | ||
|
|
0e1e5e80f6 | ||
|
|
118f1f7543 | ||
|
|
eaa35ed26d | ||
|
|
7b39bcd412 | ||
|
|
255cd7f7f6 | ||
|
|
b8011947a8 | ||
|
|
39e7e064c9 | ||
|
|
7b97d7ce15 | ||
|
|
c667bac93a | ||
|
|
db96144d49 | ||
|
|
276a1a7952 | ||
|
|
b219e03b38 | ||
|
|
824ebd80f9 | ||
|
|
5aedf31b46 | ||
|
|
d94d0bcc2f | ||
|
|
ed8e3e4d02 | ||
|
|
30fd4514dc | ||
|
|
08e83601f5 | ||
|
|
e606f4e997 | ||
|
|
9008d8391c | ||
|
|
21682e8814 | ||
|
|
f82b0838a1 | ||
|
|
dabd0a08d2 | ||
|
|
c3e10dbb03 | ||
|
|
3883c2a2b8 | ||
|
|
cd0caaaceb | ||
|
|
1e4a060d9e | ||
|
|
fe3b238dea | ||
|
|
46a6966b70 | ||
|
|
be3fc61859 | ||
|
|
0adbb92e50 | ||
|
|
09da4e001a | ||
|
|
3eb8c7e8f2 | ||
|
|
189c679e13 | ||
|
|
5d5000011a | ||
|
|
f81f5fe63c | ||
|
|
6e643406a2 | ||
|
|
de36a11be7 | ||
|
|
799c55b4dd | ||
|
|
ddd8f37508 | ||
|
|
c55dec254d | ||
|
|
0996a2f5ed | ||
|
|
e3c594c250 | ||
|
|
daba94b495 | ||
|
|
2f604bfa9a | ||
|
|
9bbb2247a7 | ||
|
|
9b4df11473 | ||
|
|
4a77c42ed7 | ||
|
|
b12eac356e | ||
|
|
82702d8149 | ||
|
|
1f9cc9651a | ||
|
|
04b9c7fa3d | ||
|
|
5e8a6cde20 | ||
|
|
d59081a918 | ||
|
|
250a94c588 | ||
|
|
37818a1847 | ||
|
|
0e3d1df129 | ||
|
|
586c3073f9 | ||
|
|
e3fc46f933 | ||
|
|
3941a28661 | ||
|
|
a829e6c067 | ||
|
|
b252877b05 | ||
|
|
22a3625144 | ||
|
|
6cba5518e9 | ||
|
|
caf561457d | ||
|
|
fc7d9ad573 | ||
|
|
0b91bf654b | ||
|
|
6b2b6e6000 | ||
|
|
f72a4d53e2 | ||
|
|
998f636495 | ||
|
|
075f132d77 | ||
|
|
31e1d2ec87 | ||
|
|
673c62414f | ||
|
|
007672f080 | ||
|
|
7eaca1577d | ||
|
|
996469ee28 | ||
|
|
55db252a8f | ||
|
|
cfa0adf295 | ||
|
|
ed19806434 | ||
|
|
a0d96a0856 | ||
|
|
4b992bfea5 | ||
|
|
141a7fe22b | ||
|
|
43ffc89bb4 | ||
|
|
72a410c007 | ||
|
|
090768e2c9 | ||
|
|
5f2ee530b8 | ||
|
|
4a173130b9 | ||
|
|
ef2f021892 | ||
|
|
dce14fd4b8 | ||
|
|
728bed39d5 | ||
|
|
48fcd9a0ca | ||
|
|
1871b0a0b8 | ||
|
|
d56dbbb4bf | ||
|
|
728d14879b | ||
|
|
0ed8c2f8ee | ||
|
|
d5186b088b | ||
|
|
fee177d0b9 | ||
|
|
42e3da837c | ||
|
|
358e8fe636 | ||
|
|
c50a849757 | ||
|
|
57111b219a | ||
|
|
be2d028ae6 | ||
|
|
1af8bdda16 | ||
|
|
fa22b78e7d | ||
|
|
f0161b41c8 | ||
|
|
ca23210f18 | ||
|
|
85e044f5be | ||
|
|
60e76b2da4 | ||
|
|
3c7488c131 | ||
|
|
9fd0c0297f | ||
|
|
c1c7e64249 | ||
|
|
a18b2f1049 | ||
|
|
3f144b7713 | ||
|
|
eeb3a73210 | ||
|
|
37d39f91f6 | ||
|
|
d5ce5329ea | ||
|
|
6bcd79b997 | ||
|
|
decc5f7153 | ||
|
|
a3c953ea46 | ||
|
|
d43049c84d | ||
|
|
b6ff54acc3 | ||
|
|
71fc449452 | ||
|
|
59dd1fbbf8 | ||
|
|
2502d130eb | ||
|
|
a78a268cb4 | ||
|
|
0553491107 | ||
|
|
6edac50cc4 | ||
|
|
77dceaf43a | ||
|
|
cfec017fed | ||
|
|
12186fdccc | ||
|
|
71dfab3365 | ||
|
|
20b11039c9 | ||
|
|
eb9e9c0f33 | ||
|
|
ac2a022124 | ||
|
|
1249c4ef58 | ||
|
|
aeedfb35a6 | ||
|
|
63609871f4 | ||
|
|
393eaa9dc1 | ||
|
|
b3c3981a90 | ||
|
|
185a5c5369 | ||
|
|
4ea15ed85a | ||
|
|
b218fd65a0 | ||
|
|
81edc27b6e | ||
|
|
dc52487d31 | ||
|
|
6b994b1737 | ||
|
|
0849eb801e | ||
|
|
e6916360f4 | ||
|
|
a802bcb320 | ||
|
|
846aa975f1 | ||
|
|
b65649ca73 | ||
|
|
62ddabb570 | ||
|
|
d48d6fe5d9 | ||
|
|
ac0f93ffda | ||
|
|
a1712cb6d9 | ||
|
|
2968bee86f | ||
|
|
dec7a74166 | ||
|
|
9c4e53d1c4 | ||
|
|
463edc3c01 | ||
|
|
73941c3249 | ||
|
|
7596ae67b5 | ||
|
|
fc08ab6aee | ||
|
|
c7663423d6 | ||
|
|
1ff73cd5e0 | ||
|
|
65ec1af1e8 | ||
|
|
bc3572ec37 | ||
|
|
78281a4aaa | ||
|
|
6e51ab6f55 | ||
|
|
52aaf7e3b3 | ||
|
|
09db4f25dd | ||
|
|
fed5db7743 | ||
|
|
c6dbec7830 | ||
|
|
017b0119e6 | ||
|
|
0e6e91d048 | ||
|
|
df0b557638 | ||
|
|
123201ecc6 | ||
|
|
422e8eec20 | ||
|
|
49a4da2235 | ||
|
|
4577ff16bc | ||
|
|
b430d5a8b8 | ||
|
|
a5be1d886e | ||
|
|
c3b47abcc8 | ||
|
|
2cfb2b2533 | ||
|
|
187e1a55b8 | ||
|
|
143d503c6c | ||
|
|
6e13779b8b | ||
|
|
ace2f3e613 | ||
|
|
8d1a60d6b5 | ||
|
|
11ac22d8f5 | ||
|
|
812e1f6d4b | ||
|
|
8dc052475b | ||
|
|
133eaa4e92 | ||
|
|
57f1894fbd | ||
|
|
021fe01eb0 | ||
|
|
9b4b4a581b | ||
|
|
bcff14b596 | ||
|
|
11f6278d95 | ||
|
|
ede9405daf | ||
|
|
25bf0e9e2c | ||
|
|
167a7ee80c | ||
|
|
4ce4162da4 | ||
|
|
18b074711e | ||
|
|
44b6a2c453 | ||
|
|
3fc3130364 | ||
|
|
5090395ca7 | ||
|
|
efd4373a56 | ||
|
|
92a31ff7df | ||
|
|
8025c2ae66 | ||
|
|
f7831ce8da | ||
|
|
b736fa22ff | ||
|
|
0692d1d28c | ||
|
|
4b69d5cc8a | ||
|
|
52aa518e20 | ||
|
|
919a5dba89 | ||
|
|
d9932b9031 | ||
|
|
66e521e9e5 | ||
|
|
b8e425b41d | ||
|
|
6b0658fb59 | ||
|
|
91fdfcd179 | ||
|
|
5abebcf61f | ||
|
|
145473d9bd | ||
|
|
2fb64816a9 | ||
|
|
7cf330e3f9 | ||
|
|
2e66515096 | ||
|
|
c93f377bfb | ||
|
|
d6d1844d60 | ||
|
|
fd38a3dbc4 | ||
|
|
60d58723aa | ||
|
|
a9b6cda77b | ||
|
|
091452d591 | ||
|
|
df1d909853 | ||
|
|
fb4e08ce71 | ||
|
|
7244b9d17e | ||
|
|
5c4ca36c5a | ||
|
|
292c297518 | ||
|
|
a5bb431d47 | ||
|
|
10e1c9d187 | ||
|
|
d8722b6705 | ||
|
|
2d0ac7eeb0 | ||
|
|
d5033a2bd9 | ||
|
|
45fff0fd58 | ||
|
|
c963c7b1c7 | ||
|
|
63c7835e71 | ||
|
|
35af3185eb | ||
|
|
db9d9c7653 | ||
|
|
9e5a9107f2 | ||
|
|
275fcf8fcf | ||
|
|
bc37b0ece6 | ||
|
|
e63ce24e48 | ||
|
|
d524884799 | ||
|
|
34e1f8dcc5 | ||
|
|
cd64de9323 | ||
|
|
a01b805e4b | ||
|
|
a139cbc744 | ||
|
|
06e5386d93 | ||
|
|
37f57a752f | ||
|
|
670bdf2095 | ||
|
|
6270f654a1 | ||
|
|
676db46c01 | ||
|
|
8979b54281 | ||
|
|
a6f03530ed | ||
|
|
b56b56a695 | ||
|
|
dc5fc9f327 | ||
|
|
3d35457eeb | ||
|
|
aea39ec8c8 | ||
|
|
9293068370 | ||
|
|
d054f07703 | ||
|
|
65b0b49720 | ||
|
|
48d58ba095 | ||
|
|
af0505b4cd | ||
|
|
7c1e1fe515 | ||
|
|
d053025070 | ||
|
|
ade898d815 | ||
|
|
e738b90c69 | ||
|
|
a91d26192d |
+10
-1
@@ -1,5 +1,6 @@
|
|||||||
[*]
|
|
||||||
root = true
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
indent_size = tab
|
indent_size = tab
|
||||||
tab_width = 4
|
tab_width = 4
|
||||||
@@ -7,3 +8,11 @@ charset = utf-8
|
|||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
end_of_line = lf
|
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)
|
# Shell scripts need Unix line endings (see https://github.com/gbdev/rgbds/issues/841)
|
||||||
*.sh text eol=lf
|
*.sh text eol=lf
|
||||||
*.bash 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 also need Unix line endings (see https://github.com/gbdev/rgbds/issues/955)
|
||||||
*.flags text eol=lf
|
*.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.53
|
|
||||||
|
|
||||||
## 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)" != 1d3fb8ccc2932d04aa3663e22ef5ef490244370f4e568d7850165068778d98d4 ]; 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
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
declare -A FILES
|
declare -A FILES
|
||||||
while read -r -d '' file; do
|
while IFS= read -r -d '' file; do
|
||||||
FILES["$file"]="true"
|
FILES["$file"]=true
|
||||||
done < <(git diff --name-only -z "$1" HEAD)
|
done < <(git diff --name-only -z "$1" HEAD)
|
||||||
|
|
||||||
edited () {
|
edited () {
|
||||||
${FILES["$1"]:-"false"}
|
${FILES["$1"]:-false}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependency () {
|
dependency () {
|
||||||
if edited "$1" && ! edited "$2"; then
|
if edited "$1" && ! edited "$2"; then
|
||||||
echo "'$1' was modified, but not '$2'! $3" | xargs
|
echo "'$1' was modified, but not '$2'! $3"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,15 +79,15 @@ dependency src/gfx/main.cpp contrib/zsh_compl/_rgbgfx \
|
|||||||
dependency src/gfx/main.cpp contrib/bash_compl/_rgbgfx.bash \
|
dependency src/gfx/main.cpp contrib/bash_compl/_rgbgfx.bash \
|
||||||
"Did the rgbgfx CLI change?"
|
"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?"
|
"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?"
|
"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?"
|
"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?"
|
"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?"
|
"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?"
|
"Did the RGBGFX test protocol change?"
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
clang-format --version
|
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
|
if ! git diff-index --quiet HEAD --; then
|
||||||
echo 'Unformatted files:'
|
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.53.zip' 'libpng.zip' '9fb99118ec4523d9a9dab652ce7c2472ec76f6ccd69d1aba3ab873bb8cf84b98' .
|
|
||||||
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.53 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.53
|
|
||||||
arch="$1"
|
|
||||||
|
|
||||||
## Grab sources and check them
|
|
||||||
|
|
||||||
wget http://downloads.sourceforge.net/project/libpng/libpng16/$pngver/libpng-$pngver.tar.xz
|
|
||||||
echo 1d3fb8ccc2932d04aa3663e22ef5ef490244370f4e568d7850165068778d98d4 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:
|
tags:
|
||||||
- '*'
|
- '*'
|
||||||
|
|
||||||
|
env:
|
||||||
|
# Force colored output (see https://bixense.com/clicolors/ and https://force-color.org/)
|
||||||
|
TERM: xterm-256color
|
||||||
|
CLICOLOR: 1
|
||||||
|
CLICOLOR_FORCE: 1
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish-docker-image:
|
publish-docker-image:
|
||||||
if: github.repository_owner == 'gbdev'
|
if: github.repository_owner == 'gbdev'
|
||||||
@@ -14,10 +20,10 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
@@ -43,7 +49,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Delete untagged container images
|
- name: Delete untagged container images
|
||||||
if: github.repository_owner == 'gbdev'
|
if: github.repository_owner == 'gbdev'
|
||||||
uses: Chizkiyahu/delete-untagged-ghcr-action@v5
|
uses: Chizkiyahu/delete-untagged-ghcr-action@v6
|
||||||
with:
|
with:
|
||||||
# Requires a personal access token with delete:packages permissions
|
# Requires a personal access token with delete:packages permissions
|
||||||
token: ${{ secrets.PAT_TOKEN }}
|
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
|
- push
|
||||||
- pull_request
|
- 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:
|
jobs:
|
||||||
coverage:
|
coverage:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
./.github/scripts/install_deps.sh ubuntu
|
.github/scripts/install-deps.sh ubuntu-latest lcov
|
||||||
- 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
|
|
||||||
- name: Generate coverage report
|
- name: Generate coverage report
|
||||||
run: |
|
run: |
|
||||||
contrib/coverage.bash ubuntu-ci
|
contrib/coverage.bash --os ubuntu-latest --jobs "$(getconf _NPROCESSORS_ONLN)"
|
||||||
- name: Upload coverage report
|
- name: Upload coverage report
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: coverage-report
|
name: coverage-report
|
||||||
# Workaround for keeping the top-level coverage/ directory
|
# Workaround for keeping the top-level coverage/ directory
|
||||||
@@ -32,3 +30,4 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
coverage
|
coverage
|
||||||
dummy-file-to-keep-directory-structure.txt
|
dummy-file-to-keep-directory-structure.txt
|
||||||
|
if-no-files-found: error
|
||||||
|
|||||||
@@ -4,162 +4,122 @@ on:
|
|||||||
tags:
|
tags:
|
||||||
- v[0-9]*
|
- 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:
|
jobs:
|
||||||
windows:
|
windows:
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
bits: [32, 64]
|
bits: [32, 64]
|
||||||
include:
|
|
||||||
- bits: 32
|
|
||||||
arch: x86
|
|
||||||
platform: Win32
|
|
||||||
- bits: 64
|
|
||||||
arch: x86_x64
|
|
||||||
platform: x64
|
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
steps:
|
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
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
- name: Install deps
|
- 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: |
|
run: |
|
||||||
cmake --install zbuild
|
bash .github/scripts/install-deps.sh windows
|
||||||
- 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
|
- name: Build Windows binaries
|
||||||
shell: bash
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
cmake -S . -B build -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release
|
call .github\scripts\msvc-env.bat ${{ matrix.bits }}
|
||||||
cmake --build build --config Release -j --verbose
|
cmake -B build -G Ninja -DFETCHCONTENT_BASE_DIR="${{ env.DEPS_ROOT_DIR }}" -DCMAKE_C_FLAGS="/nologo"
|
||||||
cmake --install build --verbose --prefix install_dir --strip
|
cmake --build build -- -k 0
|
||||||
- name: Package binaries
|
- name: Package binaries
|
||||||
|
working-directory: build
|
||||||
run: |
|
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
|
- name: Upload Windows binaries
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: win${{ matrix.bits }}
|
name: win${{ matrix.bits }}
|
||||||
path: rgbds-win${{ matrix.bits }}.zip
|
path: build/rgbds-win${{ matrix.bits }}.zip
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
macos:
|
macos:
|
||||||
runs-on: macos-14
|
runs-on: macos-26
|
||||||
steps:
|
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
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
./.github/scripts/install_deps.sh macos
|
./.github/scripts/install-deps.sh macos lld
|
||||||
- name: Build libpng
|
|
||||||
run: |
|
|
||||||
./.github/scripts/build_libpng.sh
|
|
||||||
# We force linking libpng statically; the other libs are provided by macOS itself
|
|
||||||
- name: Build binaries
|
- name: Build binaries
|
||||||
run: |
|
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}
|
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
|
- name: Package binaries
|
||||||
run: |
|
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
|
- name: Upload macOS binaries
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: macos
|
name: macos
|
||||||
path: rgbds-macos.zip
|
path: rgbds-macos.zip
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
linux:
|
linux:
|
||||||
runs-on: ubuntu-22.04 # Oldest supported, for best glibc compatibility.
|
runs-on: ubuntu-22.04 # Oldest supported, for best glibc compatibility.
|
||||||
steps:
|
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
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
./.github/scripts/install_deps.sh ubuntu-22.04
|
./.github/scripts/install-deps.sh ubuntu-22.04
|
||||||
- name: Build binaries
|
- name: Build binaries
|
||||||
run: |
|
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}
|
strip rgb{asm,link,fix,gfx}
|
||||||
|
- name: Create install script
|
||||||
|
run: |
|
||||||
|
make install.sh Q=
|
||||||
- name: Package binaries
|
- name: Package binaries
|
||||||
run: |
|
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
|
- name: Upload Linux binaries
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: linux
|
name: linux
|
||||||
path: rgbds-linux-x86_64.tar.xz
|
path: rgbds-linux-x86_64.tar.xz
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
release:
|
release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-slim
|
||||||
needs: [windows, macos, linux]
|
needs: [windows, macos, linux]
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
steps:
|
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
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
- name: Package sources
|
- name: Package sources
|
||||||
run: |
|
run: |
|
||||||
make dist Q=
|
make dist Q=
|
||||||
ls
|
- name: Download all binary packages
|
||||||
- name: Download Linux binaries
|
uses: actions/download-artifact@v8
|
||||||
uses: actions/download-artifact@v4
|
- name: Draft the release
|
||||||
- name: Release
|
run: |
|
||||||
uses: softprops/action-gh-release@v2
|
.github/scripts/draft-release.sh "${ref#refs/tags/}"
|
||||||
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
|
|
||||||
env:
|
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:
|
types:
|
||||||
- released # This avoids triggering on pre-releases
|
- 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:
|
jobs:
|
||||||
build:
|
build:
|
||||||
if: github.repository_owner == 'gbdev'
|
if: github.repository_owner == 'gbdev'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-slim
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout rgbds@release
|
- name: Checkout rgbds@release
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
path: rgbds
|
path: rgbds
|
||||||
- name: Checkout rgbds-www@master
|
sparse-checkout: man # Avoid checking out other files, we don't use them here.
|
||||||
uses: actions/checkout@v4
|
- name: Checkout rgbds-www
|
||||||
|
uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
repository: ${{ github.repository_owner }}/rgbds-www
|
|
||||||
path: 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
|
- name: Install groff and mandoc
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get -qq update
|
sudo apt install -Uyq groff mandoc -o APT::Color=yes -o Acquire::Queue-Mode=access
|
||||||
sudo apt-get install -yq groff mandoc
|
|
||||||
- name: Update pages
|
- name: Update pages
|
||||||
working-directory: rgbds/man
|
working-directory: rgbds/man
|
||||||
run: | # The ref appears to be in the format "refs/tags/<version>", so strip that
|
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##*/}
|
../../rgbds-www/maintainer/new_release.sh ${GITHUB_REF##*/}
|
||||||
- name: Push new pages
|
- name: Push new pages
|
||||||
working-directory: rgbds-www
|
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: |
|
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 add -A
|
||||||
git commit -m "Create RGBDS ${GITHUB_REF##*/} documentation"
|
git commit -m "Create RGBDS ${GITHUB_REF##*/} documentation"
|
||||||
if git remote | grep -q origin; then
|
git push
|
||||||
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
|
|
||||||
|
|||||||
+249
-187
@@ -3,57 +3,102 @@ on:
|
|||||||
- push
|
- push
|
||||||
- pull_request
|
- 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:
|
jobs:
|
||||||
unix:
|
unix:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-22.04, macos-14]
|
os: [ubuntu-22.04, macos-15-intel, macos-26]
|
||||||
cxx: [g++, clang++]
|
cxx: [g++, clang++]
|
||||||
buildsys: [make, cmake]
|
buildsys: [make, cmake]
|
||||||
exclude:
|
exclude: # Don't use `g++` on macOS; it's just an alias to `clang++`.
|
||||||
# Don't use `g++` on macOS; it's just an alias to `clang++`.
|
- { os: macos-15-intel, cxx: g++ }
|
||||||
- os: macos-14
|
- { os: macos-26, cxx: g++ }
|
||||||
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
|
fail-fast: false
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
./.github/scripts/install_deps.sh ${{ matrix.os }}
|
.github/scripts/install-deps.sh ${{ matrix.os }} ${{ matrix.cxx }}
|
||||||
- name: Build & install using Make
|
- name: Build using Make
|
||||||
if: matrix.buildsys == 'make'
|
if: matrix.buildsys == 'make'
|
||||||
run: |
|
run: |
|
||||||
make develop -kj Q= CXX=${{ matrix.cxx }}
|
make develop -k -j "$(getconf _NPROCESSORS_ONLN)" Q= CXX=${{ matrix.cxx }}
|
||||||
sudo make install -j Q=
|
- name: Install using Make
|
||||||
- name: Build & install using CMake
|
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'
|
if: matrix.buildsys == 'cmake'
|
||||||
run: |
|
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
|
sudo cmake --install build --verbose
|
||||||
|
type rgbasm rgblink rgbfix rgbgfx
|
||||||
|
man -w 1 rgbasm rgblink rgbfix rgbgfx
|
||||||
- name: Package binaries
|
- name: Package binaries
|
||||||
run: |
|
run: |
|
||||||
mkdir bins
|
mkdir bins
|
||||||
cp rgb{asm,link,fix,gfx} bins
|
cp rgb{asm,link,fix,gfx} bins
|
||||||
- name: Upload binaries
|
- name: Upload binaries
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: rgbds-canary-${{ matrix.os }}-${{ matrix.cxx }}-${{ matrix.buildsys }}
|
name: rgbds-canary-${{ matrix.os }}-${{ matrix.cxx }}-${{ matrix.buildsys }}
|
||||||
path: bins
|
path: bins
|
||||||
|
if-no-files-found: error
|
||||||
- name: Compute test dependency cache params
|
- name: Compute test dependency cache params
|
||||||
id: test-deps-cache-params
|
id: test-deps-cache-params
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
paths=$(test/fetch-test-deps.sh --get-paths)
|
paths=$(test/external/fetch-repos.sh --get-paths)
|
||||||
hash=$(test/fetch-test-deps.sh --get-hash)
|
hash=$(test/external/fetch-repos.sh --get-hash)
|
||||||
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
|
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
|
||||||
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
|
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
|
||||||
- name: Check test dependency repositories cache
|
- name: Check test dependency repositories cache
|
||||||
id: test-deps-cache
|
id: test-deps-cache
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
|
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
|
||||||
key: ${{ matrix.os }}-${{ steps.test-deps-cache-params.outputs.hash }}
|
key: ${{ matrix.os }}-${{ steps.test-deps-cache-params.outputs.hash }}
|
||||||
@@ -61,211 +106,179 @@ jobs:
|
|||||||
if: steps.test-deps-cache.outputs.cache-hit != 'true'
|
if: steps.test-deps-cache.outputs.cache-hit != 'true'
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
run: |
|
run: |
|
||||||
test/fetch-test-deps.sh
|
test/external/fetch-repos.sh
|
||||||
- name: Install test dependency dependencies
|
- name: Run tests using our script
|
||||||
shell: bash
|
if: matrix.buildsys == 'make'
|
||||||
run: |
|
run: |
|
||||||
test/fetch-test-deps.sh --get-deps ${{ matrix.os }}
|
CXX=${{ matrix.cxx }} test/run-tests.sh --os ${{ matrix.os }} --jobs "$(getconf _NPROCESSORS_ONLN)"
|
||||||
- name: Run tests
|
- name: Run tests using CTest
|
||||||
shell: bash
|
if: matrix.buildsys == 'cmake'
|
||||||
run: |
|
run: |
|
||||||
CXX=${{ matrix.cxx }} test/run-tests.sh --os ${{ matrix.os }}
|
ctest --test-dir build --schedule-random
|
||||||
|
|
||||||
macos-static:
|
macos-static:
|
||||||
runs-on: macos-14
|
runs-on: macos-26
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
./.github/scripts/install_deps.sh macos
|
.github/scripts/install-deps.sh macos lld
|
||||||
- name: Build libpng
|
- 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: |
|
run: |
|
||||||
./.github/scripts/build_libpng.sh
|
cmake -B build -G Ninja --preset macos-static -DFETCHCONTENT_BASE_DIR="${{ env.DEPS_ROOT_DIR }}"
|
||||||
- name: Build & install
|
cmake --build build -- -k 0
|
||||||
|
env:
|
||||||
|
LDFLAGS: -fuse-ld=lld # cmake/macos-static.cmake comments explain why we use lld.
|
||||||
|
- name: Install
|
||||||
run: |
|
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
|
- name: Package binaries
|
||||||
run: |
|
run: |
|
||||||
mkdir bins
|
mkdir bins
|
||||||
cp rgb{asm,link,fix,gfx} bins
|
cp rgb{asm,link,fix,gfx} bins
|
||||||
- name: Upload binaries
|
- name: Upload binaries
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: rgbds-canary-macos-static
|
name: rgbds-canary-macos-static
|
||||||
path: bins
|
path: bins
|
||||||
|
if-no-files-found: error
|
||||||
- name: Compute test dependency cache params
|
- name: Compute test dependency cache params
|
||||||
id: test-deps-cache-params
|
id: test-deps-cache-params
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
paths=$(test/fetch-test-deps.sh --get-paths)
|
paths=$(test/external/fetch-repos.sh --get-paths)
|
||||||
hash=$(test/fetch-test-deps.sh --get-hash)
|
hash=$(test/external/fetch-repos.sh --get-hash)
|
||||||
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
|
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
|
||||||
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
|
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
|
||||||
- name: Check test dependency repositories cache
|
- name: Check test dependency repositories cache
|
||||||
id: test-deps-cache
|
id: test-deps-cache
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
|
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
|
- name: Fetch test dependency repositories
|
||||||
if: steps.test-deps-cache.outputs.cache-hit != 'true'
|
if: steps.test-deps-cache.outputs.cache-hit != 'true'
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
run: |
|
run: |
|
||||||
test/fetch-test-deps.sh
|
test/external/fetch-repos.sh
|
||||||
- name: Install test dependency dependencies
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
test/fetch-test-deps.sh --get-deps macos
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
test/run-tests.sh --os macos
|
ctest --test-dir build --schedule-random
|
||||||
|
|
||||||
windows:
|
windows:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
bits: [32, 64]
|
bits: [32, 64]
|
||||||
os: [windows-2022, windows-2025]
|
os: [windows-2022, windows-2025]
|
||||||
include:
|
|
||||||
- bits: 32
|
|
||||||
arch: x86
|
|
||||||
platform: Win32
|
|
||||||
- bits: 64
|
|
||||||
arch: x86_x64
|
|
||||||
platform: x64
|
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
run: .github/scripts/get_win_deps.ps1
|
run: |
|
||||||
- name: Check libraries cache
|
bash .github/scripts/install-deps.sh ${{ matrix.os }}
|
||||||
id: cache
|
- name: Cache library deps
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
path: |
|
path: ${{ env.DEPS_ROOT_DIR }}/*-tmp/
|
||||||
zbuild
|
key: dep-srcs-${{ hashFiles('cmake/deps.cmake') }}
|
||||||
pngbuild
|
enableCrossOsArchive: true
|
||||||
key: ${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles('zlib/**', 'libpng/**') }}
|
- name: Build
|
||||||
- name: Build zlib
|
shell: cmd
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
run: | # ASan seems to be broken on Windows, so we disable it.
|
||||||
shell: bash
|
call .github\scripts\msvc-env.bat ${{ matrix.bits }}
|
||||||
run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll`
|
cmake -B build -G Ninja --preset develop -DFETCHCONTENT_BASE_DIR="${{ env.DEPS_ROOT_DIR }}" ^
|
||||||
cmake -S zlib -B zbuild -A ${{ matrix.platform }} -Wno-dev -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
|
-DSANITIZERS=OFF -DCMAKE_C_FLAGS="/nologo"
|
||||||
cmake --build zbuild --config Release -j
|
cmake --build build -- -k 0
|
||||||
- name: Install zlib
|
- name: Install
|
||||||
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
cmake --install zbuild
|
cmake --install build --verbose
|
||||||
- name: Build libpng
|
where rgbasm rgblink rgbfix rgbgfx
|
||||||
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
|
|
||||||
- name: Package binaries
|
- name: Package binaries
|
||||||
shell: bash
|
working-directory: build
|
||||||
run: |
|
run: |
|
||||||
mkdir bins
|
cpack -DCPACK_PACKAGE_FILE_NAME=rgbds-win${{ matrix.bits }} -G ZIP --verbose
|
||||||
cp install_dir/bin/{rgbasm.exe,rgblink.exe,rgbfix.exe,rgbgfx.exe,zlib1.dll,libpng16.dll} bins
|
|
||||||
- name: Upload Windows binaries
|
- name: Upload Windows binaries
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: rgbds-canary-w${{ matrix.bits }}-${{ matrix.os }}
|
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
|
- name: Compute test dependency cache params
|
||||||
id: test-deps-cache-params
|
id: test-deps-cache-params
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
paths=$(test/fetch-test-deps.sh --get-paths)
|
paths=$(test/external/fetch-repos.sh --get-paths)
|
||||||
hash=$(test/fetch-test-deps.sh --get-hash)
|
hash=$(test/external/fetch-repos.sh --get-hash)
|
||||||
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
|
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
|
||||||
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
|
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
|
||||||
- name: Check test dependency repositories cache
|
- name: Check test dependency repositories cache
|
||||||
id: test-deps-cache
|
id: test-deps-cache
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
|
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
|
||||||
key: ${{ matrix.os }}-${{ matrix.bits }}-${{ steps.test-deps-cache-params.outputs.hash }}
|
key: ${{ matrix.os }}-${{ matrix.bits }}-${{ steps.test-deps-cache-params.outputs.hash }}
|
||||||
- name: Fetch test dependency repositories
|
- name: Fetch test dependency repositories
|
||||||
if: steps.test-deps-cache.outputs.cache-hit != 'true'
|
if: steps.test-deps-cache.outputs.cache-hit != 'true'
|
||||||
shell: bash
|
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
run: |
|
run: |
|
||||||
test/fetch-test-deps.sh
|
test/external/fetch-repos.sh
|
||||||
- name: Install test dependency dependencies
|
- name: Run tests using CTest
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
test/fetch-test-deps.sh --get-deps ${{ matrix.os }}
|
ctest --test-dir build --schedule-random
|
||||||
- name: Run tests
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
cp bins/* .
|
|
||||||
cp bins/*.dll test/gfx
|
|
||||||
test/run-tests.sh --os ${{ matrix.os }}
|
|
||||||
|
|
||||||
windows-mingw-build:
|
windows-mingw-build:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
bits: [32, 64]
|
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
|
fail-fast: false
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
env:
|
|
||||||
DIST_DIR: win${{ matrix.bits }}
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
./.github/scripts/install_deps.sh ubuntu
|
.github/scripts/install-deps.sh ubuntu mingw${{ matrix.bits }}
|
||||||
- name: Install MinGW
|
- name: Cache library deps
|
||||||
run: | # dpkg-dev is apparently required for pkg-config for cross-building
|
uses: actions/cache@v5
|
||||||
sudo apt-get install g++-mingw-w64-${{ matrix.arch }}-win32 mingw-w64-tools libz-mingw-w64-dev dpkg-dev
|
with:
|
||||||
- name: Install libpng dev headers for MinGW
|
path: ${{ env.DEPS_ROOT_DIR }}/*-tmp/
|
||||||
run: |
|
key: dep-srcs-${{ hashFiles('cmake/deps.cmake') }}
|
||||||
./.github/scripts/mingw-w64-libpng-dev.sh ${{ matrix.triplet }}
|
enableCrossOsArchive: true
|
||||||
- name: Cross-build Windows binaries
|
- 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: |
|
run: |
|
||||||
make mingw${{ matrix.bits }} -kj Q=
|
cmake --install build --prefix . --verbose --component binaries
|
||||||
- name: Package binaries
|
cmake --install build --prefix . --verbose --component shared-libs
|
||||||
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
|
|
||||||
- name: Upload Windows binaries
|
- name: Upload Windows binaries
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: rgbds-canary-mingw-win${{ matrix.bits }}
|
name: rgbds-canary-mingw-win${{ matrix.bits }}
|
||||||
path: bins
|
path: bin
|
||||||
|
if-no-files-found: error
|
||||||
- name: Upload Windows test binaries
|
- name: Upload Windows test binaries
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: testing-programs-mingw-win${{ matrix.bits }}
|
name: testing-programs-mingw-win${{ matrix.bits }}
|
||||||
path: |
|
path: |
|
||||||
test/gfx/randtilegen.exe
|
test/gfx/randtilegen.exe
|
||||||
test/gfx/rgbgfx_test.exe
|
test/gfx/rgbgfx_test.exe
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
windows-mingw-testing:
|
windows-mingw-testing:
|
||||||
needs: windows-mingw-build
|
needs: windows-mingw-build
|
||||||
@@ -277,113 +290,162 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- 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
|
- name: Retrieve binaries
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v8
|
||||||
with:
|
with:
|
||||||
name: rgbds-canary-mingw-win${{ matrix.bits }}
|
name: rgbds-canary-mingw-win${{ matrix.bits }}
|
||||||
path: bins
|
path: bins
|
||||||
- name: Retrieve test binaries
|
- name: Retrieve test binaries
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v8
|
||||||
with:
|
with:
|
||||||
name: testing-programs-mingw-win${{ matrix.bits }}
|
name: testing-programs-mingw-win${{ matrix.bits }}
|
||||||
path: test/gfx
|
path: test/gfx
|
||||||
- name: Extract binaries
|
- name: Extract binaries
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
cp bins/* .
|
cp bins/* .
|
||||||
cp bins/*.dll test/gfx
|
cp bins/*.dll test/gfx
|
||||||
- name: Compute test dependency cache params
|
- name: Compute test dependency cache params
|
||||||
id: test-deps-cache-params
|
id: test-deps-cache-params
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
paths=$(test/fetch-test-deps.sh --get-paths)
|
paths=$(test/external/fetch-repos.sh --get-paths)
|
||||||
hash=$(test/fetch-test-deps.sh --get-hash)
|
hash=$(test/external/fetch-repos.sh --get-hash)
|
||||||
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
|
tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
|
||||||
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
|
tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
|
||||||
- name: Check test dependency repositories cache
|
- name: Check test dependency repositories cache
|
||||||
id: test-deps-cache
|
id: test-deps-cache
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
|
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
|
||||||
key: mingw-${{ matrix.bits }}-${{ steps.test-deps-cache-params.outputs.hash }}
|
key: mingw-${{ matrix.bits }}-${{ steps.test-deps-cache-params.outputs.hash }}
|
||||||
- name: Fetch test dependency repositories
|
- name: Fetch test dependency repositories
|
||||||
if: steps.test-deps-cache.outputs.cache-hit != 'true'
|
if: steps.test-deps-cache.outputs.cache-hit != 'true'
|
||||||
shell: bash
|
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
run: |
|
run: |
|
||||||
test/fetch-test-deps.sh
|
test/external/fetch-repos.sh
|
||||||
- name: Install test dependency dependencies
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
test/fetch-test-deps.sh --get-deps ${{ matrix.os }}
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
test/run-tests.sh --os ${{ matrix.os }}
|
test/run-tests.sh --os ${{ matrix.os }} --jobs "$(getconf _NPROCESSORS_ONLN)"
|
||||||
|
|
||||||
cygwin:
|
cygwin:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
bits: [32, 64]
|
arch: [x86, x86_64]
|
||||||
include:
|
|
||||||
- bits: 32
|
|
||||||
arch: x86
|
|
||||||
- bits: 64
|
|
||||||
arch: x86_64
|
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
|
env:
|
||||||
|
CYGWIN_NOWINPATH: 1
|
||||||
|
CHERE_INVOKING: 1
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: C:\cygwin\bin\bash.exe -leo igncr '{0}'
|
||||||
steps:
|
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
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
fetch-tags: true
|
|
||||||
- name: Setup Cygwin
|
- name: Setup Cygwin
|
||||||
uses: cygwin/cygwin-install-action@v4
|
uses: cygwin/cygwin-install-action@v6
|
||||||
with:
|
with:
|
||||||
platform: ${{ matrix.arch }}
|
platform: ${{ matrix.arch }}
|
||||||
packages: >-
|
packages: >-
|
||||||
bison
|
bison
|
||||||
|
cmake
|
||||||
gcc-g++
|
gcc-g++
|
||||||
git
|
git
|
||||||
libpng-devel
|
libpng-devel
|
||||||
make
|
make
|
||||||
|
ninja
|
||||||
pkg-config
|
pkg-config
|
||||||
- name: Build & install using Make
|
python3
|
||||||
shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -o igncr '{0}'
|
python-imaging
|
||||||
run: | # Cygwin does not support `make develop` sanitizers ASan or UBSan
|
- name: Build using Make
|
||||||
make -kj Q=
|
if: matrix.arch == 'x86'
|
||||||
make install -j Q=
|
run: | # Cygwin doesn't support `make develop` sanitizers ASan or UBSan, so we don't use it.
|
||||||
- name: Run tests
|
make -k -j "$(getconf _NPROCESSORS_ONLN)" Q=
|
||||||
shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -o igncr '{0}'
|
- name: Install using Make
|
||||||
|
if: matrix.arch == 'x86'
|
||||||
run: |
|
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:
|
freebsd:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
fetch-tags: true
|
|
||||||
- name: Build & test using CMake on FreeBSD
|
- name: Build & test using CMake on FreeBSD
|
||||||
uses: vmactions/freebsd-vm@v1
|
uses: vmactions/freebsd-vm@v1
|
||||||
with:
|
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
|
usesh: true
|
||||||
|
copyback: false
|
||||||
prepare: |
|
prepare: |
|
||||||
pkg install -y \
|
.github/scripts/install-deps.sh freebsd
|
||||||
bash \
|
run: |
|
||||||
bison \
|
: # Build
|
||||||
cmake \
|
cmake -B build -G Ninja --preset develop
|
||||||
git \
|
cmake --build build -- -k 0
|
||||||
png
|
: # Install
|
||||||
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
|
|
||||||
cmake --install build --verbose
|
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:
|
branches:
|
||||||
- master
|
- master
|
||||||
paths:
|
paths:
|
||||||
- man/gbz80.7
|
- man/*
|
||||||
- man/rgbds.5
|
workflow_dispatch:
|
||||||
- man/rgbds.7
|
|
||||||
- man/rgbasm.1
|
env:
|
||||||
- man/rgbasm.5
|
# Force colored output (see https://bixense.com/clicolors/ and https://force-color.org/)
|
||||||
- man/rgbasm-old.5
|
TERM: xterm-256color
|
||||||
- man/rgblink.1
|
CLICOLOR: 1
|
||||||
- man/rgblink.5
|
CLICOLOR_FORCE: 1
|
||||||
- man/rgbfix.1
|
|
||||||
- man/rgbgfx.1
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
if: github.repository_owner == 'gbdev'
|
if: github.repository_owner == 'gbdev'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-slim
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout rgbds@master
|
- name: Checkout rgbds
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
repository: gbdev/rgbds
|
|
||||||
ref: master
|
|
||||||
path: rgbds
|
path: rgbds
|
||||||
- name: Checkout rgbds-www@master
|
sparse-checkout: man # Avoid checking out other files, we don't use them here.
|
||||||
uses: actions/checkout@v4
|
- name: Checkout rgbds-www
|
||||||
|
uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
repository: gbdev/rgbds-www
|
|
||||||
ref: master
|
|
||||||
path: 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
|
- name: Install groff and mandoc
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get -qq update
|
sudo apt install -Uyq groff mandoc -o APT::Color=yes -o Acquire::Queue-Mode=access
|
||||||
sudo apt-get install -yq groff mandoc
|
|
||||||
- name: Update pages
|
- name: Update pages
|
||||||
working-directory: rgbds/man
|
working-directory: rgbds/man
|
||||||
run: |
|
run: |
|
||||||
../../rgbds-www/maintainer/man_to_html.sh master *
|
../../rgbds-www/maintainer/man_to_html.sh master *
|
||||||
- name: Push new pages
|
- name: Push new pages
|
||||||
working-directory: rgbds-www
|
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: |
|
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 add -A
|
||||||
git commit -m "Update RGBDS master documentation"
|
git commit -m "Update RGBDS master documentation"
|
||||||
if git remote | grep -q origin; then
|
git push
|
||||||
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
|
|
||||||
|
|||||||
+4
-1
@@ -2,6 +2,7 @@
|
|||||||
/rgblink
|
/rgblink
|
||||||
/rgbfix
|
/rgbfix
|
||||||
/rgbgfx
|
/rgbgfx
|
||||||
|
/install.sh
|
||||||
/rgbshim.sh
|
/rgbshim.sh
|
||||||
/coverage/
|
/coverage/
|
||||||
*.o
|
*.o
|
||||||
@@ -10,9 +11,11 @@
|
|||||||
*.gcno
|
*.gcno
|
||||||
*.gcda
|
*.gcda
|
||||||
*.gcov
|
*.gcov
|
||||||
|
/compile_flags.txt
|
||||||
CMakeCache.txt
|
CMakeCache.txt
|
||||||
CMakeFiles/
|
CMakeFiles/
|
||||||
cmake_install.cmake
|
cmake_install.cmake
|
||||||
build/
|
CMakeUserPresets.json
|
||||||
|
build*/
|
||||||
*.dSYM/
|
*.dSYM/
|
||||||
callgrind.out.*
|
callgrind.out.*
|
||||||
|
|||||||
+190
-93
@@ -1,122 +1,199 @@
|
|||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
# 3.9 required for LTO checks
|
# - 3.24 is required for `FetchContent`'s `find_package` integration.
|
||||||
# 3.17 optional for CMAKE_CTEST_ARGUMENTS
|
# Older versions *may* work, but we can't test them; compat patches are welcome.
|
||||||
cmake_minimum_required(VERSION 3.9..3.17 FATAL_ERROR)
|
# - 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
|
project(rgbds
|
||||||
LANGUAGES CXX)
|
VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}"
|
||||||
|
LANGUAGES CXX
|
||||||
include(CTest)
|
DESCRIPTION "Game Boy assembly toolchain"
|
||||||
|
HOMEPAGE_URL "https://rgbds.gbdev.io")
|
||||||
# get real path of source and binary directories
|
if(DEFINED VERSION_RC)
|
||||||
get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH)
|
string(APPEND CMAKE_PROJECT_VERSION "-rc${VERSION_RC}")
|
||||||
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")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(SANITIZERS "Build with sanitizers enabled" OFF) # Ignored on MSVC
|
# Reject in-source builds, as they may conflict with the Makefile.
|
||||||
option(MORE_WARNINGS "Turn on more warnings" OFF) # Ignored on MSVC
|
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)
|
include(CTest) # Note: CTest only functions properly if included from the top-level CMakeLists.
|
||||||
# MSVC's own standard library triggers warning C5105,
|
include(GNUInstallDirs)
|
||||||
# "macro expansion producing 'defined' has undefined behavior".
|
include(CMakeDependentOption)
|
||||||
# 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)
|
|
||||||
|
|
||||||
if(SANITIZERS)
|
## Compiler switches that should apply to our deps too.
|
||||||
set(SAN_FLAGS /fsanitize=address)
|
|
||||||
add_compile_options(${SAN_FLAGS})
|
option(SANITIZERS "Build with sanitizers enabled" OFF)
|
||||||
add_link_options(${SAN_FLAGS})
|
cmake_dependent_option(MORE_WARNINGS "Turn on more warnings" OFF "NOT MSVC" OFF)
|
||||||
endif()
|
|
||||||
else()
|
if(NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY) # Allow this to be overridden from the CLI easily.
|
||||||
add_compile_options(-Wall -pedantic)
|
# We link against the Microsoft C++ runtime libs statically, except the debug-mode one.
|
||||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
# This is because Microsoft's license terms (through some indirection) allow us to redistribute
|
||||||
# C++20 allows macros to take zero variadic arguments, but Clang (aka AppleClang on macOS)
|
# the runtime lib code *except* the debug-mode libs'.
|
||||||
# does not recognize this yet.
|
# Since we want to remain able to not think too hard about debug executables, we link against
|
||||||
add_compile_options(-Wno-gnu-zero-variadic-macro-arguments)
|
# the debug libs dynamically, shifting the burden of obtaining them onto the recipient.
|
||||||
endif()
|
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:DebugDLL>")
|
||||||
if(SANITIZERS)
|
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
|
set(SAN_FLAGS -fsanitize=address -fsanitize=undefined
|
||||||
-fsanitize=float-divide-by-zero)
|
-fsanitize=float-divide-by-zero)
|
||||||
add_compile_options(${SAN_FLAGS})
|
add_compile_options(${SAN_FLAGS})
|
||||||
add_link_options(${SAN_FLAGS})
|
add_link_options(${SAN_FLAGS})
|
||||||
add_definitions(-D_GLIBCXX_ASSERTIONS -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG)
|
add_definitions(-D_GLIBCXX_ASSERTIONS -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG)
|
||||||
# A non-zero optimization level is desired in debug mode, but allow overriding it nonetheless
|
# A non-zero optimization level is desired even in debug mode (especially for Clang),
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "-g -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls ${CMAKE_CXX_FLAGS_DEBUG}"
|
# and the two codegen flags improve the sanitizers' backtraces, but we want the user to
|
||||||
CACHE STRING "" FORCE)
|
# 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()
|
||||||
|
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)
|
if(MORE_WARNINGS)
|
||||||
add_compile_options(-Werror -Wextra
|
add_compile_options(-Wextra
|
||||||
-Walloc-zero -Wcast-align -Wcast-qual -Wduplicated-branches -Wduplicated-cond
|
-Walloc-zero -Wcast-align -Wcast-qual -Wduplicated-branches -Wduplicated-cond
|
||||||
-Wfloat-equal -Wlogical-op -Wnull-dereference -Wold-style-cast -Wshift-overflow=2
|
-Wfloat-equal -Wlogical-op -Wnull-dereference -Wold-style-cast -Wshift-overflow=2
|
||||||
-Wstringop-overflow=4 -Wtrampolines -Wundef -Wuninitialized -Wunused -Wshadow
|
-Wstringop-overflow=4 -Wtrampolines -Wundef -Wuninitialized -Wunused -Wshadow
|
||||||
-Wformat=2 -Wformat-overflow=2 -Wformat-truncation=1
|
-Wformat=2 -Wformat-overflow=2 -Wformat-truncation=1
|
||||||
-Wno-format-nonliteral -Wno-strict-overflow
|
-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
|
-Wno-type-limits -Wno-tautological-constant-out-of-range-compare
|
||||||
-Wvla # MSVC does not support VLAs
|
-Wvla) # MSVC does not support VLAs
|
||||||
-Wno-unknown-warning-option) # Clang shouldn't diagnose unknown warnings
|
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()
|
||||||
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)
|
add_subdirectory(src)
|
||||||
set(CMAKE_CTEST_ARGUMENTS "--verbose")
|
if(BUILD_TESTING) # This option is defined implicitly by `include(CTest)`.
|
||||||
add_subdirectory(test)
|
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()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(MANDIR "share/man")
|
|
||||||
set(man1 "man/rgbasm.1"
|
set(man1 "man/rgbasm.1"
|
||||||
"man/rgbfix.1"
|
"man/rgbfix.1"
|
||||||
"man/rgbgfx.1"
|
"man/rgbgfx.1"
|
||||||
@@ -129,6 +206,26 @@ set(man7 "man/gbz80.7"
|
|||||||
"man/rgbds.7")
|
"man/rgbds.7")
|
||||||
|
|
||||||
foreach(SECTION "man1" "man5" "man7")
|
foreach(SECTION "man1" "man5" "man7")
|
||||||
set(DEST "${MANDIR}/${SECTION}")
|
install(FILES ${${SECTION}} DESTINATION "${CMAKE_INSTALL_MANDIR}/${SECTION}" COMPONENT man)
|
||||||
install(FILES ${${SECTION}} DESTINATION ${DEST})
|
|
||||||
endforeach()
|
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
|
LABEL org.opencontainers.image.source=https://github.com/gbdev/rgbds
|
||||||
ARG version=1.0.1
|
ARG version=1.0.3
|
||||||
WORKDIR /rgbds
|
WORKDIR /rgbds
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install sudo make cmake gcc build-essential -y
|
apt-get install sudo make cmake gcc build-essential -y
|
||||||
|
RUN ./.github/scripts/install-deps.sh debian
|
||||||
|
|
||||||
# Install dependencies and compile RGBDS
|
# Build RGBDS
|
||||||
RUN ./.github/scripts/install_deps.sh ubuntu-22.04
|
RUN make -j "$(getconf _NPROCESSORS_ONLN)" CXXFLAGS="-O3 -flto -DNDEBUG -static" PKG_CONFIG="pkg-config --static" Q=
|
||||||
RUN make -j 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
|
# 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
|
# Install RGBDS on the container so all the executables will be available in the PATH
|
||||||
RUN cp man/* .
|
RUN cp man/* .
|
||||||
RUN ./.github/scripts/install.sh
|
RUN make install Q=
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
.SUFFIXES: .cpp .y .o
|
.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
|
# User-defined variables
|
||||||
|
|
||||||
@@ -15,6 +15,7 @@ SUFFIX :=
|
|||||||
STRIP := -s
|
STRIP := -s
|
||||||
BINMODE := 755
|
BINMODE := 755
|
||||||
MANMODE := 644
|
MANMODE := 644
|
||||||
|
MANSRC := man/
|
||||||
|
|
||||||
# Other variables
|
# Other variables
|
||||||
|
|
||||||
@@ -26,25 +27,25 @@ PNGLDLIBS := `${PKG_CONFIG} --libs-only-l libpng`
|
|||||||
# Note: if this comes up empty, `version.cpp` will automatically fall back to last release number
|
# 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`
|
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
|
# Overridable CXXFLAGS
|
||||||
CXXFLAGS ?= -O3 -flto -DNDEBUG
|
CXXFLAGS ?= -O3 -flto -DNDEBUG
|
||||||
# Non-overridable CXXFLAGS
|
# Non-overridable CXXFLAGS
|
||||||
REALCXXFLAGS := ${CXXFLAGS} ${WARNFLAGS} -std=c++20 -I include -fno-exceptions -fno-rtti
|
REQUIREDCXXFLAGS := -std=c++20 -I include -fno-exceptions -fno-rtti
|
||||||
|
REALCXXFLAGS := ${CXXFLAGS} ${WARNFLAGS} ${REQUIREDCXXFLAGS}
|
||||||
# Overridable LDFLAGS
|
# Overridable LDFLAGS
|
||||||
LDFLAGS ?=
|
LDFLAGS ?=
|
||||||
# Non-overridable 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
|
# Wrapper around bison that passes flags depending on what the version supports
|
||||||
BISON := src/bison.sh
|
BISON := src/bison.sh
|
||||||
|
|
||||||
RM := rm -rf
|
RM := rm -rf
|
||||||
|
|
||||||
# Used for checking pull requests
|
|
||||||
BASE_REF := origin/master
|
|
||||||
|
|
||||||
# Rules to build the RGBDS binaries
|
# Rules to build the RGBDS binaries
|
||||||
|
|
||||||
all: rgbasm rgblink rgbfix rgbgfx
|
all: rgbasm rgblink rgbfix rgbgfx
|
||||||
@@ -64,6 +65,7 @@ rgbasm_obj := \
|
|||||||
src/asm/fixpoint.o \
|
src/asm/fixpoint.o \
|
||||||
src/asm/format.o \
|
src/asm/format.o \
|
||||||
src/asm/fstack.o \
|
src/asm/fstack.o \
|
||||||
|
src/asm/intern.o \
|
||||||
src/asm/lexer.o \
|
src/asm/lexer.o \
|
||||||
src/asm/macro.o \
|
src/asm/macro.o \
|
||||||
src/asm/main.o \
|
src/asm/main.o \
|
||||||
@@ -182,6 +184,11 @@ src/gfx/rgba.o: src/gfx/rgba.cpp
|
|||||||
.cpp.o:
|
.cpp.o:
|
||||||
$Q${CXX} ${REALCXXFLAGS} -c -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
|
# Target used to remove all files generated by other Makefile targets
|
||||||
clean:
|
clean:
|
||||||
$Q${RM} rgbasm rgbasm.exe
|
$Q${RM} rgbasm rgbasm.exe
|
||||||
@@ -190,7 +197,7 @@ clean:
|
|||||||
$Q${RM} rgbgfx rgbgfx.exe
|
$Q${RM} rgbgfx rgbgfx.exe
|
||||||
$Qfind src/ -name "*.o" -exec rm {} \;
|
$Qfind src/ -name "*.o" -exec rm {} \;
|
||||||
$Qfind . -type f \( -name "*.gcno" -o -name "*.gcda" -o -name "*.gcov" \) -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/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} src/link/script.cpp src/link/script.hpp src/link/stack.hh
|
||||||
$Q${RM} test/gfx/randtilegen test/gfx/rgbgfx_test
|
$Q${RM} test/gfx/randtilegen test/gfx/rgbgfx_test
|
||||||
@@ -202,13 +209,9 @@ install: all
|
|||||||
$Qinstall ${STRIP} -m ${BINMODE} rgblink ${DESTDIR}${bindir}/rgblink${SUFFIX}
|
$Qinstall ${STRIP} -m ${BINMODE} rgblink ${DESTDIR}${bindir}/rgblink${SUFFIX}
|
||||||
$Qinstall ${STRIP} -m ${BINMODE} rgbfix ${DESTDIR}${bindir}/rgbfix${SUFFIX}
|
$Qinstall ${STRIP} -m ${BINMODE} rgbfix ${DESTDIR}${bindir}/rgbfix${SUFFIX}
|
||||||
$Qinstall ${STRIP} -m ${BINMODE} rgbgfx ${DESTDIR}${bindir}/rgbgfx${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} ${MANSRC}rgbasm.1 ${MANSRC}rgblink.1 ${MANSRC}rgbfix.1 ${MANSRC}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} ${MANSRC}rgbds.5 ${MANSRC}rgbasm.5 ${MANSRC}rgbasm-old.5 ${MANSRC}rgblink.5 ${DESTDIR}${mandir}/man5/
|
||||||
$Qinstall -m ${MANMODE} man/rgbds.7 man/gbz80.7 ${DESTDIR}${mandir}/man7/
|
$Qinstall -m ${MANMODE} ${MANSRC}rgbds.7 ${MANSRC}gbz80.7 ${DESTDIR}${mandir}/man7/
|
||||||
|
|
||||||
# Target used to check for suspiciously missing changed files.
|
|
||||||
checkdiff:
|
|
||||||
$Qcontrib/checkdiff.bash `git merge-base HEAD ${BASE_REF}`
|
|
||||||
|
|
||||||
# Target used in development to prevent adding new issues to the source code.
|
# 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
|
# All warnings are treated as errors to block the compilation and make the
|
||||||
@@ -232,23 +235,27 @@ debug:
|
|||||||
CXXFLAGS="-ggdb3 -O0 -fno-omit-frame-pointer -fno-optimize-sibling-calls"
|
CXXFLAGS="-ggdb3 -O0 -fno-omit-frame-pointer -fno-optimize-sibling-calls"
|
||||||
|
|
||||||
# Target used in development to profile with callgrind.
|
# Target used in development to profile with callgrind.
|
||||||
|
# Use `valgrind --tool=callgrind --dump-instr=yes --simulate-cache=yes --collect-jumps=yes ./rgbasm ...`.
|
||||||
profile:
|
profile:
|
||||||
$Qenv ${MAKE} \
|
$Qenv ${MAKE} \
|
||||||
CXXFLAGS="-ggdb3 -O3 -fno-omit-frame-pointer -fno-optimize-sibling-calls"
|
CXXFLAGS="-ggdb3 -O3 -fno-omit-frame-pointer -fno-optimize-sibling-calls"
|
||||||
|
|
||||||
# Target used in development to inspect code coverage with gcov.
|
# Target used in development to inspect code coverage with gcov.
|
||||||
|
# Use `./contrib/coverage.bash`.
|
||||||
coverage:
|
coverage:
|
||||||
$Qenv ${MAKE} \
|
$Qenv ${MAKE} \
|
||||||
CXXFLAGS="-ggdb3 -Og --coverage -fno-omit-frame-pointer -fno-optimize-sibling-calls"
|
CXXFLAGS="-ggdb3 -Og --coverage -fno-omit-frame-pointer -fno-optimize-sibling-calls"
|
||||||
|
|
||||||
# Target used in development to format source code with clang-format.
|
# Target used in development to format source code with clang-format.
|
||||||
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.
|
# Target used in development to check code with clang-tidy.
|
||||||
# Requires Bison-generated header files to exist.
|
# Requires Bison-generated header files to exist.
|
||||||
tidy: src/asm/parser.hpp src/link/script.hpp
|
tidy: src/asm/parser.hpp src/link/script.hpp compile_flags.txt
|
||||||
$Qclang-tidy -p . $$(git ls-files '*.hpp' '*.cpp')
|
$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.
|
# Target used in development to remove unused `#include` headers.
|
||||||
iwyu:
|
iwyu:
|
||||||
@@ -256,22 +263,7 @@ iwyu:
|
|||||||
CXX="include-what-you-use" \
|
CXX="include-what-you-use" \
|
||||||
REALCXXFLAGS="-std=c++20 -I include"
|
REALCXXFLAGS="-std=c++20 -I include"
|
||||||
|
|
||||||
# Targets for the project maintainer to easily create Windows exes.
|
# Target used in development to conveniently invoke RGBDS binaries with Wine.
|
||||||
# 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"
|
|
||||||
|
|
||||||
wine-shim:
|
wine-shim:
|
||||||
$Qecho '#!/usr/bin/env bash' > rgbshim.sh
|
$Qecho '#!/usr/bin/env bash' > rgbshim.sh
|
||||||
$Qecho 'WINEDEBUG=-all wine $$0.exe "$${@:1}"' >> rgbshim.sh
|
$Qecho 'WINEDEBUG=-all wine $$0.exe "$${@:1}"' >> rgbshim.sh
|
||||||
@@ -283,7 +275,6 @@ wine-shim:
|
|||||||
|
|
||||||
# Target for the project maintainer to produce distributable release tarballs
|
# Target for the project maintainer to produce distributable release tarballs
|
||||||
# of the source code.
|
# of the source code.
|
||||||
|
|
||||||
dist:
|
dist:
|
||||||
$Qgit ls-files | sed s~^~$${PWD##*/}/~ \
|
$Qgit ls-files | sed s~^~$${PWD##*/}/~ \
|
||||||
| tar -czf rgbds-source.tar.gz -C .. -T -
|
| tar -czf rgbds-source.tar.gz -C .. -T -
|
||||||
|
|||||||
@@ -1,33 +1,39 @@
|
|||||||
# RGBDS
|
# RGBDS
|
||||||
|
|
||||||
RGBDS (Rednex Game Boy Development System) is a free assembler/linker package
|
[RGBDS](https://github.com/gbdev/rgbds) (Rednex Game Boy Development System) is
|
||||||
for the Game Boy and Game Boy Color. It consists of:
|
a free assembler/linker package for the Game Boy and Game Boy Color.
|
||||||
|
|
||||||
- RGBASM (assembler)
|
It consists of four tools:
|
||||||
- RGBLINK (linker)
|
|
||||||
- RGBFIX (checksum/header fixer)
|
|
||||||
- RGBGFX (PNG-to-Game Boy graphics converter)
|
|
||||||
|
|
||||||
This is a fork of the original RGBDS which aims to make the programs more like
|
- **RGBASM:** assembler
|
||||||
other UNIX tools.
|
- **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/),
|
The [full documentation](https://rgbds.gbdev.io/docs/) is available online,
|
||||||
including its [basic usage and development history](https://rgbds.gbdev.io/docs/rgbds.7).
|
including the [development history](https://rgbds.gbdev.io/docs/rgbds.7) and
|
||||||
It is generated from the man pages found in this repository.
|
[version history](https://rgbds.gbdev.io/versions), generated from the man pages
|
||||||
The source code of the website itself is on GitHub as well under the repository
|
in this repository.
|
||||||
[rgbds-www](https://github.com/gbdev/rgbds-www).
|
|
||||||
|
|
||||||
If you want to contribute or maintain RGBDS, read [CONTRIBUTING.md](CONTRIBUTING.md).
|
The documentation website's own source code is available in the
|
||||||
If you have questions regarding the code, its organization, etc. you can find the maintainers
|
[rgbds-www](https://github.com/gbdev/rgbds-www) repository.
|
||||||
[on the GBDev community channels](https://gbdev.io/chat) or via mail at `rgbds at gbdev dot io`.
|
|
||||||
|
|
||||||
## Installing RGBDS
|
## Community
|
||||||
|
|
||||||
The [installation procedure](https://rgbds.gbdev.io/install) is available
|
If you have questions about the RGBDS code or its organization, you can contact
|
||||||
online for various platforms. [Building from source](https://rgbds.gbdev.io/install/source)
|
the maintainers on the [GBDev Discord server](https://discord.gg/RjJKA8wrD4) or
|
||||||
is possible using `make` or `cmake`; follow the link for more detailed instructions.
|
[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
|
```sh
|
||||||
make
|
make
|
||||||
@@ -40,8 +46,8 @@ cmake --build build
|
|||||||
cmake --install build
|
cmake --install build
|
||||||
```
|
```
|
||||||
|
|
||||||
Two parameters available when building are a prefix (e.g. to put the executables in a directory)
|
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).
|
and a suffix (e.g. to append the version number or commit ID):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
make
|
make
|
||||||
@@ -54,4 +60,4 @@ cmake --build build
|
|||||||
cmake --install build --prefix install_dir
|
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++20
|
|
||||||
-I
|
|
||||||
include
|
|
||||||
-fno-exceptions
|
|
||||||
-fno-rtti
|
|
||||||
-fno-caret-diagnostics
|
|
||||||
@@ -142,6 +142,7 @@ _rgblink_completions() {
|
|||||||
mapfile -t COMPREPLY < <(compgen -W "
|
mapfile -t COMPREPLY < <(compgen -W "
|
||||||
assert
|
assert
|
||||||
div
|
div
|
||||||
|
large-constant
|
||||||
obsolete
|
obsolete
|
||||||
shift
|
shift
|
||||||
shift-amount
|
shift-amount
|
||||||
|
|||||||
+56
-16
@@ -1,17 +1,55 @@
|
|||||||
#!/usr/bin/env bash
|
#!/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
|
# Build RGBDS with gcov support
|
||||||
make coverage -j
|
make coverage "${make_args[@]}"
|
||||||
|
|
||||||
# Run the tests
|
# Run the tests
|
||||||
pushd test
|
pushd test
|
||||||
./fetch-test-deps.sh
|
external/fetch-repos.sh
|
||||||
if [[ $# -eq 0 ]]; then
|
./run-tests.sh "${runtests_args[@]}"
|
||||||
./run-tests.sh
|
|
||||||
else
|
|
||||||
./run-tests.sh --os "$1"
|
|
||||||
fi
|
|
||||||
popd
|
popd
|
||||||
|
|
||||||
# Generate coverage logs
|
# Generate coverage logs
|
||||||
@@ -24,12 +62,14 @@ 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"
|
lcov -r "$COVERAGE_INFO" src/asm/parser.{hpp,cpp} src/link/script.{hpp,cpp} -o "$COVERAGE_INFO"
|
||||||
genhtml --dark-mode --num-spaces 4 -f -s -o coverage/ "$COVERAGE_INFO"
|
genhtml --dark-mode --num-spaces 4 -f -s -o coverage/ "$COVERAGE_INFO"
|
||||||
|
|
||||||
# Check whether running from coverage.yml workflow
|
if "$open_report"; then
|
||||||
if [ "$1" != "ubuntu-ci" ]; then
|
# Open the report in the preferred web browser
|
||||||
# Open report in web browser
|
if [ "$(uname)" == "Darwin" ]; then
|
||||||
if [ "$(uname)" == "Darwin" ]; then
|
open coverage/index.html
|
||||||
open coverage/index.html
|
else
|
||||||
else
|
xdg-open coverage/index.html
|
||||||
xdg-open coverage/index.html
|
fi
|
||||||
fi
|
else
|
||||||
|
# Output the path to the report
|
||||||
|
echo "Generated LCOV report at $PWD/coverage/index.html"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
if [[ $# -ne 2 ]]; then
|
if [[ $# -ne 2 ]]; then
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ _rgblink_warnings() {
|
|||||||
|
|
||||||
'assert:Warn when WARN-type asserts fail'
|
'assert:Warn when WARN-type asserts fail'
|
||||||
'div:Warn when dividing the smallest int by -1'
|
'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'
|
'obsolete:Warn when using deprecated features'
|
||||||
'shift:Warn when shifting negative values'
|
'shift:Warn when shifting negative values'
|
||||||
'shift-amount:Warn when a shift'\''s operand is negative or \> 32'
|
'shift-amount:Warn when a shift'\''s operand is negative or \> 32'
|
||||||
|
|||||||
@@ -28,11 +28,15 @@ rgbds/
|
|||||||
│ │ └── ...
|
│ │ └── ...
|
||||||
│ └── workflows/
|
│ └── workflows/
|
||||||
│ └── ...
|
│ └── ...
|
||||||
|
├── cmake/
|
||||||
|
│ └── ...
|
||||||
├── contrib/
|
├── contrib/
|
||||||
│ ├── bash_compl/
|
│ ├── bash_compl/
|
||||||
│ ├── zsh_compl/
|
│ ├── zsh_compl/
|
||||||
│ │ └── ...
|
│ │ └── ...
|
||||||
│ └── ...
|
│ └── ...
|
||||||
|
├── docs/
|
||||||
|
│ └── ...
|
||||||
├── include/
|
├── include/
|
||||||
│ └── ...
|
│ └── ...
|
||||||
├── man/
|
├── man/
|
||||||
@@ -52,13 +56,15 @@ rgbds/
|
|||||||
│ ├── bison.sh
|
│ ├── bison.sh
|
||||||
│ └── ...
|
│ └── ...
|
||||||
├── test/
|
├── test/
|
||||||
│ ├── fetch-test-deps.sh
|
|
||||||
│ ├── run-tests.sh
|
│ ├── run-tests.sh
|
||||||
|
│ ├── external/
|
||||||
|
│ │ ├── fetch-repos.sh
|
||||||
|
│ │ └── ...
|
||||||
│ └── ...
|
│ └── ...
|
||||||
├── .clang-format
|
├── .clang-format
|
||||||
├── .clang-tidy
|
├── .clang-tidy
|
||||||
├── CMakeLists.txt
|
├── CMakeLists.txt
|
||||||
├── compile_flags.txt
|
├── CMakePresets.json
|
||||||
├── Dockerfile
|
├── Dockerfile
|
||||||
└── Makefile
|
└── Makefile
|
||||||
```
|
```
|
||||||
@@ -69,12 +75,20 @@ rgbds/
|
|||||||
Scripts used by GitHub Actions workflow files.
|
Scripts used by GitHub Actions workflow files.
|
||||||
* **`workflows/`:**
|
* **`workflows/`:**
|
||||||
GitHub Actions CI workflow description files. Used for automated testing, deployment, etc.
|
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/`:**
|
- **`contrib/`:**
|
||||||
Scripts and other resources which may be useful to RGBDS users and developers.
|
Scripts and other resources which may be useful to RGBDS users and developers.
|
||||||
* **`bash_compl/`:**
|
* **`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.
|
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/`:**
|
* **`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.
|
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/`:**
|
- **`include/`:**
|
||||||
Header files for the respective source files in `src`.
|
Header files for the respective source files in `src`.
|
||||||
- **`man/`:**
|
- **`man/`:**
|
||||||
@@ -97,18 +111,23 @@ rgbds/
|
|||||||
Script used to run the Bison parser generator with the latest flags that the user's version supports.
|
Script used to run the Bison parser generator with the latest flags that the user's version supports.
|
||||||
- **`test/`:**
|
- **`test/`:**
|
||||||
Testing framework used to verify that changes to the code don't break or modify the behavior of RGBDS.
|
Testing framework used to verify that changes to the code don't break or modify the behavior of RGBDS.
|
||||||
* **`fetch-test-deps.sh`:**
|
The `test.sh` scripts inside each of the subdirectories are the individual test drivers.
|
||||||
Script used to fetch dependencies for building external repositories. `fetch-test-deps.sh --help` describes its options.
|
|
||||||
* **`run-tests.sh`:**
|
* **`run-tests.sh`:**
|
||||||
Script used to run tests, including internal test cases and external repositories. `run-tests.sh --help` describes its options.
|
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`:**
|
- **`.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`).
|
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`:**
|
- **`.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`).
|
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`:**
|
- **`CMakeLists.txt`:**
|
||||||
Defines how to build RGBDS with CMake.
|
Defines how to build RGBDS with CMake.
|
||||||
- **`compile_flags.txt`:**
|
- **`CMakePresets.json`:**
|
||||||
Compiler flags for `clang-tidy`.
|
Defines some [presets](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html) useful for working with our CMake.
|
||||||
- **`Dockerfile`:**
|
- **`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)).
|
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`:**
|
- **`Makefile`:**
|
||||||
@@ -165,10 +184,13 @@ These files have been copied ("vendored") from external authors and adapted for
|
|||||||
- **`fstack.cpp`:**
|
- **`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).
|
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`.
|
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`:**
|
- **`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.
|
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`.
|
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.
|
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`:**
|
- **`macro.cpp`:**
|
||||||
`MacroArgs` methods related to macro arguments. Each `MacroArgs` *references* its arguments' contents.
|
`MacroArgs` methods related to macro arguments. Each `MacroArgs` *references* its arguments' contents.
|
||||||
@@ -186,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).
|
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`.
|
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`:**
|
- **`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`:**
|
- **`section.cpp`:**
|
||||||
Functions and data related to `SECTION`s.
|
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.)
|
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.)
|
||||||
@@ -261,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`).
|
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.
|
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`:**
|
- **`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.
|
This file *owns* the `Assertion`s in its `assertions` collection, and the `RPNStackEntry`s in its `rpnStack` collection.
|
||||||
- **`script.y`:**
|
- **`script.y`:**
|
||||||
Grammar for the linker script language, which Bison preprocesses into a [LALR(1) parser](https://en.wikipedia.org/wiki/LALR_parser).
|
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
|
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.
|
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
|
Bug reports are essential to improve RGBDS and they are always welcome. If you
|
||||||
want to report a bug:
|
want to report a bug:
|
||||||
@@ -35,6 +35,9 @@ implement it yourself, you can always contribute to RGBDS with your own code.
|
|||||||
|
|
||||||
## Contributing 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
|
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
|
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
|
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
|
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
|
new warning (but it may be possible to remove some warning checks if it makes
|
||||||
the code much easier).
|
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.
|
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
|
`./run-tests.sh --help` will print its available options. (You must run
|
||||||
will fail and remind you mid-way.)
|
`external/fetch-repos.sh` first; if you forget to, the test suite will fail and
|
||||||
5. Format your changes according to `clang-format`, which will reformat the
|
remind you mid-way.)
|
||||||
coding style according to our standards defined in `.clang-format`.
|
|
||||||
6. Create a pull request against the branch `master`.
|
You can also use `ctest --test-dir build` if you prefer.
|
||||||
7. Check the results of the GitHub Actions CI jobs for your pull request. The
|
`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.
|
"Code format checking" and "Regression testing" jobs should all succeed.
|
||||||
The "Diff completeness check" and "Static analysis" jobs should be manually
|
The "Diff completeness check" job should be manually checked, as it may
|
||||||
checked, as they may output warnings which do not count as failure errors.
|
output warnings which do not count as failure errors. The "Code coverage
|
||||||
The "Code coverage report" provides an
|
report" provides an [LCOV](https://github.com/linux-test-project/lcov)-generated
|
||||||
[LCOV](https://github.com/linux-test-project/lcov)-generated report which
|
report which can be downloaded and checked to see if your new code has full
|
||||||
can be downloaded and checked to see if your new code has full test coverage.
|
test coverage.
|
||||||
8. Be prepared to get some comments about your code and to modify it. Tip: Use
|
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.
|
`git rebase -i origin/master` to modify chains of commits.
|
||||||
|
|
||||||
## Adding a test
|
## 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.
|
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
|
A `.out` file **must** exist, and RGBLINK's total output must match that file's
|
||||||
contents.
|
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 `seed*.bin` file corresponds to one test.
|
||||||
Each one is a binary RNG file which is passed to the `rgbgfx_test` program.
|
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
|
Each `.cfg` file corresponds to one test.
|
||||||
<code>make <var><target></var> RGBDS=<var><path/to/RGBDS/></var></code>.
|
Each one defines the parameters for a real external project that builds using RGBDS.
|
||||||
While the test suite supports any Make target name, only
|
|
||||||
[Make](//gnu.org/software/make) is currently supported, and the Makefile must
|
1. Ensure that the downstream project supports a `RGBDS` variable to build with
|
||||||
support a `RGBDS` variable to use a non-system RGBDS directory.
|
a non-system copy of RGBDS in some directory, i.e.
|
||||||
|
<code>make <var><target></var> RGBDS=<var><path/to/rgbds/></var></code>.
|
||||||
Also, only projects hosted on GitHub are currently supported.
|
Only [GNU Make](https://www.gnu.org/software/make/) is currently supported.
|
||||||
2. Add the project to `test/fetch-test-deps.sh`: add a new `action` line at the
|
2. Create the new `.cfg` file, following the existing ones.
|
||||||
bottom, following the existing pattern:
|
|
||||||
|
If an external project does not support `make RGBDS=`, or otherwise fails to
|
||||||
```sh
|
build with current RGBDS, then you can edit the project to build correctly, and
|
||||||
action <owner> <repo> <date of last commit> <hash of last commit>
|
create a patch with `git diff` to be committed as
|
||||||
```
|
<code>test/external/patches/<var><project></var>.patch</code>.
|
||||||
|
|
||||||
(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>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Container images
|
## Container images
|
||||||
|
|
||||||
@@ -254,4 +260,12 @@ manually running:
|
|||||||
# e.g. to build and tag as 'master'
|
# e.g. to build and tag as 'master'
|
||||||
docker build . --tag ghcr.io/gbdev/rgbds:master
|
docker build . --tag ghcr.io/gbdev/rgbds:master
|
||||||
docker push 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.
|
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`.
|
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`.
|
`PACKAGE_VERSION_MINOR`, `PACKAGE_VERSION_PATCH`, and `PACKAGE_VERSION_RC`.
|
||||||
**Only** define `PACKAGE_VERSION_RC` if you are publishing a release candidate!
|
**Only** define `PACKAGE_VERSION_RC` if you are publishing a release candidate!
|
||||||
- [Dockerfile](Dockerfile): update `ARG version`.
|
- [Dockerfile](/Dockerfile): update `ARG version`.
|
||||||
- [test/fetch-test-deps.sh](test/fetch-test-deps.sh): update test dependency commits
|
- [test/external/\*.cfg](/test/external): update test dependency commits
|
||||||
(preferably, use the latest available).
|
(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>,
|
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>
|
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>,
|
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
|
<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>.
|
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:
|
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`.
|
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
|
procedure. You can use <code>git push --delete origin <i><tag></i></code> and
|
||||||
<code>git tag --delete <i><tag></i></code>.
|
<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).
|
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
|
This is not done automatically for prereleases, since we do not normally publish documentation
|
||||||
@@ -13,7 +13,8 @@
|
|||||||
|
|
||||||
#include "linkdefs.hpp" // AssertionType, RPNCommand
|
#include "linkdefs.hpp" // AssertionType, RPNCommand
|
||||||
|
|
||||||
#include "asm/rpn.hpp" // Expression
|
#include "asm/intern.hpp" // InternedStr
|
||||||
|
#include "asm/rpn.hpp" // Expression
|
||||||
|
|
||||||
struct AlignmentSpec {
|
struct AlignmentSpec {
|
||||||
uint8_t alignment;
|
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 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
|
#endif // RGBDS_ASM_ACTIONS_HPP
|
||||||
|
|||||||
@@ -10,14 +10,14 @@
|
|||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#define DEFAULT_CHARMAP_NAME "main"
|
#include "asm/intern.hpp"
|
||||||
|
|
||||||
|
void charmap_Init();
|
||||||
bool charmap_ForEach(
|
bool charmap_ForEach(
|
||||||
void (*mapFunc)(std::string const &),
|
void (*mapFunc)(InternedStr), void (*charFunc)(std::string const &, std::vector<int32_t>)
|
||||||
void (*charFunc)(std::string const &, std::vector<int32_t>)
|
|
||||||
);
|
);
|
||||||
void charmap_New(std::string const &name, std::string const *baseName);
|
void charmap_New(InternedStr name, InternedStr const *baseName);
|
||||||
void charmap_Set(std::string const &name);
|
void charmap_Set(InternedStr name);
|
||||||
void charmap_Push();
|
void charmap_Push();
|
||||||
void charmap_Pop();
|
void charmap_Pop();
|
||||||
void charmap_CheckStack();
|
void charmap_CheckStack();
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
|
|
||||||
|
#include "asm/intern.hpp"
|
||||||
#include "asm/lexer.hpp"
|
#include "asm/lexer.hpp"
|
||||||
|
|
||||||
struct FileStackNode {
|
struct FileStackNode {
|
||||||
@@ -68,12 +69,10 @@ bool fstk_FailedOnMissingInclude();
|
|||||||
|
|
||||||
bool yywrap();
|
bool yywrap();
|
||||||
bool fstk_RunInclude(std::string const &path, bool isQuiet);
|
bool fstk_RunInclude(std::string const &path, bool isQuiet);
|
||||||
void fstk_RunMacro(
|
void fstk_RunMacro(InternedStr macroName, std::shared_ptr<MacroArgs> macroArgs, bool isQuiet);
|
||||||
std::string const ¯oName, std::shared_ptr<MacroArgs> macroArgs, bool isQuiet
|
|
||||||
);
|
|
||||||
void fstk_RunRept(uint32_t count, int32_t reptLineNo, ContentSpan const &span, bool isQuiet);
|
void fstk_RunRept(uint32_t count, int32_t reptLineNo, ContentSpan const &span, bool isQuiet);
|
||||||
void fstk_RunFor(
|
void fstk_RunFor(
|
||||||
std::string const &symName,
|
InternedStr symName,
|
||||||
int32_t start,
|
int32_t start,
|
||||||
int32_t stop,
|
int32_t stop,
|
||||||
int32_t step,
|
int32_t step,
|
||||||
|
|||||||
@@ -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 <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <variant>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "platform.hpp" // SSIZE_MAX
|
#include "asm/intern.hpp"
|
||||||
|
|
||||||
// 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");
|
|
||||||
|
|
||||||
enum LexerMode {
|
enum LexerMode {
|
||||||
LEXER_NORMAL,
|
LEXER_NORMAL,
|
||||||
@@ -32,7 +23,7 @@ enum LexerMode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Expansion {
|
struct Expansion {
|
||||||
std::optional<std::string> name;
|
std::optional<InternedStr> name;
|
||||||
std::shared_ptr<std::string> contents;
|
std::shared_ptr<std::string> contents;
|
||||||
size_t offset; // Cursor into `contents`
|
size_t offset; // Cursor into `contents`
|
||||||
|
|
||||||
@@ -45,34 +36,6 @@ struct ContentSpan {
|
|||||||
size_t size;
|
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 {
|
struct IfStackEntry {
|
||||||
bool ranIfBlock; // Whether an IF/ELIF/ELSE block ran already
|
bool ranIfBlock; // Whether an IF/ELIF/ELSE block ran already
|
||||||
bool reachedElseBlock; // Whether an ELSE block ran already
|
bool reachedElseBlock; // Whether an ELSE block ran already
|
||||||
@@ -87,31 +50,28 @@ struct LexerState {
|
|||||||
int lastToken;
|
int lastToken;
|
||||||
int nextToken;
|
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
|
bool capturing; // Whether the text being lexed should be captured
|
||||||
size_t captureSize; // Amount of text captured
|
size_t captureSize; // Amount of text captured
|
||||||
std::shared_ptr<std::vector<char>> captureBuf; // Buffer to send the captured text to if set
|
std::shared_ptr<std::vector<char>> captureBuf; // Buffer to send the captured text to if set
|
||||||
|
|
||||||
bool disableExpansions;
|
bool enableExpansions;
|
||||||
size_t expansionScanDistance; // Max distance already scanned for expansions
|
bool enableStringExpansions;
|
||||||
bool expandStrings;
|
size_t expansionScanDistance; // Max distance already scanned for expansions
|
||||||
std::deque<Expansion> expansions; // Front is the innermost current expansion
|
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();
|
~LexerState();
|
||||||
|
|
||||||
int peekChar();
|
int peekChar();
|
||||||
int peekCharAhead();
|
int peekCharAhead();
|
||||||
|
|
||||||
std::shared_ptr<char[]> makeSharedCaptureBufPtr() const {
|
|
||||||
return std::shared_ptr<char[]>(captureBuf, captureBuf->data());
|
|
||||||
}
|
|
||||||
|
|
||||||
void setAsCurrentState();
|
void setAsCurrentState();
|
||||||
void setFileAsNextState(std::string const &filePath, bool updateStateNow);
|
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_);
|
void clear(uint32_t lineNo_);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ struct MacroArgs {
|
|||||||
std::vector<std::shared_ptr<std::string>> args;
|
std::vector<std::shared_ptr<std::string>> args;
|
||||||
|
|
||||||
uint32_t nbArgs() const { return args.size() - shift; }
|
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;
|
std::shared_ptr<std::string> getAllArgs() const;
|
||||||
|
|
||||||
void appendArg(std::shared_ptr<std::string> arg);
|
void appendArg(std::shared_ptr<std::string> arg);
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "helpers.hpp" // assume
|
||||||
|
#include "util.hpp" // xfclose
|
||||||
|
|
||||||
enum MissingInclude {
|
enum MissingInclude {
|
||||||
INC_ERROR, // A missing included file is an error that halts assembly
|
INC_ERROR, // A missing included file is an error that halts assembly
|
||||||
GEN_EXIT, // A missing included file is assumed to be generated; exit normally
|
GEN_EXIT, // A missing included file is assumed to be generated; exit normally
|
||||||
@@ -30,12 +33,13 @@ struct Options {
|
|||||||
|
|
||||||
~Options() {
|
~Options() {
|
||||||
if (dependFile) {
|
if (dependFile) {
|
||||||
fclose(dependFile);
|
xfclose(dependFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void printDep(std::string const &depName) {
|
void printDep(std::string const &depName) {
|
||||||
if (dependFile) {
|
if (dependFile) {
|
||||||
|
assume(targetFileName.has_value());
|
||||||
fprintf(dependFile, "%s: %s\n", targetFileName->c_str(), depName.c_str());
|
fprintf(dependFile, "%s: %s\n", targetFileName->c_str(), depName.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-4
@@ -10,16 +10,18 @@
|
|||||||
|
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
|
|
||||||
|
#include "asm/intern.hpp"
|
||||||
|
|
||||||
struct Symbol;
|
struct Symbol;
|
||||||
|
|
||||||
struct RPNValue {
|
struct RPNValue {
|
||||||
RPNCommand command; // The RPN_* command ID
|
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);
|
||||||
RPNValue(RPNCommand cmd, uint8_t val);
|
RPNValue(RPNCommand cmd, uint8_t val);
|
||||||
RPNValue(RPNCommand cmd, uint32_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;
|
void appendEncoded(std::vector<uint8_t> &buffer) const;
|
||||||
};
|
};
|
||||||
@@ -40,8 +42,8 @@ struct Expression {
|
|||||||
bool isDiffConstant(Symbol const *symName) const;
|
bool isDiffConstant(Symbol const *symName) const;
|
||||||
|
|
||||||
void makeNumber(uint32_t value);
|
void makeNumber(uint32_t value);
|
||||||
void makeSymbol(std::string const &symName);
|
void makeSymbol(InternedStr symName);
|
||||||
void makeBankSymbol(std::string const &symName);
|
void makeBankSymbol(InternedStr symName);
|
||||||
void makeBankSection(std::string const §Name);
|
void makeBankSection(std::string const §Name);
|
||||||
void makeSizeOfSection(std::string const §Name);
|
void makeSizeOfSection(std::string const §Name);
|
||||||
void makeStartOfSection(std::string const §Name);
|
void makeStartOfSection(std::string const §Name);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "intern.hpp"
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
|
|
||||||
struct Expression;
|
struct Expression;
|
||||||
@@ -107,6 +108,6 @@ void sect_PushSection();
|
|||||||
void sect_PopSection();
|
void sect_PopSection();
|
||||||
void sect_CheckStack();
|
void sect_CheckStack();
|
||||||
|
|
||||||
std::string sect_PushSectionFragmentLiteral();
|
InternedStr sect_PushSectionFragmentLiteral();
|
||||||
|
|
||||||
#endif // RGBDS_ASM_SECTION_HPP
|
#endif // RGBDS_ASM_SECTION_HPP
|
||||||
|
|||||||
+20
-21
@@ -10,6 +10,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
|
#include "asm/intern.hpp"
|
||||||
#include "asm/lexer.hpp"
|
#include "asm/lexer.hpp"
|
||||||
#include "asm/section.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`
|
bool sym_IsPC(Symbol const *sym); // Forward declaration for `getSection`
|
||||||
|
|
||||||
struct Symbol {
|
struct Symbol {
|
||||||
std::string name;
|
InternedStr name;
|
||||||
SymbolType type;
|
SymbolType type;
|
||||||
bool isBuiltin;
|
bool isBuiltin;
|
||||||
bool isExported; // Not relevant for SYM_MACRO or SYM_EQUS
|
bool isExported; // Not relevant for SYM_MACRO or SYM_EQUS
|
||||||
@@ -68,36 +69,34 @@ struct Symbol {
|
|||||||
uint32_t getConstantValue() const;
|
uint32_t getConstantValue() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool sym_IsDotScope(std::string const &symName);
|
bool sym_IsDotScope(InternedStr symName);
|
||||||
|
|
||||||
void sym_ForEach(void (*callback)(Symbol &));
|
void sym_ForEach(void (*callback)(Symbol &));
|
||||||
|
|
||||||
Symbol *sym_AddLocalLabel(std::string const &symName);
|
Symbol *sym_AddLocalLabel(InternedStr symName);
|
||||||
Symbol *sym_AddLabel(std::string const &symName);
|
Symbol *sym_AddLabel(InternedStr symName);
|
||||||
Symbol *sym_AddAnonLabel();
|
Symbol *sym_AddAnonLabel();
|
||||||
std::string sym_MakeAnonLabelName(uint32_t ofs, bool neg);
|
InternedStr sym_MakeAnonLabelName(uint32_t ofs, bool neg);
|
||||||
void sym_Export(std::string const &symName);
|
void sym_Export(InternedStr symName);
|
||||||
Symbol *sym_AddEqu(std::string const &symName, int32_t value);
|
Symbol *sym_AddEqu(InternedStr symName, int32_t value);
|
||||||
Symbol *sym_RedefEqu(std::string const &symName, int32_t value);
|
Symbol *sym_RedefEqu(InternedStr symName, int32_t value);
|
||||||
Symbol *sym_AddVar(std::string const &symName, int32_t value);
|
Symbol *sym_AddVar(InternedStr symName, int32_t value);
|
||||||
int32_t sym_GetRSValue();
|
int32_t sym_GetRSValue();
|
||||||
void sym_SetRSValue(int32_t value);
|
void sym_SetRSValue(int32_t value);
|
||||||
// Find a symbol by exact name, bypassing expansion checks
|
// 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
|
// 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
|
// 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 const *sym_GetPC();
|
||||||
Symbol *sym_AddMacro(
|
Symbol *sym_AddMacro(InternedStr symName, int32_t defLineNo, ContentSpan const &span, bool isQuiet);
|
||||||
std::string const &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_Ref(std::string const &symName);
|
Symbol *sym_RedefString(InternedStr symName, std::shared_ptr<std::string> value);
|
||||||
Symbol *sym_AddString(std::string const &symName, std::shared_ptr<std::string> value);
|
void sym_Purge(InternedStr symName);
|
||||||
Symbol *sym_RedefString(std::string const &symName, std::shared_ptr<std::string> value);
|
bool sym_IsPurgedExact(InternedStr symName);
|
||||||
void sym_Purge(std::string const &symName);
|
bool sym_IsPurgedScoped(InternedStr symName);
|
||||||
bool sym_IsPurgedExact(std::string const &symName);
|
|
||||||
bool sym_IsPurgedScoped(std::string const &symName);
|
|
||||||
void sym_Init(time_t now);
|
void sym_Init(time_t now);
|
||||||
|
|
||||||
// Functions to save and restore the current label scopes.
|
// 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, ...);
|
void warning(WarningID id, char const *fmt, ...);
|
||||||
|
|
||||||
// Used for errors that compromise the whole assembly process by affecting the
|
// 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.
|
// 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,
|
// It is also used when the assembler goes into an invalid state (for example,
|
||||||
// when it fails to allocate memory).
|
// when it fails to allocate memory).
|
||||||
[[gnu::format(printf, 1, 2), noreturn]]
|
[[gnu::format(printf, 1, 2), noreturn]]
|
||||||
void fatal(char const *fmt, ...);
|
void fatal(char const *fmt, ...);
|
||||||
|
|
||||||
|
// Used for fatal errors that handle their own backtrace output.
|
||||||
|
[[noreturn]]
|
||||||
|
void fatalNoTrace(std::function<void()> callback);
|
||||||
|
|
||||||
// Used for errors that make it impossible to assemble correctly, but don't
|
// 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
|
// 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
|
// get a list of all errors at the end, making it easier to fix all of them at
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "helpers.hpp" // InvocableR
|
||||||
#include "style.hpp"
|
#include "style.hpp"
|
||||||
|
|
||||||
#define TRACE_SEPARATOR "<-"
|
#define TRACE_SEPARATOR "<-"
|
||||||
@@ -25,8 +26,12 @@ extern Tracing tracing;
|
|||||||
|
|
||||||
bool trace_ParseTraceDepth(char const *arg);
|
bool trace_ParseTraceDepth(char const *arg);
|
||||||
|
|
||||||
template<typename NodeT, typename NameFnT, typename LineNoFnT>
|
template<typename NodeT>
|
||||||
void trace_PrintBacktrace(std::vector<NodeT> const &stack, NameFnT getName, LineNoFnT getLineNo) {
|
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();
|
size_t n = stack.size();
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
return; // LCOV_EXCL_LINE
|
return; // LCOV_EXCL_LINE
|
||||||
|
|||||||
+21
-21
@@ -1,21 +1,21 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
#ifndef RGBDS_CLI_HPP
|
#ifndef RGBDS_CLI_HPP
|
||||||
#define RGBDS_CLI_HPP
|
#define RGBDS_CLI_HPP
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "extern/getopt.hpp" // option
|
#include "extern/getopt.hpp" // option
|
||||||
#include "usage.hpp"
|
#include "usage.hpp"
|
||||||
|
|
||||||
void cli_ParseArgs(
|
void cli_ParseArgs(
|
||||||
int argc,
|
int argc,
|
||||||
char *argv[],
|
char *argv[],
|
||||||
char const *shortOpts,
|
char const *shortOpts,
|
||||||
option const *longOpts,
|
option const *longOpts,
|
||||||
void (*parseArg)(int, char *),
|
void (*parseArg)(int, char *),
|
||||||
Usage usage
|
Usage usage
|
||||||
);
|
);
|
||||||
|
|
||||||
#endif // RGBDS_CLI_HPP
|
#endif // RGBDS_CLI_HPP
|
||||||
|
|||||||
+56
-6
@@ -15,9 +15,20 @@
|
|||||||
|
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "itertools.hpp"
|
#include "itertools.hpp"
|
||||||
|
#include "style.hpp"
|
||||||
|
|
||||||
[[gnu::format(printf, 1, 2)]]
|
[[gnu::format(printf, 1, 2)]]
|
||||||
void warnx(char const *fmt, ...);
|
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 };
|
enum WarningAbled { WARNING_DEFAULT, WARNING_ENABLED, WARNING_DISABLED };
|
||||||
|
|
||||||
@@ -30,7 +41,7 @@ struct WarningState {
|
|||||||
|
|
||||||
std::pair<WarningState, std::optional<uint32_t>> getInitialWarningState(std::string &flag);
|
std::pair<WarningState, std::optional<uint32_t>> getInitialWarningState(std::string &flag);
|
||||||
|
|
||||||
template<typename LevelEnumT>
|
template<Enum LevelEnumT>
|
||||||
struct WarningFlag {
|
struct WarningFlag {
|
||||||
char const *name;
|
char const *name;
|
||||||
LevelEnumT level;
|
LevelEnumT level;
|
||||||
@@ -38,14 +49,14 @@ struct WarningFlag {
|
|||||||
|
|
||||||
enum WarningBehavior { DISABLED, ENABLED, ERROR };
|
enum WarningBehavior { DISABLED, ENABLED, ERROR };
|
||||||
|
|
||||||
template<typename WarningEnumT>
|
template<Enum WarningEnumT>
|
||||||
struct ParamWarning {
|
struct ParamWarning {
|
||||||
WarningEnumT firstID;
|
WarningEnumT firstID;
|
||||||
WarningEnumT lastID;
|
WarningEnumT lastID;
|
||||||
uint8_t defaultLevel;
|
uint8_t defaultLevel;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename WarningEnumT>
|
template<Enum WarningEnumT>
|
||||||
struct DiagnosticsState {
|
struct DiagnosticsState {
|
||||||
WarningState flagStates[WarningEnumT::NB_WARNINGS];
|
WarningState flagStates[WarningEnumT::NB_WARNINGS];
|
||||||
WarningState metaStates[WarningEnumT::NB_WARNINGS];
|
WarningState metaStates[WarningEnumT::NB_WARNINGS];
|
||||||
@@ -53,7 +64,7 @@ struct DiagnosticsState {
|
|||||||
bool warningsAreErrors = false;
|
bool warningsAreErrors = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename LevelEnumT, typename WarningEnumT>
|
template<Enum LevelEnumT, Enum WarningEnumT>
|
||||||
struct Diagnostics {
|
struct Diagnostics {
|
||||||
std::vector<WarningFlag<LevelEnumT>> metaWarnings;
|
std::vector<WarningFlag<LevelEnumT>> metaWarnings;
|
||||||
std::vector<WarningFlag<LevelEnumT>> warningFlags;
|
std::vector<WarningFlag<LevelEnumT>> warningFlags;
|
||||||
@@ -71,7 +82,7 @@ struct Diagnostics {
|
|||||||
void processWarningFlag(char const *flag);
|
void processWarningFlag(char const *flag);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename LevelEnumT, typename WarningEnumT>
|
template<Enum LevelEnumT, Enum WarningEnumT>
|
||||||
WarningBehavior Diagnostics<LevelEnumT, WarningEnumT>::getWarningBehavior(WarningEnumT id) const {
|
WarningBehavior Diagnostics<LevelEnumT, WarningEnumT>::getWarningBehavior(WarningEnumT id) const {
|
||||||
// Check if warnings are globally disabled
|
// Check if warnings are globally disabled
|
||||||
if (!state.warningsEnabled) {
|
if (!state.warningsEnabled) {
|
||||||
@@ -120,7 +131,7 @@ WarningBehavior Diagnostics<LevelEnumT, WarningEnumT>::getWarningBehavior(Warnin
|
|||||||
return WarningBehavior::DISABLED;
|
return WarningBehavior::DISABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename LevelEnumT, typename WarningEnumT>
|
template<Enum LevelEnumT, Enum WarningEnumT>
|
||||||
void Diagnostics<LevelEnumT, WarningEnumT>::processWarningFlag(char const *flag) {
|
void Diagnostics<LevelEnumT, WarningEnumT>::processWarningFlag(char const *flag) {
|
||||||
std::string rootFlag = flag;
|
std::string rootFlag = flag;
|
||||||
|
|
||||||
@@ -208,4 +219,43 @@ void Diagnostics<LevelEnumT, WarningEnumT>::processWarningFlag(char const *flag)
|
|||||||
warnx("Unknown warning flag \"%s\"", rootFlag.c_str());
|
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
|
#endif // RGBDS_DIAGNOSTICS_HPP
|
||||||
|
|||||||
Vendored
+6
-1
@@ -8,6 +8,11 @@
|
|||||||
#define UTF8_ACCEPT 0
|
#define UTF8_ACCEPT 0
|
||||||
#define UTF8_REJECT 12
|
#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
|
#endif // RGBDS_EXTERN_UTF8DECODER_HPP
|
||||||
|
|||||||
+3
-8
@@ -34,6 +34,9 @@ public:
|
|||||||
} else {
|
} else {
|
||||||
assume(mode & std::ios_base::out);
|
assume(mode & std::ios_base::out);
|
||||||
_file.emplace<std::streambuf *>(std::cout.rdbuf());
|
_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;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -41,15 +44,7 @@ public:
|
|||||||
return std::holds_alternative<std::filebuf>(_file) ? std::get<std::filebuf>(_file)
|
return std::holds_alternative<std::filebuf>(_file) ? std::get<std::filebuf>(_file)
|
||||||
: *std::get<std::streambuf *>(_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 *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 {
|
char const *c_str(std::string const &path) const {
|
||||||
return std::holds_alternative<std::filebuf>(_file) ? path.c_str()
|
return std::holds_alternative<std::filebuf>(_file) ? path.c_str()
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public:
|
|||||||
static constexpr size_t capacity = 4;
|
static constexpr size_t capacity = 4;
|
||||||
|
|
||||||
private:
|
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)
|
// (OK because it's not a valid color index)
|
||||||
// Sorting is done on the raw numerical values to lessen `compare`'s complexity
|
// 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};
|
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.
|
// Adds the specified color to the set, or **silently drops it** if the set is full.
|
||||||
void add(uint16_t color);
|
void add(uint16_t color);
|
||||||
|
|
||||||
enum ComparisonResult {
|
enum ComparisonResult { INCOMPARABLE, SUBSET_OR_EQUAL, STRICT_SUPERSET };
|
||||||
NEITHER,
|
|
||||||
WE_BIGGER,
|
|
||||||
THEY_BIGGER = -1,
|
|
||||||
};
|
|
||||||
ComparisonResult compare(ColorSet const &other) const;
|
ComparisonResult compare(ColorSet const &other) const;
|
||||||
|
|
||||||
size_t size() const;
|
size_t size() const;
|
||||||
|
|||||||
+23
-23
@@ -1,23 +1,23 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
#ifndef RGBDS_GFX_FLIP_HPP
|
#ifndef RGBDS_GFX_FLIP_HPP
|
||||||
#define RGBDS_GFX_FLIP_HPP
|
#define RGBDS_GFX_FLIP_HPP
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// Flipping tends to happen fairly often, so take a bite out of dcache to speed it up
|
// 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 {
|
static std::array<uint16_t, 256> flipTable = ([]() constexpr {
|
||||||
std::array<uint16_t, 256> table{};
|
std::array<uint16_t, 256> table{};
|
||||||
for (uint16_t i = 0; i < table.size(); ++i) {
|
for (uint16_t i = 0; i < table.size(); ++i) {
|
||||||
// To flip all the bits, we'll flip both nibbles, then each nibble half, etc.
|
// To flip all the bits, we'll flip both nibbles, then each nibble half, etc.
|
||||||
uint16_t byte = i;
|
uint16_t byte = i;
|
||||||
byte = (byte & 0b0000'1111) << 4 | (byte & 0b1111'0000) >> 4;
|
byte = (byte & 0b0000'1111) << 4 | (byte & 0b1111'0000) >> 4;
|
||||||
byte = (byte & 0b0011'0011) << 2 | (byte & 0b1100'1100) >> 2;
|
byte = (byte & 0b0011'0011) << 2 | (byte & 0b1100'1100) >> 2;
|
||||||
byte = (byte & 0b0101'0101) << 1 | (byte & 0b1010'1010) >> 1;
|
byte = (byte & 0b0101'0101) << 1 | (byte & 0b1010'1010) >> 1;
|
||||||
table[i] = byte;
|
table[i] = byte;
|
||||||
}
|
}
|
||||||
return table;
|
return table;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
#endif // RGBDS_GFX_FLIP_HPP
|
#endif // RGBDS_GFX_FLIP_HPP
|
||||||
|
|||||||
+27
-27
@@ -1,27 +1,27 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
#ifndef RGBDS_GFX_PALETTE_HPP
|
#ifndef RGBDS_GFX_PALETTE_HPP
|
||||||
#define RGBDS_GFX_PALETTE_HPP
|
#define RGBDS_GFX_PALETTE_HPP
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
struct Palette {
|
struct Palette {
|
||||||
// An array of 4 GBC-native (RGB555) colors
|
// An array of 4 GBC-native (RGB555) colors
|
||||||
std::array<uint16_t, 4> colors{UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX};
|
std::array<uint16_t, 4> colors{UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX};
|
||||||
|
|
||||||
void addColor(uint16_t color);
|
void addColor(uint16_t color);
|
||||||
uint8_t indexOf(uint16_t color) const;
|
uint8_t indexOf(uint16_t color) const;
|
||||||
uint16_t &operator[](size_t index) { return colors[index]; }
|
uint16_t &operator[](size_t index) { return colors[index]; }
|
||||||
uint16_t const &operator[](size_t index) const { return colors[index]; }
|
uint16_t const &operator[](size_t index) const { return colors[index]; }
|
||||||
|
|
||||||
decltype(colors)::iterator begin();
|
decltype(colors)::iterator begin();
|
||||||
decltype(colors)::iterator end();
|
decltype(colors)::iterator end();
|
||||||
decltype(colors)::const_iterator begin() const;
|
decltype(colors)::const_iterator begin() const;
|
||||||
decltype(colors)::const_iterator end() const;
|
decltype(colors)::const_iterator end() const;
|
||||||
|
|
||||||
uint8_t size() const;
|
uint8_t size() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // RGBDS_GFX_PALETTE_HPP
|
#endif // RGBDS_GFX_PALETTE_HPP
|
||||||
|
|||||||
+2
-1
@@ -10,7 +10,8 @@
|
|||||||
#include "gfx/rgba.hpp"
|
#include "gfx/rgba.hpp"
|
||||||
|
|
||||||
struct Png {
|
struct Png {
|
||||||
uint32_t width, height;
|
uint32_t width = 0;
|
||||||
|
uint32_t height = 0;
|
||||||
std::vector<Rgba> pixels{};
|
std::vector<Rgba> pixels{};
|
||||||
std::vector<Rgba> palette{};
|
std::vector<Rgba> palette{};
|
||||||
|
|
||||||
|
|||||||
+25
-7
@@ -4,6 +4,9 @@
|
|||||||
#define RGBDS_GFX_RGBA_HPP
|
#define RGBDS_GFX_RGBA_HPP
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "helpers.hpp" // literal_strlen
|
||||||
|
|
||||||
struct Rgba {
|
struct Rgba {
|
||||||
uint8_t red;
|
uint8_t red;
|
||||||
@@ -17,6 +20,10 @@ struct Rgba {
|
|||||||
explicit constexpr Rgba(uint32_t rgba = 0)
|
explicit constexpr Rgba(uint32_t rgba = 0)
|
||||||
: red(rgba >> 24), green(rgba >> 16), blue(rgba >> 8), alpha(rgba) {}
|
: 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) {
|
static constexpr Rgba fromCGBColor(uint16_t color) {
|
||||||
constexpr auto _5to8 = [](uint8_t channel) -> uint8_t {
|
constexpr auto _5to8 = [](uint8_t channel) -> uint8_t {
|
||||||
channel &= 0b11111; // For caller's convenience
|
channel &= 0b11111; // For caller's convenience
|
||||||
@@ -26,12 +33,12 @@ struct Rgba {
|
|||||||
_5to8(color),
|
_5to8(color),
|
||||||
_5to8(color >> 5),
|
_5to8(color >> 5),
|
||||||
_5to8(color >> 10),
|
_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
|
// Returns this RGBA as a 32-bit number that can be printed in hex (`#%08x`)
|
||||||
// representation
|
// to yield its CSS representation (`#rrggbbaa`).
|
||||||
uint32_t toCSS() const {
|
uint32_t toCSS() const {
|
||||||
constexpr auto shl = [](uint8_t val, unsigned shift) {
|
constexpr auto shl = [](uint8_t val, unsigned shift) {
|
||||||
return static_cast<uint32_t>(val) << shift;
|
return static_cast<uint32_t>(val) << shift;
|
||||||
@@ -41,10 +48,6 @@ struct Rgba {
|
|||||||
|
|
||||||
bool operator==(Rgba const &rhs) const { return toCSS() == rhs.toCSS(); }
|
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;
|
static constexpr uint8_t transparency_threshold = 0x10;
|
||||||
bool isTransparent() const { return alpha < transparency_threshold; }
|
bool isTransparent() const { return alpha < transparency_threshold; }
|
||||||
static constexpr uint8_t opacity_threshold = 0xF0;
|
static constexpr uint8_t opacity_threshold = 0xF0;
|
||||||
@@ -56,4 +59,19 @@ struct Rgba {
|
|||||||
uint8_t grayIndex() const;
|
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
|
#endif // RGBDS_GFX_RGBA_HPP
|
||||||
|
|||||||
+38
-17
@@ -3,6 +3,8 @@
|
|||||||
#ifndef RGBDS_HELPERS_HPP
|
#ifndef RGBDS_HELPERS_HPP
|
||||||
#define RGBDS_HELPERS_HPP
|
#define RGBDS_HELPERS_HPP
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
// Ideally we'd use `std::unreachable`, but it has insufficient compiler support
|
// Ideally we'd use `std::unreachable`, but it has insufficient compiler support
|
||||||
#ifdef __GNUC__ // GCC or compatible
|
#ifdef __GNUC__ // GCC or compatible
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
@@ -48,42 +50,40 @@ static inline void unreachable_() {
|
|||||||
#pragma intrinsic(_BitScanReverse, _BitScanForward)
|
#pragma intrinsic(_BitScanReverse, _BitScanForward)
|
||||||
|
|
||||||
static inline int ctz(unsigned int x) {
|
static inline int ctz(unsigned int x) {
|
||||||
unsigned long cnt;
|
|
||||||
|
|
||||||
assume(x != 0);
|
assume(x != 0);
|
||||||
_BitScanForward(&cnt, x);
|
unsigned long count;
|
||||||
return cnt;
|
_BitScanForward(&count, x);
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int clz(unsigned int x) {
|
static inline int clz(unsigned int x) {
|
||||||
unsigned long cnt;
|
|
||||||
|
|
||||||
assume(x != 0);
|
assume(x != 0);
|
||||||
_BitScanReverse(&cnt, x);
|
unsigned long count;
|
||||||
return 31 - cnt;
|
_BitScanReverse(&count, x);
|
||||||
|
return 31 - count;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
static inline int ctz(unsigned int x) {
|
static inline int ctz(unsigned int x) {
|
||||||
int cnt = 0;
|
assume(x != 0);
|
||||||
|
int count = 0;
|
||||||
while (!(x & 1)) {
|
while (!(x & 1)) {
|
||||||
x >>= 1;
|
x >>= 1;
|
||||||
++cnt;
|
++count;
|
||||||
}
|
}
|
||||||
return cnt;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int clz(unsigned int x) {
|
static inline int clz(unsigned int x) {
|
||||||
int cnt = 0;
|
assume(x != 0);
|
||||||
|
int count = 0;
|
||||||
while (x <= UINT_MAX / 2) {
|
while (x <= UINT_MAX / 2) {
|
||||||
x <<= 1;
|
x <<= 1;
|
||||||
++cnt;
|
++count;
|
||||||
}
|
}
|
||||||
return cnt;
|
return count;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -99,14 +99,35 @@ static inline int clz(unsigned int x) {
|
|||||||
#define RANGE(s) std::begin(s), std::end(s)
|
#define RANGE(s) std::begin(s), std::end(s)
|
||||||
#define RRANGE(s) std::rbegin(s), std::rend(s)
|
#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
|
// MSVC does not inline `strlen()` or `.length()` of a constant string
|
||||||
template<int SizeOfString>
|
template<int SizeOfString>
|
||||||
|
requires(SizeOfString > 0)
|
||||||
static constexpr int literal_strlen(char const (&)[SizeOfString]) {
|
static constexpr int literal_strlen(char const (&)[SizeOfString]) {
|
||||||
return SizeOfString - 1; // Don't count the ending '\0'
|
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))`
|
// For ad-hoc RAII in place of a `defer` statement or cross-platform `__attribute__((cleanup))`
|
||||||
template<typename DeferredFnT>
|
template<Procedure DeferredFnT>
|
||||||
struct Defer {
|
struct Defer {
|
||||||
DeferredFnT deferred;
|
DeferredFnT deferred;
|
||||||
Defer(DeferredFnT func) : deferred(func) {}
|
Defer(DeferredFnT func) : deferred(func) {}
|
||||||
|
|||||||
+21
-13
@@ -12,6 +12,8 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "helpers.hpp" // Enum, assume
|
||||||
|
|
||||||
// A wrapper around iterables to reverse their iteration order; used in `for`-each loops.
|
// A wrapper around iterables to reverse their iteration order; used in `for`-each loops.
|
||||||
template<typename IterableT>
|
template<typename IterableT>
|
||||||
struct ReversedIterable {
|
struct ReversedIterable {
|
||||||
@@ -33,18 +35,18 @@ ReversedIterable<IterableT> reversed(IterableT &&_iterable) {
|
|||||||
return {_iterable};
|
return {_iterable};
|
||||||
}
|
}
|
||||||
|
|
||||||
// A map from `std::string` keys to `ItemT` items, iterable in the order the items were inserted.
|
// A map from `KeyT` keys to `ItemT` items, iterable in the order the items were inserted.
|
||||||
template<typename ItemT>
|
template<typename KeyT, typename ItemT>
|
||||||
class InsertionOrderedMap {
|
class InsertionOrderedMap {
|
||||||
std::deque<ItemT> list;
|
std::deque<ItemT> list; // `deque` does not invalidate item references
|
||||||
std::unordered_map<std::string, size_t> map; // Indexes into `list`
|
std::unordered_map<KeyT, size_t> map; // Indexes into `list`
|
||||||
|
|
||||||
public:
|
public:
|
||||||
size_t size() const { return list.size(); }
|
size_t size() const { return list.size(); }
|
||||||
|
|
||||||
bool empty() const { return list.empty(); }
|
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(); }
|
||||||
|
|
||||||
ItemT &operator[](size_t i) { return list[i]; }
|
ItemT &operator[](size_t i) { return list[i]; }
|
||||||
|
|
||||||
@@ -53,13 +55,19 @@ public:
|
|||||||
typename decltype(list)::const_iterator begin() const { return list.begin(); }
|
typename decltype(list)::const_iterator begin() const { return list.begin(); }
|
||||||
typename decltype(list)::const_iterator end() const { return list.end(); }
|
typename decltype(list)::const_iterator end() const { return list.end(); }
|
||||||
|
|
||||||
ItemT &add(std::string const &name) {
|
// Adding a key that already exists would make the previous value unreachable.
|
||||||
map[name] = list.size();
|
// `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();
|
return list.emplace_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemT &add(std::string const &name, ItemT &&value) {
|
ItemT &add(KeyT const &key, ItemT &&value) {
|
||||||
map[name] = list.size();
|
assume(!contains(key));
|
||||||
|
map[key] = list.size();
|
||||||
list.emplace_back(std::move(value));
|
list.emplace_back(std::move(value));
|
||||||
return list.back();
|
return list.back();
|
||||||
}
|
}
|
||||||
@@ -69,8 +77,8 @@ public:
|
|||||||
return list.emplace_back();
|
return list.emplace_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<size_t> findIndex(std::string const &name) const {
|
std::optional<size_t> findIndex(KeyT const &key) const {
|
||||||
if (auto search = map.find(name); search != map.end()) {
|
if (auto search = map.find(key); search != map.end()) {
|
||||||
return search->second;
|
return search->second;
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@@ -78,7 +86,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// An iterable of `enum` values in the half-open range [start, stop).
|
// An iterable of `enum` values in the half-open range [start, stop).
|
||||||
template<typename EnumT>
|
template<Enum EnumT>
|
||||||
class EnumSeq {
|
class EnumSeq {
|
||||||
EnumT _start;
|
EnumT _start;
|
||||||
EnumT _stop;
|
EnumT _stop;
|
||||||
@@ -169,7 +177,7 @@ template<typename IterableT>
|
|||||||
using ZipHolder = std::conditional_t<
|
using ZipHolder = std::conditional_t<
|
||||||
std::is_lvalue_reference_v<IterableT>,
|
std::is_lvalue_reference_v<IterableT>,
|
||||||
IterableT,
|
IterableT,
|
||||||
std::remove_cv_t<std::remove_reference_t<IterableT>>>;
|
std::remove_cvref_t<IterableT>>;
|
||||||
|
|
||||||
// Iterates over N containers at once, yielding tuples of N items at a time.
|
// 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!
|
// Does the same number of iterations as the first container's iterator!
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "helpers.hpp" // QualifiedEquivalent
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
|
|
||||||
struct FileStackNode;
|
struct FileStackNode;
|
||||||
@@ -52,7 +53,7 @@ struct Section {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// Template class for both const and non-const iterators over the "pieces" of this section
|
// Template class for both const and non-const iterators over the "pieces" of this section
|
||||||
template<typename SectionT>
|
template<QualifiedEquivalent<Section> SectionT>
|
||||||
class PiecesIterable {
|
class PiecesIterable {
|
||||||
SectionT *_firstPiece;
|
SectionT *_firstPiece;
|
||||||
|
|
||||||
|
|||||||
@@ -22,11 +22,12 @@ enum WarningLevel {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum WarningID {
|
enum WarningID {
|
||||||
WARNING_ASSERT, // Assertions
|
WARNING_ASSERT, // Assertions
|
||||||
WARNING_DIV, // Undefined division behavior
|
WARNING_DIV, // Undefined division behavior
|
||||||
WARNING_OBSOLETE, // Obsolete/deprecated things
|
WARNING_LARGE_CONSTANT, // Constants too large
|
||||||
WARNING_SHIFT, // Undefined `SHIFT` behavior
|
WARNING_OBSOLETE, // Obsolete/deprecated things
|
||||||
WARNING_SHIFT_AMOUNT, // Strange `SHIFT` amount
|
WARNING_SHIFT, // Undefined `SHIFT` behavior
|
||||||
|
WARNING_SHIFT_AMOUNT, // Strange `SHIFT` amount
|
||||||
|
|
||||||
NB_PLAIN_WARNINGS,
|
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, ...);
|
void warning(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...);
|
||||||
[[gnu::format(printf, 1, 2)]]
|
[[gnu::format(printf, 1, 2)]]
|
||||||
void warning(char const *fmt, ...);
|
void warning(char const *fmt, ...);
|
||||||
|
[[gnu::format(printf, 2, 3)]]
|
||||||
|
void scriptWarning(WarningID id, char const *fmt, ...);
|
||||||
|
|
||||||
[[gnu::format(printf, 3, 4)]]
|
[[gnu::format(printf, 3, 4)]]
|
||||||
void error(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...);
|
void error(FileStackNode const *src, uint32_t lineNo, char const *fmt, ...);
|
||||||
|
|||||||
@@ -55,8 +55,14 @@
|
|||||||
#define setmode(fd, mode) (0)
|
#define setmode(fd, mode) (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// MingGW and Cygwin need POSIX functions which are not standard C explicitly enabled,
|
// Windows has 32-bit `long`, which limits `fseek` and `ftell` to 2 GiB
|
||||||
#if defined(__MINGW32__) || defined(__CYGWIN__)
|
#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
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
+48
-11
@@ -8,7 +8,8 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string>
|
#include <stdio.h>
|
||||||
|
#include <string_view>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
@@ -21,6 +22,13 @@ enum NumberBase {
|
|||||||
BASE_16 = 16,
|
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
|
// Locale-independent character class functions
|
||||||
bool isNewline(int c);
|
bool isNewline(int c);
|
||||||
bool isBlankSpace(int c);
|
bool isBlankSpace(int c);
|
||||||
@@ -29,10 +37,6 @@ bool isPrintable(int c);
|
|||||||
bool isUpper(int c);
|
bool isUpper(int c);
|
||||||
bool isLower(int c);
|
bool isLower(int c);
|
||||||
bool isLetter(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);
|
bool isAlphanumeric(int c);
|
||||||
|
|
||||||
// Locale-independent character transform functions
|
// Locale-independent character transform functions
|
||||||
@@ -42,30 +46,63 @@ char toUpper(char c);
|
|||||||
bool startsIdentifier(int c);
|
bool startsIdentifier(int c);
|
||||||
bool continuesIdentifier(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> parseNumber(char const *&str, NumberBase base = BASE_AUTO);
|
||||||
std::optional<uint64_t> parseWholeNumber(char const *str, NumberBase base = BASE_AUTO);
|
std::optional<uint64_t> parseWholeNumber(char const *str, NumberBase base = BASE_AUTO);
|
||||||
|
|
||||||
char const *printChar(int c);
|
char const *printChar(int c);
|
||||||
|
|
||||||
struct Uppercase {
|
struct Uppercase {
|
||||||
|
using is_transparent = void;
|
||||||
|
|
||||||
// FNV-1a hash of an uppercased string
|
// FNV-1a hash of an uppercased string
|
||||||
constexpr size_t operator()(std::string const &str) const {
|
constexpr size_t operator()(std::string_view str) const {
|
||||||
return std::accumulate(RANGE(str), 0x811C9DC5, [](size_t hash, char c) {
|
return std::accumulate(RANGE(str), size_t(0x811C9DC5), [](size_t hash, char c) {
|
||||||
return (hash ^ toUpper(c)) * 16777619;
|
return (hash ^ toUpper(c)) * 16777619;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare two strings without case-sensitivity (by converting to uppercase)
|
// 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 std::equal(RANGE(str1), RANGE(str2), [](char c1, char c2) {
|
||||||
return toUpper(c1) == toUpper(c2);
|
return toUpper(c1) == toUpper(c2);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// An unordered map from case-insensitive `std::string` keys to `ItemT` items
|
// An unordered map from case-insensitive `std::string_view` keys to `ItemT` items
|
||||||
template<typename ItemT>
|
template<typename ItemT>
|
||||||
using UpperMap = std::unordered_map<std::string, ItemT, Uppercase, Uppercase>;
|
using UpperMap = std::unordered_map<std::string_view, ItemT, Uppercase, Uppercase>;
|
||||||
|
|
||||||
#endif // RGBDS_UTIL_HPP
|
#endif // RGBDS_UTIL_HPP
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "helpers.hpp" // Procedure
|
||||||
|
#include "style.hpp"
|
||||||
|
|
||||||
// This macro does not evaluate its arguments unless the condition is true.
|
// This macro does not evaluate its arguments unless the condition is true.
|
||||||
#define verbosePrint(level, ...) \
|
#define verbosePrint(level, ...) \
|
||||||
do { \
|
do { \
|
||||||
@@ -30,6 +33,14 @@ bool checkVerbosity(Verbosity level);
|
|||||||
[[gnu::format(printf, 1, 2)]]
|
[[gnu::format(printf, 1, 2)]]
|
||||||
void printVerbosely(char const *fmt, ...);
|
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();
|
void printVVVVVVerbosity();
|
||||||
|
|
||||||
#endif // RGBDS_VERBOSITY_HPP
|
#endif // RGBDS_VERBOSITY_HPP
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#define PACKAGE_VERSION_MAJOR 1
|
#define PACKAGE_VERSION_MAJOR 1
|
||||||
#define PACKAGE_VERSION_MINOR 0
|
#define PACKAGE_VERSION_MINOR 0
|
||||||
#define PACKAGE_VERSION_PATCH 1
|
#define PACKAGE_VERSION_PATCH 3
|
||||||
// #define PACKAGE_VERSION_RC 1
|
// #define PACKAGE_VERSION_RC 1
|
||||||
|
|
||||||
char const *get_package_version_string();
|
char const *get_package_version_string();
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd January 1, 2026
|
.Dd August 1, 2026
|
||||||
.Dt GBZ80 7
|
.Dt GBZ80 7
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
|||||||
+44
-1
@@ -2,7 +2,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd January 1, 2026
|
.Dd August 1, 2026
|
||||||
.Dt RGBASM-OLD 5
|
.Dt RGBASM-OLD 5
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -140,12 +140,55 @@ Deprecated in 0.9.0, removed in 1.0.0.
|
|||||||
Instead, use a multi-value
|
Instead, use a multi-value
|
||||||
.Ic CHARMAP ,
|
.Ic CHARMAP ,
|
||||||
or explicitly combine the values of individual characters.
|
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
|
.Ss Treating strings as numbers
|
||||||
Deprecated in 1.0.0.
|
Deprecated in 1.0.0.
|
||||||
.Pp
|
.Pp
|
||||||
Instead, use character constants or the
|
Instead, use character constants or the
|
||||||
.Ic CHARVAL
|
.Ic CHARVAL
|
||||||
function.
|
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
|
.Ss rgbgfx -f/--fix and -F/--fix-and-save
|
||||||
Removed in 0.6.0.
|
Removed in 0.6.0.
|
||||||
.Pp
|
.Pp
|
||||||
|
|||||||
+4
-1
@@ -1,6 +1,6 @@
|
|||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd January 1, 2026
|
.Dd August 1, 2026
|
||||||
.Dt RGBASM 1
|
.Dt RGBASM 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -177,6 +177,9 @@ or
|
|||||||
The defaults are 0123.
|
The defaults are 0123.
|
||||||
.It Fl h , Fl \-help
|
.It Fl h , Fl \-help
|
||||||
Print help text for the program and exit.
|
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
|
.It Fl I Ar path , Fl \-include Ar path
|
||||||
Add a new
|
Add a new
|
||||||
.Dq include path ;
|
.Dq include path ;
|
||||||
|
|||||||
+10
-8
@@ -2,7 +2,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd January 1, 2026
|
.Dd August 1, 2026
|
||||||
.Dt RGBASM 5
|
.Dt RGBASM 5
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -745,9 +745,14 @@ The result may be constant if
|
|||||||
is able to compute it.
|
is able to compute it.
|
||||||
.It Fn SECTION symbol Ta Returns the name of the section that
|
.It Fn SECTION symbol Ta Returns the name of the section that
|
||||||
.Ar symbol
|
.Ar symbol
|
||||||
is in.
|
is defined in.
|
||||||
.Ar symbol
|
.Ar symbol
|
||||||
must have been defined already.
|
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
|
.It Fn SIZEOF arg Ta If
|
||||||
.Ar arg
|
.Ar arg
|
||||||
is a string, this function returns the size of the section named
|
is a string, this function returns the size of the section named
|
||||||
@@ -1737,9 +1742,6 @@ error: Undefined symbol "LabelA"
|
|||||||
at c.asm(2)
|
at c.asm(2)
|
||||||
Linking failed with 1 error
|
Linking failed with 1 error
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
|
||||||
Note also that only exported symbols will appear in symbol and map files produced by
|
|
||||||
.Xr rgblink 1 .
|
|
||||||
.Ss Purging symbols
|
.Ss Purging symbols
|
||||||
.Ic PURGE
|
.Ic PURGE
|
||||||
allows you to completely remove a symbol from the symbol table, as if it had never been defined.
|
allows you to completely remove a symbol from the symbol table, as if it had never been defined.
|
||||||
@@ -2571,9 +2573,9 @@ The stack's number of entries is limited only by the amount of memory in your ma
|
|||||||
.Ic PUSHO
|
.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:
|
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
|
.Bd -literal -offset indent
|
||||||
PUSHO b.X, g.oOX
|
PUSHO b.#, g.oO#
|
||||||
DB %..XXXX..
|
DB %..####..
|
||||||
DW `..ooOOXX
|
DW `..ooOO##
|
||||||
POPO
|
POPO
|
||||||
.Ed
|
.Ed
|
||||||
.Ss Excluding locations from backtraces
|
.Ss Excluding locations from backtraces
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd January 1, 2026
|
.Dd August 1, 2026
|
||||||
.Dt RGBDS 5
|
.Dt RGBDS 5
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd January 1, 2026
|
.Dd August 1, 2026
|
||||||
.Dt RGBDS 7
|
.Dt RGBDS 7
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
|||||||
+4
-1
@@ -1,6 +1,6 @@
|
|||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd January 1, 2026
|
.Dd August 1, 2026
|
||||||
.Dt RGBFIX 1
|
.Dt RGBFIX 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -152,6 +152,9 @@ Trash the global checksum.
|
|||||||
.El
|
.El
|
||||||
.It Fl h , Fl \-help
|
.It Fl h , Fl \-help
|
||||||
Print help text for the program and exit.
|
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
|
.It Fl i Ar game_id , Fl \-game-id Ar game_id
|
||||||
Set the game ID string
|
Set the game ID string
|
||||||
.Pq Ad 0x13F Ns \(en Ns Ad 0x142
|
.Pq Ad 0x13F Ns \(en Ns Ad 0x142
|
||||||
|
|||||||
+5
-1
@@ -2,7 +2,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd January 1, 2026
|
.Dd August 1, 2026
|
||||||
.Dt RGBGFX 1
|
.Dt RGBGFX 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
.Op Fl CmhOuVwXYZ
|
.Op Fl CmhOuVwXYZ
|
||||||
.Op Fl v Op Fl v No ...
|
.Op Fl v Op Fl v No ...
|
||||||
.Op Fl a Ar attrmap | Fl A
|
.Op Fl a Ar attrmap | Fl A
|
||||||
|
.Op Fl B Ar color
|
||||||
.Op Fl b Ar base_ids
|
.Op Fl b Ar base_ids
|
||||||
.Op Fl c Ar pal_spec
|
.Op Fl c Ar pal_spec
|
||||||
.Op Fl \-color Ar when
|
.Op Fl \-color Ar when
|
||||||
@@ -256,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).
|
This changes how tile data is output, and the maximum number of colors per palette (2 and 4 respectively).
|
||||||
.It Fl h , Fl \-help
|
.It Fl h , Fl \-help
|
||||||
Print help text for the program and exit.
|
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
|
.It Fl i Ar input_tiles , Fl \-input-tileset Ar input_tiles
|
||||||
Use the specified input tiles in addition to having
|
Use the specified input tiles in addition to having
|
||||||
.Nm
|
.Nm
|
||||||
|
|||||||
+17
-7
@@ -1,6 +1,6 @@
|
|||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd January 1, 2026
|
.Dd August 1, 2026
|
||||||
.Dt RGBLINK 1
|
.Dt RGBLINK 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -152,6 +152,9 @@ This option automatically enables
|
|||||||
.Fl w .
|
.Fl w .
|
||||||
.It Fl h , Fl \-help
|
.It Fl h , Fl \-help
|
||||||
Print help text for the program and exit.
|
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
|
.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.
|
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.
|
The attributes assigned in the linker script must be consistent with any assigned in the code.
|
||||||
@@ -257,22 +260,27 @@ an at-file, it only disables option processing within that at-file, and processi
|
|||||||
The default section placement algorithm tries to place sections into as few banks as possible.
|
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
|
(It turns out that section placement is an NP-complete problem known as "bin packing", so
|
||||||
.Nm
|
.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.
|
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.)
|
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
|
.Pp
|
||||||
.Dq Scrambling
|
.Dq Scrambling
|
||||||
instead places sections into a given pool of banks, trying to minimize the number of sections sharing a given bank.
|
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).
|
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
|
.Pp
|
||||||
A scrambling spec is a comma-separated list of region specs.
|
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.
|
A trailing comma is allowed, as well as whitespace between all specs and their components.
|
||||||
Each region spec has the following form:
|
Each region spec has the following form:
|
||||||
.D1 Ar region Ns Op = Ns Ar size
|
.D1 Ar region Ns Op = Ns Ar size
|
||||||
.Ar region
|
.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
|
must be one of the following (case-insensitive), while
|
||||||
.Ar size
|
.Ar size
|
||||||
must be a positive decimal integer between 1 and the corresponding maximum.
|
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"
|
.Bl -column "Region name" "Max value" "Size optional"
|
||||||
Region name Ta Max size Ta Size optional
|
Region name Ta Max size Ta Size optional
|
||||||
.Cm romx Ta 65535 Ta \&No
|
.Cm romx Ta 65535 Ta \&No
|
||||||
@@ -285,14 +293,14 @@ A
|
|||||||
of 0 disables scrambling for that region.
|
of 0 disables scrambling for that region.
|
||||||
.Pp
|
.Pp
|
||||||
For example,
|
For example,
|
||||||
.Ql romx=64,wramx=4
|
.Ql romx=64,wramx,sram=4
|
||||||
will scramble
|
will scramble
|
||||||
.Ic ROMX
|
.Ic ROMX
|
||||||
sections among ROM banks 1 to 64,
|
sections among ROM banks 1 to 64,
|
||||||
.Ic WRAMX
|
.Ic WRAMX
|
||||||
sections among RAM banks 1 to 4, and will not scramble
|
sections among RAM banks 1 to 7, and
|
||||||
.Ic SRAM
|
.Ic SRAM
|
||||||
sections.
|
sections among SRAM banks 0 to 3.
|
||||||
.Pp
|
.Pp
|
||||||
Later region specs override earlier ones; for example,
|
Later region specs override earlier ones; for example,
|
||||||
.Ql romx=42, Romx=0
|
.Ql romx=42, Romx=0
|
||||||
@@ -369,6 +377,8 @@ for
|
|||||||
Warn when dividing the smallest negative integer (-2**31) by -1, which yields itself due to integer overflow.
|
Warn when dividing the smallest negative integer (-2**31) by -1, which yields itself due to integer overflow.
|
||||||
This warning is enabled by
|
This warning is enabled by
|
||||||
.Fl Wall .
|
.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
|
.It Fl Wno-obsolete
|
||||||
Warn when obsolete features are encountered, which have been deprecated and may later be removed.
|
Warn when obsolete features are encountered, which have been deprecated and may later be removed.
|
||||||
.It Fl Wshift
|
.It Fl Wshift
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd January 1, 2026
|
.Dd August 1, 2026
|
||||||
.Dt RGBLINK 5
|
.Dt RGBLINK 5
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
# Generated by CMake
|
|
||||||
/.version.cpp
|
|
||||||
+78
-54
@@ -1,48 +1,44 @@
|
|||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
configure_file(version.cpp _version.cpp ESCAPE_QUOTES)
|
add_library(common OBJECT
|
||||||
|
|
||||||
set(common_src
|
|
||||||
"extern/getopt.cpp"
|
"extern/getopt.cpp"
|
||||||
"cli.cpp"
|
"cli.cpp"
|
||||||
"diagnostics.cpp"
|
"diagnostics.cpp"
|
||||||
"style.cpp"
|
"style.cpp"
|
||||||
"usage.cpp"
|
"usage.cpp"
|
||||||
"util.cpp"
|
"util.cpp"
|
||||||
"_version.cpp"
|
"version.cpp"
|
||||||
)
|
)
|
||||||
|
target_compile_definitions(common PRIVATE "BUILD_VERSION_STRING=\"${GIT_REV}\"")
|
||||||
|
|
||||||
find_package(BISON 3.0.0 REQUIRED)
|
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(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")
|
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()
|
endif()
|
||||||
if(BISON_VERSION VERSION_GREATER_EQUAL "3.6")
|
if(BISON_VERSION VERSION_GREATER_EQUAL "3.6")
|
||||||
set(BISON_FLAGS "${BISON_FLAGS} -Dparse.error=detailed")
|
set(BISON_FLAGS "${BISON_FLAGS} -Dparse.error=detailed")
|
||||||
else()
|
else()
|
||||||
set(BISON_FLAGS "${BISON_FLAGS} -Dparse.error=verbose")
|
set(BISON_FLAGS "${BISON_FLAGS} -Dparse.error=verbose")
|
||||||
endif()
|
endif()
|
||||||
|
if(BISON_VERSION VERSION_GREATER_EQUAL "3.7")
|
||||||
|
set(BISON_FLAGS "${BISON_FLAGS} -Wcounterexamples")
|
||||||
|
endif()
|
||||||
|
|
||||||
BISON_TARGET(ASM_PARSER "asm/parser.y"
|
bison_target(asm_parser "asm/parser.y"
|
||||||
"${PROJECT_SOURCE_DIR}/src/asm/parser.cpp"
|
"${CMAKE_CURRENT_BINARY_DIR}/parser.cpp"
|
||||||
COMPILE_FLAGS "${BISON_FLAGS}"
|
COMPILE_FLAGS "${BISON_FLAGS}")
|
||||||
DEFINES_FILE "${PROJECT_SOURCE_DIR}/src/asm/parser.hpp"
|
add_executable(rgbasm $<TARGET_OBJECTS:common>
|
||||||
)
|
"${BISON_asm_parser_OUTPUT_SOURCE}"
|
||||||
|
|
||||||
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}"
|
|
||||||
"asm/actions.cpp"
|
"asm/actions.cpp"
|
||||||
"asm/charmap.cpp"
|
"asm/charmap.cpp"
|
||||||
"asm/fixpoint.cpp"
|
"asm/fixpoint.cpp"
|
||||||
"asm/format.cpp"
|
"asm/format.cpp"
|
||||||
"asm/fstack.cpp"
|
"asm/fstack.cpp"
|
||||||
|
"asm/intern.cpp"
|
||||||
"asm/lexer.cpp"
|
"asm/lexer.cpp"
|
||||||
"asm/macro.cpp"
|
"asm/macro.cpp"
|
||||||
"asm/main.cpp"
|
"asm/main.cpp"
|
||||||
@@ -57,10 +53,15 @@ set(rgbasm_src
|
|||||||
"linkdefs.cpp"
|
"linkdefs.cpp"
|
||||||
"opmath.cpp"
|
"opmath.cpp"
|
||||||
"verbosity.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_target(linker_script_parser "link/script.y"
|
||||||
"${BISON_LINKER_SCRIPT_PARSER_OUTPUT_SOURCE}"
|
"${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/assign.cpp"
|
||||||
"link/fstack.cpp"
|
"link/fstack.cpp"
|
||||||
"link/lexer.cpp"
|
"link/lexer.cpp"
|
||||||
@@ -78,16 +79,18 @@ set(rgblink_src
|
|||||||
"linkdefs.cpp"
|
"linkdefs.cpp"
|
||||||
"opmath.cpp"
|
"opmath.cpp"
|
||||||
"verbosity.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/fix.cpp"
|
||||||
"fix/main.cpp"
|
"fix/main.cpp"
|
||||||
"fix/mbc.cpp"
|
"fix/mbc.cpp"
|
||||||
"fix/warning.cpp"
|
"fix/warning.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
set(rgbgfx_src
|
add_executable(rgbgfx $<TARGET_OBJECTS:common>
|
||||||
"gfx/color_set.cpp"
|
"gfx/color_set.cpp"
|
||||||
"gfx/main.cpp"
|
"gfx/main.cpp"
|
||||||
"gfx/pal_packing.cpp"
|
"gfx/pal_packing.cpp"
|
||||||
@@ -100,32 +103,53 @@ set(rgbgfx_src
|
|||||||
"gfx/rgba.cpp"
|
"gfx/rgba.cpp"
|
||||||
"gfx/warning.cpp"
|
"gfx/warning.cpp"
|
||||||
"verbosity.cpp"
|
"verbosity.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
foreach(PROG "asm" "fix" "gfx" "link")
|
install(TARGETS rgbasm rgblink rgbfix rgbgfx RUNTIME COMPONENT binaries)
|
||||||
add_executable(rgb${PROG}
|
# Tests expect the binaries to end up in-source; this is more acceptable than the entire artifact dir.
|
||||||
${rgb${PROG}_src}
|
set_target_properties(rgbasm rgblink rgbfix rgbgfx PROPERTIES
|
||||||
${common_src}
|
# 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}/..>)
|
||||||
install(TARGETS rgb${PROG} RUNTIME DESTINATION bin)
|
target_link_libraries(rgbgfx PRIVATE PNG::PNG)
|
||||||
# Required to run tests
|
# Copy the DLLs in the output directory so the program can be run for testing without having to `install`.
|
||||||
set_target_properties(rgb${PROG} PROPERTIES
|
# From https://cmake.org/cmake/help/v4.3/manual/cmake-generator-expressions.7.html#genex:TARGET_RUNTIME_DLLS.
|
||||||
# hack for MSVC: no-op generator expression to stop generation of "per-configuration subdirectory"
|
add_custom_command(TARGET rgbgfx POST_BUILD COMMENT "Copying rgbgfx's DLLs"
|
||||||
RUNTIME_OUTPUT_DIRECTORY $<1:${CMAKE_SOURCE_DIR}>)
|
# It would be nice to symlink instead, but that only supports one file at a time.
|
||||||
endforeach()
|
COMMAND ${CMAKE_COMMAND} -E copy -t $<TARGET_FILE_DIR:rgbgfx> $<TARGET_RUNTIME_DLLS:rgbgfx>
|
||||||
|
COMMAND_EXPAND_LISTS VERBATIM)
|
||||||
|
|
||||||
if(LIBPNG_FOUND) # pkg-config
|
if(WIN32)
|
||||||
target_include_directories(rgbgfx PRIVATE ${LIBPNG_INCLUDE_DIRS})
|
# CMake 3.27 is required for `$<INSTALL_PREFIX>`, but is only needed when cross-compiling for MinGW.
|
||||||
target_link_directories(rgbgfx PRIVATE ${LIBPNG_LIBRARY_DIRS})
|
if(CMAKE_VERSION VERSION_LESS "3.27")
|
||||||
target_link_libraries(rgbgfx PRIVATE ${LIBPNG_LIBRARIES})
|
message(WARNING "CMake 3.27 or higher is required for `\$<INSTALL_PREFIX>` inside `install(CODE)`")
|
||||||
else()
|
endif()
|
||||||
target_compile_definitions(rgbgfx PRIVATE ${PNG_DEFINITIONS})
|
# On Windows, you don't link against DLLs directly, but against an import library for that DLL.
|
||||||
target_include_directories(rgbgfx PRIVATE ${PNG_INCLUDE_DIRS})
|
# This leads to, sometimes, the DLL being stored in a directory far away from the import library itself!
|
||||||
target_link_libraries(rgbgfx PRIVATE ${PNG_LIBRARIES})
|
set(DLL_SEARCH_DIRS CACHE PATH "List of directories in which DLLs will be searched")
|
||||||
endif()
|
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.
|
||||||
include(CheckLibraryExists)
|
# Anyone who knows how to handle this better, feel free to submit a patch!
|
||||||
check_library_exists("m" "sin" "" HAS_LIBM)
|
if(DEFINED CMAKE_FIND_ROOT_PATH)
|
||||||
if(HAS_LIBM)
|
list(APPEND search_dirs "${CMAKE_FIND_ROOT_PATH}/bin")
|
||||||
target_link_libraries(rgbasm PRIVATE "m")
|
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()
|
endif()
|
||||||
|
|||||||
+29
-31
@@ -18,10 +18,12 @@
|
|||||||
#include "extern/utf8decoder.hpp"
|
#include "extern/utf8decoder.hpp"
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "linkdefs.hpp"
|
#include "linkdefs.hpp"
|
||||||
|
#include "util.hpp" // xfclose, seekSize
|
||||||
|
|
||||||
#include "asm/charmap.hpp"
|
#include "asm/charmap.hpp"
|
||||||
#include "asm/format.hpp"
|
#include "asm/format.hpp"
|
||||||
#include "asm/fstack.hpp"
|
#include "asm/fstack.hpp"
|
||||||
|
#include "asm/intern.hpp"
|
||||||
#include "asm/lexer.hpp"
|
#include "asm/lexer.hpp"
|
||||||
#include "asm/output.hpp"
|
#include "asm/output.hpp"
|
||||||
#include "asm/rpn.hpp" // Expression
|
#include "asm/rpn.hpp" // Expression
|
||||||
@@ -146,16 +148,15 @@ std::optional<std::string> act_ReadFile(std::string const &name, uint32_t maxLen
|
|||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
Defer closeFile{[&] { fclose(file); }};
|
Defer closeFile{[&] { xfclose(file); }};
|
||||||
|
|
||||||
size_t readSize = maxLen;
|
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,
|
// If the file is seekable and shorter than the max length,
|
||||||
// just read as many bytes as there are
|
// just read as many bytes as there are
|
||||||
if (long fileSize = ftell(file); static_cast<size_t>(fileSize) < readSize) {
|
if (*fileSize < readSize) {
|
||||||
readSize = fileSize;
|
readSize = *fileSize;
|
||||||
}
|
}
|
||||||
fseek(file, 0, SEEK_SET);
|
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
} else if (errno != ESPIPE) {
|
} else if (errno != ESPIPE) {
|
||||||
error(
|
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 act_StringLen(std::string const &str, bool printErrors) {
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
uint32_t state = UTF8_ACCEPT;
|
Utf8Decoder decoder;
|
||||||
uint32_t codepoint = 0;
|
|
||||||
|
|
||||||
for (char c : str) {
|
for (char c : str) {
|
||||||
uint8_t byte = static_cast<uint8_t>(c);
|
uint8_t byte = static_cast<uint8_t>(c);
|
||||||
|
|
||||||
switch (decode(&state, &codepoint, byte)) {
|
switch (decoder.update(byte)) {
|
||||||
case UTF8_REJECT:
|
case UTF8_REJECT:
|
||||||
if (printErrors) {
|
if (printErrors) {
|
||||||
errorInvalidUTF8Byte(byte, "STRLEN");
|
errorInvalidUTF8Byte(byte, "STRLEN");
|
||||||
}
|
}
|
||||||
state = UTF8_ACCEPT;
|
decoder.state = UTF8_ACCEPT;
|
||||||
// fallthrough
|
[[fallthrough]];
|
||||||
case UTF8_ACCEPT:
|
case UTF8_ACCEPT:
|
||||||
++len;
|
++len;
|
||||||
break;
|
break;
|
||||||
@@ -298,7 +298,7 @@ size_t act_StringLen(std::string const &str, bool printErrors) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for partial code point.
|
// Check for partial code point.
|
||||||
if (state != UTF8_ACCEPT) {
|
if (decoder.state != UTF8_ACCEPT) {
|
||||||
if (printErrors) {
|
if (printErrors) {
|
||||||
error("STRLEN: Incomplete UTF-8 character");
|
error("STRLEN: Incomplete UTF-8 character");
|
||||||
}
|
}
|
||||||
@@ -316,17 +316,16 @@ std::string
|
|||||||
|
|
||||||
size_t strLen = str.length();
|
size_t strLen = str.length();
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
uint32_t state = UTF8_ACCEPT;
|
Utf8Decoder decoder;
|
||||||
uint32_t codepoint = 0;
|
|
||||||
uint32_t curIdx = 0;
|
uint32_t curIdx = 0;
|
||||||
|
|
||||||
// Advance to starting index in source string.
|
// Advance to starting index in source string.
|
||||||
while (index < strLen && curIdx < start) {
|
while (index < strLen && curIdx < start) {
|
||||||
switch (decode(&state, &codepoint, str[index])) {
|
switch (decoder.update(str[index])) {
|
||||||
case UTF8_REJECT:
|
case UTF8_REJECT:
|
||||||
errorInvalidUTF8Byte(str[index], "STRSLICE");
|
errorInvalidUTF8Byte(str[index], "STRSLICE");
|
||||||
state = UTF8_ACCEPT;
|
decoder.state = UTF8_ACCEPT;
|
||||||
// fallthrough
|
[[fallthrough]];
|
||||||
case UTF8_ACCEPT:
|
case UTF8_ACCEPT:
|
||||||
++curIdx;
|
++curIdx;
|
||||||
break;
|
break;
|
||||||
@@ -348,11 +347,11 @@ std::string
|
|||||||
|
|
||||||
// Advance to ending index in source string.
|
// Advance to ending index in source string.
|
||||||
while (index < strLen && curIdx < stop) {
|
while (index < strLen && curIdx < stop) {
|
||||||
switch (decode(&state, &codepoint, str[index])) {
|
switch (decoder.update(str[index])) {
|
||||||
case UTF8_REJECT:
|
case UTF8_REJECT:
|
||||||
errorInvalidUTF8Byte(str[index], "STRSLICE");
|
errorInvalidUTF8Byte(str[index], "STRSLICE");
|
||||||
state = UTF8_ACCEPT;
|
decoder.state = UTF8_ACCEPT;
|
||||||
// fallthrough
|
[[fallthrough]];
|
||||||
case UTF8_ACCEPT:
|
case UTF8_ACCEPT:
|
||||||
++curIdx;
|
++curIdx;
|
||||||
break;
|
break;
|
||||||
@@ -361,7 +360,7 @@ std::string
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for partial code point.
|
// Check for partial code point.
|
||||||
if (state != UTF8_ACCEPT) {
|
if (decoder.state != UTF8_ACCEPT) {
|
||||||
error("STRSLICE: Incomplete UTF-8 character");
|
error("STRSLICE: Incomplete UTF-8 character");
|
||||||
++curIdx;
|
++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 strLen = str.length();
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
uint32_t state = UTF8_ACCEPT;
|
Utf8Decoder decoder;
|
||||||
uint32_t codepoint = 0;
|
|
||||||
uint32_t curPos = 1;
|
uint32_t curPos = 1;
|
||||||
|
|
||||||
// Advance to starting position in source string.
|
// Advance to starting position in source string.
|
||||||
while (index < strLen && curPos < pos) {
|
while (index < strLen && curPos < pos) {
|
||||||
switch (decode(&state, &codepoint, str[index])) {
|
switch (decoder.update(str[index])) {
|
||||||
case UTF8_REJECT:
|
case UTF8_REJECT:
|
||||||
errorInvalidUTF8Byte(str[index], "STRSUB");
|
errorInvalidUTF8Byte(str[index], "STRSUB");
|
||||||
state = UTF8_ACCEPT;
|
decoder.state = UTF8_ACCEPT;
|
||||||
// fallthrough
|
[[fallthrough]];
|
||||||
case UTF8_ACCEPT:
|
case UTF8_ACCEPT:
|
||||||
++curPos;
|
++curPos;
|
||||||
break;
|
break;
|
||||||
@@ -417,11 +415,11 @@ std::string act_StringSub(std::string const &str, int32_t negPos, std::optional<
|
|||||||
|
|
||||||
// Compute the result length in bytes.
|
// Compute the result length in bytes.
|
||||||
while (index < strLen && curLen < len) {
|
while (index < strLen && curLen < len) {
|
||||||
switch (decode(&state, &codepoint, str[index])) {
|
switch (decoder.update(str[index])) {
|
||||||
case UTF8_REJECT:
|
case UTF8_REJECT:
|
||||||
errorInvalidUTF8Byte(str[index], "STRSUB");
|
errorInvalidUTF8Byte(str[index], "STRSUB");
|
||||||
state = UTF8_ACCEPT;
|
decoder.state = UTF8_ACCEPT;
|
||||||
// fallthrough
|
[[fallthrough]];
|
||||||
case UTF8_ACCEPT:
|
case UTF8_ACCEPT:
|
||||||
++curLen;
|
++curLen;
|
||||||
break;
|
break;
|
||||||
@@ -430,7 +428,7 @@ std::string act_StringSub(std::string const &str, int32_t negPos, std::optional<
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for partial code point.
|
// Check for partial code point.
|
||||||
if (state != UTF8_ACCEPT) {
|
if (decoder.state != UTF8_ACCEPT) {
|
||||||
error("STRSUB: Incomplete UTF-8 character");
|
error("STRSUB: Incomplete UTF-8 character");
|
||||||
++curLen;
|
++curLen;
|
||||||
}
|
}
|
||||||
@@ -607,7 +605,7 @@ std::string act_StringFormat(
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string act_SectionName(std::string const &symName) {
|
std::string act_SectionName(InternedStr symName) {
|
||||||
Symbol *sym = sym_FindScopedValidSymbol(symName);
|
Symbol *sym = sym_FindScopedValidSymbol(symName);
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
if (sym_IsPurgedScoped(symName)) {
|
if (sym_IsPurgedScoped(symName)) {
|
||||||
@@ -625,7 +623,7 @@ std::string act_SectionName(std::string const &symName) {
|
|||||||
return section->name;
|
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;
|
Expression oldExpr, constExpr, newExpr;
|
||||||
oldExpr.makeSymbol(symName);
|
oldExpr.makeSymbol(symName);
|
||||||
constExpr.makeNumber(constValue);
|
constExpr.makeNumber(constValue);
|
||||||
|
|||||||
+70
-60
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "asm/charmap.hpp"
|
#include "asm/charmap.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <concepts> // predicate
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
@@ -19,27 +21,57 @@
|
|||||||
#include "itertools.hpp" // InsertionOrderedMap
|
#include "itertools.hpp" // InsertionOrderedMap
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
|
||||||
|
#include "asm/intern.hpp"
|
||||||
#include "asm/warning.hpp"
|
#include "asm/warning.hpp"
|
||||||
|
|
||||||
// Charmaps are stored using a structure known as "trie".
|
static InternedStr mainCharmapName;
|
||||||
// Essentially a tree, where each nodes stores a single character's worth of info:
|
|
||||||
// whether there exists a mapping that ends at the current character,
|
static bool compareNode(std::pair<char, size_t> edge, char c) {
|
||||||
|
return edge.first < c;
|
||||||
|
}
|
||||||
|
|
||||||
struct CharmapNode {
|
struct CharmapNode {
|
||||||
std::vector<int32_t> value; // The mapped value, if there exists a mapping that ends here
|
// The mapped value, if there exists a mapping that ends here; empty for non-terminal nodes.
|
||||||
|
std::vector<int32_t> value;
|
||||||
|
// Trie edges, pairing each next character with an index into the parent `Charmap`'s `nodes`.
|
||||||
|
// Sorted by character. Indexes must be nonzero.
|
||||||
// These MUST be indexes and not pointers, because pointers get invalidated by reallocation!
|
// These MUST be indexes and not pointers, because pointers get invalidated by reallocation!
|
||||||
size_t next[256]; // Indexes of where to go next, 0 = nowhere
|
std::vector<std::pair<char, size_t>> children;
|
||||||
|
|
||||||
bool isTerminal() const { return !value.empty(); }
|
bool isTerminal() const { return !value.empty(); }
|
||||||
|
|
||||||
|
size_t nextIndex(char c) const {
|
||||||
|
if (auto pos = std::lower_bound(RANGE(children), c, compareNode);
|
||||||
|
pos != children.end() && pos->first == c) {
|
||||||
|
assume(pos->second != 0);
|
||||||
|
return pos->second;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Charmap {
|
struct Charmap {
|
||||||
std::string name;
|
InternedStr name;
|
||||||
std::vector<CharmapNode> nodes; // first node is reserved for the root node
|
std::vector<CharmapNode> nodes; // Trie of mappings (first node is reserved for the root node)
|
||||||
|
|
||||||
|
size_t nextIndexOrAdd(size_t nodeIdx, char c) {
|
||||||
|
std::vector<std::pair<char, size_t>> &children = nodes[nodeIdx].children;
|
||||||
|
if (auto pos = std::lower_bound(RANGE(children), c, compareNode);
|
||||||
|
pos != children.end() && pos->first == c) {
|
||||||
|
assume(pos->second != 0);
|
||||||
|
return pos->second;
|
||||||
|
} else {
|
||||||
|
auto nextIdx = children.emplace(pos, c, nodes.size());
|
||||||
|
nodes.emplace_back();
|
||||||
|
return nextIdx->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Traverse the trie depth-first to derive the character mappings in definition order
|
// Traverse the trie depth-first to derive the character mappings in definition order
|
||||||
template<typename CallbackFnT>
|
bool forEachChar(
|
||||||
bool forEachChar(Charmap const &charmap, CallbackFnT callback) {
|
Charmap const &charmap, std::predicate<size_t, std::string const &> auto callback
|
||||||
|
) {
|
||||||
// clang-format off: nested initializers
|
// clang-format off: nested initializers
|
||||||
for (std::stack<std::pair<size_t, std::string>> prefixes({{0, ""}}); !prefixes.empty();) {
|
for (std::stack<std::pair<size_t, std::string>> prefixes({{0, ""}}); !prefixes.empty();) {
|
||||||
// clang-format on
|
// clang-format on
|
||||||
@@ -49,23 +81,26 @@ bool forEachChar(Charmap const &charmap, CallbackFnT callback) {
|
|||||||
if (node.isTerminal() && !callback(nodeIdx, mapping)) {
|
if (node.isTerminal() && !callback(nodeIdx, mapping)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (unsigned c = 0; c < std::size(node.next); ++c) {
|
for (auto const &[c, nextIdx] : node.children) {
|
||||||
if (size_t nextIdx = node.next[c]; nextIdx) {
|
assume(nextIdx);
|
||||||
prefixes.push({nextIdx, mapping + static_cast<char>(c)});
|
prefixes.push({nextIdx, mapping + c});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static InsertionOrderedMap<Charmap> charmaps;
|
static InsertionOrderedMap<InternedStr, Charmap> charmaps;
|
||||||
|
|
||||||
static Charmap *currentCharmap;
|
static Charmap *currentCharmap;
|
||||||
static std::stack<Charmap *> charmapStack;
|
static std::stack<Charmap *> charmapStack;
|
||||||
|
|
||||||
|
void charmap_Init() {
|
||||||
|
mainCharmapName = intern("main");
|
||||||
|
charmap_New(mainCharmapName, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
bool charmap_ForEach(
|
bool charmap_ForEach(
|
||||||
void (*mapFunc)(std::string const &),
|
void (*mapFunc)(InternedStr), void (*charFunc)(std::string const &, std::vector<int32_t>)
|
||||||
void (*charFunc)(std::string const &, std::vector<int32_t>)
|
|
||||||
) {
|
) {
|
||||||
for (Charmap const &charmap : charmaps) {
|
for (Charmap const &charmap : charmaps) {
|
||||||
std::map<size_t, std::string> mappings;
|
std::map<size_t, std::string> mappings;
|
||||||
@@ -82,7 +117,7 @@ bool charmap_ForEach(
|
|||||||
return !charmaps.empty();
|
return !charmaps.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void charmap_New(std::string const &name, std::string const *baseName) {
|
void charmap_New(InternedStr name, InternedStr const *baseName) {
|
||||||
std::optional<size_t> baseIdx = std::nullopt;
|
std::optional<size_t> baseIdx = std::nullopt;
|
||||||
|
|
||||||
if (baseName != nullptr) {
|
if (baseName != nullptr) {
|
||||||
@@ -109,7 +144,7 @@ void charmap_New(std::string const &name, std::string const *baseName) {
|
|||||||
currentCharmap = &charmap;
|
currentCharmap = &charmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
void charmap_Set(std::string const &name) {
|
void charmap_Set(InternedStr name) {
|
||||||
if (auto index = charmaps.findIndex(name); index) {
|
if (auto index = charmaps.findIndex(name); index) {
|
||||||
currentCharmap = &charmaps[*index];
|
currentCharmap = &charmaps[*index];
|
||||||
} else {
|
} else {
|
||||||
@@ -144,55 +179,25 @@ void charmap_Add(std::string const &mapping, std::vector<int32_t> &&value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Charmap &charmap = *currentCharmap;
|
Charmap &charmap = *currentCharmap;
|
||||||
|
|
||||||
size_t nodeIdx = 0;
|
size_t nodeIdx = 0;
|
||||||
|
|
||||||
for (char c : mapping) {
|
for (char c : mapping) {
|
||||||
size_t &nextIdxRef = charmap.nodes[nodeIdx].next[static_cast<uint8_t>(c)];
|
nodeIdx = charmap.nextIndexOrAdd(nodeIdx, c);
|
||||||
size_t nextIdx = nextIdxRef;
|
|
||||||
|
|
||||||
if (!nextIdx) {
|
|
||||||
// Switch to and zero-init the new node
|
|
||||||
nextIdxRef = charmap.nodes.size();
|
|
||||||
nextIdx = nextIdxRef;
|
|
||||||
// This may reallocate `charmap.nodes` and invalidate `nextIdxRef`,
|
|
||||||
// which is why we keep the actual value in `nextIdx`
|
|
||||||
charmap.nodes.emplace_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeIdx = nextIdx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CharmapNode &node = charmap.nodes[nodeIdx];
|
CharmapNode &node = charmap.nodes[nodeIdx];
|
||||||
|
|
||||||
if (node.isTerminal()) {
|
if (node.isTerminal()) {
|
||||||
warning(WARNING_CHARMAP_REDEF, "Overriding charmap mapping");
|
warning(WARNING_CHARMAP_REDEF, "Overriding charmap mapping");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::swap(node.value, value);
|
std::swap(node.value, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool charmap_HasChar(std::string const &mapping) {
|
|
||||||
Charmap const &charmap = *currentCharmap;
|
|
||||||
size_t nodeIdx = 0;
|
|
||||||
|
|
||||||
for (char c : mapping) {
|
|
||||||
nodeIdx = charmap.nodes[nodeIdx].next[static_cast<uint8_t>(c)];
|
|
||||||
|
|
||||||
if (!nodeIdx) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return charmap.nodes[nodeIdx].isTerminal();
|
|
||||||
}
|
|
||||||
|
|
||||||
static CharmapNode const *charmapEntry(std::string const &mapping) {
|
static CharmapNode const *charmapEntry(std::string const &mapping) {
|
||||||
Charmap const &charmap = *currentCharmap;
|
Charmap const &charmap = *currentCharmap;
|
||||||
|
|
||||||
size_t nodeIdx = 0;
|
size_t nodeIdx = 0;
|
||||||
|
|
||||||
for (char c : mapping) {
|
for (char c : mapping) {
|
||||||
nodeIdx = charmap.nodes[nodeIdx].next[static_cast<uint8_t>(c)];
|
nodeIdx = charmap.nodes[nodeIdx].nextIndex(c);
|
||||||
|
|
||||||
if (!nodeIdx) {
|
if (!nodeIdx) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -201,6 +206,11 @@ static CharmapNode const *charmapEntry(std::string const &mapping) {
|
|||||||
return &charmap.nodes[nodeIdx];
|
return &charmap.nodes[nodeIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool charmap_HasChar(std::string const &mapping) {
|
||||||
|
CharmapNode const *node = charmapEntry(mapping);
|
||||||
|
return node && node->isTerminal();
|
||||||
|
}
|
||||||
|
|
||||||
size_t charmap_CharSize(std::string const &mapping) {
|
size_t charmap_CharSize(std::string const &mapping) {
|
||||||
CharmapNode const *node = charmapEntry(mapping);
|
CharmapNode const *node = charmapEntry(mapping);
|
||||||
return node && node->isTerminal() ? node->value.size() : 0;
|
return node && node->isTerminal() ? node->value.size() : 0;
|
||||||
@@ -231,7 +241,7 @@ size_t charmap_ConvertNext(std::string_view &input, std::vector<int32_t> *output
|
|||||||
size_t inputIdx = 0;
|
size_t inputIdx = 0;
|
||||||
|
|
||||||
for (size_t nodeIdx = 0; inputIdx < input.length();) {
|
for (size_t nodeIdx = 0; inputIdx < input.length();) {
|
||||||
nodeIdx = charmap.nodes[nodeIdx].next[static_cast<uint8_t>(input[inputIdx])];
|
nodeIdx = charmap.nodes[nodeIdx].nextIndex(input[inputIdx]);
|
||||||
|
|
||||||
if (!nodeIdx) {
|
if (!nodeIdx) {
|
||||||
break;
|
break;
|
||||||
@@ -263,15 +273,14 @@ size_t charmap_ConvertNext(std::string_view &input, std::vector<int32_t> *output
|
|||||||
} else if (inputIdx < input.length()) { // No match found, but there is some input left
|
} else if (inputIdx < input.length()) { // No match found, but there is some input left
|
||||||
size_t codepointLen = 0;
|
size_t codepointLen = 0;
|
||||||
// This will write the codepoint's value to `output`, little-endian
|
// This will write the codepoint's value to `output`, little-endian
|
||||||
for (uint32_t state = UTF8_ACCEPT, codepoint = 0;
|
for (Utf8Decoder decoder; inputIdx + codepointLen < input.length();) {
|
||||||
inputIdx + codepointLen < input.length();) {
|
if (decoder.update(input[inputIdx + codepointLen]) == UTF8_REJECT) {
|
||||||
if (decode(&state, &codepoint, input[inputIdx + codepointLen]) == UTF8_REJECT) {
|
|
||||||
error("Input string is not valid UTF-8");
|
error("Input string is not valid UTF-8");
|
||||||
codepointLen = 1;
|
codepointLen = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
++codepointLen;
|
++codepointLen;
|
||||||
if (state == UTF8_ACCEPT) {
|
if (decoder.state == UTF8_ACCEPT) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -285,11 +294,12 @@ size_t charmap_ConvertNext(std::string_view &input, std::vector<int32_t> *output
|
|||||||
// Warn if this character is not mapped but any others are
|
// Warn if this character is not mapped but any others are
|
||||||
if (int firstChar = input[inputIdx]; charmap.nodes.size() > 1) {
|
if (int firstChar = input[inputIdx]; charmap.nodes.size() > 1) {
|
||||||
warning(WARNING_UNMAPPED_CHAR_1, "Unmapped character %s", printChar(firstChar));
|
warning(WARNING_UNMAPPED_CHAR_1, "Unmapped character %s", printChar(firstChar));
|
||||||
} else if (charmap.name != DEFAULT_CHARMAP_NAME) {
|
} else if (charmap.name != mainCharmapName) {
|
||||||
warning(
|
warning(
|
||||||
WARNING_UNMAPPED_CHAR_2,
|
WARNING_UNMAPPED_CHAR_2,
|
||||||
"Unmapped character %s not in `" DEFAULT_CHARMAP_NAME "` charmap",
|
"Unmapped character %s not in `%s` charmap",
|
||||||
printChar(firstChar)
|
printChar(firstChar),
|
||||||
|
mainCharmapName.c_str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-2
@@ -8,6 +8,8 @@
|
|||||||
#include <numbers>
|
#include <numbers>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "helpers.hpp" // assume
|
||||||
|
|
||||||
static constexpr double tau = std::numbers::pi * 2;
|
static constexpr double tau = std::numbers::pi * 2;
|
||||||
|
|
||||||
static double fix2double(int32_t i, int32_t q) {
|
static double fix2double(int32_t i, int32_t q) {
|
||||||
@@ -21,7 +23,8 @@ static int32_t double2fix(double d, int32_t q) {
|
|||||||
if (isinf(d)) {
|
if (isinf(d)) {
|
||||||
return d < 0 ? INT32_MIN : INT32_MAX;
|
return d < 0 ? INT32_MIN : INT32_MAX;
|
||||||
}
|
}
|
||||||
return static_cast<int32_t>(round(d * pow(2.0, q)));
|
double v = round(d * pow(2.0, q));
|
||||||
|
return v < INT32_MIN ? INT32_MIN : v > INT32_MAX ? INT32_MAX : static_cast<int32_t>(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
static double turn2rad(double t) {
|
static double turn2rad(double t) {
|
||||||
@@ -74,7 +77,11 @@ int32_t fix_Div(int32_t i, int32_t j, int32_t q) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int32_t fix_Mod(int32_t i, int32_t j, int32_t q) {
|
int32_t fix_Mod(int32_t i, int32_t j, int32_t q) {
|
||||||
return double2fix(fmod(fix2double(i, q), fix2double(j, q)), q);
|
double divisor = fix2double(j, q);
|
||||||
|
if (fpclassify(divisor) == FP_ZERO) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return double2fix(fmod(fix2double(i, q), divisor), q);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fix_Pow(int32_t i, int32_t j, int32_t q) {
|
int32_t fix_Pow(int32_t i, int32_t j, int32_t q) {
|
||||||
@@ -83,6 +90,9 @@ int32_t fix_Pow(int32_t i, int32_t j, int32_t q) {
|
|||||||
|
|
||||||
int32_t fix_Log(int32_t i, int32_t j, int32_t q) {
|
int32_t fix_Log(int32_t i, int32_t j, int32_t q) {
|
||||||
double divisor = log(fix2double(j, q));
|
double divisor = log(fix2double(j, q));
|
||||||
|
if (isnan(divisor) || isinf(divisor)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (fpclassify(divisor) == FP_ZERO) {
|
if (fpclassify(divisor) == FP_ZERO) {
|
||||||
return INT32_MAX;
|
return INT32_MAX;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -47,7 +47,7 @@ size_t FormatSpec::parseSpec(char const *spec) {
|
|||||||
padZero = true;
|
padZero = true;
|
||||||
}
|
}
|
||||||
// <width>
|
// <width>
|
||||||
if (isDigit(spec[i])) {
|
if (isDigit<10>(spec[i])) {
|
||||||
width = parseSpecNumber();
|
width = parseSpecNumber();
|
||||||
}
|
}
|
||||||
// <frac>
|
// <frac>
|
||||||
|
|||||||
+13
-14
@@ -25,6 +25,7 @@
|
|||||||
#include "platform.hpp" // strncasecmp
|
#include "platform.hpp" // strncasecmp
|
||||||
#include "verbosity.hpp"
|
#include "verbosity.hpp"
|
||||||
|
|
||||||
|
#include "asm/intern.hpp"
|
||||||
#include "asm/lexer.hpp"
|
#include "asm/lexer.hpp"
|
||||||
#include "asm/macro.hpp"
|
#include "asm/macro.hpp"
|
||||||
#include "asm/main.hpp"
|
#include "asm/main.hpp"
|
||||||
@@ -47,14 +48,14 @@ struct Context {
|
|||||||
bool isForLoop = false;
|
bool isForLoop = false;
|
||||||
int32_t forValue = 0;
|
int32_t forValue = 0;
|
||||||
int32_t forStep = 0;
|
int32_t forStep = 0;
|
||||||
std::string forName{};
|
InternedStr forName{};
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::stack<Context> contextStack;
|
static std::stack<Context> contextStack;
|
||||||
|
|
||||||
// The first include path for `fstk_FindFile` to try is none at all
|
// The first include path for `fstk_FindFile` to try is none at all
|
||||||
static std::vector<std::string> includePaths = {""}; // -I
|
static std::vector<std::string> includePaths = {""}; // -I
|
||||||
static std::deque<std::string> preIncludeNames; // -P
|
static std::deque<std::string> preIncludeStack; // -P
|
||||||
static bool failedOnMissingInclude = false;
|
static bool failedOnMissingInclude = false;
|
||||||
|
|
||||||
void FileStackNode::printBacktrace(uint32_t curLineNo) const {
|
void FileStackNode::printBacktrace(uint32_t curLineNo) const {
|
||||||
@@ -124,9 +125,9 @@ void fstk_VerboseOutputConfig() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -P/--preinclude
|
// -P/--preinclude
|
||||||
if (!preIncludeNames.empty()) {
|
if (!preIncludeStack.empty()) {
|
||||||
fputs("\tPreincluded files:\n", stderr);
|
fputs("\tPreincluded files:\n", stderr);
|
||||||
for (std::string const &name : preIncludeNames) {
|
for (std::string const &name : preIncludeStack) {
|
||||||
fprintf(stderr, "\t - %s\n", name.c_str());
|
fprintf(stderr, "\t - %s\n", name.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,7 +169,7 @@ void fstk_AddIncludePath(std::string const &path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void fstk_AddPreIncludeFile(std::string const &path) {
|
void fstk_AddPreIncludeFile(std::string const &path) {
|
||||||
preIncludeNames.emplace_front(path);
|
preIncludeStack.emplace_front(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isValidFilePath(std::string const &path) {
|
static bool isValidFilePath(std::string const &path) {
|
||||||
@@ -309,7 +310,7 @@ static void
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fileInfoName.append(NODE_SEPARATOR);
|
fileInfoName.append(NODE_SEPARATOR);
|
||||||
fileInfoName.append(macro.name);
|
fileInfoName.append(macro.name.str());
|
||||||
|
|
||||||
auto fileInfo = std::make_shared<FileStackNode>(NODE_MACRO, fileInfoName, isQuiet);
|
auto fileInfo = std::make_shared<FileStackNode>(NODE_MACRO, fileInfoName, isQuiet);
|
||||||
assume(!contextStack.empty()); // The top level context cannot be a MACRO
|
assume(!contextStack.empty()); // The top level context cannot be a MACRO
|
||||||
@@ -389,9 +390,7 @@ bool fstk_RunInclude(std::string const &path, bool isQuiet) {
|
|||||||
return fstk_FileError(path, "`INCLUDE`");
|
return fstk_FileError(path, "`INCLUDE`");
|
||||||
}
|
}
|
||||||
|
|
||||||
void fstk_RunMacro(
|
void fstk_RunMacro(InternedStr macroName, std::shared_ptr<MacroArgs> macroArgs, bool isQuiet) {
|
||||||
std::string const ¯oName, std::shared_ptr<MacroArgs> macroArgs, bool isQuiet
|
|
||||||
) {
|
|
||||||
auto makeSuggestion = [¯oName, ¯oArgs]() -> std::optional<std::string> {
|
auto makeSuggestion = [¯oName, ¯oArgs]() -> std::optional<std::string> {
|
||||||
std::shared_ptr<std::string> arg = macroArgs->getArg(1);
|
std::shared_ptr<std::string> arg = macroArgs->getArg(1);
|
||||||
if (!arg) {
|
if (!arg) {
|
||||||
@@ -402,14 +401,14 @@ void fstk_RunMacro(
|
|||||||
static char const *types[] = {"EQUS", "EQU", "RB", "RW", "RL", "="};
|
static char const *types[] = {"EQUS", "EQU", "RB", "RW", "RL", "="};
|
||||||
for (char const *type : types) {
|
for (char const *type : types) {
|
||||||
if (strncasecmp(str, type, strlen(type)) == 0) {
|
if (strncasecmp(str, type, strlen(type)) == 0) {
|
||||||
return "\"DEF "s + macroName + " " + type + " ...\"";
|
return "\"DEF "s + macroName.str() + " " + type + " ...\"";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (strncasecmp(str, "SET", literal_strlen("SET")) == 0) {
|
if (strncasecmp(str, "SET", literal_strlen("SET")) == 0) {
|
||||||
return "\"DEF "s + macroName + " = ...\"";
|
return "\"DEF "s + macroName.str() + " = ...\"";
|
||||||
}
|
}
|
||||||
if (str[0] == ':') {
|
if (str[0] == ':') {
|
||||||
return "a label \""s + macroName + (str[1] == ':' ? "::" : ":") + "\"";
|
return "a label \""s + macroName.str() + (str[1] == ':' ? "::" : ":") + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@@ -439,7 +438,7 @@ void fstk_RunRept(uint32_t count, int32_t reptLineNo, ContentSpan const &span, b
|
|||||||
}
|
}
|
||||||
|
|
||||||
void fstk_RunFor(
|
void fstk_RunFor(
|
||||||
std::string const &symName,
|
InternedStr symName,
|
||||||
int32_t start,
|
int32_t start,
|
||||||
int32_t stop,
|
int32_t stop,
|
||||||
int32_t step,
|
int32_t step,
|
||||||
@@ -497,7 +496,7 @@ void fstk_NewRecursionDepth(size_t newDepth) {
|
|||||||
bool fstk_Init(std::string const &mainPath) {
|
bool fstk_Init(std::string const &mainPath) {
|
||||||
newFileContext(mainPath, false, true);
|
newFileContext(mainPath, false, true);
|
||||||
|
|
||||||
for (std::string const &name : preIncludeNames) {
|
for (std::string const &name : preIncludeStack) {
|
||||||
if (std::optional<std::string> fullPath = fstk_FindFile(name); fullPath) {
|
if (std::optional<std::string> fullPath = fstk_FindFile(name); fullPath) {
|
||||||
newFileContext(*fullPath, false, false);
|
newFileContext(*fullPath, false, false);
|
||||||
} else if (fstk_FileError(name, "pre-included")) {
|
} else if (fstk_FileError(name, "pre-included")) {
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "asm/intern.hpp"
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <functional> // equal_to
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "helpers.hpp" // assume
|
||||||
|
#include "verbosity.hpp"
|
||||||
|
|
||||||
|
// Avoid `std::string` allocations when looking up heterogeneous values in `internedIndexes`
|
||||||
|
struct StringHash {
|
||||||
|
using is_transparent = void;
|
||||||
|
|
||||||
|
size_t operator()(std::string_view str) const { return std::hash<std::string_view>{}(str); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use a `deque` not a `vector` to prevent reallocation so `internedIndexes` keys stay valid
|
||||||
|
static std::deque<std::string> internedStrings;
|
||||||
|
// Keys are views of values in `internedStrings`; values are their corresponding indexes
|
||||||
|
static std::unordered_map<std::string_view, size_t, StringHash, std::equal_to<>> internedIndexes;
|
||||||
|
|
||||||
|
std::string const &InternedStr::str() const {
|
||||||
|
assume(index != static_cast<size_t>(-1));
|
||||||
|
return internedStrings[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
InternedStr intern(std::string_view str) {
|
||||||
|
if (auto search = internedIndexes.find(str); search != internedIndexes.end()) {
|
||||||
|
return InternedStr(search->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t index = internedStrings.size();
|
||||||
|
std::string &interned = internedStrings.emplace_back(str);
|
||||||
|
internedIndexes.emplace(interned, index);
|
||||||
|
|
||||||
|
verbosePrint(VERB_TRACE, "Interned string \"%s\"\n", interned.c_str());
|
||||||
|
|
||||||
|
return InternedStr(index);
|
||||||
|
}
|
||||||
+513
-461
File diff suppressed because it is too large
Load Diff
+17
-9
@@ -8,18 +8,26 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "helpers.hpp" // assume
|
||||||
|
|
||||||
#include "asm/warning.hpp"
|
#include "asm/warning.hpp"
|
||||||
|
|
||||||
std::shared_ptr<std::string> MacroArgs::getArg(int32_t i) const {
|
std::shared_ptr<std::string> MacroArgs::getArg(int32_t num) const {
|
||||||
// Bracketed macro arguments adjust negative indexes such that -1 is the last argument.
|
assume(num != 0);
|
||||||
if (i < 0) {
|
if (num > 0) {
|
||||||
i += args.size() + 1;
|
// Macro arguments adjust 1-based indexes by the shift amount.
|
||||||
|
if (size_t i = num - 1 + shift; i < args.size()) {
|
||||||
|
return args[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Bracketed macro arguments adjust negative indexes such that -1 is the last argument.
|
||||||
|
if (num == INT32_MIN || static_cast<size_t>(-num) > args.size()) {
|
||||||
|
return nullptr;
|
||||||
|
} else if (size_t i = args.size() - static_cast<size_t>(-num); i >= shift) {
|
||||||
|
return args[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
int32_t realIndex = i + shift - 1;
|
|
||||||
|
|
||||||
return realIndex < 0 || static_cast<uint32_t>(realIndex) >= args.size() ? nullptr
|
|
||||||
: args[realIndex];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<std::string> MacroArgs::getAllArgs() const {
|
std::shared_ptr<std::string> MacroArgs::getAllArgs() const {
|
||||||
|
|||||||
+12
-19
@@ -24,7 +24,7 @@
|
|||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "parser.hpp" // Generated from parser.y
|
#include "parser.hpp" // Generated from parser.y
|
||||||
#include "platform.hpp"
|
#include "platform.hpp"
|
||||||
#include "style.hpp"
|
#include "style.hpp" // style_Parse
|
||||||
#include "usage.hpp"
|
#include "usage.hpp"
|
||||||
#include "util.hpp" // UpperMap
|
#include "util.hpp" // UpperMap
|
||||||
#include "verbosity.hpp"
|
#include "verbosity.hpp"
|
||||||
@@ -190,9 +190,9 @@ static void parseArg(int ch, char *arg) {
|
|||||||
char *equals = strchr(arg, '=');
|
char *equals = strchr(arg, '=');
|
||||||
if (equals) {
|
if (equals) {
|
||||||
*equals = '\0';
|
*equals = '\0';
|
||||||
sym_AddString(arg, std::make_shared<std::string>(equals + 1));
|
sym_AddString(intern(arg), std::make_shared<std::string>(equals + 1));
|
||||||
} else {
|
} else {
|
||||||
sym_AddString(arg, std::make_shared<std::string>("1"));
|
sym_AddString(intern(arg), std::make_shared<std::string>("1"));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -267,6 +267,7 @@ static void parseArg(int ch, char *arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'r':
|
case 'r':
|
||||||
|
errno = 0;
|
||||||
if (std::optional<uint64_t> maxDepth = parseWholeNumber(arg); !maxDepth) {
|
if (std::optional<uint64_t> maxDepth = parseWholeNumber(arg); !maxDepth) {
|
||||||
fatal("Invalid argument for option '-r'");
|
fatal("Invalid argument for option '-r'");
|
||||||
} else if (errno == ERANGE) {
|
} else if (errno == ERANGE) {
|
||||||
@@ -289,7 +290,7 @@ static void parseArg(int ch, char *arg) {
|
|||||||
if (localOptions.stateFileSpecs.find(name) != localOptions.stateFileSpecs.end()) {
|
if (localOptions.stateFileSpecs.find(name) != localOptions.stateFileSpecs.end()) {
|
||||||
warnx("Overriding state file \"%s\"", name);
|
warnx("Overriding state file \"%s\"", name);
|
||||||
}
|
}
|
||||||
localOptions.stateFileSpecs.emplace(name, std::move(features));
|
localOptions.stateFileSpecs[name] = std::move(features);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,8 +315,6 @@ static void parseArg(int ch, char *arg) {
|
|||||||
case 'X':
|
case 'X':
|
||||||
if (std::optional<uint64_t> maxErrors = parseWholeNumber(arg); !maxErrors) {
|
if (std::optional<uint64_t> maxErrors = parseWholeNumber(arg); !maxErrors) {
|
||||||
fatal("Invalid argument for option '-X'");
|
fatal("Invalid argument for option '-X'");
|
||||||
} else if (*maxErrors > UINT64_MAX) {
|
|
||||||
fatal("Argument for option '-X' must be between 0 and %" PRIu64, UINT64_MAX);
|
|
||||||
} else {
|
} else {
|
||||||
options.maxErrors = *maxErrors;
|
options.maxErrors = *maxErrors;
|
||||||
}
|
}
|
||||||
@@ -374,12 +373,6 @@ static void parseArg(int ch, char *arg) {
|
|||||||
|
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
static void verboseOutputConfig() {
|
static void verboseOutputConfig() {
|
||||||
if (!checkVerbosity(VERB_CONFIG)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
style_Set(stderr, STYLE_MAGENTA, false);
|
|
||||||
|
|
||||||
usage.printVersion(true);
|
usage.printVersion(true);
|
||||||
|
|
||||||
printVVVVVVerbosity();
|
printVVVVVVerbosity();
|
||||||
@@ -491,8 +484,6 @@ static void verboseOutputConfig() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fputs("Ready for assembly\n", stderr);
|
fputs("Ready for assembly\n", stderr);
|
||||||
|
|
||||||
style_Reset(stderr);
|
|
||||||
}
|
}
|
||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
|
|
||||||
@@ -501,9 +492,11 @@ int main(int argc, char *argv[]) {
|
|||||||
// https://reproducible-builds.org/docs/source-date-epoch/
|
// https://reproducible-builds.org/docs/source-date-epoch/
|
||||||
time_t now = time(nullptr);
|
time_t now = time(nullptr);
|
||||||
if (char const *sourceDateEpoch = getenv("SOURCE_DATE_EPOCH"); sourceDateEpoch) {
|
if (char const *sourceDateEpoch = getenv("SOURCE_DATE_EPOCH"); sourceDateEpoch) {
|
||||||
// Use `strtoul`, not `parseWholeNumber`, because SOURCE_DATE_EPOCH does
|
if (std::optional<uint64_t> epoch = parseWholeNumber(sourceDateEpoch, BASE_10); epoch) {
|
||||||
// not conventionally support our custom base prefixes
|
now = static_cast<time_t>(*epoch);
|
||||||
now = static_cast<time_t>(strtoul(sourceDateEpoch, nullptr, 0));
|
} else {
|
||||||
|
warnx("Ignoring invalid `SOURCE_DATE_EPOCH` value \"%s\"", sourceDateEpoch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sym_Init(now);
|
sym_Init(now);
|
||||||
|
|
||||||
@@ -518,7 +511,7 @@ int main(int argc, char *argv[]) {
|
|||||||
options.targetFileName = options.objectFileName;
|
options.targetFileName = options.objectFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
verboseOutputConfig();
|
verboseDo(VERB_CONFIG, verboseOutputConfig);
|
||||||
|
|
||||||
if (!localOptions.inputFileName) {
|
if (!localOptions.inputFileName) {
|
||||||
usage.printAndExit("No input file specified (pass \"-\" to read from standard input)");
|
usage.printAndExit("No input file specified (pass \"-\" to read from standard input)");
|
||||||
@@ -556,7 +549,7 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
options.printDep(*localOptions.inputFileName);
|
options.printDep(*localOptions.inputFileName);
|
||||||
|
|
||||||
charmap_New(DEFAULT_CHARMAP_NAME, nullptr);
|
charmap_Init();
|
||||||
|
|
||||||
// Init lexer and file stack, and parse (`yy::parser` is auto-generated from `parser.y`)
|
// Init lexer and file stack, and parse (`yy::parser` is auto-generated from `parser.y`)
|
||||||
if (yy::parser parser; fstk_Init(*localOptions.inputFileName) && parser.parse() != 0) {
|
if (yy::parser parser; fstk_Init(*localOptions.inputFileName) && parser.parse() != 0) {
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ void opt_Parse(char const *s) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'r':
|
case 'r':
|
||||||
|
errno = 0;
|
||||||
if (std::optional<uint64_t> maxRecursionDepth = parseWholeNumber(s); !maxRecursionDepth) {
|
if (std::optional<uint64_t> maxRecursionDepth = parseWholeNumber(s); !maxRecursionDepth) {
|
||||||
error("Invalid argument for option 'r'");
|
error("Invalid argument for option 'r'");
|
||||||
} else if (errno == ERANGE) {
|
} else if (errno == ERANGE) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user