litgen options#
litgen uses numerous options which can be found here: litgen/options.py.
Note about regexes#
Many options use regexes: see the note about their usage in the options.py file:
regexes can support several alternatives: separate them by “|”.
For example, in order to match an exact function name (YourFunctionName
), as well as functions ending with _private
, use a regex like this:
r"^YourFunctionName$|_private$",
Tips:
If a regex string is empty, it will not match anything (this is specific to litgen)
To match everything, use r”.*”
It is advised to prefix your regex strings with “r” (in order to use raw strings)
litgen main options#
Below, we show the content of litgen/options.py:
from codemanip import code_utils
from litgen.demo import litgen_demo
litgen_options_code = code_utils.download_url_content(
"https://raw.githubusercontent.com/pthom/litgen/main/src/litgen/options.py"
)
litgen_demo.show_python_code(litgen_options_code, title="litgen/options.py")
from __future__ import annotations
from enum import Enum
from typing import Any, Callable, List
from codemanip import code_utils
from codemanip.code_replacements import RegexReplacementList
from srcmlcpp import SrcmlcppOptions
from litgen.internal.template_options import TemplateFunctionsOptions, TemplateClassOptions
from litgen.internal.class_iterable_info import ClassIterablesInfos
class BindLibraryType(Enum):
pybind11 = 1
nanobind = 2
class LitgenOptions:
"""Numerous options to configure litgen code generation.
(include / excludes, indentation, c++ to python translation settings, function parameters
adaptations, etc.)"""
# ------------------------------------------------------------------------------
# Note about regexes below:
# =========================
# - regexes can support several alternatives: separate them by "|"
# For example, in order to match an exact function name, as well as functions ending with "_private",
# use a regex like this:
# r"^YourFunctionName$|_private$",
# - If a regex string is empty, it will not match anything
# - To match everything, use r".*"
# - It is advised to prefix your regex strings with "r" (in order to use raw strings)
# ------------------------------------------------------------------------------
################################################################################
# <bind library options>
################################################################################
#
bind_library: BindLibraryType = BindLibraryType.pybind11
################################################################################
# <srcmlcpp options>
################################################################################
# There are interesting options to set in SrcmlcppOptions (see srcmlcpp/srcmlcpp_options.py)
#
# Notably:
# * fill srcmlcpp_options.functions_api_prefixes: the prefix(es) that denotes exported dll functions
# * also set LitgenOptions.fn_exclude_non_api=True if you want to exclude non api functions and methods
srcmlcpp_options: SrcmlcppOptions
################################################################################
# <Layout settings for the generated python stub code>
################################################################################
# <show the original location and or signature of elements as a comment>
original_location_flag_show = False
# if showing location, how many parent folders shall be shown
# (if -1, show the full path)
original_location_nb_parent_folders = 0
# If True, the complete C++ original signature will be show as a comment in the python stub (pyi)
original_signature_flag_show = False
# Size of an indentation in the python stubs
python_indent_size = 4
python_ident_with_tabs: bool = False
# Insert as many empty lines in the python stub as found in the header file, keep comments layout, etc.
python_reproduce_cpp_layout: bool = True
# The generated code will try to adhere to this max length (if negative, this is ignored)
python_max_line_length = 88
# Strip (remove) empty comment lines
python_strip_empty_comment_lines: bool = False
# Run black formatter
python_run_black_formatter: bool = False
python_black_formatter_line_length: int = 88
################################################################################
# <Layout settings for the C++ generated pydef code>
################################################################################
# Spacing option in C++ code
cpp_indent_size: int = 4
cpp_indent_with_tabs: bool = False
################################################################################
# <Disable comments inclusion in C++ and Python>
################################################################################
comments_exclude: bool = False
################################################################################
# <names translation from C++ to python>
################################################################################
# Convert variables, functions and namespaces names to snake_case (class, structs, and enums names are always preserved)
python_convert_to_snake_case: bool = True
# List of code replacements when going from C++ to Python
# Notes:
# - by default, type_replacements is prefilled with standard_type_replacements()
# type_replacements will be applied to all types (including class and enum names)
# - by default, value_replacements is prefilled with standard_value_replacements()
# - by default, comments_replacements is prefilled with standard_comments_replacements()
# - by default, the others are empty
# - type_replacements, var_names_replacements and function_names_replacements enable you
# to modify the outputted python code
type_replacements: RegexReplacementList # = cpp_to_python.standard_type_replacements() by default
var_names_replacements: RegexReplacementList # = RegexReplacementList() by default (i.e. empty)
namespace_names_replacements: RegexReplacementList # = RegexReplacementList() by default (i.e. empty)
function_names_replacements: RegexReplacementList # = RegexReplacementList() by default (i.e. empty)
value_replacements: RegexReplacementList # = cpp_to_python.standard_value_replacements() by default
comments_replacements: RegexReplacementList # = cpp_to_python.standard_comment_replacements() by default
macro_name_replacements: RegexReplacementList # = RegexReplacementList() by default (i.e. empty)
################################################################################
# <functions and method adaptations>
################################################################################
# ------------------------------------------------------------------------------
# Exclude some functions
# ------------------------------------------------------------------------------
# Exclude certain functions and methods by a regex on their name
fn_exclude_by_name__regex: str = ""
# Exclude certain functions and methods by a regex on any of their parameter type and/or return type
# (those should be decorated type)
# For example:
# options.fn_exclude_by_param_type__regex = "^char\s*$|^unsigned\s+char$|Callback$"
# would exclude all functions having params of type "char *", "unsigned char", "xxxCallback"
#
# Note: this is distinct from `fn_params_exclude_types__regex` which removes params
# from the function signature, but not the function itself.
fn_exclude_by_param_type__regex: str = ""
# Exclude function and methods by its name and signature
# For example:
# options.fn_exclude_by_name_and_signature = {
# "Selectable": "const char *, bool, ImGuiSelectableFlags, const ImVec2 &"
# }
fn_exclude_by_name_and_signature: dict[str, str]
# ------------------------------------------------------------------------------
# Exclude some params by name or type
# ------------------------------------------------------------------------------
# Remove some params from the python published interface. A param can only be removed if it has a default value
# in the C++ signature
fn_params_exclude_names__regex: str = ""
fn_params_exclude_types__regex: str = ""
# fn_exclude_non_api:
# if srcmlcpp_options.functions_api_prefixes is filled, and fn_exclude_non_api=True,
# then only functions with an api marker will be exported.
fn_exclude_non_api: bool = True
# fn_non_api_comment:
# if fn_exclude_non_api is False, a comment can be added to non api functions in the stub file
fn_non_api_comment: str = "(private API)"
# ------------------------------------------------------------------------------
# Templated functions options
# ------------------------------------------------------------------------------
# Template function must be instantiated for the desired types.
# See https://pybind11.readthedocs.io/en/stable/advanced/functions.html#binding-functions-with-template-parameters
#
# fn_template_options:
# of type Dict[ TemplatedFunctionNameRegexStr (aka str), List[CppTypeName] ]
#
# For example,
# 1. This line:
# options.fn_template_options.add_specialization(r"template^", ["int", double"])
# would instantiate all template functions whose name end with "template" with "int" and "double"
# 2. This line:
# options.fn_template_options.add_specialization(r".*", ["int", float"])
# would instantiate all template functions (whatever their name) with "int" and "float"
# 3. This line:
# options.fn_template_options.add_ignore(r".*")
# would ignore all template functions (they will not be exported)
fn_template_options: TemplateFunctionsOptions
# if fn_template_decorate_in_stub is True, then there will be some
# decorative comments in the stub file, in order to visually group
# the generated functions together
fn_template_decorate_in_stub: bool = True
# ------------------------------------------------------------------------------
# Vectorize functions options (pybind11 only, not compatible with nanobind)
# ------------------------------------------------------------------------------
# Numeric functions (i.e. function accepting and returning only numeric params or py::array), can be vectorized
# i.e. they will accept numpy arrays as an input.
# See https://pybind11.readthedocs.io/en/stable/advanced/pycpp/numpy.html#vectorizing-functions
# and https://github.com/pybind/pybind11/blob/master/tests/test_numpy_vectorize.cpp
#
# * fn_vectorize__regex and fn_namespace_vectorize__regex contain a regexes
# on functions names + namespace names for which this transformation will be applied.
#
# For example, to vectorize all function of the namespace MathFunctions, apply these options:
# options.fn_namespace_vectorize__regex: str = r"MathFunctions^$"
# options.fn_vectorize__regex = r".*"
#
# * fn_vectorize_prefix and fn_vectorize_suffix will be added to the vectorized functions names
# (they can be empty, in which case the vectorized function will be a usable overload with the same name)
fn_vectorize__regex: str = r""
fn_namespace_vectorize__regex: str = r""
fn_vectorize_prefix: str = ""
fn_vectorize_suffix: str = ""
# ------------------------------------------------------------------------------
# Return policy
# ------------------------------------------------------------------------------
# Force the function that match those regexes to use `pybind11::return_value_policy::reference`
#
# Note:
# you can also write "// py::return_value_policy::reference" as an end of line comment after the function.
# See packages/litgen/integration_tests/mylib/include/mylib/return_value_policy_test.h as an example
fn_return_force_policy_reference_for_pointers__regex: str = ""
fn_return_force_policy_reference_for_references__regex: str = ""
# ------------------------------------------------------------------------------
# Force overload
# ------------------------------------------------------------------------------
# Force using py::overload for functions that matches these regexes
fn_force_overload__regex: str = ""
# Force using a lambda for functions that matches these regexes
# (useful when pybind11 is confused and gives error like
# error: no matching function for call to object of type 'const detail::overload_cast_impl<...>'
fn_force_lambda__regex: str = ""
# ------------------------------------------------------------------------------
# C style buffers to py::array
# ------------------------------------------------------------------------------
#
# Signatures with a C buffer like this:
# MY_API inline void add_inside_array(uint8_t* array, size_t array_size, uint8_t number_to_add)
# may be transformed to:
# void add_inside_array(py::array & array, uint8_t number_to_add) (c++ bound signature)
# def add_inside_array(array: numpy.ndarray, number_to_add: int) -> None (python)
#
# It also works for templated buffers:
# MY_API template<typename T> void mul_inside_array(T* array, size_t array_size, double factor)
# will be transformed to:
# void mul_inside_array(py::array & array, double factor) (c++ bound signature)
# def mul_inside_array(array: numpy.ndarray, factor: float) -> None (python)
# (and factor will be down-casted to the target type)
#
# fn_params_buffer_replace_by_array_regexes contains a regex on functions names
# for which this transformation will be applied.
# Set it to r".*" to apply this to all functions, set it to "" to disable it
#
fn_params_replace_buffer_by_array__regex: str = r""
# fn_params_buffer_types: list of numeric types that are considered as possible buffers.
# You can customize this list in your own options by removing items from it,
# but you *cannot* add new types or new synonyms (typedef for examples); since the conversion between
# py::array and native relies on these *exact* names!
#
# By default, fn_params_buffer_types will contain those types:
fn_params_buffer_types: str = code_utils.join_string_by_pipe_char(
[
"uint8_t",
"int8_t",
"uint16_t",
"int16_t",
"uint32_t",
"int32_t",
"np_uint_l", # Platform dependent: "uint64_t" on *nixes, "uint32_t" on windows
"np_int_l", # Platform dependent: "int64_t" on *nixes, "int32_t" on windows
"float",
"double",
"long double",
"long long",
]
)
# fn_params_buffer_template_types: list of templated names that are considered as possible templated buffers
# By default, only template<typename T> or template<typename NumericType> are accepted
fn_params_buffer_template_types: str = code_utils.join_string_by_pipe_char(["T", "NumericType"])
# fn_params_buffer_size_names__regex: possible names for the size of the buffer
# = ["nb", "size", "count", "total", "n"] by default
fn_params_buffer_size_names__regex: str = code_utils.join_string_by_pipe_char(
[
code_utils.make_regex_var_name_contains_word("nb"),
code_utils.make_regex_var_name_contains_word("size"),
code_utils.make_regex_var_name_contains_word("count"),
code_utils.make_regex_var_name_contains_word("total"),
code_utils.make_regex_var_name_contains_word("n"),
]
)
# ------------------------------------------------------------------------------
# C style arrays functions and methods parameters
# ------------------------------------------------------------------------------
#
# Signatures like
# void foo_const(const int input[2])
# may be transformed to:
# void foo_const(const std::array<int, 2>& input) (c++ bound signature)
# def foo_const(input: List[int]) -> None: (python)
# fn_params_replace_c_array_const_by_std_array__regex contains a list of regexes on functions names
# for which this transformation will be applied.
# Set it to r".*" to apply this to all functions, set it to "" to disable it
fn_params_replace_c_array_const_by_std_array__regex: str = r".*"
# Signatures like
# void foo_non_const(int output[2])
# may be transformed to:
# void foo_non_const(BoxedInt & output_0, BoxedInt & output_1) (c++ bound signature)
# def foo_non_const(output_0: BoxedInt, output_0: BoxedInt) -> None (python)
# fn_params_replace_c_array_modifiable_by_boxed__regex contains a list of regexes on functions names
# for which this transformation will be applied.
# Set it to r".*" to apply this to all functions, set it to "" to disable it
fn_params_replace_c_array_modifiable_by_boxed__regex: str = r".*"
# (c_array_modifiable_max_size is the maximum number of params that can be boxed like this)
fn_params_replace_modifiable_c_array__max_size = 10
# ------------------------------------------------------------------------------
# C style string list functions and methods parameters
# ------------------------------------------------------------------------------
# Signatures like
# void foo(const char * const items[], int items_count)
# may be transformed to:
# void foo(const std::vector<std::string>& const items[]) (c++ bound signature)
# def foo(items: List[str]) -> None (python)
# fn_params_replace_c_string_list_regexes contains a list of regexes on functions names
# for which this transformation will be applied.
# Set it to [r".*"] to apply this to all functions, set it to [] to disable it
fn_params_replace_c_string_list__regex: str = r".*"
# ------------------------------------------------------------------------------
# Make "immutable python types" modifiable, when passed by pointer or reference
# ------------------------------------------------------------------------------
#
# adapt functions params that use non const pointers or reference to a type that is immutable in python.
# Signatures like
# int foo(int* value)
# May be transformed to:
# def foo(BoxedInt value) -> int (python)
# So that any modification done on the C++ side can be seen from python.
#
# fn_params_adapt_modifiable_immutable_regexes contains a list of regexes on functions names
# Set it to r".*" to apply this to all functions. Set it to "" to disable it
fn_params_replace_modifiable_immutable_by_boxed__regex: str = r""
# ------------------------------------------------------------------------------
# Make "mutable default parameters" behave like C++ default arguments
# (i.e. re-evaluate the default value each time the function is called)
# ------------------------------------------------------------------------------
# Regex which contains a list of regexes on functions names for which this transformation will be applied.
# by default, this is disabled (set it to r".*" to enable it for all functions)
fn_params_adapt_mutable_param_with_default_value__regex: str = r""
# if True, auto-generated named constructors will adapt mutable default parameters
fn_params_adapt_mutable_param_with_default_value__to_autogenerated_named_ctor: bool = False
# if True, a comment will be added in the stub file to explain the behavior
fn_params_adapt_mutable_param_with_default_value__add_comment: bool = True
# fn_params_adapt_mutable_param_with_default_value__fn_is_known_immutable_type
# may contain a user defined function that will determine if a type is considered immutable in python based on its name.
# By default, all the types below are considered immutable in python:
# "int|float|double|bool|char|unsigned char|std::string|..."
fn_params_adapt_mutable_param_with_default_value__fn_is_known_immutable_type: Callable[[str], bool] | None = None
# Same as above, but for values
fn_params_adapt_mutable_param_with_default_value__fn_is_known_immutable_value: Callable[[str], bool] | None = None
# ------------------------------------------------------------------------------
# Convert `const char* x = NULL` for Python passing None without TypeError
# ------------------------------------------------------------------------------
# Signatures like
# void foo(const char* text = NULL)
# may be transformed to:
# void foo(std::optional<std::string> text = std::nullopt)
# with a lambda function wrapping around original interface.
#
# NOTE: Enable this for nanobind.
fn_params_const_char_pointer_with_default_null: bool = True
# As an alternative, we can also add the modified value to the returned type
# of the function (which will now be a tuple)
#
# For example
# int foo(int* value)
# May be transformed to:
# def foo(int value) -> Tuple[int, bool]
# So that any modification done on the C++ side can be seen from python.
#
# fn_params_output_modifiable_immutable_to_return__regex contains a list of regexes on functions names
# Set it to r".*" to apply this to all functions. Set it to "" to disable it
fn_params_output_modifiable_immutable_to_return__regex: str = ""
# ------------------------------------------------------------------------------
# Custom adapters (advanced, very advanced and not documented here)
# fn_custom_adapters may contain callables of signature
# f(adapted_function: AdaptedFunction) -> Optional[LambdaAdapter]
# ------------------------------------------------------------------------------
fn_custom_adapters: list[Any]
################################################################################
# <class, struct, and member adaptations>
################################################################################
# Exclude certain classes and structs by a regex on their name
class_exclude_by_name__regex: str = ""
# Exclude certain members by a regex on their name
member_exclude_by_name__regex: str = ""
# Exclude members based on their type
member_exclude_by_type__regex: str = ""
# Exclude certain members by a regex on their name, if class or struct name matched
# For example:
# options.member_exclude_by_name_and_class__regex = {
# "ImVector": join_string_by_pipe_char([
# r"^Size$",
# r"^Capacity$",
# ...
# ])
# }
member_exclude_by_name_and_class__regex: dict[str, str]
# Make certain members read-only by a regex on their name
member_readonly_by_name__regex: str = ""
# Make certain members read-only based on their type
member_readonly_by_type__regex: str = ""
# class_create_default_named_ctor__regex / struct_create_default_named_ctor__regex:
# regex giving the list of class & struct names for which we want to generate a named
# constructor for Python, when no default constructor is provided by C++
# (by default, this is active for all structs and not for the classes,
# in order for it to work, all struct members need to be default constructible if
# they are not declared with a default value)
struct_create_default_named_ctor__regex: str = r".*"
class_create_default_named_ctor__regex: str = r""
# class_expose_protected_methods__regex:
# regex giving the list of class names for which we want to expose protected methods.
# (by default, only public methods are exposed)
# If active, this will use the technique described at
# https://pybind11.readthedocs.io/en/stable/advanced/classes.html#binding-protected-member-functions)
class_expose_protected_methods__regex: str = ""
# class_expose_protected_methods__regex:
# regex giving the list of class names for which we want to be able to override virtual methods
# from python.
# (by default, this is not possible)
# If active, this will use the technique described at
# https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python
#
# Note: if you want to override protected functions, also fill `class_expose_protected_methods__regex`
class_override_virtual_methods_in_python__regex: str = ""
# class_dynamic_attributes__regex
# By default, classes exported from C++ do not support dynamic attributes and the only writable attributes are
# the ones explicitly defined using class_::def_readwrite() or class_::def_property().
# If active, this will use the technique described at
# https://pybind11.readthedocs.io/en/stable/classes.html#dynamic-attributes
class_dynamic_attributes__regex: str = ""
# class_deep_copy__regex & class_copy__regex:
# By default, structs and classes exported from C++ do not support (deep)copy.
# However, if they do have a copy constructor (implicit or user defined),
# (deep)copy can be enabled by invoking this constructor.
# https://pybind11.readthedocs.io/en/stable/advanced/classes.html#deepcopy-support
class_deep_copy__regex: str = ""
class_copy__regex: str = ""
# If class_copy_add_info_in_stub=True, the existence of __copy__ and __deepcopy__
# will be mentioned in the stub file.
class_copy_add_info_in_stub: bool = False
# iterable classes: if some cpp classes expose begin()/end()/size(), they can be made iterable in python
# Make classes iterables by setting:
# options.class_iterables_infos.add_iterable_class(python_class_name__regex, iterable_python_type_name)
class_iterables_infos: ClassIterablesInfos
# class_held_as_shared__regex:
# Regex specifying the list of class names that should be held using std::shared_ptr in the generated bindings
# (when using pybind11. This is unused for nanobind)
#
# **Purpose:**
# By default, pybind11 uses `std::unique_ptr` as the holder type for bound classes.
#
# **When to Use:**
# If your C++ code uses `std::shared_ptr` to manage instances of a class (e.g., as member variables, return types,
# or parameters), and you expose that class to Python, you need to ensure that pybind11 uses `std::shared_ptr` as
# the holder type for that class.
#
# **References:**
# - [pybind11 Documentation: Smart Pointers](https://pybind11.readthedocs.io/en/stable/advanced/smart_ptrs.html)
# - [Understanding Holder Types in pybind11](https://pybind11.readthedocs.io/en/stable/advanced/classes.html#custom-smart-pointers)
class_held_as_shared__regex: str = ""
# ------------------------------------------------------------------------------
# Templated class options
# ------------------------------------------------------------------------------
# Template class must be instantiated for the desired types, and a new name must be given for each instantiation
# See https://pybind11.readthedocs.io/en/stable/advanced/classes.html#binding-classes-with-template-parameters
#
# class_template_options enables to set this
#
# For example
# 1. this call would instantiate some classes for types "int" and "const char *", with a naming scheme:
# MyClass<int> (cpp) -> MyClassInt (python)
# ------------------------------------------
# options.class_template_options.add_specialization(
# class_name_regex=r"^MyPrefix", # r"^MyPrefix" => select class names with this prefix
# cpp_types_list=["int", "const char *"], # instantiated types
# naming_scheme=TemplateNamingScheme.camel_case_suffix
# )
# 2. this call would ignore all template classes:
# options.class_template_options.add_ignore(r".*")
# would ignore all template functions (they will not be exported)
class_template_options: TemplateClassOptions
# if class_template_decorate_in_stub is True, then there will be some
# decorative comments in the stub file, in order to visually group
# the generated classes together
class_template_decorate_in_stub: bool = True
# ------------------------------------------------------------------------------
# Adapt class members
# ------------------------------------------------------------------------------
# adapt class members which are a fixed size array of a numeric type:
#
# For example
# struct Foo { int values[10]; };
# May be transformed to:
# class Foo:
# values: numpy.ndarray
#
# i.e. the member will be transformed to a property that points to a numpy array
# which can be read/written from python (this requires numpy)
# This is active by default.
member_numeric_c_array_replace__regex: str = r".*"
# member_numeric_c_array_types: list of numeric types that can be stored in a numpy array
# for a class member which is a fixed size array of a numeric type
# - Synonyms (defined via. `typedef` or `using`) are allowed here
# - *don't* include char, *don't* include byte, those are not numeric!
# See https://numpy.org/doc/stable/reference/generated/numpy.chararray.html
member_numeric_c_array_types: str = code_utils.join_string_by_pipe_char(
[
"int",
"unsigned int",
"long",
"unsigned long",
"long long",
"unsigned long long",
"float",
"double",
"long double",
"uint8_t",
"int8_t",
"uint16_t",
"int16_t",
"uint32_t",
"int32_t",
"uint64_t",
"int64_t",
"bool",
]
)
################################################################################
# <namespace adaptations>
################################################################################
# All C++ namespaces in this list will not be emitted as a submodule
# (i.e. their inner code will be placed in the root python module, or in the parent
# module)
namespaces_root: List[str]
# All C++ namespaces that match this regex will be excluded
# By default, any namespace whose name contains "internal" or "detail" will be excluded.
namespace_exclude__regex = r"[Ii]nternal|[Dd]etail"
################################################################################
# <enum adaptations>
################################################################################
# Exclude certain enums by a regex on their name
enum_exclude_by_name__regex: str = ""
# Remove the typical "EnumName_" prefix from "C enum" values.
# For example, with the C enum:
# enum MyEnum { MyEnum_A = 0, MyEnum_B };
# Values would be named "a" and "b" in python
enum_flag_remove_values_prefix: bool = True
# A specific case for ImGui, which defines private enums which may extend the public ones:
# enum ImGuiMyFlags_ { ImGuiMyFlags_None = 0,...}; enum ImGuiMyFlagsPrivate_ { ImGuiMyFlags_PrivValue = ...};
enum_flag_remove_values_prefix_group_private: bool = False
# Skip count value from enums, for example like in:
# enum MyEnum { MyEnum_A = 1, MyEnum_B = 1, MyEnum_COUNT };
enum_flag_skip_count: bool = True
# By default, all enums export rudimentary arithmetic and bit-level operations ( r".*" matches any enum name)
enum_make_arithmetic__regex: str = r".*"
# Export all entries of the enumeration into the parent scope.
enum_export_values: bool = False
################################################################################
# <define adaptations>
################################################################################
# Simple preprocessor defines can be exported as global variables, e.g.:
# #define MY_VALUE 1
# #define MY_FLOAT 1.5
# #define MY_STRING "abc"
# #define MY_HEX_VALUE 0x00010009
# This is limited to *simple* defines (no param, string, int, float or hex only)
# By default nothing is exported
macro_define_include_by_name__regex: str = ""
################################################################################
# <globals vars adaptations>
################################################################################
# Global variable defines can be exported as global variables, e.g.:
# By default nothing is exported (still experimental)
globals_vars_include_by_name__regex: str = ""
################################################################################
# <post processing>
################################################################################
# If you need to process the code after generation, fill these functions
postprocess_stub_function: Callable[[str], str] | None = None # run at the very end
postprocess_pydef_function: Callable[[str], str] | None = None
################################################################################
# <Sanity checks and utilities below>
################################################################################
def check_options_consistency(self) -> None:
# the only authorized type are those for which the size is known with certainty
# * int and long are not acceptable candidates: use int8_t, uint_8t, int32_t, etc.
# * concerning float and doubles, there is no standard for fixed size floats, so we have to cope with
# float, double and long double and their various platforms implementations...
authorized_types = [
"byte",
"uint8_t",
"int8_t",
"uint16_t",
"int16_t",
"uint32_t",
"int32_t",
"np_uint_l", # Platform dependent: "uint64_t" on *nixes, "uint32_t" on windows
"np_int_l", # Platform dependent: "int64_t" on *nixes, "int32_t" on windows
"float",
"double",
"long double",
"long long",
]
for buffer_type in self._fn_params_buffer_types_list():
if buffer_type not in authorized_types:
raise ValueError(
f"""
options.build_types contains an unauthorized type: {buffer_type}
Authorized types are: { ", ".join(authorized_types) }
"""
)
def _indent_cpp_spaces(self) -> str:
space = "\t" if self.cpp_indent_with_tabs else " "
return space * self.cpp_indent_size
def _indent_python_spaces(self) -> str:
space = "\t" if self.python_ident_with_tabs else " "
return space * self.python_indent_size
def _fn_params_buffer_types_list(self) -> list[str]:
return code_utils.split_string_by_pipe_char(self.fn_params_buffer_types)
def _fn_params_buffer_template_types_list(self) -> list[str]:
return code_utils.split_string_by_pipe_char(self.fn_params_buffer_template_types)
def _member_numeric_c_array_types_list(self) -> list[str]:
return code_utils.split_string_by_pipe_char(self.member_numeric_c_array_types)
def __init__(self) -> None:
# See doc for all the params at their declaration site (scroll up to the top of this file!)
from litgen.internal import cpp_to_python
self.srcmlcpp_options = SrcmlcppOptions()
self.srcmlcpp_options.header_filter_preprocessor_regions = True
self.type_replacements = cpp_to_python.standard_type_replacements()
self.value_replacements = cpp_to_python.standard_value_replacements()
self.comments_replacements = cpp_to_python.standard_comment_replacements()
self.function_names_replacements = RegexReplacementList()
self.var_names_replacements = RegexReplacementList()
self.macro_name_replacements = RegexReplacementList()
self.namespace_names_replacements = RegexReplacementList()
self.fn_template_options = TemplateFunctionsOptions()
self.class_template_options = TemplateClassOptions()
self.class_iterables_infos = ClassIterablesInfos()
self.fn_custom_adapters = []
self.namespaces_root = []
self.fn_exclude_by_name_and_signature = {}
self.member_exclude_by_name_and_class__regex = {}
srcmlcpp options#
litgen is based on srcmlcpp, which also provides some options, via LitgenOptions.srcmlcpp_options
. They are available at srcmlcpp/srcmlcpp_options.py
litgen_options_code = code_utils.download_url_content(
"https://raw.githubusercontent.com/pthom/litgen/main/src/srcmlcpp/srcmlcpp_options.py"
)
litgen_demo.show_python_code(litgen_options_code, title="srcmlcpp/srcmlcpp_options.py")
"""
Options for srcmlcpp. Read the doc near all options elements.
"""
from __future__ import annotations
from typing import Callable, Optional
from codemanip.code_utils import split_string_by_pipe_char
from srcmlcpp.scrml_warning_settings import WarningType
class SrcmlcppOptions:
################################################################################
# <API prefixes for functions / API comment suffixes for classes>
################################################################################
# Prefixes that denote exported dll functions.
# For example, you could use "MY_API" which would be defined as `__declspec(dllexport|dllimport)` on windows
# You can have several prefixes: separate them with a "|", for example: "MY_API|OTHER_API"
#
# If you filled SrcmlcppOptions.functions_api_prefixes, then those prefixes will be mentioned
# as specifiers for the return type of the functions.
functions_api_prefixes: str = ""
################################################################################
# <Numbers parsing: resolve macros values>
################################################################################
# List of named possible numbers or sizes (fill it if some number/sizes are defined by macros or constexpr values)
# For example it could store `{ "SPACE_DIMENSIONS" : 3 }` if the C++ code uses a macro `SPACE_DIMENSIONS`
named_number_macros: dict[str, int]
################################################################################
# <Exclude certain regions based on preprocessor macros>
################################################################################
# Set header_filter_preprocessor_regions to True if the header has regions
# that you want to exclude from the parsing, like this:
# #ifdef SOME_RARE_OPTION
# // code we want to exclude
# #endif
#
# See srcmlcpp/filter_preprocessor_regions.py for more complete examples
header_filter_preprocessor_regions: bool = False
# If header_filter_preprocessor_regions is True,
# you need to also fill header_filter_acceptable__regex in order to accept code contained
# inside header_guards (and other acceptable preprocessor defines you may set via this regex)
# Your regex can have several options: separate them with a "|".
# By default, all macros names ending with "_H", "HPP", "HXX" are considered as acceptable.
header_filter_acceptable__regex: str = "__cplusplus|_h_$|_h$|_H$|_H_$|hpp$|HPP$|hxx$|HXX$"
################################################################################
# <Custom preprocess of the code>
################################################################################
#
# If you need to preprocess the code before parsing, fill this function
#
code_preprocess_function: Optional[Callable[[str], str]] = None
################################################################################
# <Misc options>
################################################################################
# Encoding of python and C++ files
encoding: str = "utf-8"
# Preserve empty lines, i.e. any empty line in the C++ code will be mentioned as a CppEmptyLine element
# this is done by adding a dummy comment on the line.
preserve_empty_lines: bool = True
# flag_srcml_dump_positions: if True, code positions will be outputted in the xml tree (recommended)
flag_srcml_dump_positions: bool = True
# indentation used by CppElements str_code() methods (4 spaces by default)
indent_cpp_str: str = " "
################################################################################
# <Verbose / Quiet mode>
################################################################################
# if quiet, all warning messages are discarded (warning messages go to stderr)
flag_quiet: bool = False
# List of ignored warnings
ignored_warnings: list[WarningType]
# List of ignored warnings, identified by a part of the warning message
ignored_warning_parts: list[str]
# Show python callstack when warnings are raised
flag_show_python_callstack: bool = False
# if true, display parsing progress during execution (on stdout)
flag_show_progress: bool = False
################################################################################
# Workaround for https://github.com/srcML/srcML/issues/1833
################################################################################
fix_brace_init_default_value = True
################################################################################
# <End>
################################################################################
def __init__(self) -> None:
# See doc for all the params at their declaration site (scroll up!)
self.named_number_macros = {}
self.ignored_warnings = []
self.ignored_warning_parts = []
def functions_api_prefixes_list(self) -> list[str]:
assert isinstance(self.functions_api_prefixes, str)
return split_string_by_pipe_char(self.functions_api_prefixes)
def _int_from_str_or_named_number_macros(options: SrcmlcppOptions, int_str: Optional[str]) -> Optional[int]:
if int_str is None:
return None
try:
v = int(int_str)
return v
except ValueError:
if int_str in options.named_number_macros:
return options.named_number_macros[int_str]
else:
return None