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-daisy-140929.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 | } | ||