-1

I am trying to learn how to code on a Raspberry PI. I am coming from coding using Windows and VS Code. Now I am using Linux Mint 19.1 and ssh to access Raspbian 4.14.

The problem is that, after a long battle with downloading the library that I am trying to use, after installing a compiler, creating a file, and finding the right command to run and include paths I get undefined reference to errors.

I am trying to compile the simplest example code from https://github.com/hzeller/rpi-rgb-led-matrix because I started with this project. I don't have any other code or example.

Here are the commands that I've wrote in command line:

sudo apt-get install g++
mkdir 4panel
cd 4panel
sudo nano main.cpp
git clone https://github.com/hzeller/rpi-rgb-led-matrix.git
sudo g++ -Wall -Irpi-rgb-led-matrix/include  main.cpp -o main

The following commands should be:

sudo chmod +x main
./main

main.cpp contains the same code as https://github.com/hzeller/rpi-rgb-led-matrix/blob/master/examples-api-use/minimal-example.cc

#include "led-matrix.h"

#include <unistd.h>
#include <math.h>
#include <stdio.h>
#include <signal.h>

using rgb_matrix::GPIO;
using rgb_matrix::RGBMatrix;
using rgb_matrix::Canvas;

volatile bool interrupt_received = false;
static void InterruptHandler(int signo) {
  interrupt_received = true;
}

static void DrawOnCanvas(Canvas *canvas) {
  /*
   * Let's create a simple animation. We use the canvas to draw
   * pixels. We wait between each step to have a slower animation.
   */
  canvas->Fill(0, 0, 255);

  int center_x = canvas->width() / 2;
  int center_y = canvas->height() / 2;
  float radius_max = canvas->width() / 2;
  float angle_step = 1.0 / 360;
  for (float a = 0, r = 0; r < radius_max; a += angle_step, r += angle_step) {
    if (interrupt_received)
      return;
    float dot_x = cos(a * 2 * M_PI) * r;
    float dot_y = sin(a * 2 * M_PI) * r;
    canvas->SetPixel(center_x + dot_x, center_y + dot_y,
                     255, 0, 0);
    usleep(1 * 1000);  // wait a little to slow down things.
  }
}

int main(int argc, char *argv[]) {
  RGBMatrix::Options defaults;
  defaults.hardware_mapping = "regular";  // or e.g. "adafruit-hat"
  defaults.rows = 32;
  defaults.chain_length = 1;
  defaults.parallel = 1;
  defaults.show_refresh_rate = true;
  Canvas *canvas = rgb_matrix::CreateMatrixFromFlags(&argc, &argv, &defaults);
  if (canvas == NULL)
    return 1;

  // It is always good to set up a signal handler to cleanly exit when we
  // receive a CTRL-C for instance. The DrawOnCanvas() routine is looking
  // for that.
  signal(SIGTERM, InterruptHandler);
  signal(SIGINT, InterruptHandler);

  DrawOnCanvas(canvas);    // Using the canvas.

  // Animation finished. Shut down the RGB matrix.
  canvas->Clear();
  delete canvas;

  return 0;
}

Errors:

/tmp/cci8MGL5.o: In function `main':
main.cpp:(.text+0x264): undefined reference to `rgb_matrix::RGBMatrix::Options::Options()'
main.cpp:(.text+0x2a8): undefined reference to `rgb_matrix::CreateMatrixFromFlags(int*, char***, rgb_matrix::RGBMatrix::Options*, rgb_matrix::RuntimeOptions*, bool)'
collect2: error: ld returned 1 exit status

Possible fixes that I found:

    1. Link .cpp files in a strict order when compiling: sudo g++ main1.cpp main2.cpp
    1. This
    1. The need of a makefile

While searching for similar issues and hopefully finding some magic fix, I ended up more puzzled than before. I have no idea if what I did is what I was supposed to do.

    1. What cpp files to link if I have just one ?
    1. Do I need to link all the .cpp and .h files that the library has ?
    1. I don't understand a thing about makefile or why it even exists.

My issue may be specific to my situation but I believe that the answers will help me with future projects.

You are free to answer all of my questions and misunderstandings and help me understand what is going on or answer just the question related to the title: Why makefile ?

bleah1
  • 471
  • 3
  • 18
  • 5
    Do not `sudo g++ ...`. Why would you want g++ to run as root? – Benjamin T May 28 '19 at 14:13
  • 3
    A Makefile is a sort of script that automates (all or part of) the build process. Before dealing with `make`, you should already be familiar with how to invoke your compiler and in particular how to produce object files and how to link them to produce an executable. – melpomene May 28 '19 at 14:15
  • Please ask one question per post. – HolyBlackCat May 28 '19 at 14:21
  • You do not need/have a makefile. Your error is caused by the linker and it is desperate to find the implementation of the used library (usually a .a/.lib file). You need to tell your compiler (g++) to add the library to the linker input. – Zaiborg May 28 '19 at 14:24
  • You probably need to do following: Go to `rpi-rgb-led-matrix/lib` directory, run `make` from it. It should compile the library and produce `librgbmatrix.a`. Add `-Lrpi-rgb-led-matrix/lib -lrgbmatrix` to the `g++` command to link the library (the flag should come after `main.cpp`). – HolyBlackCat May 28 '19 at 14:25
  • 2
    You **never** have to use makefile. But when you have 10, 50, 100 or 1000 files to compile, you start to think that just using command line g++ is not the best solution. `make` is not much more than a simple script to call compiler, with possibility of having several different calls defined. – Yksisarvinen May 28 '19 at 14:27
  • I would rather not use a makefile but use cmake instead. – Devolus May 28 '19 at 14:44
  • First you should learn how a compiler works and what happens behind your IDE. Learn what your compiler does on windows in visual studio code. You can compile your code in Powershell with visual c++. After you learned this very important part of software development on your favourite platform, you know what to do on most other platforms. Makefile is a tool that also can be used on windows to automate your build process. – Thomas Sablik May 28 '19 at 14:50

1 Answers1

3

The problem is that, after a long battle with downloading the library that I am trying to use, after installing a compiler, creating a file, and finding the right command to run and include paths I get undefined reference to errors.

There are already numerous questions and answers on SO pertaining to such problems, especially What is an undefined reference/unresolved external symbol error and how do I fix it?

Possible fixes that I found:

    1. Link .cpp files in a strict order when compiling: sudo g++ main1.cpp main2.cpp
    1. [SO question with answers saying roughly the same as the previous]

Not typically relevant. Although link order of different objects / libraries is significant, that rarely affects the case when all the needed C and / or C++ source files are specified in the same compilation command.

    1. The need of a makefile

Using make does not inherently solve the problem, and it is certainly not necessary for solving the problem. Writing a makefile that provides for a successful build, whether directly or via a build tool such as CMake or the Autotools, requires you to understand at least at a high level how compilers and linkers work, what their inputs and outputs are, and what their arguments and options mean.

    1. What cpp files to link if I have just one ?

You do not link a .cpp (directly) at all. You compile it and link the result to any needed libraries and any other objects. g++ will try to do that all in one step by default, in which case the process is conventionally called "compiling", not "linking", even though both functions are performed. g++ can be made to compile only, without linking, by specifying the -c option to it (which is common in makefiles, as it turns out), and it will happily link objects and libraries without compiling anything if you don't name any source files to it.

Anyway, your case is not at all that of just one .cpp file. It is your one .cpp file plus all those of the library you are trying to use.

    1. Do I need to link all the .cpp and .h files that the library has ?

You do not need to compile (directly) or link any .h files. But if you want to use the library whose sources you downloaded, you do need to compile all the sources, and you probably should link them into an actual library. Furthermore, unless you produce and use a static library, you should also install the library you build. It looks like the library sources include a makefile, so you would be well advised to use make to perform those steps.

    1. I don't understand a thing about makefile or why it even exists.

A makefile is the input to make. A well-written one defines rules for how to build one or more "targets", and expresses the prerequisites (generally original sources or other targets) for doing so. make uses these, together with a set of built-in rules, to figure out what steps to take to build the target(s) you ask it to build, and also what steps it can skip. It is typical, for example, to write makefiles so that if you build a multisource project, modify only one source file, and then build again, only the modified source gets recompiled.

This may seem trivial when you're used to projects with only a handful of sources, but it becomes important in larger projects, where full rebuilds are expensive -- many hours, in some cases. But even if a full build takes only a few minutes, if you really only needed to spend a few seconds then that adds up to a lot of wasted time over a full day of work.

Overall, then:

When do I need to use/have a makefile?

Never. But providing a good one and using make to build your project has these among its advantages:

  • memorializing all the needed build commands, including options and arguments, in a persistent, actionable form, and therefore
  • providing for consistent, automated builds.

Those can also be achieved by a simple build script, but make also can give you

  • faster builds by building only those pieces that are out of date, and
  • built-in knowledge of how to build certain kinds of targets from corresponding sources.
John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Thank you for your patience to answer all of my questions. Even though the issue persists, I know have a better understanding of the purpose of compilers, link editors and makefile. – bleah1 May 29 '19 at 11:16