Dmitry Develop: post #339 — TG.ME

Сегодня хотел скомпилировать программу на C++ с минимальным размером исполняемого файла и без зависимостей от стандартной библиотеки, только winAPI, так как её суть всего лишь быть небольшой обёрткой для запуска другой программы.

Поискал нужные ключи для компилятора по своим проектам, запискам и в интернете, и нашёл их.
Но при компиляции с ними возникли странные ошибки.
Я уже успел забыть про них, и когда-то уже с ними сталкивался, но не сразу вспомнил, как их можно исправить.
Поиск в google похожей проблемы ничего не дал.

Не помню, было ли такое же поведение на более старых версиях gcc + mingw, но при сборке на gcc 14.2.0 и mingw 12.0.0 оно есть, и мне кажется, это баг или недоработка.
Хотя, возможно, так было и раньше, но я мог собирать код без -ffreestanding, поэтому проблема себя не проявляла.
А если компилятор из-за оптимизаций или по другим причинам генерировал вызов любой функции из стандартной библиотеки или crt, то я просто получал ошибку компоновки.
Например, побайтовое копирование циклом for компилятор спокойно может оптимизировать в вызов функции memcpy.

Минимальный воспроизводимый пример состоит лишь из включения заголовочного файла windows.h и ключа компилятора -ffreestanding.
// g++ -ffreestanding -o winapi.exe winapi.cpp

#include <windows.h>

int main()
{
MessageBoxA(nullptr, "Hello world", "message", 0);

return 0;
};


При такой комбинации компилятор выдаёт такой текст ошибки.

Посмотрел в текст заголовочных файлов, на которые указал компилятор, и понял, что из-за ключа -ffreestanding макрос __STDC_HOSTED__ устанавливается в значение 0, поэтому hosted код исключается из сборки.
Беглым поиском я нашёл ещё несколько мест с такими же проверками, но почему-то их не оказалось в x86intrin.h, immintrin.h и xmmintrin.h (возможно, есть ещё такие), которые вне зависимости от значения __STDC_HOSTED__ используют функционал hosted окружения, который отсутствует в freestanding окружении.

Я не знаю для чего нужны эти заголовочные файлы и какое будет наиболее правильное решение, поэтому я сделал максимально простое и тупое решение.
Так как в этих заголовочных файлах вместо директивы препроцессора #pragma once используются header guards через #ifndef #def, я просто перед включением windows.h определил два нужных макроса, чтобы препроцессор не включал эти проблемные заголовочные файлы:
// g++ -ffreestanding -o winapi.exe winapi.cpp

#define _X86INTRIN_H_INCLUDED
#define _EMMINTRIN_H_INCLUDED
#include <windows.h>

int main()
{
MessageBoxA(nullptr, "Hello world", "message", 0);

return 0;
};


Получается, первый способ это не использовать ключ -ffreestanding и получать ошибки на этапе компоновки, а второй это использовать ключ -ffreestanding и получать ошибки на этапе компиляции, но решать некоторые из них придётся костылями или редактированием заголовочных файлов стандартной библиотеки компилятора.
Вне зависимости от использованного способа, конкретно с этим MRE (Minimal Reproducible Example), размер исполняемого файла получается одинаковым.

Интересно даже, действительно ли это баг или недоработка.
Я не знаю, куда писать, но оставлять это как есть не хочется, поэтому буду рад ссылкам и советам, куда мне написать об этой проблеме.

ссылка на канал | ссылка на группу
👍1👎1🤓1
February 22, 2025 662 25 1