Compare commits

..

32 Commits

Author SHA1 Message Date
Rangi
69a573923f Version 0.6.1 2022-12-02 22:48:37 -05:00
ISSOtm
7eb4ecea8b Remove use of std::filesystem
This appears to break compatibility with macOS 10.9
2022-12-03 01:51:14 +01:00
ISSOtm
599ce757a1 Force Windows builds to use our zlib and libpng
Otherwise we will have a few problems if, say, a system version was
detected and picked up instead of ours...
2022-12-03 00:58:50 +01:00
ISSOtm
75a07a90f8 Always initialise section->data to avoid an uninit read
The addition of SDCC objects required a change in the logic of
`mergeSections()` to dispatch based on `->data` instead of
`sect_HasData`, which implicitly assumes that `->data` is
always initialised (maybe NULL).
However, RGBDS sections did not do that!
2022-12-02 22:39:31 +01:00
ISSOtm
ec2d1312ef Remove auto parameter to -flto
Not all supported compilers support the argument;
the move was a bit premature.
2022-11-15 19:49:04 +01:00
ISSOtm
03b6dd9321 Only cache dependency directories instead of whole test/
Otherwise, changes made to the test suite are not picked up
2022-11-15 19:49:04 +01:00
ISSOtm
a16d3d6405 Fail RGBGFX test suite if support test programs fail to be built 2022-11-15 19:49:04 +01:00
ISSOtm
3e5cd8ce1a Use a special name for stdin/stdout in diagnostics 2022-11-15 19:49:04 +01:00
ISSOtm
6902387991 Allow rgbgfx - for stdin and stdout
Closes #1087
2022-11-15 19:49:04 +01:00
ISSOtm
62b4f2b264 Upgrade to checkout action v3
No code changes, just uses Node 16 instead of the
deprecated Node 12
2022-11-13 14:33:03 +01:00
Rangi
79748afdc4 Align the "; Next union/fragment" comments with their symbols 2022-11-06 23:55:15 +01:00
Rangi
32cb0558e4 Print "; Next union/fragment" between "pieces" in .map file
Resolves #1099
2022-11-06 23:55:15 +01:00
rlewicki
92b2ac3c8c Remove duplicated EMPTY label in case no bank memory is used 2022-11-03 19:54:21 +01:00
rlewicki
0e67298dff Fix indention when writing EMPTY label inside link output.c file 2022-11-03 19:54:21 +01:00
Robert Lewicki
f6d218ed36 Fix regression tests failing due to invalid cache being restored (#1104) 2022-11-01 14:27:40 +01:00
Robert Lewicki
1a9fc964df #1082 Add cache check for external repositories used during testing (#1100)
Co-authored-by: Rangi <35663410+Rangi42@users.noreply.github.com>
Co-authored-by: Eldred Habert <eldredhabert0@gmail.com>
2022-10-25 08:39:19 +02:00
ISSOtm
48248faab0 Suppress CMake project maintainer warnings in CI 2022-10-16 12:21:54 +02:00
ISSOtm
58181c2d73 Hoist common Windows dep grabbing code to a script
Function courtesy of @aaaaaa123456789
2022-10-16 12:21:54 +02:00
ISSOtm
0f86084e08 Rename actions folder as scripts
It's clearer this way.
2022-10-16 12:21:54 +02:00
ISSOtm
c8e602dec1 Mangle the name of absolute sections
They are unlikely to be unique across files, actually
2022-10-15 23:16:04 +02:00
ISSOtm
b168717e91 Update zlib to 1.2.13
1.2.12 is no longer provided by upstream anymore,
which fails Windows CI
2022-10-15 22:02:34 +02:00
ISSOtm
930c2ac328 Require Bison 3.0.0 in CMakeLists
We actually require that version, so be explicit about it
to provide better error messages.
2022-10-13 11:02:33 +02:00
ISSOtm
28737d5778 Enable GLIBCXX_ASSERTIONS in make develop
Not sure it's very portable, but this is only the dev config
2022-10-12 01:23:37 +02:00
ISSOtm
12ba057b4f Check that colour slot is non-empty before checking for gray-ness
This is otherwise UB, and trips a GLIBCXX assertion (when enabled).
2022-10-11 21:39:32 +02:00
ISSOtm
0e0876b17f Print addr ranges for empty blocks as well
Mirrors what sections do, for clarity & consistency
2022-10-07 16:04:02 +02:00
Eldred Habert
b28eea24fc Update .github/workflows/create-release-artifacts.yaml
Co-authored-by: Rangi <35663410+Rangi42@users.noreply.github.com>
2022-10-04 12:50:46 -04:00
ISSOtm
a1e59ddc3d Avoid -x c++ affecting ${PNGLDLIBS}
version.c doesn't link to anything from libpng, so it'll be fine
2022-10-04 12:50:46 -04:00
ISSOtm
3fbdba31bf Build macOS binaries as well for releases 2022-10-04 12:50:46 -04:00
ISSOtm
d90a7e4302 Terminate RGBGFX when opening a file fails
`std::filebuf::open`'s result must be checked, though that's not obvious.
2022-10-04 13:58:05 +02:00
ISSOtm
7377a14245 Improve RGBASM's "input files" error messages slightly 2022-10-03 17:17:19 +02:00
Eldred Habert
e2136d60b2 Print a more user-friendly error message for leftover diff marks (#1089) 2022-10-03 16:52:29 +02:00
ISSOtm
74e40654e6 Sync release docs CI workflow with master
We should look into reusable workflows, really.
https://docs.github.com/en/actions/using-workflows/reusing-workflows
2022-10-03 01:50:17 +02:00
28 changed files with 556 additions and 243 deletions

23
.github/scripts/get_win_deps.ps1 vendored Normal file
View File

@@ -0,0 +1,23 @@
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/zlib1213.zip' 'zlib.zip' 'd233fca7cf68db4c16dc5287af61f3cd01ab62495224c66639ca3da537701e42' .
getlibrary 'https://download.sourceforge.net/libpng/lpng1637.zip' 'libpng.zip' '3b4b1cbd0bae6822f749d39b1ccadd6297f05e2b85a83dd2ce6ecd7d09eabdf2' .
getlibrary 'https://github.com/lexxmark/winflexbison/releases/download/v2.5.24/win_flex_bison-2.5.24.zip' 'winflexbison.zip' '39c6086ce211d5415500acc5ed2d8939861ca1696aee48909c7f6daf5122b505' install_dir
Move-Item zlib-1.2.13 zlib
Move-Item lpng1637 libpng

6
.github/scripts/install.sh vendored Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/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 /usr/local/share/man/man5/
install -m 644 rgbds.7 gbz80.7 /usr/local/share/man/man7/

View File

@@ -9,7 +9,7 @@ arch="$1"
wget http://downloads.sourceforge.net/project/libpng/libpng16/$pngver/libpng-$pngver.tar.xz
wget http://downloads.sourceforge.net/project/apng/libpng/libpng16/libpng-$pngver-apng.patch.gz
sha256sum -c .github/actions/mingw-w64-libpng-dev.sha256sums
sha256sum -c .github/scripts/mingw-w64-libpng-dev.sha256sums
## Extract sources and patch them

View File

@@ -7,77 +7,107 @@ on:
jobs:
windows:
runs-on: windows-2022
strategy:
matrix:
bits: [32, 64]
include:
- bits: 32
arch: x86
platform: Win32
- bits: 64
arch: x86_x64
platform: x64
fail-fast: false
steps:
- name: Get version from tag
shell: bash
run: | # Turn "vX.Y.Z" into "X.Y.Z"
VERSION="${{ github.ref_name }}"
echo "version=${VERSION#v}" >> $GITHUB_ENV
- uses: actions/checkout@v3
- name: Install deps
run: .github/scripts/get_win_deps.ps1
- uses: actions/cache@v3
id: cache
with:
path: |
zbuild
pngbuild
key: ${{ matrix.arch }}-${{ hashFiles('zlib/**', 'libpng/**') }}
- name: Build zlib
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
if: steps.cache.outputs.cache-hit != 'true'
- name: Install zlib
run: |
cmake --install zbuild
- name: Build libpng
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 -DPNG_BUILD_ZLIB=ON -DZLIB_INCLUDE_DIR="$PWD"/install_dir/include -DZLIB_LIBRARY="$PWD"/install_dir/lib/zlib.lib
cmake --build pngbuild --config Release -j
if: steps.cache.outputs.cache-hit != 'true'
- 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 -DZLIB_LIBRARY="$PWD"/install_dir/lib/zlib.lib -DZLIB_INCLUDE_DIR="$PWD"/install_dir/include -DPNG_LIBRARY="$PWD"/install_dir/lib/libpng16.lib -DPNG_INCLUDE_DIR="$PWD"/install_dir/include
cmake --build build --config Release -j --verbose
cmake --install build --verbose --prefix install_dir --strip
- name: Package binaries
run: |
Compress-Archive -LiteralPath @("install_dir/bin/rgbasm.exe", "install_dir/bin/rgblink.exe", "install_dir/bin/rgbfix.exe", "install_dir/bin/rgbgfx.exe", "install_dir/bin/zlib1.dll", "install_dir/bin/libpng16.dll") "rgbds-${{ env.version }}-win${{ matrix.bits }}.zip"
- name: Upload Windows binaries
uses: actions/upload-artifact@v3
with:
name: win${{ matrix.bits }}
path: rgbds-${{ env.version }}-win${{ matrix.bits }}.zip
macos:
runs-on: macos-12
steps:
- uses: actions/checkout@v2
- name: Get version from tag
shell: bash
run: | # Turn "refs/tags/vX.Y.Z" into "X.Y.Z"
VERSION="${{ github.ref }}"
echo "version=${VERSION##*/v}" >> $GITHUB_ENV
- name: Get zlib, libpng and bison
run: | # TODO: use an array
$wc = New-Object System.Net.WebClient
$wc.DownloadFile('https://www.zlib.net/zlib1212.zip', 'zlib.zip')
$hash = (Get-FileHash "zlib.zip" -Algorithm SHA256).Hash
if ($hash -ne '173e89893dcb8b4a150d7731cd72f0602f1d6b45e60e2a54efdf7f3fc3325fd7') {
Write-Host "zlib SHA256 mismatch! ($hash)"
exit 1
}
$wc.DownloadFile('https://download.sourceforge.net/libpng/lpng1637.zip', 'libpng.zip')
$hash = (Get-FileHash "libpng.zip" -Algorithm SHA256).Hash
if ($hash -ne '3b4b1cbd0bae6822f749d39b1ccadd6297f05e2b85a83dd2ce6ecd7d09eabdf2') {
Write-Host "libpng SHA256 mismatch! ($hash)"
exit 1
}
$wc.DownloadFile('https://github.com/lexxmark/winflexbison/releases/download/v2.5.24/win_flex_bison-2.5.24.zip', 'winflexbison.zip')
$hash = (Get-FileHash "winflexbison.zip" -Algorithm SHA256).Hash
if ($hash -ne '39c6086ce211d5415500acc5ed2d8939861ca1696aee48909c7f6daf5122b505') {
Write-Host "bison SHA256 mismatch! ($hash)"
}
Expand-Archive -DestinationPath . "zlib.zip"
Expand-Archive -DestinationPath . "libpng.zip"
Expand-Archive -DestinationPath install_dir "winflexbison.zip"
Move-Item zlib-1.2.12 zlib
Move-Item lpng1637 libpng
- name: Build 32-bit zlib
run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll`
cmake -S zlib -B zbuild32 -A Win32 -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
cmake --build zbuild32 --config Release
cmake --install zbuild32
- name: Build 32-bit libpng
VERSION="${{ github.ref_name }}"
echo "version=${VERSION#v}" >> $GITHUB_ENV
- uses: actions/checkout@v3
- name: Install deps
shell: bash
run: |
cmake -S libpng -B pngbuild32 -A Win32 -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=ON -DPNG_TESTS=OFF
cmake --build pngbuild32 --config Release
cmake --install pngbuild32
- name: Build 32-bit Windows binaries
./.github/scripts/install_deps.sh macos-latest
# We force linking libpng statically; the other libs are provided by macOS itself
- name: Build binaries
run: |
cmake -S . -B build32 -A Win32 -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release
cmake --build build32 --config Release
cmake --install build32
- name: Package 32-bit binaries
export PATH="/usr/local/opt/bison/bin:$PATH"
make -j WARNFLAGS="-Wall -Wextra -mmacosx-version-min=10.9" PKG_CONFIG="pkg-config --static" PNGLDLIBS="$(pkg-config --static --libs-only-L libpng | cut -c 3-)/libpng.a $(pkg-config --static --libs-only-l libpng | sed s/-lpng[0-9]*//g)" Q=
- name: Package binaries
run: |
Compress-Archive -LiteralPath @("install_dir/bin/rgbasm.exe", "install_dir/bin/rgblink.exe", "install_dir/bin/rgbfix.exe", "install_dir/bin/rgbgfx.exe", "install_dir/bin/zlib1.dll", "install_dir/bin/libpng16.dll") "rgbds-${{ env.version }}-win32.zip"
- name: Build 64-bit zlib
run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll`
cmake -S zlib -B zbuild64 -A x64 -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
cmake --build zbuild64 --config Release
cmake --install zbuild64
- name: Build 64-bit libpng
run: |
cmake -S libpng -B pngbuild64 -A x64 -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=ON -DPNG_TESTS=OFF
cmake --build pngbuild64 --config Release
cmake --install pngbuild64
- name: Build 64-bit Windows binaries
run: |
cmake -S . -B build64 -A x64 -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release
cmake --build build64 --config Release
cmake --install build64
- name: Package 64-bit binaries
run: |
Compress-Archive -LiteralPath @("install_dir/bin/rgbasm.exe", "install_dir/bin/rgblink.exe", "install_dir/bin/rgbfix.exe", "install_dir/bin/rgbgfx.exe", "install_dir/bin/zlib1.dll", "install_dir/bin/libpng16.dll") "rgbds-${{ env.version }}-win64.zip"
zip --junk-paths rgbds-${{ env.version }}-macos-x86-64.zip rgb{asm,link,fix,gfx} man/* .github/scripts/install.sh
- name: Upload macOS binaries
uses: actions/upload-artifact@v3
with:
name: macos
path: rgbds-${{ env.version }}-macos-x86-64.zip
release:
runs-on: ubuntu-latest
needs: [windows, macos]
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
- uses: actions/checkout@v3
- name: Package sources
run: |
make dist
make dist Q=
ls
- uses: actions/download-artifact@v3
- name: Release
uses: softprops/action-gh-release@v1
with:
@@ -88,8 +118,9 @@ jobs:
draft: true # Don't publish the release quite yet...
prerelease: ${{ contains(github.ref, '-rc') }}
files: |
rgbds-${{ env.version }}-win32.zip
rgbds-${{ env.version }}-win64.zip
win32/rgbds-${{ env.version }}-win32.zip
win64/rgbds-${{ env.version }}-win64.zip
macos/rgbds-${{ env.version }}-macos-x86-64.zip
rgbds-${{ env.version }}.tar.gz
fail_on_unmatched_files: true
env:

View File

@@ -10,11 +10,11 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout rgbds@release
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
path: rgbds
- name: Checkout rgbds-www@master
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
repository: ${{ github.repository_owner }}/rgbds-www
path: rgbds-www
@@ -25,7 +25,7 @@ jobs:
- name: Update pages
working-directory: rgbds/man
run: | # The ref appears to be in the format "refs/tags/<version>", so strip that
../../rgbds-www/.github/actions/get-pages.sh ${GITHUB_REF##*/} *
../../rgbds-www/maintainer/man_to_html.sh ${GITHUB_REF##*/} *
- name: Push new pages
working-directory: rgbds-www
run: |

View File

@@ -24,11 +24,11 @@ jobs:
fail-fast: false
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Install deps
shell: bash
run: |
./.github/actions/install_deps.sh ${{ matrix.os }}
./.github/scripts/install_deps.sh ${{ matrix.os }}
# The `export` lines are to allow working on macOS...
# Apple's base version is severely outdated, not even supporting -Wall,
# but it overrides Homebrew's version nonetheless...
@@ -55,6 +55,25 @@ jobs:
with:
name: rgbds-canary-${{ matrix.os }}-${{ matrix.cc }}-${{ matrix.buildsys }}
path: bins
- name: Compute test dependency cache params
id: test-deps-cache-params
shell: bash
run: |
paths=$(test/fetch-test-deps.sh --get-paths)
hash=$(test/fetch-test-deps.sh --get-hash)
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@v3
with:
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
key: ${{ matrix.os }}-${{ steps.test-deps-cache-params.outputs.hash }}
- if: steps.test-deps-cache.outputs.cache-hit != 'true'
name: Fetch test dependency repositories
continue-on-error: true
run: |
test/fetch-test-deps.sh
- name: Test
shell: bash
run: |
@@ -75,32 +94,9 @@ jobs:
fail-fast: false
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: Get zlib, libpng and bison
run: | # TODO: use an array; remember to update the versions being downloaded, *and* the paths being extracted! (`Move-Item`)
$wc = New-Object System.Net.WebClient
$wc.DownloadFile('https://www.zlib.net/zlib1212.zip', 'zlib.zip')
$hash = (Get-FileHash "zlib.zip" -Algorithm SHA256).Hash
if ($hash -ne '173e89893dcb8b4a150d7731cd72f0602f1d6b45e60e2a54efdf7f3fc3325fd7') {
Write-Host "zlib SHA256 mismatch! ($hash)"
exit 1
}
$wc.DownloadFile('https://download.sourceforge.net/libpng/lpng1637.zip', 'libpng.zip')
$hash = (Get-FileHash "libpng.zip" -Algorithm SHA256).Hash
if ($hash -ne '3b4b1cbd0bae6822f749d39b1ccadd6297f05e2b85a83dd2ce6ecd7d09eabdf2') {
Write-Host "libpng SHA256 mismatch! ($hash)"
exit 1
}
$wc.DownloadFile('https://github.com/lexxmark/winflexbison/releases/download/v2.5.24/win_flex_bison-2.5.24.zip', 'winflexbison.zip')
$hash = (Get-FileHash "winflexbison.zip" -Algorithm SHA256).Hash
if ($hash -ne '39c6086ce211d5415500acc5ed2d8939861ca1696aee48909c7f6daf5122b505') {
Write-Host "bison SHA256 mismatch! ($hash)"
}
Expand-Archive -DestinationPath . "zlib.zip"
Expand-Archive -DestinationPath . "libpng.zip"
Expand-Archive -DestinationPath install_dir "winflexbison.zip"
Move-Item zlib-1.2.12 zlib
Move-Item lpng1637 libpng
- uses: actions/checkout@v3
- name: Install deps
run: .github/scripts/get_win_deps.ps1
- uses: actions/cache@v3
id: cache
with:
@@ -110,23 +106,25 @@ jobs:
key: ${{ matrix.arch }}-${{ hashFiles('zlib/**', 'libpng/**') }}
- name: Build zlib
run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll`
cmake -S zlib -B zbuild -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
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
if: steps.cache.outputs.cache-hit != 'true'
- name: Install zlib
run: |
cmake --install zbuild
- name: Build libpng
shell: bash
run: |
cmake -S libpng -B pngbuild -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=ON -DPNG_TESTS=OFF
cmake -S libpng -B pngbuild -A ${{ matrix.platform }} -Wno-dev -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=OFF -DPNG_TESTS=OFF -DPNG_BUILD_ZLIB=ON -DZLIB_INCLUDE_DIR="$PWD"/install_dir/include -DZLIB_LIBRARY="$PWD"/install_dir/lib/zlib.lib
cmake --build pngbuild --config Release -j
if: steps.cache.outputs.cache-hit != 'true'
- 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 -S . -B build -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release -DZLIB_LIBRARY="$PWD"/install_dir/lib/zlib.lib -DZLIB_INCLUDE_DIR="$PWD"/install_dir/include -DPNG_LIBRARY="$PWD"/install_dir/lib/libpng16.lib -DPNG_INCLUDE_DIR="$PWD"/install_dir/include
cmake --build build --config Release -j --verbose
cmake --install build --verbose --prefix install_dir
- name: Package binaries
@@ -139,6 +137,26 @@ jobs:
with:
name: rgbds-canary-win${{ matrix.bits }}
path: bins
- name: Compute test dependency cache params
id: test-deps-cache-params
shell: bash
run: |
paths=$(test/fetch-test-deps.sh --get-paths)
hash=$(test/fetch-test-deps.sh --get-hash)
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@v3
with:
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
key: ${{ matrix.os }}-${{ matrix.bits }}-${{ steps.test-deps-cache-params.outputs.hash }}
- if: steps.test-deps-cache.outputs.cache-hit != 'true'
name: Fetch test dependency repositories
shell: bash
continue-on-error: true
run: |
test/fetch-test-deps.sh
- name: Test
shell: bash
run: |
@@ -162,17 +180,17 @@ jobs:
env:
DIST_DIR: win${{ matrix.bits }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Install deps
shell: bash
run: |
./.github/actions/install_deps.sh ${{ matrix.os }}
./.github/scripts/install_deps.sh ${{ matrix.os }}
- name: Install MinGW
run: | # dpkg-dev is apparently required for pkg-config for cross-building
sudo apt-get install {gcc,g++}-mingw-w64-${{ matrix.arch }}-win32 mingw-w64-tools libz-mingw-w64-dev dpkg-dev
- name: Install libpng dev headers for MinGW
run: |
sudo ./.github/actions/mingw-w64-libpng-dev.sh ${{ matrix.triplet }}
sudo ./.github/scripts/mingw-w64-libpng-dev.sh ${{ matrix.triplet }}
- name: Cross-build Windows binaries
run: |
make mingw${{ matrix.bits }} -j Q=
@@ -205,7 +223,7 @@ jobs:
fail-fast: false
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Retrieve binaries
uses: actions/download-artifact@v3
with:
@@ -221,6 +239,26 @@ jobs:
run: |
cp bins/* .
cp bins/*.dll test/gfx
- name: Compute test dependency cache params
id: test-deps-cache-params
shell: bash
run: |
paths=$(test/fetch-test-deps.sh --get-paths)
hash=$(test/fetch-test-deps.sh --get-hash)
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@v3
with:
path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
key: mingw-${{ matrix.bits }}-${{ steps.test-deps-cache-params.outputs.hash }}
- if: steps.test-deps-cache.outputs.cache-hit != 'true'
name: Fetch test dependency repositories
shell: bash
continue-on-error: true
run: |
test/fetch-test-deps.sh
- name: Run tests
shell: bash
run: |

View File

@@ -20,13 +20,13 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout rgbds@master
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
repository: gbdev/rgbds
ref: master
path: rgbds
- name: Checkout rgbds-www@master
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
repository: gbdev/rgbds-www
ref: master

View File

@@ -52,6 +52,7 @@ else()
-fsanitize=alignment -fsanitize=null -fsanitize=address)
add_compile_options(${SAN_FLAGS})
add_link_options(${SAN_FLAGS})
add_definitions(-D_GLIBCXX_ASSERTIONS)
# A non-zero optimization level is desired in debug mode, but allow overriding it nonetheless
# TODO: this overrides anything previously set... that's a bit sloppy!
set(CMAKE_C_FLAGS_DEBUG "-g -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls" CACHE STRING "" FORCE)

View File

@@ -35,8 +35,8 @@ VERSION_STRING := `git describe --tags --dirty --always 2>/dev/null`
WARNFLAGS := -Wall -pedantic
# Overridable CFLAGS
CFLAGS ?= -O3 -flto=auto -DNDEBUG
CXXFLAGS ?= -O3 -flto=auto -DNDEBUG
CFLAGS ?= -O3 -flto -DNDEBUG
CXXFLAGS ?= -O3 -flto -DNDEBUG
# Non-overridable CFLAGS
# _ISOC11_SOURCE is required on certain platforms to get C11 on top of the C99-based POSIX 2008
REALCFLAGS := ${CFLAGS} ${WARNFLAGS} -std=gnu11 -I include \
@@ -130,7 +130,7 @@ rgbfix: ${rgbfix_obj}
$Q${CC} ${REALLDFLAGS} -o $@ ${rgbfix_obj} ${REALCFLAGS} src/version.c
rgbgfx: ${rgbgfx_obj}
$Q${CXX} ${REALLDFLAGS} ${PNGLDFLAGS} -o $@ ${rgbgfx_obj} ${REALCXXFLAGS} -x c++ src/version.c ${PNGLDLIBS}
$Q${CXX} ${REALLDFLAGS} ${PNGLDFLAGS} -o $@ ${rgbgfx_obj} ${REALCXXFLAGS} ${PNGLDLIBS} -x c++ src/version.c
test/gfx/randtilegen: test/gfx/randtilegen.c
$Q${CC} ${REALLDFLAGS} ${PNGLDFLAGS} -o $@ $^ ${REALCFLAGS} ${PNGCFLAGS} ${PNGLDLIBS}
@@ -183,21 +183,11 @@ clean:
# Target used to install the binaries and man pages.
install: all
$Qmkdir -p ${DESTDIR}${bindir}
$Qinstall ${STRIP} -m ${BINMODE} rgbasm ${DESTDIR}${bindir}/rgbasm
$Qinstall ${STRIP} -m ${BINMODE} rgbfix ${DESTDIR}${bindir}/rgbfix
$Qinstall ${STRIP} -m ${BINMODE} rgblink ${DESTDIR}${bindir}/rgblink
$Qinstall ${STRIP} -m ${BINMODE} rgbgfx ${DESTDIR}${bindir}/rgbgfx
$Qmkdir -p ${DESTDIR}${mandir}/man1 ${DESTDIR}${mandir}/man5 ${DESTDIR}${mandir}/man7
$Qinstall -m ${MANMODE} man/rgbds.7 ${DESTDIR}${mandir}/man7/rgbds.7
$Qinstall -m ${MANMODE} man/gbz80.7 ${DESTDIR}${mandir}/man7/gbz80.7
$Qinstall -m ${MANMODE} man/rgbds.5 ${DESTDIR}${mandir}/man5/rgbds.5
$Qinstall -m ${MANMODE} man/rgbasm.1 ${DESTDIR}${mandir}/man1/rgbasm.1
$Qinstall -m ${MANMODE} man/rgbasm.5 ${DESTDIR}${mandir}/man5/rgbasm.5
$Qinstall -m ${MANMODE} man/rgbfix.1 ${DESTDIR}${mandir}/man1/rgbfix.1
$Qinstall -m ${MANMODE} man/rgblink.1 ${DESTDIR}${mandir}/man1/rgblink.1
$Qinstall -m ${MANMODE} man/rgblink.5 ${DESTDIR}${mandir}/man5/rgblink.5
$Qinstall -m ${MANMODE} man/rgbgfx.1 ${DESTDIR}${mandir}/man1/rgbgfx.1
$Qinstall -d ${DESTDIR}${bindir}/ ${DESTDIR}${mandir}/man1/ ${DESTDIR}${mandir}/man5/ ${DESTDIR}${mandir}/man7/
$Qinstall ${STRIP} -m ${BINMODE} rgbasm rgblink rgbfix rgbgfx ${DESTDIR}${bindir}/
$Qinstall -m ${MANMODE} man/rgbasm.1 man/rgblink.1 man/rgbfix.1 man/rgbgfx.1 ${DESTDIR}${mandir}/man1/
$Qinstall -m ${MANMODE} man/rgbds.5 man/rgbasm.5 man/rgblink.5 ${DESTDIR}${mandir}/man5/
$Qinstall -m ${MANMODE} man/rgbds.7 man/gbz80.7 ${DESTDIR}${mandir}/man7/
# Target used to check the coding style of the whole codebase.
# `extern/` is excluded, as it contains external code that should not be patched
@@ -244,6 +234,7 @@ develop:
-Wno-type-limits -Wno-tautological-constant-out-of-range-compare \
-Wvla \
-Wno-unknown-warning-option \
-D_GLIBCXX_ASSERTIONS \
-fsanitize=shift -fsanitize=integer-divide-by-zero \
-fsanitize=unreachable -fsanitize=vla-bound \
-fsanitize=signed-integer-overflow -fsanitize=bounds \

103
include/file.hpp Normal file
View File

@@ -0,0 +1,103 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2022, Eldred Habert and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_FILE_HPP
#define RGBDS_FILE_HPP
#include <array>
#include <assert.h>
#include <cassert>
#include <fcntl.h>
#include <fstream>
#include <ios>
#include <iostream>
#include <streambuf>
#include <string>
#include <string.h>
#include <string_view>
#include <variant>
#include "helpers.h"
#include "platform.h"
#include "gfx/main.hpp"
// Convenience feature for visiting the below.
template<typename... Ts>
struct Visitor : Ts... {
using Ts::operator()...;
};
template<typename... Ts>
Visitor(Ts...) -> Visitor<Ts...>;
class File {
// Construct a `std::streambuf *` by default, since it's probably lighter than a `filebuf`.
std::variant<std::streambuf *, std::filebuf> _file;
public:
File() {}
~File() { close(); }
/**
* This should only be called once, and before doing any `->` operations.
* Returns `nullptr` on error, and a non-null pointer otherwise.
*/
File *open(std::string const &path, std::ios_base::openmode mode) {
if (path != "-") {
return _file.emplace<std::filebuf>().open(path, mode) ? this : nullptr;
} else if (mode & std::ios_base::in) {
assert(!(mode & std::ios_base::out));
_file.emplace<std::streambuf *>(std::cin.rdbuf());
if (setmode(STDIN_FILENO, mode & std::ios_base::binary ? O_BINARY : O_TEXT) == -1) {
fatal("Failed to set stdin to %s mode: %s",
mode & std::ios_base::binary ? "binary" : "text", strerror(errno));
}
} else {
assert(mode & std::ios_base::out);
_file.emplace<std::streambuf *>(std::cout.rdbuf());
}
return this;
}
std::streambuf &operator*() {
return std::visit(Visitor{[](std::filebuf &file) -> std::streambuf & { return file; },
[](std::streambuf *buf) -> std::streambuf & { return *buf; }},
_file);
}
std::streambuf const &operator*() const {
// The non-`const` version does not perform any modifications, so it's okay.
return **const_cast<File *>(this);
}
std::streambuf *operator->() { return &**this; }
std::streambuf const *operator->() const {
// See the `operator*` equivalent.
return const_cast<File *>(this)->operator->();
}
File *close() {
return std::visit(Visitor{[this](std::filebuf &file) {
// This is called by the destructor, and an explicit `close`
// shouldn't close twice.
_file.emplace<std::streambuf *>(nullptr);
return file.close() != nullptr;
},
[](std::streambuf *buf) { return buf != nullptr; }},
_file)
? this
: nullptr;
}
char const *c_str(std::string const &path) const {
return std::visit(Visitor{[&path](std::filebuf const &) { return path.c_str(); },
[](std::streambuf const *buf) {
return buf == std::cin.rdbuf() ? "<stdin>" : "<stdout>";
}},
_file);
}
};
#endif // RGBDS_FILE_HPP

View File

@@ -63,8 +63,10 @@
# define O_RDWR _O_RDWR
# define S_ISREG(field) ((field) & _S_IFREG)
# define O_BINARY _O_BINARY
# define O_TEXT _O_TEXT
#elif !defined(O_BINARY) // Cross-compilers define O_BINARY
# define O_BINARY 0 // POSIX says we shouldn't care!
# define O_TEXT 0 // Assume that it's not defined either
#endif // _MSC_VER
// Windows has stdin and stdout open as text by default, which we may not want
@@ -72,7 +74,7 @@
# include <io.h>
# define setmode(fd, mode) _setmode(fd, mode)
#else
# define setmode(fd, mode) ((void)0)
# define setmode(fd, mode) (0)
#endif
#endif // RGBDS_PLATFORM_H

View File

@@ -15,7 +15,7 @@ extern "C" {
#define PACKAGE_VERSION_MAJOR 0
#define PACKAGE_VERSION_MINOR 6
#define PACKAGE_VERSION_PATCH 0
#define PACKAGE_VERSION_PATCH 1
char const *get_package_version_string(void);

View File

@@ -72,6 +72,18 @@ All of these are equivalent:
.Ql 0X2A ,
.Ql 0x2a .
.Pp
Unless otherwise noted, passing
.Ql -
(a single dash) as a file name makes
.Nm
use standard input (for input files) or standard output (for output files).
To suppress this behavior, and open a file in the current directory actually called
.Ql - ,
pass
.Ql ./-
instead.
Using standard input or output more than once in a single command will likely produce unexpected results.
.Pp
The following options are accepted:
.Bl -tag -width Ds
.It Fl a Ar attrmap , Fl Fl attr-map Ar attrmap
@@ -145,7 +157,9 @@ The expected format is
.Ql format:path ,
where
.Ar path
is a path to a file, which will be processed according to the
is a path to a file
.Ql ( -
is not treated specially), which will be processed according to the
.Ar format .
See
.Sx PALETTE SPECIFICATION FORMATS

View File

@@ -14,21 +14,20 @@ set(common_src
"_version.c"
)
find_package(BISON REQUIRED)
find_package(BISON 3.0.0 REQUIRED)
set(BISON_FLAGS "-Wall")
# Set sompe optimization flags on versions that support them
# Set some optimization flags on versions that support them
if(BISON_VERSION VERSION_GREATER_EQUAL "3.5")
set(BISON_FLAGS "${BISON_FLAGS} -Dapi.token.raw=true")
endif()
if(BISON_VERSION VERSION_GREATER_EQUAL "3.6")
set(BISON_FLAGS "${BISON_FLAGS} -Dparse.error=detailed")
elseif(BISON_VERSION VERSION_GREATER_EQUAL "3.0")
else()
set(BISON_FLAGS "${BISON_FLAGS} -Dparse.error=verbose")
endif()
if(BISON_VERSION VERSION_GREATER_EQUAL "3.0")
set(BISON_FLAGS "${BISON_FLAGS} -Dparse.lac=full")
set(BISON_FLAGS "${BISON_FLAGS} -Dlr.type=ielr")
endif()
BISON_TARGET(PARSER "asm/parser.y"
"${PROJECT_SOURCE_DIR}/src/asm/parser.c"
COMPILE_FLAGS "${BISON_FLAGS}"

View File

@@ -359,10 +359,10 @@ int main(int argc, char *argv[])
targetFileName[targetFileNameLen - 1] = '\0'; // Overwrite the last space
if (argc == musl_optind) {
fputs("FATAL: No input files\n", stderr);
fputs("FATAL: Please specify an input file (pass `-` to read from standard input)\n", stderr);
print_usage();
} else if (argc != musl_optind + 1) {
fputs("FATAL: More than one input file given\n", stderr);
fputs("FATAL: More than one input file specified\n", stderr);
print_usage();
}

View File

@@ -690,17 +690,19 @@ asmfile : lines
;
lines : %empty
| lines line
| lines opt_diff_mark line
;
endofline : T_NEWLINE | T_EOB
;
plain_directive : label
| label cpu_command
| label macro
| label directive
| assignment_directive
opt_diff_mark : %empty // OK
| T_OP_ADD {
error("syntax error, unexpected + at the beginning of the line (is it a leftover diff mark?)\n");
}
| T_OP_SUB {
error("syntax error, unexpected - at the beginning of the line (is it a leftover diff mark?)\n");
}
;
line : plain_directive endofline
@@ -786,6 +788,13 @@ else : T_POP_ELSE T_NEWLINE {
}
;
plain_directive : label
| label cpu_command
| label macro
| label directive
| assignment_directive
;
endc : T_POP_ENDC {
lexer_DecIFDepth();
}

View File

@@ -1174,8 +1174,8 @@ static bool processFilename(char const *name)
{
nbErrors = 0;
if (!strcmp(name, "-")) {
setmode(STDIN_FILENO, O_BINARY);
setmode(STDOUT_FILENO, O_BINARY);
(void)setmode(STDIN_FILENO, O_BINARY);
(void)setmode(STDOUT_FILENO, O_BINARY);
name = "<stdin>";
processFile(STDIN_FILENO, STDOUT_FILENO, name, 0);

View File

@@ -23,8 +23,10 @@
#include <stdlib.h>
#include <string.h>
#include <string_view>
#include <type_traits>
#include "extern/getopt.h"
#include "file.hpp"
#include "platform.h"
#include "version.h"
@@ -253,10 +255,13 @@ static void registerInput(char const *arg) {
* @param argPool Argument characters will be appended to this vector, for storage purposes.
*/
static std::vector<size_t> readAtFile(std::string const &path, std::vector<char> &argPool) {
std::filebuf file;
file.open(path, std::ios_base::in);
File file;
if (!file.open(path, std::ios_base::in)) {
fatal("Error reading @%s: %s", file.c_str(path), strerror(errno));
}
static_assert(decltype(file)::traits_type::eof() == EOF,
// We only filter out `EOF`, but calling `isblank()` on anything else is UB!
static_assert(std::remove_reference_t<decltype(*file)>::traits_type::eof() == EOF,
"isblank(char_traits<...>::eof()) is UB!");
std::vector<size_t> argvOfs;
@@ -265,7 +270,7 @@ static std::vector<size_t> readAtFile(std::string const &path, std::vector<char>
// First, discard any leading whitespace
do {
c = file.sbumpc();
c = file->sbumpc();
if (c == EOF) {
return argvOfs;
}
@@ -273,7 +278,7 @@ static std::vector<size_t> readAtFile(std::string const &path, std::vector<char>
switch (c) {
case '#': // If it's a comment, discard everything until EOL
while ((c = file.sbumpc()) != '\n') {
while ((c = file->sbumpc()) != '\n') {
if (c == EOF) {
return argvOfs;
}
@@ -281,7 +286,7 @@ static std::vector<size_t> readAtFile(std::string const &path, std::vector<char>
continue; // Start processing the next line
// If it's an empty line, ignore it
case '\r': // Assuming CRLF here
file.sbumpc(); // Discard the upcoming '\n'
file->sbumpc(); // Discard the upcoming '\n'
[[fallthrough]];
case '\n':
continue; // Start processing the next line
@@ -296,11 +301,11 @@ static std::vector<size_t> readAtFile(std::string const &path, std::vector<char>
// on `vector` and `sbumpc` to do the right thing here.
argPool.push_back(c); // Push the character we've already read
for (;;) {
c = file.sbumpc();
if (isblank(c) || c == '\n' || c == EOF) {
c = file->sbumpc();
if (c == EOF || c == '\n' || isblank(c)) {
break;
} else if (c == '\r') {
file.sbumpc(); // Discard the '\n'
file->sbumpc(); // Discard the '\n'
break;
}
argPool.push_back(c);
@@ -309,10 +314,10 @@ static std::vector<size_t> readAtFile(std::string const &path, std::vector<char>
// Discard whitespace until the next argument (candidate)
while (isblank(c)) {
c = file.sbumpc();
c = file->sbumpc();
}
if (c == '\r') {
c = file.sbumpc(); // Skip the '\n'
c = file->sbumpc(); // Skip the '\n'
}
} while (c != '\n' && c != EOF); // End if we reached EOL
}

View File

@@ -27,6 +27,7 @@
#include <vector>
#include "defaultinitalloc.hpp"
#include "file.hpp"
#include "helpers.h"
#include "itertools.hpp"
@@ -77,7 +78,7 @@ public:
class Png {
std::string const &path;
std::filebuf file{};
File file{};
png_structp png = nullptr;
png_infop info = nullptr;
@@ -93,25 +94,26 @@ class Png {
[[noreturn]] static void handleError(png_structp png, char const *msg) {
Png *self = reinterpret_cast<Png *>(png_get_error_ptr(png));
fatal("Error reading input image (\"%s\"): %s", self->path.c_str(), msg);
fatal("Error reading input image (\"%s\"): %s", self->file.c_str(self->path), msg);
}
static void handleWarning(png_structp png, char const *msg) {
Png *self = reinterpret_cast<Png *>(png_get_error_ptr(png));
warning("In input image (\"%s\"): %s", self->path.c_str(), msg);
warning("In input image (\"%s\"): %s", self->file.c_str(self->path), msg);
}
static void readData(png_structp png, png_bytep data, size_t length) {
Png *self = reinterpret_cast<Png *>(png_get_io_ptr(png));
std::streamsize expectedLen = length;
std::streamsize nbBytesRead = self->file.sgetn(reinterpret_cast<char *>(data), expectedLen);
std::streamsize nbBytesRead =
self->file->sgetn(reinterpret_cast<char *>(data), expectedLen);
if (nbBytesRead != expectedLen) {
fatal("Error reading input image (\"%s\"): file too short (expected at least %zd more "
"bytes after reading %lld)",
self->path.c_str(), length - nbBytesRead,
self->file.pubseekoff(0, std::ios_base::cur));
self->file.c_str(self->path), length - nbBytesRead,
self->file->pubseekoff(0, std::ios_base::cur));
}
}
@@ -142,7 +144,7 @@ public:
}
uint8_t bins = 0;
for (auto const &color : colors) {
if (color->isTransparent()) {
if (!color.has_value() || color->isTransparent()) {
continue;
}
if (!color->isGray()) {
@@ -175,17 +177,17 @@ public:
*/
explicit Png(std::string const &filePath) : path(filePath), colors() {
if (file.open(path, std::ios_base::in | std::ios_base::binary) == nullptr) {
fatal("Failed to open input image (\"%s\"): %s", path.c_str(), strerror(errno));
fatal("Failed to open input image (\"%s\"): %s", file.c_str(path), strerror(errno));
}
options.verbosePrint(Options::VERB_LOG_ACT, "Opened input file\n");
std::array<unsigned char, 8> pngHeader;
if (file.sgetn(reinterpret_cast<char *>(pngHeader.data()), pngHeader.size())
if (file->sgetn(reinterpret_cast<char *>(pngHeader.data()), pngHeader.size())
!= static_cast<std::streamsize>(pngHeader.size()) // Not enough bytes?
|| png_sig_cmp(pngHeader.data(), 0, pngHeader.size()) != 0) {
fatal("Input file (\"%s\") is not a PNG image!", path.c_str());
fatal("Input file (\"%s\") is not a PNG image!", file.c_str(path));
}
options.verbosePrint(Options::VERB_INTERM, "PNG header signature is OK\n");
@@ -624,14 +626,16 @@ static std::tuple<DefaultInitVec<size_t>, std::vector<Palette>>
}
static void outputPalettes(std::vector<Palette> const &palettes) {
std::filebuf output;
output.open(options.palettes, std::ios_base::out | std::ios_base::binary);
File output;
if (!output.open(options.palettes, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to open \"%s\": %s", output.c_str(options.palettes), strerror(errno));
}
for (Palette const &palette : palettes) {
for (uint8_t i = 0; i < options.nbColorsPerPal; ++i) {
uint16_t color = palette.colors[i]; // Will return `UINT16_MAX` for unused slots
output.sputc(color & 0xFF);
output.sputc(color >> 8);
output->sputc(color & 0xFF);
output->sputc(color >> 8);
}
}
}
@@ -750,8 +754,10 @@ namespace unoptimized {
static void outputTileData(Png const &png, DefaultInitVec<AttrmapEntry> const &attrmap,
std::vector<Palette> const &palettes,
DefaultInitVec<size_t> const &mappings) {
std::filebuf output;
output.open(options.output, std::ios_base::out | std::ios_base::binary);
File output;
if (!output.open(options.output, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to open \"%s\": %s", output.c_str(options.output), strerror(errno));
}
uint64_t remainingTiles = (png.getWidth() / 8) * (png.getHeight() / 8);
if (remainingTiles <= options.trim) {
@@ -764,9 +770,9 @@ static void outputTileData(Png const &png, DefaultInitVec<AttrmapEntry> const &a
Palette const &palette = palettes[attr.getPalID(mappings)];
for (uint32_t y = 0; y < 8; ++y) {
uint16_t bitplanes = TileData::rowBitplanes(tile, palette, y);
output.sputc(bitplanes & 0xFF);
output->sputc(bitplanes & 0xFF);
if (options.bitDepth == 2) {
output.sputc(bitplanes >> 8);
output->sputc(bitplanes >> 8);
}
}
@@ -780,18 +786,27 @@ static void outputTileData(Png const &png, DefaultInitVec<AttrmapEntry> const &a
static void outputMaps(DefaultInitVec<AttrmapEntry> const &attrmap,
DefaultInitVec<size_t> const &mappings) {
std::optional<std::filebuf> tilemapOutput, attrmapOutput, palmapOutput;
std::optional<File> tilemapOutput, attrmapOutput, palmapOutput;
if (!options.tilemap.empty()) {
tilemapOutput.emplace();
tilemapOutput->open(options.tilemap, std::ios_base::out | std::ios_base::binary);
if (!tilemapOutput->open(options.tilemap, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to open \"%s\": %s", tilemapOutput->c_str(options.tilemap),
strerror(errno));
}
}
if (!options.attrmap.empty()) {
attrmapOutput.emplace();
attrmapOutput->open(options.attrmap, std::ios_base::out | std::ios_base::binary);
if (!attrmapOutput->open(options.attrmap, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to open \"%s\": %s", attrmapOutput->c_str(options.attrmap),
strerror(errno));
}
}
if (!options.palmap.empty()) {
palmapOutput.emplace();
palmapOutput->open(options.palmap, std::ios_base::out | std::ios_base::binary);
if (!palmapOutput->open(options.palmap, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to open \"%s\": %s", palmapOutput->c_str(options.palmap),
strerror(errno));
}
}
uint8_t tileID = 0;
@@ -804,14 +819,14 @@ static void outputMaps(DefaultInitVec<AttrmapEntry> const &attrmap,
}
if (tilemapOutput.has_value()) {
tilemapOutput->sputc(tileID + options.baseTileIDs[bank]);
(*tilemapOutput)->sputc(tileID + options.baseTileIDs[bank]);
}
if (attrmapOutput.has_value()) {
uint8_t palID = attr.getPalID(mappings) & 7;
attrmapOutput->sputc(palID | bank << 3); // The other flags are all 0
(*attrmapOutput)->sputc(palID | bank << 3); // The other flags are all 0
}
if (palmapOutput.has_value()) {
palmapOutput->sputc(attr.getPalID(mappings));
(*palmapOutput)->sputc(attr.getPalID(mappings));
}
++tileID;
}
@@ -886,47 +901,55 @@ static UniqueTiles dedupTiles(Png const &png, DefaultInitVec<AttrmapEntry> &attr
}
static void outputTileData(UniqueTiles const &tiles) {
std::filebuf output;
output.open(options.output, std::ios_base::out | std::ios_base::binary);
File output;
if (!output.open(options.output, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to create \"%s\": %s", output.c_str(options.output), strerror(errno));
}
uint16_t tileID = 0;
for (auto iter = tiles.begin(), end = tiles.end() - options.trim; iter != end; ++iter) {
TileData const *tile = *iter;
assert(tile->tileID == tileID);
++tileID;
output.sputn(reinterpret_cast<char const *>(tile->data().data()), options.bitDepth * 8);
output->sputn(reinterpret_cast<char const *>(tile->data().data()), options.bitDepth * 8);
}
}
static void outputTilemap(DefaultInitVec<AttrmapEntry> const &attrmap) {
std::filebuf output;
output.open(options.tilemap, std::ios_base::out | std::ios_base::binary);
File output;
if (!output.open(options.tilemap, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to create \"%s\": %s", output.c_str(options.tilemap), strerror(errno));
}
for (AttrmapEntry const &entry : attrmap) {
output.sputc(entry.tileID); // The tile ID has already been converted
output->sputc(entry.tileID); // The tile ID has already been converted
}
}
static void outputAttrmap(DefaultInitVec<AttrmapEntry> const &attrmap,
DefaultInitVec<size_t> const &mappings) {
std::filebuf output;
output.open(options.attrmap, std::ios_base::out | std::ios_base::binary);
File output;
if (!output.open(options.attrmap, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to create \"%s\": %s", output.c_str(options.attrmap), strerror(errno));
}
for (AttrmapEntry const &entry : attrmap) {
uint8_t attr = entry.xFlip << 5 | entry.yFlip << 6;
attr |= entry.bank << 3;
attr |= entry.getPalID(mappings) & 7;
output.sputc(attr);
output->sputc(attr);
}
}
static void outputPalmap(DefaultInitVec<AttrmapEntry> const &attrmap,
DefaultInitVec<size_t> const &mappings) {
std::filebuf output;
output.open(options.attrmap, std::ios_base::out | std::ios_base::binary);
File output;
if (!output.open(options.attrmap, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to create \"%s\": %s", output.c_str(options.attrmap), strerror(errno));
}
for (AttrmapEntry const &entry : attrmap) {
output.sputc(entry.getPalID(mappings));
output->sputc(entry.getPalID(mappings));
}
}

View File

@@ -21,15 +21,16 @@
#include <vector>
#include "defaultinitalloc.hpp"
#include "file.hpp"
#include "helpers.h"
#include "itertools.hpp"
#include "gfx/main.hpp"
static DefaultInitVec<uint8_t> readInto(std::string path) {
std::filebuf file;
File file;
if (!file.open(path, std::ios::in | std::ios::binary)) {
fatal("Failed to open \"%s\": %s", path.c_str(), strerror(errno));
fatal("Failed to open \"%s\": %s", file.c_str(path), strerror(errno));
}
DefaultInitVec<uint8_t> data(128 * 16); // Begin with some room pre-allocated
@@ -40,7 +41,7 @@ static DefaultInitVec<uint8_t> readInto(std::string path) {
// Fill the new area ([oldSize; curSize[) with bytes
size_t nbRead =
file.sgetn(reinterpret_cast<char *>(&data.data()[oldSize]), curSize - oldSize);
file->sgetn(reinterpret_cast<char *>(&data.data()[oldSize]), curSize - oldSize);
if (nbRead != curSize - oldSize) {
// Shrink the vector to discard bytes that weren't read
data.resize(oldSize + nbRead);
@@ -68,13 +69,13 @@ static void pngWarning(png_structp png, char const *msg) {
}
void writePng(png_structp png, png_bytep data, size_t length) {
auto &pngFile = *static_cast<std::filebuf *>(png_get_io_ptr(png));
pngFile.sputn(reinterpret_cast<char *>(data), length);
auto &pngFile = *static_cast<File *>(png_get_io_ptr(png));
pngFile->sputn(reinterpret_cast<char *>(data), length);
}
void flushPng(png_structp png) {
auto &pngFile = *static_cast<std::filebuf *>(png_get_io_ptr(png));
pngFile.pubsync();
auto &pngFile = *static_cast<File *>(png_get_io_ptr(png));
pngFile->pubsync();
}
void reverse() {
@@ -146,14 +147,16 @@ void reverse() {
{Rgba(0xffffffff), Rgba(0xaaaaaaff), Rgba(0x555555ff), Rgba(0x000000ff)}
};
if (!options.palettes.empty()) {
std::filebuf file;
file.open(options.palettes, std::ios::in | std::ios::binary);
File file;
if (!file.open(options.palettes, std::ios::in | std::ios::binary)) {
fatal("Failed to open \"%s\": %s", file.c_str(options.palettes), strerror(errno));
}
palettes.clear();
std::array<uint8_t, sizeof(uint16_t) * 4> buf; // 4 colors
size_t nbRead;
do {
nbRead = file.sgetn(reinterpret_cast<char *>(buf.data()), buf.size());
nbRead = file->sgetn(reinterpret_cast<char *>(buf.data()), buf.size());
if (nbRead == buf.size()) {
// Expand the colors
auto &palette = palettes.emplace_back();
@@ -231,11 +234,13 @@ void reverse() {
}
options.verbosePrint(Options::VERB_LOG_ACT, "Writing image...\n");
std::filebuf pngFile;
pngFile.open(options.input, std::ios::out | std::ios::binary);
File pngFile;
if (!pngFile.open(options.input, std::ios::out | std::ios::binary)) {
fatal("Failed to create \"%s\": %s", pngFile.c_str(options.input), strerror(errno));
}
png_structp png = png_create_write_struct(
PNG_LIBPNG_VER_STRING,
const_cast<png_voidp>(static_cast<void const *>(options.input.c_str())), pngError,
const_cast<png_voidp>(static_cast<void const *>(pngFile.c_str(options.input))), pngError,
pngWarning);
if (!png) {
fatal("Couldn't create PNG write struct: %s", strerror(errno));

View File

@@ -398,6 +398,8 @@ static void readSection(FILE *file, struct Section *section, char const *fileNam
for (uint32_t i = 0; i < section->nbPatches; i++)
readPatch(file, &patches[i], fileName, section->name, i, fileNodes);
section->patches = patches;
} else {
section->data = NULL; // `mergeSections()` expects to be able to always read the ptr
}
}

View File

@@ -404,6 +404,16 @@ static void writeSymBank(struct SortedSections const *bankSections,
}
static void writeEmptySpace(uint16_t begin, uint16_t end)
{
if (begin < end) {
uint16_t len = end - begin;
fprintf(mapFile, "\tEMPTY: $%04x-$%04x ($%04" PRIx16 " byte%s)\n",
begin, end - 1, len, len == 1 ? "" : "s");
}
}
/*
* Write a bank's contents to the map file
* @param bankSections The bank's sections
@@ -432,12 +442,7 @@ static uint16_t writeMapBank(struct SortedSections const *sectList,
used += sect->size;
assert(sect->offset == 0);
if (prevEndAddr < sect->org) {
uint16_t empty = sect->org - prevEndAddr;
fprintf(mapFile, "\tEMPTY: $%04" PRIx16 " byte%s\n", empty,
empty == 1 ? "" : "s");
}
writeEmptySpace(prevEndAddr, sect->org);
prevEndAddr = sect->org + sect->size;
@@ -455,16 +460,22 @@ static uint16_t writeMapBank(struct SortedSections const *sectList,
uint16_t org = sect->org;
while (sect) {
if (sect->modifier == SECTION_UNION)
fprintf(mapFile, "\t\t; New union\n");
else if (sect->modifier == SECTION_FRAGMENT)
fprintf(mapFile, "\t\t; New fragment\n");
for (size_t i = 0; i < sect->nbSymbols; i++)
// "\tSECTION: $xxxx ..."
// Space matches "\tSECTION: $xxxx ..."
fprintf(mapFile, "\t $%04" PRIx32 " = %s\n",
sect->symbols[i]->offset + org,
sect->symbols[i]->name);
if (sect->nextu) {
// Announce the following "piece"
if (sect->nextu->modifier == SECTION_UNION)
fprintf(mapFile,
"\t ; Next union\n");
else if (sect->nextu->modifier == SECTION_FRAGMENT)
fprintf(mapFile,
"\t ; Next fragment\n");
}
sect = sect->nextu; // Also print symbols in the following "pieces"
}
}
@@ -474,19 +485,14 @@ static uint16_t writeMapBank(struct SortedSections const *sectList,
uint16_t bankEndAddr = sectionTypeInfo[type].startAddr + sectionTypeInfo[type].size;
if (prevEndAddr < bankEndAddr) {
uint16_t empty = bankEndAddr - prevEndAddr;
fprintf(mapFile, "\tEMPTY: $%04" PRIx16 " byte%s\n", empty,
empty == 1 ? "" : "s");
}
if (used == 0) {
fputs(" EMPTY\n\n", mapFile);
fputs("\tEMPTY\n\n", mapFile);
} else {
writeEmptySpace(prevEndAddr, bankEndAddr);
uint16_t slack = sectionTypeInfo[type].size - used;
fprintf(mapFile, "\tSLACK: $%04" PRIx16 " byte%s\n\n", slack,
fprintf(mapFile, "\tTOTAL EMPTY: $%04" PRIx16 " byte%s\n\n", slack,
slack == 1 ? "" : "s");
}

View File

@@ -272,14 +272,12 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file) {
getToken(line, "'A' line is too short");
assert(strlen(token) != 0); // This should be impossible, tokens are non-empty
curSection->name = strdup(token); // We need a pointer that will live longer
if (!curSection->name)
fatal(where, lineNo, "Failed to alloc new area's name: %s", strerror(errno));
// The following is required for fragment offsets to be reliably predicted
for (size_t i = 0; i < nbSections; ++i) {
if (!strcmp(token, fileSections[i].section->name))
fatal(where, lineNo, "Area \"%s\" already defined earlier", token);
}
char const *sectionName = token; // We'll deal with the section's name depending on type
expectToken("size", 'A');
@@ -299,6 +297,19 @@ void sdobj_ReadFile(struct FileStackNode const *where, FILE *file) {
curSection->isBankFixed = curSection->isAddressFixed;
curSection->modifier = curSection->isAddressFixed || (tmp & (1 << AREA_TYPE))
? SECTION_NORMAL : SECTION_FRAGMENT;
// If the section is absolute, its name might not be unique; thus, mangle the name
if (curSection->modifier == SECTION_NORMAL) {
size_t len = strlen(where->name) + 1 + strlen(token);
curSection->name = malloc(len + 1);
if (!curSection->name)
fatal(where, lineNo, "Failed to alloc new area's name: %s", strerror(errno));
sprintf(curSection->name, "%s %s", where->name, sectionName);
} else {
curSection->name = strdup(sectionName); // We need a pointer that will live longer
if (!curSection->name)
fatal(where, lineNo, "Failed to alloc new area's name: %s", strerror(errno));
}
expectToken("addr", 'A');

38
test/fetch-test-deps.sh Executable file
View File

@@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")"
case "$1" in
--get-hash)
action() { # owner/repo shallow-since commit
printf "%s@%s-" "${1##*/}" "$3"
}
;;
--get-paths)
action() { # owner/repo shallow-since commit
printf "test/%s," "${1##*/}"
}
;;
*)
echo "Fetching test dependency repositories"
action() { # owner/repo shallow-since commit
if [ ! -d ${1##*/} ]; then
git clone https://github.com/$1.git --shallow-since=$2 --single-branch
fi
pushd ${1##*/}
git checkout -f $3
if [ -f ../patches/${1##*/}.patch ]; then
git apply --ignore-whitespace ../patches/${1##*/}.patch
fi
popd
}
esac
action pret/pokecrystal 2022-09-29 70a3ec1accb6de1c1c273470af0ddfa2edc1b0a9
action pret/pokered 2022-09-29 2b52ceb718b55dce038db24d177715ae4281d065
action AntonioND/ucity 2022-04-20 d8878233da7a6569f09f87b144cb5bf140146a0f

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
[[ -e ./rgbgfx_test ]] || make -C ../.. test/gfx/rgbgfx_test
[[ -e ./randtilegen ]] || make -C ../.. test/gfx/randtilegen
[[ -e ./rgbgfx_test ]] || make -C ../.. test/gfx/rgbgfx_test || exit
[[ -e ./randtilegen ]] || make -C ../.. test/gfx/randtilegen || exit
trap 'rm -f "$errtmp"' EXIT
errtmp="$(mktemp)"
@@ -12,9 +12,11 @@ red="$(tput setaf 1)"
green="$(tput setaf 2)"
rescolors="$(tput op)"
RGBGFX=../../rgbgfx
rc=0
new_test() {
cmdline="${*@Q}"
cmdline="$*"
echo "$bold${green}Testing: $cmdline$rescolors$resbold" >&2
}
test() {
@@ -42,14 +44,22 @@ rm -f out*.png result.png
for f in *.png; do
flags="$([[ -e "${f%.png}.flags" ]] && echo "@${f%.png}.flags")"
new_test ../../rgbgfx $flags "$f"
new_test "$RGBGFX" $flags "$f"
if [[ -e "${f%.png}.err" ]]; then
test 2>"$errtmp"
diff -u --strip-trailing-cr "${f%.png}.err" "$errtmp" || fail
else
test || fail $?
fi
new_test "$RGBGFX" $flags - "<$f"
if [[ -e "${f%.png}.err" ]]; then
test 2>"$errtmp"
diff -u --strip-trailing-cr <(sed "s/$f/<stdin>/g" "${f%.png}.err") "$errtmp" || fail
else
test || fail $?
fi
done
exit $rc

View File

@@ -25,20 +25,16 @@ done
# When updating subprojects, change the commit being checked out, and set the `shallow-since`
# to the day before, to reduce the amount of refs being transferred and thus speed up CI.
test_downstream() { # owner/repo shallow-since commit make-target
if [ ! -d ${1##*/} ]; then
git clone https://github.com/$1.git --shallow-since=$2 --single-branch
fi
pushd ${1##*/}
git checkout -f $3
if [ -f ../patches/${1##*/}.patch ]; then
git apply --ignore-whitespace ../patches/${1##*/}.patch
test_downstream() { # owner/repo make-target
if ! pushd ${1##*/}; then
echo >&2 'Please run `fetch-test-deps.sh` before running the test suite'
return 1
fi
make clean
make -j4 $4 RGBDS=../../
make -j4 $2 RGBDS=../../
popd
}
test_downstream pret/pokecrystal 2022-09-29 70a3ec1accb6de1c1c273470af0ddfa2edc1b0a9 compare
test_downstream pret/pokered 2022-09-29 2b52ceb718b55dce038db24d177715ae4281d065 compare
test_downstream AntonioND/ucity 2022-04-20 d8878233da7a6569f09f87b144cb5bf140146a0f ''
test_downstream pret/pokecrystal compare
test_downstream pret/pokered compare
test_downstream AntonioND/ucity ''