New Ticket     Tickets     Wiki     Browse Source     Timeline     Roadmap     Ticket Reports     Search
Last modified 2 months ago Last modified on 07/30/14 11:52:53

Using the Right Compiler

Introduction

Much of the software in MacPorts is built using a C or C++ compiler, and the various versions of Xcode for OS X come with different compiler suites and versions. With Xcode 2.5 on OS X 10.4, gcc 3.3 and 4.0 are available, with 4.0 being the default. With Xcode 3.1 on OS X 10.5, gcc 4.2 is also available. With Xcode 3.2 on OS X 10.6, llvm-gcc-4.2 and clang are also available; gcc 4.2 is the default. With Xcode 4.0 and 4.1 on OS X 10.6 or 10.7, llvm-gcc-4.2 is the default. With Xcode 4.2 or later, clang is the default and gcc is no longer included. The Xcode 4.6 release notes state that it is the last version of Xcode that will include llvm-gcc-4.2, which will leave only clang.

The problem with the default compiler

If not instructed otherwise, most software builds C code using "cc" or "gcc". But "/usr/bin/cc" and "/usr/bin/gcc" are not specific compilers; they're symlinks to some suitable default compiler, but it varies based on Xcode version. Users might also have created a "/opt/local/bin/gcc" symlink, pointing to any installed compiler, by using "port select --set gcc". So we cannot rely on "cc" oc "gcc" being any particular compiler.

Most port authors will not have used "port select --set gcc $value" and will therefore have the usual default version of gcc on their machine, and will not have tested to see what happens if a different gcc is selected. To remove this testing burden from maintainers, and to prevent users from running into unanticipated problems, MacPorts arranges for ports to compile by default using the same compiler that the installed version of Xcode would use, and does not use the unpredictable "cc" or "gcc" symlinks. It does this by specifying the desired compiler's complete path in the CC environment variable during the port's configure phase. For example, with Xcode 4.2 and later, CC is set to "/usr/bin/clang" so that there is no ambiguity.

In fact there are more variables than just CC: there's also CXX for the C++ compiler and CPP for the C pre-processor. During the configure phase, MacPorts sets each of these variables to the right value for the user's Xcode version. It does this through the use of a number of similarly-named Tcl variables: ${configure.cc}, ${configure.cxx} and ${configure.cpp}.

Selecting a different compiler

For most ports, the default compiler chosen by MacPorts is the one that should be used, unless that compiler doesn't work with that port for some reason. In that case, the maintainer can select a different compiler for that port by overwriting ${configure.cc} and friends, but what you probably want to do instead is overwrite the ${configure.compiler} variable, which sets all the related variables for you simultaneously. However, instead of overriding ${configure.compiler} manually, in most cases you should instead use some combination of the following keywords instead:

  • compiler.blacklist (prevent the named compiler from being used)
  • compiler.whitelist (only allow the named compiler to be used)
  • compiler.fallback (if all other compilers are blacklisted, allow the named compiler to be used)

These keywords all modify the compiler fallback list, which can be found in the MacPorts sources: tags/release_2_3_1/base/src/port1.0/portconfigure.tcl#L426

MacPorts knows about several compilers:

configure.compiler value Compiler Provided by
apple-gcc-4.0 Apple GCC 4.0 MacPorts (apple-gcc40)
apple-gcc-4.2 Apple GCC 4.2 MacPorts (apple-gcc42)
cc /usr/bin/cc Xcode
clang Clang / Apple LLVM Compiler Xcode 3.2 and newer
gcc /usr/bin/gcc Xcode
gcc-3.3 GCC 3.3 Xcode
gcc-4.0 Apple GCC 4.0 Xcode 2.0 through 3.2.6
gcc-4.2 Apple GCC 4.2 Xcode 3.1 through 3.2.6
llvm-gcc-4.2 LLVM-GCC 4.2 Xcode 3.1 through 4.6.x
macports-clang Clang MacPorts (port select)
macports-clang-2.9 Clang 2.9 MacPorts (clang-2.9)
macports-clang-3.0 Clang 3.0 MacPorts (clang-3.0)
macports-clang-3.1 Clang 3.1 MacPorts (clang-3.1)
macports-clang-3.2 Clang 3.2 MacPorts (clang-3.2)
macports-clang-3.3 Clang 3.3 MacPorts (clang-3.3)
macports-clang-3.4 Clang 3.4 MacPorts (clang-3.4)
macports-clang-3.5 Clang 3.5 MacPorts (clang-3.5)
macports-dragonegg-3.0 DragonEgg 3.0 with FSF GCC 4.6 MacPorts (dragonegg-3.0)
macports-dragonegg-3.0-gcc-4.5 DragonEgg 3.0 with FSF GCC 4.5 MacPorts (dragonegg-3.0-gcc-4.5)
macports-dragonegg-3.0-gcc-4.6 DragonEgg 3.0 with FSF GCC 4.6 MacPorts (dragonegg-3.0-gcc-4.6)
macports-dragonegg-3.1 DragonEgg 3.1 with FSF GCC 4.6 MacPorts (dragonegg-3.1)
macports-dragonegg-3.1-gcc-4.5 DragonEgg 3.1 with FSF GCC 4.5 MacPorts (dragonegg-3.1-gcc-4.5)
macports-dragonegg-3.1-gcc-4.6 DragonEgg 3.1 with FSF GCC 4.6 MacPorts (dragonegg-3.1-gcc-4.6)
macports-dragonegg-3.1-gcc-4.7 DragonEgg 3.1 with FSF GCC 4.7 MacPorts (dragonegg-3.1-gcc-4.7)
macports-dragonegg-3.2 DragonEgg 3.2 with FSF GCC 4.6 MacPorts (dragonegg-3.2)
macports-dragonegg-3.2-gcc-4.5 DragonEgg 3.2 with FSF GCC 4.5 MacPorts (dragonegg-3.2-gcc-4.5)
macports-dragonegg-3.2-gcc-4.6 DragonEgg 3.2 with FSF GCC 4.6 MacPorts (dragonegg-3.2-gcc-4.6)
macports-dragonegg-3.2-gcc-4.7 DragonEgg 3.2 with FSF GCC 4.7 MacPorts (dragonegg-3.2-gcc-4.7)
macports-dragonegg-3.3 DragonEgg 3.3 with FSF GCC 4.6 MacPorts (dragonegg-3.3)
macports-dragonegg-3.3-gcc-4.5 DragonEgg 3.3 with FSF GCC 4.5 MacPorts (dragonegg-3.3-gcc-4.5)
macports-dragonegg-3.3-gcc-4.6 DragonEgg 3.3 with FSF GCC 4.6 MacPorts (dragonegg-3.3-gcc-4.6)
macports-dragonegg-3.3-gcc-4.7 DragonEgg 3.3 with FSF GCC 4.7 MacPorts (dragonegg-3.3-gcc-4.7)
macports-dragonegg-3.3-gcc-4.8 DragonEgg 3.3 with FSF GCC 4.8 MacPorts (dragonegg-3.3-gcc-4.8)
macports-dragonegg-3.4 DragonEgg 3.4 with FSF GCC 4.6 MacPorts (dragonegg-3.4)
macports-dragonegg-3.4-gcc-4.5 DragonEgg 3.4 with FSF GCC 4.5 MacPorts (dragonegg-3.4-gcc-4.5)
macports-dragonegg-3.4-gcc-4.6 DragonEgg 3.4 with FSF GCC 4.6 MacPorts (dragonegg-3.4-gcc-4.6)
macports-dragonegg-3.4-gcc-4.7 DragonEgg 3.4 with FSF GCC 4.7 MacPorts (dragonegg-3.4-gcc-4.7)
macports-dragonegg-3.4-gcc-4.8 DragonEgg 3.4 with FSF GCC 4.8 MacPorts (dragonegg-3.4-gcc-4.8)
macports-dragonegg-3.5 DragonEgg 3.5 with FSF GCC 4.6 MacPorts (dragonegg-3.5)
macports-dragonegg-3.5-gcc-4.5 DragonEgg 3.5 with FSF GCC 4.5 MacPorts (dragonegg-3.5-gcc-4.5)
macports-dragonegg-3.5-gcc-4.6 DragonEgg 3.5 with FSF GCC 4.6 MacPorts (dragonegg-3.5-gcc-4.6)
macports-dragonegg-3.5-gcc-4.7 DragonEgg 3.5 with FSF GCC 4.7 MacPorts (dragonegg-3.5-gcc-4.7)
macports-dragonegg-3.5-gcc-4.8 DragonEgg 3.5 with FSF GCC 4.8 MacPorts (dragonegg-3.5-gcc-4.8)
macports-gcc FSF GCC MacPorts (port select)
macports-gcc-4.2 FSF GCC 4.2 MacPorts (gcc42)
macports-gcc-4.3 FSF GCC 4.3 MacPorts (gcc43)
macports-gcc-4.4 FSF GCC 4.4 MacPorts (gcc44)
macports-gcc-4.5 FSF GCC 4.5 MacPorts (gcc45)
macports-gcc-4.6 FSF GCC 4.6 MacPorts (gcc46)
macports-gcc-4.7 FSF GCC 4.7 MacPorts (gcc47)
macports-gcc-4.8 FSF GCC 4.8 MacPorts (gcc48)
macports-gcc-4.9 FSF GCC 4.9 MacPorts (gcc49)
macports-llvm-gcc-4.2 LLVM-GCC 4.2 MacPorts (llvm-gcc42)

Compiler names beginning with "macports" use ports in MacPorts (e.g. "macports-gcc-4.7" corresponds to the gcc47 port). So do those whose names begin with "apple" (e.g. "apple-gcc-4.2" corresponds to the apple-gcc42 port). The remaining compiler names refer to compilers installed by Xcode (e.g. "gcc-4.2" is the gcc 4.2.1 compiler installed by Xcode). Note that until the release of MacPorts 2.2, if you set ${configure.compiler} to a compiler provided by a MacPorts port, you must also declare a library dependency on that port.

C++

One thing to be aware of when choosing which compiler to use is that different compilers use different C++ runtimes:

Compiler C++ runtime used
gcc-* host libstdc++
*llvm-gcc-4.2 host libstdc++
apple-gcc-* host libstdc++
macports-gcc-* MP libstdc++
dragonegg-* MP libstdc++
clang < 163 host libstdc++
clang >= 163 host libstdc++ or host libc++
macports-clang-* host libstdc++ or host libc++

Be careful about mixing different C++ runtimes, as there are incompatibilities between them that can lead to problems.

Fortran

For the MacPorts gcc 4 compilers, additional environment variables FC, F77 and F90 are set to the path of the Fortran compiler. These variables are not set for the other compilers because they do not include a Fortran compiler. Note if that you are developing a port that uses Fortran, there is a Fortran PortfileRecipe that you can use to simplify the usage of Fortran in your port.

Ports with nonstandard or nonexistent configure scripts

Setting the CC, CXX and CPP environment variables at configure time is all that most software needs in order to use the compiler we want. But some ports have unusual configure scripts that don't obey these settings, and some ports don't have a configure script at all. For such ports, it can be necessary to set the variables at build time:

build.args-append       CC=${configure.cc} \
                        CXX=${configure.cxx} \
                        CPP=${configure.cpp}

Some ports' Makefiles do not use the CC variable and always try to run "gcc" or "cc". In these cases, patches are needed. For example, "gcc" or "cc" can be replaced with "$(CC)" in the Makefile, possibly in combination with setting ${build.args} as above. Such patches should usually be sent upstream for inclusion in the next version of the software.

How to test

Unless you look closely at the build output in debug mode, it can be hard to know whether a port is using ${configure.cc} as it should. Here is one way to make it obvious:

  1. Create a directory /opt/local/bin/no_default_gcc
  2. Create a script in that directory called "cc" that always prints an error message
  3. Create symlinks "c++", "cpp", "g++", and "gcc", all pointing to the "cc" script
  4. Edit the value of "binpath" in /opt/local/etc/macports/macports.conf so that it begins with "/opt/local/bin/no_default_gcc:"

Now anytime a port tries to use one of these unversioned programs, the above script will be found instead of the actual program and the compile will stop with an error.

Steps 1 through 3 can be done by checking out this directory from the MacPorts Subversion repository:

svn checkout \
https://svn.macports.org/repository/macports/users/ryandesign/no_default_gcc \
/opt/local/bin/no_default_gcc

If you encounter a port which triggers this error but you don't want to fix it immediately, you can bypass it by editing macports.conf and removing "/opt/local/bin/no_default_gcc:" from the "binpath" again.