Introduce "lib_compat_level" option for project configuration file

This commit is contained in:
Ivan Kravets
2016-07-24 18:17:23 +03:00
parent 2892cb8c2f
commit 01c0b45ea2
6 changed files with 114 additions and 31 deletions

View File

@ -14,8 +14,11 @@ PlatformIO 3.0
* Unit Testing for Embedded (`docs <http://docs.platformio.org/en/latest/platforms/unit_testing.html>`__)
(`issue #408 <https://github.com/platformio/platformio/issues/408>`_)
* New Library Build System: intelligent dependency finder that interprets
C Preprocessor conditional macros, `library deep search <http://docs.platformio.org/en/latest/projectconf.html#lib-deep-search>`__, support for the 3rd party
manifests (Arduino IDE ``library.properties``, ARM mbed ``module.json``)
C Preprocessor conditional macros,
`library deep search <http://docs.platformio.org/en/latest/projectconf.html#lib-deep-search>`__,
`library compatibility level <http://docs.platformio.org/en/latest/projectconf.html#lib-compat-level>`__,
support for the 3rd party manifests (Arduino IDE ``library.properties``,
ARM mbed ``module.json``)
(`issue #432 <https://github.com/platformio/platformio/issues/432>`_)
* New `lib_extra_dirs <http://docs.platformio.org/en/latest/projectconf.html#lib-extra-dirs>`__ option for project environment.
Multiple custom library locations!

View File

@ -33,6 +33,33 @@ What is ``.pioenvs`` directory
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 header files (``*.h, *.hpp``) and looks for
``#include <...>`` directives. What is more, LDF interprets C Preprocessor
conditional macros (``#ifdef ...``, etc.). Library Dependency Finder starts
work from analyzing source files from :ref:`projectconf_pio_src_dir`. It
understands "nested includes/chain" by default if they depend on each other.
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 key factors from :ref:`projectconf`:
* :ref:`projectconf_lib_ignore`
* :ref:`projectconf_lib_deep_search`
* :ref:`projectconf_lib_extra_dirs`
* :ref:`projectconf_lib_compat_level`
Command completion in Terminal
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -606,10 +606,15 @@ Example:
``lib_force``
^^^^^^^^^^^^^
Force Library Build System to build specified libraries if even they are not
Force Library Build System to build 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
folder name). In the most cases, library name is pre-defined in manifest file
(:ref:`library_config`, ``library.properties``, ``module.json``). The multiple
library names are allowed, split them with comma ``,`` separator.
Example:
.. code-block:: ini
@ -617,10 +622,19 @@ Example:
[env:myenv]
lib_force = OneWire, SPI
.. _projectconf_lib_ignore:
``lib_ignore``
^^^^^^^^^^^^^^
Specify libraries which should be ignored by ``Library Dependency Finder (LDF)``
Please make sure to read :ref:`faq_ldf` guides first.
Specify libraries which should be ignored by Library Dependency Finder.
The correct value for this option is library name (not
folder name). In the most cases, library name is pre-defined in manifest file
(:ref:`library_config`, ``library.properties``, ``module.json``). The multiple
library names are allowed, split them with comma ``,`` separator.
Example:
@ -629,18 +643,25 @@ Example:
[env:ignore_some_libs]
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 OFF (``lib_deep_search = false``) and means
that ``Library Dependency Finder (LDF)`` will look only for the libraries
that are mentioned (using ``#include <...>``) in the source files from the
project :ref:`projectconf_pio_src_dir`. Also, ``LDF`` analyzes nested
``#include <...>`` by default.
that Library Dependency Finder will analyzes only "nested includes/chain".
Nevertheless, 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. In this case, LDF will not
handle these libraries automatically because it doesn't analyze "each source
file" of the nested libraries.
If you want to enable deep search, please set this option to ``true``.
Found library will be treated like the new source files and
``LDF`` will search dependencies for it.
Found library will be treated like the new source files and LDF will
search dependencies for it.
For example, there are 2 libraries:
@ -688,17 +709,19 @@ For example, there are 2 libraries:
``lib_extra_dirs``
^^^^^^^^^^^^^^^^^^
A list with extra directories where ``Library Dependency Finder (LDF)`` will
look for dependencies. Multiple paths are allowed. Please separate them using
comma ``,`` symbol.
Please make sure to read :ref:`faq_ldf` guides first.
A list with extra directories/storages where Library Dependency Finder will
look for dependencies. Multiple paths are allowed. Please separate them
using comma ``,`` symbol.
This option can be set by global environment variable
:envvar:`PLATFORMIO_LIB_EXTRA_DIRS`.
.. warning::
This is a not direct path to library with source code. It should be the path
to directory that contains libraries grouped by folders. For example,
``/extra/lib/path/`` but not ``/extra/lib/path/MyLibrary``.
to storage that contains libraries grouped by folders. For example,
``/extra/lib/storage/`` but not ``/extra/lib/storage/MyLibrary``.
Example:
@ -707,6 +730,27 @@ Example:
[env:custom_lib_dirs]
lib_extra_dirs = /path/to/private/dir1,/path/to/private/dir2
.. _projectconf_lib_compat_level:
``lib_compat_level``
^^^^^^^^^^^^^^^^^^^^
Please make sure to read :ref:`faq_ldf` guides first.
Library compatibility level that allows to control Library Dependency Finder
strictness. If library contains manifest file (:ref:`library_config`,
``library.properties``, ``module.json``), then LDF check compatibility of this
library with real build environment. Available compatibility levels:
* ``0`` - don't check for compatibility (disable)
* ``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_level = 1`` and means that LDF
will check only for framework compatibility.
-----------
.. _projectconf_examples:

View File

@ -14,7 +14,7 @@
import sys
VERSION = (3, 0, "0.dev9")
VERSION = (3, 0, "0.dev10")
__version__ = ".".join([str(s) for s in VERSION])
__title__ = "platformio"

View File

@ -45,6 +45,7 @@ commonvars.AddVariables(
# library options
("LIB_DEEP_SEARCH",),
("LIB_COMPAT_LEVEL",),
("LIB_IGNORE",),
("LIB_FORCE",),
("LIB_EXTRA_DIRS",),
@ -121,6 +122,7 @@ for opt in ("LIB_IGNORE", "LIB_FORCE", "LIB_EXTRA_DIRS"):
continue
env[opt] = [l.strip() for l in env[opt].split(",") if l.strip()]
env.Prepend(LIBSOURCE_DIRS=env.get("LIB_EXTRA_DIRS", []))
env.LoadDevPlatform(commonvars)
env.SConscriptChdir(0)

View File

@ -17,8 +17,8 @@
from __future__ import absolute_import
import os
import sys
from os.path import basename, commonprefix, isdir, isfile, join, realpath
from sys import modules
import SCons.Scanner
@ -44,7 +44,7 @@ class LibBuilderFactory(object):
elif used_frameworks:
clsname = "%sLibBuilder" % used_frameworks[0].title()
obj = getattr(modules[__name__], clsname)(env, path)
obj = getattr(sys.modules[__name__], clsname)(env, path)
assert isinstance(obj, LibBuilderBase)
return obj
@ -327,27 +327,34 @@ def find_and_build_deps(env, lib_builders, scanner,
def GetLibBuilders(env):
items = []
libs_dirs = []
env_frameworks = [
f.lower().strip() for f in env.get("PIOFRAMEWORK", "").split(",")]
f.lower().strip() for f in env.get("PIOFRAMEWORK", "").split(",")
]
compat_level = int(env.get("LIB_COMPAT_LEVEL", 1))
for key in ("LIB_EXTRA_DIRS", "LIBSOURCE_DIRS"):
for d in env.get(key, []):
d = env.subst(d)
if isdir(d):
libs_dirs.append(d)
for libs_dir in libs_dirs:
for libs_dir in env['LIBSOURCE_DIRS']:
libs_dir = env.subst(libs_dir)
if not isdir(libs_dir):
continue
for item in sorted(os.listdir(libs_dir)):
if item == "__cores__" or not isdir(join(libs_dir, item)):
continue
lb = LibBuilderFactory.new(env, join(libs_dir, item))
if lb.name in env.get("LIB_IGNORE", []):
if not env.GetOption("silent"):
print "Ignored library " + lb.path
continue
if not lb.is_platform_compatible(env['PIOPLATFORM']):
if compat_level > 1 and not lb.is_platform_compatible(env[
'PIOPLATFORM']):
if not env.GetOption("silent"):
sys.stderr.write("Platform incompatible library %s\n" %
lb.path)
continue
if not any([lb.is_framework_compatible(f)
for f in env_frameworks]):
if compat_level > 0 and not any([lb.is_framework_compatible(f)
for f in env_frameworks]):
if not env.GetOption("silent"):
sys.stderr.write("Framework incompatible library %s\n" %
lb.path)
continue
items.append(lb)
return items
@ -358,8 +365,8 @@ def BuildDependentLibraries(env, src_dir):
scanner = SCons.Scanner.C.CScanner()
lib_builders = env.GetLibBuilders()
print "Looking for dependencies..."
print "Collecting %d compatible libraries" % len(lib_builders)
print "Looking for dependencies..."
built_lib_names = []
for lib_name in env.get("LIB_FORCE", []):