Developing C++ NLMs
Articles and Tips: article
Software Engineer
NetWare Products Division
01 Mar 1995
This DevNote describes a library of C++ classes that can be used as an interface to NetWare Directory Services (NDS). These classes provide an improved platform for NDS application development by providing an object-oriented approach to software development and by using the more advanced coding techniques available through the C++ language.
- Introduction
- Tools
- Client Configuration
- Server Configuration
- Watcom Compiler
- Link
- Debug
- DSBROWSE
- Concerns
- Summary
Introduction
With the increasing acceptance of the C++ programming language and with NetWare as an important application platform, the desire to develop C++ NetWare Loadable Modules is growing. I will demonstrate how to compile, link and source-level debug a simple NetWare Directory Services (NDS) browser NLM. I will also address some C++ NLM concerns.
The sample project included in this article is DSBROWSE . It is a C++ NLM built with Watcom and Novell tools. It will allow viewing or "walking" of the NDS tree loaded on the server on which it is run.
Tools
NLM development is best done with two computers. A client workstation is used for editing, building and remote debugging. A NetWare server is required for running and testing the NLM.
Watcom Compiler
I chose to use the Watcom C/C++ 10.0 compiler. Although Watcom is the only compiler I am aware of that supports NLM development, they have been doing it for many years. Their C++ support came out in the compiler version 9.5 and was updated twice with patch A and patch B. Version 10 with patch A is the latest version and was used for development of DSBROWSE. So this compiler is not new to the NLM environment nor to C++. This compiler supports many features expected from a C++ compiler and development environment, including templates, exception handling, I/O streams and source-level debugging.
If your Watcom compiler version 10 does not have the patch A applied to it, you may obtain it directly from Watcom. Watcom has a BBS and FTP site with technical forums on many of their products. These forums can be used to communicate with other users or Watcom technical support staff. These forums have file areas where the latest patches can be downloaded. Watcom also supplies a readme.log file for this product that includes all the bugs and enhancements that are known and that have been fixed for the next patch.
In order to patch the compiler, download c_a.zip (5,052,025 bytes) and ch_a.zip (5,953,803 bytes) files from file area 17 - "Watcom C/C++ 10.0 Problems and Fixes" forum on Watcom's BBS. See the end of this DevNote for the access instructions. The files are also available via anonymous ftp from ftp.watcom.on.ca in directory "/pub/bbs/lang_v10.0/c".
It is necessary to install the Watcom compiler and then the Novell NLM SDK. After this, the Watcom patch A should be applied (unless you are installing from an already patched version). If the compiler is already installed, TECHINFO.EXE, located in the WATCOM\BINB directory, will analyze your development environment and will display critical files and their level of patch applied.
A nice feature of this compiler is its Integrated Development Environment (IDE) for OS/2, Windows or Windows NT. This IDE can build programs for multiple platforms including NLMs, 16- and 32- bit DOS, 16- and 32- bit Windows, Win32s, Windows NT and OS/2 versions 1.x and 2.x. Although this IDE is a nice feature, DSBROWSE was developed using the DOS command line utilities for simplicity of demonstration.
Novell NLM SDK
Although compiler advertisements indicate the inclusion of the Novell NLM SDK v4.0 in the package, I have discovered Novell's NLM SDK to be a necessity. The CDROM version of this Novell SDK has online NLM documentation and NLM messaging tools required for the use of NWSNUT (the NetWare console text-based interface standard). In addition, this CDROM has other valuable things such as other SDKs and examples.
DSBROWSE was developed using the NetWare NLM SDK version 3.5. At the time of this article, the NetWare 4.1 SDK (client and server) has been released.
DOS Client Workstation
DSBROWSE was developed on an Intel-based computer running Novell DOS 7, but any DOS version 3.3 or higher should work. The processor should be an 80386 or higher with at least 8 megabytes of memory. My installation for NLM development including Watcom and Novell tools consumes 45 megabytes of disk space. This will vary depending on your installation options.
NetWare Server
The NetWare server used for testing the NLM should be dedicated for testing. A production server should not be used. Novell has special license agreements and prices for developers. Contact Novell Developer Relations at 1-800-REDWORD for further information.
Although you could write NLMs in C++ for either the NetWare 3.x or NetWare 4.x environments, DSBROWSE will only run on NetWare 4.x because NetWare Directory Services is required.
Client Configuration
After the Watcom and Novell tools have been installed, be sure to check your environment variables and DOS path. Assuming Watcom was installed to "c:\watcom", your environment should have two Watcom-related variables:
include = c:\watcom\novh;c:\watcom\h watcom = c:\watcom
The order of include locations is significant. It is important to place the Novell header file area ("c:\watcom\novh") before the Watcom header file area ("c:\watcom\h"). This will ensure the proper header file search order.
It is also required to have some directories in your path or have them mapped as search drives. These are:
c:\watcom\bin c:\watcom\binb c:\novsdk\msgtools
The first two directories contain Watcom executables and both the "bin" and "binb" directories are necessary. The Novell NLM enabling tools known as the messaging tools are used for internationalization or enabling. Although message enabling is optional for developers and DSBROWSE is not completely enabled, DSBROWSE.CPP shows one way of using message strings. DSBROWSE.MAK demonstrates the management of the message database.
Server Configuration
There are no special server "set" parameters required for debugging NLMs. One must only copy the Watcom's debugger to a directory in the server's search path. The common area to place it is in the "SYS:\SYSTEM" directory. The Watcom debugger filename varies depending on NetWare version and other debugging options. Watcom NLM debugging will be discussed in more detail later.
To source-level debug an NLM it is also necessary to copy the Watcom NLM debugger to the server. Once again, this file should be placed in a directory in the server's search path, usually SYS:\SYSTEM. DSBROWSE's MAKEFILE copies DSBROWSE.NLM to N:\SYSTEM after a successful build to place DSBROWSE.NLM in the test server's SYS:\SYSTEM directory. Note that drive "N:" must previously be mapped to the test server's SYS volume.
Compile
I used Watcom's WPP386.EXE to compile DSBROWSE. Although WCL386.EXE is available to both compile and link I have chosen to use the separate compiler and linker utilities for demonstration purposes.
The command to build DSBROWSE is:
wpp386 dsbrowse.cpp /3s /d2 /xs /bt=netware
The /3s parameter is required and it tells the compiler to generate 386 code using a stack calling convention. The /d2 switch enables full symbolic debugging which allows source-level debugging. This switch should normally be omitted for a released NLM product. The /bt=netware option is required and causes the compiler to build an NLM object module referencing __WATCOM_Prelude, which is Watcom's version of Novell's PRELUDE.OBJ.
The /xs parameter is optional in a sense. If your C++ source code contains exception handling code then the compiler must be told to allow it. If the source code does not have exception code then no exception parameter is required. Exception handling is disabled by default. If the parameter is omitted and the source code has exception code, the compiler will indicate in effect "Your source code has exception handling and you did not tell me to allow it. You are therefore confused and I must abort this compilation." Although there are various ways of implementing exception handling (controlled by other "/x" switches), I would expect the compiler to enable it by default.
Link
WLINK.EXE is Watcom's linker filename. The DSBROWSE project has a link file named DSBROWSE.LNK. This link file simply has a list of linker commands.
The command to link DSBROWSE with its link file is:
wlink @dsbrowse.lnk
Referring to the listing of DSBROWSE.LNK, there are some important options that must be included. The format statement "form nov nlm..." tells the linker to generate a Novell NLM. The "debug all" and "debug novell" tells it to include all debug information including source-level debugging information. Both of these debug statements are required to be able to source-level debug the NLM.
Since DSBROWSE is message-enabled, "option messages=dsbrowse.msg" will include the default english messages. These messages can be found in the DSBROWSE file MESSAGES.H. In addition to the "import" and "module" statements which indicate where the linked should search for external references and which corresponding NLMS NetWare should autoload, the link file should specify the library path as indicated:
libpath c:\watcom\lib386\netware;c:\watcom\lib386
Here the linker should search the Novell NetWare library directory before the Watcom library directory.
Debug
The compiler and linker options previously mentioned will build a debug version of DSBROWSE. To better understand what we need to do to source-level debug an NLM, we should briefly discuss Watcom's debugging architecture.
Watcom only supports remote debugging. This means the machine running your application must be controlled by a separate machine. This separate machine can be connected by a parallel, serial or SPX connection.
Figure 1: This shows how the Watcom NLM Debugger works.
The name of Watcom's server debugger is Watcom Novell Debugger v2.5. This NLM runs on the server and relays requests and information to and from the client debugging workstation. Watcom supplies six versions of its debug NLM to allow for each combination of parallel (par), serial (ser) and SPX (nov) transport type to each major NetWare version (NetWare 3.x and NetWare 4.x). Consult Watcom's documentation for more details, but I debug DSBROWSE on a NetWare 4.x server over an SPX connection, so I load NOVSERV4.NLM.
The server console command to load Watcom Novell Debugger v2.5 is:
load novserv4 nvi
The nvi parameter is the NetWare Service Advertising Protocol (SAP) name. This is an arbitrary name posted on the network that the client debugging workstation will search. If you don't specify a SAP name, NOVSERV4 uses the default value "NOVLINK."
Once the server debugger is loaded (there is no need to load DSBROWSE.NLM), the client needs to be setup. Watcom's client debugger WD.EXE is version 4.0. It is executed by the following DOS command line:
wd /vga50 -trap=nov;nvi
The /vga50 is optional and puts the video in a 50-column mode if the hardware supports it. The -trap=nov identifies the transport type just like on the server side. Since we will use our network SPX connection to link the two machines, nov specifies that request.
Since we are using a network SPX connection, the client debugger needs to find the debug server on the network. It does this by search SAP for the name "nvi" which we specified on the server. Once again, if ";nvi" is omitted, the default SAP name searched is "NOVLINK".
When the client debugger is loaded and finds the debug server, the server debugger automatically loads DSBROWSE.NLM. The client debugger then displays DSBROWSE.CPP and highlights the first executable line of code.
DSBROWSE
When you run DSBROWSE.NLM you might notice no login capability is included. This is because none is required. NetWare Directory Services does not require one to login to "browse" the tree. Although this is the default NDS behavior, it is possible for browse rights to be revoked at specific locations in the tree by users of proper authority. This means a login ability might be useful and it would be a good enhancement to DSBROWSE.
Be aware that no unload procedure is included in DSBROWSE. Every production NLM should register an unload function that will free resources when the NLM is unloaded from the console.
Listing 1 shows a MAKEFILE that will build DSBROWSE and will work with Watcom's WMAKE.EXE. The environment variables and path (or search drives) must be setup prior to running the make. The command to build DSBROWSE assuming all DSBROWSE files are in the default directory is:
wmake
WMAKE.EXE will search the default make filename of MAKEFILE.
Listing 1
# # DSBROWSE C++ NLM make file # # Author: W. Dale Cave # Date: Jan. 1995 # compileoptions = /3s /d2 /xs /bt=netware linkoptions = @dsbrowse.lnk dsbrowse.nlm : dsbrowse.msg dsbrowse.obj dsbrowse.lnk wlink @dsbrowse.lnk copy dsbrowse.nlm n:\system dsbrowse.obj : dsbrowse.cpp dsbrowse.h messages.h dsbrowse.msg wpp386 dsbrowse.cpp $(compileoptions) # Manage the messaging # If the message database (.MDB) does not exist, then it can be created # with "msgmake dsbrowse.MDB dsbrowse 1 4 English". dsbrowse.MDB identifies the # database name. dsbrowse is the program name and 1 is the program version. # The 4 is the language (4=english). English is the TranVersion. dsbrowse.mdb : -btrieve /P:1536 msgmake dsbrowse.mdb dsbrowse 1 4 English butil -stop dsbrowse.msg : dsbrowse.mdb messages.h # the '-' causes the program's return code to be ignored -btrieve /P:1536 msgextr -w -tIDEMSG -mdsbrowse -smessages.h msgexp dsbrowse CString NLM dsbrowse.msg -tIDEMSG butil -stop
Concerns
My client workstation consistently crashes after a debugging session. Although irritating, source-level debugging DSBROWSE has been very effective and worth the nuisance.
With C++ comes its peculiarities. One of which is name mangling. In short, name mangling supports function overloading (functions with the same name). It is the naming of functions that include an encoding of the function's number of arguments and their types. This can be a problem.
DSBROWSE demonstrates one such problem. If a variable is to be made public in the NetWare environment, the variable symbol would have to be exported. Listing 2, from DSBROWSE.CPP show how two variables (exported in DSBROWSE.LNK) are handled. The first symbol ExportSymbolMangled actually becomes W?ExportSymbolMangled$ni because of name mangling. If ExportSymbolMangled is exported, the linker cannot resolve it. But the mangled name, W?ExportSymbolMangled$ni, can be resolved.
Another variable ExportSymbolUnMangled is included with the >extern 'C"' linkage. This forces a C naming convention on the variable. This will prevent it from being mangled and it can be exported as is.
Listing 2
/* "ExportedSymbolMangled" and "ExportedSymbolUnMangled" are included only for examples of exporting symbols in the C++ name-mangling environment. See DSBROWSE.LNK for the export statement syntax. This symbol will be mangled in the C++ environment. With debug information on, a scan of the symbols (NetWare internal debugger command "n") shows this symbol "ExportedSymbolMangled" is mangled to "W?ExportedSymbolMangled$ni". */ int ExportedSymbolMangled = 0xF1; #ifdef __cplusplus extern "C" { #endif /* This symbol name will not be mangled if enclosed within these "extern C..." constructs. The Watcom compiler will define __cplusplus by default if compiling a .CPP file. */ int ExportedSymbolUnMangled = 0xF0;
Note: The C linkage is not available for C++ constructs. In addition, the Watcom linker refuses to export a mangled name with parentheses in them and the Novell Internal Debugger also cannot recognize such a name.This is a problem because all mangled methods have parentheses. |
The last concern is that of Watcom's static library CLIB3S.LIB. This is Watcom's static library version of Novell's CLIB.NLM. To build C++ NLMs it is required to use this static library. So even though you think you might be getting some functions from Novell's CLIB.NLM you could be getting them from Watcom's CLIB version. This can cause difficulty in obtaining technical support and identifying which product has the problem.
Summary
This article has demonstrated how to build a C++ NLM. It is important to note that this process requires the use of Watcom's NLM startup code (__WATCOM_Prelude) and therefore requires the developer to get support from Watcom and not Novell. There are other ways of imbedding C++ in NLMs. One other way would be to compile C++ source code to object modules and link them into a C NLM. This is more complex but would give Novell the opportunity to support the development efforts. Perhaps a follow-up article can explore these alternative methods.
The tools exist today to develop C++ NLMs. Because there are some caveats, a C++ NLM project might require some research. In addition to obtaining the readme.log for the compiler, Watcom technical support can be contacted for product and development questions while Novell can be reached for SDK and NetWare licensing assistance. Whatever you decide, developing C++ can be fun. Watcom's source-level debugging feature makes NLM debugging easy and effective.
* Originally published in Novell AppNotes
Disclaimer
The origin of this information may be internal or external to Novell. While Novell makes all reasonable efforts to verify this information, Novell does not make explicit or implied claims to its validity.