由於要使用到log4cpp的庫,而log4c的資料是非常的少,也懶得去研究它的用法,於是就決定試試混合編程者玩意。
首先先引用下C++它的father: Stroustrup的一篇文章《C++ Style and Technique FAQ》(http://www2.research.att.com/~bs/bs_faq2.html)裡的一小個片段:
Just declare the C function ``extern "C"'' (in your C++ code) and call it (from your C or C++ code). For example:
// C++ codeextern "C" void f(int);// one wayextern "C" {// another wayint g(double);double h();};void code(int i, double d){f(i);int ii = g(d);double dd = h();// ...}
The definitions of the functions may look like this:
/* C code: */void f(int i){/* ... */}int g(double d){/* ... */}double h(){/* ... */}
Note that C++ type rules, not C rules, are used. So you can't call function declared ``extern "C"'' with the wrong number of argument. For example:
// C++ codevoid more_code(int i, double d){double dd = h(i,d);// error: unexpected arguments// ...}
Just declare the C++ function ``extern "C"'' (in your C++ code) and call it (from your C or C++ code). For example:
// C++ code:extern "C" void f(int);void f(int i){// ...}
Now f() can be used like this:
/* C code: */void f(int);void cc(int i){f(i);/* ... */}
Naturally, this works only for non-member functions. If you want to call member functions (incl. virtual functions) from C, you need to provide a simple wrapper. For example:
// C++ code:class C {// ...virtual double f(int);};extern "C" double call_C_f(C* p, int i)// wrapper function{return p->f(i);}
Now C::f() can be used like this:
/* C code: */double call_C_f(struct C* p, int i);void ccc(struct C* p, int i){double d = call_C_f(p,i);/* ... */}
If you want to call overloaded functions from C, you must provide wrappers with distinct names for the C code to use. For example:
// C++ code:void f(int);void f(double);extern "C" void f_i(int i) { f(i); }extern "C" void f_d(double d) { f(d); }
Now the f() functions can be used like this:
/* C code: */void f_i(int);void f_d(double);void cccc(int i,double d){f_i(i);f_d(d);/* ... */}
Note that these techniques can be used to call a C++ library from C code even if you cannot (or do not want to) modify the C++ headers.
由於咱是用到c調用c++,暫不關心c++調用c的部分,如上可知,要調用c++類的成員函數,那可是麻煩的麻煩。於是還是乖乖寫個函數封裝一下類。
由於log4cpp的調用日誌比較麻煩,不像log4j,每次都要初始化一大堆東西,於是自己就把這些東西封裝成了一個類為Log4cppBase:
Here is code:
Log4cppBase.h
#ifndef LOG4CPPBASE_H<br />#define LOG4CPPBASE_H<br />#include <iostream><br />#include "log4cpp/Category.hh"<br />#include "log4cpp/PropertyConfigurator.hh"<br />#include <stdarg.h><br />/*<br />*author: Lan Zhihong from xmu soft<br />*/<br />class Log4cppBase<br />{<br />protected:<br />Log4cppBase()<br />{<br />try{<br />log4cpp::PropertyConfigurator::configure("log4cpp/log4cpp.conf");<br />}catch(log4cpp::ConfigureFailure& f)<br />{<br />std::cout << "Configure Problem" << f.what() << std::endl;<br />}<br />iRoot = &log4cpp::Category::getRoot();<br />iSub = &log4cpp::Category::getInstance(std::string("sub1"));</p><p>}<br />private:<br />Log4cppBase& operator=(Log4cppBase&);<br />Log4cppBase(const Log4cppBase&);</p><p>public:<br />~Log4cppBase();<br />static Log4cppBase* getInstance();<br />static std::string vform(const char* format, va_list args);<br />void info(const std::string& msg);<br />void debug(const std::string& msg);<br />void notice(const std::string& msg);<br />void warn(const std::string& msg);<br />void error(const std::string& msg);<br />void crit(const std::string& msg);<br />void alert(const std::string& msg);<br />void emerg(const std::string& msg);<br />void fatal(const std::string& msg);<br />private:<br />static Log4cppBase *iInstance;<br />log4cpp::Category *iSub;<br />log4cpp::Category *iRoot;<br />};<br />#endif
Log4cppBase.cpp
#include "Log4cppBase.h"<br />#include <sstream><br />#include <stdio.h><br />#define VSNPRINTF vsnprintf</p><p>Log4cppBase* Log4cppBase::iInstance = 0;<br />Log4cppBase::~Log4cppBase()<br />{<br />if( iSub != NULL )<br />{<br />delete iSub;<br />iSub = NULL;<br />}<br />if( iRoot != NULL)<br />{<br />delete iRoot;<br />iRoot = NULL;<br />}<br />if( iInstance != NULL)<br />{<br />delete iInstance;<br />iInstance = NULL;<br />}<br />}<br />Log4cppBase* Log4cppBase::getInstance()<br />{<br />if( iInstance == 0)<br />iInstance = new Log4cppBase();<br />return iInstance;<br />}<br />std::string Log4cppBase::vform(const char* format, va_list args)<br />{<br />size_t size = 1024;<br />char* buffer = new char[size];</p><p>while (1) {<br /> int n = VSNPRINTF(buffer, size, format, args);</p><p> // If that worked, return a string.<br /> if ((n > -1) && (static_cast<size_t>(n) < size)) {<br />std::string s(buffer);<br />delete [] buffer;<br />return s;<br /> }</p><p> // Else try again with more space.<br /> size = (n > -1) ?<br /> n + 1 : // ISO/IEC 9899:1999<br /> size * 2; // twice the old size</p><p> delete [] buffer;<br /> buffer = new char[size];<br />}<br />}<br />void Log4cppBase::info(const std::string& msg)<br />{<br />iSub->info(msg);<br />/*<br />va_list va;<br />va_start(va, msg);<br />iSub->info(vform(msg, va));<br />va_end(va);<br />*/<br />}<br />void Log4cppBase::debug(const std::string& msg)<br />{<br />iSub->info(msg);<br />}<br />void Log4cppBase::notice(const std::string& msg)<br />{<br />iSub->notice(msg);<br />}<br />void Log4cppBase::warn(const std::string& msg)<br />{<br />iSub->warn(msg);<br />}<br />void Log4cppBase::error(const std::string& msg)<br />{<br />iSub->error(msg);<br />}<br />void Log4cppBase::crit(const std::string& msg)<br />{<br />iSub->crit(msg);<br />}<br />void Log4cppBase::alert(const std::string& msg)<br />{<br />iSub->alert(msg);<br />}<br />void Log4cppBase::emerg(const std::string& msg)<br />{<br />iSub->emerg(msg);<br />}<br />void Log4cppBase::fatal(const std::string& msg)<br />{<br />iSub->fatal(msg);<br />}<br />/*<br />int main(int argc, char** argv)<br />{<br />Log4cppBase* instance = Log4cppBase::getInstance();<br />int i = 5;<br />instance->info("hello world");<br />return 0;<br />}<br />*/
由於選擇了調用c++的非成員函數,於是由添加了這樣的一個類Log4cppUtil
Here is code:
Log4cppUtil.h
#ifdef _cplusplus<br />extern "C"<br />{<br />#endif<br />void log4cpp_info(const char *msg, ...);<br />#ifdef _cplusplus<br />}<br />#endif<br />#ifdef _cplusplus<br />extern "C"<br />{<br />#endif<br />void log4cpp_debug(const char *msg, ...);<br />#ifdef _cplusplus<br />}<br />#endif<br />#ifdef _cplusplus<br />extern "C"<br />{<br />#endif<br />void log4cpp_notice(const char *msg, ...);<br />#ifdef _cplusplus<br />}<br />#endif<br />#ifdef _cplusplus<br />extern "C"<br />{<br />#endif<br />void log4cpp_warn(const char *msg, ...);<br />#ifdef _cplusplus<br />}<br />#endif<br />#ifdef _cplusplus<br />extern "C"<br />{<br />#endif<br />void log4cpp_error(const char *msg, ...);<br />#ifdef _cplusplus<br />}<br />#endif<br />#ifdef _cplusplus<br />extern "C"<br />{<br />#endif<br />void log4cpp_crit(const char *msg, ...);<br />#ifdef _cplusplus<br />}<br />#endif<br />#ifdef _cplusplus<br />extern "C"<br />{<br />#endif<br />void log4cpp_alert(const char *msg, ...);<br />#ifdef _cplusplus<br />}<br />#endif<br />#ifdef _cplusplus<br />extern "C"<br />{<br />#endif<br />void log4cpp_emerg(const char *msg, ...);<br />#ifdef _cplusplus<br />}<br />#endif<br />#ifdef _cplusplus<br />extern "C"<br />{<br />#endif<br />void log4cpp_fatal(const char *msg, ...);<br />#ifdef _cplusplus<br />}<br />#endif<br />
Log4cppUtil.cpp
#ifndef _cplusplus<br />#define _cplusplus<br />#endif<br />#include "Log4cppBase.h"<br />#include "Log4cppUtil.h"</p><p>void log4cpp_info(const char* msg, ...)<br />{<br />Log4cppBase * instance = Log4cppBase::getInstance();<br />va_list va;<br />va_start(va, msg);<br />instance->info(instance->vform(msg,va));<br />va_end(va);<br />}<br />void log4cpp_debug(const char* msg, ...)<br />{<br />Log4cppBase * instance = Log4cppBase::getInstance();<br />va_list va;<br />va_start(va, msg);<br />instance->debug(instance->vform(msg,va));<br />va_end(va);<br />}<br />void log4cpp_notice(const char* msg, ...)<br />{<br />Log4cppBase * instance = Log4cppBase::getInstance();<br />va_list va;<br />va_start(va, msg);<br />instance->notice(instance->vform(msg,va));<br />va_end(va);<br />}<br />void log4cpp_warn(const char* msg, ...)<br />{<br />Log4cppBase * instance = Log4cppBase::getInstance();<br />va_list va;<br />va_start(va, msg);<br />instance->warn(instance->vform(msg,va));<br />va_end(va);<br />}<br />void log4cpp_error(const char* msg, ...)<br />{<br />Log4cppBase * instance = Log4cppBase::getInstance();<br />va_list va;<br />va_start(va, msg);<br />instance->error(instance->vform(msg,va));<br />va_end(va);<br />}<br />void log4cpp_crit(const char* msg, ...)<br />{<br />Log4cppBase * instance = Log4cppBase::getInstance();<br />va_list va;<br />va_start(va, msg);<br />instance->crit(instance->vform(msg,va));<br />va_end(va);<br />}<br />void log4cpp_alert(const char* msg, ...)<br />{<br />Log4cppBase * instance = Log4cppBase::getInstance();<br />va_list va;<br />va_start(va, msg);<br />instance->alert(instance->vform(msg,va));<br />va_end(va);<br />}<br />void log4cpp_emerg(const char* msg, ...)<br />{<br />Log4cppBase * instance = Log4cppBase::getInstance();<br />va_list va;<br />va_start(va, msg);<br />instance->emerg(instance->vform(msg,va));<br />va_end(va);<br />}<br />void log4cpp_fatal(const char* msg, ...)<br />{<br />Log4cppBase * instance = Log4cppBase::getInstance();<br />va_list va;<br />va_start(va, msg);<br />instance->fatal(instance->vform(msg,va));<br />va_end(va);<br />}
然後再在自己的C代碼中調用這個Log4cppUtil,我用的測試代碼test.c如下:
#include <stdio.h><br />#include "Log4cppUtil.h"<br />extern void log4cpp_info(const char *msg, ...);<br />extern void log4cpp_debug(const char *msg, ...);<br />extern void log4cpp_notice(const char *msg, ...);<br />extern void log4cpp_warn(const char *msg, ...);<br />extern void log4cpp_error(const char *msg, ...);<br />extern void log4cpp_crit(const char *msg, ...);<br />extern void log4cpp_alert(const char *msg, ...);<br />extern void log4cpp_emerg(const char *msg, ...);<br />extern void log4cpp_fatal(const char *msg, ...);</p><p>int main()<br />{<br />int i = 3;<br />log4cpp_info("hello: %d", i);<br />log4cpp_debug("hello: %d", i);<br />log4cpp_notice("hello: %d", i);<br />log4cpp_warn("hello: %d", i);<br />log4cpp_error("hello: %d", i);<br />log4cpp_crit("hello: %d", i);<br />log4cpp_alert("hello: %d", i);<br />log4cpp_emerg("hello: %d", i);<br />log4cpp_fatal("hello: %d", i);<br />return 0;<br />}
在C代碼中要用extern告訴編譯器,這個函數在其他檔案
在Linux命令列編譯如下:
1、編譯Log4cppBase,由於我在本機上已經安裝Log4cpp的庫到了/use/lib下,所以可以不用置頂庫的路徑,直接按下面代碼編譯
g++ -fpic -llog4cpp -shared -g -o liblog4cppbase.so Log4cppBase.cpp
2、編譯Log4cppUtil,由於Log4cppUtil需要用到Log4cppBase,因此需要置頂庫的搜尋路徑為當前路徑./
g++ -fpic -shared -g -o liblog4cpputil.so Log4cppUtil.cpp -I ./
3、編譯自己寫的test.c,產生可執行檔,在此需要把上面編譯的兩個庫檔案全部加進去,編譯成可執行檔
gcc -o test test.c ./liblog4cpputil.so ./liblog4cppbase.so
編譯成功!晚上賞自己個雞腿吃!
以上是在PC機子上的編譯
交叉編譯進板子的話按上面那個方法是行不通的,因為系統找不到Log4cpp的庫或者其他庫等,可以參考前面我轉載的一篇文章《【開發工具面】GCC命令列詳解》,而我是把log4cpp交叉編譯到/use/local下面去,而我自己的/usr下面也有一個PC版本的log4cpp,因此要注意調用哪一個命令,因此使用絕對路徑/usr/local/bin/log4cpp-config
重新修改命令,如下:
arm-linux-g++ -fpic -shared `/usr/local/bin/log4cpp-config --libs --cflags` -o liblog4cppbase.so Log4cppBase.cpp
arm-linux-g++ -fpic -shared `/usr/local/bin/log4cpp-config --libs --cflags` -o liblog4cpputil.so Log4cppUtil.cpp -I./
arm-linux-gcc `/usr/local/bin/log4cpp-config --libs --cflags` -o test test.c log4cpp/liblog4cppbase.so log4cpp/liblog4cpputil.so
編譯成功,移植到開發板上去,成功跑起來!