Level: Introductory
Rick Parrish (rfmobile@swbell.net), Independent consultant, Freelance
转自:http://www-128.ibm.com/developerworks/webservices/library/co-xpcom3.html
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:
If none of these work, see the environment variables hint under step 5 below.
For Windows 9X add a few commands to AUTOEXEC.BAT like so:
|
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:
|
![]() |
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:
|
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:
Finally, run the following command to kick off the build:
|
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:
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:
![]() |
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:
Set up your environment variables like so:
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:
Use these commands to update an existing source tree (like the latest tarball) with the latest sources from the CVS server:
![]() |
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 |
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
.
|
This next method just does the inverse of the above:
|
The following method verifies that some component has been registered and is therefore available for use:
|
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.
|
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 |
Note that the NS_WITH_SERVICE macro uses nsCOMPtr
to create a smart pointer. Some examples of services are listed in Table 2.
|
|
|
|
![]() |
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
![]() |
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. |