Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
TARGET = hello
PREFIX = /usr/local/bin
SRCS = main.c hello.c
OBJS = $(SRCS:.c=.o)
.PHONY: all clean install uninstall
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) -o $(TARGET) $(OBJS) $(CFLAGS)
.c.o:
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -rf $(TARGET) $(OBJS)
install:
install $(TARGET) $(PREFIX)
uninstall:
rm -rf $(PREFIX)/$(TARGET)
.c.o:
$(CC) $(CFLAGS) -c $< -o $@
make -p, там очень много полезного. Переменная CC по умолчанию содержит имя C компилятора (т.е. на Linux это gcc, также есть и CXX и другие). CFLAGS по умолчанию пустой, но используется вот так:$ CFLAGS=-g make
$ CFLAGS=-O2 make
.c.o указывает, каким образом из .c файлов получить .o файлы. SOMETHING_TEST_ROOT := $(dir $(lastword $(MAKEFILE_LIST)))
empty = space = $(empty) $(empty)
make CFLAGS=-g
make CFLAGS=-O2
TARGET = hello
PREFIX ?= /usr/local
SRCS = main.c hello.c
OBJS = $(SRCS:.c=.o)
.PHONY: all clean install uninstall
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) -o $(TARGET) $(OBJS) $(CFLAGS)
.c.o:
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -rf $(TARGET) $(OBJS)
install:
install $(TARGET) $(PREFIX)/bin
uninstall:
rm -rf $(PREFIX)/bin/$(TARGET)
make — это конечно хорошо… было на каком-то этапе эволюции. Советую обратить внимание на cmake — универсальность2.SRCS = index.md page1.md page2.md
HTMLS = $(SRCS:.md=.html)
.PHONY: all clean install uninstall
all: $(HTMLS)
%.html: %.md
markdown < $^ > $@
make набранные в лилипонде ноты компилирую, смотрю, слушаю и архивирую:SRC = a4.ly tenor1.ly tenor2.ly bass1.ly bass2.ly lyrics.ly header.ly ../lib/paper.ly
RESULT = a4.pdf all.midi
DIRNAME = $(realpath .)
.PHONY: preview publish archive dist play view help
preview pre view $(RESULT): $(SRC)
lilypond a4.ly
mv -f a4.midi all.midi
see a4.pdf &
publish pub a4.publish.pdf: $(SRC)
lilypond -dno-point-and-click -o a4.publish a4.ly
mv -f a4.publish.midi all.midi
dist: $(SRC) a4.publish.pdf
7z a -tzip -mx=9 $(DIRNAME).zip $(SRC) a4.publish.pdf all.midi Makefile
clean:
rm -f *~ $(RESULT) a4.publish.pdf a4.ps a4.publish.ps
play: all.midi
timidity all.midi
help:
@echo Available goals:
@echo ' preview - create and show PDF preview with debug info, make MIDI file'
@echo ' publish - create final PDF file without debug info, make MIDI file'
@echo ' play - play MIDI file'
@echo ' dist - create archive with sources and result'
@echo ' clean - delete result and backup files'
@echo ' help - show this message'
Make удобно использовать с graphviz для генерации документации.
cmake скриптов легче, сами скрипты проще для понимания (естественно есть какой-то порог вхождения для любой технологии).cmake:cmake_minimum_required(VERSION 2.8)
set(TARGET "hello")
add_executable(${TARGET} hello.c main.c)
Альтернатива make -это ninjia.
Для его компиляции достаточно очень простого мэйкфайла:
hello: main.c gcc -o hello main.c
all: main
CC=clang makemake -dp --warn-undefined-variables | lessВо-первых, рекомендация про хороший стиль перестают работать.
Во-вторых, там объективная необходимость в переменных, ибо кроссплатформенность и различные настройки и прочее.
В-третьих, в большом проекте может быть много подпроектов, в которых свои мейкфайлы, которые включаются в главный.
В-четвёртых, в большом проекте вся выдача подавлена — ибо по дефолту выдача нужна только если какие-то ворнинги/ошибки (и это правильно), поэтому отсутствие ключика --всё-равно-всё-печатать-и-не-волнует расстраивает при необходимости копнуть глубже.
define RUN
ifeq ($(VERBOSE),y)
echo $(2);
$(2);
else
echo $(1);
$(2);
endif
$(TARGET):
$(call RUN, "CC $@", $(CC) $(CFLAGS) $(OBJS) -o $@ $(LDFLAGS))
Прошу не принимать это как оскорбление, но вы идеалист-теоретик :)
Смысла в переменных, когда у них одно определение, нет никакого, ибо это не переменные, а константы. Например, при сборке на определённой ОС, определённой версии с определённой библиотекой, добавлять к ключам компиляции такой-то флажок, а с другой библиотекой, другой флажёк и так стопицот раз. Предлагаете каждый флажёк в отдельную переменную пихать, а потом всё слить воедино? А как же тогда стиль? Там не на один экран таких переменных набежит плотным текстом. Поэтому «CFLAGS +=», а вот откуда что пришло уже не так понятно.
Про вербоз своими силами — в вашем случае и --dry-run отлично подойдёт. В реальности там будет ещё несколько генераторов генераторов, запуск этих генераторов, несколько кастомных правил, которые делают разные манипуляуции с выдачей генераторов. Генерация и обратобка зависимостей опять же. И разные файлы с разными ключами собираются, конечно же. Ну, то есть всё под одну гребёнку крайне сложно.
И, заметьте, это всё при нормальном код ревью и поставленных процессах. Ибо без них вообще адъ, мрак и средневековье. Я по долгу службы на всякое насмотрелся. Действительно большие проекты всегда живут своей жизнью.
Поэтому вместо изобретения велосипедов проще взять remake.
Это вы — любитель грязных решений. Я переписал сборку проекта из миллиона строк и тоже знаю, о чём речь.
Наличие генераторов генераторов генераторов просто не лучшим образом говорит об архитектуре системы сборки.
В remake всё, что добавлено — отладчик. Это, конечно, позволит попроще жить в уже существующей дерьмовой инфраструктуре, но первопричина в том, что инфраструктура дерьмовая, а не в том, что отлаживаться тяжело. Писать надо так, чтобы отлаживаться не приходилось.
PROG = hello
SRCS = main.c hello.c
.include <mkc.mk>set(sources main.c hello.c)
add_executable(hello ${sources})
make maingcc main.c#!/usr/local/bin/tcc -run, то можно и без gcc:./main.cSRC=$(wildcard *.c)
cmake?cmake_minimum_required(VERSION 2.8)
file(GLOB_RECURSE sample_SRC ./ "*.cpp")
add_executable(helloworld ${sample_SRC})
НЕ происходит
пример простого шелл-скрипта можно привести?
#!/bin/bash
project=hobo
outdir=build
sources=`find -name '*.cpp'`
incdirs=`ls -d */ | grep -v "${outdir}/" | sed 's/^/-I/'`
mkdir -p ${outdir}
for src in $sources; do
obj=${outdir}/${src}.o
mkdir -p `dirname $obj`
if [ ! -f "$obj" -o "$src" -nt "$obj" ]; then
echo Compiling $src into $obj
g++ ${incdirs} -c "$src" -o "$obj"
fi
done
echo Linking ${project}
g++ ${incdirs} `find ${outdir} -name '*.o'` -o ${outdir}/${project}
знаете, как в моем makefile-е обработать изменения в заголовочных файлах
я его просто удаляю сейчас, когда меняю что-то в header-е
Вдобавок, у Вас отсутствует target clean
использование зависимостей конкретного файла исходного кода это НЕ задача GNU make
в пользу by-design решений
отнюдь не хаками — просто надо читать документацию
в так любимых Вами генераторах генераторов генераторов Makefile
Если Вы претендуете на профессионализм, то хотя-бы удосужьтесь проверить самостоятельно то, что пишете
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $(df).d >> $(df).P;
Единственный способ корректной сборки без знания детальных зависимостей — каждый раз пересобирать всё с нуля.
мне на практике более удобно иметь объектник в той-же директории — я его просто удаляю сейчас, когда меняю что-то в header-е
Смешно, что никто не смог ответить на мой, достаточно элементарный вопрос
в модули которых включается изменённыйобъектныйзаголовочный файл. Если
ещё хучже
приведите «хаки с седом» в моей последней версии?
топики SO
народ просто _не умеет_ им пользоваться
Правильный ответ был-бы — «не знаю»
Потрудитесь объяснить, в чем заключается «весьма специфическое поведение make»?
Для ее поддержки make сопоставляет время изменения целей и их реквизитов (используя данные файловой системы), благодаря чему самостоятельно решает какие правила следует выполнить, а какие можно просто проигнорировать:
Можно ли как- то в make скриптах сделать прeпроцессор?
Чтобы не писать много одинакового кода на Make.
Только тех, кто умеет пользоваться makefile и можно считать настоящими программистами.
Те кто не умеет читать писать makefile(лы) - это шко-ло-та.
Для использования значения переменной ее следует разименовать при помощи конструкции
Правильно пишется разыменовать, а не разименовать
Просто о make