2 # Copyright 1999-2011 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
6 # Format of /etc/env.d/gcc/:
7 # config-TARGET: CURRENT=version for TARGET
8 # TARGET-VER: has a TARGET and VER variable
11 [[ ${ROOT} != */ ]] && ROOT="${ROOT}/"
12 [[ ${ROOT} != /* ]] && ROOT="${PWD}${ROOT}"
16 trap ":" INT QUIT TSTP
19 source /etc/init.d/functions.sh || {
20 echo "${argv0}: Could not source /etc/init.d/functions.sh!" 1>&2
31 # *BSD are plain stupid ... copy a GNU extension but don't just copy it,
32 # change it so it works differently. Wish Darwin did selective evolution
33 # on software developers.
35 : ${SED:=$(type -P sed)}
37 # Further pain: `tac` is not available everywhere #390179
38 if ! type -P tac >/dev/null ; then
39 tac() { ${SED} -e '1!G;h;$!d' "$@" ; }
42 GENTOO_LIBDIR="@GENTOO_LIBDIR@"
43 [[ ${GENTOO_LIBDIR} == @*@ ]] && GENTOO_LIBDIR="lib"
47 Usage: gcc-config [options] [CC Profile]
48 Change the current cc/gcc profile, or give info about profiles.
51 -C, --nocolor Disable color output
52 -O, --use-old Use the old profile if one was selected.
53 -f, --force Make sure all config files are regenerated.
54 -P, --use-portage-chost Only set to given profile if its CHOST is the
55 same as that set in /etc/portage/make.conf
56 (or one of other portage config files...).
57 -c, --get-current-profile Print current used gcc profile.
58 -l, --list-profiles Print a list of available profiles.
59 -S, --split-profile Split profiles into their components
60 -E, --print-environ Print environment that can be used to setup the
61 current gcc profile, or a specified one.
62 -B, --get-bin-path Print path where binaries of the given/current
64 -L, --get-lib-path Print path where libraries of the given/current
67 Profile names are of the form: <CHOST>-<gcc version>
68 For example: i686-pc-linux-gnu-3.2.1
72 [[ $# -lt 1 ]] && usage 1
74 # Usage: source_var <var> <file> [default value]
77 local val=$(source "$2"; echo ${!1})
86 try_real_hard_to_find_CHOST() {
88 # First we read make.conf
91 local varname=${1:-CHOST}
92 local conf=${ROOT}/etc/portage/make.conf
93 if [[ ! -e ${conf} && -e ${ROOT}/etc/make.conf ]] ; then
94 conf=${ROOT}/etc/make.conf
96 local ret=$(source "${conf}" 2>/dev/null ; echo ${!varname})
97 if [[ -z ${ret} ]] ; then
98 # newer portage supports spaces between the var and =
99 # CHOST = "this-is-retarded"
102 -e 's:[[:space:]]::g' \
103 -e "/^${varname}=/p" \
109 if [[ -n ${ret} ]] ; then
115 # Then we try /etc/env.d/gcc/config-${CTARGET}
117 if [[ -s ${ROOT}/etc/env.d/gcc/config-${CTARGET} ]] ; then
118 ret=$(split_gcc_ver $(show_var CURRENT "${ROOT}"/etc/env.d/gcc/config-${CTARGET}))
124 [[ -n ${REAL_CHOST} ]] && return 0
126 # shortcut for switching compilers in a cross chroot
127 if [[ -n ${CHOST} && ${ROOT} != "/" ]] ; then
132 # make sure portage isnt broken
133 if python -V &>/dev/null ; then
134 export REAL_CHOST=$(env -i portageq envvar CHOST 2>/dev/null)
136 ewarn "Python seems to be broken, attempting to locate CHOST ourselves ..."
137 export REAL_CHOST=$(try_real_hard_to_find_CHOST)
140 if [[ -z ${REAL_CHOST} ]] ; then
141 eerror "${argv0}: Could not get portage CHOST!"
142 eerror "${argv0}: You should verify that CHOST is set in one of these places:"
143 eerror "${argv0}: - ${ROOT}/etc/portage/make.conf"
144 eerror "${argv0}: - active environment"
149 is_cross_compiler() {
151 [[ ${CC_COMP/${REAL_CHOST}} == ${CC_COMP} ]]
154 convert_profile_paths() {
155 # Older gcc's used PATH= and ROOTPATH= in the env.d files.
156 # Newer one's only use GCC_PATH=. Convert old to new here.
157 cp -p "${GCC_ENV_D}/${CC_COMP}" "${GCC_ENV_D}/${CC_COMP}.gcc-config-ref" || return 1
159 unset GCC_PATH PATH ROOTPATH
160 source "${GCC_ENV_D}/${CC_COMP}"
161 echo ${GCC_PATH:-${PATH:-${ROOTPATH}}}
167 "${GCC_ENV_D}/${CC_COMP}" || return 1
168 echo "GCC_PATH=\"${GCC_PATH}\"" >> "${GCC_ENV_D}/${CC_COMP}" || return 1
169 touch -r "${GCC_ENV_D}/${CC_COMP}.gcc-config-ref" "${GCC_ENV_D}/${CC_COMP}" || return 1
170 rm -f "${GCC_ENV_D}/${CC_COMP}.gcc-config-ref" || return 1
177 # Find the bin wrapper
179 for wrapper in ${GENTOO_LIBDIR} lib lib64 lib32 lib ; do
180 wrapper="${ROOT}usr/${wrapper}/misc/gcc-config"
181 [[ -e ${wrapper} ]] && break
184 # Update the wrappers for this profile. We maintain this list
185 # by hand as the tools that are available can come & go if the
186 # user re-emerges gcc with dif USE flags. We need to clean out
187 # the old wrappers if the functionality no longer exists.
188 # XXX: Future work: save the list of wrappers we generated in
189 # the generated env.d file so we can scrub things better.
190 # After that, we can use a dynamic list based on what tools are
191 # actually available in ${GCC_PATH}/.
192 for x in {,${CTARGET}-}{cpp,cc,gcc,c++,g++,f77,g77,gcj,gcjh,gcov,gdc,gdmd,gfortran,gccgo} ; do
193 # Obviously don't want to touch native stuff for cross-compilers
194 [[ ${x} != ${CTARGET}-* ]] && is_cross_compiler && continue
196 # Make sure we have no stale wrappers
197 rm -f "${ROOT}/usr/bin/${x}"
198 [[ ${x:${#x}-3} == "gcc" || ${x:${#x}-3} == "g++" ]] \
199 && rm -f "${ROOT}/usr/bin/${x}"{32,64}
201 # Only install a wrapper if the binary exists ...
202 # We want to figure out the 'reference file' for each
203 # wrapper (the binary we're 'wrapping') so that we can
204 # sync mtimes together. This makes things like ccache
205 # happy. See Bug #70548 for more info.
212 ref="${ROOT}/${GCC_PATH}/${ref}"
213 if [[ -x ${ref} ]] ; then
214 cp -f "${wrapper}" "${ROOT}/usr/bin/${x}"
215 touch -r "${ref}" "${ROOT}/usr/bin/${x}"
218 # legacy cruft, make sure we dont leave it laying around #143205
219 rm -f "${ROOT}/usr/bin/${CTARGET}-cc"
221 # install the canonical cpp wrapper
222 [[ ${CTARGET} == *-solaris* ]] && return 0
223 if ! is_cross_compiler ; then
224 cp -f "${wrapper}" "${ROOT}/lib/cpp"
225 touch -r "${ROOT}/usr/bin/${CTARGET}-cpp" "${ROOT}/lib/cpp"
230 if cmp -s "$1" "$2" ; then
245 [[ $(id -u) != "0" ]] && die_eerror "Must be root"
247 if is_cross_compiler ; then
248 ebegin "Switching cross-compiler to ${CC_COMP}"
250 ebegin "Switching native-compiler to ${CC_COMP}"
253 if egrep -q '^(PATH|ROOTPATH)=' "${GCC_ENV_D}/${CC_COMP}" ; then
254 convert_profile_paths "${GCC_ENV_D}/${CC_COMP}" || return 1
256 source_var GCC_PATH "${GCC_ENV_D}/${CC_COMP}"
258 # Setup things properly again for this profile
259 unset GCC_SPECS LDPATH
260 source "${GCC_ENV_D}/${CC_COMP}"
261 # Ignore active profile errors here since we're switching away
262 OLD_CC_COMP=$(get_current_profile 2>/dev/null)
264 # GCC_SPECS have long been stable, and people messing with
265 # them know better than to install bad paths, so don't bother
266 # with sanity checks.
267 local envd="${ENV_D}/05gcc-${CTARGET}"
268 cat <<-EOF > "${envd}.tmp"
270 ROOTPATH="${GCC_PATH}"
271 GCC_SPECS="${GCC_SPECS}"
273 echo "CURRENT=${CC_COMP}" > "${GCC_ENV_D}/config-${CTARGET}"
274 if ! is_cross_compiler ; then
275 # Order our profiles to have the default first ...
276 # We do this so that we can have them ordered with default
277 # first in /etc/ld.so.conf, as the logical is that all
278 # compilers for default CHOST will be used to compile stuff,
279 # and thus we want all their lib paths in /etc/ld.so.conf ...
281 MY_LDPATH=$(${SED} -n \
282 -e '/^LDPATH=/{s|LDPATH=||;s|"||g;s|:|\n|g;p}' \
283 "${GCC_ENV_D}"/${REAL_CHOST}-* \
284 "${GCC_ENV_D}"/${CC_COMP} | tac
287 # Pass all by default
288 awk '!/^(STDCXX_INCDIR|LDPATH|CC|CXX|CTARGET|GCCBITS|GCC_SPECS|GCC_PATH)=/ {print $0}' \
289 "${GCC_ENV_D}/${CC_COMP}" >> "${envd}.tmp"
290 if [[ -d ${ROOT}/etc/ld.so.conf.d ]] ; then
291 echo "${MY_LDPATH}" > "${ROOT}"/etc/ld.so.conf.d/05gcc-${CTARGET}.conf
293 echo "LDPATH=\"${MY_LDPATH}\"" >> "${envd}.tmp"
296 # Punt old files; maybe globs too much, but oh well
298 "${GCC_ENV_D}/NATIVE" "${GCC_ENV_D}/.NATIVE" \
299 "${ENV_D}/05gcc" "${GCC_ENV_D}/config" \
300 "${ENV_D}/05gcc-${CTARGET}"-* "${GCC_ENV_D}/config-${CTARGET}"-*
302 # Help out the gcc wrapper
303 ln -sf ${CC_COMP} "${GCC_ENV_D}/.NATIVE"
306 # Relocate random crap
307 if [[ -e ${ROOT}/usr/${GENTOO_LIBDIR}/pkgconfig/libgcj-${CC_COMP_VERSION}.pc ]] ; then
308 local mver=${CC_COMP_VERSION:0:3}
309 for x in "" "-${mver}" ; do
310 x="${ROOT}/usr/lib/pkgconfig/libgcj${x}.pc"
312 ln -s libgcj-${CC_COMP_VERSION}.pc "${x}"
316 # We need to make sure that libgcc_s.so / libunwind.so make it into /lib.
317 # On many systems (x86/amd64/etc...), this will probably never matter,
318 # but on other systems (arm/mips/etc...), this is quite critical.
319 # http://bugs.gentoo.org/60190
321 # The funky move magic is required for proper updating of in-use files.
323 # Need to cut out extra paths in multilib case and pray the first path
324 # is the "root" multilib path ... maybe some day change this to use
325 # `gcc -print-file-name` ...
327 for multilib in $("${ROOT}/${GCC_PATH}"/gcc -print-multi-lib); do
328 multiarg=${multilib#*;}
329 multiarg=${multiarg/@/-}
330 multilibdir=${multilib%;*}
331 libdir="lib/"$("${ROOT}/${GCC_PATH}"/gcc ${multiarg} -print-multi-os-directory)
332 if mkdir -p "${ROOT}/${libdir}"/.gcc.config.new ; then
333 for gcclib in gcc_s unwind ; do
334 if [[ -n $(ls "${ROOT}/${LDPATH}/${multilibdir}"/lib${gcclib}.so.* 2>/dev/null) ]]; then
335 cp -pP "${ROOT}/${LDPATH}/${multilibdir}"/lib${gcclib}.so.* "${ROOT}/${libdir}"/.gcc.config.new/
336 # no need to sanity remove this as the `mv` should take
337 # care of it. we also need this step to be completly atomic
338 # for systems that have even `mv` linked against libgcc_s.so.
339 # http://bugs.gentoo.org/150257
340 #rm -f "${ROOT}/${libdir}"/lib${gcclib}.so*
341 mv -f "${ROOT}/${libdir}"/.gcc.config.new/* "${ROOT}/${libdir}"/
344 rmdir "${ROOT}/${libdir}"/.gcc.config.new
352 mv_if_diff "${envd}.tmp" "${envd}"
353 local envd_changed=$?
355 update_wrappers ${CTARGET}
357 if [[ ${ROOT} == "/" ]] && \
358 [[ ${OLD_CC_COMP} != ${CC_COMP} || ${FORCE} == "yes" ]] && \
359 [[ ${envd_changed} -eq 1 ]]
361 # in case python is broken ...
362 if ! env-update ; then
364 ewarn "env-update failed to work properly; making sure ld.so.conf paths"
365 ewarn "are setup properly. Please rerun gcc-config with the -f option."
367 if [[ ! -d /etc/ld.so.conf.d ]] ; then
368 show_var LDPATH "${ROOT}"/etc/env.d/05gcc-${CTARGET} \
369 | sed -e 's|:|\n|g' >> /etc/ld.so.conf
379 if [[ ${envd_changed} -ne 0 ]] ; then
381 ewarn "If you intend to use the gcc from the new profile in an already"
382 ewarn "running shell, please remember to do:"
384 ewarn " . /etc/profile"
391 get_current_profile() {
392 local conf="${GCC_ENV_D}/config-${CTARGET}"
393 if [[ ! -f ${conf} ]] ; then
394 conf="${GCC_ENV_D}/config" # old name
395 elif [[ -n ${CC_COMP} ]] && is_cross_compiler ; then
396 conf="${conf}-${CC_COMP}"
399 if [[ ! -f ${conf} ]] ; then
400 eerror "${argv0}: No gcc profile is active!"
404 source_var CURRENT "${conf}"
406 if [[ -z ${CURRENT} ]] ; then
407 eerror "${argv0}: No gcc profile is active!"
409 elif [[ ! -f ${GCC_ENV_D}/${CURRENT} ]] ; then
410 eerror "${argv0}: Active gcc profile is invalid!"
423 if [[ ${ROOT} != "/" ]] ; then
424 echo "Using gcc-config info in ${ROOT}"
427 if [[ ! -f ${GCC_ENV_D}/config-${CTARGET} ]] ; then
428 if ! is_cross_compiler && [[ -e ${GCC_ENV_D}/config ]] ; then
429 [[ -w ${GCC_ENV_D}/config ]] && mv ${GCC_ENV_D}/config ${GCC_ENV_D}/config-${CTARGET}
431 # get_current_profile already warns
432 #eerror "${argv0}: No gcc profile is active; please select one!"
437 source_var CURRENT "${GCC_ENV_D}"/config-${CTARGET}
438 CURRENT_NATIVE=${CURRENT}
440 for x in "${GCC_ENV_D}"/* ; do
441 [[ -f ${x} ]] || continue
442 [[ ${x} == */config* ]] && continue
444 source_var CTARGET "${x}"
448 [[ -n ${filter} ]] && [[ ${filter} != ${CTARGET} ]] && continue
450 if [[ ${target} != ${CTARGET} ]] ; then
451 [[ ${i} -gt 1 ]] && echo
457 if [[ ${x} == ${CURRENT_NATIVE} ]] ; then
458 x="${x} ${GOOD}*${NORMAL}"
459 elif [[ -e ${GCC_ENV_D}/config-${target} ]] ; then
460 source "${GCC_ENV_D}/config-${target}"
461 [[ ${x} == ${CURRENT} ]] && x="${x} ${HILITE}*${NORMAL}"
472 source_var GCC_PATH "${GCC_ENV_D}/${CC_COMP}" "${PATH}"
486 PATH=${GCC_PATH}:${PATH}
487 for var in PATH GCC_SPECS ; do
488 echo "${ENV_CMD} ${var}${SET_ELEMENT}\"${!var}\""
493 get_bin_path() { show_var GCC_PATH "${GCC_ENV_D}/${CC_COMP}" ; }
494 get_lib_path() { show_var LDPATH "${GCC_ENV_D}/${CC_COMP}" ; }
497 # Split up the gcc profile into components:
498 # TARGET-VER[-specs] -> TARGET VER [specs]
499 # arm-linux-3.3.6 -> arm-linux 3.3.6
500 # x86_64-linux-4.0.1-pre1234 -> x86_64-linux 4.0.1-pre1234
501 # sh-linux-3.4.4-hardened -> sh-linux 3.4.4 hardened
503 # So below we will start at the end and run a small state machine ...
506 # specs -> version transition [3->2]
507 # when we find a version component
509 # accept only version components (see the regex)
510 # version -> target transition [2->1]
511 # when we hit a non version component
513 # accept everything we have left
515 echo "$@" | awk -F- '
516 function pushit(onme, pushee) {
517 return (onme == "" ? pushee : pushee"-"onme);
524 for (i=NF; i > 0; --i) {
526 if ($i ~ /^(alpha|beta|pre|rc|p)?[[:digit:].]+$/) {
529 } else if (state == 3)
530 spec=pushit(spec, $i)
535 targ = pushit(targ, $i)
546 print targ " " ver (spec != "" ? " " spec : "")
549 chop_gcc_ver_spec() {
550 local splitTED=$(split_gcc_ver $@) # target ver spec
551 splitTED=${splitTED#* } # ver spec
552 echo ${splitTED/ /-} # ver-spec
557 DOIT="switch_profile"
562 ENV_D="${ROOT}etc/env.d"
563 GCC_ENV_D="${ENV_D}/gcc"
567 # Only use specified compiler if one is not already selected.
569 : ${CTARGET:=$(try_real_hard_to_find_CHOST)}
570 if get_current_profile &>/dev/null ; then
571 CC_COMP=$(get_current_profile)
573 die_eerror "No profile selected, unable to utilize --use-old"
579 -P|--use-portage-chost)
582 -c|--get-current-profile)
583 if [[ ${NEED_ACTION} == "yes" ]] ; then
585 DOIT="get_current_profile"
589 if [[ ${NEED_ACTION} == "yes" ]] ; then
595 if [[ ( $1 != "-S" && $1 != "--split-profile" ) || $# -eq 1 ]] ; then
605 if [[ ${NEED_ACTION} == "yes" ]] ; then
611 if [[ ${NEED_ACTION} == "yes" ]] ; then
617 if [[ ${NEED_ACTION} == "yes" ]] ; then
626 # nothing to do; functions.sh parsed this for us
632 unset RCSfile Revision Date
633 rcsfile="$RCSfile: gcc-config-1.5,v $"
634 rcsfile=${rcsfile#: }
635 rcsfile=${rcsfile%,v*}
636 cvsrev="$Revision: 1.7 $"
638 cvsdate="$Date: 2011/12/07 05:42:19 $"
639 cvsdate=${cvsdate#: }
640 echo "${rcsfile} (r${cvsrev% *} @ ${cvsdate% *})"
644 die_eerror "Invalid switch! Run ${argv0} without parameters for help."
648 if [[ -z ${CC_COMP} ]] ; then
649 if [[ -z $(echo ${x} | tr -d '[:digit:]') ]] ; then
650 # User gave us a # representing the profile
652 for y in "${GCC_ENV_D}"/* ; do
653 [[ -f ${y} ]] || continue
654 [[ ${y} == */config* ]] && continue
656 if [[ -f ${y} ]] && [[ ${x} == ${i} ]] ; then
662 if [[ -z ${CC_COMP} ]] ; then
663 die_eerror "Could not locate profile #$x !"
666 # User gave us a full HOST-gccver
668 if [[ ${DOIT} == "get_current_profile" && -z $(ls "${GCC_ENV_D}"/${x}-* 2>/dev/null) ]] || \
669 [[ ${DOIT} != "get_current_profile" && ! -f ${GCC_ENV_D}/${x} ]]
671 # Maybe they just gave us a gccver ...
673 if [[ -f ${GCC_ENV_D}/${REAL_CHOST}-${x} ]] ; then
676 die_eerror "Could not locate '$x' in '${GCC_ENV_D}/' !"
682 die_eerror "Too many arguments! Run ${argv0} without parameters for help."
690 if [[ ${DOIT} == "switch_profile" ]] && [[ -z ${CC_COMP} ]] ; then
695 [[ ${DOIT} == "get_current_profile" ]] \
696 && : ${CTARGET:=${CC_COMP:-${REAL_CHOST}}} \
697 || : ${CTARGET:=${REAL_CHOST}}
699 if [[ -z ${CC_COMP} ]] ; then
700 CC_COMP=$(get_current_profile)
701 if [[ $? -ne 0 ]] ; then
708 if [[ ${DOIT} != "get_current_profile" ]] ; then
710 show_var LDPATH "${GCC_ENV_D}/${CC_COMP}" | \
711 awk -F/ '{ print "/"$2"/"$3"/"$4"/" }'
714 CC_COMP_VERSION=$(chop_gcc_ver_spec ${CC_COMP})
715 CC_COMP_TARGET=${CC_COMP%-${CC_COMP_VERSION}*}
717 if [[ ! -d ${ROOT}/${GCC_LIB}/${CC_COMP_TARGET}/${CC_COMP_VERSION} ]]; then
718 CC_COMP_VERSION=${CC_COMP_VERSION%-*}
721 if [[ ! -d ${ROOT}/${GCC_LIB}/${CC_COMP_TARGET}/${CC_COMP_VERSION} ]] || \
722 [[ ! -f ${GCC_ENV_D}/${CC_COMP} ]]
724 eerror "${argv0}: Profile does not exist or invalid setting for ${GCC_ENV_D}/${CC_COMP}" 1>&2
729 if [[ ${CHECK_CHOST} == "yes" ]] ; then
730 # Chosen CHOST are not the same as the real CHOST according to
731 # make.conf, and --use-portage-chost option was given, so do nothing
733 CC_COMP_VERSION=$(chop_gcc_ver_spec ${CC_COMP})
734 CC_COMP_TARGET=${CC_COMP:0:${#CC_COMP}-${#CC_COMP_VERSION}-1}
735 [[ ${CC_COMP_TARGET} != ${REAL_CHOST} ]] && exit 0