Я пытаюсь написать make-файл, который шаг за шагом проходит компиляцию, проблема находится на четвертом шаге, связывании.
Программа состоит из нескольких файлов, начиная с main.c:
#include "file1.h"
#include "file2.h"
int main() {
printout1("Print one");
printout2(5);
return 0;
}
file1.h
#include <stdio.h>
void printout1(char *str);
file1.c
#include "file1.h"
void printout1(char *str) {
printf("%s\n", str);
}
file2.h
#include <stdio.h>
#include "file1.h"
void printout2(int);
file2.c
#include "file2.h"
void printout2(int val) {
printf("%d\n", val);
printout1("Print two");
}
Я пытаюсь скомпилировать эту программу со следующим make-файлом:
all:
cpp main.c main.i
gcc -S main.i
as -o main.o main.s
ld -o main.o
Возникает следующая ошибка:
ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0
main.o: in function 'main':
main.c:(.text+0xa): undefined reference to 'printout1'
main.c:(.text+0x14): undefined reference to 'printout2'
makefile:2 recipe for target 'all' failed
make:***[all] Error 1
Я новичок в таких вещах, и я знаю, что проблема в файлах заголовков, я просто не знаю, как их включить в это.
где вы компилируете file2.c и file1.c (или связываете их, если на то пошло)?
main.o вызывает printout1, но не связан с объектным файлом, который его предоставляет
Почему ты собираешься собирать? Обычный способ - сгенерировать объектные файлы непосредственно для исходных файлов все, а затем связать все объектные файлы.
Кроме того, при сборке с использованием GCC вам понадобится еще несколько объектных файлов и библиотек, которые программа внешнего интерфейса gcc предоставляет для ld, но вы этого не делаете.
Если невозможно построить его напрямую, определенно невозможно построить его шаг за шагом.
Наконец, если вы хотите пройти подобную сборку и напрямую использовать компоновщик, используйте опцию --verbose для gcc, чтобы увидеть, какие команды, флаги и библиотеки он использует.





Две проблемы с основной:
gcc - это интерфейс для всех необходимых шагов - не пытайтесь напрямую вызывать другие инструменты вашей инструментальной цепочки, всегда используйте gcc. Это гарантирует, что он всегда добавляет необходимые параметры для этих других инструментов.
У вас есть функции в разных единицах компиляции (file1 и file2), но никогда не компилируйте и не связывайте их.
Разумный Makefile для GNU make с вашей структурой будет выглядеть так:
CC ?= gcc
all: main
main: main.o file1.o file2.o
$(CC) -o$@ $^
%.o: %.c
$(CC) -c -o$@ $<
.PHONY: all
Это компилирует все файлы .c непосредственно в объектные файлы и, наконец, связывает их (используя $(CC), например, gcc) с вашим окончательным исполняемым файлом. Правило all помечено как .PHONY, потому что оно не создает файл с именем all - вы должны сообщить об этом make.
Вы, конечно, можете явно добавить дополнительные шаги, но это не имеет особого смысла.
1.) не используйте
ldнапрямую, используйтеgccкак интерфейс, 2.) то же самое дляas, собственно, зачем вам вообще создавать исходный код сборки? 3.) вы когда-либо компилируете и связываете только свой кодmain, так как вы ожидаете, что функции изfile1иfile2будут доступны? 4.)makeне предназначен для написания скриптов, используйте отдельные правила, где целью является файл, созданный этим правилом