Posts Tagged ‘gcc’

Loading a native library in Firefox via the Add-ons SDK

Thursday, October 2nd, 2014

Contact: mar10 a krutt punto org

In this tutorial we are going to discover how to use a small c library written by ourselves inside Firefox.

This tutorial assumes that you have a working GNU/Linux distribution with a gcc environment installed. Here we use Ubuntu, however all the steps must work for any POSIX system in which the Add-ons SDK runs.

Requirements:

  • A working gcc compiler. I am using gcc 4.8.2
  • A text editor
  • Firefox. I am using Firefox 32.0.3
  • The Add-ons SDK installed. I am using Add-on SDK 1.17

Please go to Mozilla Add-ons SDK to get familiar with the SDK and specially with the cfx tool.

We could use any system library (shared object) in order to demonstrate how to use the Add-ons SDK. However I prefer the long way. We start by coding our own c-library. After that, we will start with the add-on.

Step 1: Preparing the directories

Open a terminal, and create a working directory, i.e. do something like:

mkdir example example/c example/add-on

After that, you would have the following directories:

.
|- example
    |-- add-on
    |-- c

Step 2: Creating the library

We need to write some C code in order to produce a shared object. Copy the following to a file named example.c inside the c directory:

#include <stdio.h>

int sum( int a, int b )
{
  int c;
  FILE *f;

  c = a+b;

  f = fopen("output.txt", "a");
  fprintf(f, "%d + %d = %d\n", a, b, c);
  fclose(f);

  return c;
}

This code just prints the sum of two numbers. Each time this function is called, it will append a new line to file output.txt.

Compile it with the following commands:

gcc -Wall -Wextra -std=c89 --pedantic -fPIC -c example.c -o example.o
gcc -shared example.o -o libexample.so

After that, you will have something like this:

.
|-- example
    |-- add-on
    |-- c
        |-- example.c
        |-- example.o
        |-- libexample.so

From a terminal at the example directory, run the following:

file c/libexample.so

you would see this:

c/libexample.so: ELF 64-bit LSB  shared object, x86-64, version 1 (SYSV), 
dynamically linked, BuildID[sha1]=..., not stripped

Note that now we have a shared object (libexample.so) that must be installed in the target system in order to be consumed by Firefox.

Step 3: Installing the library

In order to use the library in our target system, we must install it. Assuming that you are at the example directory, do this:

sudo cp c/libexample.so /usr/lib
sudo chmod 0755 /usr/lib/libexample.so

If everything went fine, you must have libexample.so in /usr/lib. Now do this:

sudo ldconfig
ldconfig -p | grep example

You must see something like this:

libexample.so (libc6,x86-64) => /usr/lib/libexample.so

This means that you have successfully installed libexample.so, and that your system will be able to load libexample.so when asked by an application.

Step 4: Testing the library

Create a file named example/c/main.c with the following content:

#include <stdio.h>

int sum( int a, int b );

int main()
{
  int ret;
  ret = sum(1, 2);
  printf("1 + 2 = %d\n", ret);
  return 0;
}

Go to example/c. Compile main.c, as follows:

gcc -Wall -Wextra -std=c89 --pedantic -c main.c -o main.o

And now, link the object file (main.o) with the library:

gcc main.o -lexample -o main

Use the ldd command to review the new executable file:

ldd main

You must see something like this:

linux-vdso.so.1 =>  (0x00007fff02fc1000)
libexample.so => /usr/lib/libexample.so (0x00007f4c82181000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4c81dbb000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4c823a8000)

Run the executable:

./main

It must print 1 + 2 = 3.

Step 5: Creating the add-on

Here we make use of the Add-ons SDK. Go to the add-on directory and run:

cfx init

This command will create a template for the add-on. Your add-on directory now have the following structure:

.
|-- example
    |-- add-on
    |   |-- data
    |   |-- lib
    |   |   |-- main.js
    |   |-- package.json
    |   |-- test
    |       |-- test-main.js
    |-- c
        |-- example.c
        |-- example.o
        |-- libexample.so
        |-- main
        |-- main.c
        |-- main.o

Customizing packaje.json

Open the packaje.json file, you will see this:

{
  "name": "add-on",
  "title": "add-on",
  "id": "jid1-k4igzLTBAsNAew",
  "description": "a basic add-on",
  "author": "",
  "license": "MPL 2.0",
  "version": "0.1"
}

You can change the information contained in packaje.json. These fields will be visible inside the Firefox’s add-ons manager.

For example, you could put this in the packaje.json file:

{
  "name": "mar10_add-on",
  "title": "add-on example",
  "id": "jid1-k4igzLTBAsNAew",
  "description": "a basic add-on",
  "author": "mar10",
  "license": "MPL 2.0",
  "version": "0.1a"
}

The value of the "name" field will be used by the cfx tool to name the xpi add-on file.

Open the main.js file and copy this:

/* import js-ctypes */
var {Cu} = require("chrome");
var {ctypes} = Cu.import("resource://gre/modules/ctypes.jsm", null);

/* Open the library */
try 
{
  var libexample = ctypes.open("libexample.so");

  /* 
   * remember that our c-function is of the form:
   * int sum( int a, int b )
   */

  var sum = libexample.declare("sum",              /* function name */
                               ctypes.default_abi, /* call ABI */
                               ctypes.int,         /* return type */
                               ctypes.int,         /* argument type */
                               ctypes.int);        /* argument type */
  var num_a = 1;
  var num_b = 2;
  var ret = sum( num_a, num_b);
  console.log("Result: " + num_a + " + " + num_b + " = " + ret );
  libexample.close();
} 
catch (e) 
{
  console.log("Error while loading lib: " + e);
}

Run the following command:

cfx run

You will see something like this:

console.log: mar10_add-on: Result: 1 + 2 = 3

Perhaps you will find more information coming from Firefox, i.e. some GLib-GObject warnings. Don’t pay attention to those messages.

At the same directory, you will find the output.txt file with the same information you just saw at the terminal!

To create the xpi file, run the following command at the example/add-on directory:

cfx xpi

This creates the mar10_add-on.xpi file. Now you can import this add-on to Firefox.

Step 6: Importing the add-on to Firefox

Just press Ctrl+O to launch the open file dialog. Select the xpi file and
click open. In my case the add-on is mar10_add-on.xpi.
A new window will appear. Click Install Now.

Install Add-on

Go to the Add-ons manager and click on Extensions:

Install Add-on

Now click on More over our recently installed add-on, you will see something like this:

Install Add-on

Once the add-on is installed, our library libexample.so is executed each time Firefox is initiated, inclusive at the moment the add-on was installed!!!

Now write the following command:

cat output.txt

The content of output.txt must be: 1 + 2 = 3, awesome!!!. Each time you start Firefox, you will append a new line with the same content to output.txt.

Step 7: Running Firefox

Run Firefox from a terminal:

/usr/bin/firefox

The output.txt file will be created inside the directory that you use to call Firefox.

If you run Firefox by clicking over an icon in the desktop or via another graphic element, the output.txt file will be created at $HOME directory.

Final remarks

As you can see, this add-on is almost useless. There is no interaction with the browser, or with the user. However, now you are able to compile and load native libraries in Firefox!!!

See also

Download

Here you can get the code of this tutorial.

License

Copyright (C) 2014 mar10

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.

A copy of the license can be found here.