[ Last Update 12 March 2003 20.41 EST ]
Compiling
Lightwave Plugins using
Borland C++ Builder v 3.0
by Carl Looper
This discussion covers the main steps required to compile a Lightwave plugin using Builder v 3. The source code can be any of the SDK examples but this discussion assumes the SDK box example.
The SDK files are assumed to be located as follows:
C:\Lwsdk\include
C:\Lwsdk\source
C:\Lwsdk\sample
and that we will use the following folder as the location for our plugin project:
C:\MyPlugin\
Start Builder and select: File -> New...

We see the following window.

Choose DLL and click OK.
Builder generates the following
code:

We can delete the comments in box.cpp. They are irrelevant to this project.
We save this project as "Box.bpr" in "C:\MyPlugin". The result is that the above file becomes "box.cpp"

OK, we now copy/paste the SDK box source code (C:\Lwsdk\sample\boxes\box1\box.c) into our source code.
The result is the following:
|
//--------------------------------------------------------------------------- /* A Modeler plug-in that makes a box. Ernie
Wright 28 May 01 #include
<lwserver.h>
if ( version != LWMODCOMMAND_VERSION
) sprintf( cmd, "MAKEBOX
<%g %g %g> <%g %g %g> <%d %d %d>", return AFUNC_OK; //--------------------------------------------------------------------------- |
Now we need to add some files to this project. All Lightwave plugins can use these files so the SDK suggests building a library of the files but, instead, we'll be explicitly adding them to this project.
To do so we need the "Project Manager"

The following window becomes visible:

We right click on "box" (not on "box.cpp") to get a "context menu' of options. The one we want is "Add".

We navigate to the "source" directory of the SDK (C:\Lwsdk\source) and choose all the files there:

The following lines appear in our box.cpp source code, just below our include statements:
| USEUNIT("..\Lwsdk\source\username.c"); USEUNIT("..\Lwsdk\source\servdesc.c"); USEUNIT("..\Lwsdk\source\servmain.c"); USEUNIT("..\Lwsdk\source\shutdown.c"); USEUNIT("..\Lwsdk\source\startup.c"); USEDEF("..\Lwsdk\source\serv.def"); |
Now we need
to tell Builder where to find the SDK include files.
Select: Project -> Options ...

Select the Directories/Conditionals" tab ...

Click on the
button for the include path. The resulting window allows us to tell Builder
the location of the SDK include files.

Enter the path and click Add. The path is added to the list of include paths.
We are now ready to build our plugin.

Unfortunately, this results in the following error:
| [C++Error] box.cpp(44): Cannot convert 'int (*)(long,void * (*)(const char *,int),st_LWModCommand *,void *)' to 'int (*)(long,void * (*)(const char *,int),void *,void *)'. |
Hmmm. Perhaps we need to recast "Activate".
So, comment out the original Server Record block and put in an alternative.
My thanks to Sensei for this one. (My original alternative here, while it worked, was quite mad)
| /* ServerRecord ServerDesc[] = { { LWMODCOMMAND_CLASS, "Tutorial_Box1", Activate }, { NULL } }; */ ServerRecord ServerDesc[]
= { |
Rebuild ...

The DLL succeeds in building. That's good.
A quick test in Modeller, and, good grief, it works.
But while the above approach works we had to force a cast on "Activate". As it turns out, this was because we had wrapped box.c inside box.cpp, ie. as a C++ file.
Under C++, Builder regarded the attempt at Activate's pointer conversion as illegal. So we had to explicitly cast it.
What we really need to do is compile box.c as a C file instead. This way we only get a "suspicious pointer conversion" warning (which is much better than an error). It means we don't have to change any source code.
So the much better alternative approach is as follows:
|
1. Select a DLL project as before but save the project under another name, ie. other than box, eg. as "mybox.bpr" 2. Leave the Builder generated "mybox.cpp" as is. Don't change anything. 3. As before, use the Project Manager to "add" all the files in the SDK source folder (serv.def etc.) to the project. But this time, also add box.c (C:\Lwsdk\sample\boxes\box1\box.c). 4. Finally build "mybox" |
The resulting DLL is "mybox.dll".
And it works in Modeller as expected.
Checking with the Lightwave Plugin Mailing List we get the following response from Ernie regarding the above tutorial.
| Excellent--I
wish more people would do stuff like this.
The only question I'd have is about adding the SDK source/ files to the project, which is how I always do it. Ordinarily you wouldn't want to add servdesc.c or username.c. You only need those if you *don't* have a ServerRecord in your plug-in somewhere. |
Hmmm. So this explains the Linker warning we had:
| [LinkerWarning] Public symbol '_ServerDesc' defined in both module C:\MYPLUGIN\BOX.OBJ and C:\LWSDK\SOURCE\SERVDESC.OBJ. |
So, armed with Ernie's advice we remove "username.c" and "servdesc.c" from the project ...

And rebuild "mybox".
The only warning left now is the suspicious pointer conversion:
| [C++Warning] box.c(33): Suspicious pointer conversion. |
The pointer conversion is intentional so the warning can be safely ignored.
A quick test in Modeller ... and once again, "mybox.dll" works in Modeller as expected.
What about the Preprocessor Defines mentioned in the SDK? While it didn't seem to be necessary we had better put them in ...
Select: Project -> Options -> Directories/Conditionals ...

In "Conditional defines" add: _X86_;_WIN32;
EXTRA STUFF ...
OBJECT FILES
When Builder compiles the DLL it generates temporary "object" files in the same location as your source files. If you want Builder to put these object files elsewhere (ie. rather than throughout your source folders) you can specify a folder for such.
For example, if we want Builder to put all the temporary object files in a folder called "myobjects" then we would do the following:
Select: Project -> Options -> Directories/Conditionals
Enter "myobjects" for "Intermediate output":

Click "OK".
If the folder doesn't already exist Builder will seek confirmation to create it:

Click "Yes"
Now, when we build "mybox" all the object files will be written to:
C:\MyPlugin\myobjects
STANDALONE DLL
If we are not careful we may find that when we ship our DLL to another machine we get a "cannot find xxxx.dll" error. While none of the SDK examples will have this problem our own plugins might.
The simplest solution is to produce a "standalone" DLL. Any Builder specific components we might use are embedded in the DLL itself rather than requiring a link (ie. to another possibly absent DLL) at runtime:
Step 1. Select: Project -> Options -> Packages

If the "Build with runtime packages" checkbox is checked (lower left) then uncheck it.
Step 2. Select the Project Options Linker tab ...

If the "Use dynamic RTL" checkbox is checked (upper left) then uncheck it.