Calling C function in Objective-C block (Linker error) - iphone

I have created C function:
header
//FileSystem.h file
#import <Foundation/Foundation.h>
BOOL AddSkipBackupAttributeToItemAtURL(NSURL *url);
implementation
//FileSystem.mm
#import "FileSystem.h"
#import <sys/xattr.h>
#import <Support/Support.h>
static const char* attrName = "com.apple.MobileBackup";
BOOL AddSkipBackupAttributeToItemAtURL(NSURL *url) {
BOOL operationResult = NO;
// some implementation
return operationResult;
}
When i'm calling AddSkipBackupAttributeToItemAtURL from another parts of application everything is OK, except one place where i'm calling function from the block.
__block UpdateFileAsyncOperation* selfOperation = self;
_contentDownloader.completionBlock = ^(NSData* data) {
[data saveForcedToPath:selfOperation.filePath];
NSURL* fileUrlWithScheme = [NSURL fileURLWithPath:selfOperation.filePath];
AddSkipBackupAttributeToItemAtURL(fileUrlWithScheme);
[runLoop removePort:port forMode:NSDefaultRunLoopMode];
[selfOperation completeOperation];
};
In that place ,while linking in progress, there is error:
Undefined symbols for architecture i386:
"AddSkipBackupAttributeToItemAtURL", referenced from:
__36-[UpdateFileAsyncOperation start]_block_invoke in UpdateFileAsyncOperation.o ld: symbol(s) not found for architecture
i386 clang: error: linker command failed with exit code 1 (use -v to
see invocation)
I don't understand why it happens, how it depends on block? and how can I fix that?
Thanks!
Update: it is not dependent on block, i have moved calling of function to another place of class: the error still there. I'm trying to find why

I have solved the problem.
It not dependent on block. It dependent on file extensions.
The problem file was with ".m" extension, other files was with ".mm" extension.
So I have putted next macro in FileSystem.h file
#ifdef __cplusplus
extern "C" {
#endif
BOOL AddSkipBackupAttributeToItemAtURL(NSURL *url);
#ifdef __cplusplus
}
#endif

Related

C++ dylib in Swift project - undefined symbols for function exposed in dylib

C++ dylib exposes as follows
__attribute__((visibility("default"))) int addNumber(int number) {
return 0;
}
in my Swift project, I set the Import Paths dir to the dir containing my module.map file:
module MyLib {
header "myLib.h"
export *
}
I manually add myLib.h to my project:
#ifndef mylib_h
#define mylib_h
int addNumber(int number);
#endif
My main.swift does the following:
import Foundation
import MyLib
print("Hello, World!")
var result = addNumber(3)
When I compile the swift project, I can see that it links against my dylib (-lMyLib), but I get the following error:
Undefined symbols for architecture x86_64: "_addNumber", referenced
from:
_main in main.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see
invocation)
So although it's linking correctly, it can't find the symbols.
I've verified both with nm (0000000000000d00 (__TEXT,__text) external addNumber) and Hopper that this function does exist in the dylib.
In the C++ library, your function must be marked with extern "C"
for C linkage:
extern "C" __attribute__((visibility("default"))) int addNumber(int number) {
return 0;
}
so that the compiler does not mangle the exported name. Swift can only
call C functions, not C++ functions.
See also What is the effect of extern "C" in C++?.

Undefined symbols for architecture i386 with CocoaLumberjack and ZXingWidget

I've integrated the ZXing QR Code reader library (ZXingWidget) into my iPhone app, but it conflicts with a function from within the CocoaLumberjack logging library that I am also using.
Undefined symbols for architecture i386:
"ExtractFileNameWithoutExtension(char const*, signed char)", referenced from: ...
DDLog.h
NSString *ExtractFileNameWithoutExtension(const char *filePath, BOOL copy);
#define THIS_FILE (ExtractFileNameWithoutExtension(__FILE__, NO))
DDLog.m
NSString *ExtractFileNameWithoutExtension(const char *filePath, BOOL copy) { ...
As I call it in:
DDLogVerbose(#"%#:%#", THIS_FILE, THIS_METHOD);
The cause for this is that whichever Obj-C file contains the headers:
// import QR Code reader APIs
#import "ZXingWidgetController.h"
#import "QRCodeReader.h"
its file extension must be changed from .m to .mm for proper C++ support.
But then I lose my *DDLogVerbose(#"%#:%#", THIS_FILE, THIS_METHOD);* functionality.
What am I missing here to have these two play nice with each other?
If you're including C headers that aren't "C++-ified" into a C++ or Objective C++ file, you need to tell the compiler. Something like
extern "C" {
#include "DDlog.h"
}
in your .mms should work. Alternatively, if DDLog.h is your file, you can do something like
#ifdef __cplusplus
extern "C"
#endif
NSString *ExtractFileNameWithoutExtension(const char *filePath, BOOL copy);
A web search for "extern C" should provide more details/examples.

Duplicate symbol

I recently added some openfeint code to my classes and changed them to .mm
All of a sudden I get errors that duplicate symbols are found in the object files when building.
ld: duplicate symbol _audioPlayer in blah blah /Objects-normal/i386/Stage2.o and /Users/blah blah .build/Debug-iphonesimulator/blah.build/Objects-normal/i386/Stage1.o
Why is it suddenly causing this error? What exactly is the error?
I have variables with the same name in different classes, it should be a problem?
Thanks
You're probably declaring two variables with the same name in global scope (not inside interfaces), and the linker is complaining about that.
This error can also occur if you import a .m file instead of .h.
#import "SomeClass.m"
The short answer is that you can suppress this error with a command line argument to gcc:
-Wl,--allow-multiple-definition
If you implement your method like below in .mm file, duplicate symbol errorwill occur.
#import <Foundation/Foundation.h>
class CppTestOne
{
public:
void Test();
// {
// NSLog(#"Hello C Plus Plus");
// }
};
void CppTestOne::Test()
{
NSLog(#"Hello C Plus Plus");
}
then you can implement your method by
#import <Foundation/Foundation.h>
class CppTestOne
{
public:
void Test()
{
NSLog(#"Hello C Plus Plus");
}
};
//void CppTestOne::Test()
//{
// NSLog(#"Hello C Plus Plus");
//}
more details for this error not clear

Passing primitive data types by reference in Objective C

I have a C++ function which I call from Objective C.I need to pass variables by reference to the C++ function.But I get the following error in xcode - "Expected ';', ',' or ')' before '&' token in foo.h"
Function declaration in "foo.h"
#ifdef __cplusplus
extern "C"
{
#endif
NSString * LLtoUTM(double Lat,double Long,double &UTMNorthing, double &UTMEasting);
#ifdef __cplusplus
}
#endif
Function call in test_viewcontroller.m
double UTM_x;
double UTM_y;
UTMzone = [[NSString alloc] init];
UTMzone = (NSString *) LLtoUTM(latitude,longitude,UTM_y,UTM_x);
Can anyone tell me what is wrong?
Change the file to be test_viewcontroller.mm.
You told it to compile as an Objective-C file, which doesn't understand references. '.mm' means Objective-C++, which can mix the Obj-C and C++ together like what you're attempting to do.
You simply cannot do this in plain Objective-C — because references don't exist in C. They're a C++ feature. So you have to use Objective-C++, which basically means changing your Objective-C files' extensions to ".mm".

Extracting text from pdf using objective-c(libz.dylib)

I have imported the pdf.h file in my view controller class and tried calling
NSString *outPutString = convertPDF(pathToPdfFile);
but while building it gives me linker error:
_convertPDF" refrenced from: -[ScriptViewController searchBarSearchButtonClicked:] in ScriptViewController.o Symbol(s) not found
I have also included libz.dylib in my project.
What am I doing wrong?
Is there any step to be followed before building the project which includes c code?
Also one more question:
Will this search algorithm work on any PDF(simple and formatted pdfs).
What if you change the name of the .m file that calls pdf.h to xxxx.mm ? It's a c++ file.
I tested it and found out it works only with simple ascii pdfs.
Your must use the definition in the pdf.h
#if __cplusplus
extern "C" {
#endif
NSString* convertPDF(NSString * pathToFile);
#if __cplusplus
}
#endif
also in the implementation file *pdf.m*m use:
#if __cplusplus
extern "C" {
#endif
NSString* convertPDF(NSString * pathToFile);
#if __cplusplus
} //Extern C
#endif