objective c gnustep - cannot separate interface and implementation files - objective-c

I am using gnustep for objective-c on windows. If i keep interface and implementation files of a class together with main file, it compiles without error and gives expected output.
Following is the example:
// File "classA.h"
#import <Foundation/Foundation.h>
#interface classA: NSObject
{
int a;
}
-(void) print;
#end
// File "classA.m"
#import "classA.h"
#implementation classA
-(void) print
{
a = 10;
NSLog(#"a = %i", a);
}
#end
// File "test.m"
#import "classA.h"
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSLog(#"start");
classA *objA = [[classA alloc] init];
[objA print];
[objA release];
NSLog(#"done");
[pool drain];
return 0;
}
However, if i put the interface and implementation files separately, on compiling using following command
gcc `gnustep-config --objc-flags` -o program program.m -L /GNUstep/System/Library/Libraries -lobjc -lgnustep-base
i get following error
undefined reference to `__objc_class_name_myNewClass'
collect2: ld returned 1 exit status
How do i keep the files separate and still compile the program successfully
Thanks for help
Regards

You have a linker error here. Most likely, you are not including a required header file for myNewClass.

I know this is old, but double check the name of compiled files just in case the error is in a different file.
Reasons:
The class myNewClass is not referenced in the code above and there are no other imports other than Foundation.
The name of the file in the code comments and the file you appear to be compiling differ.
// File "test.m"
gcc `gnustep-config --objc-flags` -o program program.m
By the look of it, the given code should compile when split out.
Also, about the question "Also how do i included "Compiled files"?", assuming you mean a .o file, you just need to include the header file (.h) and make sure the compiler can find the matching .o file. Related: How do I link object files in C? Fails with "Undefined symbols for architecture x86_64"

Related

Can an Objective-C implementation be defined in a header file and also be imported by multiple source files?

I am aware this is not standard or conventional, please read on. I have a header file that defines the interface and implementation of an Objective-C class.
Person.h
#ifndef Person_h
#define Person_h
#interface Person : NSObject
-(void)speak;
#end
#implementation Person
-(void)speak
{
// Say something
}
#end
#endif /* Person_h */
I also have two source files that both include the header file.
Main.mm
#import Foundation;
#import "Person.h"
int main(int argc, const char * argv[])
{
// Do nothing
}
Test.mm
#import Foundation;
#import "Person.h"
When the project is built, I get duplicate symbol errors.
duplicate symbol '_OBJC_CLASS_$_Person' in:
/Debug/TestBox.build/Objects-normal/x86_64/main.o
/Debug/TestBox.build/Objects-normal/x86_64/test.o
duplicate symbol '_OBJC_METACLASS_$_Person' in:
/Debug/TestBox.build/Objects-normal/x86_64/main.o
/Debug/TestBox.build/Objects-normal/x86_64/test.o
ld: 2 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I want to be able to include the same header file in multiple source files. In C++, I can inline the implementation into the header file like this:
#ifndef Person_h
#define Person_h
class Person
{
public:
void speak()
{
// Say something
}
};
#endif /* Person_h */
However, I haven't been able to find a way to do that with Objective-C. I'm using Objective-C so I can subclass events from NSWindowDelegate and NSResponder.
I tried searching for solutions. Most of them said to separate the implementation into a source file, but that would break the single-header architecture. One suggestion is to use the Objective-C runtime library and create my classes at runtime. This appears to give me the results I'm looking for, but I'm wondering if there is a simpler way.
Is there some way to implement an Objective-C class in a header file so it can be included by multiple source files? Or is dynamically creating the classes at runtime my best option?
Update
I am looking for a solution that avoids using a .m or .mm file to write the Objective-C implementation. Even if doing so is not the conventional way to do it. The single-header file is required by the architecture of the project I am working on. The project is cross-platform, and the single-header design isn't an issue in C++ on Windows and Linux. Adding a source file to define Objective-C objects would break the existing architecture.
Thats not purpose of header file. In header file you will define properties and methods which you want to make available where needed.
Implementation always lies within .m file in case of Objective C.
EDIT
Sure thing, of course you can ... I've removed the previous failed attempt to remove clutter.
// main.m
#import <Foundation/Foundation.h>
#import "A.h"
#import "B.h"
#import "C.h"
int main(int argc, const char * argv[])
{
#autoreleasepool
{
NSLog(#"Hello, World!");
[[A alloc] init];
[[B alloc] init];
[[C alloc] init];
}
return 0;
}
// A.h, repeat for B.h and C.h
#import <Foundation/Foundation.h>
#interface A : NSObject
#end
// A.m
// B.m and C.m are quite similar
// BUT drop the line below from B and C
#define ZIMP
#import "A.h"
#import "Header.h"
#implementation A
- ( id ) init
{
self = super.init;
[[[Z alloc] init] msg:#"A"];
return self;
}
#end
Now for the grand finale
// Header.h
#import <Foundation/Foundation.h>
#interface Z : NSObject
- ( void ) msg:( NSString * ) src;
#end
#ifdef ZIMP
#implementation Z
- ( void ) msg:( NSString * ) src
{
NSLog( #"%# says hi", src );
}
#end
#endif
The proof of the pudding ... here is the output
2020-07-15 07:29:52.134413+0200 HdrImp[26901:700649] Hello, World!
2020-07-15 07:29:52.135121+0200 HdrImp[26901:700649] A says hi
2020-07-15 07:29:52.135297+0200 HdrImp[26901:700649] B says hi
2020-07-15 07:29:52.135389+0200 HdrImp[26901:700649] C says hi
Program ended with exit code: 0
The trick is of course to get the compiler to see the implementation only once, even though the header file is included several times. This is accomplished with nothing but a single #define.
Now we can tell the Swift guys that Objective-C can be done with just a single source file.
UPDATE
This works because I know precisely which files will be included and I can set the guard in one of them. If you do not know beforehand which of the files will be part of the compile you have a problem but you can solve that with more defines and by some code in your make file where you 'know' which of the files will be included and can take action based on that.
You need to understand the different purposes of header (.h) and module (.m) files:
The correct usage is this:
A Header file just declares the types and what they are composed of. It is like saying to the compiler: Look, somewhere is a class named Person, and you can call speak on it. It does not tell the compiler the internals of the speak function, it just announces that this type exists somewhere.
This is called a type declaration.
When the compiler translates the Main.mm file, it creates a call to a yet-unknown, external function speak. It does the same for Test.mm.
Then, after compilation of your code, the linker runs to resolve all the unknown addresses, e.g. it checks if there is one and exactly one definition of a class Personwith a function speak. If there is no such definition, you get an unresolved symbol error. If there are multiple definitions, you get your duplicate symbol error.
Therefore, you need to create a Module file to define all your classes - exactly once. In your case you need a file Person.m, which contains the #implementation of the class (and functions).
Types can be declared multiple times, but may only be defined once.
What you did wrong: When you put your type definition into the header file, the compiler creates two implementations of your class (when translating Main.mm and the other when translating Test.mm), which then confuses the linker, because the linker expects exactly one.
You can have a central header file which aggregates all types and sub-includes, but you need one (or more) separate module files - and you must not include them, because the linker resolves the references for you.

Undefined symbols for architecture x86_64 in hello world

Today I'm learning Objective-C without Xcode following this Guide
Here's the hello world:
makclass.m
#import "makclass.h"
#import <stdio.h>
#implementation MakClass
-(void) age {
printf("Age is %d", age);
}
-(void) setAge: (int) a {
age = a;
}
+(void) say {
printf("Haha");
}
#end
makclass.h
#import <Foundation/NSObject.h>
#interface MakClass: NSObject {
int age;
}
-(void) age;
-(void) setAge: (int) a;
+(void) say;
#end
helloworld.m
#import <stdio.h>
#import "makclass.h"
int main(void) {
printf("Hello World");
MakClass *makclass = [[MakClass alloc] init];
[makclass setAge: 1];
[makclass age];
[MakClass say];
[makclass release];
return 0;
}
And clang helloworld.m give me the following errors:
Undefined symbols for architecture x86_64:
"_OBJC_CLASS_$_MakClass", referenced from:
objc-class-ref in helloworld-XEijke.o
"_objc_msgSend", referenced from:
_main in helloworld-XEijke.o
"_objc_msgSend_fixup", referenced from:
l_objc_msgSend_fixup_alloc in helloworld-XEijke.o
l_objc_msgSend_fixup_release in helloworld-XEijke.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
You need to make sure you pass in the framework and all the files as well:
clang -framework Foundation -o helloworld helloworld.m makclass.m
Welcome to Objective-C!
When you compile, you need to specify all of the implementation files that helloworld.m requires. Just because the header files are included does not mean that the implementation files will be included as well.
Additionally, since this is Objective-C, make sure you also include the -lObjC flag to include the Objective-C libraries.
So, the command that you should run will look like clang -lObjC helloworld.m makclass.m.
clang will then spit out a program called a.out, which you can run. If you want to change the name from a.out to, say, helloworld, you can specify that with the -o flag. For example:
clang -lObjc -o helloworld helloworld.m makclass.m
Hope this helps!

error: ‘NSString’ undeclared (first use in this function)

I am getting this error when i try to compile Object-c program in cygwin Windows 7, but this program executed in Xcode.
main.m:5:3: error: ‘NSString’ undeclared (first use in this function)
#include <stdio.h>
int main (int argc, const char * argv[])
{
NSString *str1 = #"1st string";
NSString *str2 = #"2nd string";
NSLog(#"Hello, World!");
return 0;
}
Executed using the following CMD in cygwin,
gcc -c -Wno-import main.m
can you one help me how solve this compilation error.
Windows doesn't come with a Foundation library, so NSString isn't available by default. You should try GNUstep or you could cross-compile from Xcode on a Mac using Cocotron. Whichever you choose, look at its documentation to find out how to use it (at a minimum you'll need to #import <Foundation/Foundation.h> and link the Foundation library).
Make sure that you are have the following code at the top of your .h or .m file:
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
You can also put the code in your Prefix.pch file.

Objective C compilation with gcc 4.6.2

I am trying to learn objective c on windows. My program compiles with warnings
My code is
#include <objc/Object.h>
#interface Greeter:Object
{
/* This is left empty on purpose:
** Normally instance variables would be declared here,
** but these are not used in our example.
*/
}
- (void)greet;
#end
#include <stdio.h>
#implementation Greeter
- (void)greet
{
printf("Hello, World!\n");
}
#end
#include <stdlib.h>
int main(void)
{
id myGreeter;
myGreeter=[[Greeter alloc] init];
[myGreeter greet];
[myGreeter release];
return EXIT_SUCCESS;
}
I compile my program on GNUStep using the following command
gcc -o Greeter Greeter.m -I /GNUstep/System/Library/Headers -L /GNUstep/System/Libra
/Libraries -lobjc -lgnustep-base -fconstant-string-class=NSConstantString
I get the following warnings on compilation
: 'Greeter' may not respond to '+alloc' [enabled by default]
: (Messages without a matching method signature [enabled by default]
: will be assumed to return 'id' and accept [enabled by default]
: '...' as arguments.) [enabled by default]
: no '-init' method found [enabled by default]
: no '-release' method found [enabled by default]
And so when I run my executable the object does not get instantiated.
I am using gcc from MinGW where gcc version is 4.6.2
--UPDATE---
The program runs fine when I extend from NSObject instead of Object
--UPDATE 2 ----
My Object.h looks like
#include <objc/runtime.h>
#interface Object
{
Class isa;
}
#end
--UPDATE 3 ----
I have modified my code as follows. It compiles fine, but I am not sure if this is the right way to go about things
#interface Greeter
{
/* This is left empty on purpose:
** Normally instance variables would be declared here,
** but these are not used in our example.
*/
}
- (void)greet;
+ (id)alloc;
- (id)init;
- release;
#end
#include <stdio.h>
#implementation Greeter
- (void)greet
{
printf("Hello, World!\n");
}
+ (id)alloc
{
printf("Object created");
return self;
}
- (id)init
{
printf("Object instantiated");
return self;
}
- release {}
#end
#include <stdlib.h>
int main(void)
{
id myGreeter;
myGreeter=[[Greeter alloc] init];
[myGreeter greet];
[myGreeter release];
return EXIT_SUCCESS;
}
Unless you are studying the history of Objective-C, trying to learn the language based on the Object class is a complete waste of time. The Object class was last used commonly as a root class in pre-1994 NEXTSTEP.
If your goal is to learn pre-1994 Objective-C, then state that because, if so, the answers you have so far are entirely wrong. Even if the goal is to go with modern patterns, the answers are more along the lines of How do I recreate NSObject? than anything else. Note that if that is your goal.... well... go for it! Pre-1994 Objective-C was kinda like OOP macro-assembly and, through that, there was a ton of power through at the metal simplicity.
For example, you say that "I have modified my code as follows. It compiles fine, but I am not sure if this is the right way to go about things".
That code compiles, but -- no -- it doesn't work. Not at all. For starters, the +alloc method doesn't actually allocate anything. Nor does the Greeter class implement near enough functionality to act anything like an NSObject.
If your goal is to learn something akin to modern Objective-C and use Windows to do so, the best possible way would likely to be to install the GNUStep toolchain. With that, at least, you would be programming against an NSObject rooted set of APIs akin to modern Cocoa (and, to a lesser extent, iOS).
If your goal is to learn truly modern Objective-C, you'll want an environment that can run the latest versions of LLVM, at the very least. And, of course, if you want to write Objective-C based iOS or Mac OS X apps, you'll want a Mac running Lion.
From memory, the Object class does not implement retain counts, so it wouldn't have release, it'll have free or some other method. It should have +alloc and -init though. Since there's no “Objective-C standard”, you'll have to open up your objc/Object.h and see exactly what it offers.
Note that on GCC 4.6.2, objc/Object.h actually includes objc/deprecated/Object.h, meaning support for Object as a class may be fairly limited. If it doesn't include it, try including it yourself:
#import <objc/deprecated/Object.h>
Import Foundation.
#import <Foundation/Foundation.h>
Extend NSObject instead of Object.
#interface Greeter : NSObject
What I did was to install gcc-4.6 alongside the 4.7 that came with the linux system.
It seems to work, as it has a compatability layer for older code.
In my basic Makefile I specify
> CC=gcc-4.6
> LIBS=-lobjc -lpthread
>
> all: objc-test.m
> $(CC) -o objctest objc-test.m $(LIBS)
There is nothing "wrong" with using and older version of gcc.
The new 4.7 version has gutted
the objc system so it is not a stand-alone compilation suite. That sucks. I imagine there is some reason, possibly a political one, possibly just that it is difficult to make one compiler do it all for everyone. I have successfully made objc programs with gnustep in X86_64 Linux with gcc 4.7.3 after banging out failure for two days the old way.
It involves a bunch of setup:
setting up the environment variables with
source /usr/share/GNUstep/Makefiles/GNUstep.sh
and conforming to their build system.
A Basic GNUmakefile:
include $(GNUSTEP_MAKEFILES)/common.make
TOOL_NAME = test
test_OBJC_FILES = main.m
include $(GNUSTEP_MAKEFILES)/tool.make
for
main.m:
#import <Foundation/Foundation.h>
int
main (void)
{
NSLog (#"Executing");
return 0;
}
running
gs_make
builds the binary in a subdir obj.
It is actually quite frustrating to fight with the build system like that
and have to spend hours teasing out tidbitsfrom docs just to get basic functionality
from such a great compiler. I hope they fix it in coming iterations.
Have you tried with [Greeter new]; ? Open Object.h and take a look at the methods defined in the Object class...
EDIT:
To implement the alloc, retain and release you have to call the objc runtime.
So.. I think you have to write something like this:
#interface RootObject : Object
+ (id)alloc;
- (id)init;
- (id)retain;
- (void)release;
#end
#implementation RootObject
{
unsigned int retainCount;
}
+ (id)alloc
{
id myObj = class_createInstance([self class], 0);
/* FOR NEWBIES this works for GCC (default ubuntu 20.04 LTS)
id myObj = class_createInstance(self, 0);
*/
return myObj;
}
- (id)init
{
retainCount = 1;
return self;
}
- (id)retain
{
retainCount++;
return self;
}
- (void)release
{
retainCount--;
if (retainCount == 0) {
object_dispose(self);
}
}
#end
And then you can subclass RootObject.

Simple self contained Objective C file

I'm trying to run through all the Objective C I possibly can as fast as I can for my new job. I've divided up my training so I do 1/2 with cocoa tutorials and I thought it also made sense to try to learn Objective C from a general perspective as well so the other 50% i'm trying to learn out of the "Programming In Objective C" book by Stephan Kochan (2004). Many of his examples up through the first 50 pages or so seem to imply that there is a way to make a simple class (interface, implementation, and main) all in the same file. I have been trying to compile this in the mac Snowleopard terminal for the sake of speed, but as soon as I call a method inside the main I get compile errors.
I know its not my gcc compiler because the file will compile, and I can even write a printf statement, but as soon as I try to call a method, I get compile errors. I would appreciate it if someone could demonstrate a simple inclusive objectivec.m file that actually works with a method call.
here's my code
#import <stdio.h>
#import <objc/Object.h>
#interface testing1 : Object
{
int number;
}
-(void) setNum:(int)a;
-(void) print;
#end
#implementation testing1;
-(void) setNum:(int) a{
number = a;
}
-(void) print{
printf("this is the number %i \n", number);
}
#end
int main(int argc, char* argv[] )
{
//testing1 *test =[testing1 new];
//[test setNum: (int)34];
printf("testing");
//[test print];
}
this will compile in the terminal with --- gcc tester1 -o myProg -l objc
I've tried to call those methods several different ways but it does not work
any help is appreciated. Perhaps I need to break it up and use make - I don't know
Thanks
MIke
You have ; at the end of #implementation -
#implementation testing1; // Semi colon shouldn't be present at the end
With that modification made, you should see the result. Online result of the program
[test setNum: (int)34];
Here typecasting 34 to int is unnecessary. You can just pass the message setNum to reference test with 34 followed by colon.
[test setNum:34 ];
Interface declarations should go in header while the implementation to source files. Only source files get compiled. Before even the compilation phase, pre-processor just copies the content of all imported files to the translation units. So,
testing.h
#import <Foundation/NSObject.h>
#interface testing1 : NSObject
{
int number;
}
-(void) setNum:(int)a;
-(void) print;
#end
testing.m
#import <stdio.h>
#import "testing.h"
// You should definitely import just stdio.h header here because of printf function usage
// testing.h also to be imported or else compiler doesn't know what is testing1.
#implementation testing1
-(void) setNum:(int) a{
number = a;
}
-(void) print{
printf("this is the number %i \n", number);
}
#end
main.m
#import <stdio.h>
#import "testing.h"
int main(int argc, char* argv[] )
{
testing1 *test =[testing1 new];
[test setNum: 34];
printf("testing");
[test print];
return 0;
}
Now you need to compile the two source files from which corresponding object files are generated. Linker combines these object files to give the final executable.
gcc -o test testing.m main.m -framework Foundation
Run -
./test
The book you're following is out of date. The Object class was effectively deprecated way back in 1994 with the introduction of OpenStep.
In Objective-C 2.0, the Object class simply isn't available at all. That's why your program produces compiler warnings/errors.
You should instead subclass NSObject and import <Foundation/Foundation.h>. Use the -framework Foundation gcc parameter, instead of -l objc.
First of all, you used #import <stdio.h>. You only need that when your using C only. Delete the sentence and use this instead.
#import <Foundation/Foundation.h>
Secondly, why are you using #import <objc/Object.h>? The "<" and ">" are only for frameworks. If you want to import another file you made, use #import "Object.h" instead. (Unless you're talking about NSObject, then you don't need to import anything because it is part of the Foundation framework.)
And lastly, you should take away the semicolon after the #implementation because it's unnecessary.