OCMVerify and Undefined symbols for architecture i386/armv7/armv7s - ios

I am using OCMock (version 3.1.1) in my project and I am trying to use the OCMVerify macro to check if some method is called inside my object.
The problem is when I put this line:
OCMVerify([mockEngine notify]);
XCode show me the following link error (I've tried all platforms though):
Undefined symbols for architecture i386:
"OCMMakeLocation(objc_object*, char const*, int)", referenced from:
-[T009_EngineTest testPostEvent] in T009_EngineTest.o
ld: symbol(s) not found for architecture i386
I took the last version of the library from the website and I've also tried to compile it by myself.
Here is the unit test code:
Engine *mockEngine = OCMClassMock([Engine class]);
Object *obj = [[Object alloc] init];
[mockEngine startUp];
[mockEngine run];
[mockEngine postEvent:obj];
[NSThread sleepForTimeInterval:0.5];
OCMVerify([mockEngine notify]); // << THIS LINE CREATES THE LINK PROBLEM..
[mockEngine shutDown];
If I comment that line, the compiler links successfully..
It seems that that symbol is not in the library binary but I checked it was in the Xcode Compile Sources list.
Then I did a workaround... I hardcoded this line (the original code from the OCMock) into my unit test file:
OCMLocation *OCMMakeLocation(id testCase, const char *fileCString, int line){
return [OCMLocation locationWithTestCase:testCase file:[NSString stringWithUTF8String:fileCString] line:line];
}
And it works!
Now I want to know if there is some bug in OCMock or am I doing something wrong!
Here is the original header file declaring the external OCMakeLocation function:
https://github.com/erikdoe/ocmock/blob/master/Source/OCMock/OCMLocation.h
and here its implementation:
https://github.com/erikdoe/ocmock/blob/master/Source/OCMock/OCMLocation.m
Thanks.

Related

Linker Command Failed with exit code 1 (Use -v to see invocation) iOS Error

In my application I'm using a static library named ABC.a in that library in a c file named Layout.c there is a function called init(). And I linked the library to the projects and added the .h file. The program is compiled without error but while linking the function its throwing the error. Why?
Info: I've added that static library in build phases also.
And the library is built for armv7, armv7s and arm64. bitcode enabled: No and Build active architectures : NO
Example error:
Undefined symbols for architecture arm64:
"AMID_INIT(int*, int*, int)", referenced from:
-[ViewController microphone:hasAudioReceived:withBufferSize:withNumberOfChannels:] in Test_lto.o
"amid_Val(float const*, int, int*, int, unsigned int)", referenced from:
-[ViewController microphone:hasAudioReceived:withBufferSize:withNumberOfChannels:] in Test_lto.o
Please help two days gone for this.
This is based on the fact that you mention that the .a file is generated from a c file. The linker error:
"AMID_INIT(int*, int*, int)", referenced from:
-[ViewController microphone:hasAudioReceived:withBufferSize:withNumberOfChannels:] in Test_lto.o
indicates that the AMID_INIT definition came from a C++/Objective-C++ file - this is because C files would not have information about the parameters of the routine.
From this I was able to surmise that the library header file did not have c++ guards.
Three approaches in this case - wrap all imports of the library header file in the C++ code with something like:
extern "C" {
#import "lib.h"
}
or create a lib.hpp file, containing:
#pragma once
extern "C" {
#import "lib.h"
}
and #import 'lib.hpp' instead, or fix the lib.h file by adding the standard name mangling preventative:
… near start of lib.h:
#ifdef __cplusplus
extern "C" {
#endif
… near end of lib.h:
#ifdef __cplusplus
}
#endif
This allows you to keep using the lib.h with both C and C++ compilers by declaring that all the routines offered by lib.h are exposed using C linkage, rather than C++ linkage.

.c File via Bridging Header Not Working After Xcode 8 Update

The app I've been working on uses an external library, pdlib, which has it's own externals (.c files) which I've been importing via the bridging header #import "Uzi.c" and calling in my main Swift file via Uzi.c's setup function Uzi_setup() in my ViewController class. I've had no problem with this until after updating to new public Xcode 8 a few days ago (I had no problem with Xcode 8 Beta 1 over the Summer).
Here are the 7 errors I get, listed under a single "Mach-O Linker Error" umbrella:
Undefined symbols for architecture x86_64:
"_Uzi_bang", referenced from:
_Uzi_setup in ViewController.o
"_Uzi_class", referenced from:
_Uzi_setup in ViewController.o
"_Uzi_float", referenced from:
_Uzi_setup in ViewController.o
"_Uzi_new", referenced from:
_Uzi_setup in ViewController.o
"_Uzi_pause", referenced from:
_Uzi_setup in ViewController.o
"_Uzi_resume", referenced from:
_Uzi_setup in ViewController.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Those undefined symbols are 6 functions and a class declare from Uzi.c. Here's a link to the whole c file: https://github.com/electrickery/pd-miXedSon/blob/master/hammer/Uzi.c
I've tried every solution I've found online for dealing with similar problems, with no solution yet... I tried changing the "Architecture" and "Valid Architecture" settings to only armv7 and armv7s (no arm64) and changed "Build Active Architecture Only" to "No". These step seem to help others in similar situations, but they didn't work for me (and taking away arm64 causes additional errors to appear).
XCode 8 is pretty recent (the public version was released Sept. 13), so there are virtually no other questions about this upgrade causing a similar problem.
Any help would be greatly appreciated!
Solved by #danomatika on GitHub: https://github.com/libpd/libpd/issues/149
"You generally shouldn't include/import an implementation file aka .c, .cpp, .m, etc. This is what is causing the duplicate symbol issue.
This is what the "forward function declaration" in the header file is for: to tell the compiler that a function exists and what data it takes/returns. The compiler then assumes the actual implementation of the function exists in an implementation file. If it can't be found, then you get an "undefined symbol error." If you somehow end up declaring the function twice, aka include both a header with the forward declaration and the implemetaton of the function itself in the .c file, then you get a "duplicate symbol error."
This is all lower-level stuff that is only really an issue since Pd externals are designed around being dynamic libraries, so are not built or provided with headers which include the function declarations. This is why you have to do a little extra work and do it yourself.
Their are two easy fixes for this, both of which involve declaring the required function you want to call from the .c file in a header file.
Simply declare the function in the bridging header:
void uzi_setup();
Create a header, say Externals.h, and declare all of the externals stuff there:
// forward declare setup functions only found in .c implementations
void uzi_setup();
// convenience wrapper function
void externals_setup() {
uzi_setup();
}
Then import the file in your bridging header:
#import "Externals.h"
And in swift, you can now do:
externals_setup()

Can't allocate anything from my project - static library (using XCTests)

When i try tests like
#interface My_Tests : XCTestCase
- (void)testExample {
XCTAssertTrue(#YES, #"has to be passed");
}
Everything is working fine. However when i try such pattern:
#import "NSString+Additions.h"
//...
- (void)testNameValidation {
NSString *string = #"Harry";
XCTAssertTrue([string stringIsValid], #"Name validation error");
}
I get:
file:///Users/username/project/ProjectTests/ProjectTest.m: test failure:
-[Project_test testNameValidation] failed: (([string stringIsValid]) is true)
failed: throwing "-[__NSCFConstantString stringIsValid]: unrecognized selector
sent to instance 0x2f58ae8" - Name validation error
I can also just do something like this:
#import "MyViewController.h"
//...
- (void)testSomething {
MyViewController *a = [[MyViewController alloc] init];
XCTAssertTrue(#YES, #"Impossible!");
}
I get 2 errors (first and last line):
Undefined symbols for architecture i386:
"_OBJC_CLASS_$_MyViewController", referenced from:
objc-class-ref in MyTest.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Can someone explain me what am I doing wrong..? I can't do anything with my classes. It may be worth adding that i'm trying to test my custom static library and files included in it. I'm using CocoaPods and I've set environment basing on Kiwi description (only to be able to use CocoaPods files in my tests, I was also wondering whether to use Kiwi or XCTests).
PS. This is my first try with unit tests of any type, so please forgive eventual noobish question ;)
The unit tests aren't linked against the static library.
Add the library to the "Link Binary with Libraries" section of the build phases for the test target.

Undefined symbols for architecture i386 (yes, once again...)

I'm getting crazy about this issue!
One of errors I get is the next one:
Undefined symbols for architecture i386:
"_zipOpen", referenced from:
-[ZipArchive CreateZipFile2:] in ZipArchive.o
The peace of code when I call that method (I use objective-c++ there just in the case it matters):
#implementation ZipArchive
...
-(BOOL) CreateZipFile2:(NSString*) zipFile
{
_zipFile = zipOpen( (const char*)[zipFile UTF8String], 0 );
}
in the .h file I have
zipFile _zipFile;
and in other place:
typedef voidp zipFile;
where
typedef void *voidp;
Ok, I know it shouldn't be working probably. But it worked great before. The things changed with the new target I added for unit test.
I'll greatly thankful for any your help!
Okay, from the error
Undefined symbols for architecture i386:
"_zipOpen", referenced from:
-[ZipArchive CreateZipFile2:] in ZipArchive.o
we can tell that the prototype for zipOpen() function is declared as a C function (extern "C"), as its name isn't mangled.
So, there are basically 2 options why this error is coming up:
The zipOpen() implementation isn't being linked against your program at all (forgot to add the file/library to your build, #ifdef'd out, etc.)
The zipOpen() implementation is getting C++, not C linkage, for some reason. Maybe you've accidentally placed it inside a namespace, or the .cpp file doesn't include the header with the extern "C" declaration of the function.
We can't say which it is based on the information provided.
check wether function declaration inside a header file equals to function prototype in an implementation file

Link error with Objective-C++/C++ in XCode 4.2 Lion (iOS product)

I am new to Objective-C and a bit rusty at using C++ and templates, and I am not sure why I am having this link error.
I have a header file that contains definitions similar to these:
struct Info {
std::string name;
};
typedef std::map<std::string, Info> InfoMap;
void Validate(InfoMap* infoMap);
#interface InfoValidator : NSObject
{
}
+(InfoValidator*) getInstance;
-(void) validate:(InfoMap*)infoMap;
#end
I also have an .mm file that contains the following definition for the (global) Validate() method:
void Validate(InfoMap* infoMap)
{
[[InfoValidator getInstance] validate:infoMap];
}
When I call Validate() from a C++ class (defined in an .mm file), I receive the following error:
Undefined symbols for architecture armv7:
Validate(std::map<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, Info, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, > std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, ?> std::allocator<char> > const, Info> > >*)",
referenced from:
ItemInterface::ValidateItems(int, char const**)in iteminterface.o
ld: symbol(s) not found for architecture armv7
collect2: ld returned 1 exit status
The file has been added to the project, and it is the only link error I get. Thanks for any help.
Did you rename Market_Validate to Validate for the code you've quoted here? The link error refers to the former, which doesn't exist in the code given.
If so, the code looks correct in isolation, I suspect there's something outside the code you've shown going wrong. Make sure both .mm files are in fact being compiled and linked. Check that both include the same header file with your Validate() function declaration. Since you have renamed the function before posting it here, make sure you're using the same name for it throughout your code (specifically, the declaration and definition must match exactly).
Are you using namespaces anywhere? Make sure you didn't accidentally put your function definition inside a namespace if the declaration isn't - they'll be referring to different functions.
Note that the code as you've posted it won't compile, as there's a semicolon missing after your struct Info definition. It's often impossible to help once the code has been altered for the question without testing that the problem still exists with that code. If you're still stuck, I suggest trying to amend the code in this question so it will compile and show the same link error. If you can't reproduce it, take a good look at the differences between your 'real' code and the question code.

Resources