4

I'm trying to create some utility functions that can be called from both Objective-C and C++ code in an iPhone application. I have third party C++ classes that cannot be compiled as ObjectiveC++ (.mm). I have a header file declaring my functions, then a .c file defining them. I've tripled checked for spelling errors, but for some reason my linker is NOT able to find the definition of any of the functions.

Here is the header for the C helper functions:

#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

And here is the .c file:

#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];
}

I've tried compiling with and without the extern "C", but with the same linker error result.

Can anyone shed some light on what I'm doing wrong?

Linker Error:

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

UPDATE: I've seemed to solve the problem by compiling my source file as objective C, even though there was no actual ObjectiveC code, can anyone tell me why the above source file won't compile as C code?

dewhacker
  • 71
  • 1
  • 5
  • check the architecture of the shared library, most probably you were linking your program agaist a arm shared library. just switch to some arm target (the device). – Dyno Fu Sep 11 '11 at 02:46
  • You have a linker problem, so I think your .h file is working fine. Else you would get undefined functions on the compile stage. I would review the way you invoke the linker, maybe you are missing the .o for these functions? – Miguel Grinberg Sep 11 '11 at 02:49
  • @Dyno Fu: Getting closer, you're comment made me notice an odd warning: no rule to process file '$(PROJECT_DIR)/XLoaderTest/Utility/FileLoader.c' of type sourcecode.c for architecture i386, which looks like a weird XCode problem, any suggestions? – dewhacker Sep 11 '11 at 03:02
  • try to add your files to target -> build phases -> compile sources. – Dyno Fu Sep 11 '11 at 04:01
  • check out http://www.cocoabuilder.com/archive/xcode/250342-no-rule-to-process-file.html – Dyno Fu Sep 11 '11 at 04:31

2 Answers2

9

use the following construct to specify c linkage for c and c++ translations:

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

this declaration will be compatible with c, objc, c++, objc++.

justin
  • 104,054
  • 14
  • 179
  • 226
  • Still no luck after trying that, same linker error. The problem may be in the comment I described above with this warning: no rule to process file '$(PROJECT_DIR)/XLoaderTest/Utility/FileLoader.c' of type sourcecode.c for architecture i386, which makes no sense since my project settings are set to active architecture armv6,armv7 – dewhacker Sep 11 '11 at 03:04
  • There is already a definition which does that: `FOUNDATION_EXTERN` – Mr.Yeah Mar 23 '18 at 09:06
  • 1
    @Mr.Yeah Try importing Foundation in a C++ or C translation. – justin Mar 31 '18 at 01:51
  • 1
    @justin I see. I've only looked at it from an iOS development perspective. – Mr.Yeah Apr 04 '18 at 07:34
0

Double check your architecture - the issue from the linker is that it isn't compiling your .c file, not that it can't figure out the linkage. So here's what happens...

Compiler goes through, can't find a way to compile the .c file properly Linker sees external C linkage, says "okay let's see if we can find it" can't find it because the .c file isn't compiled into object code, oh crap, abort.

You need to check your build phase - so go to your targets, select whatever target is active, see what is happening in the compile phase - my guess is that somehow whatever target you're aiming for (release or debug) got this file added as a i386 target instead of arm, which is why it's confused and can't find a rule to compile it (you aren't targeting i386 so it doesn't have rules to compile it).

If all else fails, try making a brand new target for arm and see if you can use it that way, or switch targets from release to debug, etc.

If you show me a snapshot of whatever target you're compiling for I can probably be a lot more helpful :). Good luck!

Travis
  • 544
  • 3
  • 10