g ++ таинственно не работает, только если .h находится в определенной директории - PullRequest
6 голосов
/ 24 февраля 2010

У меня очень странная проблема в новой установке OSX 10.4.11 + Xcode 2.5. Я сократил это до минимального теста. Вот test.cpp:

#include "macros.h"

int main (void)
{
    return 1;
}

А вот macros.h:

#ifndef __JUST_TESTING__
#define __JUST_TESTING__

template<typename T> void swap (T& pT1, T& pT2)
{
    T pTmp = pT1;
    pT1 = pT2;
    pT2 = pTmp;
}

#endif //__JUST_TESTING__

Это компилируется и прекрасно работает, если оба файла находятся в одном каталоге. ОДНАКО, если я помещу macros.h в / usr / include / gfc2 (это часть пользовательской библиотеки, которую я использую) и изменю #include в test.cpp, компиляция завершится с этой ошибкой:

/usr/include/gfc2/macros.h:4: error: template with C linkage

Я исследовал эту ошибку, и большинство комментариев указывают на «висячий внешний C», который, похоже, совсем не тот.

Я в полной растерянности. Является ли g ++ по какой-то причине, предполагая, что все в /usr/include/gfc2 является C, хотя он включен из файла .cpp, который нигде не говорит extern «C»?

Есть идеи?

РЕДАКТИРОВАТЬ: он компилируется, если я использую полный путь в #include, то есть #include "/usr/include/gfc2/macros.h"

РЕДАКТИРОВАТЬ 2: Это не включая неправильный заголовок. Я подтвердил это, используя cpp, g++ -E и переименовывая macros.h в foobarmacros.h

Ответы [ 6 ]

7 голосов
/ 24 февраля 2010

G ++ вполне может предполагать, что все, что находится в / usr / include - это C. Попробуйте скомпилировать свой код с -E и изучить строчные маркеры в выводе препроцессора:

g++ -E test.cpp | grep '^#'

Вы, вероятно, увидите такие вещи, как

# 1 "/usr/include/gfc2/macros.h" 1 3 4

4 - это препроцессор, намекающий на G ++, что он должен обернуть все в extern "C", при условии, что древние заголовочные файлы вашей платформы в / usr / содержат предшествующую C ++. См. Выход препроцессора в руководстве по CPP.

В наши дни G ++ в основном игнорирует эту подсказку, потому что заголовки C большинства платформ больше не являются древними. См. Целевой макрос NO_IMPLICIT_EXTERN_C в руководстве по внутренним компонентам GCC. Но может случиться так, что в этой старой версии XCode настроен GCC без NO_IMPLICIT_EXTERN_C, и, таким образом, означает , слушая подсказку препроцессора. (Это устанавливается при сборке самого GCC - я не думаю, что есть ключ командной строки для его переопределения.)

Вы можете обойти это, обернув содержимое заголовочного файла в extern "C++".

1 голос
/ 24 февраля 2010

Это выстрел в темноте, но есть ли другой файл с именем macros.h где-то под /usr/include или в вашей установке GCC? В GCC есть средство для упаковки заголовков, которое называется #include_next, что может стать причиной вашей проблемы.

Одна вещь, которую вы можете сделать для устранения неоднозначности вашего macros.h с любым другим macros.h в пути включения, - включить его как gfc2/macros.h. Таким образом, компилятор будет искать каждый каталог в пути включения для подкаталога с именем gfc2, содержащего файл с именем macros.h, уменьшая вероятность конфликта. Это также предотвращает добавление /usr/include/gfc2 к пути включения.

Кстати, #include "file.h" сначала ищет текущий каталог. Чтобы пропустить это и перейти прямо к пути включения, используйте #include <file.h>:

#include <stdio.h>
#include <gfc2/macros.h>

Другой подход заключается в выборе имени файла, которое с большей вероятностью будет уникальным, например gfc2macros.h.

0 голосов
/ 20 апреля 2010

Я только что столкнулся с этой проблемой и при компиляции проекта C ++, который мы обычно строим на 10.5 и 10.6 (Xcode 3.0+) на машине 10.4 PPC с установленным Xcode 2.5. Похоже, что препроцессор обрабатывает все, что добавлено в путь включения gcc, с помощью '-isystem', как если бы оно было "extern C". Изменение '-isystem' на '-I' решило проблему.

0 голосов
/ 24 февраля 2010

Вы можете увидеть, где g ++ ищет включения с подробным флагом:

g++ -v -o test test.cpp

И это просто запустит препроцессор и покажет, что на самом деле включено в файл и скомпилировано:

g++ -E test.cpp | less

Если будут включены неправильные файлы (или ваш заголовок обернут в другой, как предполагает bk1e), вы сможете узнать с помощью этого вывода.

0 голосов
/ 24 февраля 2010

Вы пытались вообще не изменять файл test.cpp, а вместо этого при компиляции также говорят:

-I/usr/include/gfc2/
0 голосов
/ 24 февраля 2010

Ну, это действительно выглядит странно ...

Как XCode вызывает g ++? Я не думаю, что g ++ самопроизвольно решает, что включаемый файл имеет связь C только потому, что он находится в другом каталоге. Вы пытались скомпилировать свой проект вручную? Попробуйте "g ++ main.cpp -I / usr / include / gfc2 /". Если это решит вашу проблему, то это не g ++. Может быть, XCode прекомпилирует заголовки?

...