townforge/docs/COMPILING_DEBUGGING_TESTING.md
mj-xmr bd74c6b8ba Doc: Compiling, debugging and testing efficiently
see docs/COMPILING_DEBUGGING_TESTING.md
2021-04-17 06:37:23 +02:00

4.9 KiB

Compiling, debugging and testing efficiently

This document describes ways of compiling, debugging and testing efficiently for various use cases. The intented audience are developers, who want to leverage newly added tricks to Monero via CMake. The document will lower the entry point for these developers. Before reading this document, please consult section "Build instructions" in the main README.md. Some information from README.md will be repeated here, but the aim is to go beyond it.

Basic compilation

Monero can be compiled via the main Makefile, using one of several targets listed there. The targets are actually presets for CMake calls with various options, plus make commands for building or in some cases make test for testing. It is possible to extract these CMake calls and modify them for your specific needs. For example, a minimal external cmake command to compile Monero, executed from within a newly created build directory could look like:

cmake -S "$DIR_SRC" -DCMAKE_BUILD_TYPE=Release && make

where the variable DIR_SRC is expected to store the path to the Monero source code.

Use cases

Test Driven Development (TDD) - shared libraries for release builds

Building shared libraries spares a lot of disk space and linkage time. By default only the debug builds produce shared libraries. If you'd like to produce dynamic libraries for the release build for the same reasons as it's being done for the debug version, then you need to add the BUILD_SHARED_LIBS=ON flag to the CMake call, like the following:

cmake -S "$DIR_SRC" -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON && make

A perfect use case for the above call is following the Test Driven Development (TDD) principles. In a nutshell, you'd first write a couple of tests, which describe the (new) requirements of the class/method that you're about to write or modify. The tests will typically compile for quite a long time, so ideally write them once. After you're done with the tests, the only thing left to do is to keep modifying the implementation for as long as the tests are failing. If the implementation is contained properly within a .cpp file, then the only time cost to be paid will be compiling the single source file and generating the implementation's shared library. The test itself will not have to be touched and will pick up the new version of the implementation (via the shared library) upon the next execution of the test.

Project generation for IDEs

CMake allows to generate project files for many IDEs. The list of supported project files can be obtained by writing in the console:

cmake -G

For instance, in order to generate Makefiles and project files for the Code::Blocks IDE, this part of the call would look like the following:

cmake -G "CodeBlocks - Unix Makefiles" (...)

The additional artifact of the above call is the monero.cbp Code::Blocks project file in the build directory.

Debugging in Code::Blocks (CB)

First prepare the build directory for debugging using the following example command, assuming, that the path to the source dir is being held in the DIR_SRC variable, and using 2 cores:

cmake -S "$DIR_SRC" -G "CodeBlocks - Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTS=ON && make -j 2

After a successful build, open the monero.cbp with CB. From the CB's menu bar select the target, that you want debug. Assuming these are unit tests:

Build -> Select target -> Select target -> unit_tests

In order to lower the turnaround times, we will run a specific portion of code of interest, without having to go through all the time costly initialization and execution of unrelated parts. For this we'll use GTest's capabilities of test filtering. From the build directory run the following command to learn all the registered tests:

tests/unit_tests/unit_tests --gtest_list_tests

For example, if you're only interested in logging, you'd find in the list the label logging. and its subtests. To execute all the logging tests, you'd write in the console:

tests/unit_tests/unit_tests --gtest_filter="logging.*"

This parameter is what we need to transfer to CB, in order to reflect the same behaviour in the CB's debugger. From the main menu select:

Project -> Set program's arguments...

Then in the Program's arguments textbox you'd write in this case:

--gtest_filter="logging.*"

Verify if the expected UTs are being properly executed with F9 or select:

Build -> Build and run

If everything looks fine, then after setting some breakpoints of your choice, the target is ready for debugging in CB via:

Debug -> Start/Continue

To be done (and merged):

Multihost parallel compilation

https://github.com/monero-project/monero/pull/7160

Faster core_tests with caching

https://github.com/monero-project/monero/pull/5821

Precompiled headers

https://github.com/monero-project/monero/pull/7216

Unity builds

https://github.com/monero-project/monero/pull/7217