Plugins Can Be Fun (Part Two: g++)

| | Comments (2)

Last time, we covered the basics behind what a REALbasic plugin was, and how they worked -- so if you didn't read that posting, you will want to go read it now. We put that knowledge to use with Microsoft Visual Studio 2005 and built the most basic plugin possible for Windows.

Today we're going to take our knowledge and apply it to g++ (a variation of gcc, really) on Linux for building a shared library object to act as our REALbasic plugin. At the end of the post, we'll have made the same empty shell that we did last time.

gcc is the de facto standard for writing C/C++ applications on Linux, and it is nothing more than a command line utility for turning source code into executable code. Because of this, most of the work involved in getting a plugin set up is figuring out what command line options to pass in. To make our lives easier, we're going to create a very simple makefile to help out. Essentially, this makefile (and by extension, the command line arguments we use) will be taking the place of the file list and settings from Visual Studio.

As with our last example, I start off by making a folder to hold my source code, and I copy in the Plugin SDK files that I want to use. This time, we need to copy over LinuxHeader.h (which is akin to WinHeader++.h, only for Linux instead of Windows), macTypesForAnsi.h (which houses a bunch of typedefs that the SDK uses), rb_plugin.h and REALplugin.h (which are the main SDK header files) and PluginMain.cpp (the definition for the plugin SDK). Once we have those files, we have everything from the SDK that we require -- the next step is to create a main source file to put our plugin's source code.

I create a source file on the command line by doing: vi main.cpp

This pops me into my favorite command line file editor, where I enter in the same source code from last time:


#include "rb_plugin.h"

void PluginEntry( void )
{

}

Voila! We're done -- that's all the more source code we need. Easy, right? Well, I lied...we're not really done. We still have to create the makefile so that we can compile everything. To be honest, the makefile is entirely optional -- you could just type everything in. However, that gets very tedious and doesn't scale well, so that's why I'm starting you off with a makefile. Keep in mind that (1) I'm not a makefile wizard, and (2) I'm showing you the simplest possible makefile.

I am going to start off by showing you the entire makefile, and then explaining it piece by piece.


CC = g++

PERMISSIVEFLAG = -w -fpermissive
CFLAGS = -s -O2 -D__INTEL__ -D__GCC__
PREFIXHEADER = LinuxHeader.h

OBJS = main.o PluginMain.o

main.o: main.cpp
$(CC) $(PERMISSIVEFLAG) $(CFLAGS)
-include $(PREFIXHEADER) main.cpp -c

pluginmain.o: PluginMain.cpp
$(CC) $(PERMISSIVEFLAG) $(CFLAGS)
-include $(PREFIXHEADER) PluginMain.cpp -c

clean:
rm *.o -f

all: $(OBJS)
$(CC) $(CFLAGS) -shared -o libTestPlugin.so $(OBJS)


If you've never seen a makefile before, it may look intimidating. The thing to keep in mind is that a makefile is like a very simplistic programming language -- it's a script that eventually executes a command in the shell. This makefile exposes two commands: make all (which compiles everything and makes the shared library) and make clean (which removes any intermediate files).

CC = g++
This line specifies which compiler we're going to use, which is g++. But if we decided we wanted to use gcc, or something else instead, we could set it here, and everywhere that uses the $CC variable would get the change. This is a common mechanism you'll see in the makefile -- we set up a variable to represent the optional stuff, and then use the variable everywhere we actually do work.

PERMISSIVEFLAG = -w -fpermissive
This makes the compiler whine a lot less about things. If you hate warnings, turn it on. If you want warnings, just remove it entirely.

CFLAGS = -s -O2 -D__INTEL__ -D__GCC__
These are the flags that we pass in to the compiler or linker. The -s tells the linker to strip out relocation data and other symbols from the executable, which makes it smaller. It's totally optional. -O2 sets the optimization level to be not-quite-insane (it's middle of the road), and it's also optional. For a debug build, you'd probably not want either of those options turned on. -D sets up some #defines for the file being compiled. In this case, we're specifying that __INTEL__ and __GCC__ are defined.

PREFIXHEADER = LinuxHeader.h
This is the prefix header which every file must include before anything else. To make sure this happens, we just include it from the command line instead of having to remember to do it manually in all of your source files.

OBJS = main.o pluginmain.o
This is the list of objects that the linker will link together to form the final executable.

main.o: main.cpp
	$(CC) $(PERMISSIVEFLAG) $(CFLAGS) -include $(PREFIXHEADER) main.cpp -c
Finally -- some work! Whenever the makefile needs to make something named main.o, it knows that it's going to be working with main.cpp. We use the $CC variable to do the compiling, and pass in the permissive flags, compiler flags, manually include the prefix header and compile main.cpp. The -c option tells the compiler to just compile the file into a .o file (with the same name as the source file), but don't link it to anything (that will happen later).

The next line is basically the same as the previous, except it specifies PluginMain.cpp instead of main.cpp. Every new source file you add is going to look the same, with only the file name and object name changed.

clean:
	rm *.o -f
This is the clean command, which executes a simple remove statement.
all: $(OBJS)
	$(CC) $(CFLAGS) -shared -o libTestPlugin.so $(OBJS)
Here's where all of the magic happens -- the "all" command. It will use the $CC variable to do the compiling, and passes in the expected compiler and linker flags. We're telling it to build a shared library by using the -shared command, and specifying the output file name to be libTestPlugin.so with the -o command. Finally, we tell it what objects to link together by using the $OBJS variable.

One thing to note is that Linux is generally a case-sensitive file system (unless you happen to be compiling on a VFAT or other case-insensitive file system), so you need to make sure that the case of files are sane. Specifically, watch out for .cpp file names, and .o file names. You'll notice that in my $OBJS line, I use PluginMain.o -- that's because PluginMain.cpp will compile to PluginMain.o, not pluginmain.o. It's annoying, but that's why people seem to love Linux.

Ok, so if you pop onto a command line and enter "make all", then you should end up with a libTestPlugin.so, and you've created a very simple (and entirely useless) REALbasic plugin for Linux.

2 Comments

And, since gcc is the compiler in use on OS X, you could use much the same procedure on OS X (although XCode makes that kind of pointless)

With something like minGW couldn't you use gcc on all three platforms ?

I believe you could use the same type thing on MinGW. My guide (that I hope to update with some of this, with Aaron's permission, and after I finish major school projects) has setup instructions for Dev-C++ which is based on MinGW. http://jdiwnab.no-ip.org/program/other/plugin-tutorial.php

Leave a comment

Disclaimer

I'm currently an employee of REAL Software. My blog is mine. The opinions represented in this blog are mine as well and may not represent my employer's opinions. All original material is copyrighted and property of the author.

REALbasic® is a registered trademark of REAL Software, Inc. REAL SQL Server™ and Lingua™ are pending trademarks of REAL Software, Inc. All rights reserved.