SlideShare a Scribd company logo
Hourglass Interfaces 
for C++ APIs 
Stefanus Du Toit 
Thalmic Labs 
@stefanusdutoit 
Image © Erik Fitzpatrick, CC BY 2.0
Motivation and 
Introduction
Shared Libraries 
Library Code Data
Shared Libraries 
Interface 
Code Data 
Library
Shared Libraries 
Interface 
Code Data 
Client! 
Program 
Library 
Code Data
Shared Libraries 
Interface 
Code Data 
Client! 
Program 
Library 
Code Data 
ABI! 
! 
Common libraries
Different ABIs? Subtle problems… 
Class A 
Class B
Different ABIs? Subtle problems… 
Class A 
Class B 
Debug Build 
Release Build
My Goal for Libraries 
Get out of the client’s way.
My Goal for Libraries 
Don’t make my clients: 
• build my code if they don’t want to 
• change how they build their code 
• rebuild their code because I shipped a fix in mine 
• learn a new language if they don’t want to
Hourglass Interfaces for C++ APIs - CppCon 2014
Hourglass Interfaces for C++ APIs - CppCon 2014
Why does this help? 
• Avoids ABI-related binary compatibility issues 
• Enforces no use of non-trivial C++ types in the 
binary interface (e.g. std::string) 
• Keeps internal layout of data types a secret 
• Makes binding to other languages much easier 
! 
• Still get all the convenience of C++ at both ends
Example: libhairpoll 
• A library for creating hair-related polls, taking 
votes, and tallying the results
hairpoll.h 
typedef struct hairpoll* hairpoll_t; 
! 
hairpoll_t hairpoll_construct(const char* person); 
void hairpoll_destruct(hairpoll_t poll); 
! 
int32_t hairpoll_add_option(hairpoll_t hairpoll, 
const char* name, const char* image_url); 
! 
void hairpoll_vote(hairpoll_t hairpoll, int32_t option); 
! 
typedef void (*hairpoll_result_handler_t)(void* client_data, 
const char* name, int32_t votes, const char* html); 
! 
void hairpoll_tally(const hairpoll_t hairpoll, 
hairpoll_result_handler_t handler, void* client_data);
HairPoll class - client-facing 
class HairPoll { 
public: 
HairPoll(std::string person); 
~HairPoll(); 
! 
int addOption(std::string name, std::string imageUrl); 
void vote(int option); 
! 
struct Result { 
std::string name; 
int votes; 
std::string html; 
}; 
std::vector<Result> results() const; 
! 
private: 
hairpoll_t _opaque; 
};
Best Practices
Parts of C to use in the thin API 
• C89 + const and // comments 
• Functions, but no variadic functions 
• C primitive types (char, void, etc.) 
• Pointers 
• forward-declared structs 
• enumerations 
• Function pointers are OK, too
Opaque Types 
typedef struct hairpoll* hairpoll_t; 
! 
void hairpoll_vote( 
hairpoll_t hairpoll, 
int32_t option 
);
Opaque Types 
extern "C" 
struct hairpoll { 
Poll actual; 
};
Opaque Types 
extern "C" 
struct hairpoll { 
template<typename... Args> 
hairpoll(Args&&... args) 
: actual(std::forward<Args>(args)...) 
{ 
} 
! 
Poll actual; 
};
Opaque Types 
class Poll { 
public: 
Poll(std::string person); 
! 
struct option { 
option(std::string name, std::string url); 
! 
std::string name; 
std::string url; 
int votes; 
}; 
! 
std::string person; 
std::vector<option> options; 
};
Opaque Types 
hairpoll_t 
hairpoll_construct(const char* person) 
{ 
return new hairpoll(person); 
} 
! 
void hairpoll_destruct(hairpoll_t poll) 
{ 
delete poll; 
}
Integral types 
Prefer stdint.h types (int32_t, int64_t, etc.) over plain 
C integer types (short, int, long): 
! 
void hairpoll_vote( 
hairpoll_t hairpoll, 
int32_t option 
);
Integral types 
Using char is OK, though: 
! 
int32_t 
hairpoll_add_option( 
hairpoll_t hairpoll, 
const char* name, 
const char* image_url 
);
Enumerations 
typedef enum motu_alignment { 
heroic_warrior = 0, 
evil_warrior = 1, 
}; 
! 
int32_t motu_count( 
int32_t alignment 
);
Error Handling 
void hairpoll_vote( 
hairpoll_t hairpoll, 
int32_t option, 
error_t* out_error 
);
Error Handling 
typedef struct error* error_t; 
! 
const char* error_message( 
error_t error 
); 
! 
void error_destruct(error_t error); 
! 
! 
void hairpoll_vote(hairpoll_t hairpoll, int32_t option, error_t* out_error);
Errors → Exceptions 
struct Error { 
Error() : opaque(nullptr) {} 
~Error() { if (opaque) { error_destruct(opaque); } } 
error_t opaque; 
}; 
! 
class ThrowOnError { 
public: 
~ThrowOnError() noexcept(false) { 
if (_error.opaque) { 
throw std::runtime_error(error_message(_error.opaque)); 
} 
} 
! 
operator error_t*() { return &_error.opaque; } 
! 
private: 
Error _error; 
};
Errors → Exceptions 
void hairpoll_vote(hairpoll_t hairpoll, int32_t option, error_t* out_error); 
! 
void vote(int option) { 
return hairpoll_vote( 
_opaque, 
option, 
ThrowOnError{} 
); 
}
Exceptions → Errors 
template<typename Fn> 
bool translateExceptions(error_t* out_error, Fn&& fn) 
{ 
try { 
fn(); 
} catch (const std::exception& e) { 
*out_error = new error{e.what()}; 
return false; 
} catch (...) { 
*out_error = new error{"Unknown internal error"}; 
return false; 
} 
return true; 
}
Exceptions → Errors 
void hairpoll_vote(const hairpoll_t poll, 
int32_t option, error_t* out_error) 
{ 
translateExceptions(out_error, [&]{ 
if (option < 0 || 
option >= poll->actual.options.size()) { 
throw std::runtime_error("Bad optn index"); 
} 
! 
poll->actual.options[option].votes++; 
}); 
}
Callbacks 
typedef void (*hairpoll_result_handler_t)( 
void* client_data, 
const char* name, 
int32_t votes, 
const char* html 
); 
! 
void hairpoll_tally(const hairpoll_t hairpoll, 
hairpoll_result_handler_t handler, 
void* client_data, error_t* out_error);
Using lambdas as callbacks 
std::vector<Result> results() const { 
std::vector<Result> ret; 
! 
auto addResult = [&ret](const char* name, int32_t votes, 
const char* html){ 
ret.push_back(Result{name, votes, html}); 
}; 
! 
auto callback = [](void* client_data, const char* name, int32_t votes, 
const char* html){ 
auto fn = static_cast<decltype(&addResult)>(client_data); 
(*fn)(name, votes, html); 
}; 
! 
hairpoll_tally(_opaque, callback, &addResult, ThrowOnError{}); 
! 
return ret; 
}
Symbol visibility 
#if defined(_WIN32) || defined(__CYGWIN__) 
#ifdef hairpoll_EXPORTS 
#ifdef __GNUC__ 
#define HAIRPOLL_EXPORT __attribute__ ((dllexport)) 
#else 
#define HAIRPOLL_EXPORT __declspec(dllexport) 
#endif 
#else 
#ifdef __GNUC__ 
#define HAIRPOLL_EXPORT __attribute__ ((dllimport)) 
#else 
#define HAIRPOLL_EXPORT __declspec(dllimport) 
#endif 
#endif 
#else 
#if __GNUC__ >= 4 
#define HAIRPOLL_EXPORT __attribute__ ((visibility ("default"))) 
#else 
#define HAIRPOLL_EXPORT 
#endif 
#endif
Symbol visibility 
#include "visibility.h" 
! 
… 
! 
HAIRPOLL_EXPORT 
hairpoll_t hairpoll_construct(const char* person); 
! 
HAIRPOLL_EXPORT 
void hairpoll_destruct(hairpoll_t poll); 
! 
…
Symbol visibility 
On Clang and GCC, add to your compile: 
! 
-fvisibility=hidden 
! 
(applies to library only)
Remember to extern “C”! 
#ifdef __cplusplus 
extern "C" { 
#endif 
! 
// C API goes here 
! 
#ifdef __cplusplus 
} // extern "C" 
#endif
Lifetime and Ownership 
• Keep it simple: construct (if needed) and destruct 
• Always use RAII on the client side! 
• Can use refcounting (e.g. shared_ptr) both 
internally to the library and in the client 
• For callbacks, you can use the stack
Interfacing with those 
“other” languages
Foreign Function Interfaces 
• “something that allows calling code written in one 
language from another language” 
• C = de-facto standard 
• Languages with support for calling C functions in 
shared libraries include: 
• Common Lisp, Java, JavaScript, Matlab, .NET 
(C#, F#, etc.), Python, Ruby, OCaml, basically everything…
Hair Polls in Python 
hairpoll = lib.hairpoll_construct("Stefanus Du Toit", None) 
! 
skeletor = lib.hairpoll_add_option(hairpoll, "Skeletor", 
"<long URL omitted>", None) 
beast = lib.hairpoll_add_option(hairpoll, "Beast Man", 
"<long URL omitted>", None) 
! 
lib.hairpoll_vote(hairpoll, skeletor, None) 
lib.hairpoll_vote(hairpoll, beast, None) 
lib.hairpoll_vote(hairpoll, beast, None) 
! 
def print_result(client_data, name, votes, html): 
print name, votes 
! 
lib.hairpoll_tally(hairpoll, hairpoll_result_handler(print_result), 
None, None) 
! 
lib.hairpoll_destruct(hairpoll)
Hair Polls In Python 
from ctypes import * 
! 
lib = CDLL("libhairpoll.dylib") 
lib.hairpoll_construct.restype = c_void_p 
lib.hairpoll_construct.argtypes = [c_char_p, c_void_p] 
! 
lib.hairpoll_destruct.restype = None 
lib.hairpoll_destruct.argtypes = [c_void_p] 
! 
lib.hairpoll_add_option.restype = c_int 
lib.hairpoll_add_option.argtypes = [c_void_p, c_char_p, c_char_p, c_void_p] 
! 
lib.hairpoll_vote.restype = None 
lib.hairpoll_vote.argtypes = [c_void_p, c_int, c_void_p] 
! 
hairpoll_result_handler = CFUNCTYPE(None, c_void_p, c_char_p, c_int, c_char_p) 
lib.hairpoll_tally.restype = None 
lib.hairpoll_tally.argtypes = [c_void_p, hairpoll_result_handler, c_void_p, 
c_void_p]
Summary 
• Hourglass = C++ on top of C89 on top of C++ 
• Avoids ABI issues, sneaky dependencies, etc. 
• Hides object layout and other implementation 
details 
• Makes FFI bindings easy
Hourglass Interfaces for C++ APIs - CppCon 2014
Q&A 
http://blog.sduto.it/ @stefanusdutoit

More Related Content

PPTX
Python basics
PDF
DM2020 boolean algebra
PPTX
LLVM Instruction Selection
PPTX
Functions in c
PDF
OpenFOAMスレッド並列化のための基礎検討
PPTX
Regular Expressions
PDF
Introduction to python
PPTX
Tutorial: Develop an App with the Odoo Framework
Python basics
DM2020 boolean algebra
LLVM Instruction Selection
Functions in c
OpenFOAMスレッド並列化のための基礎検討
Regular Expressions
Introduction to python
Tutorial: Develop an App with the Odoo Framework

What's hot (20)

PDF
Android Virtualization: Opportunity and Organization
PDF
Intro to Python for Non-Programmers
PDF
マルチレイヤコンパイラ基盤による、エッジ向けディープラーニングの実装と最適化について
PDF
Haskell
PDF
Python Intro
PPTX
Classes and objects1
PDF
6. R data structures
PDF
Swift Tutorial Part 1. The Complete Guide For Swift Programming Language
PDF
Senai dispositivos de protecao
PPTX
Introduction to Python programming
PPTX
inline function
PDF
OpenFOAM -回転領域を含む流体計算 (Rotating Geometry)-
PDF
Introduction to OpenCL, 2010
PPTX
Function C programming
PDF
System Device Tree and Lopper: Concrete Examples - ELC NA 2022
PPTX
C function
PDF
What is Python JSON | Edureka
PPT
Structure in C
PPT
Exception Handling
PDF
Estrutura de Dados - Alocação dinâmica de memória
Android Virtualization: Opportunity and Organization
Intro to Python for Non-Programmers
マルチレイヤコンパイラ基盤による、エッジ向けディープラーニングの実装と最適化について
Haskell
Python Intro
Classes and objects1
6. R data structures
Swift Tutorial Part 1. The Complete Guide For Swift Programming Language
Senai dispositivos de protecao
Introduction to Python programming
inline function
OpenFOAM -回転領域を含む流体計算 (Rotating Geometry)-
Introduction to OpenCL, 2010
Function C programming
System Device Tree and Lopper: Concrete Examples - ELC NA 2022
C function
What is Python JSON | Edureka
Structure in C
Exception Handling
Estrutura de Dados - Alocação dinâmica de memória
Ad

Viewers also liked (9)

PPTX
Connecting C++ and JavaScript on the Web with Embind
PDF
Refactoring
PDF
Software Development Practices Patterns
PDF
Introduction to Mob Programming
PPTX
Programação simultânea em pares
PPT
Nonvital pulp therapy in pediatric dentistry
PPT
Cleaning and shaping the root canal system
PDF
Railway Oriented Programming
PDF
How To Design A Good A P I And Why It Matters G O O G L E
Connecting C++ and JavaScript on the Web with Embind
Refactoring
Software Development Practices Patterns
Introduction to Mob Programming
Programação simultânea em pares
Nonvital pulp therapy in pediatric dentistry
Cleaning and shaping the root canal system
Railway Oriented Programming
How To Design A Good A P I And Why It Matters G O O G L E
Ad

Similar to Hourglass Interfaces for C++ APIs - CppCon 2014 (20)

PPT
What's New in C++ 11?
PDF
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
PPTX
Whats New in Visual Studio 2012 for C++ Developers
PDF
An Overview Of Standard C++Tr1
PDF
Meetup C++ A brief overview of c++17
PDF
Modern C++
PPTX
Return of c++
PPTX
The Style of C++ 11
PPTX
C++ idioms.pptx
PPTX
Modern C++ Lunch and Learn
PDF
The Present and The Future of Functional Programming in C++
PDF
L10
PDF
C++primer
PDF
Effective Object Oriented Design in Cpp
PPTX
PDF
Cat's anatomy
PPTX
How to Adopt Modern C++17 into Your C++ Code
PPTX
How to Adopt Modern C++17 into Your C++ Code
PPTX
C++11: Feel the New Language
PDF
How to make a large C++-code base manageable
What's New in C++ 11?
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
Whats New in Visual Studio 2012 for C++ Developers
An Overview Of Standard C++Tr1
Meetup C++ A brief overview of c++17
Modern C++
Return of c++
The Style of C++ 11
C++ idioms.pptx
Modern C++ Lunch and Learn
The Present and The Future of Functional Programming in C++
L10
C++primer
Effective Object Oriented Design in Cpp
Cat's anatomy
How to Adopt Modern C++17 into Your C++ Code
How to Adopt Modern C++17 into Your C++ Code
C++11: Feel the New Language
How to make a large C++-code base manageable

Recently uploaded (20)

PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PPTX
L1 - Introduction to python Backend.pptx
PDF
System and Network Administration Chapter 2
PPTX
Introduction to Artificial Intelligence
PPTX
CHAPTER 2 - PM Management and IT Context
PPTX
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PPTX
Transform Your Business with a Software ERP System
PDF
Nekopoi APK 2025 free lastest update
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PPTX
Essential Infomation Tech presentation.pptx
PDF
Understanding Forklifts - TECH EHS Solution
PDF
Adobe Illustrator 28.6 Crack My Vision of Vector Design
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PPTX
ai tools demonstartion for schools and inter college
PDF
Softaken Excel to vCard Converter Software.pdf
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PDF
medical staffing services at VALiNTRY
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
L1 - Introduction to python Backend.pptx
System and Network Administration Chapter 2
Introduction to Artificial Intelligence
CHAPTER 2 - PM Management and IT Context
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
Which alternative to Crystal Reports is best for small or large businesses.pdf
Transform Your Business with a Software ERP System
Nekopoi APK 2025 free lastest update
Upgrade and Innovation Strategies for SAP ERP Customers
Essential Infomation Tech presentation.pptx
Understanding Forklifts - TECH EHS Solution
Adobe Illustrator 28.6 Crack My Vision of Vector Design
Design an Analysis of Algorithms II-SECS-1021-03
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
ai tools demonstartion for schools and inter college
Softaken Excel to vCard Converter Software.pdf
How to Migrate SBCGlobal Email to Yahoo Easily
medical staffing services at VALiNTRY

Hourglass Interfaces for C++ APIs - CppCon 2014

  • 1. Hourglass Interfaces for C++ APIs Stefanus Du Toit Thalmic Labs @stefanusdutoit Image © Erik Fitzpatrick, CC BY 2.0
  • 4. Shared Libraries Interface Code Data Library
  • 5. Shared Libraries Interface Code Data Client! Program Library Code Data
  • 6. Shared Libraries Interface Code Data Client! Program Library Code Data ABI! ! Common libraries
  • 7. Different ABIs? Subtle problems… Class A Class B
  • 8. Different ABIs? Subtle problems… Class A Class B Debug Build Release Build
  • 9. My Goal for Libraries Get out of the client’s way.
  • 10. My Goal for Libraries Don’t make my clients: • build my code if they don’t want to • change how they build their code • rebuild their code because I shipped a fix in mine • learn a new language if they don’t want to
  • 13. Why does this help? • Avoids ABI-related binary compatibility issues • Enforces no use of non-trivial C++ types in the binary interface (e.g. std::string) • Keeps internal layout of data types a secret • Makes binding to other languages much easier ! • Still get all the convenience of C++ at both ends
  • 14. Example: libhairpoll • A library for creating hair-related polls, taking votes, and tallying the results
  • 15. hairpoll.h typedef struct hairpoll* hairpoll_t; ! hairpoll_t hairpoll_construct(const char* person); void hairpoll_destruct(hairpoll_t poll); ! int32_t hairpoll_add_option(hairpoll_t hairpoll, const char* name, const char* image_url); ! void hairpoll_vote(hairpoll_t hairpoll, int32_t option); ! typedef void (*hairpoll_result_handler_t)(void* client_data, const char* name, int32_t votes, const char* html); ! void hairpoll_tally(const hairpoll_t hairpoll, hairpoll_result_handler_t handler, void* client_data);
  • 16. HairPoll class - client-facing class HairPoll { public: HairPoll(std::string person); ~HairPoll(); ! int addOption(std::string name, std::string imageUrl); void vote(int option); ! struct Result { std::string name; int votes; std::string html; }; std::vector<Result> results() const; ! private: hairpoll_t _opaque; };
  • 18. Parts of C to use in the thin API • C89 + const and // comments • Functions, but no variadic functions • C primitive types (char, void, etc.) • Pointers • forward-declared structs • enumerations • Function pointers are OK, too
  • 19. Opaque Types typedef struct hairpoll* hairpoll_t; ! void hairpoll_vote( hairpoll_t hairpoll, int32_t option );
  • 20. Opaque Types extern "C" struct hairpoll { Poll actual; };
  • 21. Opaque Types extern "C" struct hairpoll { template<typename... Args> hairpoll(Args&&... args) : actual(std::forward<Args>(args)...) { } ! Poll actual; };
  • 22. Opaque Types class Poll { public: Poll(std::string person); ! struct option { option(std::string name, std::string url); ! std::string name; std::string url; int votes; }; ! std::string person; std::vector<option> options; };
  • 23. Opaque Types hairpoll_t hairpoll_construct(const char* person) { return new hairpoll(person); } ! void hairpoll_destruct(hairpoll_t poll) { delete poll; }
  • 24. Integral types Prefer stdint.h types (int32_t, int64_t, etc.) over plain C integer types (short, int, long): ! void hairpoll_vote( hairpoll_t hairpoll, int32_t option );
  • 25. Integral types Using char is OK, though: ! int32_t hairpoll_add_option( hairpoll_t hairpoll, const char* name, const char* image_url );
  • 26. Enumerations typedef enum motu_alignment { heroic_warrior = 0, evil_warrior = 1, }; ! int32_t motu_count( int32_t alignment );
  • 27. Error Handling void hairpoll_vote( hairpoll_t hairpoll, int32_t option, error_t* out_error );
  • 28. Error Handling typedef struct error* error_t; ! const char* error_message( error_t error ); ! void error_destruct(error_t error); ! ! void hairpoll_vote(hairpoll_t hairpoll, int32_t option, error_t* out_error);
  • 29. Errors → Exceptions struct Error { Error() : opaque(nullptr) {} ~Error() { if (opaque) { error_destruct(opaque); } } error_t opaque; }; ! class ThrowOnError { public: ~ThrowOnError() noexcept(false) { if (_error.opaque) { throw std::runtime_error(error_message(_error.opaque)); } } ! operator error_t*() { return &_error.opaque; } ! private: Error _error; };
  • 30. Errors → Exceptions void hairpoll_vote(hairpoll_t hairpoll, int32_t option, error_t* out_error); ! void vote(int option) { return hairpoll_vote( _opaque, option, ThrowOnError{} ); }
  • 31. Exceptions → Errors template<typename Fn> bool translateExceptions(error_t* out_error, Fn&& fn) { try { fn(); } catch (const std::exception& e) { *out_error = new error{e.what()}; return false; } catch (...) { *out_error = new error{"Unknown internal error"}; return false; } return true; }
  • 32. Exceptions → Errors void hairpoll_vote(const hairpoll_t poll, int32_t option, error_t* out_error) { translateExceptions(out_error, [&]{ if (option < 0 || option >= poll->actual.options.size()) { throw std::runtime_error("Bad optn index"); } ! poll->actual.options[option].votes++; }); }
  • 33. Callbacks typedef void (*hairpoll_result_handler_t)( void* client_data, const char* name, int32_t votes, const char* html ); ! void hairpoll_tally(const hairpoll_t hairpoll, hairpoll_result_handler_t handler, void* client_data, error_t* out_error);
  • 34. Using lambdas as callbacks std::vector<Result> results() const { std::vector<Result> ret; ! auto addResult = [&ret](const char* name, int32_t votes, const char* html){ ret.push_back(Result{name, votes, html}); }; ! auto callback = [](void* client_data, const char* name, int32_t votes, const char* html){ auto fn = static_cast<decltype(&addResult)>(client_data); (*fn)(name, votes, html); }; ! hairpoll_tally(_opaque, callback, &addResult, ThrowOnError{}); ! return ret; }
  • 35. Symbol visibility #if defined(_WIN32) || defined(__CYGWIN__) #ifdef hairpoll_EXPORTS #ifdef __GNUC__ #define HAIRPOLL_EXPORT __attribute__ ((dllexport)) #else #define HAIRPOLL_EXPORT __declspec(dllexport) #endif #else #ifdef __GNUC__ #define HAIRPOLL_EXPORT __attribute__ ((dllimport)) #else #define HAIRPOLL_EXPORT __declspec(dllimport) #endif #endif #else #if __GNUC__ >= 4 #define HAIRPOLL_EXPORT __attribute__ ((visibility ("default"))) #else #define HAIRPOLL_EXPORT #endif #endif
  • 36. Symbol visibility #include "visibility.h" ! … ! HAIRPOLL_EXPORT hairpoll_t hairpoll_construct(const char* person); ! HAIRPOLL_EXPORT void hairpoll_destruct(hairpoll_t poll); ! …
  • 37. Symbol visibility On Clang and GCC, add to your compile: ! -fvisibility=hidden ! (applies to library only)
  • 38. Remember to extern “C”! #ifdef __cplusplus extern "C" { #endif ! // C API goes here ! #ifdef __cplusplus } // extern "C" #endif
  • 39. Lifetime and Ownership • Keep it simple: construct (if needed) and destruct • Always use RAII on the client side! • Can use refcounting (e.g. shared_ptr) both internally to the library and in the client • For callbacks, you can use the stack
  • 40. Interfacing with those “other” languages
  • 41. Foreign Function Interfaces • “something that allows calling code written in one language from another language” • C = de-facto standard • Languages with support for calling C functions in shared libraries include: • Common Lisp, Java, JavaScript, Matlab, .NET (C#, F#, etc.), Python, Ruby, OCaml, basically everything…
  • 42. Hair Polls in Python hairpoll = lib.hairpoll_construct("Stefanus Du Toit", None) ! skeletor = lib.hairpoll_add_option(hairpoll, "Skeletor", "<long URL omitted>", None) beast = lib.hairpoll_add_option(hairpoll, "Beast Man", "<long URL omitted>", None) ! lib.hairpoll_vote(hairpoll, skeletor, None) lib.hairpoll_vote(hairpoll, beast, None) lib.hairpoll_vote(hairpoll, beast, None) ! def print_result(client_data, name, votes, html): print name, votes ! lib.hairpoll_tally(hairpoll, hairpoll_result_handler(print_result), None, None) ! lib.hairpoll_destruct(hairpoll)
  • 43. Hair Polls In Python from ctypes import * ! lib = CDLL("libhairpoll.dylib") lib.hairpoll_construct.restype = c_void_p lib.hairpoll_construct.argtypes = [c_char_p, c_void_p] ! lib.hairpoll_destruct.restype = None lib.hairpoll_destruct.argtypes = [c_void_p] ! lib.hairpoll_add_option.restype = c_int lib.hairpoll_add_option.argtypes = [c_void_p, c_char_p, c_char_p, c_void_p] ! lib.hairpoll_vote.restype = None lib.hairpoll_vote.argtypes = [c_void_p, c_int, c_void_p] ! hairpoll_result_handler = CFUNCTYPE(None, c_void_p, c_char_p, c_int, c_char_p) lib.hairpoll_tally.restype = None lib.hairpoll_tally.argtypes = [c_void_p, hairpoll_result_handler, c_void_p, c_void_p]
  • 44. Summary • Hourglass = C++ on top of C89 on top of C++ • Avoids ABI issues, sneaky dependencies, etc. • Hides object layout and other implementation details • Makes FFI bindings easy