为什么我的GNU让Makefile构建我的库两次?

时间:2015-03-21 20:51:59

标签: makefile gnu-make

我的GNU make Makefile:

# TODOs so I don't forget:
# - make debugging an option
# - make 64 below an actual option
# - figure out why make test seems to rebuild the DLL [note: this TODO is this question]
# - __declspec(dllimport)

ifeq ($(MAKECMDGOALS),64)
    CC = x86_64-w64-mingw32-gcc
    RC = x86_64-w64-mingw32-windres
    mflag = -m64
else
    CC = i686-w64-mingw32-gcc
    RC = i686-w64-mingw32-windres
    mflag = -m32
endif

OBJDIR = .objs
OUTDIR = out

BASENAME = wintable
DLLFILE = $(OUTDIR)/$(BASENAME).dll
LIBFILE = $(OUTDIR)/$(BASENAME).lib
TESTEXEFILE = $(OUTDIR)/$(BASENAME).exe

CFILES = \
    alloc.c \
    api.c \
    checkboxdraw.c \
    checkboxevents.c \
    children.c \
    coord.c \
    debug.c \
    draw.c \
    enablefocus.c \
    events.c \
    header.c \
    hscroll.c \
    main.c \
    metrics.c \
    modelhelpers.c \
    modelnotify.c \
    nullmodel.c \
    resize.c \
    scroll.c \
    select.c \
    tooltips.c \
    update.c \
    util.c \
    visibility.c \
    vscroll.c

HFILES = \
    table.h \
    tablepriv.h

TESTCFILES = \
    test.c

OFILES = $(CFILES:%.c=$(OBJDIR)/%.o)
TESTOFILES = $(TESTCFILES:%.c=$(OBJDIR)/%.o)

xCFLAGS = \
    --std=c99 \
    -Wall \
    -Wextra \
    -Wno-unused-parameter \
    $(mflag) \
    $(CFLAGS)

xLDFLAGS = \
    -static-libgcc \
    -luser32 -lkernel32 -lgdi32 -lcomctl32 -luxtheme -lole32 -loleaut32 -loleacc -luuid -lmsimg32 \
    $(mflag) \
    $(LDFLAGS)

default:
    $(MAKE) clean
    $(MAKE) it
    $(MAKE) test

it: $(DLLFILE)

$(DLLFILE): $(OFILES)
    $(CC) -g -o $(DLLFILE) -shared -Wl,--out-implib,$(LIBFILE) $(OFILES) $(xLDFLAGS)

test: $(TESTEXEFILE)
# see https://stackoverflow.com/a/29021641/3408572
.PHONY: test

$(TESTEXEFILE): $(DLLFILE) $(TESTOFILES)
    $(CC) -g -o $(TESTEXEFILE) $(TESTOFILES) $(LIBFILE) $(xLDFLAGS)

$(OBJDIR)/%.o: %.c $(HFILES) dirs
    $(CC) -g -o $@ -c $< $(xCFLAGS)

dirs:
    mkdir -p $(OBJDIR) $(OUTDIR)

clean:
    rm -rf $(OBJDIR) $(OUTDIR)

我使用make构建并希望进行清理和测试(我经常这样做很方便),所以目前我的default清理($(MAKE) clean),构建DLL({ {1}}),并构建测试程序($(MAKE) it)。

但是,$(MAKE) test

make

注意重建DLL的make clean make[1]: Entering directory '/home/pietro/src/github.com/andlabs/wintable' rm -rf .objs out make[1]: Leaving directory '/home/pietro/src/github.com/andlabs/wintable' make it make[1]: Entering directory '/home/pietro/src/github.com/andlabs/wintable' mkdir -p .objs out i686-w64-mingw32-gcc -g -o .objs/alloc.o -c alloc.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/api.o -c api.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/checkboxdraw.o -c checkboxdraw.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/checkboxevents.o -c checkboxevents.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/children.o -c children.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/coord.o -c coord.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/debug.o -c debug.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/draw.o -c draw.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/enablefocus.o -c enablefocus.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/events.o -c events.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/header.o -c header.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/hscroll.o -c hscroll.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/main.o -c main.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/metrics.o -c metrics.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/modelhelpers.o -c modelhelpers.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/modelnotify.o -c modelnotify.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/nullmodel.o -c nullmodel.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/resize.o -c resize.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/scroll.o -c scroll.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/select.o -c select.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/tooltips.o -c tooltips.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/update.o -c update.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/util.o -c util.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/visibility.o -c visibility.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/vscroll.o -c vscroll.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o out/wintable.dll -shared -Wl,--out-implib,out/wintable.lib .objs/alloc.o .objs/api.o .objs/checkboxdraw.o .objs/checkboxevents.o .objs/children.o .objs/coord.o .objs/debug.o .objs/draw.o .objs/enablefocus.o .objs/events.o .objs/header.o .objs/hscroll.o .objs/main.o .objs/metrics.o .objs/modelhelpers.o .objs/modelnotify.o .objs/nullmodel.o .objs/resize.o .objs/scroll.o .objs/select.o .objs/tooltips.o .objs/update.o .objs/util.o .objs/visibility.o .objs/vscroll.o -static-libgcc -luser32 -lkernel32 -lgdi32 -lcomctl32 -luxtheme -lole32 -loleaut32 -loleacc -luuid -lmsimg32 -m32 make[1]: Leaving directory '/home/pietro/src/github.com/andlabs/wintable' make test make[1]: Entering directory '/home/pietro/src/github.com/andlabs/wintable' mkdir -p .objs out i686-w64-mingw32-gcc -g -o .objs/alloc.o -c alloc.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/api.o -c api.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/checkboxdraw.o -c checkboxdraw.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/checkboxevents.o -c checkboxevents.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/children.o -c children.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/coord.o -c coord.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/debug.o -c debug.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/draw.o -c draw.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/enablefocus.o -c enablefocus.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/events.o -c events.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/header.o -c header.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/hscroll.o -c hscroll.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/main.o -c main.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/metrics.o -c metrics.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/modelhelpers.o -c modelhelpers.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/modelnotify.o -c modelnotify.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/nullmodel.o -c nullmodel.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/resize.o -c resize.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/scroll.o -c scroll.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/select.o -c select.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/tooltips.o -c tooltips.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/update.o -c update.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/util.o -c util.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/visibility.o -c visibility.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o .objs/vscroll.o -c vscroll.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o out/wintable.dll -shared -Wl,--out-implib,out/wintable.lib .objs/alloc.o .objs/api.o .objs/checkboxdraw.o .objs/checkboxevents.o .objs/children.o .objs/coord.o .objs/debug.o .objs/draw.o .objs/enablefocus.o .objs/events.o .objs/header.o .objs/hscroll.o .objs/main.o .objs/metrics.o .objs/modelhelpers.o .objs/modelnotify.o .objs/nullmodel.o .objs/resize.o .objs/scroll.o .objs/select.o .objs/tooltips.o .objs/update.o .objs/util.o .objs/visibility.o .objs/vscroll.o -static-libgcc -luser32 -lkernel32 -lgdi32 -lcomctl32 -luxtheme -lole32 -loleaut32 -loleacc -luuid -lmsimg32 -m32 i686-w64-mingw32-gcc -g -o .objs/test.o -c test.c --std=c99 -Wall -Wextra -Wno-unused-parameter -m32 i686-w64-mingw32-gcc -g -o out/wintable.exe .objs/test.o out/wintable.lib -static-libgcc -luser32 -lkernel32 -lgdi32 -lcomctl32 -luxtheme -lole32 -loleaut32 -loleacc -luuid -lmsimg32 -m32 make[1]: Leaving directory '/home/pietro/src/github.com/andlabs/wintable' 步骤如何$(MAKE) test步骤没有发生!步骤之间没有清理,没有其他变化发生,因此我不知道为什么要重建DLL。

我认为伪造$(MAKE) itdefaultitclean目标会修复它(根据one of my previous questions),但是没有&# 39;工作。谷歌只告诉我如何告诉make两次构建我的目标,而不是如何阻止它这样做。

这是Ubuntu GNOME 14.10上的GNU make 4.0。

发生了什么?感谢。

更新 2015年4月22日
我开始认为这个问题实际上是here概述的那个问题,因为我在其他项目中看到类似的重建问题我不会做dirs事情。 #39;我在这里做:

  

这适用于这个简单的例子,但这是一个主要问题。由于目录中的时间戳通常在目录中的任何文件更新时更新,因此这个Makefile工作量太大。

     

例如,只需触摸/ out /中的随机文件/强制重建/out/foo.o。在一个复杂的例子中,这可能意味着没有任何理由重建许多目标文件,只是因为其他文件是在同一目录中重建的。

我确认实际情况确实如此,并在适当时提供答案。

2 个答案:

答案 0 :(得分:1)

问题是你正在使用make -n,它实际上没有做任何事情,结合了make的递归调用。 make -n it命令调用一个sub-make,假装构建所有东西,但实际上并没有构建任何东西。那个make退出的实例,以及它假装构建但实际上没有构建的目标的所有内部知识在它退出时都会丢失。

然后你开始一个新的make -n test依赖于那些仍然不存在的相同目标,但是这个新的make实例并不知道前一个实例已经假装已经构建它们。

如果您运行真实的make,而不是make -n,那么您不应该看到此重建。

如果您希望make -n在这种情况下工作,则无法以递归方式运行make。

ETA:您的另一个问题是所有目标文件都依赖于dirs目标,但该目标永远不存在(永远不会有名为dirs的文件)。因此,当make启动时,它会看到dirs不存在并运行规则来构建它,然后假定依赖于该目标的所有目标都已过期并重建它们。然后在下次调用make时,它会看到dirs不存在并运行规则来构建它,然后假设依赖于该目标的所有目标都已过期并重建它们......等等

答案 1 :(得分:0)

好的,事实证明它完全一样:目录修改时间已经改变,所以&x想要再次构建一切。使用仅订单的先决条件工作。不管怎样,谢谢!