This HACKING file describes the development environment. -*- org -*- Copyright (C) 2008, 2009, 2011 ViewPlus Technologies, Inc. and Abilitiessoft, Inc. Copyright (C) 2012, 2013, 2014,2015 Swiss Library for the Blind, Visually Impaired and Print Disabled Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without any warranty. This file attempts to describe the maintainer-specific notes to follow when hacking liblouis. * Table of Contents :TOC: - [[#developing][Developing]] - [[#where-to-get-it][Where to get it]] - [[#build-requirements][Build requirements]] - [[#gnulib][Gnulib]] - [[#how-to-build][How to build]] - [[#install-with-homebrew][Install with Homebrew]] - [[#docker][Docker]] - [[#how-to-run-tests][How to run tests]] - [[#how-to-debug][How to debug]] - [[#how-to-find-memory-leaks][How to find memory leaks]] - [[#static-analysis][Static analysis]] - [[#how-to-analyze-performance][How to analyze performance]] - [[#how-to-build-for-windows][How to build for Windows]] - [[#release-procedure][Release Procedure]] - [[#update-the-news-entry][Update the NEWS entry]] - [[#set-the-version-number][Set the version number]] - [[#commit-and-tag][Commit and tag]] - [[#make-the-release][Make the release]] - [[#upload][Upload]] - [[#online-documentation][Online documentation]] - [[#web-site-maintenance][Web site maintenance]] - [[#announce][Announce]] * Developing ** Where to get it The development sources are available through git at github.com: https://github.com/liblouis/liblouis ** Build requirements To build Automake, Autoconf, and Libtool are used. If you are getting the sources from git (or change configure.ac), you'll need to have these tools installed to (re)build. Optionally (if you want to generate man pages) you'll also need ~help2man~. All of these programs are available from ftp://ftp.gnu.org/gnu. If you want to run the YAML based test suite you will have to install ~libyaml~. On Mac OS, the programs can be optained with Homebrew (http://brew.sh): #+BEGIN_SRC shell $ brew install automake libtool pkg-config texinfo #+END_SRC Note that if you are using Homebrew to install liblouis (see below), the build dependencies are installed automatically. ** Gnulib Gnulib (http://www.gnu.org/software/gnulib) is used to provide portable basic functionality to programs and libraries. We use two instances of gnulib, one to provide portable functions such as ~malloc~, ~strndup~, etc to the library and another one to provide portable functionality such as ~getopt~, ~progname~ or ~version-etc~ to the tools. The first time invocation to import gnulib for the library was #+BEGIN_SRC shell $ gnulib-tool --add-import --lib=libgnu --source-base=gnulib \ --m4-base=gnulib/m4 --aux-dir=build-aux --libtool \ --macro-prefix=gl --no-vc-files \ malloc-gnu realloc-gnu strndup #+END_SRC and for the tools #+BEGIN_SRC shell $ gnulib-tool --add-import --lib=libgnutools --source-base=tools/gnulib \ --m4-base=tools/gnulib/m4 --aux-dir=build-aux --libtool \ --macro-prefix=gl_tools --no-vc-files \ getopt-gnu malloc-gnu progname version-etc #+END_SRC More modules might have been added since. The currently-used gnulib modules and other gnulib information are recorded in ~gnulib/m4/gnulib-cache.m4~ and ~tools/gnulib/m4/gnulib-cache.m4~. If you want to update from the current gnulib, install gnulib, and then run the following commands in the top-level directory. #+BEGIN_SRC shell $ gnulib-tool --add-import --lib=libgnu --source-base=gnulib \ --m4-base=gnulib/m4 --aux-dir=build-aux --libtool \ --macro-prefix=gl --no-vc-files $ gnulib-tool --add-import --lib=libgnutools --source-base=tools/gnulib \ --m4-base=tools/gnulib/m4 --aux-dir=build-aux --libtool \ --macro-prefix=gl_tools --no-vc-files #+END_SRC ** How to build After getting the sources from git, with #+BEGIN_SRC shell $ git clone https://github.com/liblouis/liblouis.git #+END_SRC and installing the tools above, change to the liblouis directory and and bootstrap the project with the following command #+BEGIN_SRC shell $ ./autogen.sh #+END_SRC to do a fresh build. Then run configure as usual: #+BEGIN_SRC shell $ ./configure #+END_SRC You have the choice to compile liblouis for either 16- or 32-bit Unicode. By default it is compiled for the former. To get 32-bit Unicode run configure with ~--enable-ucs4~. After running configure run ~make~ and then ~make install~. You must have root privileges for the installation step. ** Install with Homebrew Homebrew (http://brew.sh) is a package manager for Mac OS X that installs software from source. There is nothing special about the installation process in the sense that under the hood it happens exactly as described above, with the only difference that Homebrew automates it completely. First, use the ~brew tap~ command to add the repository that includes the liblouis formula: #+BEGIN_SRC shell $ brew tap liblouis/liblouis #+END_SRC Now you are ready to install liblouis: #+BEGIN_SRC shell $ brew install liblouis #+END_SRC ** Docker Docker (https://www.docker.com) can be useful both for creating a development environment for liblouis, and for shipping the application. Setting up a developer environment can take long and can be problematic especially for Windows. Thanks to Docker we can set up the environment for you, we can easily distribute it as an image, which can be run by anybody and will behave exactly the same for everybody. Docker images of liblouis are being built automatically each time something changes in the code (see https://registry.hub.docker.com/repos/liblouis). In order to use them, first get Docker at http://docs.docker.com/introduction/get-docker. Download the latest liblouis image with: #+BEGIN_SRC shell $ docker pull liblouis/liblouis #+END_SRC Then, enter the development environment by running the image in a Docker container: #+BEGIN_SRC shell $ docker run -it liblouis/liblouis bash #+END_SRC Local files and directories can be "mounted" inside the container, in order to make it easier to edit files and to persist changes across runs. For example, to use local table files: #+BEGIN_SRC shell $ docker run -it -v $(pwd)/tables:/tmp/liblouis/tables liblouis/liblouis bash #+END_SRC See the Docker documentation for more info. The same Docker image can be used as a development environment and as the application itself. For example, to run the lou_translate tool from inside a Docker container: #+BEGIN_SRC shell $ docker run -it liblouis/liblouis lou_translate en-us-g1.ctb #+END_SRC To rebuild the image yourself, run the following command in the root directory of the liblouis source: #+BEGIN_SRC shell $ docker build -t liblouis/liblouis . #+END_SRC A ~.dockerignore~ file is required if you want to compile the source both on te host and in the Docker container. The ~.dockerignore~ file can be updated from ~.gitignore~ with: #+BEGIN_SRC shell $ make .dockerignore #+END_SRC ** How to run tests Tests are run with #+BEGIN_SRC shell $ make check #+END_SRC ** How to debug First you have to build liblouis with debugging info enabled. #+BEGIN_SRC shell $ ./configure CFLAGS='-g -O0 -Wall -Wextra' $ make #+END_SRC Starting the programs under the tools directory within gdb is a little tricky as they are linked with libtool. See the info page of libtool for more information. To start ~lou_checktable~ for table ~wiskunde.ctb~ for example you'd have to issue the following commands: #+BEGIN_SRC shell $ libtool --mode=execute gdb ./tools/lou_checktable (gdb) run tables/wiskunde.ctb #+END_SRC ** How to find memory leaks Valgrind is a tool that can be used to find memory errors. It is recommended that you compile liblouis without any optimizations and with all warnings enabled before running it through Valgrind: #+BEGIN_SRC shell $ ./configure CFLAGS='-g -O0 -Wall' $ make #+END_SRC Then use Valgrind to analyze liblouis. For example you can run ~lou_translate~ trough Valgrind: #+BEGIN_SRC shell $ libtool --mode=execute valgrind -v --tool=memcheck \ --leak-check=full --leak-resolution=high --log-file=valgrind.log \ ./tools/lou_translate en-us-g2.ctb #+END_SRC Type a few words at the prompt, check translation and terminate ~lou_translate~. Now open the file ~valgrind.log~ and see if there are any memory leaks reported. You can also just run lou_checktable for example: #+BEGIN_SRC shell $ libtool --mode=execute valgrind -v --tool=memcheck \ --leak-check=full --leak-resolution=high --log-file=valgrind.log \ ./tools/lou_checktable tables/nl-BE-g0.utb #+END_SRC Again open valgrind.log to see if any memory leaks were reported. For the full experience run lou_allround under Valgrind: #+BEGIN_SRC shell $ libtool --mode=execute valgrind -v --tool=memcheck \ --leak-check=full --show-reachable=yes \ --leak-resolution=high --track-origins=yes \ --log-file=valgrind.log ./tools/lou_allround #+END_SRC *** AddressSanitizer [[https://github.com/google/sanitizers/wiki/AddressSanitizer][AdressSanitizer]] is a memory error detector for C/C++. It is part of both LLVM and gcc. To check liblouis build it as follows: #+BEGIN_SRC shell $ ./autogen.sh $ ./configure CFLAGS='-fsanitize=address -O1 -fno-omit-frame-pointer -g' $ make $ ./tools/lou_translate tables/en-ueb-g2.ctb #+END_SRC Run a few translations, end the program and marvel at the output of AddressSanitizer. At the time of this writing it complained pretty hard: #+BEGIN_EXAMPLE SUMMARY: AddressSanitizer: 12384 byte(s) leaked in 12 allocation(s). #+END_EXAMPLE *** Electric Fence Electric Fence is a tool that helps detect memory access that overruns the boundaries of a ~malloc()~ memory allocation, and access to memory that has been released with ~free()~. Under Debian the usage is fairly straightforward: #+BEGIN_SRC shell $ sudo apt install sudo apt install electric-fence #+END_SRC Then compile [[#how-to-debug][as above]] and invoke the debugger [[#how-to-debug][as above]]. Inside ~gdb~ set up ~LOUIS_TABLEPATH~ and ~LD_PRELOAD~ as follows: #+BEGIN_SRC shell $ libtool --mode=execute gdb ./tools/lou_allround (gdb) set environment LOUIS_TABLEPATH ./tables,./tests/tables,./tests/tables/moreTables,./tests/tablesWithMetadata,./tests/tables/emphclass (gdb) set environment LD_PRELOAD /usr/lib/libefence.so.0.0 (gdb) run #+END_SRC If there are problems with memory access the program will run into a segmentation fault which you can consequently analyze in the debugger. ** Static analysis [[http://clang-analyzer.llvm.org/scan-build.html][scan-build]] is a command line utility to run a static analyzer over the codebase. It helps to find problems such as memory leaks, dereference of null pointer, etc. #+BEGIN_SRC shell $ make maintainer-clean $ ./autogen.sh $ scan-build ./configure $ scan-build make ... scan-build: 101 bugs found. scan-build: Run 'scan-view /tmp/scan-build-2019-08-15-141827-5185-1' to examine bug reports. #+END_SRC then look at the generated reports and fix (or report) the issues. ** How to analyze performance Gprof helps you analyze the performance of programs. You have to compile liblouis as follows: #+BEGIN_SRC shell $ ./configure --disable-shared $ make clean all CFLAGS='-g -O0 -pg' LDFLAGS='-all-static' #+END_SRC Then translate some stuff with a large table: #+BEGIN_SRC shell $ ./tools/lou_translate tests/tables/large.ctb #+END_SRC Finally look at the call profile: #+BEGIN_SRC shell $ libtool --mode=execute gprof ./tools/lou_translate gmon.out #+END_SRC ** How to build for Windows See the ~README.windows~ file and the windows subdirectory. *** How to cross-compile for Windows To compile for win32, use the MinGW win32 cross-compiler as shown below. Use the prefix option to install the binaries to a temporary place where you can create a zip file. The ~LDFLAGS='-all-static'~ ensures that libgcc is linked in statically. Otherwise the users need to have ~libgcc_s_sjlj-1.dll~. Some users want the dlls unversioned. To achieve that add ~-avoid-version~ to ~LDFLAGS~. #+BEGIN_SRC shell $ ./configure --build=i686-pc-linux-gnu --host=i686-w64-mingw32 --prefix=/tmp/liblouis-mingw32 $ make LDFLAGS='-avoid-version -Xcompiler -static-libgcc' $ make install $ zip -r liblouis-mingw32msvc.zip /tmp/liblouis-mingw32 #+END_SRC To compile for win64, use the MinGW-w64 cross-compiler: #+BEGIN_SRC shell $ ./configure --build=i686-pc-linux-gnu --host=x86_64-w64-mingw32 --prefix=/tmp/liblouis-w64-mingw32 $ make LDFLAGS='-avoid-version -Xcompiler -static-libgcc' $ make install $ zip -r liblouis-w64-mingw32.zip /tmp/liblouis-w64-mingw32 #+END_SRC Two makefile rules have been provided to do this automatically for you. Docker will be used if the right cross-compiler is not installed. To compile for win32 using the MinGW cross-compiler, run ~make distwin32~. This will produce a ZIP file called ~liblouis--win32.zip~. To compile for win64 using the MinGW-w64 cross-compiler, run ~make distwin64~. This will produce a ZIP file called ~liblouis--win64.zip~. *** TODO How to build for Windows using Cygwin (possibly use a Vagrantfile as demonstration + explain that Cygwin binaries can not be used outside the Cygwin environment) *** TODO How to build for Windows using MinGW (possibly use a Vagrant file as demonstration) * Release Procedure These steps describe what a maintainer does to make a release; they are not needed for ordinary patch submission. ** Update the NEWS entry If any new tables were added, renamed or removed please note them with their file name in the NEWS entry. This is usefull for projects like NVDA. ** Set the version number Update the version number in ~NEWS~ (with version, date, and release type), ~configure.ac~ and ~windows/include/config.h~. Don't forget to update the libtool versioning info in ~configure.ac~, i.e. ~LIBLOUIS_REVISION~ and possibly ~LIBLOUIS_CURRENT~ and ~LIBLOUIS_AGE~. Check the [[https://www.gnu.org/software/libtool/manual/html_node/Interfaces.html#Interfaces][libtool documentation on versioning]] for an explanation of these values. ** Commit and tag Commit the changes and tag this version #+BEGIN_SRC shell $ git tag -s v2.6.0 -m "Release 2.6.0" $ git push origin v2.6.0 #+END_SRC If you know the exact version number that needs to be tagged use #+BEGIN_SRC shell $ git tag -s v2.6.0 -m "Release 2.6.0" $ git push origin v2.6.0 #+END_SRC ** Make the release Check out a clean copy in a different directory, like /tmp. Run autogen.sh and configure with no special prefixes. Run make distcheck. This will make sure that all needed files are present, and do a general sanity check. Run make dist. This will produce a tarball. #+BEGIN_SRC shell $ ./autogen.sh && ./configure && make && make distcheck && make dist #+END_SRC ** Upload Add the tarball to the github liblouis releases page, i.e. add it under https://github.com/liblouis/liblouis/releases with the specific release and add a link to it in $WEBSITE/downloads/index.md. See below for instructions on how to update the web site. ** Online documentation The online documentation is part of the liblouis web site. To add it to the site simply copy doc/liblouis.html to $WEBSITE/documentation/liblouis.html. Make sure you add the proper YAML front matter. Again see below for instructions on how to update the web site. ** Web site maintenance The liblouis web site at liblouis.org is maintained with the help of [[https://pages.github.com/][github pages]]. To edit the site just check out the repo at https://github.com/liblouis/liblouis.github.io. You'll need to know a few things about [[http://jekyllrb.com/][Jekyll]] and markdown, the markup that is used to edit the content. In order to update the site simply edit, commit and push. For the new release update the project web site. - Add a post containing the current NEWS to the _posts directory and - add the download artifacts to the download page ** Announce Send an announcement to the liblouis list ~liblouis-liblouisxml@freelists.org~. See ~ANNOUNCEMENT~ for an example.