GCC and Clang: Library Incompatibility Issues in MacPorts

Jumble monolog (or quickly to What to do?)

Currently, I'm using Boost libraries and C++11 features in my Xcode project. But there is a problem.

Boost libraries in my development environment was installed using MacPorts, and it seems these Boost libraries could not come along with C++11 features and LLDB in Xcode.
Let's make things clear, it is a GCC-Clang compatibility issue.

In Xcode build setting, you can choose GNU's libstdc++ for favor to Boost libraries (I'm not sure, but it seems they're built using GCC in my MacPorts environment), but then C++11 features and LLDB are crippled. Seemingly, libstdc++ provided by Apple LLVM is not C++11-ready.
Vice versa, you can choose LLVM's libc++ for favor to C++11 features and LLDB, but then Boost libraries are crippled.

I think the problem, on the surface, can be distilled to symbol name resolution failure.


For example, standard string type std::string is symbolically std::string in GNU's libstdc++ and std::__1::string in LLVM's libc++. Yes, they are different and incompatible.
Intension behind incompatible symbol naming convention in LLVM is due to difference of implementations of C++ standards between GCC and Clang; this is a safety measure to prevent different C++ implementations to mix within one program.
You can read brief explanation here → (see Stackoverflow answer).


What to do?


To avoid this GCC-Clang incompatibility mayhem, a simple and definite solution is to use a consistent toolchain throughout your development environment. This definitely prevents the trouble like this. But ports provided by MacPorts have their own preference and dislike for choice of compilers; in most cases /opt/bin/clang for Xcode 4.2 and later is used in MacPorts, or other compilers based on configure.compiler and compiler.fallback or compiler.blacklist in Portfile, and ports can be built and installed using different compilers in a long time span. Hell, what should we do!?


Relax, for some ports in MacPorts, maybe you can choose your desired compiler to build them.

System-wide solution
With sudo, edit  /opt/local/etc/macports/macports.conf  to add the following line, for example, MacPorts GCC 4.8 as 1st priority, MacPorts Apple GCC 4.2 as the least:
default_compilers macports-gcc-4.8 apple-gcc-4.2
Choose compilers from the list of available compilers listed in Selecting a different compiler. If a higher priority compiler is checked against compiler.blacklist defined by a port and rejected, then the next priority compiler will be checked against compiler.blacklist; So you should know, if you are unlucky, all of your desired compilers specified in default_compilers can be rejected.

Most of the mechanics of compiler selection is described in  /opt/local/share/macports/Tcl/port1.0/portconfigure.tcl . Here are code snippets of interest, you can have some insight about it; read and trace code lines how configure.compiler, the compiler used to build a port, is determined:
default configure.compiler {[portconfigure::configure_get_default_compiler]}
default compiler.fallback  {[portconfigure::get_compiler_fallback]}
# internal function to determine the default compiler
proc portconfigure::configure_get_default_compiler {args} {
    if {[option compiler.whitelist] != {}} {
        set search_list [option compiler.whitelist]
    } else {
        set search_list [option compiler.fallback]
    }
    foreach compiler $search_list {
        set allowed yes
        foreach pattern [option compiler.blacklist] {
            if {[string match $pattern $compiler]} {
                set allowed no
                break
            }
        }
        if {$allowed &&
            ([file executable [configure_get_compiler cc $compiler]] ||
             [compiler_is_port $compiler])
        } then {
            return $compiler
        }
    }
    ui_warn "All compilers are either blacklisted or unavailable; defaulting to first fallback option"
    return [lindex [option compiler.fallback] 0]
}
# internal function to choose compiler fallback list based on platform
proc portconfigure::get_compiler_fallback {} {
    global xcodeversion macosx_deployment_target default_compilers
    if {[info exists default_compilers]} {
        return $default_compilers
    } elseif {$xcodeversion == "none" || $xcodeversion == ""} {

Per-command solution
Because MacPorts is basically a CUI program and works as a super process of subsequent build processes (autoconf, automaker, configure, make etc), you can use conventional yet unofficial environment variables like CC and CXX to specify your desired compiler, options, et cetera (i.e. CC=/usr/bin/clang CXX=/usr/bin/clang++ CXXFLAGS="-stdlib=libc++" port install , see Using the Right Compiler). However, some ports do not concern environment variables much in their build paradigm, and unfortunately MacPorts' Boost is one of them.

But hey! Don't be depressed; MacPorts yet has several ways to specify certain build options, and it can control how ports are built, including compilers. Here is the command to install Boost with Clang (see available compilers at Selecting a different compiler and example Compiling with clang 3.3 and libc++ (c++11 enabled) (2013)):
sudo port install boost configure.compiler=clang configure.cxx_stdlib="libc++"
…or if Boost was already installed, then the command to rebuild Boost and its dependencies with GCC-4.8 in MacPorts is:
sudo port upgrade --force boost configure.compiler="macports-gcc-4.8" configure.cxx_stdlib="libstdc++"
Bottleneck is that, for consistency, you will have to specify options configure.compiler="" configure.cxx_stdlib="" every time you build some ports.


What I'm thinking, and actually undertaking now, is to completely rebuild ALL "dev" category ports with Apple LLVM Clang (you can list those ports with command port list category:dev and installed). I already uninstalled GCC related ports for certainty.
I like Clang for its user friendliness in warning and error messages (you can avoid consequence of bad programming like global naming pollution by warning option, and much more), and Xcode already transitioned to Clang; I think this is a good opportunity to tidy my development environment.


Comments

Popular posts from this blog

Hardcoding Data Like Images and Sounds into HTML or CSS

Make It Work: Global .gitattributes

Xcode: Easy Shared & Static Lib Management and Linking