Ошибка компоновщика при использовании extern C в коде Objective-C

Я пытаюсь создать некоторые служебные функции, которые можно вызывать как из кода Objective-C, так и из кода C++ в приложении iPhone. У меня есть сторонние классы C++, которые нельзя скомпилировать как ObjectiveC++ (.mm). У меня есть файл заголовка, объявляющий мои функции, а затем файл .c, определяющий их. Я трижды проверил орфографические ошибки, но по какой-то причине мой компоновщик НЕ смог найти определение ни одной из функций.

Вот заголовок для вспомогательных функций C:

#ifndef FILE_LOADER_H
#define FILE_LOADER_H

#if __cplusplus
extern "C" {
#endif

void * loadDataFromFile(const char * szFilename, bool bDocument);
void * loadImageFromFile(const char * szFilename, bool bDocument);
void loadMeshFromFile(const char *szFilename, void* pMesh);

#if __cplusplus
}   // Extern C
#endif

#endif

А вот файл .c:

#include "FileLoader.h"
#include <objc/objc.h>
#include <objc/message.h>
#include <Foundation/Foundation.h>


void * loadDataFromFile(const char * szFilename, bool bDocument)
{
    Class loaderClass = NSClassFromString(@"Loader");
    void * pReturnVal = objc_msgSend(loaderClass,   NSSelectorFromString(@"loadDataFromFile:document"), szFilename, bDocument);
    return pReturnVal;
    //return [Loader loadDataFromFile:szFilename document:bDocument];
}
void * loadImageFromFile(const char * szFilename, bool bDocument)
{
    Class loaderClass = NSClassFromString(@"Loader");
    void * pReturnVal = objc_msgSend(loaderClass, NSSelectorFromString(@"loadImageFromFile:document"), szFilename, bDocument);
    return pReturnVal;
    //return (void*)[Loader loadImageFromFile:szFilename document:bDocument];
}
void loadMeshFromFile(const char *szFilename, void* pMesh)
{
    Class loaderClass = NSClassFromString(@"Loader");
    objc_msgSend(loaderClass, NSSelectorFromString(@"loadMeshFromFile:mesh"), szFilename, pMesh);
    //[Loader loadMeshFromFile:szFilename mesh:pMesh];
}

Я пробовал компилировать с внешним "C" и без него, но с тем же результатом ошибки компоновщика.

Может ли кто-нибудь пролить свет на то, что я делаю неправильно?

Ошибка линкера:

Undefined symbols for architecture i386:
"loadMeshFromFile(char const*, void*)", referenced from:

ОБНОВЛЕНИЕ: кажется, я решил проблему, скомпилировав свой исходный файл как объектный C, хотя не было фактического кода ObjectiveC, может ли кто-нибудь сказать мне, почему приведенный выше исходный файл не будет компилироваться как код C?


person dewhacker    schedule 11.09.2011    source источник
comment
проверьте архитектуру разделяемой библиотеки, скорее всего, вы связывали свою программу с разделяемой библиотекой руки. просто переключитесь на какую-либо цель руки (устройство).   -  person Dyno Fu    schedule 11.09.2011
comment
У вас проблема с компоновщиком, поэтому я думаю, что ваш файл .h работает нормально. В противном случае вы получите неопределенные функции на этапе компиляции. Я бы проверил, как вы вызываете компоновщик, может быть, вам не хватает .o для этих функций?   -  person Miguel    schedule 11.09.2011
comment
@Dyno Fu: Подойдя ближе, ваш комментарий заставил меня заметить странное предупреждение: нет правила для обработки файла '$(PROJECT_DIR)/XLoaderTest/Utility/FileLoader.c' типа sourcecode.c для архитектуры i386, который выглядит как странная проблема с XCode, есть предложения?   -  person dewhacker    schedule 11.09.2011
comment
попробуйте добавить свои файлы в цель -> этапы сборки -> исходники компиляции.   -  person Dyno Fu    schedule 11.09.2011
comment
проверьте cocoabuilder.com/archive/xcode/   -  person Dyno Fu    schedule 11.09.2011


Ответы (2)


используйте следующую конструкцию, чтобы указать связь c для переводов c и c++:

#if !defined(__cplusplus)
#define MONExternC extern
#else
#define MONExternC extern "C"
#endif
// declare loadMeshFromFile
MONExternC void loadMeshFromFile(char const*, void*);

это объявление будет совместимо с c, objc, c++, objc++.

person justin    schedule 11.09.2011
comment
После попытки все еще не повезло, та же ошибка компоновщика. Проблема может быть в комментарии, который я описал выше с этим предупреждением: нет правила для обработки файла '$(PROJECT_DIR)/XLoaderTest/Utility/FileLoader.c' типа sourcecode.c для архитектуры i386, что не имеет смысла, поскольку настройки моего проекта настроены на активную архитектуру armv6,armv7 - person dewhacker; 11.09.2011
comment
Уже есть определение, которое делает это: FOUNDATION_EXTERN - person Mr.Yeah; 23.03.2018
comment
@Mr.Yeah Попробуйте импортировать Foundation в переводе C++ или C. - person justin; 31.03.2018
comment
@Justin Я вижу. Я смотрел на это только с точки зрения разработки iOS. - person Mr.Yeah; 04.04.2018

Дважды проверьте свою архитектуру - проблема компоновщика заключается в том, что он не компилирует ваш файл .c, а не в том, что он не может определить связь. Итак, вот что происходит...

Компилятор проходит, не может найти способ правильно скомпилировать файл .c Компоновщик видит внешнюю связь C, говорит: «Хорошо, давайте посмотрим, сможем ли мы ее найти», не может ее найти, потому что файл .c не скомпилирован в объект код, о дерьмо, прервать.

Вам нужно проверить свою фазу сборки - так что перейдите к своим целям, выберите любую активную цель, посмотрите, что происходит на этапе компиляции - я предполагаю, что каким-то образом к любой цели, к которой вы стремитесь (выпуск или отладка), был добавлен этот файл как цель i386 вместо arm, поэтому он запутался и не может найти правило для его компиляции (вы не ориентируетесь на i386, поэтому у него нет правил для его компиляции).

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

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

person Travis    schedule 11.09.2011