Нет моих знаний.* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *] С действительно действительно много проблем с make
, но это все еще самый доступный инструмент из всех, и как только вы запустите его правильно, вы должны просто сосредоточиться на разработке.напишите make-файлы.Но вместо того, чтобы искать «make library», действительно простое решение (если вы на самом деле были инициированы на языке Make), которое часто упускают из виду за очевидность, - это реализовать свой собственный .Создайте скрипт make, содержащий набор шаблонных правил и переменных по умолчанию для связи с make-файлом проекта, и просто включите этот скрипт в make-файл каждого проекта.Это не сложно, может быть, немного отнимает много времени, но часто окупается очень хорошо, особенно если у вас много небольших проектов для управления.
Я работаю с таким дизайном.У меня есть пара GNU make-скриптов, тщательно разработанных для того, чтобы предложить почти тривиальный механизм для создания довольно сложных систем сборки: автоматическое создание зависимостей, обработка разных языков, генерация синтаксических анализаторов языков, различные конфигурации сборки (отладка или выпуск), генерация журнала сборки,и так далее.И сценарий не громоздкий: текущая версия содержит всего около 250 строк кода make-файла, исключая комментарии.
Я оставлю вам образец более старой версии такой системы, которая обрабатывает только исходный код C, которыйсодержал несколько функций.Он должен обрабатывать компиляцию двоичных файлов и библиотек (как статических, так и динамических).Это также должно помочь вам отслеживать межпроектные зависимости через переменную DEPS
.
Вызовите это $(ROOT)/project.mk
:
# Remove the default suffix rules.
.SUFFIXES:
# Turn on the delete-on-error feature.
.DELETE_ON_ERROR:
# Set up additional command variables.
STRIP ?= strip
# Set up a global search path to locate prerequisites.
VPATH := $(VPATH) $(shell find -type d)
# Locate all source files from the default locations in the project tree.
SRC := $(SRC) $(shell find src -name '*.c')
# Set up the default dependency files.
DEP := $(DEP) $(addprefix dep/,$(addsuffix .d,$(basename $(notdir $(filter %.c,$(SRC))))))
# Set up the default object files.
OBJ := $(OBJ) $(addprefix obj/,$(addsuffix .o,$(basename $(notdir $(filter %.c,$(SRC))))))
# Set up a set of default flags for all commands used.
STRIPFLAGS ?= -p
CPPFLAGS ?= -DNDEBUG
CFLAGS ?= -Wall -Wextra -Werror -pedantic -O3 -march=native -fomit-frame-pointer -ffast-math
LDFLAGS ?= --as-needed -O1
ARFLAGS ?= -scr
# Set up the default include and library search paths.
override INCLUDES := \
$(addprefix $(ROOT)/,$(addsuffix /include,$(DEPS))) \
$(INCLUDES)
override LIBRARIES := \
$(addprefix $(ROOT)/,$(addsuffix /lib,$(DEPS))) \
$(LIBRARIES) lib
# The default rule to build every target in the project.
.PHONY: all
all: deps $(DEP) $(OBJ) $(BIN) $(LIB)
# Phony rule to recursively build the library dependencies.
.PHONY: deps
deps:
@for dep in $(DEPS); do cd $(ROOT)/lib/$$dep && $(MAKE); done
# Secondary expansion is used to properly locate prerequisites.
.SECONDEXPANSION:
# Rule for dependency file generation.
%.d: $$(notdir $$*).c
$(CC) -M $(CPPFLAGS) $(CFLAGS) -iquote include $(addprefix -I ,$(INCLUDES)) $< -MM -MG -MP -MT '$@ $(filter %/$(notdir $*).o,$(OBJ))' > $@
# Rule for compiling object files.
%.o: $$(notdir $$*).c
$(CC) -c $(CPPFLAGS) $(CFLAGS) -iquote include $(addprefix -I ,$(INCLUDES)) $< -o $@
# Rule for linking binaries.
%: $$(notdir $$*).c
$(CC) $(CPPFLAGS) $(CFLAGS) $(addprefix -Xlinker ,$(LDFLAGS)) -iquote include $(addprefix -I ,$(INCLUDES)) $(addprefix -L ,$(LIBRARIES)) $(filter-out $<,$^) -o $@ $(addprefix -l,$(LDLIBS))
$(STRIP) $(STRIPFLAGS) $@
# Rule for linking shared libraries.
%.so: $$(notdir $$*).c
$(CC) $(CPPFLAGS) $(CFLAGS) $(addprefix -Xlinker ,$(LDFLAGS)) -iquote include $(addprefix -I ,$(INCLUDES)) $(addprefix -L ,$(LIBRARIES)) $(filter-out $<,$^) -o $@ -fpic -shared -Wl,-h,$(notdir $@) $(addprefix -l,$(LDLIBS))
$(STRIP) $(STRIPFLAGS) $@
# Rule for generating static libraries.
%.a:
$(AR) $(ARFLAGS) $@ $?
# Include all dependency files and remake them if necessary.
ifneq ($(MAKECMDGOALS),clean)
include $(DEP)
endif
# Phony rule to clean the entire build tree.
.PHONY: clean
clean:
@for dep in $(DEPS); do cd $(ROOT)/lib/$$dep && $(MAKE) clean; done
$(RM) $(DEP) $(OBJ) $(BIN) $(LIB) $(CLEAN)
ROOT
содержит путь к каталогу ваших проектов (рабочая копия репозитория, например), обычно экспортируется как переменная окружения.Вам также понадобится пара каталогов (bin
, dep
, obj
и src
) в ваших проектах.
Примером Makefile с использованием этой системы может быть:
DEPS := mylib
BIN := bin/test
LIB := lib/libtest.a
include $(ROOT)/project.mk
bin/test: $(OBJ)
lib/libtest.a: obj/test1.o obj/test2.o
То есть вы просто пишете минимум, необходимый для вашего проекта, и пусть система сборки сделает все остальное.Вы всегда можете явно указать значение для данной переменной (SRC
, например, или CFLAGS
), но если вы этого не сделаете, то оно получит разумное значение по умолчанию.
Выше было адаптировано кмои потребности, но это должно быть просто, чтобы приспособиться к вашим, оставив при этом все так же просто, как примеры, которые вы упомянули.