Home | History | Annotate | Download | only in epid-sdk
      1 ############################################################################
      2 # Copyright 2016-2017 Intel Corporation
      3 #
      4 # Licensed under the Apache License, Version 2.0 (the "License");
      5 # you may not use this file except in compliance with the License.
      6 # You may obtain a copy of the License at
      7 #
      8 #     http://www.apache.org/licenses/LICENSE-2.0
      9 #
     10 # Unless required by applicable law or agreed to in writing, software
     11 # distributed under the License is distributed on an "AS IS" BASIS,
     12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 # See the License for the specific language governing permissions and
     14 # limitations under the License.
     15 ############################################################################
     16 
     17 """use scons -k to invoke all builds regardless of unit test failures
     18 """
     19 import string
     20 import sys
     21 import SCons.Script
     22 import os.path
     23 import subprocess
     24 from subprocess import Popen, PIPE
     25 from parts import *
     26 import re
     27 import tempfile
     28 import shutil
     29 from collections import OrderedDict
     30 
     31 def get_parts_versions(env):
     32     """Get Parts related versions given SCons environment env"""
     33     return OrderedDict({'python': string.split(sys.version, " ", 1)[0],
     34                         'scons': str(SCons.__version__),
     35                         'parts': str(PartsExtensionVersion())})
     36 
     37 def get_toolchain_versions(env):
     38     """Get version of compilation toolchain given SCons environment env"""
     39     versions = OrderedDict()
     40     if 'MSVC_VERSION' in env:
     41         versions['compiler'] = 'MSVC ' + env['MSVC_VERSION']
     42         cmd = env.subst('echo int main(){return 0;} > a.cpp'
     43                         ' | $CXX $CCFLAGS a.cpp /link /verbose')
     44         defaultlib_regexp = r'.*Searching (.*\.lib).*'
     45     elif 'GCC_VERSION' in env:
     46         versions['compiler'] = 'GCC ' + env['GCC_VERSION']
     47         if 'GXX_VERSION' in env:
     48             versions['compiler'] += ' and GXX ' + env['GXX_VERSION']
     49             if os.name == 'nt':
     50                 cmd = env.subst('echo int main(){return 0;}'
     51                                 ' | $CXX $CCFLAGS -xc++ -Wl,--verbose -')
     52             else:
     53                 cmd = env.subst('echo "int main(){return 0;}"'
     54                                 ' | $CXX $CCFLAGS -xc++ -Wl,--verbose -')
     55         else:
     56             if os.name == 'nt':
     57                 cmd = env.subst('echo int main(){return 0;}'
     58                                 ' | $CXX $CCFLAGS -xc++ -Wl,--verbose -')
     59             else:
     60                 cmd = env.subst('echo "int main(){return 0;}"'
     61                                 ' | $CC  $CCFLAGS -xc   -Wl,--verbose -')
     62         if os.name == 'nt':
     63             defaultlib_regexp = r'\n.* open (.*) succeeded'
     64         else:
     65             defaultlib_regexp = r'[\n(](/.*\.so[-.\da-fA-F]*).*'
     66 
     67     # Intel C compiler always depends from base toolchain
     68     if 'INTELC_VERSION' in env:
     69         versions['compiler'] = 'INTELC {0} with {1}'.format(
     70             env['INTELC_VERSION'],
     71             versions['compiler'])
     72 
     73     env['ENV']['PATH'] = str(env['ENV']['PATH'])
     74     temp_dir = tempfile.mkdtemp()
     75     try:
     76         proc = subprocess.Popen(cmd,
     77                                 cwd=temp_dir,
     78                                 env=env['ENV'],
     79                                 shell=True,
     80                                 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
     81         stdout, _ = proc.communicate()
     82         if proc.returncode != 0:
     83             versions['default_libs'] = 'failure executing: "{0}"'.format(cmd)
     84         else:
     85             default_libs = list(
     86                 set(re.findall(defaultlib_regexp, stdout, re.M)))
     87             if 'MSVC_VERSION' in env:
     88                 # for windows additionally report versions of Windows Kit used
     89                 runtime_version_set = set()
     90                 for lib_path in default_libs:
     91                     path_components = os.path.realpath(lib_path).split(os.sep)
     92                     if 'Windows Kits' in path_components:
     93                         i = path_components.index('Windows Kits')
     94                         runtime_version_set.add(
     95                             'Windows Kits {0} {1}'.format(path_components[i + 1],
     96                                                           path_components[i + 3]))
     97                 versions['sdk_or_libc'] = '; '.join(list(runtime_version_set))
     98             else:
     99                 # for posix additionally report versions of libc used
    100                 versions['sdk_or_libc'] = os.path.split(os.path.realpath(
    101                     next((lib for lib in default_libs if
    102                           'libc' in lib.lower() and 'libcilk' not in lib.lower()), None)))[1]
    103             versions['default_libs'] = default_libs
    104     finally:
    105         shutil.rmtree(temp_dir)
    106 
    107     return versions
    108 
    109 
    110 def log_versions(env, include_toolchain=True):
    111     """Log tools and libraries versions given SCons environment env
    112 
    113     Args:
    114         env: Scons environment.
    115         include_toolchain: Log version of compilation toolchain if True.
    116     """
    117 
    118     versions = get_parts_versions(env)
    119     if include_toolchain:
    120         versions.update(get_toolchain_versions(env))
    121 
    122     print "**************** VERSIONS *************"
    123     long_names = {
    124         'python': 'Python Version',
    125         'scons': 'SCons  Version',
    126         'parts': 'Parts  Version',
    127         'compiler': 'Compiler Version',
    128         'sdk_or_libc': 'Libc/SDK',
    129         'default_libs': 'Default Libs'
    130     }
    131     for name, value in versions.iteritems():
    132         if not isinstance(value, list):
    133             print '* {0}: {1}'.format(long_names.get(name, name), value)
    134         else:
    135             print '* {0}:\n* \t{1}'.format(long_names.get(name, name),
    136                                            '\n* \t'.join(sorted(value)))
    137     print "***************************************"
    138 
    139 
    140 def include_parts(part_list, **kwargs):
    141     for parts_file in part_list:
    142         if os.path.isfile(DefaultEnvironment().subst(parts_file)):
    143             Part(parts_file=parts_file, **kwargs)
    144 
    145 
    146 ######## Part groups ####################################################
    147 ipp_parts = ['ext/ipp/ippcp.parts']
    148 utest_parts = ['ext/gtest/gtest.parts',
    149                'epid/common-testhelper/common-testhelper.parts']
    150 common_parts = ['epid/common/common.parts']
    151 member_parts = ['epid/member/member.parts']
    152 verifier_parts = ['epid/verifier/verifier.parts']
    153 util_parts = ['example/util/util.parts']
    154 example_parts = ['ext/argtable3/argtable3.parts',
    155                  'example/verifysig/verifysig.parts',
    156                  'example/signmsg/signmsg.parts',
    157                  'example/data/data.parts',
    158                  'example/compressed_data/compressed_data.parts']
    159 sizing_parts = ['example/util/util_static.parts',
    160                 'example/signmsg/signmsg_shared.parts',
    161                 'example/verifysig/verifysig_shared.parts',
    162                 'example/verifysig/verifysig11_shared.parts']
    163 example_static_parts = ['example/util/util_static.parts',
    164                         'example/signmsg/signmsg_static.parts',
    165                         'example/verifysig/verifysig_static.parts']
    166 tools_parts = ['tools/revokegrp/revokegrp.parts',
    167                'tools/revokekey/revokekey.parts',
    168                'tools/revokesig/revokesig.parts',
    169                'tools/extractkeys/extractkeys.parts',
    170                'tools/extractgrps/extractgrps.parts']
    171 testbot_test_parts = ['test/testbot/testbot.parts',
    172                       'test/testbot/signmsg/signmsg_testbot.parts',
    173                       'test/testbot/verifysig/verifysig_testbot.parts',
    174                       'test/testbot/integration/integration_testbot.parts',
    175                       'test/testbot/ssh_remote/ssh_remote_testbot.parts',
    176                       'test/testbot/revokegrp/revokegrp_testbot.parts',
    177                       'test/testbot/revokekey/revokekey_testbot.parts',
    178                       'test/testbot/revokesig/revokesig_testbot.parts',
    179                       'test/testbot/extractkeys/extractkeys_testbot.parts',
    180                       'test/testbot/extractgrps/extractgrps_testbot.parts',
    181                       'tools/reports/reports.parts']
    182 tss_test_parts = ['test/tss/tss.parts']
    183 package_parts = ['ext/gtest/gtest.parts',
    184                  'ext/ipp/ippcp.parts',
    185                  'package.parts']
    186 memory_profiler_parts = ['tools/memory_profiler/memory_profiler.parts']
    187 internal_tools_parts = ['ext/argtable3/argtable3.parts',
    188                         'tools/ikgfwrapper/ikgfwrapper.parts']
    189 epid_data = ['test/epid_data/epid_data.parts']
    190 perf_benchmark_parts = ['ext/google_benchmark/google_benchmark.parts',
    191                         'test/performance/performance.parts']
    192 memory_benchmark_parts = ['test/dynamic_memory/dynamic_memory.parts']
    193 ######## End Part groups ###############################################
    194 ######## Commandline option setup #######################################
    195 product_variants = [
    196     'production',
    197     'internal-test',
    198     'package-epid-sdk',
    199     'internal-tools',
    200     'benchmark',
    201     'tiny',
    202     'internal-test-tiny'
    203 ]
    204 
    205 default_variant = 'production'
    206 
    207 
    208 def is_production():
    209     return GetOption("product-variant") == 'production'
    210 
    211 
    212 def is_internal_test():
    213     return GetOption("product-variant") == 'internal-test'
    214 
    215 
    216 def is_internal_tools():
    217     return GetOption("product-variant") == 'internal-tools'
    218 
    219 
    220 def is_package():
    221     return GetOption("product-variant") == 'package-epid-sdk'
    222 
    223 
    224 def is_benchmark():
    225     return GetOption("product-variant") == 'benchmark'
    226 
    227 def is_tiny():
    228     return GetOption("product-variant") == 'tiny'
    229 
    230 def is_internal_test_tiny():
    231     return GetOption("product-variant") == 'internal-test-tiny'
    232 
    233 
    234 def use_commercial_ipp():
    235     return GetOption("use-commercial-ipp")
    236 
    237 
    238 def use_tss():
    239     return GetOption("use-tss")
    240 
    241 
    242 def config_has_instrumentation():
    243     return any(DefaultEnvironment().isConfigBasedOn(config_name)
    244                for config_name in ['instr_release'])
    245 
    246 
    247 def variant_dirname():
    248     s = GetOption("product-variant")
    249     if s == 'production':
    250         return 'epid-sdk'
    251     elif s == 'package-epid-sdk':
    252         return 'epid-sdk'
    253     elif s == 'tiny':
    254         return 'epid-sdk'
    255     else:
    256         return s
    257 
    258 
    259 AddOption("--product-variant", "--prod-var", nargs=1,
    260           help=("Select product variant to build. Possible "
    261                 "options are: {0}. The default is {1} if no option "
    262                 "is specified").format(", ".join(product_variants),
    263                                        default_variant),
    264           action='store', dest='product-variant', type='choice',
    265           choices=product_variants, default=default_variant)
    266 
    267 AddOption("--use-commercial-ipp",
    268           help=("Link with commercial IPP. The IPPCRYPTOROOT environment "
    269                 "variable must be set."),
    270           action='store_true', dest='use-commercial-ipp',
    271           default=False)
    272 
    273 AddOption("--use-tss",
    274           help=("Link with TPM TSS. The TSSROOT environment variable "
    275                 "must be set."),
    276           action='store_true', dest='use-tss',
    277           default=False)
    278 
    279 AddOption("--ipp-shared",
    280           help=("Build /ext/ipp as shared library."),
    281           action='store_true', dest='ipp-shared',
    282           default=False)
    283 
    284 AddOption("--enable-sanitizers",
    285           help=("Build with sanitizers (https://github.com/google/sanitizers)."),
    286           action='store_true', dest='sanitizers',
    287           default=False)
    288 
    289 AddOption("--sanitizers-recover",
    290           help=("Configure sanititzers to recover and continue execution "
    291                 "on error found. Only applicable when sanitizers are enabled."
    292                 "See --enable-sanitizers option."),
    293           action='store_true', dest='sanitizers-recover',
    294           default=False)
    295 
    296 
    297 SetOptionDefault("PRODUCT_VARIANT", variant_dirname())
    298 
    299 ######## End Commandline option setup ###################################
    300 
    301 
    302 # fix for parts 0.10.8 until we get better logic to extract ${CC}
    303 SetOptionDefault('PARTS_USE_SHORT_TOOL_NAMES', 1)
    304 
    305 
    306 def enable_sanitizers(recover):
    307     """
    308         Configures compiler to enable sanitizers.
    309         Adds sanitizer options to default scons environment such
    310         that it affects all parts.
    311     Args:
    312         recover: Enable sanitizers recovery from errors found when True.
    313     """
    314     env = DefaultEnvironment()
    315     error_msg = None
    316     try:
    317        major = int(env.subst('$GCC_VERSION').partition('.')[0])
    318     except ValueError:
    319        major = 0
    320 
    321     if major >= 6 and env['TARGET_OS'] == 'posix':
    322         if 'INTELC_VERSION' not in env:
    323             ccflags = ['-fsanitize=address,undefined', '-fno-sanitize=alignment',
    324                        '-fno-sanitize=shift', '-fno-omit-frame-pointer']
    325             if recover:
    326                 ccflags = ccflags + ['-fsanitize-recover=all', '-fsanitize-recover=address']
    327             else:
    328                 ccflags = ccflags + ['-fno-sanitize-recover']
    329             # Extends default flags with sanitizer options
    330             SetOptionDefault('CCFLAGS', ccflags)
    331             SetOptionDefault('LIBS', ['asan', 'ubsan'])
    332         else:
    333             error_msg = """
    334                 Build with sanitizers is not supported for Intel(R) C++ Compiler.
    335                 Try scons --toolchain=gcc_6 --target=posix
    336                 """
    337     else:
    338         # User experience with sanitizers in GCC 4.8 is not great. Use at least GCC 6.x.
    339         error_msg = """
    340             Build with sanitizers is only supported for GCC version greater than
    341             6.x targeting posix OS. Current GCC version is "{0}" and OS target is "{1}".
    342             Try scons --toolchain=gcc_6 --target=posix
    343             """.format(env.get('GCC_VERSION', 'unknown'), env.get('TARGET_OS', 'unknown'))
    344     if error_msg is not None:
    345         env.PrintError(error_msg)
    346 
    347 
    348 def set_default_production_options():
    349     SetOptionDefault('CONFIG', 'release')
    350 
    351     SetOptionDefault('TARGET_VARIANT', '${TARGET_OS}-${TARGET_ARCH}')
    352 
    353     SetOptionDefault('INSTALL_ROOT',
    354                      '#_install/${PRODUCT_VARIANT}')
    355 
    356     SetOptionDefault('INSTALL_TOOLS_BIN',
    357                      '$INSTALL_ROOT/tools')
    358 
    359     SetOptionDefault('INSTALL_SAMPLE_BIN',
    360                      '$INSTALL_ROOT/example')
    361 
    362     SetOptionDefault('INSTALL_EPID_INCLUDE',
    363                      '$INSTALL_ROOT/include/epid')
    364 
    365     SetOptionDefault('INSTALL_IPP_INCLUDE',
    366                      '$INSTALL_ROOT/include/ext/ipp/include')
    367 
    368     SetOptionDefault('INSTALL_TEST_BIN',
    369                      '$INSTALL_ROOT/test')
    370 
    371     SetOptionDefault('INSTALL_LIB',
    372                      '$INSTALL_ROOT/lib/${TARGET_VARIANT}')
    373 
    374     SetOptionDefault('INSTALL_SAMPLE_DATA',
    375                      '$INSTALL_ROOT/example')
    376 
    377     SetOptionDefault('INSTALL_TOOLS_DATA',
    378                      '$INSTALL_ROOT/tools')
    379 
    380     SetOptionDefault('PACKAGE_DIR',
    381                      '#_package')
    382 
    383     SetOptionDefault('PACKAGE_ROOT',
    384                      '#_package/${PRODUCT_VARIANT}')
    385 
    386     SetOptionDefault('ROOT',
    387                      '#')
    388 
    389     SetOptionDefault('PACKAGE_NAME',
    390                      '{PRODUCT_VARIANT}')
    391 
    392 
    393 if GetOption("sanitizers"):
    394     enable_sanitizers(GetOption("sanitizers-recover"))
    395 
    396 if is_production():
    397     set_default_production_options()
    398     ipp_mode = ['install_lib']
    399     if use_commercial_ipp():
    400         ipp_mode.append('use_commercial_ipp')
    401     sdk_mode = ['install_lib']
    402     if use_tss():
    403         sdk_mode.append('use_tss')
    404     if GetOption('ipp-shared'):
    405         ipp_mode.append('build_ipp_shared')
    406     include_parts(ipp_parts, mode=ipp_mode,
    407                   INSTALL_INCLUDE='${INSTALL_IPP_INCLUDE}')
    408     include_parts(utest_parts + common_parts +
    409                   member_parts + verifier_parts,
    410                   mode=sdk_mode,
    411                   INSTALL_INCLUDE='${INSTALL_EPID_INCLUDE}')
    412     include_parts(util_parts + example_parts,
    413                   INSTALL_INCLUDE='${INSTALL_EPID_INCLUDE}',
    414                   INSTALL_BIN='${INSTALL_SAMPLE_BIN}',
    415                   INSTALL_DATA='${INSTALL_SAMPLE_DATA}')
    416     include_parts(tools_parts,
    417                   INSTALL_BIN='${INSTALL_TOOLS_BIN}',
    418                   INSTALL_DATA='${INSTALL_TOOLS_DATA}')
    419     Default('all')
    420     Default('utest::')
    421     if not use_tss():
    422         Default('run_utest::')
    423 
    424 if is_internal_test():
    425     set_default_production_options()
    426     sdk_mode = []
    427     if use_tss():
    428         sdk_mode.append('use_tss')
    429         include_parts(tss_test_parts)
    430     include_parts(ipp_parts)
    431     include_parts(utest_parts + common_parts +
    432                   member_parts + verifier_parts,
    433                   mode=sdk_mode)
    434     include_parts(util_parts + example_parts,
    435                   INSTALL_BIN='${INSTALL_SAMPLE_BIN}',
    436                   INSTALL_DATA='${INSTALL_SAMPLE_DATA}')
    437     include_parts(sizing_parts,
    438                   INSTALL_BIN='${INSTALL_SAMPLE_BIN}')
    439     include_parts(tools_parts, INSTALL_BIN='${INSTALL_TOOLS_BIN}')
    440     include_parts(testbot_test_parts)
    441     Default('all')
    442 
    443 if is_internal_tools():
    444     set_default_production_options()
    445     include_parts(ipp_parts + utest_parts + common_parts + verifier_parts + member_parts + util_parts)
    446     include_parts(internal_tools_parts + memory_profiler_parts,
    447                   INSTALL_BIN='${INSTALL_TOOLS_BIN}')
    448     Default('ikgfwrapper', 'memory_profiler')
    449     Default('run_utest::memory_profiler::')
    450 
    451 if is_benchmark():
    452     set_default_production_options()
    453     MODE = []
    454     if config_has_instrumentation():
    455         MODE.append('use_memory_profiler')
    456     ipp_mode = []
    457     if use_commercial_ipp():
    458         ipp_mode.append('use_commercial_ipp')
    459 
    460     # install ipp static and ipp shared builds into separate locations
    461     if GetOption('ipp-shared'):
    462         ipp_mode.append('build_ipp_shared')
    463         SetOptionDefault('INSTALL_TEST_BIN',
    464                          '$INSTALL_ROOT/test_ipp_shared')
    465         SetOptionDefault('INSTALL_LIB',
    466                          '$INSTALL_ROOT/lib_ipp_shared')
    467     else:
    468         SetOptionDefault('INSTALL_LIB',
    469                          '$INSTALL_ROOT/lib')
    470 
    471     # do not allow file links to keep previous builds intact
    472     SetOptionDefault('CCOPY_LOGIC', 'copy')
    473 
    474     include_parts(ipp_parts, config_independent=True, mode=MODE + ipp_mode,
    475                   INSTALL_BIN='${INSTALL_TEST_BIN}')
    476     include_parts(example_static_parts + utest_parts + perf_benchmark_parts +
    477                   common_parts + verifier_parts +
    478                   sizing_parts + epid_data,
    479                   config_independent=True,
    480                   mode=MODE,
    481                   INSTALL_BIN='${INSTALL_TEST_BIN}')
    482 
    483     member_mode = ['install_lib']
    484     member_cfg = ('embedded' if not DefaultEnvironment().isConfigBasedOn(
    485         'debug') and not config_has_instrumentation() else DefaultEnvironment().subst('$CONFIG'))
    486     Part(parts_file='epid/common/tinycommon.parts', CONFIG=member_cfg)
    487     Part(parts_file='epid/member/tinymember.parts', CONFIG=member_cfg,
    488          config_independent=True, mode=MODE + member_mode, INSTALL_BIN='${INSTALL_TEST_BIN}')
    489 
    490     if config_has_instrumentation():
    491         include_parts(memory_benchmark_parts + memory_profiler_parts,
    492                       config_independent=True,
    493                       mode=MODE,
    494                       INSTALL_BIN='${INSTALL_TEST_BIN}')
    495 
    496     Default('build::')
    497 
    498 if is_package():
    499     set_default_production_options()
    500     include_parts(package_parts,
    501                   mode=['install_package'],
    502                   INSTALL_TOP_LEVEL='${PACKAGE_ROOT}')
    503     Default('package')
    504 
    505 if is_tiny():
    506     set_default_production_options()
    507     ### Member
    508     Part(parts_file='ext/gtest/gtest.parts')
    509     member_mode = ['install_lib']
    510     member_cfg = ('embedded'
    511                   if not DefaultEnvironment().isConfigBasedOn('debug')
    512                   else DefaultEnvironment().subst('$CONFIG'))
    513     Part(parts_file='epid/common/tinycommon.parts', CONFIG=member_cfg)
    514     Part(parts_file='epid/member/tinymember.parts', CONFIG=member_cfg,
    515          config_independent=True, mode=member_mode)
    516     Default('member::')
    517     Default('run_utest::member::')
    518     ### Verifier, samples and tools
    519     verifier_mode = ['install_lib']
    520     ipp_mode = ['install_lib']
    521     if use_commercial_ipp():
    522         ipp_mode.append('use_commercial_ipp')
    523     if GetOption('ipp-shared'):
    524         ipp_mode.append('build_ipp_shared')
    525     include_parts(ipp_parts, mode=ipp_mode,
    526                   INSTALL_INCLUDE='${INSTALL_IPP_INCLUDE}')
    527     Part(parts_file='epid/common-testhelper/common-testhelper.parts',
    528          config_independent=True)
    529     include_parts(common_parts + verifier_parts,
    530                   mode=verifier_mode,
    531                   INSTALL_INCLUDE='${INSTALL_EPID_INCLUDE}')
    532     include_parts(util_parts + example_parts,
    533                   INSTALL_INCLUDE='${INSTALL_EPID_INCLUDE}',
    534                   INSTALL_BIN='${INSTALL_SAMPLE_BIN}',
    535                   INSTALL_DATA='${INSTALL_SAMPLE_DATA}')
    536     include_parts(tools_parts,
    537                   INSTALL_BIN='${INSTALL_TOOLS_BIN}',
    538                   INSTALL_DATA='${INSTALL_TOOLS_DATA}')
    539     Default('all')
    540     Default('utest::')
    541 
    542 if is_internal_test_tiny():
    543     set_default_production_options()
    544     sdk_mode = []
    545     ### Member
    546     Part(parts_file='ext/gtest/gtest.parts')
    547     member_cfg = ('embedded'
    548                   if not DefaultEnvironment().isConfigBasedOn('debug')
    549                   else DefaultEnvironment().subst('$CONFIG'))
    550     Part(parts_file='epid/common/tinycommon.parts', CONFIG=member_cfg)
    551     Part(parts_file='epid/member/tinymember.parts', CONFIG=member_cfg,
    552          config_independent=True, mode=sdk_mode)
    553     ### Verifier, samples and tools
    554     include_parts(ipp_parts)
    555     Part(parts_file='epid/common-testhelper/common-testhelper.parts',
    556          config_independent=True)
    557     include_parts(common_parts + verifier_parts,
    558                   mode=sdk_mode)
    559     include_parts(util_parts + example_parts,
    560                   INSTALL_BIN='${INSTALL_SAMPLE_BIN}',
    561                   INSTALL_DATA='${INSTALL_SAMPLE_DATA}')
    562     include_parts(tools_parts, INSTALL_BIN='${INSTALL_TOOLS_BIN}')
    563     include_parts(testbot_test_parts)
    564     Default('build::')
    565 
    566 log_versions(DefaultEnvironment(), not is_package())
    567