diff --git a/HISTORY.rst b/HISTORY.rst index cded83ea..a948fcfa 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -17,6 +17,9 @@ PlatformIO 3.0 C Preprocessor conditional macros, `library deep search `__, support for the 3rd party manifests (Arduino IDE ``library.properties``, ARM mbed ``module.json``) (`issue #432 `_) +* Handle extra build flags and build script from + `library.json `__ + (`issue #289 `_) * Show detailed build information about dependent libraries (`issue #617 `_) * Embedded Board compatibility with more than one development platform diff --git a/docs/faq.rst b/docs/faq.rst index 663c108f..75ed3cfb 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -155,12 +155,6 @@ Answered in `issue #144 `_ -* `#331: Unable to use MySensors library `_ - ARM toolchain: cc1plus: error while loading shared libraries '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' diff --git a/docs/librarymanager/config.rst b/docs/librarymanager/config.rst index c56d74ed..2072aabc 100644 --- a/docs/librarymanager/config.rst +++ b/docs/librarymanager/config.rst @@ -22,6 +22,7 @@ to keep project in own structure and define: * examples list * compatible frameworks and platforms * library dependencies +* advanced build settings PlatformIO Library Crawler uses ``library.json`` manifest to extract source code from developer's location and keeps cleaned library in own @@ -397,7 +398,7 @@ See more ``library.json`` :ref:`library_creating_examples`. .. _libjson_examples: ``examples`` ----------------- +------------ *Optional* | Type: ``String`` or ``Array`` | `Glob Pattern `_ @@ -413,3 +414,80 @@ A list of example patterns. This field is predefined with default value: "[Ee]xamples/*/*.ino", "[Ee]xamples/*/*.pde" ] + + +.. _libjson_build: + +``build`` +------------ + +*Optional* | Type: ``Object`` + +Specify advanced settings, options and flags for the build system. Possible +options: + +* ``flags`` - extra flags to control preprocessing, compilation, assembly and + linking processes. More details :ref:`projectconf_build_flags` +* ``unflags`` - remove base/initial flags which were set by development + platform. More details :ref:`projectconf_build_unflags` +* ``srcFilter`` - specify which source files should be included/excluded + from build process. More details :ref:`projectconf_src_filter` +* ``extraScript`` - launch extra script before build process. + More details :ref:`projectconf_extra_script`. + +**Examples** + +1. Custom macros/defines + +.. code-block:: javascript + + "build": { + "flags": "-D MYLIB_REV=0.1.2 -DRELEASE" + } + +2. Extra includes for C preprocessor + +.. code-block:: javascript + + "build": { + "flags": "-I inc -I inc/target_x13" + } + +3. Force to use ``C99`` standard instead ``C11`` + +.. code-block:: javascript + + "build": { + "unflags": "-std=gnu++11", + "flags": "-std=c99" + } + +4. Build source files (``c, cpp, h``) only from the root of the library + +.. code-block:: javascript + + "build": { + "srcFilter": [ + "+<*.c>", + "+<*.cpp>", + "+<*.h>" + ] + } + + +5. Extend PlatformIO Build System with own extra script + +.. code-block:: javascript + + "build": { + "extraScript": "generate_headers.py" + } + +``generate_headers.py`` + +.. code-block:: python + + # Import('env') + # print env.Dump() + + # some python code that generates headers files "on-the-fly" diff --git a/docs/projectconf.rst b/docs/projectconf.rst index f3700743..5d5b9596 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -422,6 +422,8 @@ but will be applied only for the project source code from This option can be set by global environment variable :envvar:`PLATFORMIO_SRC_BUILD_FLAGS`. +.. _projectconf_build_unflags: + ``build_unflags`` ^^^^^^^^^^^^^^^^^ diff --git a/platformio/__init__.py b/platformio/__init__.py index 15f4a2a8..6ab03493 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 0, "0.dev4") +VERSION = (3, 0, "0.dev5") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index d110a279..ac31c85f 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -17,7 +17,7 @@ from __future__ import absolute_import import os -from os.path import basename, commonprefix, isdir, isfile, join +from os.path import basename, commonprefix, isdir, isfile, join, realpath from sys import modules import SCons.Scanner @@ -73,7 +73,7 @@ class LibBuilderFactory(object): class LibBuilderBase(object): def __init__(self, env, path): - self.env = env.Clone() + self.env = env self.path = path self._is_built = False self._manifest = self.load_manifest() @@ -108,6 +108,18 @@ class LibBuilderBase(object): def build_dir(self): return join("$BUILD_DIR", "lib", self.name) + @property + def build_flags(self): + return None + + @property + def build_unflags(self): + return None + + @property + def extra_script(self): + return None + @property def is_built(self): return self._is_built @@ -118,8 +130,8 @@ class LibBuilderBase(object): def get_path_dirs(self, use_build_dir=False): return [self.build_dir if use_build_dir else self.src_dir] - def append_to_cpppath(self, env): - env.AppendUnique( + def append_to_cpppath(self): + self.env.AppendUnique( CPPPATH=self.get_path_dirs(use_build_dir=True) ) @@ -130,8 +142,20 @@ class LibBuilderBase(object): print "Depends on <%s>" % self.name assert self._is_built is False self._is_built = True - return self.env.BuildLibrary( - self.build_dir, self.src_dir, self.src_filter) + self.append_to_cpppath() + + env = self.env.Clone() + with util.cd(self.path): + env.ProcessUnFlags(self.build_unflags) + env.ProcessFlags(self.build_flags) + if self.extra_script: + env.SConscript(realpath(self.extra_script), exports="env") + + # copy some data to global env + for key in ("CPPPATH", "LIBPATH", "LIBS", "LINKFLAGS"): + self.env.AppendUnique(**{key: env.get(key)}) + + return env.BuildLibrary(self.build_dir, self.src_dir, self.src_filter) class UnknownLibBuilder(LibBuilderBase): @@ -199,6 +223,30 @@ class PlatformIOLibBuilder(LibBuilderBase): assert "name" in manifest return manifest + @property + def src_filter(self): + if "srcFilter" in self._manifest.get("build", {}): + return self._manifest.get("build").get("srcFilter") + return LibBuilderBase.src_filter.fget(self) + + @property + def build_flags(self): + if "flags" in self._manifest.get("build", {}): + return self._manifest.get("build").get("flags") + return LibBuilderBase.build_flags.fget(self) + + @property + def build_unflags(self): + if "unflags" in self._manifest.get("build", {}): + return self._manifest.get("build").get("unflags") + return LibBuilderBase.build_unflags.fget(self) + + @property + def extra_script(self): + if "extra_script" in self._manifest.get("build", {}): + return self._manifest.get("build").get("extra_script") + return LibBuilderBase.extra_script.fget(self) + def find_deps(env, scanner, path_dirs, src_dir, src_filter): result = [] @@ -232,7 +280,7 @@ def find_and_build_deps(env, lib_builders, scanner, libs = [] # append PATH directories to global CPPPATH before build starts for lb in target_lbs: - lb.append_to_cpppath(env) + lb.append_to_cpppath() # start builder for lb in target_lbs: libs.append(lb.build()) @@ -277,7 +325,6 @@ def BuildDependentLibraries(env, src_dir): libs.extend(find_and_build_deps( env, lib_builders, scanner, lb.src_dir, lb.src_filter)) if not lb.is_built: - lb.append_to_cpppath(env) libs.append(lb.build()) # process project source code diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index 91a0a149..7ce3692e 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -154,7 +154,7 @@ def ProcessUnFlags(env, flags): all_flags = set(all_flags) for key in parsed_flags: - cur_flags = set(env.get(key, [])) + cur_flags = set(env.Flatten(env.get(key, []))) for item in cur_flags & all_flags: while item in env[key]: env[key].remove(item)