makefile重载问题

Posted by LuckXiang on March 19, 2021

虽然现代化的编译过程构建工具已经很流行,但是在某些地方,或者由于历史原因,还是需要使用基本的makefile语法来构建我们的工程。假如我们需要在makefile A中加载makefile B,而makefile B 是在 makefile A中生成的,那么就会遇到重载问题。 下面举一段示例:


objdir = $(GXSRC_PATH)/output

TARGET = appservice
LIBS += -lmongoose -lcjson

SRCS = $(shell find . -iname "*.c" | sed "s/\(\.\/\)\(.*\)/\2/g" | xargs)
OBJS = $(shell find . -iname "*.c" | sed "s%\(\.\/\)\(.*\)%$(objdir)\/\2%g" | sed "s/\.c/\.o/g" | xargs)

all: deps $(TARGET)

DEPS = $(objdir)/deps

deps: $(SRCS)
	@echo -e "\033[31m---- generate ----\033[0m";
	@echo -e "\033[32mdeps=$(DEPS)\033[0m";
	@-mkdir -p $(objdir);
	@-rm -f ./deps;
	@for a in $(SRCS); do \
		b=${objdir}/$$(echo $$a | sed 's/\.c/\.o/'); \
		c=$$(dirname $$a); \
		if [ $$c != "." ]; then \
			d=$(objdir)/$$c; \
			if [ ! -d $$d ]; then \
				mkdir -p $$d; \
			fi; \
		fi; \
		echo $$b: $$a >> ./deps; \
		echo '	@echo -e "compiling \033[032m[$$(CC)]\033[0m": ' $$a >> ./deps; \
		echo '	@$$(CC) -c $$(CFLAGS) -o $$@ $$^'>> ./deps; \
	done
	@-mv ./deps $(DEPS)

-include $(DEPS)


$(TARGET): $(OBJS)
	@echo "LDFLAGS:"$(LDFLAGS)
	@echo "LIBS:"$(LIBS)
	$(LD) $(OBJS) $(LDFLAGS) $(LIBS) -o $@


clean:
	rm -rf output;

这个makefile通过自动搜寻目录下的所有.c文件,然后构建一个名为deps的makfile文件,再通过加载这个deps文件实现整个工程的编译。然而这个makefile第一次执行就会报错,第二次执行才能实现编译动作,原因是啥呢? 在makefile执行时首先做的就是加载所有的makefile文件,内建所有的变量、明确规则和隐含规则,并建立所有目标和依赖之间的依赖关系结构链表。因此第一次执行makefile时,deps文件还没生成就被include了,它还是个空文件。 等到第二次执行,其实加载的是第一次执行生成的deps文件。要保证能正确的执行编译动作,就要求我们在deps文件生成时再把它重新加载一次。修改方法也很简单,我们只需要在生成deps文件以后,再执行一次make命令。为了避免 陷入死循环,我们引入一个中间目标 elf,把整个编译过程分解为两步,先通过deps目标构建自动化的编译脚本deps,然后再执行make elf来完成重载和编译。


objdir = $(GXSRC_PATH)/output

TARGET = appservice
LIBS += -lmongoose -lcjson

SRCS = $(shell find . -iname "*.c" | sed "s/\(\.\/\)\(.*\)/\2/g" | xargs)
OBJS = $(shell find . -iname "*.c" | sed "s%\(\.\/\)\(.*\)%$(objdir)\/\2%g" | sed "s/\.c/\.o/g" | xargs)

all: deps 

elf: $(TARGET)

DEPS = $(objdir)/deps

deps: $(SRCS)
	@echo -e "\033[31m---- generate ----\033[0m";
	@echo -e "\033[32mdeps=$(DEPS)\033[0m";
	@-mkdir -p $(objdir);
	@-rm -f ./deps;
	@for a in $(SRCS); do \
		b=${objdir}/$$(echo $$a | sed 's/\.c/\.o/'); \
		c=$$(dirname $$a); \
		if [ $$c != "." ]; then \
			d=$(objdir)/$$c; \
			if [ ! -d $$d ]; then \
				mkdir -p $$d; \
			fi; \
		fi; \
		echo $$b: $$a >> ./deps; \
		echo '	@echo -e "compiling \033[032m[$$(CC)]\033[0m": ' $$a >> ./deps; \
		echo '	@$$(CC) -c $$(CFLAGS) -o $$@ $$^'>> ./deps; \
	done
	@-mv ./deps $(DEPS)
	make elf

-include $(DEPS)


$(TARGET): $(OBJS)
	@echo "LDFLAGS:"$(LDFLAGS)
	@echo "LIBS:"$(LIBS)
	$(LD) $(OBJS) $(LDFLAGS) $(LIBS) -o $@


clean:
	rm -rf output;