Связывание C с C++ в OS X Mavericks

После перехода на OS X Mavericks и XCode 5.0.1 я больше не могу изящно связать скомпилированные файлы C (выходные данные gcc) с проектом C++ (выходные данные g++).

Оскорбительная пара команд, созданных из моего make-файла:

gcc `pkg-config --cflags glib-2.0` -g -Wall -O3 `pkg-config --cflags flann`   -c -o vec.o vec.c
g++ `pkg-config --cflags glib-2.0` -g -Wall -O3   -stdlib=libstdc++ -lstdc++  layoutquality.cpp vec.o  `pkg-config --libs glib-2.0`  -L/usr/local/Cellar/flann/1.8.4/lib -lflann -o layoutquality

На что компоновщик жалуется:

Неопределенные символы для архитектуры x86_64: "load_dmat(char const*)", ссылка из: _main в layoutquality-I8HOqy.old: символ(ы) не найден(ы) для архитектуры x86_64

Где load_dmat — это просто функция в файле vec.c. Если я заменю gcc на g++ в первой строке, то все компилируется и линкуется нормально, но clang говорит:

clang: предупреждение: обработка ввода 'c' как 'c++' в режиме C++, такое поведение устарело

Есть ли безобидный, не устаревший способ их компиляции и связывания? Связывание с g++ вместе с объектными файлами из gcc работало нормально, пока я не обновился до OS X Mavericks и новых инструментов командной строки. Любое понимание того, что изменилось и как двигаться вперед, было бы здорово, спасибо.


person stephen f    schedule 28.10.2013    source источник
comment
Используете ли вы extern "C" в объявлении load_dmat, который скомпилирован в модуль C++? В противном случае компилятор C++ ожидает искаженное имя.   -  person nullptr    schedule 29.10.2013
comment
Нет, не знаю, куда он должен идти? В шапке vec.h или в исходниках vec.c? Тем не менее, я не решаюсь редактировать vec.*, потому что он используется другими проектами C.   -  person stephen f    schedule 29.10.2013
comment
В заголовке приложите свою декларацию, например: extern "C" { void load_dmat(char const*); }. Используйте #ifdef __cplusplus (как в ответе ниже), чтобы сохранить проекты C нетронутыми.   -  person nullptr    schedule 29.10.2013
comment
В любом случае вы можете заменить gcc на clang и g++ на clang++, чтобы привыкнуть не использовать устаревшие символические ссылки для clang.   -  person Nikos C.    schedule 29.10.2013
comment
Не думайте, что это искажение имени. Смотрите мой ответ на @Inspired   -  person stephen f    schedule 29.10.2013
comment
Оба этих ответа повлияют на любой проект. В данном конкретном случае сборка работала, а потом нет. Ни одно из этих решений вряд ли решит проблему, потому что, если бы они были причиной сбоя, то, вероятно, у вас возникла бы эта проблема задолго до этого.   -  person SevenBits    schedule 22.06.2014


Ответы (3)


Добавление «-x c» (без кавычек) перед «vec.c» должно исправить это.

Если вы компилируете несколько файлов .c/.cpp в одной строке, вы можете использовать «-x c» или «-x c++» перед каждым списком имен файлов C или C++ для соответствующего переключения контекста. Например:

g++ -x c  alpha.c beta.c  -x c++  gamma.cpp
person AbePralle    schedule 22.06.2014
comment
Спасибо за совет -x c и -x c++, очень полезный. Но мне нужно указать -std=c++11, чтобы использовать C++11 с моими файлами .cpp. Я получаю error: invalid argument '-std=c++11' not allowed with 'C/ObjC' сейчас. Есть ли способ сделать однострочную сборку с файлами С++ и С, указав стандарт С++ 11? - person bhaller; 27.02.2016
comment
Нет, я не знаю, как сделать однострочную сборку g++ с файлом C и файлом C++ 11, хотя компиляция в промежуточные файлы .o и их последующее связывание должны работать. - person AbePralle; 28.02.2016

Вот пример Makefile, который позволяет нам использовать C++ код/функцию в C программе.

CC=clang
CXX=clang++
CFLAGS=-Wall -g
CXXFLAGS=-Wall -g -std=c++11 -I.

DEPS=CPP.h
OBJ=main.o CPP.o

RM=rm -f

# compile only, C source
%.o: %.c
    $(CC) -c -o $@ $< $(CFLAGS)

# compile only, C++ source
%.o: %.cpp $(DEPS)
    $(CXX) -c -o $@ $< $(CXXFLAGS)

# link
main: $(OBJ)
    $(CXX) -o $@ $^ $(CXXFLAGS)

clean:
    $(RM) $(OBJ)

Как видите, мы генерируем наши объекты отдельно, используя CXXFLAGS и CFLAGS в двух отдельных вызовах компилятора. В контексте Mac, использующего clang Xcode, clang (CC) и clang++ (CXX) на самом деле одно и то же. Имеют значение только разные флаги. Я просто педантичен, указав определения CC и CXX в приведенном выше примере Makefile.

Как только объектные файлы сгенерированы, мы готовы связать их вместе.

Обратите внимание, однако, что вам нужно сделать один дополнительный шаг, чтобы сделать ваш код C++ пригодным для использования программой C.

В этом примере в CPP.h вы должны явно использовать extern "C", чтобы указать связь для вашего кода C++ для использования C.

Например, вот так:

#ifdef __cplusplus
extern "C" {
#endif

double timesTwo(double number);

#ifdef __cplusplus
}
#endif

Макросы препроцессора #ifdef __cplusplus и #endif должны гарантировать, что наш заголовочный файл не вызовет ошибок компиляции в режиме C и действует только во время компиляции в режиме C++.

Этот полный пример содержит только 4 файла.

  • Makefile
  • main.c
  • CPP.ч
  • CPP.cpp

Источник Makefile и CPP.h описаны выше.

Для полного понимания я также включаю сюда main.c и CPP.cpp.

main.c:

#include <stdio.h>
#include "CPP.h"

int main()
{
    printf("Running main.c\n");
    double ans = timesTwo(3.0);
    printf("The answer from our C++ timesTwo function, when given 3.0, is %f\n", ans);

    return 0;
}

CPP.cpp:

#include "CPP.h"

double timesTwo(double number)
{
    return 2 * number;
}

Я надеюсь, что это объяснение и пример проясняют, как мы можем настроить наш Makefile, указать макрос препроцессора #ifdef __cplusplus и объявление компоновки extern "C", чтобы разрешить взаимодействие C++ с C, и без ошибочного предупреждения Clang при запуске make.

person Calvin Cheng    schedule 24.04.2015

Скорее всего, вы стали жертвой изменения имени. Чтобы избежать искажения имен в C++, используйте extern "C" вокруг объявлений, например:

#ifdef __cplusplus 
extern "C" {
#endif
    void load_dmat(char const*);
#ifdef __cplusplus
}
#endif
person nullptr    schedule 28.10.2013
comment
Если это решит проблему, то мне любопытно, как источник мог быть построен и связан раньше. - person bames53; 29.10.2013
comment
Спасибо за указание на изменение имени, но, к сожалению, это не решает проблему. Я добавил редактирование в свой vec.h, и ошибка компоновщика сохраняется. - person stephen f; 29.10.2013