38993

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

Question:

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.

Answer1:

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 <em>DO</em> 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 <a href="http://www.gnu.org/software/make/manual/html_node/Phony-Targets.html" rel="nofollow">.PHONY special target</a>:

.PHONY: test

From the manual:

<blockquote>

The implicit rule search is skipped for .PHONY targets.

</blockquote>

Recommend

  • Fortran debugging with gdb on Mac OS?
  • Symbol not found when using template defined in a library
  • Missing bridge cast causes error in preprocessed source but not in real source
  • How to compile gcc 6.4.0 with gcc 7.2 in Archlinux
  • Mac gcc non-virtual thunk error
  • GTK+ compilation undefined reference C
  • Predict/estimate values using randomForest in R
  • copy all *.so files excluding libgcc*.so [closed]
  • Javascript - why this loop ? instance->(prototype property->constructor property->function
  • ignoring ensurepip failure pip requires ssl/tls error in Ubuntu 18.04
  • failing to initialize opencl vector literal
  • Output spits two extra control characters, possibly a memory corruption bug?
  • Can I use Preprocessor Directives in .ld file
  • dbus - how to set include paths
  • Using CUDA 8.0 with GCC 6.x - bad function overloading complaint
  • Boost Spirit Qi Attribute Propagation
  • Call a macro with parameters : Python win32com API
  • Greek letters in legend in R
  • Typecasting `this` of a base class template to its derived class
  • Express displaying mongodb documents in Jade
  • Search files(key) in s3 bucket takes longer time
  • JavaScriptCore External Arrays
  • passing parameter to DownloadStringCompletedEventHandler in C#
  • How do I check if System::Collections:ArrayList is empty / nullptr / null?
  • Deduce parent class of inherited method in C++
  • Processing different annotations with the same Processor instance
  • Google analytics measurement protocol session timeout and query time limits
  • crash in __tcf_0
  • Get a trait object reference from a vector
  • LESS CSS how to modify parent property in mixin
  • Passing variable arguments using PowerShell's Start-Process cmdlet
  • Cannot get the UserManager class
  • Unable to decode certificate at client new X509Certificate2()
  • Needing to do .toArray() to get output of mongodb .find() on key name not value
  • sending/ receiving email in Java
  • Symfony2: How to get request parameter
  • ORA-29908: missing primary invocation for ancillary operator
  • How to delete a row from a dynamic generate table using jquery?
  • Proper way to use connect-multiparty with express.js?
  • Checking variable from a different class in C#