Приветствую, Хабравчане!
Сидел я значит за свои столом, читал Хабр, листал хаб старое железо и ничего не предвещало беды. В последнее время появилось много обзоров на старые ноутбуки, что даже захотелось найти и прикупить. Смотрю, где то дос стоит, windows 95.
Умилялся скриншотами, вчитывался в характеристики девайсов, pentium 1 c 100 mhz и 16 мб озу. Смешно конечно по нашим меркам. Естественно в голову приходили мысли, железо конечно абсурдно по производительности, но если применить современные фичи С++ то вполне можно и под них писать да хоть игры. Правда нет таких современных компиляторов поддерживающих такую дремучую древность.
Ещё раз окинул взглядом репозиторий по SimpleOS где получилось перевести хост версию на модули С++ 20. И так они мне понравились, что когда я загрузил сою библиотеку LDL, даже пропало желание программировать, так как проект написан на С++ 98 с серьезными ограничениями, нет namespace, свои минимальные шаблоны и т.д Вздохнул, и сказал про себя было бы здорово если бы получилось переписать к примеру тот же LDL на С++ 23 и сохранить совместимость со старым железом.
И тут сработал триггер в голове, подождите, что то подобное я где то видел. Начал искать гуглить и нашел.
Если в кратце
Михал понял, что объектные файлы, созданные AOT-компилятором CoreRT в 2020 году, можно собрать компоновщиком из Visual C++ 2.0 образца 1994 года. В результате получается машинный код, скомпонованный с интерфейсами Win32s, работающими в 16-разрядной Windows 3.11. Магия. Респект Михалу.
А, что так можно было?
И тут Бендер всё понял :-)
У меня был план и я его придерживался.
Дано, большое желание программировать под ретро железо используя современные фичи С++ 23. Windows 11 и Visual Studio Community 2026 (на днях обновился)
Что бы план сработал нужно.
Собирать код компилятором msvc 2026 c указанием что бы компилировал только в 32 битный x86, ещё отключить исключения и стандартную библиотеку, этим компилятор будет порождать только чистые и совместимые obj файлы.
Спасибо Microsoft что за больше чем 25 лет не стали кардинально менять формат obj. Ну хоть, что то они не сломали:)
Берем линкер от Visual C++ 6.0 и скармливаем эти obj файлы.
Получаем exe совместимый с Windows 95.
Теперь практика.
Создаем main.cpp
import std;
import Win32;
int main()
{
std::string title = "Hello Habr!";
std::string message = "Crazy programming!";
MessageBoxA(GetActiveWindow(), title.c_str(), message.c_str(), 0x00000000L);
ExitProcess(0);
return 0;
}Просто выводим самым простым способом, текст.
Создаем модуль Win32.ixx
export module Win32;
extern "C"
{
__declspec(dllimport) void* __stdcall GetProcessHeap();
__declspec(dllimport) void* __stdcall HeapAlloc(void* hHeap, unsigned int dwFlags, unsigned int dwBytes);
__declspec(dllimport) int __stdcall HeapFree(void* hHeap, unsigned int dwFlags, void* lpMem);
__declspec(dllimport) void* __stdcall GetActiveWindow();
__declspec(dllimport) int __stdcall MessageBoxA(void* hWnd, const char* lpText, const char* lpCaption, unsigned int uType);
__declspec(dllimport) void __stdcall ExitProcess(unsigned int);
}Экспортируем нужные нам функции.
Так как нет STL и libc то нужно для совместимости кода написать свой минимальный вариант.
void* malloc(size_t size)
{
return HeapAlloc(GetProcessHeap(), 0, size);
}
void free(void* ptr)
{
if (ptr)
{
HeapFree(GetProcessHeap(), 0, ptr);
}
}Базовые вещи, поддержку динамической памяти.
export
{
void* operator new(size_t bytes)
{
return std::malloc(bytes);
}
void* operator new[](size_t bytes)
{
return std::malloc(bytes);
}
void* operator new(size_t bytes, void* ptr)
{
return ptr;
}
void* operator new[](size_t bytes, void* ptr)
{
return ptr;
}
}Перегружаем аллокаторы, они нам нужны что бы написать минимальные std::string
typedef base_string<char> string;Я не стал приводить внутренности строки, они не особо интересны, но в итоге все это экспортируется в пространство имен std;
Код main не меняется, это очень важно.
В чем суть?
Такой способ позволяет писать на С++ 23 под ретро железо с Windows 9x. Пишем в студии код, отлаживаем, тестируем, используем фичи, лямбды, constexpr, модули.
Но при сборке именно под старые ОС используем std реализацию, сейчас в ней не очень много кода, только базовые вещи, что бы запустилось и работало. Общий код остается единым не требуется его переписывать, нужно лишь ограничить проект фичами. Не использовать потоки, файловую систему, мьютексы и исключения. STL можно написать свою, добавить основные контейнеры vector, unordered_map, array.
Из коробки доступно string_view, span и т.д
Для поддержки сборки создал каталог make в нем батники для сборки и сам линкер от vc 6.0

Файл компиляции compiler.bat
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars32.bat"
cl /O2 /std:c++20 /arch:IA32 /GS- /Zc:threadSafeInit- /GR- /EHa- /c ../Win32.ixx
cl /O2 /std:c++20 /arch:IA32 /GS- /Zc:threadSafeInit- /GR- /EHa- /c ../std.ixx
cl /O2 /std:c++20 /arch:IA32 /GS- /Zc:threadSafeInit- /GR- /EHa- /c ../main.cpp
pauseФайл линковки linker.bat
link /SUBSYSTEM:CONSOLE,4.0 /NODEFAULTLIB /ENTRY:EntryPoint /OUT:main.exe ^
main.obj ^
std.obj ^
kernel32.lib ^
user32.lib
pause Не самый удобный способ, но позже добавлю вариант сборки в cmake, пока cmake собирает только под современные системы.
cmake_minimum_required(VERSION 3.28)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_SCAN_FOR_MODULES ON)
set(SOURCES
Win32.ixx)
add_executable(main "main.cpp")
target_sources(main PUBLIC FILE_SET CXX_MODULES FILES ${SOURCES})Теперь все ради чего были все наши мытарства!

Оно живое и даже работает:)
Слышу первый же вопрос, зачем?
Отвечаю.
Мне по фану. Я хочу портировать свои проекты на С++ 23 и оставить совместимость со старыми системами. Только они могут показать, красоту кода через производительность. На моём основном ПК i5 11400 и 48 гб озу (купил до полного пи.. подорожания) На нём ничего не тормозит, ни мой проект LDL, не проект по воссозданию движка Arcanum по которому я пишу цикл статей. А именно на старом железе, где мало памяти у процессора смешные 50-150 mhz и вдруг на них работает графика, проигрывается звук, какой никакой геймплей, 2D графика, бывает даже 3D. И это работает приемлемо, твой код продуман, уже не получится не приходя в сознание писать код чик чик и в прод. Мне это нравится, а если ещё и доступен современный С++ 23 это прекрасно и расширяет вообще сферу ретро программирования, не нужно искать старые компиляторы, пиши на современных собирай и проверяй на Windows 9x.
Это лишь пока проверка идей, ещё предстоит разделить модуль std на контейнеры и реализации определенных фич типа expected. Заменить winapi на реализацию std cout в небольшом объеме. Главное, что бы к��д который пишут на современном ПК, мог без изменений собираться таким способом с подменой всего std, но с доступам к основным фичам С++ 23. Я думаю это клёво.
Теперь я могу продолжать свой цикл статей по разработке движка Arcanum на С++ 23 и не отказываться от поддержки Windows 98.
В ближайшее время обновлю, реализацию std добавлю поддержку linux. Основные контейнеры STL. Думаю, что в Linux с такими пируэтами даже проще.
Есть конечно вариант портировать последний gcc для сборки наитивно под Windows 98, как это сделал пользователь fsb4000, для gcc 11. Но пока я к такой древней и темной магии не готов:)
Обязательно напишу статью о более серьезных успехах, когда они будут в портировании LDL на С++ 23 код с работой на Linux, Windows. Сейчас же это описание возможно безумного, странного, но все же рабочего способа, запустить современный С++ код, на старых системах.
Отвечу на вопрос кому оно вообще нужно то?
Отвечаю. Нам.
К примеру в русскоязычной сфере это конечно Old-Games.ru
Это центр всех любителей и энтузиастов старых, игр, программ, ПК. И я рад, сказать, что тоже являюсь частью. Но мы не только играем в старые игры, но так же создаем новые проекты для старых систем. Новые переводы для старых игры, новые моды, новые улучшения. Все это делается ради фана. Потому, что нравится, у каждого есть своя работа и свои заботы. Но все жё находится время и на такое хобби. Здесь нет KPI или менеджеров, чем хочешь тем и занимайся.
Все же есть в старом железе, свое очарование!
Буду раз, предложениям, советам, критике и рад пообщаться в комментариях.
Ссылка на весь представленный код