make

Материал из Xgu.ru

Перейти к: навигация, поиск
stub.png
Данная страница находится в разработке.
Эта страница ещё не закончена. Информация, представленная здесь, может оказаться неполной или неверной.

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


make — программа, которая используется для автоматизации сборки проекта. Отслеживает взаимосвязь между зависимостями в проекте, и принимает решение о пересборке, на основе связей между зависимостями и состояние зависимостей.

Содержание

[править] Вопросы и ответы

[править] Я хочу немного разобраться в том, что такое make/gmake/bmake, зачем они нужны и в чём разница между ними

на вопрос отвечает Алексей Чеусов
 >> > А что ты мне порекомендуешь прочитать,
 >> > чтобы вообще въехать в проблему как таковую?

 >> Да просто посмотри примеры, прикинь, справляется ли инструмент с задачами,
 >> которые возникают у тебя лично. Что ты там используешь? autoconf? cmake?
 >> голые Makefile-ы?

> Я использую голые Makefil'ы в тех небольших проектах,
> где мне они вообще нужны. А поскольку больше всего, 
> что я пишу, я пишу на perl/python, то я с autoconf вообще
> не сталкиваюсь.

Как я уже говорил на LVEE, стрелял бы писателей "самобытных" Makefile-в :-)
Столько проблем от них... В общем, если не использовать никакой
"стандартный" инструмент для сборки и установки, и писать все с нуля самому,
существует очень большой риск нарушить правила написания Makefile-ов,
которые вроде как существуют десятки лет, но которым люди в эпоху всеобщей
линуксоидизации перестают следовать почему-то.
Почему -- не понятно, видимо просто от незнания.

Ну, например, банальные факты. Переменные Makefile-ов принимают значения
по умолчания из окружения. Это раз. Два - Все присваивания переменной
VAR в Makefile-е отменяются при вызове
  'make -f Makefile VAR=myvalue'.
Три - нет ничего хуже, чем заставлять пользователя изменять
предоставленный ему Makefile. Должна быть возможность установить все,
что угодно, снаружи.
Не всегда очевидные, но тем не менее, выводы:
- нельзя писать
  CFLAGS = -my -local -opts -and -optimization -flags

  Необходимо разнести флаги оптимизации и опции, локальные для сборки
  проекта, например -I. -Isubdir. Лучше было бы написать

  EXTRA_CFLAGS  = -O2 -Wall -Werror
  CFLAGS       += ${EXTRA_CFLAGS} -I. -Isubdir

  В этом случае пользователь может легко снести gcc-specific флаги
  запустив make all EXTRA_CFLAGS='-O0 -g'

- Желательно, предоставить возможность установить параметры сборки через
  окружение, а не через "make target VAR=value" (hint: ?= вместо =)

  EXTRA_CFLAGS ?= -O2 -Wall -Werror
  CFLAGS       += ${EXTRA_CFLAGS} -I. -Isubdir

  Сейчас можно запустить
    EXTRA_CFLAGS='-O0 -g' make all

- Категорически нежелательно писать 
  LDFLAGS += -Lreadline-subdir -Lanotherdir
  LIBS    += -lreadline -lanother-lib
  ...

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

  LIBDIR_READLINE ?= -Lreadline-subdir
  LIB_READLINE    ?= -lreadline
  LIBDIR_ANOTHER  ?= -Lanotherdir
  LIB_ANOTHER     ?= -lanother-lib

  LDFLAGS         += ${LIBDIR_READLINE} ${LIBDIR_AMOTHER}
  LIBS            += ${LIB_READLINE} ${LIB_ANOTHER}

  Это полезно, например, для сборки проекта с системными библиотеками
  типа readline и всякими iconv, которые пионеры любят совать в дерево
  проектов (bash и readline).

- Значения переменным типа LDFLAGS, LIBS, CFLAGS и т.п. лучше вообще никогда
  не присваивать значения с помощью =. Всегда лучше использовать +=.
  Это дает возможность сборки с пользовательскими настройками по
  умолчанию, например на Interix-е можно прописать
    export CPPFLAGS=-D_ALL_SOURCE
  прямо в профайле пользователя.

- Не придумывайте свои переменные. Используйте "стандартные"
  CFLAGS, CPPFLAGS, LDFLAGS, LDADD/LIBS/LDLIBS, COPTS etc.

- Нельзя писать 
   test: test.c
     gcc -o test test.c

   Такой способ
     a) работает только с gcc и не позволяет его легко заменить на
        нужный пользователю компилятор.
     b) не допускает указания доп. -I для компилятора
     c) не допускает указания опций оптимизации
     d) не допускает указания опций включения предупреждений компилятора
        и проч.
     e) Не позволяет добавить доп. библиотеку/каталог/опции для линковки.
        Есть разные "смешные" платформы типа Solaris-а,
        на которых стандартные функции
        находятся не в libc, а в libsocket. В то же время dlopen(3)
        под Линупсом находится в libdl, а в BSD  - в libc. И туча других
        примеров несовместимостей, например c libcompat из NetBSD
        и прочими.

   Всегда лучше писать
     CC ?= cc
     test: test.c
        ${CC} ${CPPFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $< ${LDADD}

   или (POSIX make)

     CC ?= cc
     .c:
        ${CC} ${CPPFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $< ${LDADD}

   или (GNU make, smake, ...)

     CC ?= cc
     %: %.c
        ${CC} ${CPPFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $< ${LDADD}

Ну и так далее. Много выводов можно сделать.
Уже на этом этапе куче писателей нужно было бы поставить единицу, даже
не два балла. Ну а про всякие там "стандартные" DESTDIR, PREFIX и
прочее я уж молчу. Это вообще запредельные знания.

В общем, этим всем призван заниматься automake.
Но уж больно через ... (через кодогенерацию) он это делает...

> Я на Си практически ничего не пишу, за исключением маленьких
> маленьких кусочков, которые мне нужно сделать для
> повышения производительности, и там я их собираю
> через обычный make, без всяких наворотов.
См. выше. Или покажи, я раскритикую :-)
Может, что полезное извлечешь. Поругаться я люблю :-)

> Я понимаю, что вообще надо разобраться с autoconf/autotools
> и вообще сборочным процессом.
Не дури себе голову этим [злом]. Лучше поищи альтернативу.
Нет, не обязательно mk-configure :-) И они есть в наличии.
Хотя адекватную замену libtool найти непросто,
autoconf и automake однозначно в топку.

> Я занимаюсь в фоновом режиме этим, сам видишь, с какой
> периодичностью отвечаю, но у меня ещё тогда летом появилась идея
> (своя погремушка), в которой очень классно было бы использовать
> make, и вот теперь я думаю, что надо с этим разобраться получше.

> Вот первая отправная точка, с которой можно было бы начать:
> http://catb.org/~esr/writings/taoup/html/ch15s04.html#id2987644
Неплохая точка, но autoconf+automake - морально устаревшая давно
прогнившая связка. То же относится и к imake.
makedepend (или mkdep) - это одна из тех вещей, которые обычно делаются
автоматом. По крайней мере в "современных" make-о-заменителях.
в BSD - 'make depend' либо автоматом в зависимости от
использующихся mk-files.

[править] У меня в Makefile несколько раз повторно используется один и тот же очень похожий код. Куда копать?

Для GNU Make копать в сторону eval/call. Например, так [1]:

     PROGRAMS    = server client
     
     server_OBJS = server.o server_priv.o server_access.o
     server_LIBS = priv protocol
     
     client_OBJS = client.o client_api.o client_mem.o
     client_LIBS = protocol
     
     # Everything after this is generic
     
     .PHONY: all
     all: $(PROGRAMS)
     
     define PROGRAM_template
     $(1): $$($(1)_OBJS) $$($(1)_LIBS:%=-l%)
     ALL_OBJS   += $$($(1)_OBJS)
     endef
     
     $(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog))))
     
     $(PROGRAMS):
             $(LINK.o) $^ $(LDLIBS) -o $@
     
     clean:
             rm -f $(ALL_OBJS) $(PROGRAMS)

<<GNU make-овская конструкция foreach/eval/call -- настоящее уродство, если ты о примере из 8.8 (-- а я как раз о нём, он выше, -- прим. автора), то в bmake это делается на порядок проще, нагляднее и короче>>(С)Чеусов. Аналогичная функциональность в bmake (как и в других BSD make-ах) реализуется следующим образом.

    PROGRAMS    = server client

    server_OBJS = server.o server_priv.o server_access.o
    server_LIBS = priv protocol

    client_OBJS = client.o client_api.o client_mem.o
    client_LIBS = protocol

    # Everything after this is generic
    .PHONY: all
    all: ${PROGRAMS}

    .for p in ${PROGRAMS}
    ALL_OBJS   += ${${p}_OBJS}
    ${p}:
            $(LD) ${${p}_OBJS} ${${p}_LIBS:S/^/-l/} -o $@
    .endfor # p

    clean:
	    rm -f $(ALL_OBJS) $(PROGRAMS)

Хотя на bmake так никто не пишет, для подобных задач есть гораздо более адекватные средства.

[править] Как разделить вывод разных ветвей исполнения при параллельном исполнение (-j) в GNU Make?

опция командной строки "--output-sync" в GNU Make 4.0

[править] Почему make это плохо?

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

Подробнее:

[править] Дополнительная информация

  • make: Automating Your Recipes(англ.) — глава из книги The Art of Unix Programming, посвящённая make. Может рассматриваться как хорошее введение в тему


[править] Компиляция, линковка, сборка

Источник — «http://xgu.ru:81/wiki/make»