GNU make is adding an extra step not in my Makefile that causes all sorts of linker errors. What's going on?

僤鯓⒐⒋嵵緔 提交于 2020-02-08 07:54:31

问题


Given the following makefile for GNU make:

# 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
# - __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 \
    events.c \
    header.c \
    hscroll.c \
    main.c \
    metrics.c \
    modelhelpers.c \
    nullmodel.c \
    resize.c \
    scroll.c \
    select.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)

$(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 -n test produces

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 
(and so on for all the other C files)
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/events.o .objs/header.o .objs/hscroll.o .objs/main.o .objs/metrics.o .objs/modelhelpers.o .objs/nullmodel.o .objs/resize.o .objs/scroll.o .objs/select.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 
i686-w64-mingw32-gcc     test.c out/wintable.exe   -o test

Notice how the last step that GNU make decides to do tries to recompile my test.c with the correct output executable file built before that into a new test executable, which (predictably) fails spectacularly:

out/wintable.exe: In function `WinMainCRTStartup':
/build/buildd/mingw-w64-3.1.0/build/i686-w64-mingw32-i686-w64-mingw32-crt/../../mingw-w64-crt/crt/crtexe.c:171: multiple definition of `WinMainCRTStartup'
/usr/lib/gcc/i686-w64-mingw32/4.9-win32/../../../../i686-w64-mingw32/lib/../lib/crt2.o:/build/buildd/mingw-w64-3.1.0/build/i686-w64-mingw32-i686-w64-mingw32-crt/../../mingw-w64-crt/crt/crtexe.c:171: first defined here
out/wintable.exe: In function `mainCRTStartup':
/build/buildd/mingw-w64-3.1.0/build/i686-w64-mingw32-i686-w64-mingw32-crt/../../mingw-w64-crt/crt/crtexe.c:199: multiple definition of `mainCRTStartup'
/usr/lib/gcc/i686-w64-mingw32/4.9-win32/../../../../i686-w64-mingw32/lib/../lib/crt2.o:/build/buildd/mingw-w64-3.1.0/build/i686-w64-mingw32-i686-w64-mingw32-crt/../../mingw-w64-crt/crt/crtexe.c:199: first defined here
out/wintable.exe:cygming-crtbegin.c:(.text+0x500): multiple definition of `__gcc_register_frame'
/usr/lib/gcc/i686-w64-mingw32/4.9-win32/crtbegin.o:cygming-crtbegin.c:(.text+0x0): first defined here
out/wintable.exe:cygming-crtbegin.c:(.text+0x550): multiple definition of `__gcc_deregister_frame'
/usr/lib/gcc/i686-w64-mingw32/4.9-win32/crtbegin.o:cygming-crtbegin.c:(.text+0x50): first defined here
out/wintable.exe: In function `mainwinCreate':
/home/pietro/src/github.com/andlabs/wintable/test.c:20: multiple definition of `mainwinCreate'
/tmp/cc50VrIz.o:test.c:(.text+0x0): first defined here
out/wintable.exe: In function `mainwinDestroy':
/home/pietro/src/github.com/andlabs/wintable/test.c:66: multiple definition of `mainwinDestroy'
/tmp/cc50VrIz.o:test.c:(.text+0x2ba): first defined here
(and so on for virtually every symbol in my test.c)
/usr/lib/gcc/i686-w64-mingw32/4.9-win32/crtbegin.o:cygming-crtbegin.c:(.text+0x22): undefined reference to `_Jv_RegisterClasses'
collect2: error: ld returned 1 exit status
<builtin>: recipe for target 'test' failed
make: *** [test] Error 1

Where is this last step coming from? It's nowhere in my makefile, as far as I can tell. (Notice the lack of compiler flags.) Googling the problem was also ineffective here. This only started to happen today, with all the same rules as before (the only change is the addition of modelhelpers.c and nullmodel.c to CFILES), so I'm not sure what's going on.

Does it have to do with the rule being test? If so, why did it work before?

This is GNU make 4.0 on Ubuntu GNOME 14.10.

Thanks.


回答1:


Make has various built-in implicit rules, and one of them is the pattern rule % : %.c, which tells make how to create an executable (in UNIX systems, executables don't have any extension like .exe etc., they're just words like test, mkdir, etc.) if it has a source file with the same extension.

Your makefile has:

test: $(TESTEXEFILE)

and you provide no recipe for building the target test, so make looks at its built-in rules and finds % : %.c, and then make looks and sees that you DO have a test.c file, so make applies that default recipe to build the target test, which you asked it to do.

If you don't want this to happen you should tell make that test is not a real target: that you're only using it as a handle to build other things, using the .PHONY special target:

.PHONY: test

From the manual:

The implicit rule search is skipped for .PHONY targets.



来源:https://stackoverflow.com/questions/29021591/gnu-make-is-adding-an-extra-step-not-in-my-makefile-that-causes-all-sorts-of-lin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!