Hacking Guidelines ================== This document is an introduction to hacking on GnuCash. Related Documents ----------------- In addition to this file, you should read the README file, which explains the details of getting the git source, building GnuCash, and creating patches for submission. Coding Style Conventions ------------------------ Please refer to https://wiki.gnucash.org/wiki/CodingStandard. ============== TIPS AND HINTS ============== Building GnuCash in-tree ------------------------ This is generally discouraged. You should always use a separate build directory, preferably outside of the source directory. If you really want a build directory inside your source directory, make it a hidden one (starting with a '.'), to keep intltool from incorrectly picking up translatable strings from the build directory. Starting GnuCash from the build tree ------------------------------------ This should mostly work, but there may be corner cases where it behaves differently from running gnucash from the target installation directory. You can tell cmake which install directory to use via the command line switch '-DCMAKE_INSTALL_PREFIX=' Don't use '/usr' or '/usr/local' unless you're a package maintainer for a distro. Instead choose /opt/gnc/git/ or even $HOME/gnc/git (or something similar). Getting Trace Messages From GnuCash ----------------------------------- See the doxygen comments in libgnucash/engine/qoflog.h (and .c) Starting GnuCash in GDB ----------------------- To run gdb on an installed version of gnucash (installed in /opt/gnc/unstable:) % gdb /opt/gnc/unstable/bin/gnucash You'll also probably want to know about these: gdb> catch fork gdb> set follow-fork-mode child ----- It may be the case that running GDB from within emacs doesn't work for you, with the following error: [C-u M-x gdb /opt/gnucash-cvs/bin/gnucash ...in buffer *gud-gdb*:] (gdb) attach jsled needed to re-define a gud.el function as such: (defun gud-gdb-massage-args (file args) (let ((l (copy-list args))) (nconc l (list "-cd" (expand-file-name default-directory) "-fullname")))) jsled does not need the above with emacs-22, thankfully. It was getting quite tiresome. Using Electric Fence with GnuCash --------------------------------- There are currently no rules in our build system to build and run gnucash or unit tests with Electric Fence. It should probably be relatively straightforward to add this as all it needs is to link with libefence.so (-lefence). Fedora 27 ships an ElectricFence package containing that library and also an executable 'ef' to run an arbitrary program with Electric Fence guarding enabled. I have given it a quick spin on gnucash but it immediately crashes. I haven't investigated whether this is because I should first have linked gnucash with -lefence or because a real problem in GnuCash code. Using Valgrind with GnuCash --------------------------- -- run ${prefix}/bin/gnucash-valgrind However, I did not find valgrind to be useful. It reported a bunch of guile bugs, some g_hash_table bugs, and then the program exited prematurely for no apparent reason. :-( For the moment, gnucash-valgrind uses the suppressions in src/debug/valgrind/valgrind-*.supp For valgrind-gnucash.supp, this comment was made (but is perhaps outdated by now ?): This file needs to be cleaned up in two ways: 1/ There are a bunch of duplicate suppressions in the file. * The suppressions in place were auto-generated by valgrind itself [--gen-suppressions=yes], and it makes no effort to output the suppression only once. 2/ There are a bunch of suppressions which need to not be suppressions, but instead just not be generated by valgrind. Using Callgrind with GnuCash ---------------------------- In order to debug with callgrind, you need to add a couple of code fragments around the section of code you are profiling. This is easiest if you can find the function that invokes the routine(s) you want to profile, add the following code around the function call of interest. Add the following to the start of the file: #include Add the following to the start of the calling function: static GTimeVal start, end; Add the following just before the function of interest: g_print("Start timing.\n"); g_get_current_time(&start); CALLGRIND_START_INSTRUMENTATION(); CALLGRIND_TOGGLE_COLLECT(); Add the following just after the function of interest: CALLGRIND_TOGGLE_COLLECT(); CALLGRIND_STOP_INSTRUMENTATION(); g_get_current_time(&end); if (start.tv_usec > end.tv_usec) { end.tv_usec += 1000000; end.tv_sec -= 1; } g_print("Callgrind enabled for %d.%6d seconds.\n", (int)(end.tv_sec - start.tv_sec), (int)(end.tv_usec - start.tv_usec)); You will need to recompile, and then run the 'gnucash-valgrind' wrapper script instead of the normal 'gnucash' script. NOTE: Version 3.2 of valgrind has changed the above macros to no longer take an argument. In order to compile with this version of valgrind you will need to remove the trailing parentheses and semicolon. Look up exported and imported symbols ------------------------------------- These commands may be useful to find out the library that actually exported a particular symbol, and to check which import symbol one particular library depends upon and where they are imported from. Run these from the top-level of the build tree. Note "lib64" below should be "lib" for a 32-bit build. # Create a table of all exported symbols and where they come from nm -A `find . -name '*.so'` | grep ' T ' | \ sed 's/^\([^:]*\).* \([^ ]*\)$/\1: \2/' > exportedsymbols # For a particular library, check symbol import requirements, # listing all symbols (needs the file from above) A=lib64/libgnc-module.so && echo "$A requirements:" \ && nm $A | grep ' U ' | sed 's/^.* \([^ ]*\)$/\1/' | \ grep -wFf- exportedsymbols # For a particular library, check import requirements, # summarized by library A=lib64/libgnc-module.so && echo "$A requirements:" \ && nm $A | grep ' U ' | sed 's/^.* \([^ ]*\)$/\1/' | \ grep -wFf- exportedsymbols | cut -d: -f1 | sort | uniq # For a particular library, check import requirements, # summarized by library, formatted for a cmake TARGET_LINK_LIBRARIES command A=lib64/libgnc-gnome.so && echo "$A target link libraries:" \ && nm $A | grep ' U ' | sed 's/^.* \([^ ]*\)$/\1/' | \ grep -wFf- exportedsymbols | cut -d: -f1 | sort | uniq | \ sed 's!.*/lib! !' | sed 's/.so$//' # List all import requirements summarized by library for a full # recursive directory tree for A in `find lib64 -name '*.so'`; do \ echo -e "\n##$A requirements:" && nm $A | grep ' U ' | \ sed 's/^.* \([^ ]*\)$/\1/' | grep -wFf- exportedsymbols | \ cut -d: -f1 | sort | uniq; done XCode project ------------- There is an XCode project available in gnucash.xcodeproj at the root of the source tree. This project can be used with XCode on a Macintosh to debug GnuCash. It is not set up to build GnuCash, but only to debug it. Building must be done using the normal command line tools. Note this XCode project has not been updated since the big directory restructuring preceding the 2.7.1 release. So it will currently not find source files where it's expecting them. This project is designed to be used with the X Window version of GnuCash, not the native Quartz version. To use it you must build and install GnuCash into directories "build" and "install" parallel to the source directory. Furthermore the architecture dependent parts of the install are put in a subdirectory "install/darwin". To build, then, if the source directory is somewhere/gnucash you must create the directories somewhere/build/darwin and somewhere/install/darwin/bin, cd into somewhere/build/darwin and execute ../../gnucash/configure --prefix=../../install \ --exec-prefix=../../install/bin \ --enable-debug \ ...other options... make make install This will build and install a copy of GnuCash that can be debugged using the XCode project. The debug target in the project is set with a build tool of /usr/bin/true so building in XCode won't hurt anything, it just won't do much. It is also set to not launch GnuCash automatically, but rather to wait for it to be launched manually. This lets you run it from a command prompt and see the console output which can often be useful. Hence to initiate a debugging session in XCode, tell XCode to run GnuCash then go to a terminal window and launch install/darwin/bin/gnucash with whatever options you want. XCode will notice that it has been launched and attach to the process. Since there seems to be no way to make the path to the executable a relative path, you must make one change to the debug scheme before you can run gnucash under XCode. In XCode 5 (other versions may be different) go to Product->Scheme->Edit Scheme and select the "info" tab of the "Run gnucash" pane. Select "Other..." in the "Executable" menu and select the installed binary for gnucash in the resulting file open dialog. This should be install/darwin/bin/gnucash as described above. This, and the act of opening the project in XCode, will change some of the files in the XCode project directory. You can, or course, commit these locally, but please don't push them upstream.