Почему этот make-файл всегда выполняет рецепт $ (LIB)? - PullRequest
0 голосов
/ 22 декабря 2018

Я изучаю / укрепляю мое понимание make-файлов, написав простой проект на основе makefile с нуля.

Дерево моего проекта структурировано следующим образом:

.
│   makefile
│
├───dep
├───exe
├───include
│       b.h
│       c.h
│
├───lib
├───obj
└───src
        a.cpp
        b.cpp
        c.cpp

Итак, мое намерение /цели:

  1. Иметь один make-файл в корне проекта

  2. Иметь исходники, заголовки, объектные файлы, библиотеки, зависимые файлы и исполняемые файлы каждыйв своем собственном подкаталоге корневого каталога проекта.

  3. Ровно один исходный файл в src/ будет содержать int main(...).

  4. Makefile долженскомпилировать все исходники, кроме того, который реализует int main(...) для объектных файлов в obj/.

  5. Makefile должен архивировать все объектные файлы в lib в lib/

  6. Makefile должен скомпилировать исходный файл, который реализует int main(...) прямо в исполняемый файл в exe/, путем ссылки на созданную библиотеку.

Я думаю, что 'мы достигли того, что я хочу с этим make-файлом:

SRCDIR = ./src
INCDIR = ./include
OBJDIR = ./obj
LIBDIR = ./lib
EXEDIR = ./exe
DEPDIR = ./dep

EXE = foo
EXESRC = $(SRCDIR)/a.cpp

DEP = $(DEPDIR)/$(EXE).dep

CXX = g++
CXXFLAGS = -g
AR = ar

# List of *.cpp in $(SRCDIR) that are not $(EXE)
LIBSRC = $(filter-out $(EXESRC),$(wildcard $(SRCDIR)/*.cpp))

# Replace {$(SRCDIR)/a.cpp $(SRCDIR)/b.cpp} w/ {$(OBJDIR)/a.o $(OBJDIR)/b.o} etc
OBJS = $(patsubst %.cpp,%.o,$(patsubst $(SRCDIR)%,$(OBJDIR)%,$(LIBSRC)))

LIB = $(LIBDIR)/lib$(EXE).a

bin: $(EXEDIR)/$(EXE)

$(EXEDIR)/$(EXE): $(EXEDIR) $(EXESRC) $(LIB)
        $(CXX) -o $(EXEDIR)/$(EXE) $(CXXFLAGS) -I$(INCDIR) $(EXESRC) -L$(LIBDIR) -l$(EXE)

$(LIB): $(OBJDIR) $(OBJS) $(LIBDIR)
        $(AR) ur $(LIB) $(OBJS)

$(EXEDIR):
        mkdir $(EXEDIR)

$(LIBDIR):
        mkdir $(LIBDIR)

$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(DEP)
        $(CXX) $(CXXFLAGS) -I$(INCDIR) -o $@ -c $<

$(OBJDIR):
        mkdir $(OBJDIR)

$(DEP): $(DEPDIR)
        makedepend -- $(CXXFLAGS) -I$(INCDIR) -- $(LIBSRC) $(EXESRC) -f- 2>/dev/null > $(DEP)
        sed -i 's,$(SRCDIR),$(OBJDIR),' $(DEP)

$(DEPDIR):
        mkdir $(DEPDIR)

-include $(DEP)

Но соблюдайтевывод "make bin" выполняется дважды подряд:

> make bin
mkdir ./dep
makedepend -- -g -I./include -- ./src/c.cpp ./src/b.cpp ./src/a.cpp -f- 2>/dev/null > ./dep/foo.dep
sed -i 's,./src,./obj,' ./dep/foo.dep
mkdir ./exe
mkdir ./obj
g++ -g -I./include -o obj/c.o -c src/c.cpp
g++ -g -I./include -o obj/b.o -c src/b.cpp
mkdir ./lib
ar ur ./lib/libfoo.a ./obj/c.o ./obj/b.o
ar: creating ./lib/libfoo.a
g++ -o ./exe/foo -g -I./include ./src/a.cpp -L./lib -lfoo
> 
> make bin
ar ur ./lib/libfoo.a ./obj/c.o ./obj/b.o

Вопрос:

Почему, когда я запускаю "make bin" несколько раз встрока: всегда ли make-файл выполняет рецепт $(LIB)?

По моему шаткому пониманию make-файлов, это может произойти, когда зависимости цели новее, чем цель.В этом случае, я думаю, это означает, что $(LIBDIR) новее, чем $(LIB).Но с чего бы это?Согласно выводу первого "make bin", $(LIBDIR) создается до $(LIB), как и ожидалось.

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

>ls --full-time -ld lib/libfoo.a
-rw-r--r-- 1 User None 81448 2018-12-22 00:42:07.188906200 -0800 lib/libfoo.a
>
>ls --full-time -ld lib/
drwxr-xr-x+ 1 User None 0 2018-12-22 00:42:07.204531200 -0800 lib/

Средой сборки является cygwin.

...