Call C/C++ from Codon
C/C++ functions can be called from Codon via the from C import
import statement. Unlike standard imports, from C import must
specify the imported function's argument and return types. For
example:
# import the C standard library 'sqrt' function
from C import sqrt(float) -> float
print(sqrt(2.0)) # 1.41421
You can also rename C-imported functions:
# cobj is a C pointer (void*, char*, etc.)
# None can be used to represent C's void
from C import puts(cobj) -> None as print_line
print_line("hello".c_str()) # prints "hello"; c_str() converts Codon str to C string
You can also add annotations such as
@pure to C-imported functions by instead declaring them with the @C
attribute:
@C
@pure
def sqrt(x: float) -> float:
pass
print(sqrt(2.0)) # 1.41421
Warning
If you're using C++, remember to declare any functions you want to call from
Codon with extern "C" to enable C linkage, which Codon expects.
Type conversions¶
The following table shows the conversions between Codon and C/C++ types:
| Codon | C/C++ |
|---|---|
int |
int64_t |
float |
double |
bool |
bool |
complex |
{double, double} (real and imag.) |
str |
{int64_t, char*} (length and data) |
tuple |
Struct of fields |
class |
Pointer to corresponding tuple |
Ptr[T] |
T* |
Warning
Use caution when returning structures from C-imported functions, as C compilers might use an ABI that differs from Codon's ABI. It is recommended to instead pass a pointer as an argument that the callee can populate with the return value.
Optionals¶
Codon also has an Optional[T] type for representing None values, which
is represented in one of two ways:
-
If
Tis a reference type (i.e. a type defined withclass), thenOptional[T]is represented the same way asT(i.e. a pointer to dynamically-allocated member data) with null representingNone. -
Otherwise,
Optional[T]is represented as a C structure{bool, T}where the boolean field indicates whether the value is present.
NumPy arrays¶
NumPy array types are parameterized by the data type (dtype) and array dimension
(ndim). They correspond to the following C structure definition:
struct ndarray {
int64_t shape[ndim];
int64_t strides[ndim];
dtype *data
};
Refer to the NumPy documentation for an explanation of these fields.
Dynamic loading¶
Shared libraries can be loaded dynamically as follows:
LIBRARY = "libhello.so"
# load dynamically from 'libhello.so'
from C import LIBRARY.foo(int, float) -> None
from C import LIBRARY.bar() -> int as baz
x = foo(1, 2.2)
y = baz()
Dynamic C imports are implemented by calling dlopen() on the given shared library,
followed by dlsym() to obtain the required functions.