Friday, February 25, 2011

Getting Started with GDB

GDB is a very powerful debugging tool for C/C++ and many other languages. Here I'm gonna show you how to get started with GDB.

testgdb.cpp
#include <iostream>
#include <string>
using namespace std;

string globalmsg = "Hello World";

void half(int& a) {
    a /= 2;
}

int whatever() {
    int i = 5;
    i *= 3;
    return i;
}

int main() {
    int a = 10;
    half(a);
    cout << a << endl;
    cout << whatever() << endl;
    return 0;
}

1. Compile the code
g++ -c -g -Wall -O0 testgdb.cpp
The -O0 flag is useful for debugging information because the compiler may do its own optimization that can eliminate some debugging information, such as -O2 flag for example.
2. Link it
g++ -o testgdb testgdb.o
3. Run it
gdb ./testgdb
After running this statement, there will be gdb prompt.
4. Set the breakpoint in line 18 and 19
break testgdb.cpp:18
break testgdb.cpp:19
5. See the list of breakpoints
info break
6. Remove the second breakpoint
delete 2
7. Run the program
run
8. See the current line
list
9. Step over to the next line
next
10. See the current line again
list
11. Step in to the half() function
step
12. Print the arguments
info args
13. Go to the next line
next
14. Print the value a now
print a
The new value should be 5.
15. Step out from half() function
finish
16. Print all the local variables
info locals
17. Set another breakpoint in line 13
break testgdb.cpp:13
18. Jump to that newly-set breakpoint
continue
19. Step over
next
20. Print the new value of i
print i
The value of i should be 15
21. Step out from the whatever() function
finish
22. Get the length of globalmessage string
print globalmessage.size()
23. Quit gdb
quit

I hope this brief introduction is useful. For more information, type
help <command>

Thursday, February 10, 2011

Getting Started with Distutils

Distutils is such a wonderful tool. It makes installation of Python modules, packages so easy. Here I'm gonna show you how to write a simple setup.py file, which is required by distutils.

setup.py
from distutils.core import setup
import os
import glob

pyfiles = glob.glob("*.py")
pyfiles = [pyfile[:-3] for pyfile in pyfiles]
setup(name='mymodule',
      version='1.0',
      py_modules=pyfiles,
      packages=['test.test1', 'abc.def'],
      package_dir={'abc.def':'mypackage/abc/def'})
Since setup.py is basically just a Python script, we can do pretty much anything with it. What this script is trying to do is it will copy all the python files in the root directory as well as the some python packages in the test.test1 and abc.def. The directory structure is like this:
root
 |--- test/__init__.py
 |--------/test1/__init__.py
 |--------------/mypackage1.py
 |--------------/mypackage2.py
 |--- mypackage/abc/__init__.py
 |-----------------/def/__init__.py
 |---------------------/mypackage3.py
 |--- mymodule1.py
 |--- mymodule2.py
 |--- mymodule3.py
As we can see mypackage is not part of package name (there isn't any __init__.py file there), thus we need package_dir={'abc.def':'mypackage/abc/def'} in the setup() function.

To build a source distribution:
python setup.py sdist
To build Linux RPM:
python setup.py bdist_prm
To build Windows MSI:
python setup.py bdist_msi
To build Windows installer:
python setup.py bdist_wininst

To install to the default Python installation:
python setup.py install
To install to a particular location:
python setup.py install --prefix=/home/whoever/wherever

Wednesday, February 9, 2011

Converting Tabs to Spaces

Mixing tabs and spaces in Python is a bad thing. In recent Python, Python will complain if there are such occurrences. Here I'm gonna show you a small tool to convert tabs to spaces.
import os, sys

def _error(msg):
    print "Error:", msg
    sys.exit(1)
    
def tab2space(path, numspace):
    """ Convert tabs to spaces """
    if not os.path.exists(path): _error(path + "does not exist")
    print "Converting tabs to spaces..."
    origfile = open(path, "r")
    origfilename = origfile.name
    tmpfile = open(path + ".tmp", "w")
    tmpfilename = tmpfile.name
    try:
        for l in origfile.readlines():
            newline = l.replace("\t", " " * numspace)
            tmpfile.write(newline)
    finally:
        # It is important to close the open files; otherwise the
        # remove statement below may not work, especially on Windows.
        tmpfile.close()
        origfile.close()
    os.remove(origfilename)
    os.rename(tmpfilename, origfilename)
    print "*** Done ***"

def _usage(progname):
    print "Usage:", progname, "<path> <number of spaces>"
    sys.exit(1)
    
if __name__ == "__main__":
    if len(sys.argv) != 3: _usage(sys.argv[0])
    tab2space(sys.argv[1], int(sys.argv[2]))

Enjoy!

Creating Custom Function Decorator in Python

Python provides many built-in function decorators, such as staticmethod, abstractmethod, etc. Creating our own function decorator is pretty easy. What we need to do is to overload the __call__ function. Here is how to do it.

class Log:
    def __init__(self, func):
        self.func = func
    def __call__(self, *args):
        print "Before", self.func.__name__ + "()"
        self.func(*args)
        print "After", self.func.__name__ + "()"

@Log
def hello():
    print "Hello"
    
if __name__ == "__main__":
    hello()

This is equivalent to:
class Log:
    def __init__(self, func):
        self.func = func
    def __call__(self, *args):
        print "Before", self.func.__name__ + "()"
        self.func(*args)
        print "After", self.func.__name__ + "()"

def hello():
    print "Hello"
hello = Log(hello)
    
if __name__ == "__main__":
    hello()

The output is
Before hello()
Hello
After hello()

Sunday, February 6, 2011

Creating Abstract Class in Python

Prior to Python 2.6, Python had no concept of abstract class. To enforce that a derived class implements some particular methods from the base class, we can do something like this.
class BaseClass:
    def do_something(self):
        assert False, "Not implemented"

class DerivedClass(BaseClass):
    def do_mystuff(self):
        print "Do my stuff!"
    def do_something(self):
        print "Do something!"
        
if __name__ == "__main__":
    c = DerivedClass()
    c.do_something()
    c.do_mystuff()
If we don't implement the do_something() method, an exception will be raised.

In Python 2.6 onwards, we can achieve the same functionality in a more elegant manner with the help from abc (Abstract Base Class) module.

from abc import ABCMeta, abstractmethod

class BaseClass:
    __metaclass__ = ABCMeta

    @abstractmethod
    def do_something(self): pass

class DerivedClass(BaseClass):
    def do_mystuff(self):
        print "Do my stuff!"
    def do_something(self):
        print "Do something!"
        
if __name__ == "__main__":
    c = DerivedClass()
    c.do_something()
    c.do_mystuff()

Understanding C++ Include Guard

In C++, include guard is often seen and it has a syntax like this
#ifndef MACRONAME_H
#define MACRONAME_H

....

#endif
The purpose of it is to disallow multiple redefinition. For example.
Person.h
//#ifndef PERSON_H_
//#define PERSON_H_

class Person
{
public:
    Person();
    virtual ~Person();
};

//#endif /* PERSON_H_ */

Person.cpp
#include "Person.h"

Person::Person()
{
}

Person::~Person()
{
}

Employee.h
//#ifndef EMPLOYEE_H_
//#define EMPLOYEE_H_

#include "Person.h"

class Employee : public Person
{
public:
    Employee();
    virtual ~Employee();
};

//#endif /* EMPLOYEE_H_ */

Employee.cpp
#include "Employee.h"

Employee::Employee()
{
}

Employee::~Employee()
{
}

Main.cpp
#include <iostream>
#include "Person.h"
#include "Employee.h"
using namespace std;

int main()
{
    Employee employee;
    return 0;
}

Here, we included the Person.h twice, one in the Employee.h and the other one is in the Main.cpp. This code won't compile because C++ has One Definition Rule. If we uncomment the include guard part in the code, the code will compile just fine.

Microsoft Visual C++ has #pragma once for such purpose, but it's not a standard, thus not portable.