Level: Introductory Rick Parrish (rfmobile@swbell.net), Independent consultant, Freelance
01 Mar 2001 Rick Parrish details the process of building Mozilla for Windows or Linux. He also covers other necessaries of setting up XPCOM including (but not limited to) enabling XPCOM in an application, and understanding the basic workings of the component, service and category managers. Before getting into the nuts and bolts of constructing your own XPCOM-enabled application or even your own XPCOM components, you will need a
proper development environment. The best way to verify that all of the
tools are in place and working properly is to do a build of the Mozilla
browser. Build the lizard
Mozilla, known to some as "the lizard," is built on top of XPCOM and
XPConnect so building it gives you both libraries and a suite of useful
XPCOM components - some of which do not depend upon cohabitation with a
browser. Go to www.mozilla.org, download the source code and supplemental
development tools, and build everything. The Mozilla code uses generic
make files, shell scripts, and Perl scripts in its build process instead
of compiler-specific project files. This "least common denominator"
approach is the only way to make sure that the same code gets built the
same way on different platforms. Be aware that this approach eats up lots of disk space. As of this
writing, just unpacking the source code tarball held 160,975,003 bytes in
over 28567 files. Due to file system inefficiencies on NTFS, this works
out to 244,293,632 bytes of actual disk space used. That's only
the source code! Source code and binaries after a release build add up to
just under 450 megabytes. This doesn't include disk space for additional
tools or space for a debug build.
CVS
Part of the magic of getting the same source code to compile on
different platforms comes from the availability of some tools that have
themselves been ported to numerous platforms. Some of those tools are
gmake, CVS, and infozip. CVS -- the Concurrent Versioning System -- is a simple but well-used and
well-tested multiuser source control and versioning system for allowing
large numbers of programmers to collaborate on large projects. It is
comparable in function to Microsoft's SourceSafe tool. RCS is another
similar UNIX-oriented program. CVS is a crucial weapon in the Mozilla arsenal for tracking bugs and
patches. Your main interest in CVS is the ability to incrementally
download the latest changes to the source code just as soon as they become
available to everyone else. You can skip CVS if you don't mind waiting for
the next tarball release. The CVS server requires a password and, unless you've gained the
confidence of a module owner to nominate you for write access privileges,
you will be using the generic, read-only account. This does not mean you
aren't allowed to contribute -- far from it. It just means you will need to
submit your patches directly to one of the module owners for
consideration.
Setting up a Windows environment
Here's the fast track to getting through this step on MS Windows:
- Make sure Microsoft Visual C++ 6 is installed along with all the
latest updates (they were up to Service Pack 4 last I checked). There are
efforts underway to support other compilers on Windows such as gcc, but
for now only VC6 is known to work. VC5 with SP3 is also supposed to work,
but I haven't tried it.
- Make sure your compiler, linker, and make tool can be run from a
shell window.
- type "cl" - you should see something like "Microsoft (R) 32 bit
Optimizing C/C++ compiler version .."
- type "nmake" - you should see something like "Microsoft (R)
Program Maintenance Utility ..."
- type "lib" - you should see something like "Microsoft (R) Library
Manager ..."
If none of these work, see the environment variables hint under
step 5 below.
- Download the source tarball (see Resources) and unzip the contents to a "mozilla" directory on a disk with lots of space (about 1 gig minimum or 2 gigs if you plan to do debug and release
builds at the same time).
- Download the supplemental tools needed like cygwin, Active State Perl
and infozip (see Resources for links to these programs). Note that you can use winzip or pkzip to unzip the tarball, but the Mozilla makefiles use infozip as part of the build.
- The following environment variables need to be defined:
For Windows 9X add a few commands to AUTOEXEC.BAT like so:
set PATH=%PATH%;C:\cygwin\bin;C:\progra~1\micros~1\common\msdev98\bin;c:\perl\bin
C:\progra~1\micros~1\vc98\bin\vcvars32
set MOZ_BITS=32
set MOZ_src=C:
set MOZ_TOOLS=C:
set CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot
|
For Windows 2000 navigate to the Control Panel (click
Start/Settings/Control Panel), click on "System", select the "Advanced"
tab and click on "Environment Variables" to get the edit dialog. Check
for the following or something equivalent for your system (see Table 1).
Table 1. System environment variables
[
| PATH | C:\Program Files\Microsoft Visual Studio\Common\Tools\WinNT;
C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin;
C:\Program Files\Microsoft Visual Studio\Common\Tools;
C:\Program Files\Microsoft Visual Studio\VC98\bin;
C:\Perl\bin;
C:\cygwin\bin
| | include | C:\Program Files\Microsoft Visual Studio\VC98\atl\include;
C:\Program Files\Microsoft Visual Studio\VC98\mfc\include;
C:\Program Files\Microsoft Visual Studio\VC98\include | | lib | C:\Program Files\Microsoft Visual Studio\VC98\mfc\lib;
C:\Program Files\Microsoft Visual Studio\VC98\lib | | MSDevDir | C:\Program Files\Microsoft Visual Studio\Common\MSDev98 | | MOZ_BITS | 32 | | MOZ_SRC | C: | | MOZ_TOOLS | C: | | CVSROOT | :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot
|
The exact PATH specification will vary depending upon where you've
installed some of your tools. The MOZ_SRC variable should point to the
directory just above the mozilla directory tree. The MOZ_TOOLS
variable should point to the directory
just above
your cygwin
tools bin directory.
Cygwin GNU tools
The first set of third-party tools to install are a set of GNU
command-line tools ported for Windows. Download the file "setup.exe" and
run it (you need an active Internet connection for this to work). The
setup program downloads the selected components and installs them. The
components needed are ash, cygwin, diff, fileutils, gawk, grep, sed,
shellutils, textutils, unzip, and zip. You could also
pick up Perl and CVS while you are downloading these GNU tools but don't
do it -- the build experts are recommending different versions, which are
available elsewhere. Downloading the different modules can take time so
some patience is required.
Infozip
The build process requires infozip to make JAR files. The cygwin setup
above should have given you the option to download and install
zip and unzip (the two pieces of infozip). As an
alternate route for getting the infozip, tools you can follow these steps.
The zip tool distribution comes in a ZIP file, so to unzip it you will need
the separate unzip as well. Download the files "unz542xN.exe" and
"zip23xN.zip" from the infozip site (or one of its mirrors) to a temporary
directory and type these commands:
cd \temp
unz542xN
unzip zip23.zip
copy *.exe c:\bin
|
Netscape Wintools
Netscape has modified a handful of the GNU command-line tools to solve
some problems mostly for makefile compatibility with the GNU-styled UNIX
builds. You should have already added the environment variables mentioned
earlier, as the installer for this bundle uses MOZ_TOOLS variable to
determine where to install a few of the executables. The following, when
done from the command prompt, will unzip the wintools.zip file to the
default directory "buildtools" and complete the installation:
cd \temp
unzip wintools.zip
cd \buildtools\windows
install
|
The above step actually creates the "C:\bin" and "C:\include"
directories (assuming you've defined MOZ_TOOLS to be "C:"). You can delete everything under "buildtools" after this step if you want to save some space. Unlike the other tools, the path to Netscape Wintools should
not be included in the PATH environment variable. The makefiles
use MOZ_TOOLS to find gmake and other Netscape-modified binaries.
Perl
Installing Active-State Perl is dreadfully easy -- you can download it
as a Windows installer module or MSI file. Using Windows Explorer, browse
to the folder where you downloaded it, and click on the file named
something like "ActivePerl-5_6_0_616-MSWin32-x86-multi-thread.msi". There are two minor potential "gotchas" to be aware of. First, the
installer will add "\Perl\bin" to your PATH environment variable. If you
are running Windows NT or Windows 2000, this will only apply to the
currently logged-in user. Second, if you are running Windows 9X or NT,
then you may need to download the Microsoft Windows Installer package from
Microsoft's Web site. As a final test, reboot your machine to make sure any changes took
effect. Open up a command-line window and try to run each of the third
party tools by typing their names at the command prompt. Some commands to
try are ash, diff, grep, perl, and unzip. The preceding steps are only necessary when you are creating or
recreating your build environment. These next steps are the ones you will
need to perform each time you wish to actually build Mozilla. If you plan to do a debug build, enter this command just before the
build:
A few extra neat-to-know options are:
- MOZ_SVG which adds SVG support
- MOZ_MATHML which adds MathML support
- MOZ_LDAP_XPCOM for LDAP support
- MOZ_DISABLE_JAR_PACKAGING is useful if you do not want to mess with using
zip in your builds
- Some others worth playing with are MOZ_LITE,
MOZ_MEDIUM, and MOZ_MAIL_NEWS
Finally, run the following command to kick off the build:
nmake /f client.mak build_all
|
Most of the common potential errors at this point involve the
makefile issuing a command that fails because either the tool involved in
the command is missing or is not visible from the search path. Once the
kinks in the build environment are ironed out, the build process will run
for a couple of hours (I am not kidding). Even with a correct build environment, you may run into problems. To
validate the above procedure, I tested it against the mozilla-0.7 tarball.
I quickly ran into problems with gmake crashing on the NSPR module when
the PR_CLIENT_BUILD_WINDOWS option was set (NSPR is the very first module
to get built). I downloaded and unzipped the mozilla-0.8 tarball, re-ran
the above command and everything compiled fine. The Mozilla build page (see Resources) offers a list of common errors and how to resolve them.
CVS on Windows
Download CVS binaries for Windows from the cvshome.org site. Here's the command sequence to pull the whole source tree from the CVS
server:
- set CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot
- set HOME=\TEMP
- cvs login (answer the prompts for the CVS login)
- cvs checkout mozilla/client.mak
- cd mozilla
- nmake -f client.mak pull_all
Here's the command sequence to update an existing source tree (like the
latest tarball) by having the CVS server only deliver those files that
have changed:
- set CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot
- set HOME=\TEMP
- cvs login (answer the prompts for the CVS login)
- cd mozilla
- cvs -z3 checkout -PA mozilla/client.mk
- nmake -f mozilla/client.mak checkout MOZ_CO_FLAGS=-PA
Setting up a Linux environment
In contrast to Windows, most of the programmer-friendly Linux
distributions include all the tools needed to build Mozilla. If you've got
a Linux CD like Debian or RedHat or Slackware, chances are that all the
pieces you need are already there. The only issue for getting your build
environment up and running is verifying which versions are installed. Here's a summary of the packages needed:
- C++ Compiler
- GNU make
- GTK/GLib
- Perl 5
- zip
Set up your environment variables like so:
- setenv MOZ_BITS 32
- setenv MOZ_src=/usr/home
- setenv CVSROOT=:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot
Run the config tool from the mozilla directory like so:
From the mozilla directory, do a default build:
From the mozilla directory, do a manual build:
CVS on Linux
Use these commands to pull the whole source tree from the CVS
server:
- setenv CVSROOT :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot
- cvs login (answer the CVS server login prompts)
- cvs checkout mozilla/client.mk
- cd mozilla
- make -f client.mk checkout
Use these commands to update an existing source tree (like the latest
tarball) with the latest sources from the CVS server:
- setenv CVSROOT :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot
- cvs login (answer the CVS server login prompts)
- cd mozilla
- cvs -z3 checkout -PA mozilla/client.mk
- make -f mozilla/client.mk checkout MOZ_CO_FLAGS=-PA
Other environments
Check the build page (see Resources) for
explicit build instructions for Win32, Mac, UNIX, Linux, BSD, and other
platforms. If you have actually followed through all of this and
successfully established a working build environment on your computer,
take a bow (and a break)! Pat yourself on the back, for now you can
actually start to do something productive.
Enabling XPCOM in an application
Before an application can actually begin using XPCOM components, there
are a set of libraries that must be loaded and initialized for the XPCOM
framework to operate. Here's a sample app to do that: Listing 1. Sample app to load and initialize necessary libraries
#include <stdio.h>
#include <nsIServiceManager.h>
#include <nsISomething.h>
int main()
{
static const char szContractId[] =
"Your component's contract ID goes here";
nsresult rv;
// Initialize XPCOM and check for failure ...
rv = NS_InitXPCOM(nsnull, nsnull);
if ( NS_FAILED(rv) )
{
printf("Calling NS_InitXPCOM returns [%x].\n", rv);
return -1;
}
// optional autoregistration - forces component manager to check for new components.
(void)nsComponentManager::AutoRegister(nsIComponentManager::NS_Startup, nsnull);
// Create an instance of our component
nsCOMPtr
mysample = do_CreateInstance(szContractId, &rv);
if ( NS_FAILED(rv) )
{
printf("Creating component instance of %s fails.\n", szContractId);
return -2;
}
// Do something useful with your component ...
// (main body of code goes here)
// Released any interfaces.
// Shutdown XPCOM
NS_ShutdownXPCOM(nsnull);
return 0;
}
|
The two crucial calls are NS_InitXPCOM and NS_ShutdownXPCOM. The XPCOM
core libraries are normally located in the same directory as the
application, and an additional subdirectory named "components" is
required. Once XPCOM has been initialized, the two big XPCOM components
of immediate interest for doing something productive are the Component
Manager and the Service Manager. The call to AutoRegister is actually
optional, and is really only needed when a new component is installed. The above example assumes a stand-alone application that does not need
browser support. nsISomething is a placebo for some actual interface.
Real-world application code that makes use of the interface would be
placed where the "main body of code goes here" comment appears above.
Component manager
The component manager does just what its name implies. It keeps track
of what components are currently installed and what DLL or shared library
must be loaded to create a specific component. The components subdirectory
mentioned above is where the component manager expects to find any
components. It scans this directory in the AutoRegister step above looking
for components not already registered and adds a descriptive entry into a
private map file. Subsequent requests for components happen much quicker
because it already knows from the map which DLL or shared library to load.
Components are identified in one of two ways: a 128-bit UUID known as a
class ID or CID or a short text name known as a Contract ID.
Note to MSCOM programmers: a contract ID is functionally equivalent
to an MSCOM Program ID or ProgID.
Here are some core methods offered by the component manager in IDL.
The first one looks up the class ID for a given contract ID. If you plan
to create a lot of components of the same class and you only know the
component's contract ID, you can improve performance by calling this
method first and using the shorter, faster class ID for subsequent calls
to createInstance.
void contractIDToClassID(in string aContractID, out nsCID aClass);
|
This next method just does the inverse of the above:
string CLSIDToContractID(in nsCIDRef aClass, out string aClassName);
|
The following method verifies that some component has been registered
and is therefore available for use:
boolean isRegistered(in nsCIDRef aClass);
|
The next two methods do all the grunt work for loading an arbitrary
XPCOM component. You get your choice of identifying a component in the
first parameter by class ID with createInstance or contractID in
createInstanceByContractID. The second parameter aDelegate is only
needed when you are doing what is called aggregation and is usually set to
nsnull. The third parameter is the interface IID.
voidPtr createInstance(in nsCIDRef aClass, in nsISupports aDelegate, in nsIIDRef aIID);
voidPtr createInstanceByContractID(in string aContractID, in nsISupports aDelegate, in nsIIDRef IID);
|
The IDL source for all of the component manager methods can be found in
nsIComponentManager.idl.
Service manager
XPCOM services are referred to in some books as singleton objects. No
matter how many times you request a service you will always receive an
interface to the same component. You've already seen the biggest service
of them all -- the component manager. How's this for indirection: the
service manager is itself a service. In a nutshell, the service manager
takes care of loading and unloading services. When a request is made for a
service that is already loaded, the service manager is smart enough to
return another pointer to the existing service instead of trying to
construct another object. Note how this behavior differs from the component
manager which gives you a fresh new component on each request. Services
are usually requested using the NS_WITH_SERVICE macro as illustrated in Listing 2. Listing 2. Service request
{ // enter scope of service smart pointer ...
NS_WITH_SERVICE(nsIMyService, service, kMyServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
service->DoSomething(...); // use my service
} // leaving scope of service smart pointer ...
|
Note that the NS_WITH_SERVICE macro uses nsCOMPtr to create a smart
pointer. Some examples of services are listed in Table 2. Table 2. Examples of services
- LDAP
- WebShell
- JSRuntime
- Editor
|
| |
|
|
Category manager
The component manager and service manager will fetch a component given
its contract or class ID. How would you go about finding components
without either of these? The answer to this question is the category
manager. The category manager provides a directory of class IDs grouped
into categories. When I say "directory" here, think phone book (as in the
Yellow Pages) and not disk drive. Using the phone book analogy, if
we wanted to find all of the hotels in the area, we could look up "hotels"
in the phone book. Suppose you've written a neat editor with lots of word processing
features that supports multiple document types through a generic set of
interfaces. The document types you chose to support are text, HTML, RTF
and PDF -- but you've also registered your document handlers under the
"document handler" category and written your program to always check the
document handler category to determine what document types are
available. Your friend decides your program desperately needs to support WordPerfect files so she creates a new document handler component that implements the same set of interfaces, and she registers it under the document handler category. Any user of your program can now download, install and
begin using your friend's new document handler without any extra work on
your part. Components grouped under a category usually have something in common,
like a predefined set of interfaces. The category becomes an implied
contract for any component registering itself under that category.
Categories are a very powerful means of achieving object independence
since the code that makes use of a category only cares about the
interfaces and can divorce itself from any specific implementation.
Despite this power, categories are one of the most under-used features of
XPCOM.
Conclusion
Once you reach the point where you can build the Mozilla source tree
and actually become a user of components, you can proudly proclaim
yourself armed and dangerous. If a little knowledge is dangerous, then the
next two articles in this series should round out your knowledge so that
you will not only have the power to write components, but also be able to
do that without shooting yourself in the foot or accidentally setting
someone else's application on fire.
Resources - This is Part 3 of our continuing five-part series on XPCOM. Other parts are:
- This article makes use of Mozilla's CVS. Some other common source code
tools, used to keep many developers all working on the same code include:
- Tools common to many environments allow the same source to compile the
same way on different platforms. Windows users will need to download and
install some of these tools:
- Infozip comes in two parts:
- Linux distributions usually come with these tools as part of the
distribution. Some popular Linux distributions include:
- If you are experiencing problems on any platform, you may find it useful
to visit the Mozilla Build Info page at the Mozilla site
- Windows users may also need to download Microsoft Visual Studio Service or the Microsoft Windows Installer package.
About the author  | |  | Rick Parrish has held an interest in computers since high school and in electronics even longer. He originally pursued an education in electrical engineering but discovered that software, unlike hardware, did not require smelly vats of ferric chloride or run the risk of burnt fingers just to perform a design change. Rick has been programming in C/C++ for A LONG TIME(tm) but has also done heaps of work in VB, Delphi(Pascal), and a handful of assembly languages. He still manages to squeeze in a project or two that requires hot solder. His current opinions are that while Windows 2000 is neat-o, Ogg Vorbis is cool, and the Linux 2.4 kernel with IPTables definitely rocks! He is
currently interested in starting an open source project to develop tools for software modeling design. Rick can be reached at rfmobile@swbell.net.
|
Rate this page
|