make: неявное правило для связи проекта c ++ - PullRequest
15 голосов
/ 29 марта 2011

Я прорабатываю учебник по 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 не работает.

Я мог бы указатьправила, но вы хотите научиться использовать неявные правила.

Ответы [ 7 ]

14 голосов
/ 29 марта 2011

Согласно инструкции make , вы можете использовать правило неявного связывания с несколькими объектами, если один из них соответствует имени исполняемого файла, например:

VPATH = src include
CPPFLAGS = -I include

main: implementation.o
main.o: header.hpp
implementation.o: header.hpp

Это создаст исполняемый файл с именем main как из main.o, так и реализационного. O. 1006 *

Обратите внимание, что встроенное неявное правило использует компилятор C для компоновки, который по умолчанию не связывается с библиотекой C ++ std, вам нужно явно добавить это в LDFLAGS

6 голосов
/ 29 марта 2011

Как насчет этого для минимального 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 $@ $^

clean::
    $(RM) prog

.cpp.o:
    $(CXX) -MD -MP $(CXXFLAGS) -o $@ -c $<

clean::
    $(RM) src/*.o

DEPENDS = $(SOURCES:.cpp=.d)

-include $(DEPENDS)

%.d:
    @touch $@

clean::
    $(RM) src/*.d

Это предполагает GNU make и gcc, но добавляет правильное отслеживание зависимостей, поэтому нет необходимости явно перечислять зависимости файла заголовка.

5 голосов
/ 29 марта 2011

Там должно быть неявное правило для прог, или я что-то упустил?

Не существует неявного правила. make не может знать, как создать prog, потому что не знает, что prog должен быть исполняемым файлом. make использует имя файла только как шаблон для вывода правила сборки. prog - это общее имя файла без расширения, поэтому make не знает, как с ним обращаться.

3 голосов
/ 12 ноября 2015

Мой ответ (изящное решение): добавьте

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 к CXX, который выглядит как взлом, а также сбивает с толку читателей.

LDFLAGS vs LDLIBS

Я только что попробовал и обнаружил, что этот компилятор неработает для LDFLAGS = -lstdc++:

  • GCC 4.8.5 в Ubuntu 14.04

, но следующие компиляторы принимают LDFLAGS = -lstdc++:

  • Clang3.4 в Ubuntu 14.04
  • GCC 4.7.2 в Debian Wheezy
  • Clang 7.3.0 (703.0.31) в OS X

Так что он работает большую частьвремя, но не гарантировано.Если вы хотите, чтобы ваш make-файл был более переносимым, используйте LDLIBS, который работает во всех вышеперечисленных средах.

Почему нет других решений выше?

  1. Hasturkun: иметь main.o в правиле

    main: main.o implementation.o
    

    не приводит к ошибке.main.o не является необходимым, но он все равно будет иметь значение.

  2. Саймон Рихтер: решение устраняет необходимость отслеживать заголовок (что действительно здорово), но 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» - это еще одна огромная тема, заслуживающая всего учебника (например, , этот ).Так что извините, но его ответ на самом деле не ответил на вопрос.

  3. Джером: Раньше я менял LINK.o с $(CC) $(LDFLAGS) $(TARGET_ARCH) на $(CXX) $(LDFLAGS) $(TARGET_ARCH), и это работало, ноЯ предпочитаю редактировать LDLIBS, так как LINK.o не документирован (и, возможно, не является частью общедоступного API) и не предназначен для будущего.Я бы назвал это хаком.

1 голос
/ 29 апреля 2015

Неявное правило для связывания объектных файлов:

$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@

Но $(LINK.o) использует $(CC), что не совсем корректно для компиляции программ на C ++, поэтому самое простое исправление:

CC = $(CXX)
0 голосов
/ 08 февраля 2019

Если вы хотите связать объектные файлы c ++, вы можете указать LINK.o, чтобы быть LINK.cc вверху

LINK.o := $(LINK.cc)

Затем вы должны увидеть g++ вместо cc в вашем make вывод

0 голосов
/ 29 марта 2011

Хмм ...

CXX = g++               # Just an example
CXXFLAGS = -Wall -O2    # Just an example

prog: main.o implementation.o
    $(CXX) $(CXXFLAGS) $^ -o $@

main.o: header.hpp
implementation.o: header.hpp

должен сделать эту работу.Почему ваш вариант не работает, объясняется в Конрад Рудольф ответ

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...