Developer's Corner

From Eigen
Revision as of 13:11, 19 May 2009 by Hauke (Talk | contribs)

Jump to: navigation, search

Code Quality

Nightly build reports:

To know more about krazy code checker, please check this page: http://techbase.kde.org/Development/Tutorials/Code_Checking.


Submitting test suite reports

To submit reports to the dashboard:

  • Create a folder and get the last testsuite.cmake script:
 mkdir cdash
 cd cdash
 svn cat svn://anonsvn.kde.org/home/kde/trunk/kdesupport/eigen2/test/testsuite.cmake > testsuite.cmake
  • run the testsuite:
 ctest -VV -S testsuite.cmake,EIGEN_BUILD_STRING=fedora-10-`uname -m`-gcc-4.3.2,EIGEN_CXX=g++-4.3,EIGEN_MODE=Experimental

Of course, change the value of the variable to match your system. The full list of options with description is available in the testsuite.cmake file.

Then you can check the results on the Eigen's project page of cdash.org: http://my.cdash.org/index.php?project=Eigen.

For further information, check theses web pages:

Eigen hacking

Coding rules

We are not very strict about coding rules, however the trends are:

  • indentation with 2 spaces (no tabs !)
  • the best is to show a typical example of a public class:
 template<typename MatrixType
 class NameOfTheClass
 {
     typedef typename MatrixType::Scalar Scalar;
   public:
     // public functions start with lower case:
     Scalar nameOfTheFunction(int i) const;
     // public static functions start with upper case:
     static NameOfTheClass* Create(const MatrixType& mat);
   protected:
     // member attributes start with m_:
     Scalar m_attributeName;
     MatrixType m_matrix;
 };
 
 template<typename MatrixType> typename MatrixType::Scalar
 NameOfTheClass<MatrixType>::nameOfTheFunction(int i) const
 {
   Scalar res = 0;
   if(i>0)
   {
     for(int j=0; i<m_matrix.cols(); ++j,++i)
       res = ei_hypot(res, m_matrix.coeff(i,j));
   }
   else
   {
     j = 0;
     while (i<m_matrix.rows())
     {
       res = ei_hypot(res, m_matrix.coeff(i,j));
       ++i;
       ++j;
     }
   }
   return res;
 }
  • global functions and class/struct reserved for internal use start with ei_, eg:
 struct ei_assign_selector;
  • favor explicit names rather than short ones

Running the unit tests

The unit tests are managed by the pair cmake/ctest. Typically one proceeds as follow:

  $ mkdir build
  $ cd build
  $ cmake path_to_eigen2 -DEIGEN_BUILD_TESTS=on

From this point you can:

  • build all tests: make
  • run a specific test: ./test/test_name_of_the_test (e.g., ./test/test_geo_quaternion)
  • (build and) run all tests: ctest
  • (build and) run all tests with more feedback: ctest -V
  • (build and) run all tests matching a regular expression with feedback: ctest -V -R <regexp> (e.g., to run all tests of the geometry module: ctest -V -R geo)

Note that the unit tests of the unsupported modules are built in the unsupported/test sub-folder.

For more information, please check the cmake and ctest documentations.


Writing unit tests

If you want to add a simple test of small feature highly related to an existing unit test, then simply extend the existing one. Otherwise, you have to create a new unit test. Let's call it mytest.

  • Create a new file mytest.cpp in the eigen2/test (or eigen2/unsupported/test) folder.
  • Your file must start by including the file main.h and define a function test_mytest:
  #include <main.h>
  void test_mytest()
  {
    /* ... */
  }
  • If you don't know how to fill the blank, have a look at the other unit test files in eigen2/test.
  • Add it to the respective CMakeLists.txt file by adding the line:
  ei_add_test(mytest)
  • Do not forget to add it to svn: svn add test/mytest.cpp
  • Finally, you can compile and run it from your build directory:
  $ make test_mytest
  $ ctest -V -R mytest

Advanced: The macro ei_add_test takes two optional arguments:

  • The first one specifies additional compile flags.
  • The second one contains the additional libraries to link with.


Submitting patches (svn)

Make sure your local checkout is up to date:

  $ cd path_to_eigen2
  $ svn up 

If your patch contains new files, make svn know about them:

  svn add path_to_new_file1 path_to_new_file2 ...

Check your patch by running:

  $ svn status
  $ svn diff | kompare -o -

Note that the last command requires kompare, but it can be easily adapted to any diff viewer.

Finally, create the patch file:

  $ svn diff > mypatch.diff

and send it to the mailing list.


Backporting bugfixes (svn)

Current development always occurs in trunk (/trunk/kdesupport/eigen2) which will become the next stable branch (e.g., 2.1). Whenever we fix a bug in trunk, if we want the bugfix to appear in the next release of the current stable branch (e.g., 2.0.x), we need to manually backport that fix to the 2.0 branch. For that you need to have a checkout of both trunk (in path/to/trunk) and stable branch (path/to/branch). Then the recipes is:

  • First, commit your fix to the trunk. Note down the revision number, call it N.
  • Then do:
 $ cd path/to/branch
 $ svn up
 $ svn merge -cN path/to/trunk
 $ svn ci
  • Start your commit message with: "Backporting commit N" and a small explanation.


Mercurial workflow

Before starting, let's mention these links:

 http://www.selenic.com/mercurial/wiki/UnderstandingMercurial
 http://www.selenic.com/mercurial/wiki/Tutorial

Basic usage

Getting the source

Initial checkout:

 $ hg clone http://bitbucket.org/eigen/eigen2

or if you have a write access to the repository you have two options:

 $ hg clone ssh://hg@bitbucket.org/eigen/eigen2/        # See [1] to setup ssh
 $ hg clone https://login@bitbucket.org/eigen/eigen2/   # password login


After that, to update your checkout (get the new changes made to the repository):

 $ hg in            # check what's coming in
 $ hg pull -u       # hg pull brings the changes into your store, and -u updates
                    # your working directory to the latest revision.
                    # 'hg pull -u' is the same as 'hg pull && hg update'.

Branches

By default, what you now see is the development branch, called the 'default branch'. This is what was called 'trunk' in SVN.

 $ hg branch        # show the name the current branch
 $ hg branches      # show the list of branches
 $ hg up 2.0        # switch to 2.0 branch

Local commit

First of all, like with SVN, make sure you have put any new files under revision control:

 $ hg add <filename> # Put a file under revision control

Then you can examine before committing:

 $ hg status        # see what files are affected (same as 'svn status')
 $ hg diff          # show differences that are to be committed (same as 'svn diff')

Also, before commiting, it's important that you have configured your identity, so that you will be credited in the hg history. So edit your .hgrc file (either the one in your home directory, or the one in the .hg/ subdirectory of your current working directory) and add:

 [ui]
 username = John Smith <johnny@something.com>

To proceed with the local commit:

 $ hg commit        # take care, this will commit changes for the whole repository
                    # even if you are in a sub-directory (this is not as SVN does)
 $ hg commit .      # if you want to commit only the local directory

Undoing a local commit

In case you want to undo a local commit, e.g. to deal with typos in the commit log or similar, do:

 $ hg rollback      # roll back the last transaction

I suggest to not (!) use this technique, for anything else but local commits. Otherwise, it makes no sense, since it cannot be guaranteed that other users already pulled in public changes.

Generating a patch

Once you have made a local commit, you can generate a patch from it:

 $ hg export tip > somefile

Here, 'tip' means the latest revision. Try "hg help export" to see other options. This generates a file 'somefile' that you can then attach to an e-mail to the Eigen mailing-list. If you have properly configured your identity as above before committing, then importing your patch will properly credit you.

Pushing the local changes to the central repository

Once you have made a local commit, you can push it to the central repository.

 $ hg out           # to check what you are actually pushing
 $ hg push          # no need to give the repository if this is the one cloned

You may see this error message:

 abort: push creates new remote heads!
 (did you forget to merge? use push -f to force)

This means that one of your modified files has been modified meanwhile in the repository. You need to merge before you can push: see next section. Do not use push -f as mentioned in that message, as there may be a conflict to resolve manually.

Merge changes from another repository

 $ hg in <repo>     # check what's coming in
 $ hg pull <repo>   # pull changesets from <repo>
 $ hg merge         # merge the new tip from <repo> into our working directory
 $ hg parents       # see the revisions that have been merged into the working directory
 $ hg commit        # commit the result of the merge

After 'hg merge', you may see this error message:

 warning: conflicts during merge.
 merging <filename> failed!
 0 files updated, 0 files merged, 0 files removed, x files unresolved

In that case, read the section "Resolving Conflicts" below.

Resolving conflicts

This is very similar to SVN. After a 'hg merge' has found conflicts, the files are left with special markers at the locations of conflicts, like:

 <<<<<<< local
 Hello Sir
 =======
 Hello Madam
 >>>>>>> other

You have to edit these files manually to resolve the conflict. Once a file <filename> is fixed, do:

 hg resolve -m <filename>   # mark the file as resolved

Once all the files are marked as resolved, you can proceed with committing.

Viewing history

The basic command here is 'hg log'. If you want to see full information about a certain revision, you can do:

 $ hg log --style changelog -r 1000  # examine revision 1000

But you can also enable a couple of extensions that provide fancier views. Edit (or create) your global .hgrc file (in your home directory) and add these lines:

 [extensions]
 hgext.graphlog =
 hgk=

You can now enjoy a graphical view of the commit history:

 $ hg view

Or if you prefer a plain text output of the graph:

 $ hg glog

Pushing many local commits as a single one

In case you love abusing of local commits and finally want to record only one, then here is the recipe:

 $ hg clone <central-repo> hackrepo
 $ cd hackrepo
 $ hg log | head                  # record the last rev id (=id0)
 # hack/commit many times
 $ cd ..
 $ hg clone <central-repo> main
 $ cd main
 $ (cd ../hackrepo ; hg export id0:) | hg import - -m "unified commit message"
 $ hg push

Backporting bugfixes

 $ hg clone <central-repo>
 $ hg up 2.0              # switch your working copy to the 2.0 stable branch
 $ hg log | less             # find the changeset ids you want to backport
 $ hg transplant --log REV

The last command automatically commit the change using the same message than the exported commit appended with the

 (transplanted from REV)

line. If the merge failed, then you have to resolve the conflict and commit as usual. See also the transplant extension doc for more details.

Instead of the transplant command, you might also do:

 $ hg export -r REV | hg import -

or even:

 $ hg export -r REV | hg import - -m "backporting REV : short explanation"

Commit review

Unless we do not find the "optimal" solution for commit reviews here is a possibility using bitbucket.org forks.

In a first step you need to create a fork of Eigen. Once the fork is created you can clone it

 $ hg clone !https://<username>@bitbucket.org/<username>/eigen2/ eigen2_clone

The next step is to pull the changes from the local clone of your Eigen tip into the forked version.

 $ cd eigen2_clone
 $ hg pull -u -r tip ../eigen

Finally, you can push back the potential commit to the Eigen fork via

 $ hg push

Your commit is now publicly visible and the developers can review it.

Make a new release

Documentation tips