1*4882a593Smuzhiyun# IceCream distributed compiling support 2*4882a593Smuzhiyun# 3*4882a593Smuzhiyun# Stages directories with symlinks from gcc/g++ to icecc, for both 4*4882a593Smuzhiyun# native and cross compilers. Depending on each configure or compile, 5*4882a593Smuzhiyun# the directories are added at the head of the PATH list and ICECC_CXX 6*4882a593Smuzhiyun# and ICEC_CC are set. 7*4882a593Smuzhiyun# 8*4882a593Smuzhiyun# For the cross compiler, creates a tar.gz of our toolchain and sets 9*4882a593Smuzhiyun# ICECC_VERSION accordingly. 10*4882a593Smuzhiyun# 11*4882a593Smuzhiyun# The class now handles all 3 different compile 'stages' (i.e native ,cross-kernel and target) creating the 12*4882a593Smuzhiyun# necessary environment tar.gz file to be used by the remote machines. 13*4882a593Smuzhiyun# It also supports meta-toolchain generation 14*4882a593Smuzhiyun# 15*4882a593Smuzhiyun# If ICECC_PATH is not set in local.conf then the class will try to locate it using 'bb.utils.which' 16*4882a593Smuzhiyun# but nothing is sure ;) 17*4882a593Smuzhiyun# 18*4882a593Smuzhiyun# If ICECC_ENV_EXEC is set in local.conf, then it should point to the icecc-create-env script provided by the user 19*4882a593Smuzhiyun# or the default one provided by icecc-create-env.bb will be used 20*4882a593Smuzhiyun# (NOTE that this is a modified version of the script need it and *not the one that comes with icecc* 21*4882a593Smuzhiyun# 22*4882a593Smuzhiyun# User can specify if specific recipes or recipes belonging to class should not use icecc to distribute 23*4882a593Smuzhiyun# compile jobs to remote machines, but handled locally, by defining ICECC_CLASS_DISABLE and ICECC_RECIPE_DISABLE 24*4882a593Smuzhiyun# with the appropriate values in local.conf. In addition the user can force to enable icecc for recipes 25*4882a593Smuzhiyun# which set an empty PARALLEL_MAKE variable by defining ICECC_RECIPE_ENABLE. 26*4882a593Smuzhiyun# 27*4882a593Smuzhiyun######################################################################################### 28*4882a593Smuzhiyun#Error checking is kept to minimum so double check any parameters you pass to the class 29*4882a593Smuzhiyun########################################################################################### 30*4882a593Smuzhiyun 31*4882a593SmuzhiyunBB_BASEHASH_IGNORE_VARS += "ICECC_PARALLEL_MAKE ICECC_DISABLED ICECC_RECIPE_DISABLE \ 32*4882a593Smuzhiyun ICECC_CLASS_DISABLE ICECC_RECIPE_ENABLE ICECC_PATH ICECC_ENV_EXEC \ 33*4882a593Smuzhiyun ICECC_CARET_WORKAROUND ICECC_CFLAGS ICECC_ENV_VERSION \ 34*4882a593Smuzhiyun ICECC_DEBUG ICECC_LOGFILE ICECC_REPEAT_RATE ICECC_PREFERRED_HOST \ 35*4882a593Smuzhiyun ICECC_CLANG_REMOTE_CPP ICECC_IGNORE_UNVERIFIED ICECC_TEST_SOCKET \ 36*4882a593Smuzhiyun ICECC_ENV_DEBUG ICECC_REMOTE_CPP \ 37*4882a593Smuzhiyun " 38*4882a593Smuzhiyun 39*4882a593SmuzhiyunICECC_ENV_EXEC ?= "${STAGING_BINDIR_NATIVE}/icecc-create-env" 40*4882a593Smuzhiyun 41*4882a593SmuzhiyunHOSTTOOLS_NONFATAL += "icecc patchelf" 42*4882a593Smuzhiyun 43*4882a593Smuzhiyun# This version can be incremented when changes are made to the environment that 44*4882a593Smuzhiyun# invalidate the version on the compile nodes. Changing it will cause a new 45*4882a593Smuzhiyun# environment to be created. 46*4882a593Smuzhiyun# 47*4882a593Smuzhiyun# A useful thing to do for testing Icecream changes locally is to add a 48*4882a593Smuzhiyun# subversion in local.conf: 49*4882a593Smuzhiyun# ICECC_ENV_VERSION:append = "-my-ver-1" 50*4882a593SmuzhiyunICECC_ENV_VERSION = "2" 51*4882a593Smuzhiyun 52*4882a593Smuzhiyun# Default to disabling the caret workaround, If set to "1" in local.conf, icecc 53*4882a593Smuzhiyun# will locally recompile any files that have warnings, which can adversely 54*4882a593Smuzhiyun# affect performance. 55*4882a593Smuzhiyun# 56*4882a593Smuzhiyun# See: https://github.com/icecc/icecream/issues/190 57*4882a593Smuzhiyunexport ICECC_CARET_WORKAROUND ??= "0" 58*4882a593Smuzhiyun 59*4882a593Smuzhiyunexport ICECC_REMOTE_CPP ??= "0" 60*4882a593Smuzhiyun 61*4882a593SmuzhiyunICECC_CFLAGS = "" 62*4882a593SmuzhiyunCFLAGS += "${ICECC_CFLAGS}" 63*4882a593SmuzhiyunCXXFLAGS += "${ICECC_CFLAGS}" 64*4882a593Smuzhiyun 65*4882a593Smuzhiyun# Debug flags when generating environments 66*4882a593SmuzhiyunICECC_ENV_DEBUG ??= "" 67*4882a593Smuzhiyun 68*4882a593Smuzhiyun# Disable recipe list contains a list of recipes that can not distribute 69*4882a593Smuzhiyun# compile tasks for one reason or the other. When adding new entry, please 70*4882a593Smuzhiyun# document why (how it failed) so that we can re-evaluate it later e.g. when 71*4882a593Smuzhiyun# there is new version 72*4882a593Smuzhiyun# 73*4882a593Smuzhiyun# libgcc-initial - fails with CPP sanity check error if host sysroot contains 74*4882a593Smuzhiyun# cross gcc built for another target tune/variant 75*4882a593Smuzhiyun# pixman - prng_state: TLS reference mismatches non-TLS reference, possibly due to 76*4882a593Smuzhiyun# pragma omp threadprivate(prng_state) 77*4882a593Smuzhiyun# systemtap - _HelperSDT.c undefs macros and uses the identifiers in macros emitting 78*4882a593Smuzhiyun# inline assembly 79*4882a593Smuzhiyun# target-sdk-provides-dummy - ${HOST_PREFIX} is empty which triggers the "NULL 80*4882a593Smuzhiyun# prefix" error. 81*4882a593SmuzhiyunICECC_RECIPE_DISABLE += "\ 82*4882a593Smuzhiyun libgcc-initial \ 83*4882a593Smuzhiyun pixman \ 84*4882a593Smuzhiyun systemtap \ 85*4882a593Smuzhiyun target-sdk-provides-dummy \ 86*4882a593Smuzhiyun " 87*4882a593Smuzhiyun 88*4882a593Smuzhiyun# Classes that should not use icecc. When adding new entry, please 89*4882a593Smuzhiyun# document why (how it failed) so that we can re-evaluate it later 90*4882a593Smuzhiyun# 91*4882a593Smuzhiyun# image - Image aren't compiling, but the testing framework for images captures 92*4882a593Smuzhiyun# PARALLEL_MAKE as part of the test environment. Many tests won't use 93*4882a593Smuzhiyun# icecream, but leaving the high level of parallelism can cause them to 94*4882a593Smuzhiyun# consume an unnecessary amount of resources. 95*4882a593SmuzhiyunICECC_CLASS_DISABLE += "\ 96*4882a593Smuzhiyun image \ 97*4882a593Smuzhiyun " 98*4882a593Smuzhiyun 99*4882a593Smuzhiyundef get_icecc_dep(d): 100*4882a593Smuzhiyun # INHIBIT_DEFAULT_DEPS doesn't apply to the patch command. Whether or not 101*4882a593Smuzhiyun # we need that built is the responsibility of the patch function / class, not 102*4882a593Smuzhiyun # the application. 103*4882a593Smuzhiyun if not d.getVar('INHIBIT_DEFAULT_DEPS'): 104*4882a593Smuzhiyun return "icecc-create-env-native" 105*4882a593Smuzhiyun return "" 106*4882a593Smuzhiyun 107*4882a593SmuzhiyunDEPENDS:prepend = "${@get_icecc_dep(d)} " 108*4882a593Smuzhiyun 109*4882a593Smuzhiyunget_cross_kernel_cc[vardepsexclude] += "KERNEL_CC" 110*4882a593Smuzhiyundef get_cross_kernel_cc(bb,d): 111*4882a593Smuzhiyun if not icecc_is_kernel(bb, d): 112*4882a593Smuzhiyun return None 113*4882a593Smuzhiyun 114*4882a593Smuzhiyun # evaluate the expression by the shell if necessary 115*4882a593Smuzhiyun kernel_cc = d.getVar('KERNEL_CC') 116*4882a593Smuzhiyun if '`' in kernel_cc or '$(' in kernel_cc: 117*4882a593Smuzhiyun import subprocess 118*4882a593Smuzhiyun kernel_cc = subprocess.check_output("echo %s" % kernel_cc, shell=True).decode("utf-8")[:-1] 119*4882a593Smuzhiyun 120*4882a593Smuzhiyun kernel_cc = kernel_cc.replace('ccache', '').strip() 121*4882a593Smuzhiyun kernel_cc = kernel_cc.split(' ')[0] 122*4882a593Smuzhiyun kernel_cc = kernel_cc.strip() 123*4882a593Smuzhiyun return kernel_cc 124*4882a593Smuzhiyun 125*4882a593Smuzhiyundef get_icecc(d): 126*4882a593Smuzhiyun return d.getVar('ICECC_PATH') or bb.utils.which(os.getenv("PATH"), "icecc") 127*4882a593Smuzhiyun 128*4882a593Smuzhiyundef use_icecc(bb,d): 129*4882a593Smuzhiyun if d.getVar('ICECC_DISABLED') == "1": 130*4882a593Smuzhiyun # don't even try it, when explicitly disabled 131*4882a593Smuzhiyun return "no" 132*4882a593Smuzhiyun 133*4882a593Smuzhiyun # allarch recipes don't use compiler 134*4882a593Smuzhiyun if icecc_is_allarch(bb, d): 135*4882a593Smuzhiyun return "no" 136*4882a593Smuzhiyun 137*4882a593Smuzhiyun if icecc_is_cross_canadian(bb, d): 138*4882a593Smuzhiyun return "no" 139*4882a593Smuzhiyun 140*4882a593Smuzhiyun pn = d.getVar('PN') 141*4882a593Smuzhiyun bpn = d.getVar('BPN') 142*4882a593Smuzhiyun 143*4882a593Smuzhiyun # Enable/disable checks are made against BPN, because there is a good 144*4882a593Smuzhiyun # chance that if icecc should be skipped for a recipe, it should be skipped 145*4882a593Smuzhiyun # for all the variants of that recipe. PN is still checked in case a user 146*4882a593Smuzhiyun # specified a more specific recipe. 147*4882a593Smuzhiyun check_pn = set([pn, bpn]) 148*4882a593Smuzhiyun 149*4882a593Smuzhiyun class_disable = (d.getVar('ICECC_CLASS_DISABLE') or "").split() 150*4882a593Smuzhiyun 151*4882a593Smuzhiyun for bbclass in class_disable: 152*4882a593Smuzhiyun if bb.data.inherits_class(bbclass, d): 153*4882a593Smuzhiyun bb.debug(1, "%s: bbclass %s found in disable, disable icecc" % (pn, bbclass)) 154*4882a593Smuzhiyun return "no" 155*4882a593Smuzhiyun 156*4882a593Smuzhiyun disabled_recipes = (d.getVar('ICECC_RECIPE_DISABLE') or "").split() 157*4882a593Smuzhiyun enabled_recipes = (d.getVar('ICECC_RECIPE_ENABLE') or "").split() 158*4882a593Smuzhiyun 159*4882a593Smuzhiyun if check_pn & set(disabled_recipes): 160*4882a593Smuzhiyun bb.debug(1, "%s: found in disable list, disable icecc" % pn) 161*4882a593Smuzhiyun return "no" 162*4882a593Smuzhiyun 163*4882a593Smuzhiyun if check_pn & set(enabled_recipes): 164*4882a593Smuzhiyun bb.debug(1, "%s: found in enabled recipes list, enable icecc" % pn) 165*4882a593Smuzhiyun return "yes" 166*4882a593Smuzhiyun 167*4882a593Smuzhiyun if d.getVar('PARALLEL_MAKE') == "": 168*4882a593Smuzhiyun bb.debug(1, "%s: has empty PARALLEL_MAKE, disable icecc" % pn) 169*4882a593Smuzhiyun return "no" 170*4882a593Smuzhiyun 171*4882a593Smuzhiyun return "yes" 172*4882a593Smuzhiyun 173*4882a593Smuzhiyundef icecc_is_allarch(bb, d): 174*4882a593Smuzhiyun return d.getVar("PACKAGE_ARCH") == "all" 175*4882a593Smuzhiyun 176*4882a593Smuzhiyundef icecc_is_kernel(bb, d): 177*4882a593Smuzhiyun return \ 178*4882a593Smuzhiyun bb.data.inherits_class("kernel", d); 179*4882a593Smuzhiyun 180*4882a593Smuzhiyundef icecc_is_native(bb, d): 181*4882a593Smuzhiyun return \ 182*4882a593Smuzhiyun bb.data.inherits_class("cross", d) or \ 183*4882a593Smuzhiyun bb.data.inherits_class("native", d); 184*4882a593Smuzhiyun 185*4882a593Smuzhiyundef icecc_is_cross_canadian(bb, d): 186*4882a593Smuzhiyun return bb.data.inherits_class("cross-canadian", d) 187*4882a593Smuzhiyun 188*4882a593Smuzhiyundef icecc_dir(bb, d): 189*4882a593Smuzhiyun return d.expand('${TMPDIR}/work-shared/ice') 190*4882a593Smuzhiyun 191*4882a593Smuzhiyun# Don't pollute allarch signatures with TARGET_FPU 192*4882a593Smuzhiyunicecc_version[vardepsexclude] += "TARGET_FPU" 193*4882a593Smuzhiyundef icecc_version(bb, d): 194*4882a593Smuzhiyun if use_icecc(bb, d) == "no": 195*4882a593Smuzhiyun return "" 196*4882a593Smuzhiyun 197*4882a593Smuzhiyun parallel = d.getVar('ICECC_PARALLEL_MAKE') or "" 198*4882a593Smuzhiyun if not d.getVar('PARALLEL_MAKE') == "" and parallel: 199*4882a593Smuzhiyun d.setVar("PARALLEL_MAKE", parallel) 200*4882a593Smuzhiyun 201*4882a593Smuzhiyun # Disable showing the caret in the GCC compiler output if the workaround is 202*4882a593Smuzhiyun # disabled 203*4882a593Smuzhiyun if d.getVar('ICECC_CARET_WORKAROUND') == '0': 204*4882a593Smuzhiyun d.setVar('ICECC_CFLAGS', '-fno-diagnostics-show-caret') 205*4882a593Smuzhiyun 206*4882a593Smuzhiyun if icecc_is_native(bb, d): 207*4882a593Smuzhiyun archive_name = "local-host-env" 208*4882a593Smuzhiyun elif d.expand('${HOST_PREFIX}') == "": 209*4882a593Smuzhiyun bb.fatal(d.expand("${PN}"), " NULL prefix") 210*4882a593Smuzhiyun else: 211*4882a593Smuzhiyun prefix = d.expand('${HOST_PREFIX}' ) 212*4882a593Smuzhiyun distro = d.expand('${DISTRO}') 213*4882a593Smuzhiyun target_sys = d.expand('${TARGET_SYS}') 214*4882a593Smuzhiyun float = d.getVar('TARGET_FPU') or "hard" 215*4882a593Smuzhiyun archive_name = prefix + distro + "-" + target_sys + "-" + float 216*4882a593Smuzhiyun if icecc_is_kernel(bb, d): 217*4882a593Smuzhiyun archive_name += "-kernel" 218*4882a593Smuzhiyun 219*4882a593Smuzhiyun import socket 220*4882a593Smuzhiyun ice_dir = icecc_dir(bb, d) 221*4882a593Smuzhiyun tar_file = os.path.join(ice_dir, "{archive}-{version}-@VERSION@-{hostname}.tar.gz".format( 222*4882a593Smuzhiyun archive=archive_name, 223*4882a593Smuzhiyun version=d.getVar('ICECC_ENV_VERSION'), 224*4882a593Smuzhiyun hostname=socket.gethostname() 225*4882a593Smuzhiyun )) 226*4882a593Smuzhiyun 227*4882a593Smuzhiyun return tar_file 228*4882a593Smuzhiyun 229*4882a593Smuzhiyundef icecc_path(bb,d): 230*4882a593Smuzhiyun if use_icecc(bb, d) == "no": 231*4882a593Smuzhiyun # don't create unnecessary directories when icecc is disabled 232*4882a593Smuzhiyun return 233*4882a593Smuzhiyun 234*4882a593Smuzhiyun staging = os.path.join(d.expand('${STAGING_BINDIR}'), "ice") 235*4882a593Smuzhiyun if icecc_is_kernel(bb, d): 236*4882a593Smuzhiyun staging += "-kernel" 237*4882a593Smuzhiyun 238*4882a593Smuzhiyun return staging 239*4882a593Smuzhiyun 240*4882a593Smuzhiyundef icecc_get_external_tool(bb, d, tool): 241*4882a593Smuzhiyun external_toolchain_bindir = d.expand('${EXTERNAL_TOOLCHAIN}${bindir_cross}') 242*4882a593Smuzhiyun target_prefix = d.expand('${TARGET_PREFIX}') 243*4882a593Smuzhiyun return os.path.join(external_toolchain_bindir, '%s%s' % (target_prefix, tool)) 244*4882a593Smuzhiyun 245*4882a593Smuzhiyundef icecc_get_tool_link(tool, d): 246*4882a593Smuzhiyun import subprocess 247*4882a593Smuzhiyun try: 248*4882a593Smuzhiyun return subprocess.check_output("readlink -f %s" % tool, shell=True).decode("utf-8")[:-1] 249*4882a593Smuzhiyun except subprocess.CalledProcessError as e: 250*4882a593Smuzhiyun bb.note("icecc: one of the tools probably disappeared during recipe parsing, cmd readlink -f %s returned %d:\n%s" % (tool, e.returncode, e.output.decode("utf-8"))) 251*4882a593Smuzhiyun return tool 252*4882a593Smuzhiyun 253*4882a593Smuzhiyundef icecc_get_path_tool(tool, d): 254*4882a593Smuzhiyun # This is a little ugly, but we want to make sure we add an actual 255*4882a593Smuzhiyun # compiler to the toolchain, not ccache. Some distros (e.g. Fedora) 256*4882a593Smuzhiyun # have ccache enabled by default using symlinks PATH, meaning ccache 257*4882a593Smuzhiyun # would be found first when looking for the compiler. 258*4882a593Smuzhiyun paths = os.getenv("PATH").split(':') 259*4882a593Smuzhiyun while True: 260*4882a593Smuzhiyun p, hist = bb.utils.which(':'.join(paths), tool, history=True) 261*4882a593Smuzhiyun if not p or os.path.basename(icecc_get_tool_link(p, d)) != 'ccache': 262*4882a593Smuzhiyun return p 263*4882a593Smuzhiyun paths = paths[len(hist):] 264*4882a593Smuzhiyun 265*4882a593Smuzhiyun return "" 266*4882a593Smuzhiyun 267*4882a593Smuzhiyun# Don't pollute native signatures with target TUNE_PKGARCH through STAGING_BINDIR_TOOLCHAIN 268*4882a593Smuzhiyunicecc_get_tool[vardepsexclude] += "STAGING_BINDIR_TOOLCHAIN" 269*4882a593Smuzhiyundef icecc_get_tool(bb, d, tool): 270*4882a593Smuzhiyun if icecc_is_native(bb, d): 271*4882a593Smuzhiyun return icecc_get_path_tool(tool, d) 272*4882a593Smuzhiyun elif icecc_is_kernel(bb, d): 273*4882a593Smuzhiyun return icecc_get_path_tool(get_cross_kernel_cc(bb, d), d) 274*4882a593Smuzhiyun else: 275*4882a593Smuzhiyun ice_dir = d.expand('${STAGING_BINDIR_TOOLCHAIN}') 276*4882a593Smuzhiyun target_sys = d.expand('${TARGET_SYS}') 277*4882a593Smuzhiyun for p in ice_dir.split(':'): 278*4882a593Smuzhiyun tool_bin = os.path.join(p, "%s-%s" % (target_sys, tool)) 279*4882a593Smuzhiyun if os.path.isfile(tool_bin): 280*4882a593Smuzhiyun return tool_bin 281*4882a593Smuzhiyun external_tool_bin = icecc_get_external_tool(bb, d, tool) 282*4882a593Smuzhiyun if os.path.isfile(external_tool_bin): 283*4882a593Smuzhiyun return external_tool_bin 284*4882a593Smuzhiyun return "" 285*4882a593Smuzhiyun 286*4882a593Smuzhiyundef icecc_get_and_check_tool(bb, d, tool): 287*4882a593Smuzhiyun # Check that g++ or gcc is not a symbolic link to icecc binary in 288*4882a593Smuzhiyun # PATH or icecc-create-env script will silently create an invalid 289*4882a593Smuzhiyun # compiler environment package. 290*4882a593Smuzhiyun t = icecc_get_tool(bb, d, tool) 291*4882a593Smuzhiyun if t: 292*4882a593Smuzhiyun link_path = icecc_get_tool_link(t, d) 293*4882a593Smuzhiyun if link_path == get_icecc(d): 294*4882a593Smuzhiyun bb.error("%s is a symlink to %s in PATH and this prevents icecc from working" % (t, link_path)) 295*4882a593Smuzhiyun return "" 296*4882a593Smuzhiyun else: 297*4882a593Smuzhiyun return t 298*4882a593Smuzhiyun else: 299*4882a593Smuzhiyun return t 300*4882a593Smuzhiyun 301*4882a593Smuzhiyunwait_for_file() { 302*4882a593Smuzhiyun local TIME_ELAPSED=0 303*4882a593Smuzhiyun local FILE_TO_TEST=$1 304*4882a593Smuzhiyun local TIMEOUT=$2 305*4882a593Smuzhiyun until [ -f "$FILE_TO_TEST" ] 306*4882a593Smuzhiyun do 307*4882a593Smuzhiyun TIME_ELAPSED=$(expr $TIME_ELAPSED + 1) 308*4882a593Smuzhiyun if [ $TIME_ELAPSED -gt $TIMEOUT ] 309*4882a593Smuzhiyun then 310*4882a593Smuzhiyun return 1 311*4882a593Smuzhiyun fi 312*4882a593Smuzhiyun sleep 1 313*4882a593Smuzhiyun done 314*4882a593Smuzhiyun} 315*4882a593Smuzhiyun 316*4882a593Smuzhiyundef set_icecc_env(): 317*4882a593Smuzhiyun # dummy python version of set_icecc_env 318*4882a593Smuzhiyun return 319*4882a593Smuzhiyun 320*4882a593Smuzhiyunset_icecc_env[vardepsexclude] += "KERNEL_CC" 321*4882a593Smuzhiyunset_icecc_env() { 322*4882a593Smuzhiyun if [ "${@use_icecc(bb, d)}" = "no" ] 323*4882a593Smuzhiyun then 324*4882a593Smuzhiyun return 325*4882a593Smuzhiyun fi 326*4882a593Smuzhiyun ICECC_VERSION="${@icecc_version(bb, d)}" 327*4882a593Smuzhiyun if [ "x${ICECC_VERSION}" = "x" ] 328*4882a593Smuzhiyun then 329*4882a593Smuzhiyun bbwarn "Cannot use icecc: could not get ICECC_VERSION" 330*4882a593Smuzhiyun return 331*4882a593Smuzhiyun fi 332*4882a593Smuzhiyun 333*4882a593Smuzhiyun ICE_PATH="${@icecc_path(bb, d)}" 334*4882a593Smuzhiyun if [ "x${ICE_PATH}" = "x" ] 335*4882a593Smuzhiyun then 336*4882a593Smuzhiyun bbwarn "Cannot use icecc: could not get ICE_PATH" 337*4882a593Smuzhiyun return 338*4882a593Smuzhiyun fi 339*4882a593Smuzhiyun 340*4882a593Smuzhiyun ICECC_BIN="${@get_icecc(d)}" 341*4882a593Smuzhiyun if [ -z "${ICECC_BIN}" ]; then 342*4882a593Smuzhiyun bbwarn "Cannot use icecc: icecc binary not found" 343*4882a593Smuzhiyun return 344*4882a593Smuzhiyun fi 345*4882a593Smuzhiyun if [ -z "$(which patchelf patchelf-uninative)" ]; then 346*4882a593Smuzhiyun bbwarn "Cannot use icecc: patchelf not found" 347*4882a593Smuzhiyun return 348*4882a593Smuzhiyun fi 349*4882a593Smuzhiyun 350*4882a593Smuzhiyun ICECC_CC="${@icecc_get_and_check_tool(bb, d, "gcc")}" 351*4882a593Smuzhiyun ICECC_CXX="${@icecc_get_and_check_tool(bb, d, "g++")}" 352*4882a593Smuzhiyun # cannot use icecc_get_and_check_tool here because it assumes as without target_sys prefix 353*4882a593Smuzhiyun ICECC_WHICH_AS="${@bb.utils.which(os.getenv('PATH'), 'as')}" 354*4882a593Smuzhiyun if [ ! -x "${ICECC_CC}" -o ! -x "${ICECC_CXX}" ] 355*4882a593Smuzhiyun then 356*4882a593Smuzhiyun bbnote "Cannot use icecc: could not get ICECC_CC or ICECC_CXX" 357*4882a593Smuzhiyun return 358*4882a593Smuzhiyun fi 359*4882a593Smuzhiyun 360*4882a593Smuzhiyun ICE_VERSION="$($ICECC_CC -dumpversion)" 361*4882a593Smuzhiyun ICECC_VERSION=$(echo ${ICECC_VERSION} | sed -e "s/@VERSION@/$ICE_VERSION/g") 362*4882a593Smuzhiyun if [ ! -x "${ICECC_ENV_EXEC}" ] 363*4882a593Smuzhiyun then 364*4882a593Smuzhiyun bbwarn "Cannot use icecc: invalid ICECC_ENV_EXEC" 365*4882a593Smuzhiyun return 366*4882a593Smuzhiyun fi 367*4882a593Smuzhiyun 368*4882a593Smuzhiyun # Create symlinks to icecc and wrapper-scripts in the recipe-sysroot directory 369*4882a593Smuzhiyun mkdir -p $ICE_PATH/symlinks 370*4882a593Smuzhiyun if [ -n "${KERNEL_CC}" ]; then 371*4882a593Smuzhiyun compilers="${@get_cross_kernel_cc(bb,d)}" 372*4882a593Smuzhiyun else 373*4882a593Smuzhiyun compilers="${HOST_PREFIX}gcc ${HOST_PREFIX}g++" 374*4882a593Smuzhiyun fi 375*4882a593Smuzhiyun for compiler in $compilers; do 376*4882a593Smuzhiyun ln -sf $ICECC_BIN $ICE_PATH/symlinks/$compiler 377*4882a593Smuzhiyun rm -f $ICE_PATH/$compiler 378*4882a593Smuzhiyun cat <<-__EOF__ > $ICE_PATH/$compiler 379*4882a593Smuzhiyun #!/bin/sh -e 380*4882a593Smuzhiyun export ICECC_VERSION=$ICECC_VERSION 381*4882a593Smuzhiyun export ICECC_CC=$ICECC_CC 382*4882a593Smuzhiyun export ICECC_CXX=$ICECC_CXX 383*4882a593Smuzhiyun $ICE_PATH/symlinks/$compiler "\$@" 384*4882a593Smuzhiyun __EOF__ 385*4882a593Smuzhiyun chmod 775 $ICE_PATH/$compiler 386*4882a593Smuzhiyun done 387*4882a593Smuzhiyun 388*4882a593Smuzhiyun ICECC_AS="$(${ICECC_CC} -print-prog-name=as)" 389*4882a593Smuzhiyun # for target recipes should return something like: 390*4882a593Smuzhiyun # /OE/tmp-eglibc/sysroots/x86_64-linux/usr/libexec/arm920tt-oe-linux-gnueabi/gcc/arm-oe-linux-gnueabi/4.8.2/as 391*4882a593Smuzhiyun # and just "as" for native, if it returns "as" in current directory (for whatever reason) use "as" from PATH 392*4882a593Smuzhiyun if [ "$(dirname "${ICECC_AS}")" = "." ] 393*4882a593Smuzhiyun then 394*4882a593Smuzhiyun ICECC_AS="${ICECC_WHICH_AS}" 395*4882a593Smuzhiyun fi 396*4882a593Smuzhiyun 397*4882a593Smuzhiyun if [ ! -f "${ICECC_VERSION}.done" ] 398*4882a593Smuzhiyun then 399*4882a593Smuzhiyun mkdir -p "$(dirname "${ICECC_VERSION}")" 400*4882a593Smuzhiyun 401*4882a593Smuzhiyun # the ICECC_VERSION generation step must be locked by a mutex 402*4882a593Smuzhiyun # in order to prevent race conditions 403*4882a593Smuzhiyun if flock -n "${ICECC_VERSION}.lock" \ 404*4882a593Smuzhiyun ${ICECC_ENV_EXEC} ${ICECC_ENV_DEBUG} "${ICECC_CC}" "${ICECC_CXX}" "${ICECC_AS}" "${ICECC_VERSION}" 405*4882a593Smuzhiyun then 406*4882a593Smuzhiyun touch "${ICECC_VERSION}.done" 407*4882a593Smuzhiyun elif ! wait_for_file "${ICECC_VERSION}.done" 30 408*4882a593Smuzhiyun then 409*4882a593Smuzhiyun # locking failed so wait for ${ICECC_VERSION}.done to appear 410*4882a593Smuzhiyun bbwarn "Timeout waiting for ${ICECC_VERSION}.done" 411*4882a593Smuzhiyun return 412*4882a593Smuzhiyun fi 413*4882a593Smuzhiyun fi 414*4882a593Smuzhiyun 415*4882a593Smuzhiyun # Don't let ccache find the icecream compiler links that have been created, otherwise 416*4882a593Smuzhiyun # it can end up invoking icecream recursively. 417*4882a593Smuzhiyun export CCACHE_PATH="$PATH" 418*4882a593Smuzhiyun export CCACHE_DISABLE="1" 419*4882a593Smuzhiyun 420*4882a593Smuzhiyun export PATH="$ICE_PATH:$PATH" 421*4882a593Smuzhiyun 422*4882a593Smuzhiyun bbnote "Using icecc path: $ICE_PATH" 423*4882a593Smuzhiyun bbnote "Using icecc tarball: $ICECC_VERSION" 424*4882a593Smuzhiyun} 425*4882a593Smuzhiyun 426*4882a593Smuzhiyundo_configure[network] = "1" 427*4882a593Smuzhiyundo_configure:prepend() { 428*4882a593Smuzhiyun set_icecc_env 429*4882a593Smuzhiyun} 430*4882a593Smuzhiyun 431*4882a593Smuzhiyundo_compile[network] = "1" 432*4882a593Smuzhiyundo_compile:prepend() { 433*4882a593Smuzhiyun set_icecc_env 434*4882a593Smuzhiyun} 435*4882a593Smuzhiyun 436*4882a593Smuzhiyundo_compile_kernelmodules[network] = "1" 437*4882a593Smuzhiyundo_compile_kernelmodules:prepend() { 438*4882a593Smuzhiyun set_icecc_env 439*4882a593Smuzhiyun} 440*4882a593Smuzhiyun 441*4882a593Smuzhiyundo_install[network] = "1" 442*4882a593Smuzhiyundo_install:prepend() { 443*4882a593Smuzhiyun set_icecc_env 444*4882a593Smuzhiyun} 445*4882a593Smuzhiyun 446*4882a593Smuzhiyun# IceCream is not (currently) supported in the extensible SDK 447*4882a593SmuzhiyunICECC_SDK_HOST_TASK = "nativesdk-icecc-toolchain" 448*4882a593SmuzhiyunICECC_SDK_HOST_TASK:task-populate-sdk-ext = "" 449*4882a593Smuzhiyun 450*4882a593Smuzhiyun# Don't include IceCream in uninative tarball 451*4882a593SmuzhiyunICECC_SDK_HOST_TASK:pn-uninative-tarball = "" 452*4882a593Smuzhiyun 453*4882a593Smuzhiyun# Add the toolchain scripts to the SDK 454*4882a593SmuzhiyunTOOLCHAIN_HOST_TASK:append = " ${ICECC_SDK_HOST_TASK}" 455