Improve compiler-related documentation.
PiperOrigin-RevId: 651827545 Change-Id: I85c12dc12967e49087c342445dbfa049c5cdbcdf
This commit is contained in:
committed by
Copybara-Service
parent
5d51b4cd5f
commit
e13ddfa2ab
@@ -1078,12 +1078,13 @@ is initialized, others change at runtime.
|
||||
|
||||
.. _tySpecStructure:
|
||||
|
||||
mjSpec
|
||||
^^^^^^
|
||||
Model Editing
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
The strucs below are defined in `mjspec.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjspec.h>`__
|
||||
and, with the exception of the top level :ref:`mjSpec` struct, begin with the ``mjs`` prefix.
|
||||
For more details, see the :doc:`Model Editing <../programming/modeledit>` chapter.
|
||||
The strucs below are defined in
|
||||
`mjspec.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjspec.h>`__ and, with the exception of
|
||||
the top level :ref:`mjSpec` struct, begin with the ``mjs`` prefix. For more details, see the :doc:`Model Editing
|
||||
<../programming/modeledit>` chapter.
|
||||
|
||||
.. _mjSpec:
|
||||
|
||||
@@ -1375,6 +1376,8 @@ Plugin specification.
|
||||
.. mujoco-include:: mjsPlugin
|
||||
|
||||
|
||||
.. _ArrayHandles:
|
||||
|
||||
.. _mjString:
|
||||
|
||||
.. _mjStringVec:
|
||||
@@ -1392,7 +1395,8 @@ Plugin specification.
|
||||
Array handles
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Explain how handles work.
|
||||
C handles for C++ strings and vector types. When using from C, use the provided :ref:`getters<AttributeGetters>` and
|
||||
:ref:`setters<AttributeSetters>`.
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
|
||||
@@ -56,7 +56,17 @@ mj_recompile
|
||||
|
||||
.. mujoco-include:: mj_recompile
|
||||
|
||||
Recompile spec to model, preserving the state.
|
||||
Recompile spec to model, preserving the state. Like :ref:`mj_compile`, this function compiles an :ref:`mjSpec` to an
|
||||
:ref:`mjModel`, with two differences. First, rather than returning an entirely new model, it will
|
||||
reallocate existing :ref:`mjModel` and :ref:`mjData` instances in-place. Second, it will preserve the
|
||||
:ref:`integration state<geIntegrationState>`, as given in the provided :ref:`mjData` instance, while accounting for
|
||||
newly added or removed degrees of freedom. This allows the user to continue simulation with the same model and data
|
||||
struct pointers while editing the model programmatically.
|
||||
|
||||
.. admonition:: Incomplete implementation
|
||||
:class: attention
|
||||
|
||||
This function is currently incomplete, preserving only ``mjData.qpos`` and ``mjData.qvel``.
|
||||
|
||||
.. _mj_saveLastXML:
|
||||
|
||||
@@ -2682,7 +2692,8 @@ Note that derivatives depend only on :math:`h` and :math:`v` (in fact, on :math:
|
||||
All outputs are optional.
|
||||
|
||||
|
||||
These functions provide high level manipulation for :ref:`mjSpec` structs, which represent an uncompiled :ref:`mjModel`.
|
||||
These functions provide high level manipulation for the :ref:`mjSpec` struct, which represents an
|
||||
uncompiled :ref:`mjModel`.
|
||||
|
||||
.. _Plugins-api:
|
||||
|
||||
|
||||
@@ -29,6 +29,20 @@ The key function here is :ref:`mj_loadXML`. It invokes the built-in parser and c
|
||||
a valid mjModel, or NULL - in which case the user should check the error information in the user-provided string.
|
||||
The model and all files referenced in it can be loaded from disk or from a VFS when provided.
|
||||
|
||||
.. _mj_recompile:
|
||||
|
||||
Recompile spec to model, preserving the state. Like :ref:`mj_compile`, this function compiles an :ref:`mjSpec` to an
|
||||
:ref:`mjModel`, with two differences. First, rather than returning an entirely new model, it will
|
||||
reallocate existing :ref:`mjModel` and :ref:`mjData` instances in-place. Second, it will preserve the
|
||||
:ref:`integration state<geIntegrationState>`, as given in the provided :ref:`mjData` instance, while accounting for
|
||||
newly added or removed degrees of freedom. This allows the user to continue simulation with the same model and data
|
||||
struct pointers while editing the model programmatically.
|
||||
|
||||
.. admonition:: Incomplete implementation
|
||||
:class: attention
|
||||
|
||||
This function is currently incomplete, preserving only ``mjData.qpos`` and ``mjData.qvel``.
|
||||
|
||||
.. _Mainsimulation:
|
||||
|
||||
These are the main entry points to the simulator. Most users will only need to call :ref:`mj_step`, which computes
|
||||
@@ -638,5 +652,5 @@ All outputs are optional.
|
||||
|
||||
.. _SpecManip:
|
||||
|
||||
These functions provide high level manipulation for :ref:`mjSpec` structs, which represent an uncompiled :ref:`mjModel`.
|
||||
|
||||
These functions provide high level manipulation for the :ref:`mjSpec` struct, which represents an
|
||||
uncompiled :ref:`mjModel`.
|
||||
|
||||
+27
-24
@@ -5,65 +5,68 @@ Changelog
|
||||
Upcoming version (not yet released)
|
||||
-----------------------------------
|
||||
|
||||
New features
|
||||
^^^^^^^^^^^^
|
||||
|
||||
1. Introduced a major new feature: **procedural model creation and editing**, using a new top-level data-structure
|
||||
:ref:`mjSpec`. See the :doc:`Model Editing<programming/modeledit>` chapter for details.
|
||||
Note that as of this release this feature is still in testing and subject to future breaking changes.
|
||||
Fixes :github:issue:`364`.
|
||||
|
||||
General
|
||||
^^^^^^^
|
||||
|
||||
.. admonition:: Breaking API changes
|
||||
:class: attention
|
||||
|
||||
1. Removed deprecated ``mj_makeEmptyFileVFS`` and ``mj_findFileVFS`` functions. The constants ``mjMAXVFS`` and
|
||||
2. Removed deprecated ``mj_makeEmptyFileVFS`` and ``mj_findFileVFS`` functions. The constants ``mjMAXVFS`` and
|
||||
``mjMAXVFSNAME`` are also removed as they are no longer needed.
|
||||
|
||||
**Migration:** Use :ref:`mj_addBufferVFS` to copy a buffer into a VFS file directly.
|
||||
|
||||
2. Calls to :ref:`mj_defaultVFS` may allocate memory inside VFS, and the corresponding
|
||||
3. Calls to :ref:`mj_defaultVFS` may allocate memory inside VFS, and the corresponding
|
||||
:ref:`mj_deleteVFS` must be called to deallocate any internal allocated memory.
|
||||
|
||||
3. Deprecated :ref:`mju_rotVecMat` and :ref:`mju_rotVecMatT` in favor of :ref:`mju_mulMatVec3` and
|
||||
4. Deprecated :ref:`mju_rotVecMat` and :ref:`mju_rotVecMatT` in favor of :ref:`mju_mulMatVec3` and
|
||||
:ref:`mju_mulMatTVec3`. These function names and argument order are more consistent with the rest of the API.
|
||||
The older functions have been removed from the Python bindings and will be removed from the C API in the next
|
||||
release.
|
||||
4. Removed the ``actuator_actdim`` callback from actuator plugins. They now have the ``actdim`` attribute, which
|
||||
5. Removed the ``actuator_actdim`` callback from actuator plugins. They now have the ``actdim`` attribute, which
|
||||
must be used with actuators that write state to the ``act`` array. This fixed a crash which happend when
|
||||
keyframes were used in a model with stateful actuator plugins. The PID plugin will give an error when the wrong
|
||||
value of actdim is provided.
|
||||
|
||||
5. The :ref:`VFS<Virtualfilesystem>` implementation has been rewritten in C++ and is now considerably more efficient in
|
||||
6. Added :ref:`attach<body-attach>` meta-element to MJCF, which allows :ref:`attaching<meAttachment>` a subtree from a
|
||||
different model to a body in the current model.
|
||||
7. The :ref:`VFS<Virtualfilesystem>` implementation has been rewritten in C++ and is now considerably more efficient in
|
||||
speed and memory footprint.
|
||||
|
||||
6. Added a new API for :doc:`procedural model manipulation<programming/modeledit>`. Fixes :github:issue:`364`.
|
||||
Still missing:
|
||||
|
||||
- Detailed documentation.
|
||||
|
||||
.. youtube:: ZXBTEIDWHhs
|
||||
:align: right
|
||||
:width: 240px
|
||||
|
||||
7. Add :ref:`attach<body-attach>` meta-element to MJCF, which allows attaching a model to a body.
|
||||
8. Added support for orthographic cameras. This is available for both fixed cameras and the free camera, using the
|
||||
:ref:`camera/orthographic<body-camera-orthographic>` and :ref:`global/orthographic<visual-global-orthographic>`
|
||||
attributes, respectively.
|
||||
9. Added :ref:`maxhullvert<asset-mesh-maxhullvert>`, the maximum number of vertices in a mesh's convex hull.
|
||||
10. Added :ref:`mj_setKeyframe` for saving the current state into a model keyframe.
|
||||
11. Added support for ``ball`` joints in the URDF parser ("spherical" in URDF).
|
||||
12. Deprecated :ref:`mju_rotVecMat` and :ref:`mju_rotVecMatT` in favor of :ref:`mju_mulMatVec3` and
|
||||
:ref:`mju_mulMatTVec3`. These functions names and argument ordering are more consistent with the rest of the API.
|
||||
13. Replaced ``mjUSEDOUBLE`` which was previously hard-coded in
|
||||
12. Replaced ``mjUSEDOUBLE`` which was previously hard-coded in
|
||||
`mjtnum.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjtnum.h>`__
|
||||
with the build-time flag ``mjUSESINGLE``. If this symbol is not defined, MuJoCo will use double-precision floating
|
||||
point, as usual. If ``mjUSESINGLE`` is defined, MuJoCo will use single-precision floating point. See :ref:`mjtNum`.
|
||||
|
||||
Relatedly, fixed various type errors that prevented building with single-precision.
|
||||
14. Quaternions in ``mjData->qpos`` and ``mjData->mocap_quat`` are no longer normalized in-place by
|
||||
13. Quaternions in ``mjData->qpos`` and ``mjData->mocap_quat`` are no longer normalized in-place by
|
||||
:ref:`mj_kinematics`. Instead they are normalized when they are used. After the first step, quaternions in
|
||||
``mjData->qpos`` will be normalized.
|
||||
15. Mesh loading in the compiler, which is usually the slowest part of the loading process, is now multi-threaded.
|
||||
14. Mesh loading in the compiler, which is usually the slowest part of the loading process, is now multi-threaded.
|
||||
|
||||
MJX
|
||||
~~~
|
||||
16. Added support for :ref:`elliptic friction cones<option-cone>`.
|
||||
17. Fixed a bug that resulted in less-optimal linesearch solutions for some difficult constraint settings.
|
||||
18. Fixed a bug in the Newton solver that sometimes resulted in less-optimal gradients.
|
||||
15. Added support for :ref:`elliptic friction cones<option-cone>`.
|
||||
16. Fixed a bug that resulted in less-optimal linesearch solutions for some difficult constraint settings.
|
||||
17. Fixed a bug in the Newton solver that sometimes resulted in less-optimal gradients.
|
||||
|
||||
|
||||
.. youtube:: P83tKA1iz2Y
|
||||
@@ -72,17 +75,17 @@ MJX
|
||||
|
||||
Simulate
|
||||
^^^^^^^^
|
||||
19. Added improved tutorial video.
|
||||
20. Improved the Brownian noise generator.
|
||||
21. Now displaying model load times if they are longer than 0.25 seconds.
|
||||
18. Added improved tutorial video.
|
||||
19. Improved the Brownian noise generator.
|
||||
20. Now displaying model load times if they are longer than 0.25 seconds.
|
||||
|
||||
Python bindings
|
||||
^^^^^^^^^^^^^^^
|
||||
22. Fixed a memory leak when using ``copy.deepcopy()`` on a ``mujoco.MjData`` instance (:github:issue:`1572`).
|
||||
21. Fixed a memory leak when using ``copy.deepcopy()`` on a ``mujoco.MjData`` instance (:github:issue:`1572`).
|
||||
|
||||
Bug fixes
|
||||
^^^^^^^^^
|
||||
23. Fix an issue where ``mj_copyData`` (or ``copy.copy()`` in the Python bindings) was not copying contact information
|
||||
22. Fix an issue where ``mj_copyData`` (or ``copy.copy()`` in the Python bindings) was not copying contact information
|
||||
correctly (:github:issue:`1710`).
|
||||
|
||||
Version 3.1.6 (Jun 3, 2024)
|
||||
|
||||
@@ -13,3 +13,18 @@
|
||||
..
|
||||
Role for attribute value specs in MJCF spec.
|
||||
.. role:: at-val
|
||||
|
||||
..
|
||||
Role for pretty-printed inline C/C++ code.
|
||||
.. role:: cpp(code)
|
||||
:language: C++
|
||||
|
||||
..
|
||||
Role for pretty-printed inline Python code.
|
||||
.. role:: python(code)
|
||||
:language: Python
|
||||
|
||||
..
|
||||
Role for pretty-printed inline shell code.
|
||||
.. role:: shell(code)
|
||||
:language: bash
|
||||
|
||||
@@ -110,7 +110,7 @@ To build MuJoCo from source, you will need CMake and a working C++17 compiler in
|
||||
|
||||
#. Clone the ``mujoco`` repository from GitHub.
|
||||
#. Create a new build directory somewhere, and ``cd`` into it.
|
||||
#. Run ``cmake $PATH_TO_CLONED_REPO`` to configure the build.
|
||||
#. Run :shell:`cmake $PATH_TO_CLONED_REPO` to configure the build.
|
||||
#. Run ``cmake --build .`` to build.
|
||||
|
||||
MuJoCo's build system automatically fetches dependencies from upstream repositories over the Internet using CMake's
|
||||
@@ -123,11 +123,11 @@ section of the documentation.
|
||||
Additionally, the CMake setup also implements an installation phase which will copy and organize the output files to a
|
||||
target directory.
|
||||
|
||||
5. Select the directory: ``cmake $PATH_TO_CLONED_REPO -DCMAKE_INSTALL_PREFIX=<my_install_dir>``
|
||||
5. Select the directory: :shell:`cmake $PATH_TO_CLONED_REPO -DCMAKE_INSTALL_PREFIX=<my_install_dir>`
|
||||
#. After building, install with ``cmake --install .``
|
||||
|
||||
When building on Windows, use Visual Studio 2019 or later and make sure Windows SDK version 10.0.22000 or later is
|
||||
installed (see `here <https://github.com/google-deepmind/mujoco/issues/862>`__ for more details).
|
||||
installed (see :github:issue:`862` for more details).
|
||||
|
||||
.. tip::
|
||||
As a reference, a working build configuration can be found in MuJoCo's
|
||||
@@ -198,7 +198,7 @@ the symbol :ref:`mjVERSION_HEADER <glNumeric>` and the library provides the func
|
||||
.. code-block:: C
|
||||
|
||||
// recommended version check
|
||||
if( mjVERSION_HEADER!=mj_version() )
|
||||
if (mjVERSION_HEADER!=mj_version())
|
||||
complain();
|
||||
|
||||
Note that only the main header defines this symbol. We assume that the collection of headers released with each software
|
||||
|
||||
@@ -17,28 +17,99 @@ use this API when loading a model.
|
||||
Overview
|
||||
~~~~~~~~
|
||||
|
||||
As summarized in the the :ref:`Overview chapter<Instance>`, the traditional workflow to create compiled :ref:`mjModel`
|
||||
instances is:
|
||||
The new API augments the traditional workflow of creating and editing models using XML files, breaking up the *parse* and
|
||||
*compile* steps. As summarized in the the :ref:`Overview chapter<Instance>`, the traditional workflow is:
|
||||
|
||||
1. Create an XML model description file (MJCF or URDF).
|
||||
2. Call :ref:`mj_loadXML` passing in the XML (and associated assets), obtain an :ref:`mjModel` instance.
|
||||
1. Create an XML model description file (MJCF or URDF) and ascociated assets. |br|
|
||||
2. Call :ref:`mj_loadXML`, obtain an :ref:`mjModel` instance.
|
||||
|
||||
The new workflow looks like:
|
||||
The new workflow is:
|
||||
|
||||
1. Create an :ref:`mjSpec`, either an empty one corresponding to the XML ``<mujoco/>``, or by loading an existing XML
|
||||
file.
|
||||
2. Modify the :ref:`mjSpec` as desired, adding, editing and removing elements.
|
||||
3. Compile the :ref:`mjSpec` at any point, obtaining an updated :ref:`mjModel` instance. After compilation, the
|
||||
:ref:`mjSpec` remains editable, so steps 2 and 3 are interchangable.
|
||||
1. :ref:`Create<mj_makeSpec>` an empty :ref:`mjSpec` or :ref:`parse<mj_parseXML>` an existing XML file to an
|
||||
:ref:`mjSpec`.
|
||||
2. Edit the mutable :ref:`mjSpec` datastructure adding, changing and removing elements.
|
||||
3. Compile the :ref:`mjSpec` at any point, obtaining an updated :ref:`mjModel` instance. After compilation, the
|
||||
:ref:`mjSpec` remains editable, so steps 2 and 3 are interchangable.
|
||||
|
||||
|
||||
.. _meUsage:
|
||||
|
||||
Usage
|
||||
~~~~~
|
||||
Here we describe the C API for procedural model editing, but it is also exposed in the
|
||||
:ref:`Python bindings<PyModelEdit>`.
|
||||
After creating a new :ref:`mjSpec` or parsing an existing XML file to an :ref:`mjSpec`, procedural editing corresponds
|
||||
to setting attributes. For example, in order to change the timestep, one can do:
|
||||
|
||||
Detailed documentation is still missing. In the meantime, advanced users can refer to
|
||||
`user_api_test.cc <https://github.com/google-deepmind/mujoco/blob/main/test/user/user_api_test.cc>`__ and the MJCF
|
||||
parser in `xml_native_reader.cc <https://github.com/google-deepmind/mujoco/blob/main/src/xml/xml_native_reader.cc>`__,
|
||||
which is already using this API.
|
||||
.. code-block:: C
|
||||
|
||||
mjSpec* spec = mj_makeSpec();
|
||||
spec->opt.timestep = 0.01;
|
||||
...
|
||||
mjModel* model = mj_compile(spec);
|
||||
|
||||
Attributes which have variable length are C++ vectors and strings, :ref:`exposed to C as opaque types<ArrayHandles>`.
|
||||
In C one uses the provided :ref:`getters<AttributeGetters>` and :ref:`setters<AttributeSetters>`:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
mjs_setString(model->modelname, "my_model");
|
||||
|
||||
In C++ one can use these directly:
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
std::string modelname = "my_model";
|
||||
*spec->modelname = modelname;
|
||||
|
||||
.. _meMjsElements:
|
||||
|
||||
Model elements
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Model elements corresponding to MJCF are added to the spec using the corresponding functions. For example, to add a box
|
||||
geom to the world body, one would do
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
mjSpec* spec = mj_makeSpec();
|
||||
mjsBody* world = mjs_findBody(spec, "world");
|
||||
mjsGeom* my_geom = mjs_addGeom(world, NULL);
|
||||
my_geom->type = mjGEOM_BOX;
|
||||
my_geom->size[0] = my_geom->size[1] = my_geom->size[2] = 0.5;
|
||||
mjModel* model = mj_compile(spec);
|
||||
|
||||
The ``NULL`` second argument to :ref:`mjs_addGeom` is the optional default class pointer. When using defaults
|
||||
procedurally, default classes are passed in explicitly to element constructors. The global defaults of all elements
|
||||
(used when no default class is passed in) can be inspected in
|
||||
`user_init.c <https://github.com/google-deepmind/mujoco/blob/main/src/user/user_init.c>`__.
|
||||
|
||||
|
||||
.. _meAttachment:
|
||||
|
||||
Attachment
|
||||
^^^^^^^^^^
|
||||
The new framework introduces a powerful new feature: attaching and detaching model subtrees. Attachment allows the user
|
||||
copy a subtree from one model into another, while also copying related referenced assets and referencing elements from
|
||||
outside the kinematic tree (e.g., actuators and sensors). Similarly, detaching a subtree will remove all associated
|
||||
elements from the model.
|
||||
|
||||
This feature is incomplete and will be described in detail once it is fully implemented, but it is already used to power
|
||||
the :ref:`attach<body-attach>` and :ref:`replicate<replicate>` meta-elements in MJCF.
|
||||
|
||||
|
||||
.. _meKnownIssues:
|
||||
|
||||
Known issues
|
||||
~~~~~~~~~~~~
|
||||
|
||||
- Better documentation is still missing and will be added in the future. In the meantime, advanced users can refer
|
||||
to `user_api_test.cc <https://github.com/google-deepmind/mujoco/blob/main/test/user/user_api_test.cc>`__ and the MJCF
|
||||
parser in `xml_native_reader.cc <https://github.com/google-deepmind/mujoco/blob/main/src/xml/xml_native_reader.cc>`__,
|
||||
which is already using this API.
|
||||
- One of the central design consideration of the new API is incremental compilation, meaning that after making small
|
||||
changes to a spec that has already been compiled, subsequent re-compilation will be very fast. While the code is
|
||||
written to support inceremntal compilation, this functionality is not fully implemented and will be added in the
|
||||
future, resulting in faster re-compilation times.
|
||||
- Since the main test for the new API is the MJCF parser, which always constructs a model from scratch, there
|
||||
might be latent bugs related to model editing. Please report such bugs if you encounter them.
|
||||
|
||||
@@ -465,6 +465,49 @@ Alternatively, if a callback is implemented in a native dynamic library, users c
|
||||
it to ``mujoco.set_mjcb_foo``. The bindings will then retrieve the underlying function pointer and assign it directly to
|
||||
the raw callback pointer, and the GIL will **not** be acquired each time the callback is entered.
|
||||
|
||||
.. _PyModelEdit:
|
||||
|
||||
Model editing
|
||||
=============
|
||||
The :doc:`Model Editing<programming/modeledit>` framework which allows for procedural model manipulation is exposed
|
||||
via Python. In many ways this API is conceptually similar to ``dm_control``'s
|
||||
`PyMJCF module <https://github.com/google-deepmind/dm_control/tree/main/dm_control/mjcf#readme>`__, where ``MjSpec``
|
||||
plays the role of ``mjcf_model``. The largest difference between these two APIs is speed. Native model manipulation via
|
||||
``MjSpec`` is around ~100x faster than PyMJCF.
|
||||
|
||||
Below is a simple example of how to use the model editing API. For more examples, please refer to
|
||||
`specs_test.py <https://github.com/google-deepmind/mujoco/blob/main/python/mujoco/specs_test.py>`__.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import mujoco
|
||||
spec = mujoco.MjSpec()
|
||||
body = spec.worldbody.add_body()
|
||||
body.pos = [1, 2, 3]
|
||||
body.quat = [0, 1, 0, 0]
|
||||
geom = body.add_geom()
|
||||
geom.name = 'my_geom'
|
||||
geom.type = mujoco.mjtGeom.mjGEOM_SPHERE
|
||||
geom.size[0] = 1
|
||||
geom.rgba = [1, 0, 0, 1]
|
||||
...
|
||||
model = spec.compile()
|
||||
|
||||
.. admonition:: Missing features
|
||||
:class: attention
|
||||
|
||||
We are aware of multiple missing features in the Python API, including:
|
||||
|
||||
- Convenient constructors like:
|
||||
|br| :python:`geom = body.add_geom(name='my_geom', size=[1, 1, 1], rgba=[1, 0, 0, 1])`
|
||||
- Better tree traversal utilities like :python:`children = body.children()` etc.
|
||||
- PyMJCF's notion of "binding", allowing access to :ref:`mjModel` and :ref:`mjData` values via the associated ``mjs``
|
||||
elements.
|
||||
|
||||
There are certainly other missing features that we are not aware of. Please contact us on GitHub with feature
|
||||
requests or bug reports and we will prioritize accordingly.
|
||||
|
||||
|
||||
.. _PyBuild:
|
||||
|
||||
Building from source
|
||||
|
||||
Reference in New Issue
Block a user