Make: неявное правило для ссылки на проект С++
Я работаю над учебником. Очень простые тестовые проекты, которые я пытаюсь создать, имеют только 3 файла: ./src/main.cpp./src/implementation.cpp и ./include/header.hpp Это файл make.
VPATH = src include
CPPFLAGS = -I include
main: main.o implementation.o
main.o: header.hpp
implementation.o: header.hpp
При вызове без каких-либо аргументов make строит только объектные файлы, но не связывает исполняемый файл. Предполагалось, что это неявное правило для prog или я чего-то не хватает? Мне действительно нужно, чтобы кто-то указал мне в правильном направлении.
Спасибо.
Я сделал первое имя цели таким же, как префикс исходного файла. Теперь вызовите cc, чтобы связать файлы объектов.
g++ -I include -c -o main.o src/main.cpp
g++ -I include -c -o implementation.o src/implementation.cpp
cc main.o implementation.o -o main
По какой-то причине ссылка на g++ работает, но ссылка на cc не работает.
Я могу явно указать правило, но хочу узнать, как использовать неявные правила.
Ответы
Ответ 1
В соответствии с make manual вы можете использовать правило неявного связывания с несколькими объектами, если одно из них соответствует исполняемому имени, например:
VPATH = src include
CPPFLAGS = -I include
main: implementation.o
main.o: header.hpp
implementation.o: header.hpp
Это создаст исполняемый файл named main из main.o и implementation.o.
Обратите внимание, однако, что встроенное неявное правило использует компилятор C для связывания, который по умолчанию не связывается с библиотекой std С++, вам нужно явно указать это в LDFLAGS
Ответ 2
Как насчет этого для минимального Makefile:
SOURCES = src/main.cpp src/implementation.cpp
CXX = g++
CXXFLAGS = -g -W -Wall -Werror
LDFLAGS = -g
OBJECTS = $(SOURCES:.cpp=.o)
prog: $(OBJECTS)
$(CXX) $(LDFLAGS) -o [email protected] $^
clean::
$(RM) prog
.cpp.o:
$(CXX) -MD -MP $(CXXFLAGS) -o [email protected] -c $<
clean::
$(RM) src/*.o
DEPENDS = $(SOURCES:.cpp=.d)
-include $(DEPENDS)
%.d:
@touch [email protected]
clean::
$(RM) src/*.d
Это предполагает GNU make и gcc, но добавляет правильное отслеживание зависимостей, поэтому нет необходимости явно перечислять зависимости файлов заголовков.
Ответ 3
Там должно быть неявное правило для prog или я что-то не хватает?
Нет никакого неявного правила. make
не может знать, как построить prog
, потому что он не знает, что prog
должен быть исполняемым. make
использует только имя файла в качестве шаблона для вывода правила сборки. prog
- это общее имя файла без расширения, поэтому make
не знает, как его обрабатывать.
Ответ 4
Мой ответ (аккуратное решение): добавьте
LDLIBS = -lstdc++
в Makefile. В соответствии с руководство:
Библиотеки (-lfoo
) следует добавить вместо переменной LDLIBS
.
LDFLAGS
предназначены для флагов каталога библиотеки, таких как -L
. На моем Linux (Ubuntu 14.04) LDFLAGS = -lstdc++
создает
cc -lstdc++ main.o -o main
который не работает, а LDLIBS = -lstdc++
производит
cc main.o -lstdc++ -o main
который работает. Я понятия не имею, почему порядок имеет значение, но он имеет смысл в соответствии с ролями двух встроенных переменных. Мне не нравится псевдоним CC
to CXX
, который кажется взломанным, а также запутанным для читателей.
LDFLAGS v.s. LDLIBS
Я просто попытался и обнаружил, что этот компилятор не работает для LDFLAGS = -lstdc++
:
- GCC 4.8.5 на Ubuntu 14.04
но следующие компиляторы принимают LDFLAGS = -lstdc++
:
- Clang 3.4 на Ubuntu 14.04
- GCC 4.7.2 на Debian Wheezy
- Clang 7.3.0 (703.0.31) на OS X
Поэтому он работает большую часть времени, но не гарантируется. Если вы хотите, чтобы ваш make файл был более переносимым, используйте LDLIBS
, который работает во всех вышеперечисленных средах.
Почему другие решения выше?
-
Хастуркун: имеющий main.o
в правиле
main: main.o implementation.o
не приводит к ошибке. main.o
не требуется, но он все равно сделает.
-
Саймон Рихтер: решение устраняет необходимость отслеживать заголовок (что действительно здорово), но OP хочет неявное правило. Мы действительно можем получить лучшее из обоих:
VPATH = src include
CPPFLAGS = -I include -MMD -MP
CXXFLAGS = -g -W -Wall -Werror
LDLIBS = -lstdc++
target = main
lib = implementation.cpp
objects = $(target:=.o) $(lib:.cpp=.o)
$(target): $(objects)
%.o: %.cpp %.d
%.d: ;
-include $(objects:.o=.d)
clean::
$(RM) $(target) $(objects) $(objects:.o=.d)
который делает то, что он сделал, а также использует неявные правила. Однако этого полного решения не должно быть здесь, поскольку это не то, чего хочет OP: OP просто хочет знать, почему его Makefile не работает и почему. "Auto-Dependency Generation" - еще одна огромная тема, заслуживающая полного учебника (например, этот). Так что я сожалею, но его ответ фактически не ответил на вопрос.
-
Jerome: Я использовал для изменения LINK.o
от $(CC) $(LDFLAGS) $(TARGET_ARCH)
до $(CXX) $(LDFLAGS) $(TARGET_ARCH)
, и он работал, но я предпочитаю редактировать LDLIBS
, поскольку LINK.o
не документирован (и, возможно, не является частью общедоступного API), а не в будущем. Я бы назвал это хаком.
Ответ 5
Хм...
CXX = g++ # Just an example
CXXFLAGS = -Wall -O2 # Just an example
prog: main.o implementation.o
$(CXX) $(CXXFLAGS) $^ -o [email protected]
main.o: header.hpp
implementation.o: header.hpp
должен выполнить эту работу. Почему ваш вариант не работает, объясняется в Конрад Рудольф ответ
Ответ 6
Неявное правило для связывания объектных файлов:
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o [email protected]
Но $(LINK.o)
использует $(CC)
, что не совсем корректно для компиляции программ на С++, поэтому самое легкое исправление:
CC = $(CXX)