惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Forbes - Security
Forbes - Security
A
Arctic Wolf
M
MIT News - Artificial intelligence
T
Threat Research - Cisco Blogs
T
The Exploit Database - CXSecurity.com
C
CERT Recently Published Vulnerability Notes
NISL@THU
NISL@THU
L
Lohrmann on Cybersecurity
Martin Fowler
Martin Fowler
A
About on SuperTechFans
P
Palo Alto Networks Blog
Project Zero
Project Zero
The GitHub Blog
The GitHub Blog
WordPress大学
WordPress大学
Blog — PlanetScale
Blog — PlanetScale
博客园_首页
大猫的无限游戏
大猫的无限游戏
Cisco Talos Blog
Cisco Talos Blog
P
Proofpoint News Feed
D
DataBreaches.Net
Cyberwarzone
Cyberwarzone
T
Tor Project blog
IT之家
IT之家
P
Proofpoint News Feed
Help Net Security
Help Net Security
S
Securelist
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
CXSECURITY Database RSS Feed - CXSecurity.com
Microsoft Azure Blog
Microsoft Azure Blog
V2EX - 技术
V2EX - 技术
K
Kaspersky official blog
Hugging Face - Blog
Hugging Face - Blog
MongoDB | Blog
MongoDB | Blog
B
Blog
N
News and Events Feed by Topic
The Cloudflare Blog
S
Schneier on Security
P
Privacy & Cybersecurity Law Blog
T
The Blog of Author Tim Ferriss
Recorded Future
Recorded Future
Last Week in AI
Last Week in AI
The Last Watchdog
The Last Watchdog
Hacker News - Newest:
Hacker News - Newest: "LLM"
L
LangChain Blog
I
InfoQ
F
Full Disclosure
The Register - Security
The Register - Security
阮一峰的网络日志
阮一峰的网络日志
H
Hacker News: Front Page
V
V2EX

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
ncpp: Как создать самодостаточную экосистему на С++98 в 2026 году, которая запустится даже на железе со свалки
Vlad441 · 2026-05-10 · via Все публикации подряд на Хабре

Уровень сложностиСредний

Время на прочтение6 мин

Охват и читатели597

Кейс

Современный С++ стал значительно удобнее по сравнению с прошлыми стандартами. STL и стандартная библиотека существенно облегчают жизнь программиста. С каждой новой версией стандарта добавляют что-то новое, что помогает упростить (или усложнить) очередной аспект разработки.

Однако со временем при разработке на С++ начинают появляться вопросики:

  • Везде ли скомпилируется ли моя программа?

    • Поддерживается ли текущая версия компилятора для моей ОС?

    • Поддерживается ли текущий стандарт в моей версии компилятора?

  • Везде ли запуститься моя программа?

    • Какие зависимости тянет моя программа?

      • Есть ли эти зависимости в минимальной комплектации моей ОС?

      • Или может проще все статически намертво слинковать?

  • На сколько эффективны стандартные реализации?

    • На сколько эффективно они линкуются?

    • Какой будет итоговый размер исполняемого файла?

Обилие этих вопросов побудило меня на вопрос А возможно ли это решить?, и я попробовал написать свою реализацию системной библиотеки, которая призвана минимизировать количество таких проблем.

Выбор стандарта и окружения

Как же можно запуститься на максимально возможном количестве конфигураций металлолома, сохраняя минимальный комфорт который дает C++?

Самый ранний из доступных стандартов - C++98, под него больше всего поддерживаемых компиляторов (а следовательно и архитектур и ОС для них) было выпущено.

От каких минимальных версий ОС стоит отталкиваться? В ходе изучения доступных системных вызовов на разных версиях ОС, системных вызовов из Win XP в большинстве своем достаточно для комфортной работы и на Win 10+, а некоторые улучшения в новых версиях можно уже добавить в ходе Progressive Enhancement.

Что на счет Linux, версия ядра 2.6 уже содержит большинство вызовов, которые используются сегодня, например epoll(), pthread_* и прочие.

По компиляторам я пришел к выводу, что более-менее возможно поддерживать компиляторы начиная с gcc 3.4 (с натяжкой при Graceful Degradation), а более полноценно поддерживать начиная с gcc ~4.9, собирая тесты на этой версии, а далее уже следовать Progressive Enhancement. Так как это минимальная версия, в которые включены минимально необходимые определения системных вызовов для написания всех модулей проекта.

Примечание: Подразумевается, что вы сможете одновременно и скомпилировать, и запустить на целевой ОС. Я знаю что вы умеете С++23 запускать и на Win95, но собрать C++23 на Win95, если у вас на руках только металлолом без доступа к современной системе, у вас вряд-ли получится. (Или у кого-то таки получилось?)

Проект нацелен на то, что он должен собраться, даже если ваш металлолом это последний в мире ЭВМ.

Отказ от STL

Как я упоминал в прошлой статье, STL - непозволительная роскошь. Чтобы не зависеть от того, как реализован std::string/std::vector/etc в libstdc++, были написаны свои варианты реализаций ncpp::Array/ncpp::String/etc, которые содержат STL подобный интерфейс.

В стандартных контейнерах реализован метод .stack(), чтобы вы могли передать под управление заранее выделенную память и не дергать лишний раз malloc()/free().

В STL принято использовать snake_case, проект же предлагает использовать CamelCase для более удобного восприятия кода, где классы в конце-концов именуются с большой буквы.

Unity Build

Для упрощения и ускорения сборки используется Unity Build стиль, где собирается единая единица трансляции (мастер-файл) из .cpp файлов в необходимой последовательности, что может помочь с оптимизациями, однако может потреблять больше памяти в сравнении классической модульной сборкой.

Как я бодался с линковщиком?

Если взять простейший пример Hello World:

#include "src/ncpp.cpp"
using namespace ncpp;
int main(){ print("Hello World\n"); }

И скомпилировать его на gcc 4.9.2 просто с флагами g++ -O2 -std=c++98 -static hello.cpp -o hello.exe -lws2_32 -lpsapi мы получим… 702 КБ. Непорядок. Просчитался, но где?

Что не пошло не так с линковкой?

По умолчанию линковщик рассчитан на модульную структуру, где должен включать только те объектные файлы (.o) в которых находятся необходимые символы (функции) для включения в бинарник. Однако для линковщика .o является минимальной включаемой единицей трансляции, и если из него нужен даже один символ, он включит весь .o целиком.

Если же импортируемые статические библиотеки неэффективно собраны, то линковщик может тянуть значительно больше мертвого кода. Для решения этой проблемы придумали LTO (Link Time Optimization).

Однако LTO в основном рассчитан именно на модульную сборку, где на этапе линковки он по идее должен более агрессивно выбирать только нужные символы, видя весь проект “целиком”.

У GCC есть свой специальный флаг -fwhole-program который лучше приспособлен для этой задачи: Он указывает, что текущая единица трансляция и есть вся программа, что позволяет оптимизировать еще агрессивнее. Сравнительная таблица применения флагов:

702 КБ -(без доп. флагов)
415 КБ -s
370 КБ -s -m32
302 КБ -fno-exceptions -fno-rtti -s -m32

Как мы видим, вырезание отладочной информации, архитектура и выпиливание исключений явно помогают уменьшить вес. Для Hello World это нам явно не нужно. Продолжаем навешивать флаги уже с позиции:

g++ -O2 -std=c++98 -static hello.cpp -o hello.exe -lws2_32 -lpsapi -fno-exceptions -fno-rtti -s -m32

302 КБ -fvisibility=hidden
303 КБ -ffunction-sections -fdata-sections -Wl,–gc-sections
138 КБ -flto
138 КБ -flto=thin
138 КБ -flto=thin -fvisibility=hidden -ffunction-sections -fdata-sections -Wl,–gc-sections
138 КБ -flto -fvisibility=hidden -Dexternally_visible=‘visibility(“default”)’
16 КБ -fwhole-program

Как мы видим, не все флаги оптимизации могут помогать в конкретных случаях. Что заметно, флаг -fwhole-program лидирует и может даже немного ускорить компиляцию. Однако в Clang посчитали что он не нужен и LTO справится лучше.

Как мы видим правильные флаги линковки помогают добиться 16 КБ размера исполняемого файла. Однако даже тут оптимизации не смогли вырезать все. Чтобы помочь линковщику, для сравнения я ввел в проект макрос NCPP_BASE_ONLY, который еще на уровне препроцессинга выпиливает большую часть лишнего.

Сравнительная таблица применения флагов с макросом NCPP_BASE_ONLY начиная с g++ -O2 -std=c++98 -static hello.cpp -o hello.exe:

405 КБ -(без доп. флагов)
215 КБ -s
153 КБ -s -m32
129 КБ -s -m32 -flto
129 КБ -s -m32 -flto=thin
16 КБ -s -fwhole-program
12 КБ -s -m32 -fwhole-program

В итоге для кода:

#define NCPP_BASE_ONLY
#include "src/ncpp.cpp"
using namespace ncpp;
int main(){ print("Hello World\n"); }

При использовании таких флагов:

g++ -O2 -std=c++98 -fno-exceptions -fno-rtti -fwhole-program -static -s -m32 hello.cpp -o hello.exe

Удалось добиться размера в 12 кб - размер, сравнимый использованию системного вызова WriteFile. В итоге именно такой вариант параметров я и вшил по умолчанию в сборочный скрипт make.bat

Системщики скажут что это много - и вы будете правы. По оптимизации еще есть над чем работать.

Что с линковкой на Linux?

Тут ситуация усложняется, так как мы наталкиваемся на существенное препятствие: glibc. Его монолитная структура не позволяет линковщику выдернуть только нужное, и он тащится целиком.

  • При использовании iostream которая тянет libstdc++ на gcc 4.8.5 - вы получите 1.3 Mb.

  • И даже при использовании примера выше (без -m32) вы сможете ужаться лишь до 769 Kb.

Как же это можно решить? Отказаться от libc и написать свои syscalls на ASM? Это неоправданно, если только вы не хотите познать ад.

Наиболее компромиссное на текущий момент решение - статическая линковка с musl заместо glibc. В таком случае при использовании:

musl-gcc -O2 -std=c++98 -fno-exceptions -fno-rtti -fwhole-program -static -s hello.cpp -o hello

Вы сможете получить размер около 14 Kb. Этот вариант сборки также можно вызвать из сборочного скрипта make.sh MUSL

Что по зависимостям?

В идеале конечно цель добиться полного Zero Deps, и большая часть компонентов не требуют внешних зависимостей.

Однако с текущей архитектурой современных ОС, некоторые вещи просто невозможно написать без динамической линковки. Например GUI или работу с графикой OpenGL/Vulkan. Нельзя просто взять и вшить ту тонкую прослойку GLX/EGL/libGLdispatch.so чтобы ваш бинарник мог независимо обращаться к видеокарте и дергать из нее API. Ядро-то диспатчить не умеет, а нужных либ в системе может попросту не быть.

Хотя на Windows это работает хитрее. Даже при флаге -static на самом деле у вас все еще остается динамическая зависимость от opengl32.dll, которая содержит реализации OpenGL 1.1 и содержит необходимый wglGetProcAddress() чтобы подгрузить недостающее.

Для любителей ASM

Многие из вас крайне крутые специалисты, которые могут так заоптимизировать Hello World на ASM что оно будет легче планковского веса - я верю что вы это можете и что вы очень круты.

Однако ASM - совершенно непереносим, да и мы тут пытаемся писать именно на С++, пытаясь выжать все соки из доступного компилятора на доступной платформе.

Если же вы действительно готовы писать свой оптимизированный CRT с блэкджеком для большинства существующих архитектур - я был бы рад вашему вкладу в проект.