Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: CI

# What this workflow asserts about djgpp-platform: on a Linux x86_64 machine, mcpp builds
# examples/hello for i586-dos-djgpp with DJGPP's GCC (the row's GCC target names the payload), the
# artefact is a go32 DOS executable, and `mcpp run` runs it under DOSBox Staging through dirun with
# its arguments, its output and its status (42).
#
# The row's GCC target is read by mcpp 2026.11.13.1 and later. A dispatch, or the repository
# variable MCPP_SOURCE_REF, names a branch of mcpp that the released mcpp builds and that is then
# used.

on:
push:
branches: [main]
pull_request:
workflow_dispatch:
inputs:
mcpp_ref:
description: "Branch of mcpp-community/mcpp to build and use (empty = the released mcpp)"
required: false
default: ""

env:
MCPP_SOURCE_REF: ${{ github.event.inputs.mcpp_ref || vars.MCPP_SOURCE_REF || '' }}
MCPP_VERSION: 2026.11.14.1
XLINGS_VERSION: v2026.10.26.1
XLINGS_NON_INTERACTIVE: '1'

jobs:
dos:
name: i586-dos-djgpp (built and run on Linux x86_64)
runs-on: ubuntu-24.04
timeout-minutes: 60
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v4

- name: Install xlings and mcpp
run: |
set -euo pipefail
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh \
| bash -s "$XLINGS_VERSION"
export PATH="$HOME/.xlings/subos/current/bin:$PATH"
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"
for attempt in 1 2 3 4 5 6; do
xlings update > /dev/null 2>&1 || true
if xlings install "mcpp@$MCPP_VERSION" -y -g; then break; fi
[ "$attempt" = 6 ] && { echo "::error::mcpp could not be installed"; exit 1; }
sleep 60
done
mcpp self config --mirror GLOBAL
if [ -n "$MCPP_SOURCE_REF" ]; then
src="$RUNNER_TEMP/mcpp-src"
git clone --quiet --depth 1 --branch "$MCPP_SOURCE_REF" https://github.com/mcpp-community/mcpp.git "$src"
rm -f "$src/.xlings.json"
( cd "$src" && mcpp build --release )
built=$(find "$src/target" -type f -name mcpp -path '*/bin/*' | head -1)
[ -n "$built" ] || { echo "::error::mcpp did not build from $MCPP_SOURCE_REF"; exit 1; }
echo "$(cd "$(dirname "$built")" && pwd)" >> "$GITHUB_PATH"
echo "under review: $("$built" --version) (from $MCPP_SOURCE_REF)"
fi

- name: A DOS program, built and run
working-directory: examples/hello
run: |
set -euo pipefail
mcpp --version
mcpp build --target i586-dos-djgpp
exe=$(find target/i586-dos-djgpp -path '*bin/hello.exe' -type f | head -1)
file "$exe"
file "$exe" | grep -q 'DJGPP go32' || { echo "::error::not a go32 DOS executable"; exit 1; }
set +e
mcpp run --target i586-dos-djgpp -- one two | tee run.log
status=${PIPESTATUS[0]}
set -e
grep -q "hello from dos: 3 arguments" run.log && grep -q "all held" run.log \
|| { echo "::error::the program's output"; exit 1; }
[ "$status" = 42 ] || { echo "::error::the status is $status, not 42"; exit 1; }
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target/
*.log
10 changes: 10 additions & 0 deletions examples/hello/mcpp.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "hello"
version = "0.1.0"

[targets.hello]
kind = "bin"
main = "src/main.c"

[target.i586-dos-djgpp]
platform = { path = "../.." }
20 changes: 20 additions & 0 deletions examples/hello/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* A DOS program built by mcpp: its arguments, a file written and read back, and its status. */
#include <stdio.h>
#include <string.h>

int main(int argc, char** argv) {
int failures = 0;
printf("hello from dos: %d arguments\n", argc);
if (argc < 2 || strcmp(argv[argc - 1], "two") != 0) { printf(" FAIL the arguments arrive\n"); ++failures; }
FILE* f = fopen("NOTE.TXT", "w");
if (!f) { printf(" FAIL a file is created\n"); return 1; }
fputs("kept", f);
fclose(f);
char back[8] = {0};
f = fopen("NOTE.TXT", "r");
if (!f || !fgets(back, sizeof back, f) || strcmp(back, "kept") != 0) { printf(" FAIL a file is read back\n"); ++failures; }
if (f) fclose(f);
remove("NOTE.TXT");
puts(failures ? "FAILED" : "all held");
return failures ? 1 : 42;
}
49 changes: 49 additions & 0 deletions mcpp.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# djgpp-platform: 32-bit DOS programs built by DJGPP, as a platform package (mcpp SPEC-013). The
# row is data here, not in the engine: a program is a go32 executable (an MZ stub before a COFF
# image) that runs under a DPMI host; its compiler is DJGPP's GCC, named by the row's GCC target
# (`gcc-triple`), and its C library and C++ run-time are DJGPP's own. The runner is DOSBox Staging
# through dirun's payload form: the program and the DPMI host in a directory DOSBox mounts as C:,
# its output and status read back from the files a launcher writes.
[package]
namespace = "mcpplibs"
name = "djgpp-platform"
version = "0.1.0"
description = "32-bit DOS programs built by DJGPP: the i586-dos-djgpp row, its GCC payload, and DOSBox Staging as its runner"
license = "Apache-2.0"
authors = ["mcpplibs"]
repo = "https://github.com/mcpplibs/djgpp-platform"
mcpp = ">=2026.11.13.1" # the row's GCC target (gcc-triple) and COFF objects

[platform]
targets = ["i586-dos-djgpp"]
toolchain = "gcc@12.2.0"

# The runner: dirun boots the program under DOSBox Staging with the package's profile, which
# places the program and CWSDPMI in the directory DOSBox mounts as C: and reads the program's
# output and status back from files (DOSBox's own status is not the program's). The program's
# arguments follow `--`.
[platform.runner]
cmd = ["dirun", "--payload", "{}", "--profile", "{pkg:dosbox-staging}/dirun.toml", "--"]
hosts = ["linux-x86_64", "macos-aarch64", "windows-x86_64"]
requires = ["xim:dirun@0.3.0", "xim:dosbox-staging@0.83.0"]

[[platform.define]]
triple = "i586-dos-djgpp"
gcc-triple = "i586-pc-msdosdjgpp"
object-format = "coff"
data-model = "ilp32"
exe-suffix = ".exe"
execution = "dos"
standard = false

[[platform.provider]]
serves = ["i586-dos-djgpp"]
pairs = ["gcc"]
linkage = "static"

# The C library and the C++ run-time are the toolchain's (DJGPP 2.05, libstdc++ 12).
[platform.layers]
"kernel-abi" = false
"c-abi" = false
"c++-abi" = false
"compiler-runtime" = false
Loading