C++ dark magic of templating and constexpr

Continuing a little bit from my previous post. I was working on this Android thing that needs Java to be called from C++ and vice-versa, so I had to use JNI and as some might know JNI isn’t that beautiful to work with out of the box, so I was creating nice abstractions – like wrapping jobject in RAII class and make it possible to call methods on that object without always passing the JNIEnv pointer and also creating global references to use the object out of the function call scope etc.

As some might know calling a JNI method requires to pass the method signature which is this string that looks like this for an example: "(IJLjava/lang/String;)Z" where:

  • I stands for integer;
  • J stands for long;
  • Ljava/langString; stands for java.lang.String object;
  • and Z stands for boolean;
  • more on that here.

So every time you call a method you have to think of this string and also pass the apropriate arguments, but why not deduct the signature directly from the argument types passed in the method – of course it wouldn’t work for all the custom Java classes, but something could still be done about it … and so I got carried away.

First take – try to concatenate string by using recursive template argument pack unwrapping.

Basically this:

inline std::string get_signature()
{
    return {};
}

template<typename T, typename... TArgs>
inline std::string get_signature(const T& arg, const TArgs&... args)
{
	  return "x" + get_signature(std::forward<const TArgs&>(args)...);
}

All good – created a lot of special cases for each known JNI type and one special case for std::string -> java.lang.String.

The problem – Godbolt showed me a test case to be around 500 instructions – a lot of things to happening at run-time – mostly string construction and concatenation – which is not what I’d like to happen on every method call.

Take two – reuse single std::string with pre-reserved memory.

inline void get_signature(const std::string&)
{}

template<typename T, typename... TArgs>
inline void get_signature(std::string& out, const T& arg, const TArgs&... args)
{
	  out.append("x");
	  get_signature(out, std::forward<const TArgs&>(args)...);
}

Things start to look better – Godbolt shows reduced instruction count to 200 – still a lot of run-time calculations are happening, but at least there’s no unnecessary re-allocations.

Still I thought to myself – I can do better.

Take three – the dark arts of constexpr.

I thought – could it be possible to run all these concatenations at compile-time? I reverted back to first solution and switched to C++20 in hopes to invoke std::string constexpr constructor and hoped the concatenation operator would work too – turns out compilers are not all there yet.

Then I found this wonderful C++17 example on StackOverflow and that helped me achieve this:

inline constexpr auto get_signature()
{
    return concat("");
}

template<typename T, typename... TArgs>
inline constexpr auto get_signature(const T& arg, const TArgs&... args)
{
	  return concat("x", get_signature(std::forward<const TArgs&>(args)...).str);
}

This reduces everything down to near zero instructions as the string get’s concatenated at compile time. How cool is that?

So in the end I can have this abstraction for JNI method call:

template<typename... TArgs>
inline void invokeMethod(const std::string& method, const TArgs&... args)
{
	constexpr auto signature = get_signature(std::forward<const TArgs&>(args)...);
	jniEnv->CallVoidMethod(method, signature.str, std::forward<const TArgs&>(args)...);
}

which reduces this:

javaObject->invokeMethod("doSomething", "(IJLjava/lang/String;)V", 1234, 987654321L, "asdf");

into this:

javaObject->invokeMethod("doSomething", 1234, 987654321L, "asdf");

Not much, but dope AF!

How to use C++ for Cross-Platform Development

My current line of work revolves around an app that runs on four platforms – Android, iOS, macOS and Windows. It’s core code base is written in C++ and it uses Objective-C (on iOS and macOS) and Java (on Android) to access native APIs. I wanted to share some tips and tricks that I’ve accumulated over time on how to make the ends meet.

This article will mainly concentrate on languages and so called backend part of the application, if you are also interested in cross-platform UI development, then that is a whole another story and I won’t be covering it here. I can only mention some good frameworks to start with, like Qt, React Native, Flutter to name a few (the latter two being further away from C++, but they have C++ bindings).

This article also comes with code examples which you can check out on my GitHub.

Table of contents:

Why C++? Why not JavaScript all the way?

Well, first of all because it’s available on all these platforms plus-minus ouf-of-the-box, so it gives us opportunity to consolidate the business logic and avoid code duplication.

Second it’s truly a Swiss army knife of languages – it gives you speeds of low level languages, and safety and flexibility of high level ones. It allows you to program in OOP or functional style wherever it’s applicable.

<rant><dis>

Third – why not JavaScript (i.e. React and others)? – I hate web development, I’ve spent 12 years of my life doing it and for me it has been the churn of buzzwords and trendy frameworks that die after a year or so. And of course any such high level of abstraction comes with high degree of performance penalty, especially on mobile platforms.

</dis></rant>

Tools

First of all operating system – if you want to develop anything Apple related there’s no other (reasonable) way – you’ll need to get a Mac. So in general my choice is always to use macOS as it gives you opportunity to cover three platforms in one – iOS, macOS and Android, and then use Parallels Desktop with Windows for Windows development. And if you want to throw in Linux in the mix – you can use the same Parallels and install Ubuntu in a separate virtual machine.

Next you’ll need IDE – I chose to go native – Android Studio, Visual Studio and Xcode – they give you all the tools to debug and instrument your app the way the ecosystem developers intended.

Eventually it would be a mess to keep track of four (or five) different IDE/build system projects and all the configuration they could host, so to manage the build systems my weapon of choice is CMake. It’s a build system project generator which means it’s not a build system per-se it just knows how to generate projects for and run other build systems. It outputs native IDE projects which is amazing as it gives you full benefits of native development, but keeps your source and build configuration centralized.

A few tips on CMake:

  • Use APPLE, IOS, WIN32 and ANDROID variables to differentiate between platforms. APPLE in this case covers both macOS and iOS.
  • Avoid temptation to use file(GLOB) as it prevents CMake to detect changes in source structure and prevents it from auto-regenerating the project (which is nice feature to have).
  • You can use single header (.hpp file) for all platforms, but different compilation units (.cpp or .mm files – .mm in this case is Objective-C++ which I’ll cover further down). This gives cleaner C++ code without the unnecessary preprocessor clutter and in case of Objective-C++ it can use the Objective-C syntax mixed with C++.

For example:

set(SOURCE_FILES
    "MyClass.hpp"
    "MyClass.cpp" # Covers shared implementation parts
)
if(IOS)
    # Covers iOS implementation
    list(APPEND SOURCE_FILES "ios/MyClass.mm")
elseif(APPLE)
    # Covers macOS implementation
    list(APPEND SOURCE_FILES "macos/MyClass.mm")
elseif(ANDROID)
    # Covers Android implementation
    list(APPEND SOURCE_FILES "android/MyClass.cpp")
elseif(WIN32)
    # Covers Windows implementation
    list(APPEND SOURCE_FILES "windows/MyClass.cpp")
endif()

Android

Android’s eco system is the weirdest of them all – it uses completely different build system from the rest – Gradle – for which CMake does not generate a project, instead Gradle uses CMake as an underlying build system, but actually it uses CMake to generate and build Ninja projects – yet another build system.

Adding CMake to gradle is quite easy, all you need to do is to add externalNativeBuild clause and point it to root CMakeLists.txt file like this:

externalNativeBuild {
    cmake {
        path 'CMakeLists.txt'
        buildStagingDirectory "build_android_cmake"
    }
}

Then there’s the language for native development which on Android is Java and lately Kotlin – both of them can be mixed among themselves as they both run on JVM (Java Virtual Machine). This is where the fun part begins – to interop it with C++ you have to use JNI (Java Native Interface) which in turn is C API.

Also don’t forget to load your library from Java. You can do that by simply adding a static initialized to any Java class, like Activity or Application class:

    static {
        // Explicitly load our libraries before we start doing everything else
        System.loadLibrary("MyLib"); // name of the library which file name would be libMyLib.so
    }

Few tips to be aware of:

  • jobjects passed to function as arguments are local references, that means that they will be destroyed after the function finished, so if you wish to keep references you need to convert them to global references using NewGlobalRef(JNIEnv*, jobject) method.
  • Don’t forget to explicitly delete your global references, otherwise you’ll run into JVM memory leaks – this is where RAII comes in handy – just call DeleteGlobalRef(JNIEnv*, jobject) method in your destructor for every global reference your C++ object has created.
  • Be careful about threads – if you change threads in C++ and wish to call anything from JNI, you have to attach the thread using jint AttachCurrentThread(JavaVM* vm, void** p_env, void* thr_args) method.
  • Same goes the other way around – don’t forget to add @Synchronize attribute to any Java method that might be called from different thread from C++.

Calling C++ from Java

This is, in some ways, the easiest part – you need to expose your C function (or static C++ method) to JNI and that’s basically it. For example you can declare a Java method native:

package com.example;

class MyClass {
    public native void myMethod();
    # or
    public static native void myMethod();
}

And then to map a C function to it you simply use special naming convention for your C function (Java_<package_name>_<class_name>_<method_name>) with C++ name mangling disabled (i.e. extern “C”):

extern "C" JNIEXPORT jlong JNICALL Java_com_example_MyClass_myMethod(JNIEnv* env, jobject thisptr);

This will map a C function directly to MyClass.myMethod in package com.example.

Another way would be to register your methods in JNI_onLoad callback – a method that is called once when native library is loaded (think of it as a JNI’s “main” or “DllMain” method for the library). This gives opportunity to register any function as native, including static C++ methods.

class MyClass
{
public:
    static void myMethod();
};

// Declare JNI method map
namespace
{
    const JNINativeMethod methodsArray[] =
    {
        { "myMethod", "()V", reinterpret_cast<void*>(&MyClass::myMethod) }
    }
}

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
    JNIEnv* env;
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
    {
        return JNI_ERR;
    }
    // Find the class definition in the current environment
    jclass javaClass = env->FindClass("com/example/MyClass");
    if (!javaClass)
    {
        return JNI_ERR;
    }
    // Register method map for the class
    if (env->RegisterNatives(javaClass, methodsArray, sizeof(methodsArray) / sizeof(methodsArray[0])) < 0)
    {
        return JNI_ERR;
    }
    return JNI_VERSION_1_6;
}

Calling Java from C++

This is a bit trickier as I mentioned above – you have to be careful about which thread you are working in, so you have to keep track of the JVM pointer to get the environment for current thread – this can be achieved by storing the JVM pointer in JNI_OnLoad function.
Apart from thread safety all you need to do is find the class, method ID and then perform the call:

// Find the class
auto javaClass = jniEnv->FindClass("com/example/MyClass");
if (!javaClass)
{
    throw std::runtime_error("Failed to find MyClass in JNI environment");
}
// Find method ID
auto methodId = jniEnv->GetMethodID(javaClass, "someMethod", "()V");
if (!methodId)
{
    throw std::runtime_error("Failed to find someMethod in MyClass");
}
// Call this method on the object (not the class)
jniEnv->CallVoidMethod(jniObject, methodId);

Of course you can get the method of your global object reference without knowing it’s full packaged name using GetObjectClass(JNIEnv*, jobject) function.

Object instances from Java

Now the trickiest part is managing dynamically allocated objects on both sides – having a C++ object instance match Java object instance and vice-versa. To achieve that you’ll need to keep global reference to Java object in your C++ object and a raw pointer address in Java class, and you have to define which of those objects will be the master (responsible for creation and destruction of the other object).

An example of master class in Java:

package com.example;

class MyClass {
    // This member holds a raw ptr to the native C++ object
    private long nativePtr;
    // This method constructs the C++ object and returns
    // raw pointer that get's stored in nativePtr member
    private native long constructNative();
    // This method destroys the C++ object
    private native void destructNative();

    MyClass() {
        nativePtr = constructNative();
    }
    // Java does not have destructors, so you have to have and
    // explicit Dispose method for this
    void Dispose() {
        destructNative();
    }

    private void otherMethod() {
        Log.d("Example", "Java method called");
    }
    private native void someMethod();
}

An example class in C++:

#include <iostream>
#include <jni/jni.h>

class MyClass
{
public:
    MyClass(JNIEnv* initJniEnv, jobject initJniObject)
        : jniEnv(initJniEnv)
        // Immediatelly create a global reference so we don't loose it
        , jniObject(initJniEnv->NewGlobalRef(initJniObject))
    {}
    MyClass(const MyClass&) = delete;
    MyClass& operator=(const MyClass&) = delete;
    ~MyClass()
    {
        // Release the global reference
        jniEnv->DeleteGlobalRef(jniObject);
    }
    void someMethod()
    {
        std::cout << "C++ method called\n";
    }
private:
    JNIEnv* jniEnv { nullptr };
    jobject jniObject;
};

// This method will return the raw C++ pointer stored
// in the MyClass.nativePtr member of the Java object
MyClass* getPtr(JNIEnv* jniEnv, jobject ptrThis)
{
    // First we need to get the class definition of the object
    jclass javaClass = jniEnv->GetObjectClass(ptrThis);
    if (!javaClass)
    {
        jniEnv->FatalError("GetObjectClass failed");
    }
    // Now we find the field ID
    jfieldID nativePtrId = jniEnv->GetFieldID(javaClass, "nativePtr", "J");
    if (! nativePtrId)
    {
        jniEnv->FatalError("GetFieldID failed");
    }
    // And now we read the pointer value, cast it and return it
    jlong nativePtr = jniEnv->GetLongField(ptrThis, nativePtrId);
    return reinterpret_cast<MyClass*>(nativePtr);
}

extern "C" JNIEXPORT jlong JNICALL Java_com_example_MyClass_constructNative(JNIEnv* jniEnv, jobject ptrThis)
{
    // Create global reference
    MyClass* nativeObject = new MyClass(jniEnv, ptrThis);
    return reinterpret_cast<jlong>(nativeObject);
}

extern "C" JNIEXPORT void JNICALL Java_com_example_MyClass_destructNative(JNIEnv* jniEnv, jobject ptrThis)
{
    MyClass* nativeObject = getPtr(jniEnv, ptrThis);
    delete nativeObject;
}

extern "C" JNIEXPORT void JNICALL Java_com_example_MyClass_someMethod(JNIEnv* jniEnv, jobject ptrThis)
    MyClass* nativeObject = getPtr(jniEnv, ptrThis);
    nativeObject->someMethod();
}

Object instances from C++

Another way of doing this is when you have C++ class as the master, you still keep pointers and reference at both ends for ease of inter-communication, but you need to create and destroy Java object from C++, so you need to make calls into JNI from C++.

To do so you’ll need to keep at least JNIEnv pointer stored globally somewhere, and the easiest way is to get it is by declaring JNI_OnLoad function.

A shortened down example of C++ class definition:

// You need a construcotr that constructs the Java object
MyClass:: MyClass()
{
    // Find the class definition
    auto javaClass = jniEnv->FindClass("com/example/MyClass");
    if (!javaClass)
    {
        throw std::runtime_error("Failed to find MyClass in JNI environment");
    }
    // Find constructor method's ID
    auto constructorId = jniEnv->GetMethodID(javaClass, "<init>", "(J)V");
    if (!constructorId)
    {
        throw std::runtime_error("Failed to find MyCrossPlatformClass2 constructor");
    }
    // Create object and pass this pointer as it's first argument for storage
    auto localObject = jniEnv->NewObject(javaClass, constructorId, reinterpret_cast<jlong>(this));
    if (!localObject)
    {
        throw std::runtime_error("Failed to create MyCrossPlatformClass2");
    }
    // Last but not least we need to create global reference so we can keep owning the Java companion class
    jniObject = jniEnv->NewGlobalRef(localObject);
}

// Of course don't forget to have a destructor that releases
// the global reference
MyClass::~ MyClass()
{
    // Release the global reference
    jniEnv->DeleteGlobalRef(jniObject);
}

An example class in Java:

package com.example;

class MyClass {
    // This member holds a raw ptr to the native C++ object
    private long nativePtr;

    // Constructor receives the C++ pointer at initialization time
    MyClass(long initNativePtr) {
        nativePtr = initNativePtr;
    }
}

iOS and macOS

Both platforms are from the same ecosystem the only difference for now is the target architecture, SDKs and a few Frameworks, but the lines are being blurred every day (Catalyst, M1, etc.), so soon it might be a single platform. Both platforms are built using Xcode for which CMake has a nice generator interface. To generate Xcode projects simply call this command line:

# Generate iOS project
cmake -G Xcode -S . -B build_ios -DCMAKE_SYSTEM_NAME=iOS
# Generate macOS project
cmake -G Xcode -S . -B build_macos

*OS native language for almost 20 years has been Objective-C (all the native frameworks are written in it), but lately Swift has taken on the stage and it seems it won’t go anywhere soon.

Objective-C, as it is a C-based language with some syntactic sugar, is really easy to mix with C++, Swift on the other hand is not – unfortunately Swift native functions and objects are not visible to C++ and neither is C++ objects to Swift. I’ll talk about Swift a bit further down.

The tricky part in Objective-C is the memory management, especially with ARC (Automatic Reference Counting) enabled – by default the compiler will continue keeping track of the references even in .cpp files, but if you use some APIs that tend to reinterpret_cast to void* – all is lost then and you might end up with garbage objects (I’m looking at you Qt!).

Overall you only need to use .mm extension to turn the compilation unit into an Objective-C++ file which allows you to write both C++ and Objective-C in the same file, for example – call an Objective-C message within the C++ class method:

void MyClass::someMethod(std::size_t someValue)
{
    [myObjcObject setValue:(NSUInteger)someValue];
}

And of course vice-versa – call C++ method from within the Objective-C method:

-(void)myMethod:(NSUInteger)newValue
{
    _cppObject->otherMetod(static_cast<std::size_t>(newValue));
}

Hosting Objective-C object within C++ class

The tricky part here is to differentiate where the header file that defines the class will be used – this is where the __OBJC__ macro comes in handy. First we add a forward declaration to our Objective-C delegate so it can be used in both Objective-C and C++:

#ifdef __OBJC__
// A standard Objective-C forward declaration when compiling within an Obective-C compilation unit
@class MyDelegate;
#else
#   include <objc/objc.h>
// Declare a type alias when compiling in C++
using MyDelegate = objc_object;
#endif

After that we can add an ARC managed pointer to our C++ class declaration:

class MyClass
{
public:
    MyClass();
    void platformNativeMethod() const;
    void cppMethod() const noexcept;
private:
    // This also keeps track of the reference
    MyDelegate* objCObject;
};

And then just create the object from within Objective-C++:

MyClass::MyClass()
{
    objCObject = [[MyDelegate alloc] init];
}

The ARC will take care of cleaning up when C++ object get’s destroyed.

Hosting C++ object within Objective-C class

This is by far the easiest part, a good example would be a typical Apple delegate pattern with a delegate that proxies all the Objective-C message calls back to C++ class, similarly like in previous example we add an Objective-C delegate as a member to our C++ class, but we also add our C++ class to the delegate like this:

@implementation MyDelegate {
    MyClass* _cppObject;
}

-(instancetype)initWithCppObject:(MyClass*)cppObject
{
    self = [super init];
    if (self)
    {
        _cppObject = cppObject;
    }
    return self;
}

@end

And in C++ constructor pass this to it:

MyClass::MyClass()
{
    objCObject = [[MyDelegate alloc] initWithCppObject:this];
}

You can also create C++ objects within the Objective-C object, just make sure they are properly destroyed either by using RAII smart pointers like std::unique_ptr or by deleting them in the [MyDelegate dalloc] method.

A few words about Objective-C runtime

There is one more way to work with Objective-C from C++ and it’s by calling Objective-C runtime directly using it’s C API (similar to JNI). All you need to know is a few functions, like:

  • objc_msgSend – allows you to call any Objective-C method (send a message)
  • sel_registerName – to get the SEL pointer from message name (remember that message name includes colons) to use in other methods

A few words about Swift

In case of Swift you need to use Objective-C or C to bridge it with C++. An example of making a class and method accessible through Objective-C runtime is marking them with @objc attribute:

@objc
class MyClass {
    @objc
    func swiftMethod() {
        // ...
    }
}

The other way around is somewhat easier – you just need an Objective-C wrapper (just like the delegate example above) that would proxy all the method calls to C++.

There is also undocumented @_cdecl attribute (soon to be standardized) exposing Swift functions as C functions which then can be called from C++. And of course you can call C functions from Swift, so wrapping your C++ method calls in plain C functions would also work.

Windows

On Windows I’d suggest you stick with Visual Studio, you can get a free Community Edition to do some development. To generate Visual Studio project from CMake, simply call this command:

# Generate Windows project
cmake -G "Visual Studio 15 2017 Win64" -S . -B build_windows

This is the easiest part so far as C/C++ are the native languages of the system, although Microsoft has been pushing more on C# and web technologies lately. The tricky part here is that all the previously mentioned platforms have already switched to Clang while Microsoft still uses it’s proprietary C++ compiler by default (you have options to switch to Clang, but as of this writing – it’s not there yet) which means you have to be careful about language features you choose as they might not be implemented yet.

A few words about C#

As I wasn’t planning on describing C# and C++ interop in this article, I won’t be showing any examples, but I wanted to mention the P/Invoke that allows bridging C/C++ to C# classes and makes it possible to call C/C++ functions from C#.

Conclusions

It’s not an easy task at first – you have to pull together three different idioms and wrap them, but after initial boilerplate and keeping stuff in mind you can achieve almost everything.

By far the most complicated is Android and JNI as there are so many abstractions in the way, but once you get to know them, you can actually write everything in C++ without ever touching Java.

The easiest (apart from the obvious – Windows) would be the Objective-C, as it’s a C family language and interops with C++ super easy.

A few things to remember:

  • Always check how each platform/language/ecosystem performs memory management and think ahead – be even more careful than with raw heap allocated C pointers.
  • Always check your thread affinity – especially in JNI, don’t start calling JNIEnv acquired from one thread into another. But it’s also important in Objective-C when working with GCD.

Case against single line if statements

… in curly bracket languages. I’ve always said – using single line ifs is dangerous, because a junior (or even a seasoned) developer might make a mistake and add an extra line of code which will not be executed in the if block.

I was watching this presentation of Kevlin Henney about Structured Programming – it talks that it’s good to use if and else if and fast returns and gotos are bad. It has a lot of examples with single line (non-curly bracket wrapped) ifs, and then this Apple’s SSL goto bug came along.

Let’s look at this simple example:

if (someBoolVar)
    doSomething();

Pretty simple – doSomething() is executed only if someBoolVar is true. Now say someone want’s to add another method call if someBoolVar is true:

if (someBoolVar)
    doSomething();
    doSomethingElse(); // This executes whether someBoolVar is true or not

We have a logical error, that will blow up on run-time. A better solution would be to actually write a single line of if statement:

if (someBoolVar) doSomething();

At least that would prevent adding additional statements without adding scope block. But curly bracket languages have curly brackets that define scope block and my way is to always use them:

if (someBoolVar)
{
    doSomething();
}

And when other developer adds it’s new method call it will actually work as expected:

if (someBoolVar)
{
    doSomething();
    doSomethingElse(); // Executes only if someBoolVar == true
}

So my rules of thumb are:

  • Always use curly brackets in if (or any other control structure) to define subsequent statements;
  • If you must use single line if statement – use just single line;
  • Leave wrapped single if statements to Python, because adding another line won’t make things blow up.

Master’s degree in Computer Engineering

So, I finally did it, I’m graduating from university for the second time. The first time was 12 years ago when I got myself a master’s degree in Physical Chemistry, now it’s time to tie up some loose ends and get a degree in what I’ve been doing professionally for the past 14 years – Computer Engineering.

This time I’m so proud of my work in my master’s thesis that I’m willing to share it in public, so here it goes:

Abstract

In today’s live music performance a computer has become one of the music instruments on stage, but unfortunately it might become a cumbersome factor because of it’s universal nature. As an alternative this thesis researches processor architecture and operating system combinations for running virtual music instrument and virtual sound effects applications on specially developed embedded hardware for live music performances.

The research was done on two different devices with programs running on Linux operating system and directly on processor (bare metal). The main criteria for the research were – the ease of use of development tools, processor performance of floating point calculations and power consumption with an aim to use the device with battery power.

Conclusions were drawn that with today’s relatively cheap embedded hardware devices it’s possible to run virtual music instrument software, these devices boot up fast enough and they can perform long enough on battery power to use them for live performances on stage.

ARCHITECTURE, VST, DAW, EMBEDDED HARDWARE, MUSIC INSTRUMENTS, SOUND EFFECTS, DIGITAL SIGNAL PROCESSING, SOUND SIGNAL SYNTHESIS.

And finally…

So where to next? If that would be possible, I’d look into opportunity to wire a joint doctor’s thesis in chemistry and computer engineering, but we’ll see …

Analog Devices CrossCore Embedded Studio on macOS using Lubuntu

Continuing from my previous how-to post, today I’d like to show you how to develop on Analog Devices hardware using CrossCore Embeded Studio on macOS. As it is with most of these types of sofware – they run on Windows and sometimes (if you’re lucky) they’ll have a Linux version. In my case I wasn’t 100% lucky, as the Linux version does not run quite perfectly on virtual machine.

Prerequisites

  1. VirtualBox
  2. Lubuntu LiveCD
  3. Analog Devices CrossCore Embedded Studio (this one you can download inside the virtual machine)
  4. Windows virtual machine (I used one downloaded from modern.ie)

Prepare virtual machine

After installing the VirtualBox and downloading Lubuntu LiveCD, go and create a new virtual machine with at least 40GB of disk space (you’ll actually need less than that, but it’s always safe to have some legroom).

Mount the LiveCD and install the bare minimum Lubuntu with GUI. After installing the Lubuntu, open the web browser inside it and download CrossCore Embedded Studio.

Installing CCES

Installing CCES is pretty straight forward, just install the deb package using:

wget http://download.analog.com/tools/CrossCoreEmbeddedStudio/Releases/Release_2.8.3/adi-CrossCoreEmbeddedStudio-linux-x86-2.8.3.deb
cd ~/Downloads/
sudo dpkg -i adi-CrossCoreEmbeddedStudio-linux-x86-2.8.3.deb

It will be installed under /opt/analog/cces/2.8.3/.

Unfortunatelly CCES is based on Eclipse (requires Java) and is 32-bit only, so you’ll have to install a few more dependencies by hand to make it work:

sudo apt install lib32z1 lib32stdc++6 lib32ncurses5 openjdk-8-jre:i386 libswt-gtk-3-java:i386

Now you can run the CCES by running:

/opt/analog/cces/2.8.3/Eclipse/cces

Installing license

This is the tricky part – unfortunatelly CCES can’t install license on Lubuntu – it fails with error “validation code has expired” even after entering a valid serial and all the registration data. It also can’t do the e-mail validation and effectivelly won’t add your serial number to license manager. Don’t worry – I found a workaround – use Windows. Bare with me…

You’ll need to do following:

  1. Download Windows on a VirtualBox disk image (I used modern.ie for that purpose with Windows 10 disk image)
  2. Before launching the image change it’s network adapter’s MAC address to match the one used in Lubuntu (Go to Settings -> Network -> Advanced) as CCES uses MAC address to tie the activation to your computer.
  3. Launch Windows, install CCES, activate CCES using your serial number.
  4. Now you’ll have to copy the license.dat file from C:\ProgramData\Analog Devices\CrossCore Embedded Studio\license.dat to your Lubuntu ~/.analog/cces/license.dat – easiest way is to copy it through shared clip-board, because license.dat is just a text file. Just mind that on Windows it has CRLF line endings whereas on Linux it’s LF only.
  5. Get rid of Windows.

Use CrossCore Embedded Studio

When all that is done, you’re ready to write your DSP stuff on a macOS in a virtual Linux, just pass throuh [the device] to the guest machine (Go to Devices -> USB -> [device]) and you’re good to go.

Xilinx ISE WebPACK 14.7 on macOS using Lubuntu

Xilinx does not provide official installation of their FPGA IDEs for macOS, but there’s a nice way around – by using a Linux running on virtual machine. There’s an older how-to for Ubuntu, but I prefer to keep it light weight and went for Lubuntu instead.

Prerequisites

  1. VirtualBox
  2. Lubuntu LiveCD
  3. Xilinx ISE WebPACK 14.7 (this one you can download inside the virtual machine)

Prepare virtual machine

After installing the VirtualBox and downloading Lubuntu LiveCD, go and create a new virtual machine with at least 40GB of disk space (you’ll actually need less than that, but ISE download is huge and the same is the installed version – you’ll need some legroom).

Mount the LiveCD and install the bare minimum Lubuntu with GUI. After installing the Lubuntu, open the web browser inside it and download ISE WebPACK installer.

Installing ISE is pretty straight forward, just extract the archive and run these commands in terminal:

cd ~/Downloads/Xilinx_ISE_DS_Lin_14.7_1015_1/
./xsetup

When installing choose WebPACK version and uncheck “Install cable drivers” as that will fail (we’ll build the driver in the next step). After the installation is finished I’d suggest you add Xilinx bin path to PATH in your ~/.bashrc file:

export PATH=$PATH:/path/to/Xilinx/14.7/ISE_DS/ISE/bin/lin64

You’ll also need to get a license file from Xilinx support site and add it’s path to environment (in the same ~/.bashrc file) as this:

export XILINXD_LICENSE_FILE=/path/to/Xilinx.lic

Build the driver

You’ll need to install a few packages using APT:

sudo apt install git libusb-dev build-essential libc6-dev fxload

Now clone the usb driver from a GIT repo:

cd /path/to/Xilinx
sudo git clone git://git.zerfleddert.de/usb-driver

Build the driver:

cd usb-driver/
sudo make

Set up the driver and restart the udev:

./setup_pcusb /path/to/Xilinx/14.7/ISE_DS/ISE/
/etc/init.d/udev restart

And add the dirver path as a pre-load variable in ~/.bashrc:

export LD_PRELOAD=/path/to/Xilinx/usb-driver/libusb-driver.so

And you’re set, now if you’ve set up everything as I’ve said, type ise in the terminal and it should open up ISE WebPACK.

Use ISE

Don’t forget to pass the Xilinx device to Lubuntu from macOS in VirtualBox Devices -> USB menu.

Here are some screenshots of macOS High Sierra running Lubuntu running ISE WebPACK 14.7:

OS X: an unfinished bussines

It’s been a while since I’ve posted something larger than a tweet. A lot has changed since…

So I’ve got a Mac – after 18 years of PC I’ve finally returned to the wonderful world of Apple – It has changed a lot since the last time I was there (it was Mac OS 7 & 8 back then). It’s changed to something really good – and I can agree with everyone who has switched to OS X, that it just works. All the preinstalled apps, like iMovie, Pages, Mail and Maps – they are a great set of products made to be useful from the very first boot.

Continue reading OS X: an unfinished bussines