LINUX.ORG.RU

hpp vs cpp

 ,


0

2

Привет! Вот вброс. какие есть за и против писать все в заголовочных файлах, с шаблонами и без, и писать, использую *.cpp файлы. (ну я хочу поднять эту тему у себя, вот готовлюсь.)

если это тут возможно, изменю это сообщение и добавлю, ответы. пока что так

hpp подход

  • + ускоряет компиляцию
  • + дает возможность компилятору проверять код
  • + не нужна система сборки

cpp подход

  • - замедляет сборку
  • - обязывает иметь систему сборки, если проект не тривиален
  • - пряет определения функций от компилятора, что выключает полезные варнинги и оптимизаии

Ответ на: комментарий от slackwarrior

«самого правильного» способа.

Давай оставим вопрос религии. Объективно писать вручную на скриптах, когда cmake - это те же скрипты, но с обилием всяких помогалок для единообразного вида на разных системах и уменьшением времени разработки по сравнению с ручным описанием сборки на bash с нуля.

rumgot ★★★★★
()
Ответ на: комментарий от rumgot

Ну религия так религия, пиши каждый раз на цмейк, если нужны «помогалки» чтоб простой скриптик написать для того с чем тыщу лет назад прекрасно справлялся grep, глобальная замена sedом и еще пара фильтров в пайпе :) Велосипедостроители все сводят к религии, не замечая своего NIH синдрома. Какая там тебе ручая сборка всего на баш приснилась — знает только боженька :) Иногда просто нужна рутинная автоматизация («билдсистема» еще не все, а комбайн «помогалок» ради простых вещей заведомо не нужен), скрипты для которой на цмейк просто не выглядят «простыми», а девопсы без «помогалок», вебморд и т.д. уже порой и шагу ступить не могут: фильтр по логам гита на цмейке конечно можно написать... но зачем.

slackwarrior ★★★★★
()
Ответ на: комментарий от slackwarrior

Ну религия так религия, пиши каждый раз на цмейк, если нужны «помогалки» чтоб простой скриптик написать для того с чем тыщу лет назад прекрасно справлялся grep, глобальная замена sedом и еще пара фильтров в пайпе :)

А еще раньше на assembler писали.

Какая там тебе ручая сборка всего на баш приснилась — знает только боженька

Почитай ветку.

Иногда просто нужна рутинная автоматизация («билдсистема» еще не все, а комбайн «помогалок» ради простых вещей заведомо не нужен

Что такое эти «простые вещи»? Hello world. Мы обсуждаем, что в реальности используется или, что можно дома велосипедить на один раз?

скрипты для которой на цмейк просто не выглядят «простыми»

По сравнению с bash скорее всего выглядят.

а девопсы без «помогалок», вебморд и т.д. уже порой и шагу ступить не могут: фильтр по логам гита на цмейке конечно можно написать… но зачем.

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

rumgot ★★★★★
()
Последнее исправление: rumgot (всего исправлений: 1)
Ответ на: комментарий от rumgot

Зачастую щас «проект» это тоже просто пирамидка из бустов, кутей и т.д., т.к. архитекторы не хотят чтоб девелоперы писали килотонны велосипедов, а стало быть это просто куча зависимостей от чужого бойлерплейта. Совершенно неважно скока там чужих файлов, которые еще и не все цмейком собираются (например, v8 или буст :) Можешь склеить их цмейком. Но это совсем не обязательно.

slackwarrior ★★★★★
()
Ответ на: комментарий от slackwarrior

Да причем тут бестпркттицес? Я пишу, как делают в средних-крупных проектах. Это используется не потому что какой-то гуру так сказал, а потому что это удобнее.

rumgot ★★★★★
()
Ответ на: комментарий от pihter

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

ox55ff ★★★★★
()
Ответ на: комментарий от zerhud

Линковка выполняется над объектными файлами. Если не рассматривать LTO, то линковка в целом сводится к тупому копированию содержимого нескольких файлов в один с заменой ссылок на символы их адресами, плюс ещё нужно выполнить релокации кода. Теоретически линкер может вообще работать чуть ли не в потоковом режиме и не загружать целиком в ОЗУ ни один объектный файл в память, держа в памяти лишь глобальную таблицу символов.

А вот при компиляции исходник в памяти компилятора превращается в AST дерево, на котором потом запускаются всякие сложные алгоритмы, которые потенциально тоже создают всякие сложные структуры данных. Это потребляет гораздо больше памяти, чем линковка. Так как, условно, 2D структура исходника превращается в 3D. Во-первых, потоковый компилятор C++ принципиально невозможен (нужно обязательно держать все структуры в памяти одновременно), во-вторых, требуется реально много вспомогательных структур.

Линковка с включенным LTO это что-то среднее между обычной линковкой и компиляцией. Линкеру приходится держать в памяти всякие структуры, но всё же их требуется меньше.

KivApple ★★★★★
()
Ответ на: комментарий от slackwarrior

которые еще и не все цмейком собираются

Процесс сборки своего проекта и процесс сборки окружения в виде буста - это разные процессы. Не важно, как собирется буст, важно, что его можно использовать через cmake.

rumgot ★★★★★
()
Ответ на: комментарий от rumgot

А еще щас некоторые без «репозитория сиплюсплюса» шагу ступить не могут :) И? :)

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

Ну он либо знает инструменты и простые способы. Или не знает, что гиту не нужна вебморда чтоб работать. А еще что зависимости не надо каждый раз скачивать и пересобирать знают не все (более того, кукарекают про «апдейты всегда хорошо»... до первой поломки билда из-за свежей регрессии и тонны хейта в рабочем чятике от толпы раздосадованных разработчиков :)

slackwarrior ★★★★★
()
Ответ на: комментарий от rumgot

процесс сборки окружения в виде буста - это разные процессы

важно, что его можно использовать через cmake

Можно. Не всегда нужно :) а порой таки важно как собирается буст, т.к. есть варианты как с ним линковаться и «дефолт» не нужен. Т.к. есть N клиентов каждый со своими тараканами.

slackwarrior ★★★★★
()
Последнее исправление: slackwarrior (всего исправлений: 1)
Ответ на: комментарий от rumgot

Удобство — это вообще субъективно. Ман «синдром утенка». А бестпрактисы каждые полгода новые :) и их новорожденные одепты тоже вылупляются регулярно. Например, свой опыт считают универсальным :) Но в других среднекрупных проектах делают по-другому, потому что... им так удобнее :)

slackwarrior ★★★★★
()
Ответ на: комментарий от zerhud

я тут говорю о том, что замедляет компиляцию отдельного файла, зато ускоряет компиляцию проекта в целом.

Может быть и так и эдак конечно. Но чаще и в среднем, если руки прямые, ПЕРЕКОМПИЛЯЦИЯ при разбиение на несколько единиц трансляции ускоряется. Потому что перекомпилировать надо не все а какой то кусок.

что мимо кассы? там только про доступность всего ast при компиляции. это делает возможным всякие compile time проверки для которых, в противном случае, не было бы нужной информации.

Все мимо кассы. Эти оптимизации актуальны для инлайн-функций, ну дык они и так в хидерах. Но есть ещё много неинлайн функций, и там общий анализ кода ничего не даст.

Опять таки, инлайн не всегда хорошо с тз производительности.

AntonI ★★★★★
()
Ответ на: комментарий от AntonI

hpp (отказ от раздельной компиляции) замедляет компиляцию

Да?

% hyperfine --runs 10 --prepare 'make clean' 'make partialbin'
Benchmark 1: make partialbin
  Time (mean ± σ):      1.889 s ±  0.024 s    [User: 1.707 s, System: 0.154 s]
  Range (min … max):    1.860 s …  1.933 s    10 runs
 
% hyperfine --runs 10 --prepare 'make clean' 'make wholebin'
Benchmark 1: make wholebin
  Time (mean ± σ):      1.052 s ±  0.017 s    [User: 0.948 s, System: 0.090 s]
  Range (min … max):    1.033 s …  1.075 s    10 runs

Makefile:

partialbin: partialmain.o partialfoo.o
	g++ -o $@ partialmain.o partialfoo.o

partialmain.o: main.cpp
	g++ -o $@ -c -I. $<

partialfoo.o: foo.cpp
	g++ -o $@ -c -I. $<

wholebin: both.cpp
	g++ -o $@ both.cpp

both.cpp: foo.cpp main.cpp
	cat foo.cpp main.cpp > both.cpp
	sed -i '/foo.h/d' both.cpp

clean:
	$(RM) *.o partialbin wholebin both.cpp
// foo.h
#pragma once

void foo();

// foo.cpp

#include <foo.h>
#include <iostream>

void foo() {
    std::cout << __PRETTY_FUNCTION__ << '\n';
}

// main.cpp

#include <foo.h>
#include <iostream>

int main() {
    std::cout << __PRETTY_FUNCTION__ << '\n';
    foo();
}

Модули спасут отца русской демократии. Однажды. А пока что чем меньше .cpp файлов, тем быстрее будет сборка – при условии конечно, что у вас в .hpp есть какой-то код, а не сишные объявления. Ну и не стоит забывать про то, что чем больше информации о программе доступно компилятору, тем больше оптимизаций он сможет к ней применить.

Разумеется, разделение на файлы тоже нужно, так как в один .cpp свалить все не получится – компилятор тоже не всесильный. Но ваше утверждение является, мягко говоря, необоснованным.

Siborgium ★★★★★
()
Ответ на: комментарий от Siborgium

Ну например же https://herbsutter.com/2011/11/04/gotw-100-compilation-firewalls/

Не всегда нужно собрать все в один бинарь. А скорость сборки можно порешать пимплом и форвард декларейшонами.

slackwarrior ★★★★★
()
Последнее исправление: slackwarrior (всего исправлений: 1)
Ответ на: комментарий от slackwarrior

Да, pimpl как пример случаев, когда разделение необходимо. При этом нужно понимать что pimpl это дорого, а потому без необходимости прибегать к этой идиоме не стоит.

Siborgium ★★★★★
()
Ответ на: комментарий от Siborgium

Зависит от разбиения на единицы трансляции конечно и фокусов с инстацированием шаблонов. Конечно, если шаблоны толстые и инстацируются в каждой единице, то чем больше единиц тем дольше сборка.

Если шаблонов мало и инлайнов мало, то до некоторого обьема кода время сборки всего проекта от числа единиц не зависит. Хотя если сборка параллельная, то зависит.

Но вот скорость ПЕРЕКОМПИЛЯЦИИ от числа единиц трансляции зависит, и ещё как. По каждому чиху пересобирать весь проект ну такое…

AntonI ★★★★★
()
Ответ на: комментарий от Siborgium

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

slackwarrior ★★★★★
()
Последнее исправление: slackwarrior (всего исправлений: 1)
Ответ на: комментарий от slackwarrior

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

Не всегда нужно собрать все в один бинарь.

Зачастую – нужно. Будь то исполняемый файл, статическая или динамическая библиотеки.

А скорость сборки можно порешать пимплом и форвард декларейшонами.

Пимпл не решает проблемы скорости сборки. Вернее, решает, но для не-шаблонного кода в С/C с классами стиле. Для С++ он скорость сборки ухудшает. Ключевая задача pimpl – спрятать детали реализации, чтобы они не протекали при подключении заголовочных файлов.

Форвард декларейшны а) нужно обновлять б) бесполезны для использования в шаблонном контексте. Это как раз тот самый С с классами стиль.

Siborgium ★★★★★
()
Ответ на: комментарий от Siborgium

Зачастую – нужно

А зачастую нет :)

Пимпл не решает проблемы скорости сборки. Вернее, решает, но для не-шаблонного кода в С/C с классами стиле.

А развесистый шаблониум тоже нужен не везде :)

Форвард декларейшны а) нужно обновлять б) бесполезны для использования в шаблонном контексте. Это как раз тот самый С с классами стиль.

Аргуметы от корнеркейса :) Т.е. достаточно контрпримера, которым пимпл и является :)

slackwarrior ★★★★★
()
Ответ на: комментарий от Siborgium

А пока что чем меньше .cpp файлов, тем быстрее будет сборка

Полная сборка - возможно (но далеко не факт). Только с точки зрения производительности труда людей интересует время инкрементальных. Никто в своём уме не будет по несколько часов ждать пока крупный проект целиком пересобирается после минимальных изменений.

bugfixer ★★★★★
()
Ответ на: комментарий от Siborgium

Да, есть преимущества :) клиентам насрать на шаблонную магию, а вот за скорость сборки бывает плюсик в карму :) т.к. им неинтересно почему оно «компиляется». У шаблонов тоже хватает недостатков. Главное не злоупотреблять любимым молотком, а то везде гвозди мерещатся.

slackwarrior ★★★★★
()
Ответ на: комментарий от slackwarrior

А зачастую нет :)

Демагогия. Объектники нужны очень редко.

А развесистый шаблониум тоже нужен не везде :)

Рекомендую открыть по порядку <vector> <iostream> <fmt> <utility> <tuple> <optional> <type_traits>, и конечно же <functional>. Особое внимание на первые два, которые включаются примерно везде.

От того, что вы лично «развесистый шаблониум» не написали, он никуда не пропадет.

Т.е. достаточно контрпримера, которым пимпл и является

Контрпримером чему пимпл является?

Siborgium ★★★★★
()
Ответ на: комментарий от Siborgium

Демагогия. Объектники нужны очень редко.

Не более чем твой шаблонный фанатизм :) при позднем связывании в плугинах очень даже норм

От того, что вы лично «развесистый шаблониум» не написали, он никуда не пропадет.

Лично я видел templates.cpp который собирался двое суток из-за злоупотребления авторами шаблониумом :)

Контрпримером чему пимпл является?

Сборке мира, из-за пары строчек, которая нужна не всем.

slackwarrior ★★★★★
()

зачем все писать в каких-то хидерах??? писать надо все в одном файле, вставив весь код копипейстом.

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

чем больше у тебя файл в строках - тем ты круче программист. рабочие файлы в 100 млн строк - удел мастеров.

alysnix ★★★
()
Ответ на: комментарий от Siborgium

hpp (отказ от раздельной компиляции) замедляет компиляцию

Да?

На самом деле - «да». Только не надо демонстрировать циферки на пустых файлах. Чтобы доказать обратное Вам придётся нас всех убедить в том что ни один из проходов выполняемых компилятором не хуже O(N).

bugfixer ★★★★★
()
Ответ на: комментарий от pihter

Не надо ничо изобретать :) ИТТ всем мерещится какой-то версус батл. Можно пользоваться и тем и тем. Другое дело что некоторым на любой чих комбаен «помогалок» подавай.

slackwarrior ★★★★★
()
Последнее исправление: slackwarrior (всего исправлений: 1)

не нужна система сборки

А при пайке простенькой электронной схемы – не нужна печатная плата. А то её сначала разрисовывать, потом травить… Нафиг, можно же тупо скрутить-припаять ноги элементов друг к дружке.

pr849
()
Ответ на: комментарий от rumgot

Да так-то скрипты на баше нормально для сборки окружения применять. Только положить их надо в гит где-то около Dockerfile.

Например, собираешь под дебиан и тебе apt настроить надо

COPY scripts/apt.sh /tmp/apt.sh
RUN /tmp/apt.sh
fluorite ★★★★★
()
Последнее исправление: fluorite (всего исправлений: 1)
Ответ на: комментарий от pr849

А при пайке простенькой электронной схемы – не нужна печатная плата. А то её сначала разрисовывать, потом травить… Нафиг, можно же тупо скрутить-припаять ноги элементов друг к дружке.

Навесной монтаж! Хрен ли морочиться!

soomrack ★★★★★
()

hpp подход

  • ускоряет компиляцию

Нет, он замедляет компиляцию, потому что не позволяет собирать только изменившиеся файлы, при этом параллельно и с ccache.

  • дает возможность компилятору проверять код

Возможность проверять код не зависит от того где он находится.

  • не нужна система сборки

Система сборки нужна всегда.

slovazap ★★★★★
()
Ответ на: комментарий от slovazap

На счет ccache да, остальное - нет. Вот сейчас по работе один файл изменишь, заголовок, тригирятся штук 50 cpp, а так по кол-ву тестов, в итоге быстрее. Очень редкий случай, когда заголовок поправил и пару файлов пересобралось. Но даже в этом случае все равно тест пересобераться будет, так что по времени сборки примерно одинаково.

По поводу проверять код - в смысле весь аст доступен, информации больше.

Система сборки нужна всегда? Почему?

zerhud
() автор топика
Ответ на: комментарий от bugfixer

ни один из проходов

если метод а лучше метода б в 99 случаев из 100, а в 1 хуже, то, очевидно, метод а лучше, так как метод б в 99 случаев хуже.

не надо демонстрировать циферки на пустых файлах

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

zerhud
() автор топика
Ответ на: комментарий от zerhud

Ну смотря где. Мне наоборот приходилось разбивать на разные файлы чтобы в раму влазило. А ещё один файл компилироваться будет в один поток (если это не msvc, там было какое-то распараллеливание в пределах одного юнита)

mittorn ★★★★★
()
Ответ на: комментарий от zerhud

если метод а лучше метода б в 99 случаев из 100, а в 1 хуже, то, очевидно, метод а лучше, так как метод б в 99 случаев хуже.

Мне, безусловно, нравится Ваша целеустремлённость и уверенность. Вот только не работает оно так на практике. Мне приходится собираться десятки и сотни раз в день, и я бы умер ждать если бы каждый раз оно было с нуля. Если Вы вырастете за пределы «Hello, world» - поймёте (часть апликух с которыми я имею дело только линкуется больше 10 минут)…

ПыСы. Если Вы считаете что оптимизатор такой «волшебный» и вне зависимости от размера кода делает одинаково хорошую работу - то у меня для Вас сюрприз: у нас уже имеются .cpp которые (в частности) вызывают «variable tracking size limit exceeded with -fvar-tracking-assignments, retrying without» warnings. И я только что специально посмотрел - компиляция только одного из таких файлов занимает порядка 2.5 минут, на вполне себе неслабой билдовой машинке…

bugfixer ★★★★★
()
Ответ на: комментарий от ox55ff

Руками Makefile пишут именно что адекваты. Ибо если для проекта можно написать Makefile руками не страдая то больше ничего и не нужно.

https://github.com/search?l=Makefile&q=Makefile&type=Repositories

Это нездоровые на голову для мелких и средних проектов включая «привет мир» тащат meson/cmake/ и прочее да ещё приправляют всё это докером.

Вот для большого или/и сложного проекта да надо уже что-то помощнее. Хотя, смотря как организован проект.

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

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 2)
Ответ на: комментарий от slackwarrior

Можно пользоваться и тем и тем. Другое дело что некоторым на любой чих комбаен «помогалок» подавай.

Да я так и делаю: почти все собираю мейком, а в редких случаях, когда не хватает, немного подсобляю башем: на кой пес людям нужно что-то еще для сборки – для меня все еще загадка

pihter ★★★★★
()
Ответ на: комментарий от ox55ff

Потому что это может прокатить только на маленьком проекте, где малое число файлов

Почему? Иерархия же есть

Во вторых с самописными makefile будут проблемы с ide, которая не сможет извлечь инфу о проекте и какие файлы с какими ключами собираются.

Ну и дуры, значит, твои IDE. Это подгонка задачи под решение, не находишь?

pihter ★★★★★
()