2016-02-15 3 views
2

Я пытаюсь скомпилировать два файла c, calutil.c и calutil.h в один исполняемый файл. Вот мой Makefile:Makefile: «ld: невозможно связать с основным исполняемым файлом» в C

CC = gcc 
CFLAGS = -Wall -std=c11 -DNDEBUG 

all: caltool 

caltool: calutil.o caltool.o 
    $(CC) $(CFLAGS) calutil.o caltool.o 

caltool.o: caltool.c 
    $(CC) $(CFLAGS) caltool.c -o caltool.o 

calutil.o: calutil.c 
    $(CC) $(CFLAGS) -c calutil.c -o calutil.o 
clean: 
    rm -rf *.o *.out 

calutil.c не имеет main, в то время как caltool.c имеет main. я получаю ошибку

ld: can't link with a main executable file когда я make. Какова причина этого?

+0

Какую версию 'make' вы используете? Для того, что вы хотите достичь, ваш 'Makefile' может быть слишком сложным, особенно когда вы используете GNU make. –

+0

Эй, пользуюсь 3.81. Любые упрощения были бы удивительными. – MortalMan

+0

Отсутствует второе правило '-c', поэтому' caltool.o' является * полной программой *, а не объектным файлом. – immibis

ответ

0

Основная проблема заключается в том, что некоторые ваши рецепты для связи не хватает выходного файла и что ваша компиляция отсутствует -c.

В случае, если вы используете GNU сделать следующее Makefile будет достаточно, чтобы делать то, что вы хотите сделать:

CFLAGS:=-Wall -std=c11 
CPPFLAGS:=-DNDEBUG 

.PHONY: all 
all: caltool 

caltool: caltool.o calutil.o 

.PHONY: clean 
clean:: 
     $(RM) *.o 

Объяснение:

  • Когда вы не используете target- конкретные переменные, вы должны использовать := вместо = для назначения переменных, чтобы они были расширены при назначении, а не при оценке.
  • Когда ваш Makefile растет, и вы его разделяете, вы можете захотеть иметь несколько целей под названием clean, которые будут выполнены. В этом случае используйте clean:: вместо clean:.
  • Там в предопределенную переменную для вызова rm, это $(RM) и включает в себя -f флаг, чтобы предотвратить Makefile от сбоя в случае, если один или несколько файлов, подлежащих удалению, не существует в первую очередь.
  • Шаблон для clean должен быть *.[adios] (что очень легко запомнить, прощай испанский для свидания), так что она удаляет промежуточные архивы (.a при создании собственных статических библиотек), файлы зависимостей (.d), выход препроцессора (.i) и ассемблерных файлов (.s), если вы используете -save-temps, чтобы узнать, что делает компилятор.
  • GNU сделать имеет встроенные правила для компиляции и компоновки, см http://git.savannah.gnu.org/cgit/make.git/tree/default.c?id=3.81
    • Встроенный правило для компиляции вызывает $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o [email protected] $< так что вам не нужно писать собственное правило.
    • Встроенный правило для связи вызывает $(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o [email protected]
  • Цели, которые не сами файлы должны быть объявлены .PHONY, чтобы избежать путаницы, когда пользователь создает файл с таким же именем, как all или clean.
  • Я не вижу, как любая из ваших команд создаст файл, соответствующий шаблону glob *.out, поэтому я удалил эту часть правила clean.
  • Флаги для препроцессора должны быть отправлены в CPPFLAGS вместо CFLAGS. Флаги препроцессора, как правило, представляют собой все эти -D и -I флаги, а также передаются другим инструментам, использующим препроцессор C в том же проекте, например splint или PC-Lint.

Когда Makefile запускается, он ищет, как сделать all, и он считает, что для all он должен сделать caltool. Для caltool он находит, что он должен сначала сделать calutil.o и caltool.o. Когда он пытается сделать calutil.o и caltool.o, он находит, что он может сделать их от calutil.c и caltool.c и сделает это. Затем он свяжет caltool.o и calutil.o в caltool.

От вашего имени я догадался, что это caltool.c, который содержит функцию main(). Полезно поместить объект, содержащий main(), первый раз, когда вы используете статические библиотеки ссылок.

Редактировать: Вот еще волшебство для вас. Я предполагаю, что у вас есть файл заголовка calutil.h, который включен caltool.c для доступа к внешним символам, предоставленным calutil.c. Вы хотите перестроить все объекты, которые зависят от этих файлов заголовков. В этом случае, добавьте следующие строки в Makefile:

CPPFLAGS+=-MMD 
-include caltool.d calutil.d 

Для того, чтобы не иметь список объектов несколько раз, вы можете добавить переменную objects так:

objects:=caltool.o calutil.o 

Вы бы тогда построить приложение с этим правилом:

caltool: $(objects) 

И включать файлы зависимостей, как это:

-include $(objects:.o=.d) 

В случае, если вы держите ваше рабочее дерево «чистым», то есть не «загрязняет» его с «чужим» кодом, то есть вы всегда хотите включить все .c файлов в вашем проекте, вы можете изменить определение objects как следующим образом:

sources:=$(wildcard *.c) 
objects:=$(sources:.c=.o) 

в случае, если вы удивляетесь, почему это CPPFLAGS (в верхнем регистре), но objects (в нижнем регистре): он обычно используется верхний регистр для всех переменных, которые настроить рецепты правил и контроля встроенного поведения make , инструменты, построенные поверх него, и классические переменные окружения, а также переменные нижнего регистра для всего остального.

+0

Это какое-то колдовство. Я не ожидал получить такую ​​помощь от этого вопроса, спасибо Кристиан! – MortalMan

1

Я просто удалил файлы .o из каталога и отредактировал мой файл makefile, чтобы добавить -c в строку caltool.o.

Смежные вопросы