CSlug API Reference¶
Module contents¶
- class cslug.CSlug(path, *sources, headers=(), links=(), flags=())[source]¶
Compiles and loads C code in a relatively safe and streamlined manner.
- __init__(path, *sources, headers=(), links=(), flags=())[source]¶
- Parameters
path (str or os.PathLike or list) –
*sources (str or os.PathLike or io.TextIOBase) – C source code files. May also be lists of files.
headers (cslug.Header or list[cslug.Header]) – cslug generated headers - not just
*.h
files (which cslug doesn't need to see anywhere).links (str or list[str]) – Other C libraries to link to via the
-l
compiler switch. Should not contain the-l
prefix or platform suffix.flags (str or list[str]) – Additional flags to be passed directly to the C compiler. Can also be configured using the
CC_FLAGS
environment variable. Inspect usingcompile_command
.
Changed in version 0.3.0: Add flags parameter and the
CC_FLAGS
variable.
- close(all=True)[source]¶
Close the library stored in
CSlug.dll
.- Parameters
all (bool) – Close any other existing handles to the same file.
Closing is required before a recompile to avoid permission errors or dangling pointers. If the library is already closed, this function silently does nothing.
- compile()[source]¶
Recompile C code only.
- Returns
True if the compile succeeded. However this is redundant because an error is raised if it didn't.
- Return type
- Raises
exceptions.BuildError – Any compiler errors are propagated as Python exceptions.
- Warns
exceptions.BuildWarning – Any build warnings from the compiler are propagated as Python warnings.
- compile_command(_cc=None, _cc_version=None)[source]¶
Get the compile command invoked by
compile
.I hope to eventually make this function configurable.
- property dll¶
The open C library.
- Returns
- Return type
This attribute is lazily loaded. On first access, this
property
will:Check the library has been compiled and invoke a full compile with
make
if it hasn't.Open the library.
Initialise type information for all known symbols (functions).
Use
close
to reset.
- make()[source]¶
Invoke a full recompile and refresh of everything.
- Returns
True if the build succeeded.
- Return type
Everything here is defined as the following sequence in the following order:
close
any open handles.Rebuild each
Header
inheaders
usingHeader.make
.Recompile the shared library using :meth`compile`.
Rescan C source code for type information and write it to a json file.
The C library is loaded back into Python on next access of
dll
.
- cslug.anchor(*paths)[source]¶
Replace relative paths with frozen paths relative to
__file__
's parent.- Parameters
paths (str or os.PathLike or io.IOBase) – Path(s) to freeze or pseudo files.
- Returns
List of modified paths.
- Return type
Pseudo files (
io.IOBase
) and absolute paths are left unchanged. Use this function to make your code working-dir independent.
- class cslug.Header(path, *sources, includes=(), defines=())[source]¶
Automatically generate a header file.
For every function in every source file, generate a prototype for it. Use to automate the unfortunate copy/pasting required for multiple source files to interact with each other.
Using a header like this globalises every function. Whilst this type of namespace collapsing would normally be discouraged, a shared library does not allow naming collisions anyway so there is little to no advantage in keeping namespaces separate.
- class cslug.Types(path, *sources, headers=(), compact=True)[source]¶
Manages type information which is not found in a shared libraryAn executable file containing definitions (function/variables/...) but no main method..
Scans source code for:
The name, argument and return types of each function.
The name, field names, types and bit-field sizes of structures.
Stores the above in a portable and quickly deserializable json file.
Sets the types for the contents of a
ctypes.CDLL
.
- __init__(path, *sources, headers=(), compact=True)[source]¶
- Parameters
path (str or os.PathLike or io.TextIOBase) – A filename to read or write serialised type information to.
*sources (str or os.PathLike or io.TextIOBase) – C sources to extract function definitions from.
headers (str or os.PathLike or io.TextIOBase or list) – C sources to extract function prototypes from.
compact (bool) – If true, serialise minimising file size. Otherwise, pretty format for human readability.
Note the distinction between sources and headers. A function prototype such as
int foo();
will be ignored if found in sources but included if it were in headers. A true function definition such asint foo() {}
, as well as structure definitions would be collected in either case.
- apply(dll, strict=False)[source]¶
Set the type information for the contents of dll.
- Parameters
dll (ctypes.CDLL) – The opened shared libraryAn executable file containing definitions (function/variables/...) but no main method. to apply type information to.
strict (bool) – Raise an
AttributeError
if a symbol wasn't found.
For every structure in
self.structs
, turn it into actypes.Structure
and set it as an attribute of dll. For every function inself.functions
, get it from dll then set itsargtypes
andrestype
attributes.Note
Structures don't normally go in shared librariesAn executable file containing definitions (function/variables/...) but no main method. but cslug lobs them in there for simplicity.
- property functions: dict¶
All functions (from true definitions of prototypes).
The format is:
function_name: [return_type, [arg_type, arg_type, ...]]
All types are strings - either names of structures or attribute names of
ctypes
.
- json_path: Union[io.TextIOBase, pathlib.Path]¶
File to read or write the json.
- property structs: dict¶
All structures defined using
typedef struct {…} name
.The format is:
name: [(field_name, field_type), ...]
Or for bit-field structs:
name: [(field_name, field_type, bit_length), ...]
- types: dict¶
All type information collected. This is broken out into
functions
andstructs
.Note that this attribute is not set automatically. You must explicitly call either
init_from_source
orinit_from_json
before accessing.
- write(path=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>)[source]¶
Serialise contents to path.
- Parameters
path (str or os.PathLike or io.TextIOBase) – A filename or stream to write to. Defaults to
sys.stdout
.
- cslug.ptr(bytes_like)[source]¶
Get the raw address of any Python object supporting the C buffer protocol.
A bytes-like object is anything for which calling
memoryview(obj)
doesn't raise aTypeError
. This includesbytes
,bytearray
,memoryview
,array.array
andnumpy.array
. The output is a subclass ofint
.>>> from cslug import ptr >>> ptr(bytearray([10, 12, 20, 45])) <Void Pointer 140533125025616>
Pass the output of this function to a C function which expects a pointer.
On calling this function on a buffer, the buffer's reference count is incremented to prevent it from being deleted whilst you're still using it. This reference count is decremented on deletion of the pointer returned by this function. With this in place, you generally shouldn't need to worry about holding onto or releasing memory. There is one exception to this: If you use pointer arithmetic, preducts of that arithmetic are just regular integers and do not carry the reference.
If you are using
numpy
then you should be aware that this method only accepts C-contiguous buffers. If you understand how contiguity works and have explicitly supported non-contiguous buffers in your C code then you may usenc_ptr
instead. Otherwise convert your arrays to contiguous ones using either:array = np.ascontiguousarray(array)
or:
array = np.asarray(array, order="C")
- cslug.nc_ptr(bytes_like)[source]¶
Retrieve a pointer to a non-contiguous buffer.
Use with caution. If your function assumes a contiguous array but gets a non-contiguous one then you will either get garbage results or memory errors.
- class cslug.PointerType(bytes_like, flags)[source]¶
Bases:
int
A raw pointer which inc-refs the buffer it points to.
Please no not instantiate this class directly. Instead use the
ptr()
function.
- cslug.cc(CC=None)[source]¶
Get the full path of the C compiler.
- Parameters
CC – Value to override the CC environment variable.
- Returns
Full path of the C compiler.
- Return type
- Raises
exceptions.NoGccError – If CC is unset and gcc was not found in
PATH
.exceptions.CCNotFoundError – If CC is set but couldn't be found.
exceptions.BuildBlockedError – If CC is set to
!block
.
The C compiler is chosen by the CC environment variable.
If CC is unset then it defaults to
gcc
.If CC is a name, such as
gcc
orclang
, then it is searched for inPATH
(respectingPATHEXT
on Windows).If CC is a relative path, such as
./gcc
, then it is made absolute.If CC is an absolute path then it is returned as is.
If CC is
!block
then an error is raised. This can be used to test your pre-built package works without a compiler.
Note
The value of CC should never be wrapped in quotes.
- cslug.cc_version(CC=None)[source]¶
Get C compiler's name and version.
The
name
is determined by parsing the output of$CC -v
(or%CC% -v
on Windows). It can be:'gcc'
for gcc (both 32 and 64 bit).'tcc'
for TinyCC including the 32-biti386-win32-tcc
version.'clang'
for clang.'pcc'
for Portable C Compiler.'PGCC'
for pgcc.
The
version_info
is in the standard(major, minor, micro)
version format.