aaronvan
aaronvan

Reputation: 316

Linking is no occuring in my Makefile; returns 'undefined reference to `main'

This simple program (two .c files and one .h) compiles and links properly from the command line. However, my Makefile is throwing an error during the linking stage. Proper tab usage is in effect.

CC      = gcc
BINDIR  = bin/
OBJDIR  = obj/
SRCDIR  = src/
MKDIR   = mkdir -p
RM      = rm -rf

SRC     = $(wildcard $(SRCDIR)*.c) 
_OBJS   = $(patsubst $(SRCDIR)%.c, %.o, $(SRC))
OBJS    = $(addprefix $(OBJDIR), $(_OBJS))
CFLAGS  = -Wall -g -Iinclude

.PHONY: all
    all: $(BIN)

_BIN    = a.out
BIN     = $(addprefix $(BINDIR), $(_BIN))

$(BIN): $(OBJS) $(BINDIR)
    $(CC) -o $@ $(CFLAGS) $<  

$(BINDIR):
    $(MKDIR) $(BINDIR)

$(OBJS): $(SRC) $(OBJDIR)
    $(CC) $(CFLAGS) -c $< -o $@ 

$(OBJDIR):
    $(MKDIR) $(OBJDIR)

.PHONY: clean
clean:
    @echo "Cleaning things up..."
    $(RM) $(OBJDIR) $(BINDIR)

The program's files:
main.c

#include <stdio.h>
#include <stdlib.h>

#include "hellomake.h"

int main(void) {
    myPrintHelloMake();

    return EXIT_SUCCESS;
}

hellomake.c

#include <stdio.h>
#include "hellomake.h"

void myPrintHelloMake(void) {
    puts("Hello makefiles!");
}

hellomake.h

#ifndef __HELLO_H__
#define __HELLO_H__

void myPrintHelloMake(void);

#endif

The .c files are in the src/ directory and the .h file is in the include/ directory. Makefile compiles the code, creates the obj/ directory, and places and main.o and hellomake.o therein. However, that is where things break down. Here is gcc's complaint:

$ make 
mkdir -p obj/
gcc -Wall -g -Iinclude -c src/hellomake.c -o obj/hellomake.o gcc -Wall -g -Iinclude -c src/hellomake.c -o obj/main.o mkdir -p bin/ gcc -o bin/a.out -Wall -g -Iinclude
obj/hellomake.o /usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu/Scrt1.o: in function `_start': (.text+0x20): undefined reference to `main' collect2: error: ld returned 1 exit status make: *** [Makefile:34: bin/a.out] Error 1

Upvotes: 1

Views: 98

Answers (1)

Craig Estey
Craig Estey

Reputation: 33601

There were a number of issues.

I'd leave off / from (e.g.) BINDIR et. al.

The patsubst was incorrect. It needed $(OBJDIR) in the the TO

Using _OBJS was unnecessary/harmful.

The rule for $(OBJS) was incorrect. It created the two .o files using the first prereq source, so [the function] main was defined twice. It needs a pattern rule instead.

Using $(BINDIR) as a prereq for $(BIN) added bin/ at the end of the gcc line [and it complained]

As M.Oehm mentioned, $< only gets the first prereq.

The all: was indented so it was not recognized properly


Anyway, here's the corrected Makefile:

CC      = gcc
BINDIR  = bin
OBJDIR  = obj
SRCDIR  = src
MKDIR   = mkdir -p
RM      = rm -rf

SRC     = $(wildcard $(SRCDIR)/*.c)

###_OBJS   = $(patsubst $(SRCDIR)%.c, %.o, $(SRC))
###OBJS    = $(addprefix $(OBJDIR), $(_OBJS))
OBJS   = $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SRC))

CFLAGS  = -Wall -g -Iinclude

_BIN    = a.out
BIN     = $(addprefix $(BINDIR)/, $(_BIN))

.PHONY: all
all: $(BINDIR) $(OBJDIR) $(BIN)

####$(BIN): $(OBJS) $(BINDIR)
$(BIN): $(OBJS) $(BINDIR)
    ###$(CC) -o $@ $(CFLAGS) $<
    $(CC) -o $@ $(CFLAGS) $(OBJS)

$(BINDIR):
    $(MKDIR) $(BINDIR)

###$(OBJS): $(SRC) $(OBJDIR)
$(OBJDIR)/%.o: $(SRCDIR)/%.c
    $(CC) $(CFLAGS) -c $< -o $@

$(OBJDIR):
    $(MKDIR) $(OBJDIR)

.PHONY: clean
clean:
    @echo "Cleaning things up..."
    $(RM) $(OBJDIR) $(BINDIR)

Upvotes: 2

Related Questions