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 compilers from being used.compiler.whitelist
Only allow the named compilers to be used. If set,compiler.fallback
will be ignored. (Note that if the first entry in this list is a compiler provided by a port, it will always be used, so there is no point having further entries in that case. Multiple entries may be useful if the first ones are Xcode-provided compilers that may not be available on the system.)compiler.fallback
List of compilers that may be used, in order of preference. The first entry in this list that is not incompiler.blacklist
and is available (i.e. is either installed by Xcode on the current system or is provided by a port) will be chosen. The fallback list is chosen automatically based on the current OS and Xcode versions, and you should normally not need to modify it, though appending to it may occasionally be useful.
These keywords all modify the selection of the default value of configure.compiler
,
which can be found in the MacPorts sources: https://github.com/macports/macports-base/blob/master/src/port1.0/portconfigure.tcl#L758
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-3.3 | Clang 3.3 | MacPorts (clang-3.3) |
macports-clang-3.4 | Clang 3.4 | MacPorts (clang-3.4) |
macports-clang-3.7 | Clang 3.7 | MacPorts (clang-3.7) |
macports-clang-5.0 | Clang 5.0 | MacPorts (clang-5.0) |
macports-clang-6.0 | Clang 6.0 | MacPorts (clang-6.0) |
macports-clang-7.0 | Clang 7.0 | MacPorts (clang-7.0) |
macports-clang-8.0 | Clang 8.0 | MacPorts (clang-8.0) |
macports-clang-9.0 | Clang 9.0 | MacPorts (clang-9.0) |
macports-clang-10 | Clang 10 | MacPorts (clang-10) |
macports-clang-11 | Clang 11 | MacPorts (clang-11) |
macports-clang-12 | Clang 12 | MacPorts (clang-12) |
macports-clang-13 | Clang 13 | Macports (clang-13) |
macports-clang-14 | Clang 14 | Macports (clang-14) |
macports-gcc | FSF GCC | MacPorts (port select) |
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-gcc-5 | FSF GCC 5 | MacPorts (gcc5) |
macports-gcc-6 | FSF GCC 6 | MacPorts (gcc6) |
macports-gcc-7 | FSF GCC 7 | MacPorts (gcc7) |
macports-gcc-8 | FSF GCC 8 | MacPorts (gcc8) |
macports-gcc-9 | FSF GCC 9 | MacPorts (gcc9) |
macports-gcc-10 | FSF GCC 10 | MacPorts (gcc10) |
macports-gcc-11 | FSF GCC 11 | MacPorts (gcc11) |
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).
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++ |
clang < 163 | host libstdc++ |
clang >= 163 | host libstdc++ (use -stdlib=libstdc++ ) or host libc++ (use -stdlib=libc++ )
|
macports-clang-* | host libstdc++ (use -stdlib=libstdc++ ) or host libc++ (use -stdlib=libc++ )
|
macports-clang-5.0 or greater on Intel | host libstdc++ (use -stdlib=libstdc++ ) or host libc++ (use -stdlib=libc++ ) or MP libstdc++ (use -stdlib=macports-libstdc++ )
|
Be careful about mixing different C++ runtimes, as there are incompatibilities between them that can lead to problems.
Fortran
For the MacPorts gcc 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 compilers PortGroup 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:
- Create a directory /opt/local/bin/no_default_gcc
- Create a script in that directory called "
cc
" that always prints an error message - Create symlinks "
c++
", "cpp
", "g++
", and "gcc
", all pointing to the "cc
" script - 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
or using git
you can use this process:
git clone https://github.com/ryandesign/macports-user-ryandesign/ cd macports-user-ryandesign sudo cp -R no_default_gcc /opt/local/bin/
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.