Categories
Technology

Working Example C++ Addin for Excel on Mac OS X using CDT

            <h2>Introduction</h2>

There are some tutorials that try to explain how to create an Excel Addin for Mac OS X but none of the give you a working example for the Mac, and most addin tutorials are aimed at Windows. So I have created a working example which you can find here. This short article gives a bit more explanation on what was needed to make the example work.

Note. These instructions only work for Mac OS X.

Prerequisites and Installation

Install CDT (I didn’t try installing the Eclipse CDT plugin but apparently it works too). I used CDT Mars Release (4.5.0).

  • Download site: https://eclipse.org/cdt/downloads.php
    • standalone: http://www.eclipse.org/downloads/packages/eclipse-ide-cc-developers/marsr
    • update site: http://download.eclipse.org/tools/cdt/releases/8.7

Install Xcode, if not already installed. I used Version 6.4 (6E35b) with all updates applied.

Buy and install Excel Mac 2011, if not already installed.

Start Eclipse CDT and follow the instructions in README.md to import three projects into Eclipse. You should see this when you have finished:

cdt-projects

The C++ Addin – MacExampleAddin

The addin justs adds two doubles together. Its declared in addin.hpp and defined in addin.cpp. In fact we are not using C++ directly but we still use C++ file naming conventions which makes the compiler think we are using C++.

The project builds a 32 bit dylib and was created by choosing the Shared Library -> Empty Project  -> MacOSX GCC in the new Eclipse C++ project dialogue box. Important: You must build a 32 bit shared library for Excel 2011 which is a 32 bit app. So some changes were made to the settings (Eclipse menu -> Project -> Properties) as follows :

  • In C/C++ Build -> Settings Tab make the following changes:
    • MacOS X C++ Linker -> clang++
      • Dialect -> ISO C++11 (-std=c++0x)
      • Miscellaneous  -> -arch i386 -fvisibility=hidden
    • GCC C++ Complier -> clang++
      • Dialect -> ISO C++11 (-std=c++0x)
      • Miscellaneous  -> -c -fmessage-length=0 -fvisibility=hidden -arch i386
    • GCC C Complier -> clang
      • Dialect -> ISO C11 (-std=c11)
      • Miscellaneous  -> -c -fmessage-length=0 -fvisibility=hidden -arch i386

One of my objectives was to use C++11 but I couldn’t be bothered downloading the gcc compilers so I tried clang which is part of Xcode. After a bit of research I discovered the sensible people that wrote clang made the options the same as gcc so that either compiler can be used in place of the other. Eclipse CDT is more gcc focused so doesn’t know about clang which is why the settings changes below were made. As you’ll see, if you try this approach, clang works very well.

If the settings don’t work for you either I’ve missed something in the write up here so check the settings in Eclipse or time has marched on and versions have changed and this tutorial no longer works 🙁

addin.hpp

I declared the functions in an extern “C” directive to ensure the compiler doesn’t mangle the names as it will due to the hpp extension. This will make life simpler when we actually use the addin in Excel as the names in the header will be the same in the shared library. There are actually two functions on the header: addNum and addNum2 which will be explained in a moment but they do the same thing, add two numbers together.

addin.cpp

The file defines EXPORT which is a compiler/linker directive that allows us to selectively export functions in the library along with the appropriate compiler / linker options, that is “-fvisibility=hidden”.

addNum is also wrapped in an extern directive and preceded by the EXPORT to ensure its visible outside of the shared library.

addNum2 is similarly wrapped by extern and EXPORT but calls a function that is invisible in the shared library called notExported. I only did this to show it is possible.

If you examine the library with nm -gU you will see that notExported is in fact not exported which means we aren’t polluting the namespace for our clients.

nm -gU libMacExampleAddin.dylib
00000f40 T _addNum
00000f70 T _addNum2

The nm options are:
-g     Display only global (external) symbols.
-U     Don’t display undefined symbols.

The Excel Spreadsheet using the Addin – MacExampleExcel

Before you start Excel copy MacExampleAddin/Debug/libMacExampleAddin.dylib to the MacExampleExcel directory. When you start Excel you’ll need to accept macros, but don’t worry there’s nothing bad in there, just some VBA to access the shared library.

addin-test.xlsm

When you start Excel it will ask you to accept macros (say yes) but it may not start the VBA editor so select menu Tools -> Macro -> Visual Basic Editor (I’ve exported the basic module here).

As you can see there are two sorts of functions, Private and non-private functions. The private ones are not visible to Excel but the rest are. The reason for separation is because that’s the only way I could get it to work, but conveniently the shared library functions are wrapped and hidden in the private functions and referenced by Lib “….”. The public functions simply call the private ones to return the values you see in the spreadsheet.

As you’ll see I’ve shown functions with absolute paths (addFunctionAbsolute) which only work for me. Yes, not good but it shows it works and you can change it if you want to make it work for your Mac. Secondly there are examples that assume a library is present in the same directory as the Excel spread sheet (addFunctionLocal). These also work if you look at the spreadsheet. Finally there are relative paths (addFunctionRelative) which don’t work but should, but don’t know why.

But what you should see is this:

cdt-excel

 

The C Main program that uses the Addin – MacExampleMain

This is a simple  main program again generated by CDT but as a “Hello World C++ Project” with MacOSX GCC tool chains. I shan’t detail all the changes as you can look at them yourself but basically they are:

  • added -arch i386 to all the tools
  • added the include path to MacExampleAddin/src
  • added the library path to MacExampleAddin/Debug
  • added the library MacExampleAddin (without the preceding lib and .dylib extension)
  • used clang++ and C++11
  • used clang and C11
  • changed main.cpp to test addNum as follows:
if (addNum(1,2) != 3) {
  cerr << "FAIL: Wrong number from addnum expected 3 and got " << addNum(1,2) << endl;
}

For your convenience there is an Eclipse launch that sets up DYLD_LIBRARY_PATH path to allow you to run the project in Eclipse as follows:

Run -> Run History -> MacExampleMain

You should see this in the console:

PASS: Correct number from addnum expected 3 and got 3

You need to set DYLD_LIBRARY_PATH to point to the directory where the dylib is if you intend to run the program in a terminal window:

peter$ ./Debug/MacExampleMain 
dyld: Library not loaded: libMacExampleAddin.dylib
  Referenced from: /Users/peter/Documents/eclipse/workspace-cdt/MacCPPExcelAddinExample/main/./Debug/MacExampleMain
  Reason: image not found
Trace/BPT trap: 5

Fails because the library can’t be found.

peter$ export DYLD_LIBRARY_PATH=../addin/Debug/
peter$ ./Debug/MacExampleMain 
PASS: Correct number from addnum expected 3 and got 3

This works because the library can be found.

But you don’t need to set DYLD_LIBRARY_PATH  if the library is in the current working directory:

peter$ ls -l
-rwxr-xr-x  1 peter  staff  17312 30 Jul 21:04 MacExampleMain
-rwxr-xr-x  1 peter  staff   4704 30 Jul 21:04 libMacExampleAddin.dylib

peter$ ./MacExampleMain 
PASS: Correct number from addnum expected 3 and got 3

 

© Copyright 2015, Peter Lappo, SMR Ltd.