Gnu Makefile - Обработка зависимостей - PullRequest
12 голосов
/ 01 октября 2009

Какой подход используют программисты C ++ на платформе Unix для создания и управления файлами Makefile?

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

Но я столкнулся с проблемой здесь, в команде sed -

    sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
        -e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \

Проблема в третьем выражении "-e 's / * \ $$ //'. Не работает Предполагается, что для удаления обратной косой черты. Я понимаю, что там должен быть двойной доллар, так как это часть Makefile. Может кто-нибудь сказать мне, что здесь не так?

Вот полный Makefile -

CC=g++
CFLAGS=-g -Wall
LIBS=-lpthread

OBJS=file1.o file2.o
TARGET=testProg

$(TARGET) : $(OBJS)
        $(CC) -o $@ $^ $(CFLAGS) $(LIBS)

%.o : %.cpp
        $(CC) -MMD -c -o $@ $< $(CFLAGS)
        @cp $*.d $*.P; \
            sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
                -e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
            rm -f $*.d

-include $(OBJS:%.o=%.P)

clean :
        rm -f $(TARGET) $(OBJS)

all : $(TARGET)

Помимо решения этой проблемы, я также хотел бы дать несколько советов / указателей на мой 1-й вопрос.

Ответы [ 12 ]

25 голосов
/ 02 октября 2009

gcc / g ++ может генерировать зависимости для вас с помощью семейства опций -M. Следующее работает, определяя, как генерировать .depends файлы с учетом исходного файла. При этом -include $(DEPS) $ (DEPS) распознается как цель и будет построен / перестроен при изменении исходных файлов.

CXX      = g++
CXXFLAGS = -Wall -O3
LDFLAGS  =

TARGET = testcpp
SRCS   = main.cc x.cc foo.cc
OBJS   = $(SRCS:.cc=.o)
DEPS   = $(SRCS:.cc=.depends)


.PHONY: clean all

all: $(TARGET)

$(TARGET): $(OBJS)
        $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $(TARGET)

.cc.o:
        $(CXX) $(CXXFLAGS) -c $< -o $@

%.depends: %.cc
        $(CXX) -M $(CXXFLAGS) $< > $@

clean:
        rm -f $(OBJS) $(DEPS) $(TARGET)

-include $(DEPS)
8 голосов
/ 01 октября 2009
  1. Я использую этот подход и не могу похвалить его достаточно высоко. И я пишу свои make-файлы вручную и многократно использую их в новых проектах.
  2. . Выражение "s / * \\ $ //" будет работать вне контекста Make. В make-файле это не работает, потому что Make пытается интерпретировать «$ /» перед передачей результата в оболочку. Таким образом, вы должны использовать «s / * \\ $$ //» (обратите внимание на дополнительный $) внутри make-файла, но это не будет работать вне контекста Make (так что тестирование - это небольшая боль ).



EDIT:

Я пробовал твой make-файл, и это утверждение sed, похоже, прекрасно удаляет завершающие обратные слеши. Попробуйте что-нибудь попроще, например так:

backslash:
    @echo " \\" > $@

test: backslash
    @echo without sed:
    @cat backslash
    @echo with sed:
    @sed -e 's/ *\\$$//' &lt backslash



EDIT: Хорошо, теперь я подсел. Не могли бы вы попробовать эти эксперименты и сообщить нам результаты?

Change the last character to 'z'      :  s/.$/z/
Change a trailing backslash to 'z'    :  s/\\$/z/
Change a trailing backslash to 'z'    :  sm\\$mzm
Delete a trailing backslash           :  s/\\$//
Delete spaces and a trailing backslash:  s/ *\\$//
Try all of these inside and outside of Make, with '$' and '$$'.
3 голосов
/ 01 октября 2009

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

Учебник BSD по make Примечание: вы можете автоматически генерировать информацию о зависимости заголовка с помощью ключа -MM GCC.

2 голосов
/ 01 октября 2009

Я должен что-то упустить. Почему генерация файлов зависимостей не работает для вас?

1 голос
/ 01 октября 2009

В системе сборки Mozilla мы используем ключ -MD GCC для генерации файлов зависимостей: http://mxr.mozilla.org/mozilla-central/source/configure.in#7134 а затем мы используем скрипт с именем mddepend.pl для проверки удаленных заголовочных файлов, например удаление заголовка просто вызывает перестроение, а не ошибку: http://mxr.mozilla.org/mozilla-central/source/config/rules.mk#2066 http://mxr.mozilla.org/mozilla-central/source/build/unix/mddepend.pl

Этот скрипт генерирует файл .all.pp, содержащий все зависимости, с дополнительными foo.o: FORCE зависимостями, вставленными для отсутствующих заголовочных файлов. Затем мы просто включаем файл .all.pp в rules.mk прямо там.

1 голос
/ 01 октября 2009

Утилита makedepend установлена ​​во многих системах и может быть весьма полезна для генерации информации о зависимостях.

Вот пример Makefile, который использует директиву include (плюс немного магии Perl) для включения вывода makedepend:

# the name of the executable that we'll build
TARGET = foo_prog
# our .cc source files
SRCS = foo.cc main.cc

# the .o versions of our source files
OBJS := $(patsubst %.cc, %.o, $(filter %.cc, $(SRCS)))
# some flags for compiling
CXXFLAGS = -Wall -Werror

# In order to build $(TARGET), we first build each of the $(OBJS).
# Then we use the given command to link those $(OBJS) into our
# $(TARGET) executable.  $^ is a shortcut for $(OBJS).  $@ is a
# shortcut for $(TARGET).
#
# The default compile rule will compile each of the $(OBJS) for us.
$(TARGET): $(OBJS)
        $(CXX) $(CXXFLAGS) $^ -o $@

# Use "make clean" to remove all of the support files.
clean:
        rm -f $(OBJS) $(TARGET) Makefile.depend *~

# This automatically uses the 'makedepend' utility to add any
# dependencies that our source files have, namely .h files.  This way,
# if the .h files change, the code will be re-compiled.
include Makefile.depend
Makefile.depend: $(SRCS)
        makedepend -f- -Y $(SRCS) 2> /dev/null | \
        perl -p -e "s/(^.*?:)/Makefile.depend \1/" > Makefile.depend

Если foo.cc и main.cc зависят от foo.h, то содержимое Makefile.depend будет:

Makefile.depend foo.o: foo.h
Makefile.depend main.o: foo.h

Конечным результатом является то, что информация о зависимостях из makedepend внедряется в Makefile как последовательность правил. Это похоже на подход использования файла .d для каждого .cc файла , но информация о зависимостях хранится в одном файле, а не разбросана повсюду.

1 голос
/ 01 октября 2009

Я предпочитаю использовать CMake, хотя это не совсем решение вашей проблемы.

Это язык описания проекта, который сгенерирует ваши Makefiles, Visual Studio Project, Eclipse Project, KDevelop и т. Д. Все зависимости сделаны для вас:

CMakeLists.txt

add_executable(my_exe file1.c file2.c)
target_link_libraries(my_exe my_library)
add_subdirectory(lib)

В lib / CMakeLists.txt

add_library(my_library file3.c file4.c)

Это создает файл my_exe из file1.c file2.c, связанный с my_library. Я нахожу это намного проще. Также есть такие вещи, как обнаружение пакетов:

find_package(Qt4)
0 голосов
/ 30 марта 2017

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

file.d file.o : file.c header.h header2.h ...

Таким образом, make восстановит зависимости, если изменится источник или любой из заголовков. Включение фальшивых целей для заголовков (GCC -MP) должно затем позволить стабильные сборки при удалении заголовков - отсутствие требуемого заголовка остается ошибкой компиляции, а не ошибкой зависимости.

Предполагая, что файлы зависимостей создаются в том же каталоге, что и объектные файлы, для GCC в Unix должно работать следующее:

-include $(OBJ:.o=.d)

$(OBJDIR)/%d : $(SRCDIR)/%.cpp
        mkdir -p $(@D)
        echo -n "$@ " > $@.tmp
        $(CXX) $(CPPFLAGS) -MM -MP -MT $(@:.d=.o) $< >> $@.tmp
        mv $@.tmp $@

(из памяти)

0 голосов
/ 22 июля 2013

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

0 голосов
/ 02 октября 2010

Вместо сценариев sed используйте опцию -cc для gcc, чтобы изменить цель сгенерированных правил зависимости. Это сообщение в блоге содержит больше информации.

...