Pull to refresh
24
161,3
Rating
4
Subscribers
Send message

Сам принцип работы нейросетей подразумевает, что они будут давать наиболее удобный, а не наиболее честный ответ. Буквально “предсказатель наиболее вероятного следующего слова”.

Поэтому к ИИ всегда стоит относиться критически и всегда все по 7 раз уточнять и переспрашивать. И конечно сверяться с другими источниками.

Проблема в том что компилятор не может сам адаптировать, какой размер зависимостей для какого размера проекта подключать. Вот и выходит что человек написавший свою первую программу, видит 2 мегабайта, думает что язык перегружен и уходит обратно на Python или на чем он там писал раньше.

Практически всегда во всех примерах и учебниках навязывают именно iostream, и совершенно не поясняют что это далеко не единственный способ вывода.

Таргет вроде бы явный - hello.exe а не просто hello. Да системные вызовы чисто виндовые.

В третьем же абзаце было упоминание -static

Выбрать удачное название статьи так, чтобы было и эффектно, и просто, и чтобы все всё правильно поняли - тот еще квест.

Для данного примера -О3 не дает эффекта. Это флаг оптимизации отвечает за скорость программы в рантайме, а не за размер бинарника. Хотя есть флаг и для этого -Os но обычно он выигрыша не дает.

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

Чтобы все эти паре-тройке вариантов можно было выкинуть ели они явно не нужны.

Так вроде бы и называл это "системным вызовом" :)

Винда грешит тем, что даже при -static, она может неявно подключать динамические зависимости. Хотя для того же msvcrt.dll и kernel32.dll это не столь большая проблема. Так как вендор единый, они 100% будут в системе начиная с Win2000.

А вот ucrtbase.dll относительно новый, и уже могут быть системы где его еще не существовало.

Вы забыли указать -static - вам откроется портал кроличей норы :)

Статическая линковка пихает в бинарник то, что вам бы пришлось тащить в виде .dll/.so в папку вашего проекта. Динамическая библиотека грузится полностью в память, а вот при статической линковке потенциально уже может вырезать только нужные для работы объектные файлы.

Так у вас же dynamically linked :)
Использовали ли вы флаг -static? На линухе оно неизбежно будет тащить либо glibc либо musl .

Я упоминал, что:

И, собственно всё. Иные флаги оптимизаций не влияют на размер при текущей кодовой базе.

То есть ни -flto/-flto=thin, ни -fno-exceptions ни даже специальный флаг GCC -fwhole-program не помогли выкинуть лишнее в случае включения iostream. Видимо линкер считает все его зависимости используемыми.

С printf также, линкер даже со всеми навешенными оптимизациями может просто не найти неиспользуемые символы чтобы их выкинуть.

Оптимизации линкера очень хороши, но они бессильны если из конкретной сборки стандартной либы физически выкидывать нечего.

Что на счет отказа от CRT - я это использовал в качестве сравнительного примера именно для Hello World и только под Windows.

Однако для проектов посложнее, однозначно что этот путь будет крайне тернист и использование стандартного CRT будет куда выгоднее.

Я даже не стал приводить приводить примеров самопального CRT для Linux, т.к. там уже понадобились бы прямые ассемблерные вставки, что уже требует специализаций под конкретную архитектуру, а там уже есть чему ломаться. У части пользователей это могло бы просто не запуститься или что еще хуже выполнить это некорректно. Тут рациональнее использовать статическую линковку с musl заместо glibc.

Это же касается только RAM, кризис HDD пока еще не наступил, так что экономия места там мало кого волнует.

Как только вы начинаете полагаться на то что libstdc++ будет предустановлена в системе, есть риск, что на другом компьютере вы можете столкнуться c

Запуск программы невозможен, так как на компьютере отсутствует libstdc++.dll

Или какой-либо другой внешней библиотеки на которую вы полагаетесь. Это уменьшает переносимость и вынуждает качать внешние зависимости.

ldd hello.exe 
  linux-vdso.so.1 (0x00007ffed21c3000)
  libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f4b17c00000)
  libm.so.6 => /lib64/libm.so.6 (0x00007f4b17b25000)
  libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f4b17eca000)
  libc.so.6 => /lib64/libc.so.6 (0x00007f4b17800000)
  /lib64/ld-linux-x86-64.so.2 (0x00007f4b17ef0000)

В вашем примере вы полагаетесь на то, что в системе будут и libstdc++ и libc и libm и еще от компилятора libgcc_s.

Если хоть чего-то из этого не будет, или же будет не той версии которой нужно (привет от GLIBC) - ваш файл превращается в тыкву. Он не запуститься в среде с musl или же где нет компилятора с его libgcc_s.so.

Я пытался сделать обзор проблемы именно с точки зрения разработчика С++, а не как ревер-инженер на ASM. Целью этого мини-исследования было именно практически добиться минимально возможного размера компилятором С++ (в данном случае GCC) и показать развитие тенденции вместе с обновлением компилятора, конкретное содержание PE заголовков для этого мне показалось излишним. Хотя это вполне имеет место быть, и спасибо вам за дополнение!

Проблема в том, что более высокоуровневые языки почему-то не выкидывают лишнее в очевидных ситуациях, когда исключения попросту не требуются. Например компилятор GCC догадывается не прикручивать исключения для Hello Worldно как только в коде появляется malloc()/free() компилятор уже может их включить, и тут уже нужно явно указывать флаг что стоит отключить добавление механизма исключений.

В вашем примере для того чтобы добиться размера меньше, вам уже пришлось использовать ASM, что уже не совсем разработка на С++ :)

Компилятор по идее для того и нужен чтобы упростить жизнь разработчику и не заставлять его писать на ASM из-за того что компилятор не справился со своей задачей лучше программиста.

Information

Rating
33-rd
Registered
Activity

Specialization

Бэкенд разработчик, Системный инженер
C++
Node.js
Linux