Installing Objective-C Compiler

From CodeBlocks
Jump to: navigation, search

Setup the Compiler

Objective-C is a strict superset of C; the additional functionality is obtained by linking to the Objective-C library when building using the standard GNU GCC Compiler. This makes setting up a new compiler very simple, as we can make a copy of the standard compiler and change the linker settings.


Caution: Make sure your GNU GCC Compiler is properly setup before attempting to setup for Objective-C


1) Go to Settings->Compiler and debugger...

2) Select GNU GCC Compiler and make a copy it; name it whatever you like, but "GNU GCC Obj-C Compiler" would be the most descriptive.

3) Under Linker Settings, add -lobjc to Other linker options; you don't need to explicitly add the libobjc.a library, as the flag tells gcc to include it for us.

Adding Filetype Support

1) Go to Settings->Environment...

2) Select Files extension handling and add *.m

3) Go to Project->Project tree->Edit file types & categories...

4) Under Sources, add *.m to the list of filetypes.

Proper Syntax Highlighting

1) Go to Settings->Editor...

2) Select Syntax highlighting and go to Filemasks.... Add *.m to the list of filetypes.

3) Go to Keywords... (next to Filemasks...) and create a new set (up arrow). Add this to the Keywords: box:

Keywords

@interface @implementation @end @class @selector @protocol @public @protected @private id BOOL YES NO SEL nil NULL self

Note: if you feel so inclined, you could create a new custom lexer.

Optional Changes

1) Go to Settings->Compiler and dubugger...

2) Under Other Settings, change Compiler logging to Full command line. If ObjC still refuses to build properly for you, you can use this to compare the command line arguments C::B uses against the commands you would use if you were building the program manually on the command line.

3) Under Other Settings, go to Advanced Options. For Link object files to executable and Link object files to console executable, move -o $exe_output to the end of the macros. For reasons beyond my understanding, GCC will sometimes (albeit rarely) complain during complex builds if this isn't the last argument on the line.

Important Notes

1) By default, C::B will select CPP as the default compiler variable for a new source file, and the file will not be compiled or linked to a target. Whenever you add or create a new ObjC source (*.m) in your project, you must right-click on it and go to Properties.... Under advanced, change the compiler variable to CC. Under Build, select both Compile file and Link file. Before you close the dialog, go to General and uncheck File is read-only. This will automatically get selected when you change the other options and if you close the dialog before you uncheck it, you'll have to go back and change it, then close and reopen the file in the viewer before you can edit it.

2) When you add a header file (*.h), you'll also need to open up its properties window and change the compiler variable to CC. You don't need to do anything else to it.

Troubleshooting

There's a small handful of pitfalls you can fall into when attempting to compile Objective-C applications using TDM-GCC or MinGW, and these pitfalls are unfortunately not well documented. This section tries to identify and solve the currently identified issues; note that these are issues as of the current GCC 4.5.x branch, unless otherwise noted. There is currently no 4.6.x port of GCC for TDM-GCC/MinGW available; the GCC 4.6.x branch introduces an entirely new Objective-C library that brings the ObjC implementation inline with Apple's own implementation of the library. Many of these issues are likely solved in this newest release.

Shared Library Trouble

There has been some trouble with the -lobjc flag trying to link to libobjc.dll.a, which has been a nonfunctional shared library for some time. If this shared library is not removed before compilation, gcc will throw undefined reference to ... errors at every ObjC method or library call during the linking stage. This shared library must be removed, and in the case of TDM-GCC, is located at: [mingw install directory]/lib/gcc/[tdm install type]/[version]/libobjc.dll.a. If you've installed TDM-GCC x64, you must also remove the 32-bit copy of the shared library, located at: ...[version]/32/libobjc.dll.a.

BOOL Redefined

I haven't experienced this error as of TDM-GCC 4.5.2, but on TDM-GCC 4.5.1 and earlier, attempts to build a 32-bit ObjC application that also imports <windows.h> would produce a BOOL redefined error. This is the result of the windows headers defining their own version of BOOL; the headers do make checks to see if ObjC is being used (by checking if __OBJC__ is defined) and change various types and declarations to make themselves compatible, but the ObjC library doesn't define __OBJC__ because it also changes its declarations if this is already defined. You can't simply define __OBJC__ at the beginning of a program however, as it will cause a failure to build with libobjc.a. The proper way to patch in compatibility is to modify the end of objc.h (located at: .../[version]/include/objc/objc.h), and import it in your program before you import the windows headers.

Patch to objc.h

157	IMP objc_msg_lookup(id receiver, SEL op);
158
 158	#define __OBJC__	/* Insert Patch Here */
159	#ifdef __cplusplus
160	}
161	#endif
162
163	#endif /* not __objc_INCLUDE_GNU */

Test Build

Here's a bare-bones project you can throw together to test if your C::B settings will compile ObjC correctly. You can't actually test with just strict C, since any problems with the Objective-C compiler will only manifest when using ObjC functionality.

main.m

#import <stdlib.h>
#import "TestObject.h"

int main(int argc, char** argv)
{
	TestObject *aTestObject = [[TestObject alloc] init];
	printf("Initial Value: %d\n", [aTestObject value]);
	printf("+45 Value: %d\n", [aTestObject add: 45]);
	printf("-63 Value: %d\n", [aTestObject subtract: 63]);

	[aTestObject add: 103];
	printf("+103 Value: %d\n", [aTestObject value]);

	return (EXIT_SUCCESS);
}

TestObject.h

#import <objc/Object.h>

@interface TestObject : Object
{
	int internalInt;
}

- (int)add:(int)anInt;
- (int)subtract:(int)anInt;
- (int)value;

@end

TestObject.m

#import "TestObject.h"

@implementation TestObject

- (id)init
{
	if ((self = [super init]))
	{
		internalInt = 0;
	}

	return self;
}

- (int)add:(int)anInt
{
	internalInt += anInt;
	return internalInt;
}

- (int)subtract:(int)anInt
{
	internalInt -= anInt;
	return internalInt;
}

- (int)value
{
	return internalInt;
}

@end

Objective-C Library Licensing

Unlike other libraries included with GCC, the Objective-C library may be statically linked into a project without extending the GNU GPL to that project. Although the library is covered under the GNU GPL itself, it has a special exemption in its license because it is a necessary library to compile a language.

License Exemption

/* As a special exception, if you link this library with files compiled with
GCC to produce an executable, this does not cause the resulting executable
to be covered by the GNU General Public License. This exception does not
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License */