Skip to content

Linux development environment

Jean-Michel Gonet edited this page Jan 18, 2019 · 35 revisions

To write this part, my initial intention after installing a fresh Ubuntu distribution was to set up any well known IDE and click around until I could compile, debug and run the project. Boy, was I not naive! Several days later, I have had discarded Clion because it is a paying application, I had unsuccessfully tried Code::Blocks, Eclipse, and lost my patience before trying Qt Builder -- yet, I have not been able to find an acceptable IDE to just do the basic stuff with reasonable simplicity. And then I found this Stack Oveflow question «C++ IDE for Linux?» where accepted and most voted answer states that «UNIX is an IDE. All of it».

C++ - Linux is an IDE

Let's accept that in Linux we are not going to get a fancy IDE and content ourselves with a text editor. Two popular choices are:

The tool to debug code is gdb. It seems bleak, but you can actually do quite a job with it. Have a look on those videos:

In the first step, a little bit below, I will give short specific instructions for compiling with debug symbols, and debug the programs with gdb.

apt-get

This is the official package manager of most Linux distribution. Most popular applications are distributed through it and it is most usually pre-installed.

pkg-config

In a linux distribution, there is the highest chance that pkg-config is already installed. Anyway, you can give it a try; should it be already installed it will just tell you:

sudo apt-get update
sudo apt-get install pkg-config

To verify the installation, and seeing a list with all available packages:

pkg-config --list-all

Gtkmm

Gtkmm is the Gtk for C++:

sudo apt-get install libgtkmm-3.0-dev

To check if the library is available as a dependency:

pkg-config --list-all | grep gtkmm
gtkmm-3.0                      gtkmm - C++ binding for the GTK+ toolkit

CMake

You will need it to compile OpenCV, so you better install it now:

sudo apt-get install cmake

To verify that CMake is installed correctly:

cmake --version

OpenCV

Be sure to install Gtk3 before compiling OpenCV. If you don't, the CMake configuration links to Gtk2, and ends up in conflict as this project uses Gtk3.

As a prerequisite, you need to have the following libraries from apt-get:

# required:
sudo apt-get install \
   libgtk-3-dev \
   pkg-config \
   libavcodec-dev \
   libavformat-dev \
   libswscale-dev 
# Optional:
sudo apt-get install \
   python-dev \
   python-numpy \
   libjpeg-dev \
   libpng-dev \
   libtiff-dev \
   libjasper-dev \
   libdc1394-22-dev

Once you've installed all prerequisites, fetch the sources of the latest release of OpenCV from the official repository at github, and unzip it:

wget https://github.com/opencv/opencv/archive/4.0.1.zip
unzip 4.0.1.zip

Prepare and compile:

cd opencv-4.0.1
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=OFF -DCMAKE_INSTALL_PREFIX=/usr/local ..
make -j2  # Number of processors. Don't use more that you computer has.

Go for a walk; this takes ages. If process breaks, you can launch again by just retyping:

make -j2

When compilation is done, complete the installation:

sudo make install
sudo ldconfig

To check if the library is available as a dependency:

pkg-config --list-all | grep opencv
> opencv                         OpenCV - Open Source Computer Vision Library

You can now delete the sources folder; you don't need it any more:

cd ..
cd ..
rm -rf opencv-3.4.1
rm 3.4.1.zip

Git

To install Git:

sudo apt-get install git

And to verify that Git is present:

git --version
> git version 2.7.4

Launching application in Linux

Clone the example project, configure it with debug symbols, and build it:

cd go-to-your-working-folder
git clone https://github.com/cpp-tutorial/raspberry-cpp-gtk-opencv.git
cd raspberry-cpp-gtk-opencv
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug ../src
make

To debug with gdb, assuming that you're still in build folder:

gdb ./rascapp
[Now you're in gdb]
b main-window.cpp:10  # Place a break-point on line 10 of this file.
run                   # Run the program. It will stop at the break point.
where                 # It will show the stack trace
list                  # It will show some context.
print width           # Displays the value of this variable
n                     # Step over
s                     # Step into
c                     # To continue the program
q                     # Quit gdb 

Configure Vim as an IDE

I like to use the following plugins:

I also like to be able to set

To complete YouCompleteMeInstallation:

sudo apt install build-essential cmake python3-dev
cd ~/.vim/bundle/YouCompleteMe
python3 install.py --clang-completer

For example:

In the src folder, create a .vimrc file. This will be like a workspace configuration. In it, place:

set path+=src/**10
autocmd vimenter * NERDTreeVCS

To open include file:

  • gf : Open it.
  • C-W f : Open it in a separate tab.
  • C-W v : Open current file in a vertical split. Then you can gf to jump to the include file.

To go back after opening an include file:

  • gf : Open an include file.
  • Ctrl + O : Brings you back to the previous file.
  • Ctrl + I : If you're back from a file, then jumps into the next file.
  • The mnemonic would be O = OUT, I = IN => Ctrl - O brings you out, Ctrl brings you in. If every jump is like going through a door, that is. (comment by kronn in https://stackoverflow.com/questions/133626/how-do-you-return-from-gf-in-vim)

Create a symlink from the src folder to the compile_commands.json:

ln -s build/compile_commands.json compile_commands.json

To set up formatting:

set path+=src/**10              " For 'gf', looks in current folder, and up to 10 level of sub-sub-folders
set hidden                      " For 'gf', let's you go to next file without requiring to save current.                 
set cindent shiftwidth=4        " In C/C++, size of the tabulation increase each time you have a {
set tabstop=4                   " In all files, size of the Tab
set expandtab                   " Use spaces instead of Tab
autocmd vimenter * NERDTreeVCS  " Automatically opens NERDTree

To compile and run using vim and conque:

Git requires your credentials every single time

https://stackoverflow.com/questions/11403407/git-asks-for-username-every-time-i-push

Configure core dumps

Usually Linux distributions save a core dump file whenever an application crashes. However, there are multiple elements that may difficult you finding the core files.

The first step is setting the maximum size of the core file with ulimit -c. If it is 0, then core dumping is disabled:

ulimit -c
> 0
ulimit -c unlimited
ulimit -c
> unlimited

Then you need to check core_pattern configuration file to verify where, and under what name, the core files are dumped:

cat /proc/sys/kernel/core_pattern

Here you may find different situations:

  • You find a apport configuration like this:
    • |/usr/share/apport/apport %p %s %c %d %P
    • The pipe | means that the content of the core file is sent to an application.
    • Apport is used, among others, by Ubuntu to send crash reports to the authors of the applications installed via apt-get. As a consequence of its main goal, Apport just ignores crash reports of user applications like the one you're trying to develop and debug.
  • Or you find a relative path and file name.
  • Or you find an absolute path and file name.

Depending on your preference, you can either configure Apport not to ignore your core dumps, or save directly the core dumps without using another application.

Configure Apport

To configure Apport not to ignore crash reports of user applications, create configuration file called settings in folder ~/.config/apport. Most probably, the folder .config already exists, but you will need to create the apport folder:

cd ~/.config
mkdir apport
cd apport
vim settings

The content of the Apport settings file is the following:

[main]
unpackaged:true

Next time you have a core dump, you can use apport-cli, and then option [K] to locate it:

> (rascapp:12147): GLib-CRITICAL **: 18:02:14.510: Source ID 17 was not found when attempting to remove it
> Segmentation fault (core dumped)
apport-cli
>
>*** Send problem report to the developers?
>
>After the problem report has been sent, please fill out the form in the
automatically opened web browser.
>
> What would you like to do? Your options are:
>   S: Send report (9.1 MB)
>   V: View report
>   K: Keep report file for sending later or copying to somewhere else
>   I: Cancel and ignore future crashes of this program version
>   C: Cancel
> Please choose (S/V/K/I/C): K
> Problem report file: /var/crash/_home_xxx_Documents_gtk-opencv-patterns_build_app_rascapp.1001.crash

Crash reports generated by Apport are need to be unpacked it before you can access the contained core dump. I personally like to use a sub-folder in the temporary build directory of my work space because, as they get outdated as soon as you modify your source code, I don't want to keep them for long:

cd ~/where/my/project/is/gtk-opencv-simple/build
rm -rf crash
mkdir crash
cd crash
apport-unpack /var/crash/_home_xxx_Documents_gtk-opencv-patterns_build_app_rascapp.1001.crash . 

This will create plenty of files in the selected folder, and one of them is called CoreDump. This is the one you can open with gdb:

gdb ../app/rascapp CoreDump

Save core dumps in a file

Personally, I prefer the core dumps to be saved locally, besides the application that crashed. For this you can configure the core_pattern using a sysctl command (and you probably need to reset the ulimit -c):

sudo sysctl -w kernel.core_pattern=core.%e.%p
ulimit -c unlimited

With the above configuration, when your application has a core dump a file named core.rascapp.19936 appears within your current folder. If, like me, you run your application from the build temporary folder, then you can open the core dump with the following command:

gdb app/rascapp core.rascapp.19936

Using core dumps

When opening gdb with a core dump you need to be very sure that is has be produced with the exact same application you're loading. When you're developing, you change your application several times per minute and you don't always remember. So, if possible, recompile, relaunch, reproduce the crash, and then open it with gdb.

  • where shows the stack trace. It informs you in what method the fault happened, plus which method called it, and which method called the method which called, etc. As crashes may occur in a library, you have to look for the first entry where it is your code.
  • frame n navigates to the nth entry of the stack trace. where displays a number besides each entry of the stack trace.

See more about gdb commands here:

/settings More information about this topic:

troubleshooting

core file size: cannot modify limit

Depending on your Linux distribution, you may find the following error when you modify the maximum core file size:

-bash: ulimit: core file size: cannot modify limit: Operation not permitted

The following article helps you to properly configure this limit:

Segmentation fault while compiling.

If you get an error like the following:

[ 95%] Building CXX object modules/stitching/CMakeFiles/opencv_perf_stitching.dir/perf/opencl/perf_stitch.cpp.o

c++: internal compiler error: Segmentation fault (program cc1plus)
Please submit a full bug report,
with preprocessed source if appropriate.
See <file:///usr/share/doc/gcc-7/README.Bugs> for instructions.
modules/stitching/CMakeFiles/opencv_perf_stitching.dir/build.make:62: recipe for target 'modules/stitching/CMakeFiles/opencv_perf_stitching.dir/perf/opencl/perf_stitch.cpp.o' failed
make[2]: *** [modules/stitching/CMakeFiles/opencv_perf_stitching.dir/perf/opencl/perf_stitch.cpp.o] Error 4
CMakeFiles/Makefile2:4438: recipe for target 'modules/stitching/CMakeFiles/opencv_perf_stitching.dir/all' failed
make[1]: *** [modules/stitching/CMakeFiles/opencv_perf_stitching.dir/all] Error 2
Makefile:162: recipe for target 'all' failed
make: *** [all] Error 2

This is usually a problem with not having enough memory. If, like me, you're using a virtual Linux machine, then the solution is simply increasing the available memory. If not, then try not having multi-threaded compilation (don't use make -j option).

Se more about this issue: https://github.com/opencv/opencv/issues/8552

Clone this wiki locally