#!/bin/sh # gcc_select [-n] [-force] [2 | 3 | 3.x] [-h | --help] [-v | --version] # [-l | --list] [-root] # # # Switch the default gcc to either 2.x or 3.x. # # 2 Select gcc 2.95.2 as the default compiler. # 3 Select gcc 3.1 as the default compiler. # 3.x Select gcc 3.x as the default compiler. # -force Ensure the links are correct for the specified version. # even if the one specified is the current version. # -h Display this help info. # --help Same as -h. # -n Show commands to do selection but do not execute them. # -root Skip 'root' check and assume you have root access. # -v Display gcc_select version number. # --version Same as -v. # -l Display available compiler versions. # --list Same as -l. # # This script will switch the current compiler installation from 2.x # to 3.x or vice versa (or echo the commands to do it if -n is used). # The current version is displayed if no arguments are specified. # # Note, for documentation completeness, there is one additional option. # # -dstroot dir Install the sym links in a /usr directory within the # specified dir or the dir itself if it specifies a usr # directory (e.g., /foo/bar/usr). -dstroot /usr is # allowed, in which case, the sytem is changed to the # requested compiler, i.e., the same effect as not # specifying it at all. # # This is a special option NOT for general use. It is deliberately # omitted from the --help info. It is intended for internal build # procedures to install the sym links in the specified dir instead # of the system. # # Copyright Apple Computer, Inc. 2002, 2003 ####################################################################### GCC_SELECT_VERSION="2.6" ####################################################################### # List of headers in & underneath /usr/include that need to be symlinked # to a compiler-specific version. symlink_hdrs0="assert.h \ float.h \ inttypes.h \ stdarg.h \ stdbool.h \ stdint.h \ varargs.h \ va-ppc.h" symlink_hdrs1="machine/limits.h" # Note, in the above list va-ppc.h is only for gcc2. # List of libraries in /usr/lib and /usr/local/lib that need to be # symlinked to a compiler-specific version. symlink_libs="libcc_dynamic.a \ libcc_kext.a \ libgcc.a \ libcc.a \ libstdc++.a \ libsupc++.a" symlink_local_libs="libcc_noc++.a" # List of directories (underneath /usr) containing a 'default' # symlink that must be adjusted to correspond to the default compiler. default_dirs="include/gcc/darwin \ libexec/gcc/darwin/i386 \ libexec/gcc/darwin/ppc \ lib/gcc/darwin" ####################################################################### # ## gcc_select's main control function # switch_it() { local f who status argc=$# cwd="`/bin/pwd`" local n="\n`echo "usage: ${0##*/}" | sed -e 's/./ /g'`" local usage="${0##*/} [-n] [-force] [2 | 3 | 3.x] [-h | --help] [-v | --version]$n [-l | --list] [-root]" # # Collect the arguments... # dashn= switchto_cc=0 switchto_cc_driver=0 forced= list_versions= usr="/usr" installing= show_help= root= while [ $# -gt 0 ] ; do case $1 in 2* | -2* | 3* | -3*) if [[ "$switchto_cc" != "0" && "$switchto_cc" != "$1" ]]; then echo -e "usage: $usage" echo " Inconsistent compiler versions specified." exit 1 fi switchto_cc=$1 shift ;; -force | --force) forced=1 shift ;; -l | -list | --list) list_versions=1 shift ;; -h | --help | -help | -\?) show_help=1 shift ;; -n) dashn="echo -e ""\040" shift ;; -dstroot | --dstroot) shift usr="`echo "$1" | sed -e 's,/$,,'`" if [ "${usr##*/}" != "usr" ]; then usr="$usr/usr" fi installing=1 shift ;; -root) root=1 shift ;; -v | -version | --version) echo "gcc_select v$GCC_SELECT_VERSION" exit 0 ;; *) echo -e "usage: $usage" echo " Invalid argument ($1)." exit 1 ;; esac done if [ "$show_help" ]; then echo echo -e "usage: $usage" echo echo "2 Select gcc 2.95.2 as the default compiler." echo "3 Select gcc 3.1 as the default compiler." echo "3.x Select gcc 3.x as the default compiler." echo "-force Ensure the links are correct for the specified version" echo " even if it maches the current default version." echo "-h Display this help info." echo "--help Same as -h." echo "-l List available compiler versions." echo "--list Same as -l." echo "-n Show commands to do selection but do not execute them." echo "-root Skip 'root' check and assume you have root access." echo "-v Display gcc_select version number." echo "--version Same as -v." echo exit 0 fi if [ "$list_versions" ]; then echo "Available compiler versions:" cd /usr/include/gcc/darwin command ls -d [23]* exit 1 fi # # We determine which compiler is currently installed by looking at # the version number it displays when we do a cc -v... # actual_ver="`cc -v 2>&1 | grep -i 'gcc version'`" current_cc="`echo \"$actual_ver\" | sed -e 's/.*gcc version \([^ ]*\).*/\1/'`" if [[ ! "$current_cc" == 2* && ! "$current_cc" == 3* ]]; then echo "Error trying to determine current cc version (got $current_cc)" exit 1 fi # No arguments means display only the current compiler version... # if [ $argc -eq 0 ] || [ $argc -eq 1 -a "$show_ver" ]; then echo "Current default compiler:" echo "$actual_ver" exit 0 fi # if -force is specified without a compiler version, simply refresh the # currently installed compiler if [ "$forced" ] && [ "$switchto_cc" == "0" ]; then switchto_cc=$current_cc fi # From here on we must know what we're switching to... # Handle 2.95.2 and 3.1 compiler driver names specially, # for compatibility with Jaguar systems. Other version numbers # should simply have a dash prepended to them, yielding driver # names such as "gcc-3.3", "g++-3.4", etc. # case "$switchto_cc" in 0) echo -e "usage: $usage" echo " You did not specify a compiler version." exit 1 ;; 2 | 2\.95\.2) switchto_cc_driver="2" switchto_cc="2.95.2" ;; 3 | 3\.1) switchto_cc_driver="3" switchto_cc="3.1" ;; *) switchto_cc_driver="-$switchto_cc" ;; esac # # If actually modifying the system do additional checks... # if [ ! "$installing" ]; then # # If what we want to switch to is the same as the current installation # we have nothing more to do (unless we're "forced" to do it)... # if [ ! "$forced" -a "$switchto_cc" == "$current_cc" ]; then echo "You are already using gcc version $current_cc as the default compiler." exit 0 fi # # The gcc_select script operates by setting various symlinks to point to # compiler-version-specific files. The following checks that we do not # accidentally clobber non-symlink files while creating the symlinks. # list= for driver in cc c++ gcc g++; do if [ -e /usr/bin/$driver -a ! -L /usr/bin/$driver ]; then list="$list /usr/bin/$driver" fi done for header in $symlink_hdrs0 $symlink_hdrs1; do if [ -e /usr/include/$header -a ! -L /usr/include/$header ]; then list="$list /usr/include/$header" fi done for lib in $symlink_libs; do if [ -e /usr/lib/$lib -a ! -L /usr/lib/$lib ]; then list="$list /usr/lib/$lib" fi done for lib in $symlink_local_libs; do if [ -e /usr/local/lib/$lib -a ! -L /usr/local/lib/$lib ]; then list="$list /usr/local/lib/$lib" fi done if [ "$list" != "" ]; then show_list "The following file(s) exist on your system but are NOT symlinks." \ "Delete them before using gcc_select." $list exit 1 fi # # We must be running as "root" to be able to do the switching, # unless a `-root' has been specified. # if [ "$dashn" = "" -a ! "$root" ]; then who=$UID if [ $who != 0 ]; then echo '*******************************************' echo '*** THE gcc_select SCRIPT MUST BE RUN ***' echo '*** AS root (OR WITH THE -root OPTION). ***' echo '*** NO CHANGES WERE MADE TO YOUR SETUP. ***' echo '*******************************************' exit 1 fi fi fi # usr # # Make sure that the compiler we are switching to has all the indispensable # drivers, headers and libraries. Here we check only files common to all # compiler releases. # missing= #echo "switchto_cc=$switchto_cc switchto_cc_driver=$switchto_cc_driver" for file_or_dir in \ /usr/bin/gcc$switchto_cc_driver \ /usr/bin/g++$switchto_cc_driver \ /usr/include/gcc/darwin/$switchto_cc/assert.h \ /usr/include/gcc/darwin/$switchto_cc/float.h \ /usr/include/gcc/darwin/$switchto_cc/inttypes.h \ /usr/include/gcc/darwin/$switchto_cc/stdarg.h \ /usr/include/gcc/darwin/$switchto_cc/stdbool.h \ /usr/include/gcc/darwin/$switchto_cc/stdint.h \ /usr/include/gcc/darwin/$switchto_cc/varargs.h \ /usr/libexec/gcc/darwin/ppc/$switchto_cc/ \ /usr/lib/gcc/darwin/$switchto_cc/ \ /usr/include/gcc/darwin/$switchto_cc/ ; do if [ ! -e $file_or_dir ]; then missing="$missing $file_or_dir" fi done if [ "$missing" != "" ]; then show_list "The following is missing from your gcc $switchto_cc compiler installation." \ "Reinstall the $switchto_cc compiler, or use another release." $missing exit 1 fi if [ "$dashn" != "" ]; then echo "Commands that would be executed if \"-n\" were not specified:" fi # # Set the sym links to point to the specified compiler tools. # $dashn mkdir -p $usr/bin $dashn rm -f $usr/bin/cc $usr/bin/c++ $dashn ln -sf gcc$switchto_cc_driver $usr/bin/cc $dashn ln -sf g++$switchto_cc_driver $usr/bin/c++ for driver in gcc g++ gcov; do $dashn rm -f $usr/bin/$driver if [ -x /usr/bin/$driver$switchto_cc_driver ]; then $dashn ln -sf $driver$switchto_cc_driver $usr/bin/$driver fi done # Change the various "default" sym links for # directories. for dir in $default_dirs; do if [ -d /usr/$dir ]; then $dashn mkdir -p $usr/$dir $dashn rm -f $usr/$dir/default $dashn ln -sf $switchto_cc $usr/$dir/default fi done # Set up the library symlinks... $dashn mkdir -p $usr/lib for lib in $symlink_libs; do $dashn rm -f $usr/lib/$lib if [ -e /usr/lib/gcc/darwin/default/$lib ]; then $dashn ln -sf gcc/darwin/default/$lib $usr/lib/$lib fi done $dashn mkdir -p $usr/local/lib for lib in $symlink_local_libs; do $dashn rm -f $usr/local/lib/$lib if [ -e /usr/lib/gcc/darwin/default/$lib ]; then $dashn ln -sf ../gcc/darwin/default/$lib $usr/local/lib/$lib fi done # The functionality in what used to be libcc_dynamic.a in 2.95.2 now # resides in libgcc.a. if [ ! -e $usr/lib/libcc_dynamic.a ]; then $dashn ln -sf gcc/darwin/default/libgcc.a $usr/lib/libcc_dynamic.a fi # Set up header symlinks... $dashn mkdir -p $usr/include for header in $symlink_hdrs0; do $dashn rm -f $usr/include/$header if [ -e /usr/include/gcc/darwin/default/$header ]; then $dashn ln -sf gcc/darwin/default/$header $usr/include/$header fi done for header in $symlink_hdrs1; do $dashn rm -f $usr/include/$header if [ -e /usr/include/gcc/darwin/default/$header ]; then $dashn mkdir -p $usr/include/$(dirname $header) $dashn ln -sf ../gcc/darwin/default/$header $usr/include/$header fi done # Set up man page symlinks... # NB: The crufty /usr/bin/cpp script utilizes the # /usr/libexec/gcc/darwin/{i386,ppc}/default/cpp binary to do its work. # Hence, it makes sense to symlink the cpp man page to the current compiler # default. $dashn mkdir -p $usr/share/man/man1 for manpage in c++ g++ gcc gcov cpp; do $dashn rm -f $usr/share/man/man1/$manpage.1 if [ -e /usr/share/man/man1/$manpage$switchto_cc_driver.1 ]; then $dashn ln -sf $manpage$switchto_cc_driver.1 $usr/share/man/man1/$manpage.1 fi done $dashn rm -rf $usr/share/man/man1/cc.1 if [ -e /usr/share/man/man1/gcc.1 ]; then $dashn ln -sf gcc.1 $usr/share/man/man1/cc.1 fi # # We determine which compiler is currently installed by looking at # the version number it displays when we do a cc -v... # if [ ! "$installing" ]; then if [ "$dashn" == "" ]; then actual_ver="`cc -v 2>&1 | grep -i 'gcc version'`" current_cc="`echo \"$actual_ver\" | sed -e 's/.*gcc version \([^ ]*\).*/\1/'`" if [[ ! "$current_cc" == 2* && ! "$current_cc" == 3* ]]; then echo "Error trying to determine current cc version (got $current_cc)" exit 1 fi echo "Default compiler has been set to:" echo "$actual_ver" fi else echo "$(basename $0): SYMLINKS UNDER '$usr'" echo "$(basename $0): NOW POINT AT gcc$switchto_cc_driver ($switchto_cc)" fi exit 0 } #---------------------------------------------------------------------# # ## show_list info1 info2 item1 ... - display a list of items ## ## This outputs an error message about a list of "bad" items. The ## format is: ## ## info1 ## info2 ## item1 ## - - - ## ## The info2 line is not output if it is null. # show_list() { local info1="$1" local info2="$2" shift 2 if [ ${#@} -gt 0 ]; then echo "$info1" if [ "$info2" != "" ]; then echo "$info2" fi for f; do echo " $f" done fi } ####################################################################### ### main() ############################################################ ####################################################################### os_major="`uname -r | sed -e 's/\([^\.]*\).*/\1/'`" if [ $os_major -lt 6 ]; then echo "You must be using MacOS X 10.2 (Jaguar) or later." exit 1 fi switch_it "$@"