Application Program Interface
The set of functions and types that a library provides
A collection of header files
#include
An archive of object files
a single object file, that allows calling of predefined set of functions
__declspec(dllimport)
__declspec(dllexport)
// compile with flags
-fvisibility=hidden -fvisibility-inlines-hidden
__attribute__ ((visibility ("default")))
dllimport
\ dllexport
__declspec(dllexport) int answer = 42;
__declspec(dllexport) int get_answer() {
return 42;
}
dllimport
\ dllexport
class __declspec(dllexport) Renderer {
public:
void render(const Texture& texture);
};
class Texture {
public:
__declspec(dllexport) void fill(Color color);
void fill(byte r, byte g, byte b); // not exported
};
dllexport
Makes symbols to be exported from the DLL - visible to clients
dllimport
Makes symbols to be imported from a DLL, the linker is going to look for these symbols in all linked DLLs
dllimport
\ dllexport
So the library needs to say dllexport
and the client needs to
see dllimport
for the same symbol
MY_LIBRARY_API
#if defined(MY_LIBRARY_IMPL)
#define MY_LIBRARY_API __declspec(dllexport)
#else
#define MY_LIBRARY_API __declspec(dllimport)
#endif
MY_LIBRARY_API int answer();
Compile the library with MY_LIBRARY_IMPL
defined
MY_LIBRARY_API
#if defined(_WIN32)
#define MY_LIBRARY_EXPORT __declspec(dllexport)
#define MY_LIBRARY_IMPORT __declspec(dllimport)
#else
#define MY_LIBRARY_EXPORT __attribute__ ((visibility ("default")))
#define MY_LIBRARY_IMPORT
#endif
#if defined(MY_LIBRARY_IMPL)
#define MY_LIBRARY_API MY_LIBRARY_EXPORT
#else
#define MY_LIBRARY_API MY_LIBRARY_IMPORT
#endif
Controlling visibility of symbols - lack of internal linkage
VERSION
{
global:
extern "C++" {
library*;
};
local: *;
};
Link with:-Wl,--version-script=library.map
Symbol resolution is done at load time, not at link time
# link with
g++ *.o -Xlinker -Bsymbolic -o myLibrary.so
C
C++
with std::
C
APIPros
C
has no manglingCons
C++
features - resource management, OOP, generics // just a forward declaration
typedef struct lua_State lua_State;
lua_State* lua_newstate();
void lua_call(lua_State* state, int arguments, int results);
void lua_close(lua_State*);
C++
with C
APItypedef struct lua_State lua_State;
extern "C" lua_State* lua_newstate();
extern "C" {
int lua_compile(lua_State* state, const char* file);
int lua_run(lua_State* state, int);
}
struct lua_State {
bool compile(const char* file);
} ;
lua_State* lua_newstate() {
return new lua_State;
}
int lua_compile(lua_State* state, const char* file) {
return state->compile(file)? 1 : 0;
}
std::
in the APIstd::
The standard doesn't define implementation details for the standard library. So implementations may differ. For example:
// GCC
class pseudo_vector {
T* begin;
T* end;
T* end_of_storage;
};
// MSVS
class pseudo_vector {
T* begin;
T* end_of_storage;
T* end;
};
namespace library {
void add_random(std::vector<int>& numbers) {
numbers.push_back(rand());
}
}
Implementation may be different when using different compiler options
Visual Studio has debug iterators enabled in Debug build. They
allow detection of incorrect usage of STL
. For example, using an
iterator to a vector, after it has been invalidated.
In Release a vector::iterator
can be a plain pointer, but a
debug iterator is actually a smart pointer
Allocated memory must be freed from the allocator that allocated it.
STL
hides allocations from the user, so it is impossible to be sure
that the memory will be deallocated from the allocator that allocated
it.
C
with classes / COMextern "C"
function that initializes the library and returns
an object that implements the library interfaceC
with classes style - declarationnamespace Lua {
class State {
virtual void ~State() = 0;
virtual void destroy() = 0;
virtual bool compile(const char* file) = 0;
};
}
extern Lua::State* lua_new_state();
C
with classes style - implementationnamespace Lua {
class StateImpl: public State {
virtual void ~StateImpl() {
}
virtual void destroy() override {
delete this;
}
virtual bool compile(const char* file) override {
/...
}
};
}
C
with classes style - implementationLua::State* lua_newstate() {
return new StateImpl;
}
namespace Lua {
void StateImpl::destroy() override {
delete this;
}
}
Enforces that the StateImpl
object is deallocated using the
allocator that allocated it
C
with classes style - clientauto lua = lua_new_state();
lua->compile("hello.lua");
lua->destroy();
C
with classes style - resourcesstruct LuaDestroyer {
void operator(Lua::State* lua) {
lua->destroy();
}
};
std::unique_ptr<Lua::State, LuaDestroyer> lua(lua_new_state());
lua->compile("hello.lua");
An abstract class is just a virtual table - it matches the COM model, and all compilers implement it in the same way.
[HowTo: Export C++ classes from a DLL] (http://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLL)
Pointer-to-Implementation is a technique for reducing coupling between a class (a library) and its clients
Almost every project is divided in sub-projects according to some principles. For example:
pImpl can be used to implement the interfaces of the internal libraries in a project