Я изучаю / укрепляю мое понимание make-файлов, написав простой проект на основе makefile с нуля.
Дерево моего проекта структурировано следующим образом:
.
│ makefile
│
├───dep
├───exe
├───include
│ b.h
│ c.h
│
├───lib
├───obj
└───src
a.cpp
b.cpp
c.cpp
Итак, мое намерение /цели:
Иметь один make-файл в корне проекта
Иметь исходники, заголовки, объектные файлы, библиотеки, зависимые файлы и исполняемые файлы каждыйв своем собственном подкаталоге корневого каталога проекта.
Ровно один исходный файл в src/
будет содержать int main(...)
.
Makefile долженскомпилировать все исходники, кроме того, который реализует int main(...)
для объектных файлов в obj/
.
Makefile должен архивировать все объектные файлы в lib в lib/
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.