c-我如何改进这个Makefile来优化SRC和BIN文件夹的使用



这是我在学习了几篇教程和gnu-make手册后第一次尝试制作Makefile。Makefile工作并在BIN文件夹中创建.o、.a和.exe文件。但是,我已经为所有文件添加了src\和bin\前缀。我知道在使用Makefiles时,一定有更好的方法来解决文件夹问题。唯一的问题是,经过数小时的编辑和基于教程的不同尝试,我无法弄清楚。在我学习的这个阶段,我发现GNU让手册太难了。

我在Windows7上使用MinGW GCC工具链。我已经将mingw32-make.exe复制到make.exe,目的是尝试我所经历的教程和示例。

如果能在这个问题上得到任何帮助,我将不胜感激。非常感谢。

我的Makefile如下:

CC = gcc
CFLAGS = -O3 -Wall -c
BIN = bin/
LDFLAGS = -L$(BIN) -lmyLib
all: test.exe
test.exe: test.o libmyLib.a
gcc bintest.o -o bintest.exe $(LDFLAGS)
test.o: srctest.c srcmyLib.h
$(CC) $(CFLAGS) -o bintest.o srctest.c
libmyLib.a: myLib.o
ar rcs binlibmyLib.a binmyLib.o
myLib.o: srctest.c srcmyLib.h
$(CC) $(CFLAGS) -o binmyLib.o srcmyLib.c
clean:
del bin*.* /Q

首先,Makefile存在一些问题,即使它显然有效。当你写:

myLib.o: srctest.c srcmyLib.h
$(CC) $(CFLAGS) -o binmyLib.o srcmyLib.c

你在撒谎:

  1. 您告诉它,规则的结果是myLib.o,而它是binmyLib.o,即不同的文件
  2. 你告诉make,myLib.o依赖于srctest.c,而实际上它依赖于srcmyLib.c

与中的其他规则相同

libmyLib.a: myLib.o
ar rcs binlibmyLib.a binmyLib.o

您告诉make,如果myLib.olibmyLib.a新,而真正的先决条件是binmyLib.o,真正的目标是binlibmyLib.a,则应执行该规则。

通过这样做,你完全阻止了make做它应该做的事情:根据目标文件和先决条件文件的最后修改时间,决定是否必须执行配方。试试看:运行make两次,你会发现它毫无用处地重做了它已经做过的事情。永远不要撒谎。

其次,您可以使用一些高级功能来改进Makefile,如自动($@$<$^(、标准(LDLIBSARARFLAGS(和常规(BINSRC(生成变量。以下是您可以尝试的一个示例,在解决了上述问题并更好地使用变量后(再加上添加缺失的-Igcc选项,并将allclean声明为虚假文件,因为这些目标不是真实的文件,我们不想撒谎(:

BIN = bin
SRC = src
CC = gcc
CFLAGS = -O3 -Wall -c -I$(SRC)
LDFLAGS = -L$(BIN)
LDLIBS = -lmyLib
AR = ar
ARFLAGS = rcs
.PHONY: all clean
all: $(BIN)/test.exe
$(BIN)/test.exe: $(BIN)/test.o $(BIN)/libmyLib.a
$(CC) $< -o $@ $(LDFLAGS) $(LDLIBS)
$(BIN)/test.o: $(SRC)/test.c $(SRC)/myLib.h
$(CC) $(CFLAGS) -o $@ $<
$(BIN)/libmyLib.a: $(BIN)/myLib.o
$(AR) $(ARFLAGS) $@ $^
$(BIN)/myLib.o: $(SRC)/myLib.c $(SRC)/myLib.h
$(CC) $(CFLAGS) -o $@ $<
clean:
del $(BIN)*.* /Q

现在,所有非虚假的目标和先决条件都是规则中真正涉及的常规文件。再次尝试一下,你会发现make重建只是过时的,因此需要重建。

如果你想去掉$(SRC)/前缀,你可以使用vpath指令,告诉在哪里查找源文件(我坚持,很多人试图将其用于目标文件,这不是它的用途(:

vpath %.h $(SRC)
vpath %.c $(SRC)

然后:

$(BIN)/test.o: test.c myLib.h
$(CC) $(CFLAGS) -o $@ $<
$(BIN)/myLib.o: myLib.c myLib.h
$(CC) $(CFLAGS) -o $@ $<

注意:您也可以使用VPATH变量而不是vpath指令。

模式规则用于考虑类似的规则,例如,您的编译规则只因源文件和对象文件的名称而异:

$(BIN)/%.o: %.c myLib.h
$(CC) $(CFLAGS) -o $@ $<

总而言之:

BIN = bin
SRC = src
CC = gcc
CFLAGS = -O3 -Wall -c -I$(SRC)
LDFLAGS = -L$(BIN)
LDLIBS = -lmyLib
AR = ar
ARFLAGS = rcs
vpath %.h $(SRC)
vpath %.c $(SRC)
.PHONY: all clean
all: $(BIN)/test.exe
$(BIN)/test.exe: $(BIN)/test.o $(BIN)/libmyLib.a
$(CC) $< -o $@ $(LDFLAGS) $(LDLIBS)
$(BIN)/%.o: %.c myLib.h
$(CC) $(CFLAGS) -o $@ $<
$(BIN)/libmyLib.a: $(BIN)/myLib.o
$(AR) $(ARFLAGS) $@ $^

clean:
del $(BIN)*.* /Q

最后,如果您真的想在规则中避免使用$(BIN)/前缀,则必须移动到$(BIN)目录并从那里调用make。如果愿意,可以将Makefile保留在主目录中,并使用-f ../Makefile选项。

当然,这比只在主目录中键入make [goals]更不方便。有一些方法可以让make从调用它的地方进行测试,如果它不在构建目录中,请使用-C-f选项重新调用它自己,这样它就可以从构建目录中完成它的工作。但如果你是新手,可能会有点太复杂。

然而,如果你感兴趣,可以看看这篇涵盖这个主题的文章(以及更多(。如果我们尽可能简化帖子中的建议,并将其专门用于您的案例,那么最终的Makefile可能是这样的:

# here starts the black magic that makes it possible
.SUFFIXES:
BIN := bin
SRC := src
ifneq ($(notdir $(CURDIR)),$(BIN))
.PHONY: $(BIN) clean
$(BIN):
@$(MAKE) --no-print-directory -C $@ -f ../Makefile SRC=$(CURDIR)/$(SRC) $(MAKECMDGOALS)
Makefile: ;
% :: $(BIN) ; :
clean:
del $(BIN)*.* /Q
else
# here ends the black magic that makes it possible
# here starts the Makefile you would really like to write
CC      := gcc
CFLAGS  := -O3 -Wall -c -I$(SRC)
LDFLAGS := -L.
LDLIBS  := -lmyLib
AR      := ar
ARFLAGS := rcs
vpath %.h $(SRC)
vpath %.c $(SRC)
.PHONY: all
all: test.exe
test.exe: test.o libmyLib.a
$(CC) $< -o $@ $(LDFLAGS) $(LDLIBS)
%.o: %.c myLib.h
$(CC) $(CFLAGS) -o $@ $<
libmyLib.a: myLib.o
$(AR) $(ARFLAGS) $@ $^
# here ends the Makefile you would really like to write
# a last bit of black magic
endif

如果源文件和目标文件都在源目录中,那么您真正想写的Makefile就是。不再有前缀;vpath负责$(SRC)/前缀,而$(BIN)/是无用的,因为当使用Makefile的这一部分时,我们已经在$(BIN)中了。

注意:我对Windows及其各种命令行接口一无所知,所以可能有一些东西需要调整(例如,反斜杠而不是斜杠(。

相关内容

  • 没有找到相关文章

最新更新