#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)