Chciałem sobie popisać w C++ (Crossasembler). Znalazłem taki fajny extension do VS Code - Atari ST Dev. Wszystko fajnie z C - działa biblioteka libcmini, niestety wygląda na to, że do kompilatora C++ takowej nie ma, trzeba używać mintlib, mającej duży narzut i taki głupi "hello world" zajmuje 68 KB. Czy da się coś zaradzić? Ktoś, coś?

Mayonez/COBRA
Atari 1040 STE (4MB RAM, TOS 2.06/1.06, Ultrasatan, Netusbee)
Atari 65XE, 512KB ext. RAM, SIO2SD, FujiNet, IDE2+

2 Ostatnio edytowany przez Javalonde (2026-10-20 21:53:52)

Cześć, da się skompilować mały program C++ z libcmini, bez linkowania z mintlib.

Nie potrzeba osobnej biblioteki libcmini "dla kompilatora C++". Kod kompiluje

m68k-atari-mintelf-g++

, a libcmini dostarcza kod startowy i funkcje C. W linkowaniu trzeba wyłączyć domyślne biblioteki przez

-nostdlib

, podać

crt0.o

, a na końcu

-lcmini -lgcc

.

U mnie, przy GCC 15.2.0 i libcmini dla mintelf, poniższy program daje HELLO.PRG o rozmiarze 4565 bajtów. Sprawdziłem kompilację i format Atari PRG dla MC68000; nie sprawdzałem jeszcze działania na prawdziwym ST.

Układ katalogów

katalog-glowny/
  toolchain/
    mingw64/
      bin/
      lib/
      m68k-atari-mintelf/
  libcmini/
    usr/
      include/
      lib/
        crt0.o
        libcmini.a
  projects/
    hello-cpp/
      main.cpp
      build.ps1

Archiwa GCC i binutils dla Windows po rozpakowaniu tworzą katalog

mingw64

. Pakiet libcmini dla mintelf tworzy katalog

usr

. Kompilator na Windows potrzebuje też swoich DLL w katalogu

bin

lub w

PATH

.

projects/hello-cpp/main.cpp

#include <stdio.h>

class Greeting {
public:
    explicit Greeting(const char* message) : message_(message) {}

    void print() const {
        puts(message_);
    }

private:
    const char* message_;
};

int main() {
    const Greeting hello("Hello World from C++ on Atari ST!");
    hello.print();
    return 0;
}

projects/hello-cpp/build.ps1

$ErrorActionPreference = 'Stop'

$project = $PSScriptRoot
$root = [System.IO.Path]::GetFullPath((Join-Path $project '..\..'))
$bin = Join-Path $root 'toolchain\mingw64\bin'
$mini = Join-Path $root 'libcmini\usr'
$compiler = Join-Path $bin 'm68k-atari-mintelf-g++.exe'
$objdump = Join-Path $bin 'm68k-atari-mintelf-objdump.exe'
$output = Join-Path $project 'HELLO.PRG'

foreach ($file in @($compiler, $objdump, (Join-Path $mini 'lib\crt0.o'), (Join-Path $mini 'lib\libcmini.a'))) {
    if (-not (Test-Path -LiteralPath $file -PathType Leaf)) {
        throw "Brak wymaganego pliku: $file"
    }
}

$oldPath = $env:PATH
try {
    $env:PATH = "$bin;$oldPath"
    $arguments = @(
        '-m68000', '-std=c++17', '-Os',
        '-fno-exceptions', '-fno-rtti', '-fno-threadsafe-statics',
        '-fno-unwind-tables', '-fno-asynchronous-unwind-tables',
        '-ffunction-sections', '-fdata-sections',
        '-I', (Join-Path $mini 'include'),
        '-nostdlib', (Join-Path $mini 'lib\crt0.o'),
        (Join-Path $project 'main.cpp'),
        '-o', $output,
        '-Wl,--gc-sections', '-s',
        '-L', (Join-Path $mini 'lib'), '-lcmini', '-lgcc'
    )
    & $compiler @arguments
    if ($LASTEXITCODE -ne 0) { throw "Kompilacja nie powiodla sie (kod $LASTEXITCODE)." }

    $header = [System.IO.File]::ReadAllBytes($output)
    if ($header.Length -lt 28 -or $header[0] -ne 0x60 -or $header[1] -ne 0x1a) {
        throw 'Plik wynikowy nie ma naglowka Atari PRG.'
    }
    $format = (& $objdump -f $output | Out-String)
    if ($LASTEXITCODE -ne 0 -or $format -notmatch 'elf32-atariprg') {
        throw 'Plik wynikowy nie zostal rozpoznany jako Atari PRG.'
    }
    $size = (Get-Item -LiteralPath $output).Length
    Write-Host "Gotowe: $output ($size bajtow, Atari PRG, MC68000)"
}
finally {
    $env:PATH = $oldPath
}

Uruchomienie: w PowerShell przejść do

projects\hello-cpp

i wykonać

.\build.ps1

.

Ograniczenie: to mały program napisany w C++17, ale tekst wypisuje przez

puts

z libcmini. Skrypt nie linkuje pełnego libstdc++; wyłącza też wyjątki i RTTI. Użycie

std::cout

lub innych cięższych części biblioteki standardowej może ponownie zwiększyć rozmiar PRG.

Gdybyś potrzebował:

GCC i binutils dla m68k-atari-mintelf
Repozytorium libcmini
Gotowy pakiet libcmini dla mintelf

3

Dzięki, spróbuję. Niestety chciałem użyć std:string...

Mayonez/COBRA
Atari 1040 STE (4MB RAM, TOS 2.06/1.06, Ultrasatan, Netusbee)
Atari 65XE, 512KB ext. RAM, SIO2SD, FujiNet, IDE2+

4

Racja,... Poszukałem jeszcze i udało mi się zbudować mały program z prawdziwym std::string z nagłówków libstdc++ GCC 15.2.0. Wynikowy HELLO.PRG ma 4821 bajtów. Uruchomiłem go w Hatari; wypisuje "Hello World from C++ on Atari ST!".

Używam libcmini, ale nie linkuję ani mintlib, ani libstdc++. Potrzebne są natomiast nagłówki mintlib, bo nagłówki samej libcmini nie wystarczają do skompilowania <string>.

Układ katalogów w moim przykładzie:

D:\atari\mint\
  toolchain\mingw64\
  libcmini\usr\
  mintlib-headers\include\
  projects\hello-std-string\
    main.cpp
    runtime.cpp
    string_inline.hpp
    build.ps1

Do mintlib-headers\include skopiowałem zawartość katalogu usr\m68k-atari-mintelf\sys-root\usr\include z paczki deweloperskiej mintlib.

main.cpp:

#include <string>
#include <stdio.h>

int main() {
    std::string message("Hello");
    message += " World from C++ on Atari ST!";
    puts(message.c_str());
    return 0;
}

runtime.cpp:

#include <stddef.h>
#include <stdlib.h>

void* operator new(size_t size) {
    void* result = malloc(size);
    if (!result) abort();
    return result;
}

void operator delete(void* ptr) noexcept {
    free(ptr);
}

void operator delete(void* ptr, size_t) noexcept {
    free(ptr);
}

namespace std {
[[noreturn]] void __throw_length_error(const char*) {
    abort();
}

[[noreturn]] void __throw_out_of_range_fmt(const char*, ...) {
    abort();
}
}

string_inline.hpp:

#include <bits/c++config.h>
#undef _GLIBCXX_EXTERN_TEMPLATE
#define _GLIBCXX_EXTERN_TEMPLATE -1

build.ps1:

$ErrorActionPreference = 'Stop'

$project = $PSScriptRoot
$root = [System.IO.Path]::GetFullPath((Join-Path $project '..\..'))
$bin = Join-Path $root 'toolchain\mingw64\bin'
$mini = Join-Path $root 'libcmini\usr'
$headers = Join-Path $root 'mintlib-headers\include'
$compiler = Join-Path $bin 'm68k-atari-mintelf-g++.exe'
$output = Join-Path $project 'HELLO.PRG'

$oldPath = $env:PATH
try {
    $env:PATH = "$bin;$oldPath"

    $flags = @(
        '-m68000', '-std=c++20', '-Os',
        '-fno-exceptions', '-fno-rtti', '-fno-threadsafe-statics',
        '-fno-unwind-tables', '-fno-asynchronous-unwind-tables',
        '-ffunction-sections', '-fdata-sections',
        '-idirafter', $headers,
        '-idirafter', (Join-Path $mini 'include'),
        '-include', (Join-Path $project 'string_inline.hpp')
    )

    & $compiler @flags -c (Join-Path $project 'main.cpp') `
        -o (Join-Path $project 'main.o')
    if ($LASTEXITCODE -ne 0) { throw 'Blad kompilacji main.cpp' }

    & $compiler @flags -c (Join-Path $project 'runtime.cpp') `
        -o (Join-Path $project 'runtime.o')
    if ($LASTEXITCODE -ne 0) { throw 'Blad kompilacji runtime.cpp' }

    $link = $flags + @(
        '-nostdlib',
        (Join-Path $mini 'lib\crt0.o'),
        (Join-Path $project 'main.o'),
        (Join-Path $project 'runtime.o'),
        '-o', $output,
        '-Wl,--gc-sections', '-s',
        '-L', (Join-Path $mini 'lib'),
        '-lcmini', '-lgcc'
    )

    & $compiler @link
    if ($LASTEXITCODE -ne 0) { throw 'Blad linkowania' }

    Write-Host "Gotowe: $output ($((Get-Item $output).Length) bajtow)"
}
finally {
    $env:PATH = $oldPath
}

Sprawdziłem też w Hatari operacje replace, substr, find i at. Dało się je zbudować bez linkowania libstdc++.

PS. To jest rozwiązanie dla programu bez wyjątków, a nie zamiennik całej libstdc++. Przy braku pamięci lub niektórych błędach zakresu program kończy się przez abort(). Użyte makro jest wewnętrznym szczegółem libstdc++, więc po zmianie wersji GCC trzeba ponownie sprawdzić kompilację i działanie.