1 # IceCream distributed compiling support
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
8 # For the cross compiler, creates a tar.bz2 of our toolchain and sets
9 # ICECC_VERSION accordingly.
11 # This class needs ICECC_PATH to be set already. It must have
12 # been exported from the shell running bitbake. Setting it in
13 # local.conf is not adequate.
15 # This class objdump, ldconfig, grep, sed installed on the build host.
17 def icc_determine_gcc_version(gcc):
19 Hack to determine the version of GCC
21 'i686-apple-darwin8-gcc-4.0.1 (GCC) 4.0.1 (Apple Computer, Inc. build 5363)'
24 return os.popen("%s --version" % gcc ).readline().split()[2]
28 Create a tar.bz2 of the current toolchain
31 # Constin native-native compilation no environment needed if
32 # host prefix is empty (let us duplicate the query for ease)
33 prefix = bb.data.expand('${HOST_PREFIX}', d)
37 import tarfile, socket, time, os
38 ice_dir = bb.data.expand('${CROSS_DIR}', d)
39 prefix = bb.data.expand('${HOST_PREFIX}' , d)
40 distro = bb.data.expand('${DISTRO}', d)
41 target_sys = bb.data.expand('${TARGET_SYS}', d)
42 target_prefix = bb.data.expand('${TARGET_PREFIX}', d)
43 float = bb.data.getVar('${TARGET_FPU}', d) or "hard"
44 name = socket.gethostname()
46 # Stupid check to determine if we have built a libc and a cross
49 os.stat(os.path.join(ice_dir, target_sys, 'lib', 'ld-linux.so.2'))
50 os.stat(os.path.join(ice_dir, target_sys, 'bin', 'g++'))
51 except: # no cross compiler built yet
54 VERSION = icc_determine_gcc_version( os.path.join(ice_dir,target_sys,"bin","g++") )
55 cross_name = prefix + distro + target_sys + float +VERSION+ name
56 tar_file = os.path.join(ice_dir, 'ice', cross_name + '.tar.bz2')
60 # tar file already exists
64 os.makedirs(os.path.join(ice_dir,'ice'))
66 # directory already exists, continue
69 # FIXME find out the version of the compiler
70 # Consider using -print-prog-name={cc1,cc1plus}
71 # and -print-file-name=specs
73 # We will use the GCC to tell us which tools to use
80 # and we add them to /usr/bin
82 tar = tarfile.open(tar_file, 'w:bz2')
84 # Now add the required files
85 tar.add(os.path.join(ice_dir,target_sys,'bin','gcc'),
86 os.path.join("usr","bin","gcc") )
87 tar.add(os.path.join(ice_dir,target_sys,'bin','g++'),
88 os.path.join("usr","bin","g++") )
89 tar.add(os.path.join(ice_dir,target_sys,'bin','as'),
90 os.path.join("usr","bin","as") )
92 cc = bb.data.getVar('CC', d, True)
94 # use bitbake's PATH so that the cross-compiler is actually found on the PATH
95 oldpath = os.environ['PATH']
96 os.environ['PATH'] = bb.data.getVar('PATH', d, True)
98 # FIXME falsely assuming there is only a single NEEDED per file
99 # FIXME falsely assuming the lib path is /lib
101 # which libc does the compiler need? (for example: libc.so.6)
102 libc = os.popen("objdump -x `which %s` | sed -n 's/.*NEEDED *//p'" % cc).read()[:-1]
103 # what is the absolute path of libc? (for example: /lib/libc.so.6)
104 # FIXME assuming only one entry is returned, which easily breaks
105 libc = os.popen("ldconfig -p | grep -e %s$ | sed 's:[^/]*/:/:'" % libc).read()[:-1]
107 # which loader does the compiler need?
108 ldlinux = os.popen("objdump -x %s | sed -n 's/.*NEEDED *//p'" % libc).read()[:-1]
109 ldlinux = os.popen("ldconfig -p | grep -e %s$ | sed 's:[^/]*/:/:'" % ldlinux).read()[:-1]
114 # Now let us find cc1 and cc1plus
115 cc1 = os.popen("%s -print-prog-name=cc1" % cc).read()[:-1]
116 cc1plus = os.popen("%s -print-prog-name=cc1plus" % cc).read()[:-1]
117 spec = os.popen("%s -print-file-name=specs" % cc).read()[:-1]
119 os.environ['PATH'] = oldpath
121 # CC1 and CC1PLUS should be there...
122 #tar.add(cc1, os.path.join('usr', 'bin', 'cc1'))
123 #tar.add(cc1plus, os.path.join('usr', 'bin', 'cc1plus'))
125 # I think they should remain absolute paths (as gcc expects them there)
129 # spec - if it exists
130 if os.path.exists(spec):
137 def create_path(compilers, type, bb, d):
139 Create Symlinks for the icecc in the staging directory
143 staging = os.path.join(bb.data.expand('${STAGING_DIR}', d), "ice", type)
144 icecc = bb.data.getVar('ICECC_PATH', d)
146 # Create the dir if necessary
152 for compiler in compilers:
153 gcc_path = os.path.join(staging, compiler)
157 os.symlink(icecc, gcc_path)
161 def use_icc_version(bb,d):
162 # Constin native native
163 prefix = bb.data.expand('${HOST_PREFIX}', d)
167 blacklist = [ "cross", "native" ]
169 for black in blacklist:
170 if bb.data.inherits_class(black, d):
175 def icc_path(bb,d,compile):
176 native = bb.data.expand('${PN}', d)
177 blacklist = [ "ulibc", "glibc", "ncurses" ]
178 for black in blacklist:
182 blacklist = [ "cross", "native" ]
183 for black in blacklist:
184 if bb.data.inherits_class(black, d):
187 prefix = bb.data.expand('${HOST_PREFIX}', d)
188 if compile and len(prefix) != 0:
189 return create_path( [prefix+"gcc", prefix+"g++"], "cross", bb, d)
190 elif not compile or len(prefix) == 0:
191 return create_path( ["gcc", "g++"], "native", bb, d)
193 def icc_version(bb,d):
194 return create_env(bb,d)
197 # set the icecream environment variables
198 do_configure_prepend() {
199 export PATH=${@icc_path(bb,d,False)}$PATH
200 export ICECC_CC="gcc"
201 export ICECC_CXX="g++"
204 do_compile_prepend() {
205 export PATH=${@icc_path(bb,d,True)}$PATH
206 export ICECC_CC="${HOST_PREFIX}gcc"
207 export ICECC_CXX="${HOST_PREFIX}g++"
209 if [ "${@use_icc_version(bb,d)}" = "yes" ]; then
210 print ICECC_VERSION="${@icc_version(bb,d)}"
211 export ICECC_VERSION="${@icc_version(bb,d)}"