diff --git a/SConstruct b/SConstruct
index cbe7d6311..8826ffc82 100644
--- a/SConstruct
+++ b/SConstruct
@@ -113,6 +113,13 @@ AddOption('--compiler',
" supported names: empty (detect what available), {}".format(
', '.join(["'{}'".format(s) for s in supported_compilers]))))
+AddOption('--compiler-launcher',
+ dest='compiler_launcher',
+ action='store',
+ type='string',
+ help=("optional launching tool for c and c++ compilers,"
+ " e.g. 'ccache'"))
+
AddOption('--sanitizers',
dest='sanitizers',
action='store',
@@ -630,6 +637,9 @@ elif meta.compiler == 'cc':
conf.env['LINK'] = env['CXXLD']
conf.env['SHLINK'] = env['CXXLD']
+if GetOption('compiler_launcher'):
+ conf.FindProgram('COMPILER_LAUNCHER', GetOption('compiler_launcher'))
+
if meta.platform == 'darwin':
conf.FindTool('LIPO', [''], [('lipo', None)], required=False)
conf.FindTool('INSTALL_NAME_TOOL', [''], [('install_name_tool', None)], required=False)
@@ -1101,11 +1111,17 @@ env.Append(LIBPATH=[env['ROC_BUILDDIR']])
for senv in subenvs.all:
senv.MergeFrom(env)
+# enable compiler launcher
+for senv in subenvs.all:
+ if 'COMPILER_LAUNCHER' in senv.Dictionary():
+ for var in ['CC', 'CXX']:
+ senv[var] = env.WrapLauncher(senv[var], senv['COMPILER_LAUNCHER'])
+
# enable generation of compile_commands.json (a.k.a. clangdb)
if meta.compiler in ['gcc', 'clang']:
for senv in subenvs.all:
for var in ['CC', 'CXX']:
- senv[var] = env.GetClangDbWriter(senv[var], env['ROC_BUILDDIR'])
+ senv[var] = env.WrapClangDb(senv[var], env['ROC_BUILDDIR'])
compile_commands = '{}/compile_commands.json'.format(env['ROC_BUILDDIR'])
diff --git a/docs/sphinx/building/developer_cookbook.rst b/docs/sphinx/building/developer_cookbook.rst
index 02599f9df..c7c089dbb 100644
--- a/docs/sphinx/building/developer_cookbook.rst
+++ b/docs/sphinx/building/developer_cookbook.rst
@@ -8,7 +8,7 @@ Developer cookbook
Build options
=============
-Developer build:
+Full developer build:
.. code::
@@ -20,18 +20,18 @@ Explanation:
* ``-Q`` enables compact colored build output
* ``--build-3rdparty`` specifies the list of dependencies to be downloaded and built automatically
-* ``--enable-werror`` turns compiler and Doxygen warnings into error
+* ``--enable-werror`` turns compiler and Doxygen warnings into error (CI requires no warnings)
* ``--enable-debug`` enables debug build
-* ``--enable-tests`` enables building of unit tests
-* ``--enable-benchmarks`` enables building of micro benchmarks
-* ``--enable-examples`` enables building of API usage examples
-* ``--enable-doxygen`` enables running Doxygen and producing warnings for undocumented members
+* ``--enable-tests`` enables building of unit tests (CI requires all tests to pass)
+* ``--enable-benchmarks`` enables building of micro benchmarks (not needed most time)
+* ``--enable-examples`` enables building of API usage examples (not needed most time)
+* ``--enable-doxygen`` enables running Doxygen and producing warnings for undocumented members (CI requires no warnings)
* ``test`` is the target to run unit tests
* ``bench`` is the target to run micro benchmarks
For ``--build-3rdparty`` option, see :doc:`/building/user_cookbook`.
-For developer build, you may also want to automatically download and build CppUTest (for unut tests) and Google Benchmark (for micro behcmarks):
+For developer build, you may want to automatically download and build CppUTest (for unit tests) and Google Benchmark (for micro behcmarks):
.. code::
@@ -104,6 +104,19 @@ or:
The full list of the available options and variables is documented in :doc:`/building/scons_options`.
+Compiler launcher
+=================
+
+To speed up fresh build (i.e. subsequent builds after full clean), you can enable `ccache `_.
+
+.. code::
+
+ $ scons -Q --compiler-launcher=ccache ...
+
+Here, ``--compiler-launcher`` option defines launcher program that should be used for C and C++ compilers. For example, ``gcc `` will be replaced with ``ccache gcc ``.
+
+When ``--build-3rdparty`` is used, the specified launcher will be passed to third-party libraries as well.
+
macOS options
=============
diff --git a/docs/sphinx/building/scons_options.rst b/docs/sphinx/building/scons_options.rst
index 769a26de3..2a7026244 100644
--- a/docs/sphinx/building/scons_options.rst
+++ b/docs/sphinx/building/scons_options.rst
@@ -47,6 +47,7 @@ Options
--host=HOST system name where Roc will run, e.g. 'arm-linux-gnueabihf', auto-detected by default
--platform=PLATFORM platform name where Roc will run, supported values: empty (detect from host), 'linux', 'unix', 'darwin', 'android'
--compiler=COMPILER compiler name and optional version, e.g. 'gcc-4.9', supported names: empty (detect what available), 'clang', 'gcc', 'cc'
+--compiler-launcher=COMPILER_LAUNCHER optional launching tool for c and c++ compilers, e.g. 'ccache'
--sanitizers=SANITIZERS list of gcc/clang sanitizers, supported names: empty (no sanitizers), 'all', 'undefined', 'address'
--enable-debug enable debug build for Roc
--enable-debug-3rdparty enable debug build for 3rdparty libraries
diff --git a/scripts/scons_helpers/build-3rdparty.py b/scripts/scons_helpers/build-3rdparty.py
index d3958b302..63b261cd2 100644
--- a/scripts/scons_helpers/build-3rdparty.py
+++ b/scripts/scons_helpers/build-3rdparty.py
@@ -253,6 +253,12 @@ def _getvar(var, default):
'-DCMAKE_RANLIB=' + quote(find_tool(_getvar('RANLIB', 'ranlib'))),
]
+ if ctx.env.get('COMPILER_LAUNCHER', None):
+ args += [
+ '-DCMAKE_CXX_COMPILER_LAUNCHER=' + quote(ctx.env['COMPILER_LAUNCHER']),
+ '-DCMAKE_C_COMPILER_LAUNCHER=' + quote(ctx.env['COMPILER_LAUNCHER']),
+ ]
+
args += [
'-DCMAKE_POSITION_INDEPENDENT_CODE=ON',
]
@@ -375,10 +381,18 @@ def apply_patch(ctx, dir_path, patch_url, patch_name):
dir_path,
'../' + patch_name), ignore_error=True)
-def format_vars(ctx):
+def format_vars(ctx, disable_launcher=False):
ret = []
- for e in ctx.unparsed_env:
- ret.append(quote(e))
+ for k, v in ctx.env.items():
+ if k == 'COMPILER_LAUNCHER':
+ continue
+ elif k in ['CC', 'CXX'] and not disable_launcher:
+ if ctx.env.get('COMPILER_LAUNCHER', None):
+ ret.append(quote('{}={} {}'.format(k, ctx.env['COMPILER_LAUNCHER'], v)))
+ else:
+ ret.append(quote('{}={}'.format(k, v)))
+ else:
+ ret.append(quote('{}={}'.format(k, v)))
return ' '.join(ret)
def format_flags(ctx, cflags='', ldflags='', pthread=False):
@@ -448,8 +462,14 @@ def _meson_string(s):
s = s.replace(k, v)
return "'" + s + "'"
- def _meson_flags(flags):
- return '[{}]'.format(', '.join(map(_meson_string, flags)))
+ def _meson_list(l):
+ return '[{}]'.format(', '.join(map(_meson_string, l)))
+
+ def _meson_compiler(compiler, launcher):
+ if launcher:
+ return _meson_list([launcher, compiler])
+ else:
+ return _meson_string(compiler)
msg('[generate] {}', cross_file)
@@ -516,8 +536,10 @@ def _meson_flags(flags):
cpp = {cxx}
ar = {ar}
""").format(
- cc=_meson_string(ctx.env['CC']),
- cxx=_meson_string(ctx.env['CXX']),
+ cc=_meson_compiler(ctx.env['CC'],
+ ctx.env.get('COMPILER_LAUNCHER', None)),
+ cxx=_meson_compiler(ctx.env['CXX'],
+ ctx.env.get('COMPILER_LAUNCHER', None)),
ar=_meson_string(ctx.env['AR'])))
if pkg_config:
@@ -543,8 +565,8 @@ def _meson_flags(flags):
cpp_args = {cflags}
cpp_link_args = {ldflags}
""").format(
- cflags=_meson_flags(cflags),
- ldflags=_meson_flags(ldflags)))
+ cflags=_meson_list(cflags),
+ ldflags=_meson_list(ldflags)))
if ctx.toolchain:
fp.write(textwrap.dedent("""\
@@ -1153,7 +1175,7 @@ def die(text, *args):
changedir(ctx, 'src/openssl-{ctx.pkg_ver}')
# see https://github.com/openssl/openssl/blob/master/INSTALL.md#configuration-options
execute(ctx, '{vars} {flags} ./Configure {platform} {variant} {options}'.format(
- vars=format_vars(ctx),
+ vars=format_vars(ctx, disable_launcher=True),
flags=format_flags(ctx),
platform=detect_openssl_platform(ctx.host),
variant='--debug' if ctx.variant == 'debug' else '--release',
diff --git a/scripts/scons_plugin/__init__.py b/scripts/scons_plugin/__init__.py
index 78630322d..cbcd3d36d 100644
--- a/scripts/scons_plugin/__init__.py
+++ b/scripts/scons_plugin/__init__.py
@@ -1,5 +1,4 @@
import scons_plugin.arguments
-import scons_plugin.clangdb
import scons_plugin.commands
import scons_plugin.config
import scons_plugin.distfiles
@@ -11,6 +10,7 @@
import scons_plugin.systemdeps
import scons_plugin.tests
import scons_plugin.thirdparty
+import scons_plugin.wrapper
# workaround for python3
import SCons.Subst
@@ -22,7 +22,6 @@
def generate(env):
modules = [
scons_plugin.arguments,
- scons_plugin.clangdb,
scons_plugin.commands,
scons_plugin.config,
scons_plugin.distfiles,
@@ -34,6 +33,7 @@ def generate(env):
scons_plugin.systemdeps,
scons_plugin.tests,
scons_plugin.thirdparty,
+ scons_plugin.wrapper,
]
for m in modules:
m.init(env)
diff --git a/scripts/scons_plugin/clangdb.py b/scripts/scons_plugin/clangdb.py
deleted file mode 100644
index 10b25dead..000000000
--- a/scripts/scons_plugin/clangdb.py
+++ /dev/null
@@ -1,15 +0,0 @@
-import os
-
-def GetClangDbWriter(env, tool, build_dir):
- return (
- '{python_cmd} scripts/scons_helpers/clangdb.py '
- '"{root_dir}" "{build_dir}" "{compiler}"'.format(
- python_cmd=env.GetPythonExecutable(),
- root_dir=env.Dir('#').path,
- build_dir=env.Dir(build_dir).path,
- compiler=tool
- )
- )
-
-def init(env):
- env.AddMethod(GetClangDbWriter, 'GetClangDbWriter')
diff --git a/scripts/scons_plugin/config.py b/scripts/scons_plugin/config.py
index a7f126692..d998e404c 100644
--- a/scripts/scons_plugin/config.py
+++ b/scripts/scons_plugin/config.py
@@ -160,6 +160,20 @@ def CheckCompilerOptionSupported(context, opt, language):
context.Result('no')
return False
+def FindProgram(context, var, tool):
+ if tool:
+ context.Message("Searching {} executable ... ".format(var))
+
+ tool_path = context.env.Which(tool)
+ if tool_path:
+ context.env[var] = tool_path[0]
+ else:
+ context.env[var] = tool
+
+ context.Result(context.env[var])
+
+ return True
+
def FindTool(context, var, toolchains, commands,
compiler_dir=None, prepend_path=[], required=True):
env = context.env
@@ -501,6 +515,7 @@ def init(env):
'CheckProg': CheckProg,
'CheckCanRunProgs': CheckCanRunProgs,
'CheckCompilerOptionSupported': CheckCompilerOptionSupported,
+ 'FindProgram': FindProgram,
'FindTool': FindTool,
'FindClangFormat': FindClangFormat,
'FindLLVMDir': FindLLVMDir,
diff --git a/scripts/scons_plugin/thirdparty.py b/scripts/scons_plugin/thirdparty.py
index 5e2a24481..f1f839100 100644
--- a/scripts/scons_plugin/thirdparty.py
+++ b/scripts/scons_plugin/thirdparty.py
@@ -28,6 +28,9 @@ def _build_thirdparty(env, versions, name, deps, is_native):
'RANLIB=' + quote(env['RANLIB']),
]
+ if 'COMPILER_LAUNCHER' in env.Dictionary():
+ env_vars += ['COMPILER_LAUNCHER=' + quote(env['COMPILER_LAUNCHER'])]
+
if 'PKG_CONFIG' in env.Dictionary():
env_vars += ['PKG_CONFIG=' + quote(env['PKG_CONFIG'])]
diff --git a/scripts/scons_plugin/wrapper.py b/scripts/scons_plugin/wrapper.py
new file mode 100644
index 000000000..a5a769609
--- /dev/null
+++ b/scripts/scons_plugin/wrapper.py
@@ -0,0 +1,23 @@
+import os
+
+def WrapLauncher(env, tool, launcher):
+ return '"{launcher}" "{tool}"'.format(
+ launcher=launcher, tool=tool)
+
+def WrapClangDb(env, tool, build_dir):
+ if not tool.startswith('"'):
+ tool = '"{}"'.format(tool)
+
+ return (
+ '{python_cmd} scripts/scons_helpers/clangdb.py '
+ '"{root_dir}" "{build_dir}" {tool}'.format(
+ python_cmd=env.GetPythonExecutable(),
+ root_dir=env.Dir('#').path,
+ build_dir=env.Dir(build_dir).path,
+ tool=tool
+ )
+ )
+
+def init(env):
+ env.AddMethod(WrapLauncher, 'WrapLauncher')
+ env.AddMethod(WrapClangDb, 'WrapClangDb')