Как правильно объединить флаги g cc -o и -MM? - PullRequest
1 голос
/ 29 апреля 2020

Во время компиляции и компоновки простой программы я столкнулся со странным поведением gcc, которое я не могу объяснить.

Это здесь прекрасно работает для меня

cc -Wall -c -o obj/main.o src/main.c
cc -Wall -c -o obj/foo.o src/foo.c
cc -Wall -o bin/program obj/main.o obj/foo.o

Однако, как только я прошу gcc создать и сохранить информацию о зависимостях в отдельном файле, компоновщик выдает ошибку:

cc -MM -MP -MF deps/main.d -Wall -c -o obj/main.o src/main.c
cc -MM -MP -MF deps/foo.d -Wall -c -o obj/foo.o src/foo.c
cc -Wall -o bin/program obj/main.o obj/foo.o
# obj/main.o: file not recognized: File truncated
# collect2: error: ld returned 1 exit status

Я ожидаю, что gcc запишет информацию о зависимости в файл, поставляемый с -MF заявление. Похоже, что объектные файлы каким-то образом изменены, так что компоновщик больше не может их читать.

Есть предложения?

1 Ответ

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

Ваши объектные файлы усекаются до 0 байтов в качестве побочного эффекта опции препроцессора -MM

Обратитесь к документации по параметрам препроцессора G CC , и вы обратите внимание, что -MM имеет тот же эффект, что и -M, за исключением того, что правила зависимости не генерируются в отношении каких-либо системных заголовков #include -ed единицей перевода.

Для опции -M, вы увидите:

Вместо вывода результата предварительной обработки выведите правило, подходящее для make, описывающее зависимости основного исходного файла ...

А также:

Передача -M драйверу подразумевает -E ...

И, обратившись к опции -E, вы увидите:

Если вы используете опцию -E, ничего не делается, кроме предварительной обработки.

(Это на самом деле немного неаккуратно. На самом деле это должно выглядеть так: «Если вы используете опцию -E, перевод не выполняется за исключением предварительной обработки. ")

Параметр -o filename указывает, что какой бы тип файла вывода не запрашивался - предварительно обработанный код, сборка, объектный код или двоичный файл - он должен быть записан в filename.

Так, например, команда

cc -MM -MP -MF deps/main.d -Wall -c -o obj/main.o src/main.c

дает команду компилятор (между прочим): -

  • Не выполнять трансляцию после предварительной обработки (подразумевается -E).
  • Не выводить результат предварительной обработки; вместо этого выведите правило зависимости (-MM)
  • Не записывайте правило зависимости в выходной файл (obj/main.o); вместо этого запишите в него deps/main.d (-MF deps/main.d)

В результате выходной файл obj/main.o будет засорен и открыт для получения результатов предварительной обработки; там равно нет результатов предварительной обработки; сгенерированное правило зависимости записывается в deps/main.d, а после завершения команды obj/main.o закрывается, содержит 0 байтов. То же самое происходит с obj/foo.o.

Конечно, это не то, что вы хотите. Опции -M и -MM полезны только для генерации файлов зависимостей независимо от компиляции. Но вы хотите, чтобы команда генерировала файл зависимостей deps/<name>.d и , чтобы продолжить преобразование вплоть до объектного кода, выведя в obj/<name>.o

Чтобы сделать то, что вы хотите, замените опция -MM с -MMD в ваших командах. В документации вы увидите:

-MD

-MD эквивалентно -M -MF файлу, за исключением того, что -E не подразумевается ... Так как -E не подразумевается, -MD может использоваться для генерации выходного файла зависимости как побочный эффект процесса компиляции.

-MMD

Как -MD, за исключением упоминания только пользователя заголовочные файлы, а не системные заголовочные файлы.

[мой акцент]

...