configuring xcode’s clang to compile using a given c++ standard


I’ve been working with C++ lately, particularly the compilers that support the latest C++ standards such as C++11, C++14, C++17, and C++2a (the upcoming C++20 which should be finally published sometime in February). Rather than install gcc/g++ via Brew on my Mac, I’ve been endeavoring to learn how to compile against those standards using Apple’s clang/clang++ compilers.

The unfortunate part for me (at first) was what command line switches needed to be passed to clang to enable the ability to compile a given standard’s code. I was able to determine what those switches were by deliberately mangling a switch in a makefile and then running make. For my troubles I got the following helpful list:

note: use 'c++98' or 'c++03' for 'ISO C++ 1998 with amendments' standard
note: use 'gnu++98' or 'gnu++03' for 'ISO C++ 1998 with amendments and GNU extensions' standard
note: use 'c++11' for 'ISO C++ 2011 with amendments' standard
note: use 'gnu++11' for 'ISO C++ 2011 with amendments and GNU extensions' standard
note: use 'c++14' for 'ISO C++ 2014 with amendments' standard
note: use 'gnu++14' for 'ISO C++ 2014 with amendments and GNU extensions' standard
note: use 'c++17' for 'ISO C++ 2017 with amendments' standard
note: use 'gnu++17' for 'ISO C++ 2017 with amendments and GNU extensions' standard
note: use 'c++2a' for 'Working draft for ISO C++ 2020' standard
note: use 'gnu++2a' for 'Working draft for ISO C++ 2020 with GNU extensions' standard

For example, to compile against C++17, you would use

clang++ --std=c++17 ...

to enable compilation of source code that uses features from C++17 on back. This keeps the tool clutter down on my Mac, which was getting a bit out of hand with the various GCC compilers via Brew. The GCC tools are all very good, but I would rather use clang since it’s delivered by Apple and is a part of the Xcode tool suite available to every Apple user. As of this point in time the Xcode version is 12.1.2 and clang’s version is 11.0.0. One final note, gcc is linked to clang and g++ is linked to clang++.

fun with c++ 14

c++mugI am an Old Geek and this blog is titled Arcane Science Lab for a reason. It should come as no surprise then when I write about very Geeky Things like languages, especially languages like C and C++. While there are plenty of young turks running around espousing the virtues of languages such as Javascript, and their implementations in Node.js and frameworks such as Angular 2, React, and jQuery, the old guard languages such as C and C++ still hold considerable relevance. It needs to be noted that all those other languages are written in C and C++, especially Node.js, which is built on top of Google’s V8 engine, the Javascript engine that runs inside of Chrome. And of course, the Linux kernel, for better or worse, is written in C.

With all that in mind I’ve been looking to update my rusty C and C++ skills. I don’t write C/C++ code commercially anymore because the opportunities in Orlando are based around fairly ancient versions of the compiler. While I want to work with C++ 11 and C++ 14 as well as C11, too many projects are using RHEL 6 or earlier, or its equivalent CentOS 6 or earlier. RHEL 6 ships with gcc 4.4.7, which has no support for contemporary C or C++.

In order to play in those latest C and C++ versions I used Homebrew on my MBP to install gcc 5.x and gcc 6. I then use a Makefile to set up my build environment to use a specific version, thusly;

CC = g++-6
LDFLAGS = -L/usr/local/opt/isl014/lib
CPPFLAGS = -I/usr/local/opt/isl014/include

TARGET = generic_sort

all: $(TARGET)

clean:
    rm $(TARGET)

$(TARGET): $(TARGET).cpp
    $(CC) $(LDFLAGS) $(CPPFLAGS) -o $(TARGET) $(TARGET).cpp

This is the simplest makefile I can come up with. A single TARGET is defined and can be redefined for any simple project. The version of the compiler to use is defined at the top of the makefile along with any special flags (which was displayed as a caveat when I ran ‘brew install homebrew/versions/gcc6’). The test c++ file I used to test the installation is;

#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>

int main() {
    std::vector<int> V(10);

    // Use std::iota to create a sequence of integers 0, 1, ...
    std::iota(V.begin(), V.end(), 1);

    // Print the unsorted data using std::for_each and a lambda
    std::cout << "Original data" << std::endl;
    std::for_each(V.begin(), V.end(), [](auto i) { std::cout << i << " "; });
    std::cout << std::endl;

    // Sort the data using std::sort and a lambda 
    std::sort(V.begin(), V.end(), [](auto i, auto j) { return (i > j); });

    // Print the sorted data using std::for_each and a lambda
    std::cout << "Sorted data" << std::endl;
    std::for_each(V.begin(), V.end(), [](auto i) { std::cout << i << " "; });
    std::cout << std::endl;

    return 0;
}

This small application won’t compile with the latest Apple Xcode C++, but it will compile with Homebrew’s installed version.

I’m looking at C and C++ due to the Internet of Things (and small computers such as the Raspberry Pi and the BeagleBone Black rev C) and the limited resources found on such devices. I’m also interested because that’s my background, going back to when I started with Lifeboat C on an IBM PC XT in 1983. I might meander over to Java or Python or Javascript, but sooner or later, usually sooner, C and C++ call me back, especially when I want to go down to the bare silicon.

More to come…