Search code examples
cgccmakefile

Why does Make automatically execute a cc command?


I'm trying to learn how to use Make! So I have this simple Makefile,

all: main other

main: main.c other.o
    gcc main.c -o main
    echo "Compiled main.exe"

other: other.o

other.c:
    touch $@
    echo "int main(){return 0;}" > $@
    echo "Created other.c"

other.o: other.c
    gcc other.c -o other.o
    echo "Compiled other.o"

clean:
    rm -f main.exe other.o other.c

where everything executes as expected except at the end where a cc compile command is executed. Here is the output (I added the arrow),

> make all  
touch other.c
echo "int main(){return 0;}" > other.c
echo "Created other.c"
Created other.c
gcc other.c -o other.o
echo "Compiled other.o"
Compiled other.o
gcc main.c -o main
echo "Compiled main.exe"
Compiled main.exe
cc   other.o   -o other     <---
/usr/lib/gcc/x86_64-pc-msys/13.2.0/../../../../x86_64-pc-msys/bin/ld: other.o: in functio
n `mainCRTStartup':
/c/S/B/src/msys2-runtime/winsup/cygwin/crt0.c:20: multiple definition of `mainCRTStartup'
; /usr/lib/gcc/x86_64-pc-msys/13.2.0/../../../crt0.o:/c/S/B/src/msys2-runtime/winsup/cygw
in/crt0.c:20: first defined here
/usr/lib/gcc/x86_64-pc-msys/13.2.0/../../../../x86_64-pc-msys/bin/ld: other.o: in functio
n `mainCRTStartup':
/c/S/B/src/msys2-runtime/winsup/cygwin/crt0.c:20: multiple definition of `WinMainCRTStart
up'; /usr/lib/gcc/x86_64-pc-msys/13.2.0/../../../crt0.o:/c/S/B/src/msys2-runtime/winsup/c
ygwin/crt0.c:20: first defined here
/usr/lib/gcc/x86_64-pc-msys/13.2.0/../../../../x86_64-pc-msys/bin/ld: other.o:cygming-crt
beg:(.text+0x50): multiple definition of `__gcc_register_frame'; /usr/lib/gcc/x86_64-pc-m
sys/13.2.0/crtbegin.o:cygming-crtbeg:(.text+0x0): first defined here
/usr/lib/gcc/x86_64-pc-msys/13.2.0/../../../../x86_64-pc-msys/bin/ld: other.o:cygming-crt
beg:(.text+0x70): multiple definition of `__gcc_deregister_frame'; /usr/lib/gcc/x86_64-pc
-msys/13.2.0/crtbegin.o:cygming-crtbeg:(.text+0x20): first defined here
/usr/lib/gcc/x86_64-pc-msys/13.2.0/../../../../x86_64-pc-msys/bin/ld: other.o:cygming-crt
beg:(.data+0x0): multiple definition of `__dso_handle'; /usr/lib/gcc/x86_64-pc-msys/13.2.
0/crtbegin.o:cygming-crtbeg:(.data+0x0): first defined here
collect2: error: ld returned 1 exit status
make: *** [<builtin>: other] Error 1

Where the "<---" points to is the line in question. Why is this getting executed?


Solution

  • The problem is that the default program to build and link programs is cc. And with the rule other: other.o you tell make to build the executable other from the object file other.o which it will then do using the default linker.

    And the errors are because gcc other.c -o other.o builds an executable program file named other.o. To build an object file you need to use the -c option.

    The simple solution to all your problems, really, is to set the CC and LD variables, and rely on implicit rules to build your code.

    Such a Makefile could look something like this:

    # Explicitly use gcc as the compiler and linker
    CC = gcc
    LD = gcc
    
    # The "default" target, because the first target in the makefile
    # is what make will use when no target is specified
    default: main other
    
    # Build the main executable program from the main.c source
    main: main.c
    
    # Build the other executable program from the other.c source
    other: other.c
    
    # Create the other.c source file
    other.c:
        echo "int main(){return 0;}" > $@
    
    # The clean target isn't for creating a "clean" file, it's phony, fake
    .PHONY: clean
    clean:
        -rm -f main other other.c
    

    [Please note that you need to convert the indentation to tabs]