Pull to refresh

Comments 84

UFO just landed and posted this here
Мне понравилось, что автор всегда точно понимает, «как оно должно быть на самом деле». Он знает, как обязан выглядеть «идеальный make» и описывает разницу.

Или, к примеру, почему удобный вариант использования надо дополнительно настраивать? Почему простые вещи делаются нетривиально?

Меня в своё время поведение команды git log поразило — надо же, учитывает, что её человек запустить может.
Зато если надо посмотреть так, чтобы в консоли что-то осталось, приходится подпрыгивать :)
Ну, если очень хочется добиться поведения «как у остальных», то можно git log | cat использовать.
Вот вы и подпрыгнули 8)
Перевожу проект с make на scons (сейчас он переходит в фазу активного тестирования и внедрения), в ближайшем будующем напишу несколько статей на эту тему. Могу сказать одно — я убедился что make это устаревший анархаизм. Хотя scons тоже не идеален, но мне на его базе удалось сделать достаточно удобную систему сборки, а точнее целый фреймворк который я в данный момент дорабатываю и смогу использовать с любым другими проектами в будущем (а может даже кто-то еще захочет).
Пользуюсь cmake + make. Вполне доволен.
Плюсы, минусы? Что раздражает, что радует? Большой ли проект?
Проекты у меня маленькие (вот этот, например, пока чуть больше восьми тысяч строк, в завершенном виде должен быть не больше ~30..40 тысяч строк; однако библиотек используется много — поэтому вручную писать Makefile неудобно).

Поначалу я писал Makefile'ы вручную, но когда стало появляться все больше и больше зависимостей, попробовал на automake перейти. Эта зараза мало того, что медленно работает, так еще и не находила кое-какие библиотеки.

А cmake'ом пользуюсь с удовольствием. По-моему, проще уже некуда. Разве только если какая-нибудь система сборки будет грепать мои исходники и самостоятельно каким-то чудным образом понимать, какие библиотеки надо подключить, всякие там msgfmt'ы и т.п. запустить, и куда чего при установке засунуть…
>Разве только если какая-нибудь система сборки будет грепать мои исходники и самостоятельно каким-то чудным образом понимать, какие библиотеки надо подключить, всякие там msgfmt'ы и т.п.
А такого нигде нету? Было бы неплохо вообще не думать о системе сборки и зависимостях (ну или минимум телодвижений).
Ну откуда система сборки знает, что, например, вы используете функции из библиотеки A, а не аналогично обозванные функции из библиотеки Б? Да и даже если во всех библиотеках функции называются по-разному, такой системе пришлось бы сначала просканировать все /usr/include и подобные директории для составления БД функций, соответствующих им заголовочных файлов и соответствующих библиотек. Затем, когда система наткнется на функцию f1, если присутствует #include <h1.h>, подключить библиотеку lib1, если же присутствует #include <h2.h> — библиотеку l2.
Далее: как система сборки узнает, что за способ локализации вы используете?
А как она узнает, куда вы предполагаете скомпилированные файлы разложить?
А что делать с условной сборкой, когда у клиента нет библиотеки l1, но она необязательна — можно собрать без нее (просто приложение станет либо тормознутее, либо лишится дополнительной функциональностью)?
В общем, таких вопросов много.
>Ну откуда система сборки знает, что, например, вы используете функции из библиотеки A,
>а не аналогично обозванные функции из библиотеки Б?

вы ей это скажете, конечно.
человек говорит компьютеру ЧТО делать, это его функция.

>Затем, когда система наткнется на функцию f1, если присутствует #include <h1.h>

сразу нет.
кто из нас делает проект — я или система сборки?
значит, я буду решать что, где и как подключать, а не какой-то магический автомат.

>А как она узнает, куда вы предполагаете скомпилированные файлы разложить?

Fine tuning of the installation directories:
--bindir=DIR user executables [EPREFIX/bin]
--sbindir=DIR system admin executables [EPREFIX/sbin]
--libexecdir=DIR program executables [EPREFIX/libexec]
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
--datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
--datadir=DIR read-only architecture-independent data [DATAROOTDIR]
--infodir=DIR info documentation [DATAROOTDIR/info]
--localedir=DIR locale-dependent data [DATAROOTDIR/locale]
--mandir=DIR man documentation [DATAROOTDIR/man]
--docdir=DIR documentation root [DATAROOTDIR/doc/]
--htmldir=DIR html documentation [DOCDIR]
--dvidir=DIR dvi documentation [DOCDIR]
--pdfdir=DIR pdf documentation [DOCDIR]
--psdir=DIR ps documentation [DOCDIR]

вот вам куча всяких ручек, крутите на здоровье.

>А что делать с условной сборкой, когда у клиента нет библиотеки l1, но она необязательна

проверить наличие, сообщить о присутвии/отсутствии и продолжить сборку.

на все эти вопросы уже давно есть ответы, надо просто уметь их искать, а не изобретать свои системы сборки.
Вот я и говорю, что «магической» системы сборки нет. А более-менее удобная — есть. Cmake.
Я не считаю удобным использование -D<SOME_OBSCURE_DEFINE> вместо ./configure --with-option=.

Есть еще одна претензия — вместо шелла cmake изобретает свой собственный язык, который я вынужден использовать для написания вариации на тему configure.in:

почему
add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE)
удобнее, чем
CFLAGS="$CFLAGS -D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE"
?

Я с первого взгляда не скажу что делает add_definition, а в случае с CFLAGS очевидней уже некуда.
Тут зависит от, конечно. В случае с Си — всë очень сложно. А вот в случае с Go, например, они уже написали тулзу для сборки свою, которая понимает зависимости (и умеет их даже с гитхаба/битбакета/гкода качать) и собирать в библиотеки или бинарники всë.
«Анархаизм» — интересное слово :) Может, «анахронизм»? Потому как «анархаизмов» никаких не существует, а «архаизмом» называют вышедшее из употребления слово :) Хотя, возможно, вы имели в виду, что make — это «анархизм»? :)
Судя по всему, анархаизм — унаследованные хаки. Из серии, нет ничего постояннее временного.
У меня есть железная отмазка — я писал это 6:33 утра и мой мозг после ночи бодрствования не смог оформить правильно поток моих мыслей. Я хотел сказать, что make существует уже очень давно и технологии постоянно развивается, а make как был так и остается на своем очень низком уровне. Но уровень технологий уже сильно вырос с его времен и соответственно требует новых подходов и решений к сборке и управлению ей.
анахренизм :)
Позанудствую. Статья оформлена не по правилам. Для переводов есть специальный тип топика — «перевод».
А как правильно их делать?
сменить тип уже опубликованного топика нельзя, только убирать текущий и делать новый.
достаточно вверху статьи написать
Перевод статьи ...
С точки зрения правил ресурса — недостаточно.
зато с точки зрения пользователя вполне хватит, т.к. я буди читать уже готовым к тому что автору я ответить не смогу…
Автор в итоге не сделал вообще ничего. Показательное презрение к сообществу и администрации.
Нет, изменено форматирование и оформление. Удалять статью и выкладывать заново как перевод считаю ошибкой, так как она уже у 100+ людей в «избранном» — они её потеряют.
Не сделано даже упоминание о то, что это перевод (не сделано сверху, чтобы пользователь сразу понимал это, начав читать и не готовил по ходу чтения список вопросов и возражений «автору»). Это хотя бы минимум уважения к читающим.
Кроме того, на момент, когда я сделал замечание, в избранное добавило всего пять человек и мой коммент был третьим по счету, была возможность спокойно сделать все по правилам. Ты же просто забил.
Список вопросов и возражений — это именно то, чего я добивался выкладывая этот перевод.

Утверждение об уважении к читателям оставлю на вашей совести.
Как раз таки уважение к читателям осталось на твоей совести )
Если не видишь проблемы — ок, дело твое.
А надуманная фраза — на вашей.
А надуманность надуманности — на твоей.
Я выиграл!
Ок, пусть будет так.
Зато перевод на редкость хорош. Я уже ближе к середине текста всерьез заметил признаки перевода, хотя на Хабре очень часто даже оригинальные тексты читать невозможно.
здесь должна быть шутка про обречённость любого языка, содержащего colon-equals assignment :)
Colon-equals assignment приводит к появлению ошибок при опечатках в операторах «==», «!=», «+=», «-=», «*=», «/=», «.=», «%=», «&=», «|=», «^=», «=>», «>=», «<=», и тем экономит нервы программиста, не принуждая его прибегать к долгой, мучительной, нравственно тягостной отладке.

Поэтому обречённость этого оператора свидетельствует о том, что мы обречены существовать в мире техносадомазохистов, действующих по правилу «я мучительно потрахался — теперь и ты, и ты поди мучительно потрахайся».
о каких конкретнее опечатках вы говорите?
int a = 3;
int b = 15;

if (a = b)
puts(«внезапно»);
имхо, конечно, но ошибка с пропущенным равно в '==' довольно натянута. после 1-2 таких опечаток, они обычно начинают сами бросаться в глаза. а если такая даже случайно допущена, то в большинстве случаев мысль проверить сравнение приходит в голову одной из первых.

если цепляться к опечаткам, то к примеру написать x := y вместо x >=y имеет такую же вероятность.
Нормальный компилятор не пропустит такую опечатку.
Поэтому приходится, если нужно в if для сокращения написать что-то вроде if(a=b), писать if((a=b)).
Это и спасает.
А вообще пора бросать экономить строчки.
Эти ошибки возникают только в условиях. Поэтому проблема не в том, что присваивание записывается как "=", без двоеточия, а в том, что результат присваивания может неявно приводиться к типу boolean. К примеру, в Java и C# этого нет, и никто не ошибается в написании условий.
Говоря еще точнее, эта ошибка прявляется там, где присваивание есть выражение (и возвращает значение). То, что оно кастуется к булеану — это даже хорошо :)
:= в мейке значит — вычислить то, что присваивается переменной, прямо сейчас. Есть и просто '=' — тогда присвоенное (например, функция) будет вычисляться позже.
Неожиданный вопрос: автор слышал про autoconf/automake?
Писать руками Makefiles — это Свежая и Оригинальная Идея (tm).
Я, возможно, слишком радикальных взглядов придерживаюсь, но autoconf/automake — это такой большой набор хрупких костылей, после которого make кажется образцом простоты и удобства. Спасибо, задействовать их, чтобы makefile'ы генерировать — это добавить к проекту ещё одну проблему.
я думаю вы просто не разобрались с автотулзами, да это костыли, но вопервых вполне рабочие что подтверждается практикой многих открытых продуктов, во-вторых создание рукотворных мейкфайлов как правило означает, что на платформе отличной от той под которую писал автор, будут будут проблемы со сборой. Неоднократно убеждался в этом эмпирическом правиле…
И да имхо порог вхождения в autotools + make достаточно высок.
Рабочие они только там, где их тестируют. А вот стоит скомпилировать gdb на mingw64 и оказывается, что какая-то из автотулзов считает, что для компиляции маленькой вспомогательной программы можно использовать просто gcc, ведь он же есть на любой платформе. А то, что надо использовать x86_64-w64-mingw32-gcc, как указано в configure верхнего уровня, авторов волнует мало. В результате из-за какой-то ненужной документации к bfd не собирается gdb.
а если бы мэйкфайл gcc написали бы руками то конечно был бы рай, да?
Нет, просто автотулзы тоже не помогают в самом интересном для меня случае — cygwin/mingw.
я бы сказал что «автотулзы тоже не всегда помогают»…
Вот из последнего, к примеру — wiki.buici.com/xwiki/bin/view/Programing+C+and+C%2B%2B/Autoconf+and+RPL_MALLOC
Берём проект, который использует autotools (который как бы декларирует, что будет компилироваться для любых платформ), компилируем для ARM'а — получаем ошибки. Особенно доставляет её описание.
Ну да, а C — это такой хрупкий костыль вокруг ассемблера, который вообще похож на вывод из /dev/random (кстати, хорошая тема для статьи).
Всё в этом мире — костыль!
А у костылей бывают костыли?
C — это такой хрупкий костыль вокруг ассемблера, который вообще похож на вывод из /dev/random
— спасибо, супер!
UFO just landed and posted this here
autoconf/automake — ужасная штука. Ей только по историческим причинам и ради переносимости приходится пользоваться.

Каждый раз, когда я какого-нибудь апача собираю, и эта простыня ./configure тянется по полчаса, и для каждой из библиотек Апача (apr, apr-utils) перезапускается заново, и если ошибся в настройках компилятора, и make упал, то надо ее снова запускать и ждать полчаса — полдня на это может уйти.
К счастью, постепенно народ с глючных тормозных autotools переходит на cmake.
попробуйте кеширование в configure использовать, не будет так долго второй раз проверять библиотеки.
он использует кеширование, но как-то безсистемно (часть проверок кешируется, но большАя часть — нет), и даже с кешированием долго работает…
«Бессистемно»…
да я тоже сижу бывает с лицом страдальца когда что то бисекчу… пересобирать приходится помногу…
You have a problem and decide to use make.
Now you know how to make problems.

You have a problem and decide to use autotools.
Now you know how to make problems automatically.
Статья очень спорная на самом деле.
Начиная с фактических ошибок (mkdir -p <existing-dir-name> завершается успешно).
Заканчивая полным непониманием «миссии» make.

Make решает одну единственную задачу — по спецификации цели/зависимости/правила генерации найти отсутствующие или устаревшие цели и собрать их. Просто и примитивно, воплощенный UNIX way.

Это не проблема make, что для сборки среднего проекта, его возможностей недостаточно.

Зато Makefile — замечательный промежуточный формат для генераторов вроде autotools/cmake. И все довольны — билд-инжинер, потому что огромную кучу вспомогательного кода в мэйкфайле за него написал генератор; автор генератора — потому что сканирование зависимостей, сортировку задач и распараллеливание он переложил на make.

Кстати возможно решение с таймстемпами на файловой системе и не лишено недостатков, но по-сути — оно единственное. Тот же git например при поиске измененных файлов сначала смотрит на таймстемпы, и если таймстеп не изменился, то внутрь файла он даже не заглядывает.
Каждый, кто хоть раз писал makefile, скорее всего уже натолкнулся на “особенность” его синтаксиса: в нём используются табуляции. Каждая строка, описывающая запуск команды, должна начинаться с символа табуляции. Пробелы не подходят — только табуляция. К сожалению, это только один из странных аспектов языка make’а.


В книге Masterminds of programming кто-то (по-моему, Керниган) рассказывал историю: когда make только-только написали, он стал как-то использоваться и понемногу разошёлся по организации (Bell Labs).
И кто-то из «новых» пользователей обратил внимание на эту странную штуку с табами — why tabs? На что Feldman, автор этой новой утилиты, ответил, что пользователь конечно прав, и что с табами он плохо подумал, но менять это не будет, потому что это поломает обратную совместимость, а это делать нельзя, ведь у make уже 12 пользователей.

такой подход к обратной совместимости многое объясняет. фактически, он отвечает сразу по всем пунктам этой статьи.
facepalm.tar.gz

Целых 12… Порой программисты слишком заботливы в отношении пользователей: то добавляют ненужные фичи, то (как здесь) не добавляют нужные. Всё больше убеждаюсь в том, что в каждом программисте должна быть частичка менеджера. Но только частичка, а не ядро U-239.
Интересно, спросил он у этих 12-ти пользователей их мнения? А то ведь могло быть и так, что им табы тоже не нужны.
Пробелы бы вроде не поломали бы совместимость, альтернатива табам как а питоне
UFO just landed and posted this here
Пользуюсь make, ругаюсь, но пользуюсь. Удивился, когда узнал что он не умеет делать математические операции (напр., если версия меньше чем что-то, то сделать что-то особое).

Очень надеялся, что наберет популярность такая система сборки как ninja (с ее помощью хромиум собирается). martine.github.com/ninja/ Замысел хороший, нацелена на простоту и скорость, легкий синтаксис, минимум возможностей. Т.е. ninja только собирает, а всей конфигурацией должна заниматься отдельный генератор типа configure.

Жаль, кажется не взлетела.
С ниндзей лень возиться просто. Сделал бы там чувак хотя бы базовые фичи какие-то (ну там хотя бы паттерны для имëн переменных, подобные штуки) — тогда да, а так — оно имеет смысл только для больших проектов, когда мейк тормозит.
Кстати, по поводу странностей ситнтаксиса, парсинга и интерпретации мейкфайлов — все то же самое справедливо и для Bash. Недавно статью прочитал — долго удивлялся: www.aosabook.org/en/bash.html
Кому не нравится, всегда может использовать аналоги, а также питон и прочие яп
Последний пункт не совсем верен, тк в make есть order-only prerequisites, которые не будут вызывать перекомпиляцию
debug/%.o: %.c | debug
$(CC) -c $< -o $@
debug:
mkdir $@
Спасибо, интересно.
Хотел сказать то же самое. Странно что автор не знал этого
Я в своём Leaflet сейчас использую jake — аналог rake под node.js. Очень просто, удобно, и к тому же приятно описывать билд-скрипты и зависимости для JS-проекта на JS же, без лишних сторонних языков.
Уже давно для своих проектов использую rake — весьма неплохая альтернатива make, лишенная перечисленных выше недостатков. К тому же, если возможностей Rake DSL не хватает, всегда можно локально перейти на обычный ruby — и все это бесшовно. Жаль только, что за пределами мира RoR rake малоизвестен. Фактически rake — это такой "'make' done right". Не больше, но и не меньше.
Sign up to leave a comment.

Articles