Posted on 16-06-2013
Filed Under (Technology) by bigbang

It seems that Boost Log is a good choice for cross platform logging. However, boost log is not part of Boost, at least not in the regular Boost branch. If you want to use this in you code, just follow the steps.

  1. Download Boost Log separately from here.
  2. Download Boost above version 1.51. I am using Boost version 1.53.0.
  3. Unzip the Boost source file, and unzip Boost Log file into the specific folder.
  4. Then compile the Boost file by Boost instruction. After the compilation, the Boost Log library will be under folder /boost_1_53_0/stage/lib or the installation folder you prefixed.

Then you can use the static Boost Log library in your code. Here is the example code:

#include <boost/log/trivial.hpp>

int main(int, char*[])
{
    BOOST_LOG_TRIVIAL(trace) << "A trace severity message";
    BOOST_LOG_TRIVIAL(debug) << "A debug severity message";
    BOOST_LOG_TRIVIAL(info) << "An informational severity message";
    BOOST_LOG_TRIVIAL(warning) << "A warning severity message";
    BOOST_LOG_TRIVIAL(error) << "An error severity message";
    BOOST_LOG_TRIVIAL(fatal) << "A fatal severity message";

    return 0;
}
(0) Comments    (8) Views    Read More   
Posted on 05-06-2013
Filed Under (Technology) by bigbang

We know how to generate Win32 Services Installer with Native Win32 C++ Code, but if we want to do it in Python, how?

We can use Python to generate Win32 services by using py2exe and Python Win32 Extensions.

Here we show the basic steps.

1. Use py2exe to Compile Python Script into EXE

For example, if you want to compile hello.py into exe file, just use following command:

python hello.py py2exe

2. create a Windows service script and compile it to Win32 Service

This step is the same as step 1, just need to add Windows Service Wrapper code in Python script.

Copy the code and put into files, and use step1 command to compile the file.

After the compilation, you will get a service_launcher.exe under folder ./dist and you can install the service from there.

  1. You can use it to install the service on the win32 services list, just run your program with the “-install” parameter and you are done!
  2. Use “-remove” to remove the win32 services. Need to stop the Service before removing the Win32 service.

3. Questions & Answers

  1. While compiling, Why get following error?
            raise ImportError, "No module named " + qname
    ImportError: No module named win32com
    

    We need to install Python Win32 Extensions to compile it.

  2. When you start the service in Windows Control Panel, the service failed. How to check the error and debug?

    please check Windows event log error for details.

  3. Error: can’t load dll

    If your script depends on more third party dlls, you also need to copy the dlls into ./dist folder.

    Or you can add your dll path into System Path. NOTE: The thing you need to do with dll, is to add the path to system path, not just for current user.

(0) Comments    (38) Views    Read More   

By default, the Ubuntu Server installer will set your server to use DHCP. You may want to change it to a static IP address, or else you may need to update people the server IP address when you reboot your system.

We can set static IP address & DNS nameserver in file /etc/network/interfaces. Open the file with root priority:

sudo vim /etc/network/interfaces

For the primary interface, which is usually eth0, you will see these lines:

auto eth0
iface eth0 inet dhcp

As you can see, it’s using DHCP right now. We are going to change DHCP to static, and then there are a number of options that should be added below it. Obviously you’d customize this to your network.

auto eth0
iface eth0 inet static
        address 192.168.1.100
        netmask 255.255.255.0
        network 192.168.1.0
        broadcast 192.168.1.255
        gateway 192.168.1.1
        dns-nameservers 192.168.1.0

You also need to change eth0 parameters to eth1 or something else according to your server’s basic config.

Please pay attention to the last line of DNS nameserver settings. I think it is the best way to set the DNS settings.

If you add your DNS settings by editting resolv.conf file, it can just work well on current time. When you reboot your system, you will lose it!

Now we’ll just need to restart the networking components:

sudo /etc/init.d/networking restart

You can ping a web URL (for example, www.google.com) to check your settings. If you get the ping back info, name resolution is working.

(0) Comments    (58) Views    Read More   
Posted on 13-03-2013
Filed Under (Technology) by bigbang

If you want to invoke C/C++ third-party library ( third-party libraries are your libraries at the most time ), you just need a script to attach them. At this time, we can use Python ctypes to do this dirty job.

The theme Calling C/C++ from python on StackOverflow has introduced the basic usage of ctypes. The key points are:

  1. If you try to use C library, just load this library and use it.
  2. If you try to use C++ library, you should use keyword extern to wrapper C++ class into functions for C. That means we should put C++ class into C functions, and use keyword extern for statement.

In above two ways, if you get the way to use ctypes to invoke C++ library, then you also get the way to use ctypes to invoke C library. Let’s talk about how to invoke C++ library in details.

For example, there is a C++ class Foo:

#include <iostream>

class Foo{
    public:
        void bar(){
            std::cout << "Hello" << std::endl;
        }
};

Then we wrapper out following C style interfaces:

extern "C" {
    Foo* Foo_new(){ return new Foo(); }
    void Foo_bar(Foo* foo){ foo->bar(); }
}

We compile the code into library:

g++ -c -fPIC foo.cpp -o foo.o
g++ -shared -Wl,-soname,libfoo.so -o libfoo.so  foo.o

, then we can use Python to invoke this class. You can put the interfaces into a Python class or use them directly:

from ctypes import cdll
lib = cdll.LoadLibrary('./libfoo.so')

class Foo(object):
    def __init__(self):
        self.obj = lib.Foo_new()

    def bar(self):
        lib.Foo_bar(self.obj)

Everything is OK now. We can invoke this Python class like this:

f = Foo()
f.bar() #and you will see "Hello" on the screen

Under Windows, the process is the same if you try to use Python ctypes, but just need to pay attention to following two points:

  1. When start to link to C/C++ library, it is the best idea to use absolute path to load library.

    When I run above code under Windows, I got following error:

    $ python Linkcpp.py
    Traceback (most recent call last):
      File "Linkcpp.py", line 2, in <module>
        lib = cdll.LoadLibrary('./LinkExample')
      File "C:\Python27\lib\ctypes\__init__.py", line 431, in LoadLibrary
        return self._dlltype(name)
      File "C:\Python27\lib\ctypes\__init__.py", line 353, in __init__
        self._handle = _dlopen(self._name, mode)
    WindowsError: [Error 126]
    

    The reason is that I use following code to load library:

    from ctypes import cdll
    lib = cdll.LoadLibrary('./LinkExample')
    

    We can eliminate this error by changing ./LinkExample into E:/PythonCode/LinkCpp/LinkExample which is library’s absolute path under Windows. We can also use LinkExample if the library is under the same folder as the Python script.

    So, to save the debugging time, it is the best way to do it by using absolute path to load library.

    If you get WindowsError: [Error 126] message, the reason is nothing but two

    • Your DLL is not being located.
    • Your DLL depends on other DLLs that cannot be found.

    PS: The dynamic libraries under Windows has two lib & dll files. In this case, we can just use the name of the library.

  2. If the library is written by C++, then we should use extern to wrapper it.

    In the function stated by extern, we can also use the keyword belongs to C++ which is not in C. For example, we can describe our function like this:

    extern int linkExample(const int index, const char* name);
    

    Python ctypes can run it!

    The method of keyword extern in C++ is complicated. Here we just need to state a function to invoke by C, so we can use keyword const in it.

(0) Comments    (162) Views    Read More   
Posted on 13-03-2013
Filed Under (Technology) by bigbang

The extern keyword in C & C++ is a little complex, by studying from Using extern to Specify Linkage, save it for notes.

The extern keyword declares a variable or function and specifies that it has external linkage (its name is visible from files other than the one in which it’s defined). When modifying a variable, extern specifies that the variable has static duration (it is allocated when the program begins and deallocated when the program ends). The variable or function may be defined in another source file, or later in the same file. Declarations of variables and functions at file scope are external by default.

// specifying_linkage1.cpp
int i = 1;
void other();

int main() {
   // Reference to i, defined above:
   extern int i;
}

void other() {
   // Address of global i assigned to pointer variable:
   static int *external_i = &i;

   // i will be redefined; global i no longer visible:
   // int i = 16;
}

In C++, when used with a string, extern specifies that the linkage conventions of another language are being used for the declarator(s). C functions and data can be accessed only if they are previously declared as having C linkage. However, they must be defined in a separately compiled translation unit.

Microsoft C++ supports the strings “C” and “C++” in the string-literal field. All of the standard include files use the extern “C” syntax to allow the run-time library functions to be used in C++ programs.

The following example shows alternative ways to declare names that have C linkage:

// specifying_linkage2.cpp
// compile with: /c
// Declare printf with C linkage.
extern "C" int printf( const char *fmt, ... );

//  Cause everything in the specified header files
//   to have C linkage.
extern "C" {
   // add your #include statements here
   #include <stdio.h>
}

//  Declare the two functions ShowChar and GetChar
//   with C linkage.
extern "C" {
   char ShowChar( char ch );
   char GetChar( void );
}

//  Define the two functions ShowChar and GetChar
//   with C linkage.
extern "C" char ShowChar( char ch ) {
   putchar( ch );
   return ch;
}

extern "C" char GetChar( void ) {
   char ch;

   ch = getchar();
   return ch;
}

// Declare a global variable, errno, with C linkage.
extern "C" int errno;
(0) Comments    (270) Views    Read More   
Posted on 07-03-2013
Filed Under (Technology) by bigbang

Using FFmpeg under Windows, especially using Visual C++, is not very well supported or documented. Today I tried this and mark this down for reference.

1. Download pre-compiled builds or compile from source

The first thing is to download the latest “Shared” and “Dev” builds from Zeranoe FFmpeg builds.

At the time of this writing, the “Dev” builds contain the headers and libs, but not the dlls, so use the “bin” folder of the “Shared” zip.

Note it’s possible to compile FFmpeg (which contains libavcodec) on Windows with MinGW & MSYS, but not with Visual Studio. If you are interesting about compiling FFmpeg on Windows, please check this post.

2. Using libavcodec in Visual Studio

Now configure your project to use the libs, headers and dlls. For the includes, you need to add:

[ffmpeg_directory]\include

Add the corresponding libs under linker options as usual.

[Your_ffmpeg_directory]\lib

3. add missing inttypes.h & stdint.h header file

Even just using libavcodec’s headers requires inttypes.h & stdint.h, and Visual Studio 9/10 doesn’t have it. Download this version and put in your FFmpeg include folder.

[ffmpeg_directory]\include

The most important thing is to add __STDC_CONSTANT_MACROS to Preprocessor, or add following code directly in source file:

#define __STDC_CONSTANT_MACROS

4. Test Code

Since libavcodec is a C library, we have to enclose the #includes in an extern C block. If following code works OK, then you can write more complicated application.

extern "C" {
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libswscale/swscale.h>
}

int main( int argc, char* argv[] ) {
    av_register_all();
    return 0;
}

If you want to try more examples, there are a few examples under folder:

[ffmpeg_directory]\doc\examples

It is not complex but just steps!

(0) Comments    (147) Views    Read More   
Posted on 07-03-2013
Filed Under (Technology) by bigbang

1. Get FFmpeg Source Code

It’s recommended to download the release source package of FFmpeg from the official site.

2. Compiling FFmpeg

FFmpeg is developed under Linux, but it can be compiled under most Operating Systems.

For Windows, FFmpeg can be compiled with MSYS and MinGW. If you have setup MSYS and MinGW systems correctly, you can compile FFmpeg under its folder.

MinGW MSYS’s work folder is under the installation path (You can also reconfigure MSYS parameters), on my computer is

C:\MinGW\msys\1.0

Just extract the FFmpeg source code to the home folder under MSYS root path.

First, Cleanup former build results.

make distclean

Second, Setup build parameters.

./configure --enable-shared --disable-yasm --enable-memalign-hack

If there is no error, and config.mak & config.h were generated, you can build the library, and then, if you want, you can install them into the MSYS environment.

make
make install

The compile operation will take a long time.

After installation, you can find the libs and dlls under local folder in MSYS folder, which is

C:\MinGW\msys\1.0\local

on my computer. In MSYS, you can jump into the installation folder by following path:

/usr/local/include
/usr/local/lib

This is the same as on Linux machine.

3. Write FFmpeg test code

There are some example code under /doc/examples, we can use them for test.

(0) Comments    (506) Views    Read More   
Posted on 25-01-2013
Filed Under (Technology) by bigbang

I use Putty to edit code romotely today. Because for some reason I can’t download or upload the files by WinSCP or something else, I can only do the coding using Emacs under Putty. It is really a bad experience using Emacs under Putty, and I don’t know why Emacs M-v keybinding doesn’t work under Putty. It is also really bad that I can’t use my own Emacs config file. I think there should be the same situation under secureCTR. It seems using Emacs Tramp is the best choice.

1. Install Putty

There is nothing to discuss about Putty installation, just do it.

2. Add Putty Installation Path to Windows System PATH

Make sure you add Putty installation path to Windows system PATH:

C:\Program Files\PuTTY

By doing it, we can let Emacs file plink.exe file.

3. Add Tramp code in Emacs Config File

Just put following elisp code into .emacs file:

(require 'tramp)
(setq tramp-auto-save-directory "c:\\tmp")
(setq tramp-default-method "plink")

4. Use Tramp to Edit Remote File

Now, we can use M-x find-file or C-x C-f to open remote file. When Emacs prompts the open info, just input the URL pattern of following:

/usr@machine:/path/to/file

For example, if you want to explore ~/main.c on remote host, you can open it with path:

/water@192.168.1.20:/home/water/main.c

Some machines use different port to provide SSH service, and in this situation we can use following URL to open file or folder:

/test@host#2222:/tmp

, which means using # to add specific port. Just write down the SSH port behind # to enable the connection.

When you are editing the remote file or folder, all the thing is the same as editing locally.

5. Tips

Although Emacs Tramp is very convinent for editing remote Linux host, it is still a better choice if you can download files and edit them locally. By this way, you can use Emacs, use more tools ( for example, Visual Studio, WinMerge, etc.) to coding, merging, copying. There is nothing happier than done the work quickly!

(0) Comments    (230) Views    Read More   
Posted on 25-01-2013
Filed Under (Emacs) by bigbang

If we don’t want Muse to escape * symbol which means export * directly, we can use = to do it.

For example,

=*word=*

will be exported as

=word=

Actually, = is short for <code></code> expression, and <code></code> is also very convinent to escape big block text.

(0) Comments    (114) Views    Read More   
Posted on 23-01-2013
Filed Under (Technology) by bigbang

I am using log4cxx in a normal way, which provides a property file for log4cxx. Here we can find some references1, 2 about it.

But if I want to set log4cxx properties in my C++ code without using property file, what should I do? Here is the code example from log4xxx Wiki:

#include <log4cxx/logger.h>
#include <log4cxx/helpers/pool.h>
#include <log4cxx/basicconfigurator.h>
#include <log4cxx/fileappender.h>
#include <log4cxx/simplelayout.h>

int main() {
    log4cxx::FileAppender * fileAppender = new log4cxx::FileAppender( log4cxx::LayoutPtr(new log4cxx::SimpleLayout()),
                                                                      "logfile", false);

    log4cxx::helpers::Pool p;
    fileAppender->activateOptions(p);

    log4cxx::BasicConfigurator::configure(log4cxx::AppenderPtr(fileAppender));
    log4cxx::Logger::getRootLogger()->setLevel(log4cxx::Level::getDebug());
    log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger("logger");

    LOG4CXX_INFO(logger,"Created FileAppender appender");

    return 0;
}

The above code is only used for recording logs into log file. If we want to direct logs to console as well as writing to file, we need to add log4cxx::ConsoleAppender class into log4cxx::BasicConfigurator. Here is the sample code:

#include <log4cxx/logger.h>
#include <log4cxx/helpers/pool.h>
#include <log4cxx/basicconfigurator.h>
#include <log4cxx/fileappender.h>
#include <log4cxx/simplelayout.h>
#include "log4cxx/consoleappender.h"

LoggerPtr logger;

int main() {
    log4cxx::FileAppender * fileAppender = new log4cxx::FileAppender(log4cxx::LayoutPtr(new log4cxx::SimpleLayout()), L"logfile", false);

    log4cxx::ConsoleAppender * consoleAppender = new log4cxx::ConsoleAppender(log4cxx::LayoutPtr(new log4cxx::SimpleLayout()));

    log4cxx::helpers::Pool p;
    fileAppender->activateOptions(p);

    log4cxx::BasicConfigurator::configure(log4cxx::AppenderPtr(fileAppender));
    log4cxx::BasicConfigurator::configure(log4cxx::AppenderPtr(consoleAppender));
    log4cxx::Logger::getRootLogger()->setLevel(log4cxx::Level::getDebug());
    log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger("logger");

    LOG4CXX_INFO(logger,"Created FileAppender appender");

    return 0;
}

By the above code, the log will be redirected to file and console at the same time without a config file.

(0) Comments    (475) Views    Read More