1.8. Compiling code ahead of time — Anaconda Enterprise 4.4 documentation

Anaconda Enterprise: Documentation

# 1.8. Compiling code ahead of time

While Numba’s main use case is Just-in-Time compilation, it also provides a facility for Ahead-of-Time compilation (AOT).

## 1.8.1. Overview

### 1.8.1.1. Benefits

1. AOT compilation produces a compiled extension module which does not depend on Numba: you can distribute the module on machines which do not have Numba installed (but Numpy is required).
2. There is no compilation overhead at runtime (but see the `@jit` cache option), nor any overhead of importing Numba.

See also

Compiled extension modules are discussed in the Python packaging user guide.

### 1.8.1.2. Limitations

1. AOT compilation only allows for regular functions, not ufuncs.
2. You have to specify function signatures explicitly.
3. Each exported function can have only one signature (but you can export several different signatures under different names).
4. AOT compilation produces generic code for your CPU’s architectural family (for example “x86-64”), while JIT compilation produces code optimized for your particular CPU model.

## 1.8.2. Usage

### 1.8.2.1. Standalone example

    from numba.pycc import CC

    cc = CC('my_module')
    # Uncomment the following line to print out the compilation steps
    #cc.verbose = True

    @cc.export('multf', 'f8(f8, f8)')
    @cc.export('multi', 'i4(i4, i4)')
    def mult(a, b):
        return a * b

    @cc.export('square', 'f8(f8)')
    def square(a):
        return a ** 2

    if __name__ == "__main__":
        cc.compile()

If you run this Python script, it will generate an extension module named `my_module`. Depending on your platform, the actual filename may be `my_module.so`, `my_module.pyd`, `my_module.cpython-34m.so`, etc.

The generated module has three functions: `multf`, `multi` and `square`. `multi` operates on 32-bit integers (`i4`), while `multf` and `square` operate on double-precision floats (`f8`):

    >>> import my_module
    >>> my_module.multi(3, 4)
    12
    >>> my_module.square(1.414)
    1.9993959999999997

### 1.8.2.2. Distutils integration

You can also integrate the compilation step for your extension modules in your `setup.py` script, using distutils or setuptools:

    from distutils.core import setup

    from source_module import cc

    setup(...,
          ext_modules=[cc.distutils_extension()])

The `source_module` above is the module defining the `cc` object. Extensions compiled like this will be automatically included in the build files for your Python project, so you can distribute them inside binary packages such as wheels or Conda packages.

### 1.8.2.3. Signature syntax

The syntax for exported signatures is the same as in the `@jit` decorator. You can read more about it in the types reference.

Here is an example of exporting an implementation of the second-order centered difference on a 1d array:

    @cc.export('centdiff_1d', 'f8[:](f8[:], f8)')
    def centdiff_1d(u, dx):
        D = np.empty_like(u)
        D[0] = 0
        D[-1] = 0
        for i in range(1, len(D) - 1):
            D[i] = (u[i+1] - 2 * u[i] + u[i-1]) / dx**2
        return D

You can also omit the return type, which will then be inferred by Numba:

    @cc.export('centdiff_1d', '(f8[:], f8)')
    def centdiff_1d(u, dx):
        # Same code as above
        ...