diff options
| author | Tudor Florea <tudor.florea@enea.com> | 2014-10-16 03:05:19 +0200 |
|---|---|---|
| committer | Tudor Florea <tudor.florea@enea.com> | 2014-10-16 03:05:19 +0200 |
| commit | c527fd1f14c27855a37f2e8ac5346ce8d940ced2 (patch) | |
| tree | bb002c1fdf011c41dbd2f0927bed23ecb5f83c97 /meta/classes/icecc.bbclass | |
| download | poky-c527fd1f14c27855a37f2e8ac5346ce8d940ced2.tar.gz | |
initial commit for Enea Linux 4.0-140929daisy-140929
Migrated from the internal git server on the daisy-enea-point-release branch
Signed-off-by: Tudor Florea <tudor.florea@enea.com>
Diffstat (limited to 'meta/classes/icecc.bbclass')
| -rw-r--r-- | meta/classes/icecc.bbclass | 325 |
1 files changed, 325 insertions, 0 deletions
diff --git a/meta/classes/icecc.bbclass b/meta/classes/icecc.bbclass new file mode 100644 index 0000000000..5c9e66c95e --- /dev/null +++ b/meta/classes/icecc.bbclass | |||
| @@ -0,0 +1,325 @@ | |||
| 1 | # IceCream distributed compiling support | ||
| 2 | # | ||
| 3 | # Stages directories with symlinks from gcc/g++ to icecc, for both | ||
| 4 | # native and cross compilers. Depending on each configure or compile, | ||
| 5 | # the directories are added at the head of the PATH list and ICECC_CXX | ||
| 6 | # and ICEC_CC are set. | ||
| 7 | # | ||
| 8 | # For the cross compiler, creates a tar.gz of our toolchain and sets | ||
| 9 | # ICECC_VERSION accordingly. | ||
| 10 | # | ||
| 11 | # The class now handles all 3 different compile 'stages' (i.e native ,cross-kernel and target) creating the | ||
| 12 | # necessary environment tar.gz file to be used by the remote machines. | ||
| 13 | # It also supports meta-toolchain generation | ||
| 14 | # | ||
| 15 | # If ICECC_PATH is not set in local.conf then the class will try to locate it using 'bb.utils.which' | ||
| 16 | # but nothing is sure ;) | ||
| 17 | # | ||
| 18 | # If ICECC_ENV_EXEC is set in local.conf, then it should point to the icecc-create-env script provided by the user | ||
| 19 | # or the default one provided by icecc-create-env.bb will be used | ||
| 20 | # (NOTE that this is a modified version of the script need it and *not the one that comes with icecc* | ||
| 21 | # | ||
| 22 | # User can specify if specific packages or packages belonging to class should not use icecc to distribute | ||
| 23 | # compile jobs to remote machines, but handled locally, by defining ICECC_USER_CLASS_BL and ICECC_USER_PACKAGE_BL | ||
| 24 | # with the appropriate values in local.conf. In addition the user can force to enable icecc for packages | ||
| 25 | # which set an empty PARALLEL_MAKE variable by defining ICECC_USER_PACKAGE_WL. | ||
| 26 | # | ||
| 27 | ######################################################################################### | ||
| 28 | #Error checking is kept to minimum so double check any parameters you pass to the class | ||
| 29 | ########################################################################################### | ||
| 30 | |||
| 31 | BB_HASHBASE_WHITELIST += "ICECC_PARALLEL_MAKE ICECC_DISABLED ICECC_USER_PACKAGE_BL ICECC_USER_CLASS_BL ICECC_USER_PACKAGE_WL" | ||
| 32 | |||
| 33 | ICECC_ENV_EXEC ?= "${STAGING_BINDIR_NATIVE}/icecc-create-env" | ||
| 34 | |||
| 35 | def icecc_dep_prepend(d): | ||
| 36 | # INHIBIT_DEFAULT_DEPS doesn't apply to the patch command. Whether or not | ||
| 37 | # we need that built is the responsibility of the patch function / class, not | ||
| 38 | # the application. | ||
| 39 | if not d.getVar('INHIBIT_DEFAULT_DEPS'): | ||
| 40 | return "icecc-create-env-native" | ||
| 41 | return "" | ||
| 42 | |||
| 43 | DEPENDS_prepend += "${@icecc_dep_prepend(d)} " | ||
| 44 | |||
| 45 | def get_cross_kernel_cc(bb,d): | ||
| 46 | kernel_cc = d.getVar('KERNEL_CC') | ||
| 47 | |||
| 48 | # evaluate the expression by the shell if necessary | ||
| 49 | if '`' in kernel_cc or '$(' in kernel_cc: | ||
| 50 | kernel_cc = os.popen("echo %s" % kernel_cc).read()[:-1] | ||
| 51 | |||
| 52 | kernel_cc = d.expand(kernel_cc) | ||
| 53 | kernel_cc = kernel_cc.replace('ccache', '').strip() | ||
| 54 | kernel_cc = kernel_cc.split(' ')[0] | ||
| 55 | kernel_cc = kernel_cc.strip() | ||
| 56 | return kernel_cc | ||
| 57 | |||
| 58 | def get_icecc(d): | ||
| 59 | return d.getVar('ICECC_PATH') or bb.utils.which(os.getenv("PATH"), "icecc") | ||
| 60 | |||
| 61 | def create_path(compilers, bb, d): | ||
| 62 | """ | ||
| 63 | Create Symlinks for the icecc in the staging directory | ||
| 64 | """ | ||
| 65 | staging = os.path.join(d.expand('${STAGING_BINDIR}'), "ice") | ||
| 66 | if icc_is_kernel(bb, d): | ||
| 67 | staging += "-kernel" | ||
| 68 | |||
| 69 | #check if the icecc path is set by the user | ||
| 70 | icecc = get_icecc(d) | ||
| 71 | |||
| 72 | # Create the dir if necessary | ||
| 73 | try: | ||
| 74 | os.stat(staging) | ||
| 75 | except: | ||
| 76 | try: | ||
| 77 | os.makedirs(staging) | ||
| 78 | except: | ||
| 79 | pass | ||
| 80 | |||
| 81 | for compiler in compilers: | ||
| 82 | gcc_path = os.path.join(staging, compiler) | ||
| 83 | try: | ||
| 84 | os.stat(gcc_path) | ||
| 85 | except: | ||
| 86 | try: | ||
| 87 | os.symlink(icecc, gcc_path) | ||
| 88 | except: | ||
| 89 | pass | ||
| 90 | |||
| 91 | return staging | ||
| 92 | |||
| 93 | def use_icc(bb,d): | ||
| 94 | # allarch recipes don't use compiler | ||
| 95 | if icc_is_allarch(bb, d): | ||
| 96 | return "no" | ||
| 97 | |||
| 98 | pn = d.getVar('PN', True) | ||
| 99 | |||
| 100 | system_class_blacklist = [] | ||
| 101 | user_class_blacklist = (d.getVar('ICECC_USER_CLASS_BL') or "none").split() | ||
| 102 | package_class_blacklist = system_class_blacklist + user_class_blacklist | ||
| 103 | |||
| 104 | for black in package_class_blacklist: | ||
| 105 | if bb.data.inherits_class(black, d): | ||
| 106 | bb.debug(1, "%s: class %s found in blacklist, disable icecc" % (pn, black)) | ||
| 107 | return "no" | ||
| 108 | |||
| 109 | # "system" recipe blacklist contains a list of packages that can not distribute compile tasks | ||
| 110 | # for one reason or the other | ||
| 111 | # this is the old list (which doesn't seem to be valid anymore, because I was able to build | ||
| 112 | # all these with icecc enabled) | ||
| 113 | # system_package_blacklist = [ "uclibc", "glibc", "gcc", "bind", "u-boot", "dhcp-forwarder", "enchant", "connman", "orbit2" ] | ||
| 114 | # when adding new entry, please document why (how it failed) so that we can re-evaluate it later | ||
| 115 | # e.g. when there is new version | ||
| 116 | system_package_blacklist = [] | ||
| 117 | user_package_blacklist = (d.getVar('ICECC_USER_PACKAGE_BL') or "").split() | ||
| 118 | user_package_whitelist = (d.getVar('ICECC_USER_PACKAGE_WL') or "").split() | ||
| 119 | package_blacklist = system_package_blacklist + user_package_blacklist | ||
| 120 | |||
| 121 | if pn in package_blacklist: | ||
| 122 | bb.debug(1, "%s: found in blacklist, disable icecc" % pn) | ||
| 123 | return "no" | ||
| 124 | |||
| 125 | if pn in user_package_whitelist: | ||
| 126 | bb.debug(1, "%s: found in whitelist, enable icecc" % pn) | ||
| 127 | return "yes" | ||
| 128 | |||
| 129 | if d.getVar('PARALLEL_MAKE') == "": | ||
| 130 | bb.debug(1, "%s: has empty PARALLEL_MAKE, disable icecc" % pn) | ||
| 131 | return "no" | ||
| 132 | |||
| 133 | return "yes" | ||
| 134 | |||
| 135 | def icc_is_allarch(bb, d): | ||
| 136 | return \ | ||
| 137 | bb.data.inherits_class("allarch", d); | ||
| 138 | |||
| 139 | def icc_is_kernel(bb, d): | ||
| 140 | return \ | ||
| 141 | bb.data.inherits_class("kernel", d); | ||
| 142 | |||
| 143 | def icc_is_native(bb, d): | ||
| 144 | return \ | ||
| 145 | bb.data.inherits_class("cross", d) or \ | ||
| 146 | bb.data.inherits_class("native", d); | ||
| 147 | |||
| 148 | # Don't pollute allarch signatures with TARGET_FPU | ||
| 149 | icc_version[vardepsexclude] += "TARGET_FPU" | ||
| 150 | def icc_version(bb, d): | ||
| 151 | if use_icc(bb, d) == "no": | ||
| 152 | return "" | ||
| 153 | |||
| 154 | parallel = d.getVar('ICECC_PARALLEL_MAKE') or "" | ||
| 155 | if not d.getVar('PARALLEL_MAKE') == "" and parallel: | ||
| 156 | d.setVar("PARALLEL_MAKE", parallel) | ||
| 157 | |||
| 158 | if icc_is_native(bb, d): | ||
| 159 | archive_name = "local-host-env" | ||
| 160 | elif d.expand('${HOST_PREFIX}') == "": | ||
| 161 | bb.fatal(d.expand("${PN}"), " NULL prefix") | ||
| 162 | else: | ||
| 163 | prefix = d.expand('${HOST_PREFIX}' ) | ||
| 164 | distro = d.expand('${DISTRO}') | ||
| 165 | target_sys = d.expand('${TARGET_SYS}') | ||
| 166 | float = d.getVar('TARGET_FPU') or "hard" | ||
| 167 | archive_name = prefix + distro + "-" + target_sys + "-" + float | ||
| 168 | if icc_is_kernel(bb, d): | ||
| 169 | archive_name += "-kernel" | ||
| 170 | |||
| 171 | import socket | ||
| 172 | ice_dir = d.expand('${STAGING_DIR_NATIVE}${prefix_native}') | ||
| 173 | tar_file = os.path.join(ice_dir, 'ice', archive_name + "-@VERSION@-" + socket.gethostname() + '.tar.gz') | ||
| 174 | |||
| 175 | return tar_file | ||
| 176 | |||
| 177 | def icc_path(bb,d): | ||
| 178 | if icc_is_kernel(bb, d): | ||
| 179 | return create_path( [get_cross_kernel_cc(bb,d), ], bb, d) | ||
| 180 | |||
| 181 | else: | ||
| 182 | prefix = d.expand('${HOST_PREFIX}') | ||
| 183 | return create_path( [prefix+"gcc", prefix+"g++"], bb, d) | ||
| 184 | |||
| 185 | def icc_get_external_tool(bb, d, tool): | ||
| 186 | external_toolchain_bindir = d.expand('${EXTERNAL_TOOLCHAIN}${bindir_cross}') | ||
| 187 | target_prefix = d.expand('${TARGET_PREFIX}') | ||
| 188 | return os.path.join(external_toolchain_bindir, '%s%s' % (target_prefix, tool)) | ||
| 189 | |||
| 190 | # Don't pollute native signatures with target TUNE_PKGARCH through STAGING_BINDIR_TOOLCHAIN | ||
| 191 | icc_get_tool[vardepsexclude] += "STAGING_BINDIR_TOOLCHAIN" | ||
| 192 | def icc_get_tool(bb, d, tool): | ||
| 193 | if icc_is_native(bb, d): | ||
| 194 | return bb.utils.which(os.getenv("PATH"), tool) | ||
| 195 | elif icc_is_kernel(bb, d): | ||
| 196 | return bb.utils.which(os.getenv("PATH"), get_cross_kernel_cc(bb, d)) | ||
| 197 | else: | ||
| 198 | ice_dir = d.expand('${STAGING_BINDIR_TOOLCHAIN}') | ||
| 199 | target_sys = d.expand('${TARGET_SYS}') | ||
| 200 | tool_bin = os.path.join(ice_dir, "%s-%s" % (target_sys, tool)) | ||
| 201 | if os.path.isfile(tool_bin): | ||
| 202 | return tool_bin | ||
| 203 | else: | ||
| 204 | external_tool_bin = icc_get_external_tool(bb, d, tool) | ||
| 205 | if os.path.isfile(external_tool_bin): | ||
| 206 | return external_tool_bin | ||
| 207 | else: | ||
| 208 | return "" | ||
| 209 | |||
| 210 | def icc_get_and_check_tool(bb, d, tool): | ||
| 211 | # Check that g++ or gcc is not a symbolic link to icecc binary in | ||
| 212 | # PATH or icecc-create-env script will silently create an invalid | ||
| 213 | # compiler environment package. | ||
| 214 | t = icc_get_tool(bb, d, tool) | ||
| 215 | if t and os.popen("readlink -f %s" % t).read()[:-1] == get_icecc(d): | ||
| 216 | bb.error("%s is a symlink to %s in PATH and this prevents icecc from working" % (t, get_icecc(d))) | ||
| 217 | return "" | ||
| 218 | else: | ||
| 219 | return t | ||
| 220 | |||
| 221 | wait_for_file() { | ||
| 222 | local TIME_ELAPSED=0 | ||
| 223 | local FILE_TO_TEST=$1 | ||
| 224 | local TIMEOUT=$2 | ||
| 225 | until [ -f "$FILE_TO_TEST" ] | ||
| 226 | do | ||
| 227 | TIME_ELAPSED=`expr $TIME_ELAPSED + 1` | ||
| 228 | if [ $TIME_ELAPSED -gt $TIMEOUT ] | ||
| 229 | then | ||
| 230 | return 1 | ||
| 231 | fi | ||
| 232 | sleep 1 | ||
| 233 | done | ||
| 234 | } | ||
| 235 | |||
| 236 | def set_icecc_env(): | ||
| 237 | # dummy python version of set_icecc_env | ||
| 238 | return | ||
| 239 | |||
| 240 | set_icecc_env() { | ||
| 241 | if [ "x${ICECC_DISABLED}" != "x" ] | ||
| 242 | then | ||
| 243 | return | ||
| 244 | fi | ||
| 245 | ICECC_VERSION="${@icc_version(bb, d)}" | ||
| 246 | if [ "x${ICECC_VERSION}" = "x" ] | ||
| 247 | then | ||
| 248 | bbwarn "Cannot use icecc: could not get ICECC_VERSION" | ||
| 249 | return | ||
| 250 | fi | ||
| 251 | |||
| 252 | ICE_PATH="${@icc_path(bb, d)}" | ||
| 253 | if [ "x${ICE_PATH}" = "x" ] | ||
| 254 | then | ||
| 255 | bbwarn "Cannot use icecc: could not get ICE_PATH" | ||
| 256 | return | ||
| 257 | fi | ||
| 258 | |||
| 259 | ICECC_CC="${@icc_get_and_check_tool(bb, d, "gcc")}" | ||
| 260 | ICECC_CXX="${@icc_get_and_check_tool(bb, d, "g++")}" | ||
| 261 | # cannot use icc_get_and_check_tool here because it assumes as without target_sys prefix | ||
| 262 | ICECC_WHICH_AS="${@bb.utils.which(os.getenv('PATH'), 'as')}" | ||
| 263 | if [ ! -x "${ICECC_CC}" -o ! -x "${ICECC_CXX}" ] | ||
| 264 | then | ||
| 265 | bbwarn "Cannot use icecc: could not get ICECC_CC or ICECC_CXX" | ||
| 266 | return | ||
| 267 | fi | ||
| 268 | |||
| 269 | ICE_VERSION=`$ICECC_CC -dumpversion` | ||
| 270 | ICECC_VERSION=`echo ${ICECC_VERSION} | sed -e "s/@VERSION@/$ICE_VERSION/g"` | ||
| 271 | if [ ! -x "${ICECC_ENV_EXEC}" ] | ||
| 272 | then | ||
| 273 | bbwarn "Cannot use icecc: invalid ICECC_ENV_EXEC" | ||
| 274 | return | ||
| 275 | fi | ||
| 276 | |||
| 277 | ICECC_AS="`${ICECC_CC} -print-prog-name=as`" | ||
| 278 | # for target recipes should return something like: | ||
| 279 | # /OE/tmp-eglibc/sysroots/x86_64-linux/usr/libexec/arm920tt-oe-linux-gnueabi/gcc/arm-oe-linux-gnueabi/4.8.2/as | ||
| 280 | # and just "as" for native, if it returns "as" in current directory (for whatever reason) use "as" from PATH | ||
| 281 | if [ "`dirname "${ICECC_AS}"`" = "." ] | ||
| 282 | then | ||
| 283 | ICECC_AS="${ICECC_WHICH_AS}" | ||
| 284 | fi | ||
| 285 | |||
| 286 | if [ ! -f "${ICECC_VERSION}.done" ] | ||
| 287 | then | ||
| 288 | mkdir -p "`dirname "${ICECC_VERSION}"`" | ||
| 289 | |||
| 290 | # the ICECC_VERSION generation step must be locked by a mutex | ||
| 291 | # in order to prevent race conditions | ||
| 292 | if flock -n "${ICECC_VERSION}.lock" \ | ||
| 293 | ${ICECC_ENV_EXEC} "${ICECC_CC}" "${ICECC_CXX}" "${ICECC_AS}" "${ICECC_VERSION}" | ||
| 294 | then | ||
| 295 | touch "${ICECC_VERSION}.done" | ||
| 296 | elif [ ! wait_for_file "${ICECC_VERSION}.done" 30 ] | ||
| 297 | then | ||
| 298 | # locking failed so wait for ${ICECC_VERSION}.done to appear | ||
| 299 | bbwarn "Timeout waiting for ${ICECC_VERSION}.done" | ||
| 300 | return | ||
| 301 | fi | ||
| 302 | fi | ||
| 303 | |||
| 304 | export ICECC_VERSION ICECC_CC ICECC_CXX | ||
| 305 | export PATH="$ICE_PATH:$PATH" | ||
| 306 | export CCACHE_PATH="$PATH" | ||
| 307 | |||
| 308 | bbnote "Using icecc" | ||
| 309 | } | ||
| 310 | |||
| 311 | do_configure_prepend() { | ||
| 312 | set_icecc_env | ||
| 313 | } | ||
| 314 | |||
| 315 | do_compile_prepend() { | ||
| 316 | set_icecc_env | ||
| 317 | } | ||
| 318 | |||
| 319 | do_compile_kernelmodules_prepend() { | ||
| 320 | set_icecc_env | ||
| 321 | } | ||
| 322 | |||
| 323 | do_install_prepend() { | ||
| 324 | set_icecc_env | ||
| 325 | } | ||
