Связывание не встречается в моем Makefile; возвращает ‘неопределенную ссылку на `main’

#c #linux #gcc #makefile

#c #linux #gcc #makefile

Вопрос:

Эта простая программа (два файла .c и один .h) правильно компилируется и связывается из командной строки. Однако мой 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))
CFLAGS  = -Wall -g -Iinclude

.PHONY: all
    all: $(BIN)

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

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

lt;

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

$(OBJS): $(SRC) $(OBJDIR)
$(CC) $(CFLAGS) -c


lt; -o $@

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

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

Файлы программы:
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
 

Файлы .c находятся в каталоге src/, а файл .h находится в каталоге include/ . Makefile компилирует код, создает каталог obj / и помещает в него и main.o и hellomake.o . Однако именно здесь все ломается. Вот жалоба gcc:

 $ 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
 

Комментарии:

1. Я думаю, когда вы связываете (цель $(BIN) ), вам нужны $^ (все предварительные условия) вместо $< (только первое предварительное условие). (Хорошо, это будет включать $(BINDIR) , поэтому вам, возможно, придется ввести промежуточную фальшивую цель, например all: $(BIN) %(BINDIR) .)

Ответ №1:

Был ряд проблем.

Я бы отказался / от (например) BINDIR и др.

Это patsubst было неверно. Это необходимо $(OBJDIR) в TO

Использование _OBJS было ненужным / вредным.

Правило для $(OBJS) было неверным. Он создал два .o файла с использованием первого источника prereq, поэтому [функция] main была определена дважды. Вместо этого требуется правило шаблона.

Использование $(BINDIR) в качестве предварительного условия для $(BIN) добавления bin/ в конце gcc строки [и он жаловался]

Как M.Oehm уже упоминалось, $< получает только первый предварительный запрос.

В all: нем был отступ, поэтому он не был распознан должным образом


В любом случае, вот исправленное 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)

lt;
$(CC) -o $@ $(CFLAGS) $(OBJS)

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

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


lt; -o $@

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

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