wiki:UsingTheRightCompiler

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 in compiler.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:

  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

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.

Last modified 2 years ago Last modified on May 30, 2022, 12:24:25 AM