Using Dependent Libraries In Extension Components
From MDC
Extensions with binary components sometimes need to depend on other shared libraries (for example, libraries provided by a third party). The Firefox extension system does not provide automatic support for loading these dependent libraries, but it is possible to load these libraries explicitly using a component stub.
The basic strategy of the stub is to dynamically load the dependent libraries, then load the component library and continue registration. Sample code is below, and can be built by placing the two files in extensions/stub and configuring with --enable-extensions=stub
Contents |
[edit] Extension File Structure
Using the stub slightly changes how components are packaged in the extension directory structure. Note that the "real" component is no longer in the components/ directory, it is in the libraries/ directory.
extension-directory/install.rdf extension-directory/libraries/dependent1.dll extension-directory/libraries/dependent2.dll extension-directory/libraries/component.dll extension-directory/components/interface1.xpt extension-directory/components/interface2.xpt extension-directory/components/bsmedberg_stub.dll
[edit] extensions/stub/Makefile.in
# Copyright (c) 2005 Benjamin Smedberg <benjamin@smedbergs.us>
DEPTH = ../..
srcdir = @srcdir@
topsrcdir = @top_srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = bsmedberg
LIBRARY_NAME = bsmedberg_stub
IS_COMPONENT = 1
FORCE_SHARED_LIB = 1
REQUIRES = \
xpcom \
string \
$(NULL)
CPPSRCS = bdsStubLoader.cpp
EXTRA_DSO_LDOPTS += \
$(DIST)/lib/$(LIB_PREFIX)xpcomglue_s.$(LIB_SUFFIX) \
$(XPCOM_FROZEN_LDOPTS) \
$(NSPR_LIBS) \
$(NULL)
include $(topsrcdir)/config/rules.mk
DEFINES += -DMOZ_DLL_PREFIX=\"$(DLL_PREFIX)\"
[edit] extensions/stub/bdsStubLoader.cpp
// Copyright (c) 2005 Benjamin Smedberg <benjamin@smedbergs.us>
#include "nscore.h"
#include "nsModule.h"
#include "prlink.h"
#include "nsILocalFile.h"
#include "nsStringAPI.h"
#include "nsCOMPtr.h"
static char const *const kDependentLibraries[] =
{
// dependent1.dll on windows, libdependent1.so on linux
MOZ_DLL_PREFIX "dependent1" MOZ_DLL_SUFFIX,
MOZ_DLL_PREFIX "dependent2" MOZ_DLL_SUFFIX,
nsnull
// NOTE: if the dependent libs themselves depend on other libs, the subdependencies
// should be listed first.
};
// component.dll on windows, libcomponent.so on linux
static char kRealComponent[] = MOZ_DLL_PREFIX "component" MOZ_DLL_SUFFIX;
nsresult
NSGetModule(nsIComponentManager* aCompMgr,
nsIFile* aLocation,
nsIModule* *aResult)
{
nsresult rv;
// This is not the real component. We want to load the dependent libraries
// of the real component, then the component itself, and call NSGetModule on
// the component.
// Assume that we're in <extensiondir>/components, and we want to find
// <extensiondir>/libraries
nsCOMPtr<nsIFile> libraries;
rv = aLocation->GetParent(getter_AddRefs(libraries));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsILocalFile> library(do_QueryInterface(libraries));
if (!library)
return NS_ERROR_UNEXPECTED;
library->SetNativeLeafName(NS_LITERAL_CSTRING("libraries"));
library->AppendNative(NS_LITERAL_CSTRING("dummy"));
// loop through and load dependent libraries
for (char const *const *dependent = kDependentLibraries;
*dependent;
++dependent) {
library->SetNativeLeafName(nsDependentCString(*dependent));
PRLibrary *lib;
library->Load(&lib);
// 1) We don't care if this failed!
// 2) We are going to leak this library. We don't care about that either.
}
library->SetNativeLeafName(NS_LITERAL_CSTRING(kRealComponent));
PRLibrary *lib;
rv = library->Load(&lib);
if (NS_FAILED(rv))
return rv;
nsGetModuleProc getmoduleproc = (nsGetModuleProc)
PR_FindFunctionSymbol(lib, NS_GET_MODULE_SYMBOL);
if (!getmoduleproc)
return NS_ERROR_FAILURE;
return getmoduleproc(aCompMgr, aLocation, aResult);
}
[edit] Notes
- Code samples are licensed under the MIT license.
- This code only works on Firefox 1.5 and later. As written it uses only frozen APIs.
- This code will not work as written on mac. Dependent libraries on the mac must be loaded with a special system function NSAddImage() with the flag NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME.