mirror of
https://github.com/platformio/platformio-core.git
synced 2025-07-31 10:37:13 +02:00
Introduce "Library Dependency Finder"
This commit is contained in:
31
docs/faq.rst
31
docs/faq.rst
@ -33,37 +33,6 @@ What is ``.pioenvs`` directory
|
|||||||
|
|
||||||
Please refer to :ref:`projectconf_pio_envs_dir`.
|
Please refer to :ref:`projectconf_pio_envs_dir`.
|
||||||
|
|
||||||
.. _faq_ldf:
|
|
||||||
|
|
||||||
How works Library Dependency Finder (LDF)
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Library Dependency Finder is a part of PlatformIO Library Build System. It
|
|
||||||
operates with the C/C++ source files and looks for ``#include <...>``
|
|
||||||
directives. Also, LDF interprets C Preprocessor conditional macros
|
|
||||||
(``#if``, ``ifdef``, etc.). Library Dependency Finder starts
|
|
||||||
work from analyzing source files from :ref:`projectconf_pio_src_dir` by default.
|
|
||||||
|
|
||||||
If project or library contains own ``dependencies`` list (see
|
|
||||||
:ref:`libjson_dependencies`), the LDF will not looking for dependencies in
|
|
||||||
the source code. The specified libraries will be built automatically without
|
|
||||||
check.
|
|
||||||
|
|
||||||
There are different library storages where Library Dependency Finder looks for
|
|
||||||
dependencies. These storages/folders have priority. LDF operates in the next
|
|
||||||
order:
|
|
||||||
|
|
||||||
1. :ref:`projectconf_lib_extra_dirs`
|
|
||||||
2. :ref:`projectconf_pio_lib_dir`
|
|
||||||
3. :ref:`projectconf_pio_home_dir`/lib
|
|
||||||
|
|
||||||
Library Dependency Finder has a few controls from :ref:`projectconf`:
|
|
||||||
|
|
||||||
* :ref:`projectconf_lib_ignore`
|
|
||||||
* :ref:`projectconf_lib_deep_search`
|
|
||||||
* :ref:`projectconf_lib_extra_dirs`
|
|
||||||
* :ref:`projectconf_lib_compat_mode`
|
|
||||||
|
|
||||||
Command completion in Terminal
|
Command completion in Terminal
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -119,6 +119,7 @@ Contents
|
|||||||
|
|
||||||
Quickstart <librarymanager/index>
|
Quickstart <librarymanager/index>
|
||||||
User Guide <userguide/lib/index.rst>
|
User Guide <userguide/lib/index.rst>
|
||||||
|
librarymanager/ldf
|
||||||
librarymanager/config
|
librarymanager/config
|
||||||
librarymanager/creating
|
librarymanager/creating
|
||||||
|
|
||||||
|
171
docs/librarymanager/ldf.rst
Normal file
171
docs/librarymanager/ldf.rst
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
.. Copyright 2014-present Ivan Kravets <me@ikravets.com>
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
.. _ldf:
|
||||||
|
|
||||||
|
Library Dependency Finder (LDF)
|
||||||
|
===============================
|
||||||
|
|
||||||
|
.. versionadded:: 3.0
|
||||||
|
|
||||||
|
Library Dependency Finder is a core part of PlatformIO Build System that
|
||||||
|
operates with the C/C++ source files and looks for ``#include ...``
|
||||||
|
directives.
|
||||||
|
|
||||||
|
In spite of the fact that Library Dependency Finder is written in pure Python,
|
||||||
|
it interprets (emulates) :ref:`ldf_c_cond_syntax` (``#ifdef``, ``if``, ``defined``,
|
||||||
|
``else``, and ``elif``) without calling ``gcc -E``. This approach allows
|
||||||
|
significantly reduce total compilation time.
|
||||||
|
|
||||||
|
Library Dependency Finder has controls that can be set up in :ref:`projectconf`:
|
||||||
|
|
||||||
|
.. hlist::
|
||||||
|
:columns: 3
|
||||||
|
|
||||||
|
* :ref:`projectconf_lib_extra_dirs`
|
||||||
|
* :ref:`projectconf_lib_force`
|
||||||
|
* :ref:`projectconf_lib_ignore`
|
||||||
|
* :ref:`projectconf_lib_compat_mode`
|
||||||
|
* :ref:`projectconf_lib_ldf_mode`
|
||||||
|
|
||||||
|
-----------
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
|
||||||
|
Storage
|
||||||
|
-------
|
||||||
|
|
||||||
|
There are different storages/folders where Library Dependency Finder looks for
|
||||||
|
libraries. These folders/path have priority and LDF operates in the next order:
|
||||||
|
|
||||||
|
1. :ref:`projectconf_lib_extra_dirs` - extra storages per build environment
|
||||||
|
2. :ref:`projectconf_pio_lib_dir` - own/private library storage per project
|
||||||
|
3. :ref:`projectconf_pio_piolibdeps_dir` - project dependencies storage used by
|
||||||
|
:ref:`librarymanager`
|
||||||
|
4. :ref:`projectconf_pio_home_dir`/lib - global storage per all projects.
|
||||||
|
|
||||||
|
.. _ldf_mode:
|
||||||
|
|
||||||
|
Dependency Finder Mode
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Library Dependency Finder starts work from analyzing source files of the
|
||||||
|
project (:ref:`projectconf_pio_src_dir`) and can work in the next modes:
|
||||||
|
|
||||||
|
* ``0`` - "manual mode", does not process source files of a project and
|
||||||
|
dependent libraries. Builds only the libraries that are specified in
|
||||||
|
manifests (:ref:`library_config`, ``module.json``) or in the :ref:`projectconf`.
|
||||||
|
* ``1`` - parses ALL C/C++ source code of the project and follows only by
|
||||||
|
nested includes/chain (``#include ...``) from the libraries.
|
||||||
|
* ``2`` - **default** - parses ALL C/C++ source code of the project and parses
|
||||||
|
ALL C/C++ source code of the each dependent library (recursively).
|
||||||
|
|
||||||
|
This mode can be changed using :ref:`projectconf_lib_ldf_mode` option in
|
||||||
|
:ref:`projectconf`.
|
||||||
|
|
||||||
|
A difference between ``1`` and ``2`` modes. For example, there are 2 libraries:
|
||||||
|
|
||||||
|
* Library "Foo" with files:
|
||||||
|
|
||||||
|
- ``Foo/foo.h``
|
||||||
|
- ``Foo/foo.cpp``
|
||||||
|
|
||||||
|
* Library "Bar" with files:
|
||||||
|
|
||||||
|
- ``Bar/bar.h``
|
||||||
|
- ``Bar/bar.cpp``
|
||||||
|
|
||||||
|
:Case 1:
|
||||||
|
|
||||||
|
* ``lib_ldf_mode = 1``
|
||||||
|
* ``Foo/foo.h`` depends on "Bar" library (contains ``#include <bar.h>``)
|
||||||
|
* ``#include <foo.h>`` is located in one of the project source files
|
||||||
|
|
||||||
|
Here are nested includes (``project file > foo.h > bar.h``) and ``LDF``
|
||||||
|
will find both libraries "Foo" and "Bar".
|
||||||
|
|
||||||
|
:Case 2:
|
||||||
|
|
||||||
|
* ``lib_ldf_mode = 1``
|
||||||
|
* ``Foo/foo.cpp`` depends on "Bar" library (contains ``#include <bar.h>``)
|
||||||
|
* ``#include <foo.h>`` is located in one of the project source files
|
||||||
|
|
||||||
|
In this case, ``LDF`` will not find "Bar" library because it doesn't know
|
||||||
|
about CPP file (``Foo/foo.cpp``).
|
||||||
|
|
||||||
|
:Case 3:
|
||||||
|
|
||||||
|
* ``lib_ldf_mode = 2``
|
||||||
|
* ``Foo/foo.cpp`` depends on "Bar" library (contains ``#include <bar.h>``)
|
||||||
|
* ``#include <foo.h>`` is located in one of the project source files
|
||||||
|
|
||||||
|
Firstly, ``LDF`` finds "Foo" library, then it parses all sources from "Foo"
|
||||||
|
library and finds ``Foo/foo.cpp`` that depends on ``#include <bar.h>``.
|
||||||
|
Secondly, it will parse all sources from "Bar" library and this operation
|
||||||
|
continues until all dependent libraries will not be parsed.
|
||||||
|
|
||||||
|
.. _ldf_compat_mode:
|
||||||
|
|
||||||
|
Compatibility Mode
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Compatibility mode allows to control strictness of Library Dependency Finder.
|
||||||
|
If library contains one of manifest file (:ref:`library_config`,
|
||||||
|
``library.properties``, ``module.json``), then LDF check compatibility of this
|
||||||
|
library with real build environment. Available compatibility modes:
|
||||||
|
|
||||||
|
* ``0`` - does not check for compatibility (is not recommended)
|
||||||
|
* ``1`` - **default** - checks for the compatibility with
|
||||||
|
:ref:`projectconf_env_framework` from build environment
|
||||||
|
* ``2`` - checks for the compatibility with :ref:`projectconf_env_framework`
|
||||||
|
and :ref:`projectconf_env_platform` from build environment.
|
||||||
|
|
||||||
|
This mode can be changed using :ref:`projectconf_lib_compat_mode` option in
|
||||||
|
:ref:`projectconf`.
|
||||||
|
|
||||||
|
Manual dependencies
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
If project or library contains own ``dependencies`` list (see
|
||||||
|
:ref:`libjson_dependencies`), the LDF will not looking for dependencies in
|
||||||
|
the source code. The specified libraries will be built automatically without
|
||||||
|
check.
|
||||||
|
|
||||||
|
.. _ldf_c_cond_syntax:
|
||||||
|
|
||||||
|
C Preprocessor conditional syntax
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
In spite of the fact that Library Dependency Finder is written in pure Python,
|
||||||
|
it interprets (emulates) `C Preprocessor conditional syntax <https://gcc.gnu.org/onlinedocs/cpp/Conditional-Syntax.html#Conditional-Syntax>`_
|
||||||
|
(``#ifdef``, ``if``, ``defined``, ``else``, and ``elif``) without calling
|
||||||
|
``gcc -E``. For example,
|
||||||
|
|
||||||
|
``platformio.ini``
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[env:myenv]
|
||||||
|
build_flags = -D MY_PROJECT_VERSION=13
|
||||||
|
|
||||||
|
``mylib.h``
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
#ifdef PROJECT_VERSION
|
||||||
|
// include common file for the project
|
||||||
|
#include "my_common.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if PROJECT_VERSION < 10
|
||||||
|
// this include will be ignored because does not satisfy condition above
|
||||||
|
#include "my_old.h"
|
||||||
|
#endif
|
@ -14,6 +14,8 @@
|
|||||||
Unit Testing
|
Unit Testing
|
||||||
============
|
============
|
||||||
|
|
||||||
|
.. versionadded:: 3.0
|
||||||
|
|
||||||
`Unit Testing (wiki) <https://en.wikipedia.org/wiki/Unit_testing>`_
|
`Unit Testing (wiki) <https://en.wikipedia.org/wiki/Unit_testing>`_
|
||||||
is a software testing method by which individual units of source code, sets
|
is a software testing method by which individual units of source code, sets
|
||||||
of one or more MCU program modules together with associated control data,
|
of one or more MCU program modules together with associated control data,
|
||||||
|
@ -44,8 +44,8 @@ Options
|
|||||||
``home_dir``
|
``home_dir``
|
||||||
^^^^^^^^^^^^
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
Is used to store platform toolchains, frameworks, external libraries,
|
Is used to store platform toolchains, frameworks, global libraries for
|
||||||
service data and etc.
|
:ref: `ldf`, service data and etc.
|
||||||
|
|
||||||
A default value is User's home directory:
|
A default value is User's home directory:
|
||||||
|
|
||||||
@ -60,18 +60,59 @@ This option can be overridden by global environment variable
|
|||||||
``lib_dir``
|
``lib_dir``
|
||||||
^^^^^^^^^^^
|
^^^^^^^^^^^
|
||||||
|
|
||||||
This directory is used to store external libraries downloaded by
|
You can put here your own/private libraries. The source code of each library
|
||||||
:ref:`librarymanager`.
|
should be placed in separate directory, like
|
||||||
|
``lib/private_lib/[here are source files]``. This directory has the highest
|
||||||
|
priority for :ref:`ldf`.
|
||||||
|
|
||||||
A default value is ``%home_dir%/lib``.
|
A default value is ``lib`` that means that folder is located in the root of
|
||||||
|
project.
|
||||||
|
|
||||||
This option can be overridden by global environment variable
|
This option can be overridden by global environment variable
|
||||||
:envvar:`PLATFORMIO_LIB_DIR`.
|
:envvar:`PLATFORMIO_LIB_DIR`.
|
||||||
|
|
||||||
.. note::
|
For example, see how can be organized ``Foo`` and ``Bar`` libraries:
|
||||||
You can put here your own/private libraries. The source code of each
|
|
||||||
library should be placed in separate directory. For example,
|
.. code::
|
||||||
``%lib_dir%/private_lib/[here are source files]``.
|
|
||||||
|
|--lib
|
||||||
|
| |--Bar
|
||||||
|
| | |--docs
|
||||||
|
| | |--examples
|
||||||
|
| | |--src
|
||||||
|
| | |- Bar.c
|
||||||
|
| | |- Bar.h
|
||||||
|
| |--Foo
|
||||||
|
| | |- Foo.c
|
||||||
|
| | |- Foo.h
|
||||||
|
|- platformio.ini
|
||||||
|
|--src
|
||||||
|
|- main.c
|
||||||
|
|
||||||
|
|
||||||
|
Then in ``src/main.c`` you should use:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
#include <Foo.h>
|
||||||
|
#include <Bar.h>
|
||||||
|
|
||||||
|
// rest H/C/CPP code
|
||||||
|
|
||||||
|
PlatformIO will find your libraries automatically, configure preprocessor's
|
||||||
|
include paths and build them.
|
||||||
|
|
||||||
|
.. _projectconf_pio_piolibdeps_dir:
|
||||||
|
|
||||||
|
``piolibdeps_dir``
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Internal storage where :ref:`librarymanager` will install project dependencies.
|
||||||
|
A default value is ``.piolibdeps`` that means that folder is located in the root of
|
||||||
|
project.
|
||||||
|
|
||||||
|
This option can be overridden by global environment variable
|
||||||
|
:envvar:`PLATFORMIO_PIOLIBDEPS_DIR`.
|
||||||
|
|
||||||
.. _projectconf_pio_src_dir:
|
.. _projectconf_pio_src_dir:
|
||||||
|
|
||||||
@ -79,10 +120,8 @@ This option can be overridden by global environment variable
|
|||||||
^^^^^^^^^^^
|
^^^^^^^^^^^
|
||||||
|
|
||||||
A path to project's source directory. PlatformIO uses it for :ref:`cmd_run`
|
A path to project's source directory. PlatformIO uses it for :ref:`cmd_run`
|
||||||
command.
|
command. A default value is ``src`` that means that folder is located in the
|
||||||
|
root of project.
|
||||||
A default value is ``src`` which means that folder is located in the root of
|
|
||||||
project.
|
|
||||||
|
|
||||||
This option can be overridden by global environment variable
|
This option can be overridden by global environment variable
|
||||||
:envvar:`PLATFORMIO_SRC_DIR`.
|
:envvar:`PLATFORMIO_SRC_DIR`.
|
||||||
@ -110,7 +149,7 @@ fast!
|
|||||||
then PlatformIO will remove this folder automatically. It will be created on the
|
then PlatformIO will remove this folder automatically. It will be created on the
|
||||||
next build operation.
|
next build operation.
|
||||||
|
|
||||||
A default value is ``.pioenvs`` which means that folder is located in the root of
|
A default value is ``.pioenvs`` that means that folder is located in the root of
|
||||||
project.
|
project.
|
||||||
|
|
||||||
This option can be overridden by global environment variable
|
This option can be overridden by global environment variable
|
||||||
@ -127,8 +166,7 @@ This option can be overridden by global environment variable
|
|||||||
^^^^^^^^^^^^
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
Data directory to store contents and :ref:`platform_espressif_uploadfs`.
|
Data directory to store contents and :ref:`platform_espressif_uploadfs`.
|
||||||
|
A default value is ``data`` that means that folder is located in the root of
|
||||||
A default value is ``data`` which means that folder is located in the root of
|
|
||||||
project.
|
project.
|
||||||
|
|
||||||
This option can be overridden by global environment variable
|
This option can be overridden by global environment variable
|
||||||
@ -139,9 +177,8 @@ This option can be overridden by global environment variable
|
|||||||
``test_dir``
|
``test_dir``
|
||||||
^^^^^^^^^^^^
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
Directory for :ref:`unit_testing`.
|
Directory where :ref:`unit_testing` engine will look for the tests.
|
||||||
|
A default value is ``test`` that means that folder is located in the root of
|
||||||
A default value is ``test`` which means that folder is located in the root of
|
|
||||||
project.
|
project.
|
||||||
|
|
||||||
This option can be overridden by global environment variable
|
This option can be overridden by global environment variable
|
||||||
@ -206,6 +243,9 @@ For example, ``[env:hello_world]``.
|
|||||||
General options
|
General options
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
|
||||||
.. _projectconf_env_platform:
|
.. _projectconf_env_platform:
|
||||||
|
|
||||||
``platform``
|
``platform``
|
||||||
@ -265,6 +305,9 @@ using `PlatformIO Embedded Boards Explorer <http://platformio.org/boards>`_.
|
|||||||
Board options
|
Board options
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
|
||||||
``board_mcu``
|
``board_mcu``
|
||||||
^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
@ -309,8 +352,11 @@ This option isn't available for the all development platforms. The only
|
|||||||
Flash chip interface mode. This option isn't available for the all development
|
Flash chip interface mode. This option isn't available for the all development
|
||||||
platforms. The only :ref:`platform_espressif` supports it.
|
platforms. The only :ref:`platform_espressif` supports it.
|
||||||
|
|
||||||
Building options
|
Build options
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
|
||||||
.. _projectconf_build_flags:
|
.. _projectconf_build_flags:
|
||||||
|
|
||||||
@ -456,7 +502,7 @@ be applied in theirs order.
|
|||||||
|
|
||||||
By default, ``src_filter`` is predefined to
|
By default, ``src_filter`` is predefined to
|
||||||
``+<*> -<.git/> -<svn/> -<example/> -<examples/> -<test/> -<tests/>``,
|
``+<*> -<.git/> -<svn/> -<example/> -<examples/> -<test/> -<tests/>``,
|
||||||
which means "includes ALL files, then
|
that means "includes ALL files, then
|
||||||
exclude ``.git`` and ``svn`` repository folders, ``example`` ... folder.
|
exclude ``.git`` and ``svn`` repository folders, ``example`` ... folder.
|
||||||
|
|
||||||
This option can be set by global environment variable
|
This option can be set by global environment variable
|
||||||
@ -529,8 +575,11 @@ The list with available targets is located in :option:`platformio run --target`.
|
|||||||
When no targets are defined, *PlatformIO* will build only sources by default.
|
When no targets are defined, *PlatformIO* will build only sources by default.
|
||||||
|
|
||||||
|
|
||||||
Uploading options
|
Upload options
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
|
||||||
.. _projectconf_upload_port:
|
.. _projectconf_upload_port:
|
||||||
|
|
||||||
@ -587,6 +636,9 @@ development platforms. The only :ref:`platform_espressif` supports it.
|
|||||||
Library options
|
Library options
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
|
||||||
``lib_install``
|
``lib_install``
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
@ -603,12 +655,17 @@ Example:
|
|||||||
[env:depends_on_some_libs]
|
[env:depends_on_some_libs]
|
||||||
lib_install = 1,13,19
|
lib_install = 1,13,19
|
||||||
|
|
||||||
|
.. _projectconf_lib_force:
|
||||||
|
|
||||||
``lib_force``
|
``lib_force``
|
||||||
^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
Force Library Build System to build specified libraries if they even are not
|
.. seealso::
|
||||||
included in the project source code. Also, these libraries will be processed
|
Please make sure to read :ref:`ldf` guide first.
|
||||||
in the first order.
|
|
||||||
|
Force Library Dependency Finder to depend on the specified libraries if
|
||||||
|
they even are not included in the project source code. Also, these
|
||||||
|
libraries will be processed in the first order.
|
||||||
|
|
||||||
The correct value for this option is library name (not
|
The correct value for this option is library name (not
|
||||||
folder name). In the most cases, library name is pre-defined in manifest file
|
folder name). In the most cases, library name is pre-defined in manifest file
|
||||||
@ -627,7 +684,8 @@ Example:
|
|||||||
``lib_ignore``
|
``lib_ignore``
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Please make sure to read :ref:`faq_ldf` guides first.
|
.. seealso::
|
||||||
|
Please make sure to read :ref:`ldf` guide first.
|
||||||
|
|
||||||
Specify libraries which should be ignored by Library Dependency Finder.
|
Specify libraries which should be ignored by Library Dependency Finder.
|
||||||
|
|
||||||
@ -643,72 +701,14 @@ Example:
|
|||||||
[env:ignore_some_libs]
|
[env:ignore_some_libs]
|
||||||
lib_ignore = SPI, Ethernet
|
lib_ignore = SPI, Ethernet
|
||||||
|
|
||||||
.. _projectconf_lib_deep_search:
|
|
||||||
|
|
||||||
``lib_deep_search``
|
|
||||||
^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Please make sure to read :ref:`faq_ldf` guides first.
|
|
||||||
|
|
||||||
By default, this option is turned ON (``lib_deep_search = true``) and means
|
|
||||||
that Library Dependency Finder will analyze ALL source files from the library
|
|
||||||
and will try automatically find all dependencies.
|
|
||||||
|
|
||||||
If you want to disable deep search, please set this option to ``false``.
|
|
||||||
Note! Some libraries depend on other libraries and the
|
|
||||||
``#include <...>`` directives for these libraries are not declared in the
|
|
||||||
"main" header file that is used by upper library. If LDF is turned OFF
|
|
||||||
(``lib_deep_search = false``), it will not handle these libraries automatically
|
|
||||||
because it doesn't analyze "each source file" of the nested libraries
|
|
||||||
(only "nested includes/chain").
|
|
||||||
|
|
||||||
For example, there are 2 libraries:
|
|
||||||
|
|
||||||
* Library "Foo" with files:
|
|
||||||
|
|
||||||
- ``Foo/foo.h``
|
|
||||||
- ``Foo/foo.cpp``
|
|
||||||
|
|
||||||
* Library "Bar" with files:
|
|
||||||
|
|
||||||
- ``Bar/bar.h``
|
|
||||||
- ``Bar/bar.cpp``
|
|
||||||
|
|
||||||
:Case 1:
|
|
||||||
|
|
||||||
* ``lib_deep_search = false``
|
|
||||||
* ``Foo/foo.h`` depends on "Bar" library (contains ``#include <bar.h>``)
|
|
||||||
* ``#include <foo.h>`` is located in one of the project source files
|
|
||||||
|
|
||||||
Here are nested includes (``project file > foo.h > bar.h``) and ``LDF`` will
|
|
||||||
find both libraries "Foo" and "Bar".
|
|
||||||
|
|
||||||
:Case 2:
|
|
||||||
|
|
||||||
* ``lib_deep_search = false``
|
|
||||||
* ``Foo/foo.cpp`` depends on "Bar" library (contains ``#include <bar.h>``)
|
|
||||||
* ``#include <foo.h>`` is located in one of the project source files
|
|
||||||
|
|
||||||
In this case, ``LDF`` will not find "Bar" library because it doesn't know
|
|
||||||
about CPP file (``Foo/foo.cpp``).
|
|
||||||
|
|
||||||
:Case 3:
|
|
||||||
|
|
||||||
* ``lib_deep_search = true``
|
|
||||||
* ``Foo/foo.cpp`` depends on "Bar" library (contains ``#include <bar.h>``)
|
|
||||||
* ``#include <foo.h>`` is located in one of the project source files
|
|
||||||
|
|
||||||
Firstly, ``LDF`` finds "Foo" library, then it parses all sources from "Foo"
|
|
||||||
library and finds ``Foo/foo.cpp`` that depends on ``#include <bar.h>``.
|
|
||||||
Secondly, it will parse all sources from "Bar" library and this operation
|
|
||||||
continues until all dependent libraries will not be parsed.
|
|
||||||
|
|
||||||
.. _projectconf_lib_extra_dirs:
|
.. _projectconf_lib_extra_dirs:
|
||||||
|
|
||||||
``lib_extra_dirs``
|
``lib_extra_dirs``
|
||||||
^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Please make sure to read :ref:`faq_ldf` guides first.
|
.. versionadded:: 3.0
|
||||||
|
.. seealso::
|
||||||
|
Please make sure to read :ref:`ldf` guide first.
|
||||||
|
|
||||||
A list with extra directories/storages where Library Dependency Finder will
|
A list with extra directories/storages where Library Dependency Finder will
|
||||||
look for dependencies. Multiple paths are allowed. Please separate them
|
look for dependencies. Multiple paths are allowed. Please separate them
|
||||||
@ -729,23 +729,34 @@ Example:
|
|||||||
[env:custom_lib_dirs]
|
[env:custom_lib_dirs]
|
||||||
lib_extra_dirs = /path/to/private/dir1,/path/to/private/dir2
|
lib_extra_dirs = /path/to/private/dir1,/path/to/private/dir2
|
||||||
|
|
||||||
|
.. _projectconf_lib_ldf_mode:
|
||||||
|
|
||||||
|
``lib_ldf_mode``
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
.. versionadded:: 3.0
|
||||||
|
.. seealso::
|
||||||
|
Please make sure to read :ref:`ldf` guide first.
|
||||||
|
|
||||||
|
Library Dependency Finder starts work from analyzing source files of the
|
||||||
|
project (:ref:`projectconf_pio_src_dir`) and can work in the different modes
|
||||||
|
(see :ref:`ldf_mode`).
|
||||||
|
|
||||||
|
By default, this value is set to ``lib_ldf_mode = 2`` and means that LDF
|
||||||
|
will parse ALL C/C++ source code of the project and will parse ALL C/C++
|
||||||
|
source code of the each dependent library (recursively).
|
||||||
|
|
||||||
.. _projectconf_lib_compat_mode:
|
.. _projectconf_lib_compat_mode:
|
||||||
|
|
||||||
``lib_compat_mode``
|
``lib_compat_mode``
|
||||||
^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Please make sure to read :ref:`faq_ldf` guides first.
|
.. versionadded:: 3.0
|
||||||
|
.. seealso::
|
||||||
|
Please make sure to read :ref:`ldf` guide first.
|
||||||
|
|
||||||
Library compatibility mode that allows to control Library Dependency Finder
|
Library compatibility mode allows to control strictness of Library Dependency
|
||||||
strictness. If library contains manifest file (:ref:`library_config`,
|
Finder. More details :ref:`ldf_compat_mode`.
|
||||||
``library.properties``, ``module.json``), then LDF check compatibility of this
|
|
||||||
library with real build environment. Available compatibility modes:
|
|
||||||
|
|
||||||
* ``0`` - don't check for compatibility
|
|
||||||
* ``1`` - check for the compatibility with :ref:`projectconf_env_framework`
|
|
||||||
from build environment
|
|
||||||
* ``2`` - check for the compatibility with :ref:`projectconf_env_framework`
|
|
||||||
and :ref:`projectconf_env_platform` from build environment.
|
|
||||||
|
|
||||||
By default, this value is set to ``lib_compat_mode = 1`` and means that LDF
|
By default, this value is set to ``lib_compat_mode = 1`` and means that LDF
|
||||||
will check only for framework compatibility.
|
will check only for framework compatibility.
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
platformio test
|
platformio test
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
.. versionadded:: 3.0
|
||||||
|
|
||||||
.. contents::
|
.. contents::
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
|
@ -44,7 +44,7 @@ commonvars.AddVariables(
|
|||||||
("SRC_FILTER",),
|
("SRC_FILTER",),
|
||||||
|
|
||||||
# library options
|
# library options
|
||||||
("LIB_DEEP_SEARCH",),
|
("LIB_LDF_MODE",),
|
||||||
("LIB_COMPAT_MODE",),
|
("LIB_COMPAT_MODE",),
|
||||||
("LIB_IGNORE",),
|
("LIB_IGNORE",),
|
||||||
("LIB_FORCE",),
|
("LIB_FORCE",),
|
||||||
@ -63,41 +63,35 @@ commonvars.AddVariables(
|
|||||||
("UPLOAD_SPEED",),
|
("UPLOAD_SPEED",),
|
||||||
("UPLOAD_FLAGS",),
|
("UPLOAD_FLAGS",),
|
||||||
("UPLOAD_RESETMETHOD",)
|
("UPLOAD_RESETMETHOD",)
|
||||||
)
|
) # yapf: disable
|
||||||
|
|
||||||
DefaultEnvironment(
|
DefaultEnvironment(
|
||||||
tools=[
|
tools=[
|
||||||
"ar", "as", "gcc", "g++", "gnulink",
|
"ar", "as", "gcc", "g++", "gnulink",
|
||||||
"platformio", "devplatform",
|
"platformio", "devplatform",
|
||||||
"piolib", "piotest", "pioupload", "pioar", "piomisc"
|
"piolib", "piotest", "pioupload", "pioar", "piomisc"
|
||||||
],
|
], # yapf: disable
|
||||||
toolpath=[join(util.get_source_dir(), "builder", "tools")],
|
toolpath=[join(util.get_source_dir(), "builder", "tools")],
|
||||||
variables=commonvars,
|
variables=commonvars,
|
||||||
|
|
||||||
# Propagating External Environment
|
# Propagating External Environment
|
||||||
ENV=environ,
|
ENV=environ,
|
||||||
|
|
||||||
UNIX_TIME=int(time()),
|
UNIX_TIME=int(time()),
|
||||||
PROGNAME="program",
|
PROGNAME="program",
|
||||||
|
|
||||||
PIOHOME_DIR=util.get_home_dir(),
|
PIOHOME_DIR=util.get_home_dir(),
|
||||||
PROJECT_DIR=util.get_project_dir(),
|
PROJECT_DIR=util.get_project_dir(),
|
||||||
PROJECTLIB_DIR=util.get_projectlib_dir(),
|
|
||||||
PROJECTSRC_DIR=util.get_projectsrc_dir(),
|
PROJECTSRC_DIR=util.get_projectsrc_dir(),
|
||||||
PROJECTTEST_DIR=util.get_projecttest_dir(),
|
PROJECTTEST_DIR=util.get_projecttest_dir(),
|
||||||
PROJECTDATA_DIR=util.get_projectdata_dir(),
|
PROJECTDATA_DIR=util.get_projectdata_dir(),
|
||||||
PIOENVS_DIR=util.get_pioenvs_dir(),
|
PROJECTPIOENVS_DIR=util.get_projectpioenvs_dir(),
|
||||||
|
BUILD_DIR=join("$PROJECTPIOENVS_DIR", "$PIOENV"),
|
||||||
BUILD_DIR=join("$PIOENVS_DIR", "$PIOENV"),
|
|
||||||
BUILDSRC_DIR=join("$BUILD_DIR", "src"),
|
BUILDSRC_DIR=join("$BUILD_DIR", "src"),
|
||||||
BUILDTEST_DIR=join("$BUILD_DIR", "test"),
|
BUILDTEST_DIR=join("$BUILD_DIR", "test"),
|
||||||
LIBSOURCE_DIRS=[
|
LIBSOURCE_DIRS=[
|
||||||
"$PROJECTLIB_DIR",
|
util.get_projectlib_dir(), util.get_projectlibdeps_dir(),
|
||||||
util.get_lib_dir()
|
join("$PIOHOME_DIR", "lib")
|
||||||
],
|
],
|
||||||
|
PYTHONEXE=normpath(sys.executable))
|
||||||
PYTHONEXE=normpath(sys.executable)
|
|
||||||
)
|
|
||||||
|
|
||||||
env = DefaultEnvironment()
|
env = DefaultEnvironment()
|
||||||
|
|
||||||
@ -126,10 +120,9 @@ env.Prepend(LIBSOURCE_DIRS=env.get("LIB_EXTRA_DIRS", []))
|
|||||||
env.LoadDevPlatform(commonvars)
|
env.LoadDevPlatform(commonvars)
|
||||||
|
|
||||||
env.SConscriptChdir(0)
|
env.SConscriptChdir(0)
|
||||||
env.SConsignFile(join("$PIOENVS_DIR", ".sconsign.dblite"))
|
env.SConsignFile(join("$PROJECTPIOENVS_DIR", ".sconsign.dblite"))
|
||||||
env.SConscript("$BUILD_SCRIPT")
|
env.SConscript("$BUILD_SCRIPT")
|
||||||
|
|
||||||
|
|
||||||
if "UPLOAD_FLAGS" in env:
|
if "UPLOAD_FLAGS" in env:
|
||||||
env.Append(UPLOADERFLAGS=["$UPLOAD_FLAGS"])
|
env.Append(UPLOADERFLAGS=["$UPLOAD_FLAGS"])
|
||||||
|
|
||||||
|
@ -194,7 +194,7 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes
|
|||||||
if not search_paths:
|
if not search_paths:
|
||||||
search_paths = tuple()
|
search_paths = tuple()
|
||||||
assert isinstance(search_paths, tuple)
|
assert isinstance(search_paths, tuple)
|
||||||
deep_search = self.env.get("LIB_DEEP_SEARCH", "true").lower() == "true"
|
deep_search = int(self.env.get("LIB_LDF_MODE", 2)) == 2
|
||||||
|
|
||||||
if not self._scanned_paths and (
|
if not self._scanned_paths and (
|
||||||
isinstance(self, ProjectAsLibBuilder) or deep_search):
|
isinstance(self, ProjectAsLibBuilder) or deep_search):
|
||||||
@ -270,6 +270,10 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes
|
|||||||
"Error: Could not find `%s` dependency for `%s` "
|
"Error: Could not find `%s` dependency for `%s` "
|
||||||
"library\n" % (item['name'], self.name))
|
"library\n" % (item['name'], self.name))
|
||||||
self.env.Exit(2)
|
self.env.Exit(2)
|
||||||
|
|
||||||
|
# when LDF is disabled
|
||||||
|
if "LIB_LDF_MODE" in self.env and \
|
||||||
|
int(self.env.get("LIB_LDF_MODE")) == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
lib_inc_map = {}
|
lib_inc_map = {}
|
||||||
|
@ -109,7 +109,7 @@ class FDSHASumMismatch(PlatformioException):
|
|||||||
"is not equal to remote '{2}'"
|
"is not equal to remote '{2}'"
|
||||||
|
|
||||||
|
|
||||||
class NotPlatformProject(PlatformioException):
|
class NotPlatformIOProject(PlatformioException):
|
||||||
|
|
||||||
MESSAGE = "Not a PlatformIO project. `platformio.ini` file has not been "\
|
MESSAGE = "Not a PlatformIO project. `platformio.ini` file has not been "\
|
||||||
"found in current working directory ({0}). To initialize new project "\
|
"found in current working directory ({0}). To initialize new project "\
|
||||||
|
@ -156,7 +156,7 @@ def _get_projconf_option_dir(name, default=None):
|
|||||||
if option_dir.startswith("~"):
|
if option_dir.startswith("~"):
|
||||||
option_dir = expanduser(option_dir)
|
option_dir = expanduser(option_dir)
|
||||||
return abspath(option_dir)
|
return abspath(option_dir)
|
||||||
except exception.NotPlatformProject:
|
except exception.NotPlatformIOProject:
|
||||||
pass
|
pass
|
||||||
return default
|
return default
|
||||||
|
|
||||||
@ -180,13 +180,6 @@ def get_home_dir():
|
|||||||
return home_dir
|
return home_dir
|
||||||
|
|
||||||
|
|
||||||
def get_lib_dir():
|
|
||||||
return _get_projconf_option_dir(
|
|
||||||
"lib_dir",
|
|
||||||
join(get_home_dir(), "lib")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_source_dir():
|
def get_source_dir():
|
||||||
curpath = abspath(__file__)
|
curpath = abspath(__file__)
|
||||||
if not isfile(curpath):
|
if not isfile(curpath):
|
||||||
@ -201,29 +194,33 @@ def get_project_dir():
|
|||||||
return os.getcwd()
|
return os.getcwd()
|
||||||
|
|
||||||
|
|
||||||
def get_projectsrc_dir():
|
def is_platformio_project(project_dir=None):
|
||||||
return _get_projconf_option_dir(
|
if not project_dir:
|
||||||
"src_dir",
|
project_dir = get_project_dir()
|
||||||
join(get_project_dir(), "src")
|
return isfile(join(project_dir, "platformio.ini"))
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_projecttest_dir():
|
|
||||||
return _get_projconf_option_dir(
|
|
||||||
"test_dir",
|
|
||||||
join(get_project_dir(), "test")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_projectlib_dir():
|
def get_projectlib_dir():
|
||||||
return join(get_project_dir(), "lib")
|
return _get_projconf_option_dir("lib_dir", join(get_project_dir(), "lib"))
|
||||||
|
|
||||||
|
|
||||||
def get_pioenvs_dir():
|
def get_projectlibdeps_dir():
|
||||||
path = _get_projconf_option_dir(
|
return _get_projconf_option_dir("libdeps_dir",
|
||||||
"envs_dir",
|
join(get_project_dir(), ".piolibdeps"))
|
||||||
join(get_project_dir(), ".pioenvs")
|
|
||||||
)
|
|
||||||
|
def get_projectsrc_dir():
|
||||||
|
return _get_projconf_option_dir("src_dir", join(get_project_dir(), "src"))
|
||||||
|
|
||||||
|
|
||||||
|
def get_projecttest_dir():
|
||||||
|
return _get_projconf_option_dir("test_dir", join(get_project_dir(),
|
||||||
|
"test"))
|
||||||
|
|
||||||
|
|
||||||
|
def get_projectpioenvs_dir():
|
||||||
|
path = _get_projconf_option_dir("envs_dir",
|
||||||
|
join(get_project_dir(), ".pioenvs"))
|
||||||
if not isdir(path):
|
if not isdir(path):
|
||||||
os.makedirs(path)
|
os.makedirs(path)
|
||||||
dontmod_path = join(path, "do-not-modify-files-here.url")
|
dontmod_path = join(path, "do-not-modify-files-here.url")
|
||||||
@ -247,18 +244,12 @@ def load_project_config(project_dir=None):
|
|||||||
if not project_dir:
|
if not project_dir:
|
||||||
project_dir = get_project_dir()
|
project_dir = get_project_dir()
|
||||||
if not is_platformio_project(project_dir):
|
if not is_platformio_project(project_dir):
|
||||||
raise exception.NotPlatformProject(project_dir)
|
raise exception.NotPlatformIOProject(project_dir)
|
||||||
cp = ConfigParser()
|
cp = ConfigParser()
|
||||||
cp.read(join(project_dir, "platformio.ini"))
|
cp.read(join(project_dir, "platformio.ini"))
|
||||||
return cp
|
return cp
|
||||||
|
|
||||||
|
|
||||||
def is_platformio_project(project_dir=None):
|
|
||||||
if not project_dir:
|
|
||||||
project_dir = get_project_dir()
|
|
||||||
return isfile(join(project_dir, "platformio.ini"))
|
|
||||||
|
|
||||||
|
|
||||||
def change_filemtime(path, time):
|
def change_filemtime(path, time):
|
||||||
os.utime(path, (time, time))
|
os.utime(path, (time, time))
|
||||||
|
|
||||||
@ -358,6 +349,12 @@ def get_request_defheaders():
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
@memoized
|
||||||
|
def _api_request_session():
|
||||||
|
import requests
|
||||||
|
return requests.Session()
|
||||||
|
|
||||||
|
|
||||||
def get_api_result(path, params=None, data=None, skipdns=False):
|
def get_api_result(path, params=None, data=None, skipdns=False):
|
||||||
import requests
|
import requests
|
||||||
result = None
|
result = None
|
||||||
@ -371,12 +368,14 @@ def get_api_result(path, params=None, data=None, skipdns=False):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if data:
|
if data:
|
||||||
r = requests.post(
|
r = _api_request_session().post(
|
||||||
url + path, params=params, data=data, headers=headers)
|
url + path, params=params, data=data, headers=headers)
|
||||||
else:
|
else:
|
||||||
r = requests.get(url + path, params=params, headers=headers)
|
r = _api_request_session().get(url + path,
|
||||||
r.raise_for_status()
|
params=params,
|
||||||
|
headers=headers)
|
||||||
result = r.json()
|
result = r.json()
|
||||||
|
r.raise_for_status()
|
||||||
except requests.exceptions.HTTPError as e:
|
except requests.exceptions.HTTPError as e:
|
||||||
if result and "errors" in result:
|
if result and "errors" in result:
|
||||||
raise exception.APIRequestError(result['errors'][0]['title'])
|
raise exception.APIRequestError(result['errors'][0]['title'])
|
||||||
|
Reference in New Issue
Block a user