[DEV] basic simple log lib

This commit is contained in:
Edouard DUPIN 2016-03-08 21:29:34 +01:00
parent 818ede7c21
commit 31bdec208d
7 changed files with 823 additions and 0 deletions

15
elog/debug.cpp Normal file
View File

@ -0,0 +1,15 @@
/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license APACHE v2.0 (see license file)
*/
#include <elog/debug.h>
int32_t elog::getLogId() {
static int32_t g_val = elog::registerInstance("elog");
return g_val;
}

45
elog/debug.h Normal file
View File

@ -0,0 +1,45 @@
/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license APACHE v2.0 (see license file)
*/
#pragma once
#include <elog/log.h>
#include <assert.h>
namespace elog {
int32_t getLogId();
};
#define ELOG_BASIC(info,data) ELOG_BASE(elog::getLogId(),info,data)
#define ELOG_PRINT(data) ELOG_BASIC(-1, data)
#define ELOG_CRITICAL(data) ELOG_BASIC(1, data)
#define ELOG_ERROR(data) ELOG_BASIC(2, data)
#define ELOG_WARNING(data) ELOG_BASIC(3, data)
#ifdef DEBUG
#define ELOG_INFO(data) ELOG_BASIC(4, data)
#define ELOG_DEBUG(data) ELOG_BASIC(5, data)
#define ELOG_VERBOSE(data) ELOG_BASIC(6, data)
#define ELOG_TODO(data) ELOG_BASIC(4, "TODO : " << data)
#else
#define ELOG_INFO(data) do { } while(false)
#define ELOG_DEBUG(data) do { } while(false)
#define ELOG_VERBOSE(data) do { } while(false)
#define ELOG_TODO(data) do { } while(false)
#endif
#define ELOG_HIDDEN(data) do { } while(false)
#define ELOG_ASSERT(cond,data) \
do { \
if (!(cond)) { \
ELOG_CRITICAL(data); \
assert(!#cond); \
} \
} while (0)

523
elog/log.cpp Normal file
View File

@ -0,0 +1,523 @@
/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license APACHE v2.0 (see license file)
*/
#include <elog/log.h>
#include <elog/debug.h>
#include <time.h>
#include <mutex>
#include <thread>
#include <map>
#include <inttypes.h>
#ifdef ELOG_BUILD_ETHREAD
#include <ethread/tools.h>
#endif
#include <elog/debug.h>
#include <string.h>
#include <iostream>
#if defined(__TARGET_OS__Android)
# include <android/log.h>
#endif
#include <elog/logIOs.h>
#if !defined(__STDCPP_LLVM__) && defined(__TARGET_OS__Linux) && defined(DEBUG)
#include <execinfo.h>
#include <cxxabi.h>
#include <dlfcn.h>
#define MAX_DEPTH (256)
void elog::displayBacktrace(bool _breakAtEnd, int32_t _removeElement) {
// retrieve call-stack
void * trace[MAX_DEPTH];
int stack_depth = backtrace(trace, MAX_DEPTH);
ELOG_ERROR("Back-trace : ");
for (int32_t i = 1; i < stack_depth; i++) {
Dl_info dlinfo;
if(!dladdr(trace[i], &dlinfo)) {
break;
}
const char * symname = dlinfo.dli_sname;
int status;
char * demangled = abi::__cxa_demangle(symname, nullptr, 0, &status);
if(status == 0 && demangled) {
symname = demangled;
}
if (_removeElement <= 0) {
ELOG_WARNING(" " << dlinfo.dli_fname << ": ");
ELOG_ERROR(" " << symname);
}
_removeElement--;
if(demangled != nullptr) {
free(demangled);
}
}
if (_breakAtEnd == true) {
assert(false);
}
}
#else
void elog::displayBacktrace(bool _breakAtEnd, int32_t _removeElement) {
#ifdef DEBUG
assert(false);
#endif
}
#endif
#ifdef DEBUG
#define DEFAULT_LOG_LEVEL elog::logLevelInfo
#define DEFAULT_LOG_COLOR true
#define DEFAULT_LOG_LINE true
#define DEFAULT_LOG_THREAD_ID true
#define DEFAULT_LOG_THREAD_NAME true
#define DEFAULT_LOG_CLASS true
#define DEFAULT_LOG_TIME true
#define DEFAULT_LOG_LIB_NAME true
#else
#define DEFAULT_LOG_LEVEL elog::logLevelNone
#define DEFAULT_LOG_COLOR false
#define DEFAULT_LOG_LINE false
#define DEFAULT_LOG_THREAD_ID false
#define DEFAULT_LOG_THREAD_NAME false
#define DEFAULT_LOG_CLASS false
#define DEFAULT_LOG_TIME true
#define DEFAULT_LOG_LIB_NAME true
#endif
enum elog::level& getDefaultLevel() {
static enum elog::level g_val = DEFAULT_LOG_LEVEL;
return g_val;
}
size_t& getFunctionSizeLog() {
static size_t g_val = 5;
return g_val;
}
size_t& getThreadSizeLog() {
static size_t g_val = 5;
return g_val;
}
size_t& getNameSizeLog() {
static size_t g_val = 5;
return g_val;
}
static std::vector<std::pair<std::string, enum elog::level> >& getList() {
static std::vector<std::pair<std::string, enum elog::level> > g_val;
return g_val;
}
int32_t elog::registerInstance(const std::string& _name) {
for (size_t iii = 0; iii < getList().size(); ++iii) {
if (getList()[iii].first == _name) {
return iii;
}
}
getList().push_back(std::make_pair(_name, getDefaultLevel()));
if (_name.size() >= getNameSizeLog()) {
getNameSizeLog() = _name.size()+1;
}
//std::cout << "register log : '" << _name << "'=" << getList().size()-1 << std::endl;
return getList().size()-1;
}
void elog::setLevel(const std::string& _name, enum level _level) {
for (size_t iii = 0; iii < getList().size(); ++iii) {
if (getList()[iii].first == _name) {
getList()[iii].second = _level;
return;
}
}
getList().push_back(std::make_pair(_name, _level));
}
void elog::setLevel(enum level _level) {
getDefaultLevel() = _level;
for (size_t iii = 0; iii < getList().size(); ++iii) {
getList()[iii].second = _level;
}
}
void elog::setLevel(int32_t _id, enum level _level) {
if (_id < 0 || _id > (int32_t)getList().size()) {
// ERROR...
return;
}
getList()[_id].second = _level;
}
int32_t elog::getLevel(int32_t _id) {
if (_id < 0 || _id > (int32_t)getList().size()) {
// ERROR...
return 0;
}
return (int32_t)getList()[_id].second;
}
std::vector<std::string> elog::getListInstance() {
std::vector<std::string> out;
for (size_t iii = 0; iii < getList().size(); ++iii) {
out.push_back(getList()[iii].first);
}
return out;
}
void elog::logStream(int32_t _id, int32_t _level, int32_t _ligne, const char* _className, const char* _funcName, const std::ostream& _log) {
std::ostringstream oss;
oss << _log.rdbuf();
std::string sss =oss.str();
elog::logChar(_id, _level, _ligne, _className, _funcName, sss.c_str());
}
void elog::logChar1(int32_t _id, int32_t _level, const char* _log) {
elog::logChar(_id, _level, -1, nullptr, nullptr, _log);
}
void elog::logStream1(int32_t _id, int32_t _level, const std::ostream& _log) {
std::ostringstream oss;
oss << _log.rdbuf();
std::string sss =oss.str();
elog::logChar(_id, _level, -1, nullptr, nullptr, sss.c_str());
}
static bool& getColor() {
static bool g_val = DEFAULT_LOG_COLOR;
return g_val;
}
void elog::setColor(bool _status) {
getColor() = _status;
}
static bool& getTime() {
static bool g_val = DEFAULT_LOG_TIME;
return g_val;
}
void elog::setTime(bool _status) {
getTime() = _status;
}
static bool& getLine() {
static bool g_val = DEFAULT_LOG_LINE;
return g_val;
}
void elog::setLine(bool _status) {
getLine() = _status;
}
static bool& getThreadId() {
static bool g_val = DEFAULT_LOG_THREAD_ID;
return g_val;
}
void elog::setThreadId(bool _status) {
getThreadId() = _status;
}
static bool& getThreadNameEnable() {
static bool g_val = DEFAULT_LOG_THREAD_NAME;
return g_val;
}
void elog::setThreadNameEnable(bool _status) {
getThreadNameEnable() = _status;
}
static bool& getFunction() {
static bool g_val = DEFAULT_LOG_CLASS;
return g_val;
}
void elog::setFunction(bool _status) {
getFunction() = _status;
}
static bool& getLibName() {
static bool g_val = DEFAULT_LOG_LIB_NAME;
return g_val;
}
void elog::setLibName(bool _status) {
getLibName() = _status;
}
static void getDisplayTime(char* data) {
#ifdef __TARGET_OS__Android
struct timeval now;
gettimeofday(&now, nullptr);
sprintf(data, " %2dh%2d'%2d ", (int32_t)(now.tv_sec/3600)%24, (int32_t)(now.tv_sec/60)%60, (int32_t)(now.tv_sec%60));
#else
time_t rawtime;
struct tm * timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
sprintf(data, " %2dh%2d'%2d ", (timeinfo->tm_hour)%24, timeinfo->tm_min, timeinfo->tm_sec);
#endif
}
//regular colors
#define ETK_BASH_COLOR_BLACK "\e[0;30m"
#define ETK_BASH_COLOR_RED "\e[0;31m"
#define ETK_BASH_COLOR_GREEN "\e[0;32m"
#define ETK_BASH_COLOR_YELLOW "\e[0;33m"
#define ETK_BASH_COLOR_BLUE "\e[0;34m"
#define ETK_BASH_COLOR_MAGENTA "\e[0;35m"
#define ETK_BASH_COLOR_CYAN "\e[0;36m"
#define ETK_BASH_COLOR_WHITE "\e[0;37m"
//emphasized (bolded) colors
#define ETK_BASH_COLOR_BOLD_BLACK "\e[1;30m"
#define ETK_BASH_COLOR_BOLD_RED "\e[1;31m"
#define ETK_BASH_COLOR_BOLD_GREEN "\e[1;32m"
#define ETK_BASH_COLOR_BOLD_YELLOW "\e[1;33m"
#define ETK_BASH_COLOR_BOLD_BLUE "\e[1;34m"
#define ETK_BASH_COLOR_BOLD_MAGENTA "\e[1;35m"
#define ETK_BASH_COLOR_BOLD_CYAN "\e[1;36m"
#define ETK_BASH_COLOR_BOLD_WHITE "\e[1;37m"
//background colors
#define ETK_BASH_COLOR_BG_BLACK "\e[40m"
#define ETK_BASH_COLOR_BG_RED "\e[41m"
#define ETK_BASH_COLOR_BG_GREEN "\e[42m"
#define ETK_BASH_COLOR_BG_YELLOW "\e[43m"
#define ETK_BASH_COLOR_BG_BLUE "\e[44m"
#define ETK_BASH_COLOR_BG_MAGENTA "\e[45m"
#define ETK_BASH_COLOR_BG_CYAN "\e[46m"
#define ETK_BASH_COLOR_BG_WHITE "\e[47m"
// Return to the normal color setings
#define ETK_BASH_COLOR_NORMAL "\e[0m"
//go to the Top of bash
#define ETK_BASH_GO_TOP "\e[0;0f"
#define LENGHT_MAX_LOG (2048)
void elog::logChar(int32_t _id, int32_t _level, int32_t _ligne, const char* _className, const char* _funcName, const char* _log) {
static std::mutex g_lock;
char handle[LENGHT_MAX_LOG] = "";
memset(handle, ' ', LENGHT_MAX_LOG);
handle[0] = '\0';
char* pointer = handle;
if(getColor() == true) {
switch(_level) {
default:
// nothing to do ...
break;
case logLevelCritical:
strcat(pointer, ETK_BASH_COLOR_BOLD_RED);
break;
case logLevelError:
strcat(pointer, ETK_BASH_COLOR_RED);
break;
case logLevelWarning:
strcat(pointer, ETK_BASH_COLOR_MAGENTA);
break;
case logLevelInfo:
strcat(pointer, ETK_BASH_COLOR_CYAN);
break;
case logLevelDebug:
strcat(pointer, ETK_BASH_COLOR_YELLOW);
break;
case logLevelVerbose:
strcat(pointer, ETK_BASH_COLOR_WHITE);
break;
case logLevelPrint:
strcat(pointer, ETK_BASH_COLOR_WHITE);
break;
}
pointer = handle+strlen(handle);
}
if(getTime() == true) {
getDisplayTime(pointer);
pointer = handle+strlen(handle);
}
#ifndef __TARGET_OS__Android
switch(_level) {
default:
strcat(pointer, "[?] ");
break;
case logLevelPrint:
strcat(pointer, "[P] ");
break;
case logLevelCritical:
strcat(pointer, "[C] ");
break;
case logLevelError:
strcat(pointer, "[E] ");
break;
case logLevelWarning:
strcat(pointer, "[W] ");
break;
case logLevelInfo:
strcat(pointer, "[I] ");
break;
case logLevelDebug:
strcat(pointer, "[D] ");
break;
case logLevelVerbose:
strcat(pointer, "[V] ");
break;
}
pointer = handle+strlen(handle);
#endif
if (getLibName() == true) {
if (_id >= 0) {
int32_t len = strlen(handle);
strcat(pointer, getList()[_id].first.c_str());
pointer = handle+strlen(handle);
while (strlen(handle) - len < getNameSizeLog()) {
*pointer++ = ' ';
*pointer = '\0';
}
*pointer++ = '|';
*pointer++ = ' ';
*pointer = '\0';
}
}
#ifdef ELOG_BUILD_ETHREAD
if(getThreadId() == true) {
// display thread ID
uint32_t iddd = ethread::getId();
sprintf(pointer, "%3d", iddd);
pointer = handle+strlen(handle);
*pointer++ = ' ';
*pointer++ = '|';
*pointer++ = ' ';
*pointer = '\0';
}
if(getThreadNameEnable() == true) {
// display thread ID
std::string name = ethread::getName();
if (name.size() >= getThreadSizeLog() ) {
getThreadSizeLog() = name.size() + 1;
}
sprintf(pointer, "%s", name.c_str());
pointer = handle+strlen(handle);
size_t nbSpaceToAdd = getThreadSizeLog()-name.size();
for (size_t iii=0; iii<nbSpaceToAdd; ++iii) {
*pointer++ = ' ';
*pointer = '\0';
}
*pointer++ = '|';
*pointer++ = ' ';
*pointer = '\0';
}
#endif
if(getLine() == true) {
if (_ligne >= 0) {
sprintf(pointer, "(l=%5d)", _ligne);
pointer = handle+strlen(handle);
*pointer++ = ' ';
*pointer = '\0';
}
}
// TODO :Maybe optimize this one ...
if(getFunction() == true) {
int32_t len = strlen(handle);
char tmpName[1024];
char *tmpPointer = tmpName;
#ifndef __TARGET_OS__Android
if (_className != nullptr) {
snprintf(tmpPointer, 1024, "%s::", _className);
tmpPointer = tmpPointer+strlen(tmpPointer);
}
#endif
if (_funcName != nullptr) {
#if defined(__TARGET_OS__Android)
// cleen for android :
char* startPos = strchr(_funcName, ' ');
char* stopPos = strchr(_funcName, '(');
if (startPos != nullptr) {
if (stopPos != nullptr) {
if(stopPos < startPos) {
snprintf(tmpPointer, std::min(1024, int32_t(stopPos-_funcName)), "%s", _funcName);
} else {
snprintf(tmpPointer, std::min(1024, int32_t(stopPos-startPos)), "%s", startPos+1);
}
} else {
snprintf(tmpPointer, 1024, "%s", startPos);
}
} else {
if (stopPos != nullptr) {
snprintf(tmpPointer, std::min(1024, int32_t(stopPos-_funcName)), "%s", _funcName);
} else {
snprintf(tmpPointer, 1024, "%s", _funcName);
}
}
#else
snprintf(tmpPointer, 1024, "%s", _funcName);
#endif
tmpPointer = tmpPointer+strlen(tmpPointer);
}
size_t lenFunc = strlen(tmpName);
if (lenFunc >= getFunctionSizeLog()) {
getFunctionSizeLog() = lenFunc+1;
}
size_t nbSpaceToAdd = getFunctionSizeLog() - lenFunc;
for (size_t iii=0; iii<nbSpaceToAdd; ++iii) {
*tmpPointer++ = ' ';
*tmpPointer = '\0';
}
*tmpPointer++ = '|';
*tmpPointer++ = ' ';
*tmpPointer = '\0';
strcat(pointer, tmpName);
pointer += strlen(tmpName);
}
if (strlen(_log) > LENGHT_MAX_LOG - strlen(handle)-20) {
memcpy(pointer, _log, LENGHT_MAX_LOG - strlen(handle)-21);
handle[1024-25] = ' ';
handle[1024-24] = '.';
handle[1024-23] = '.';
handle[1024-22] = '.';
handle[1024-21] = '\0';
} else {
strcat(pointer, _log);
}
pointer = handle+strlen(handle);
if(getColor() == true) {
strcat(pointer, ETK_BASH_COLOR_NORMAL);
}
g_lock.lock();
#if defined(__TARGET_OS__Android)
// TODO : Set package name instead of ewol ...
switch(_level) {
default:
__android_log_print(ANDROID_LOG_VERBOSE, "EWOL", "%s", handle);
break;
case logLevelPrint:
__android_log_print(ANDROID_LOG_INFO, "EWOL", "%s", handle);
break;
case logLevelCritical:
__android_log_print(ANDROID_LOG_FATAL, "EWOL", "%s", handle);
break;
case logLevelError:
__android_log_print(ANDROID_LOG_ERROR, "EWOL", "%s", handle);
break;
case logLevelWarning:
__android_log_print(ANDROID_LOG_WARN, "EWOL", "%s", handle);
break;
case logLevelInfo:
__android_log_print(ANDROID_LOG_INFO, "EWOL", "%s", handle);
break;
case logLevelDebug:
__android_log_print(ANDROID_LOG_DEBUG, "EWOL", "%s", handle);
break;
case logLevelVerbose:
__android_log_print(ANDROID_LOG_VERBOSE, "EWOL", "%s", handle);
break;
}
#elif defined(__TARGET_OS__IOs)
iosNSLog(handle);
#else
std::cout << handle << std::endl;
#endif
g_lock.unlock();
if (_level == logLevelCritical) {
std::this_thread::sleep_for(std::chrono::milliseconds(700));
displayBacktrace(true, 2);
}
}

130
elog/log.h Normal file
View File

@ -0,0 +1,130 @@
/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license APACHE v2.0 (see license file)
*/
#pragma once
#include <sstream>
#include <ostream>
#include <vector>
namespace elog {
/**
* @brief Log level is a simple list of all log availlable. This enum is used when setting a log and when user chose the level of log displayed.
*/
enum level {
logLevelPrint = -1, //!< basic print for Help or result (never filtered)
logLevelNone = 0, //!< no display requested
logLevelCritical = 1, //!< Display only critical logs (note that critical generally assert with a backtrace (when we can))
logLevelError = 2, //!< Display Error and critical logs
logLevelWarning = 3, //!< Display log critical to warning
logLevelInfo = 4, //!< Display log critical to information (removed in release mode)
logLevelDebug = 5, //!< Display log critical to debug (removed in release mode)
logLevelVerbose = 6 //!< Display all logs (removed in release and debug mode)
};
/**
* @brief Register an element in the log system
* @param[in] _name Name of the module
* @return reference Id of an instance name
*/
int32_t registerInstance(const std::string& _name);
/**
* @brief Set the log level of a specific instance
* @param[in] _name Name of the intance
* @param[in] _id Id of the intance
* @param[in] _level New level to set on the instance
*/
void setLevel(const std::string& _name, enum level _level);
//! @previous
void setLevel(int32_t _id, enum level _level);
/**
* @brief Set global debug level
* @param[in] _level New level to set on the instance
*/
void setLevel(enum level _level);
/**
* @brief Get the current level of debug for a specific intance
* @param[in] _id Id Of the intance
* @return the enum casted in an integer ==> generise the API (not dependent of etk)
*/
int32_t getLevel(int32_t _id);
/**
* @brief Get list of all intance
* @return the name list of all intance
*/
std::vector<std::string> getListInstance();
/**
* @brief Set Color enable or disable.
* @param[in] _status New value of color.
*/
void setColor(bool _status);
/**
* @brief Set Time display enable or disable.
* @param[in] _status New value.
*/
void setTime(bool _status);
/**
* @brief Set Line display enable or disable.
* @param[in] _status New value.
*/
void setLine(bool _status);
/**
* @brief Set Function display enable or disable.
* @param[in] _status New value.
*/
void setFunction(bool _status);
/**
* @brief Set thread id enable or disable.
* @param[in] _status New value.
*/
void setThreadId(bool _status);
/**
* @brief Set thread name enable or disable.
* @param[in] _status New value.
*/
void setThreadNameEnable(bool _status);
/**
* @brief Set library display enable or disable.
* @param[in] _status New value.
*/
void setLibName(bool _status);
/**
* @brief Call log to display
* @param[in] _id Id of the instance type
* @param[in] _level Level debug
* @param[in] _ligne Line of the debug
* @param[in] _className Class name of the debug
* @param[in] _funcName Function name for debug
* @param[in] _log Stream to log
*/
void logChar(int32_t _id, int32_t _level, int32_t _ligne, const char* _className, const char* _funcName, const char* _log);
//! @previous
void logStream(int32_t _id, int32_t _level, int32_t _ligne, const char* _className, const char* _funcName, const std::ostream& _log);
//! @previous
void logChar1(int32_t _id, int32_t _level, const char* _log);
//! @previous
void logStream1(int32_t _id, int32_t _level, const std::ostream& _log);
/**
* @brief Display the current backtrace
* @param[in] _breakAtEnd assert program when backtrace is printed
*/
void displayBacktrace(bool _breakAtEnd = false, int32_t _removeElement=0);
};
#ifdef __class__
#undef __class__
#endif
#define __class__ (nullptr)
// generic define for all logs::
#define ELOG_BASE(logId,info,data) \
do { \
if (info <= elog::getLevel(logId)) { \
std::stringbuf sb; \
std::ostream tmpStream(&sb); \
tmpStream << data; \
elog::logStream(logId, info, __LINE__, __class__, __func__, tmpStream); \
} \
} while(0)

20
elog/logIOs.h Normal file
View File

@ -0,0 +1,20 @@
/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license APACHE v2.0 (see license file)
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __TARGET_OS__IOs
void iosNSLog(const char * _value);
#endif
#ifdef __cplusplus
}
#endif

17
elog/logIOs.m Normal file
View File

@ -0,0 +1,17 @@
/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license APACHE v2.0 (see license file)
*/
#import <UIKit/UIKit.h>
#include <elog/logIOs.h>
void iosNSLog(const char * _value) {
NSLog(@"\r%s", _value);
}

73
lutin_elog.py Normal file
View File

@ -0,0 +1,73 @@
#!/usr/bin/python
import lutin.module as module
import lutin.tools as tools
def get_type():
return "LIBRARY"
def get_desc():
return "Ewol log basic interface"
def get_licence():
return "APACHE-2"
def get_compagny_type():
return "com"
def get_compagny_name():
return "atria-soft"
def get_maintainer():
return ["Mr DUPIN Edouard <yui.heero@gmail.com>"]
def get_version():
return [0,1,"dev"]
def create(target, module_name):
my_module = module.Module(__file__, module_name, get_type())
my_module.add_extra_compile_flags()
# add the file to compile:
my_module.add_src_file([
'elog/debug.cpp',
'elog/log.cpp'
])
if target.name=="IOs":
my_module.add_src_file('etk/logIOs.m')
my_module.add_header_file([
'elog/log.h',
])
if target.config["mode"] == "debug":
# Bor backtrace display :
if target.name != "Windows" \
and target.name != "MacOs" \
and target.name != "IOs":
# TODO : check if it is really needed ...
my_module.add_export_flag('link', [
'-ldl',
'-rdynamic'])
elif target.name != "Windows":
my_module.add_export_flag('link', [
'-ldl'])
# build in C++ mode
my_module.compile_version("c++", 2011)
# add dependency of the generic C++ library:
my_module.add_module_depend('cxx')
my_module.add_optionnal_module_depend('ethread', ["c++", "-DELOG_BUILD_ETHREAD"])
if target.name=="Windows":
pass
elif target.name=="Android":
my_module.add_module_depend("SDK")
pass
else:
#TODO : Set it in a generic include system
my_module.add_export_flag('link-lib', "pthread")
my_module.add_path(tools.get_current_path(__file__))
return my_module