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:
Link .cpp files in a strict order when compiling: sudo g++ main1.cpp main2.cpp
This
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.
What cpp files to link if I have just one ?
Do I need to link all the .cpp and .h files that the library has ?
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 ?
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:
Link .cpp files in a strict order when compiling: sudo g++ main1.cpp main2.cpp
[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.
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.
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.
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.
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.
Related
I've been having some trouble setting up a custom Vulkan build and development environment with G++ and VSCode. G++ doesn't seem to be linking to the proper library files, and is not recognizing only one of the Vulkan functions I've defined in main.cpp. That, or it's not properly finding the header files. I followed a video tutorial and did my own tweaking to make it work. (You can find it here https://www.youtube.com/watch?v=tRQ3zqCiKdQ). He creates a .bat file to run the compiler command and sets up some boilerplate tasks.json and launch.json files. The .bat file runs fine and makes it so that I don't have to type out file paths each time. Those work fine. And then I've copied his code as well just to get the build environment working, which I'm stuck on.
I'll admit, I'm not a wizard with command line compilers, but I just can't seem to find any information online that can help me. It's either outdated or the answer doesn't fix my issue. So I thought I'd try here. (first question btw).
I've got a basic, very recent and up-to-date Vulkan installation, a main.cpp file, a build.bat file, and g++ version 11.2.0 (according to MSys2, the latest version). I'm on Windows 64 bit running VSCode. I've included some in order, ending with a capture of my working directory. Afterwards, I'll list what I've tried.
Main.cpp
#include <iostream>
#include <vulkan/vulkan.h>
#include <vulkan/vulkan.hpp>
#include <vulkan/vulkan_core.h>
using namespace std;
int main(){
VkApplicationInfo appInfo = {};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "Pong";
appInfo.pEngineName = "PongEngine";
VkInstanceCreateInfo instanceInfo = {};
instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instanceInfo.pApplicationInfo = &appInfo;
VkInstance instance;
VkResult result = vkCreateInstance(&instanceInfo, NULL, &instance);
if(result == VK_SUCCESS){
cout << "Successful!" << endl;
}
}
Build.bat
#echo off
SET include=-I ./src -I C:/VulkanSDK/1.2.198.1/Include/
SET links= -L /C:/VulkanSDK/1.2.198.1/Lib/vulkan-1.lib
#echo "Building main..."
g++ -Wall %include% %links% -o main src/main.cpp
Directory
Root
|-----src
|-main.cpp
|-build.bat
I have tried almost everything. This is always the output:
"Building main..."
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\brado\AppData\Local\Temp\ccj9NixH.o:main.cpp:(.text+0xabe): undefined reference to `vkCreateInstance'
collect2.exe: error: ld returned 1 exit status
The terminal process "E:\coding\vulkan\personal_vulkan_expirimenting\build.bat" terminated with exit code: 1.
Despite -L supposedly specifying directories to search in, anytime I don't include vulkan-1.lib on the -L tag, it breaks.
I've tried using -l to specify the specific library and that doesn't seem to work
I feel like I've tried every flag under the sun. Someone somewhere said it might have to do with -m64 flag but that wasn't it.
I've added in two seemingly redundant header files that I've manually searched for vkCreateInstance in and included them in the hopes that that would trigger it but in vain
I've edited the file paths every which way to see if the formatting was the issue
I have read and checked the g++ and Vulkan documentation to see if anything could help and I could find seemingly nothing that would have helped. Perhaps I'm looking in the wrong place. But I've been googling for hours.
Before this whole fiasco started, I was also trying to use GLFW and GLM as per the basic Vulkan tutorial that's provided, and that was also having linking problems, which to me, narrows it down to how I'm using the compiler.
What's so confusing is that the intellisense on VS Code recognizes the function, and the linker has no issue with the other functions. It may be a limitation in my understanding of compilers, or I've tunnel-visioned and am not seeing outside the problem, I don't know. I'll admit I'm not insanely familiar with g++, but as I tried to get more familiar with it over the course of this problem (that I've been on for the last couple hours) I couldn't find any documentation Let me know what other information I can provide, maybe there's something I'm leaving out. Thanks so much!
Here is an small example I did with clang++ :
===filename===
calc_mean.cpp
===filename===
===filecontent===
double mean(double a, double b) {
return (a+b) / 2;
}
===filecontent===
===filename===
calc_mean.h
===filename===
===filecontent===
double mean(double, double);
===filecontent===
===filename===
commands.sh
===filename===
===filecontent===
#/usr/bin/env bash
clang++ -c calc_mean.cpp -o calc_mean.o
ar rcs libmean.a calc_mean.o
clang++ -c -fPIC calc_mean.cpp -o calc_mean.o
gcc -shared -W1,-soname,libmean.so.1 -o libmean.so.1.0.1 calc_mean.o
clang++ main.cpp -L. -lmean -o dynamicmain -v
===filecontent===
===filename===
main.cpp
===filename===
===filecontent===
#include <stdio.h>
#include "calc_mean.h"
int main(int argc, char const* argv[])
{
double v1, v2, m;
v1 = 5.0;
v2 = 6.0;
m = mean(v1, v2);
printf("Mean: %f\n", m);
return 0;
}
===filecontent===
It worked perfectly. Now turn to eclipse, I created a project with the dynamic lib generated above in the libs folder:
(source: p.im9.eu)
Adjusted -L and -l settings accordingly:
(source: p.im9.eu)
Got these errors:
(source: p.im9.eu)
Other things I have tried:
(source: p.im9.eu)
(source: p.im9.eu)
The errors stayed the same. I almost want to bang my head against a wall now. Should I start learning cmake already?
update
I added the header file also this time, but eclipse still can't resolve the function mean (through code analysis).
It compiles without an error though, but when I run the output binary, it says:
dyld: Library not loaded: libmean.so
Referenced from: /Users/kaiyin/personal_config_bin_files/workspace/testuselib/Debug/testuselib
Reason: image not found
Edit2:
It hit me that you're on Mac, and I remembered that there's something funny about library loading. So, there are a couple reasons why you'd get Image Not Found. The below still applies, but there's another reason it could be failing. See dyld: Library not loaded: libqscintilla2.5.dylib
I don't know if eclipse on Mac even ships with GCC, or if it's clang only on that platform, but try setting DYLD_LIBRARY_PATH as a quick test to see if it's just Mac Being Special. https://superuser.com/questions/282450/where-do-i-set-dyld-library-path-on-mac-os-x-and-is-it-a-good-idea
Edit:
Yay it compiles! Now we're hitting a linking error. This one is actually pretty fun, and isn't the "common" one I listed below (namely, Unresolved Symbols). This error, "Image Not Found" usually means that the Linker found the library, but could not use it because it was compiled in an incompatible manner.
Why is it in any incompatible format? Welcome to the one feature of C++ that I hate is missing, and one of the reasons pretty much every library out there provides a C interface instead of a C++ interface.
C++ Does Not Provide a stable ABI (Application Binary Interface). This means that libraries compiled with different compilers (or even just different versions of the same compiler may not work together. 99/100 they will just outright refuse to link/work, but even if they do link, you'll get very weird, hard-to-impossible to track down bugs, etc.
Here's the tl;dr: If you want your static lib to be C++ (which i recommend) and have a C++ interface, you need to make sure the exact same version of the compiler is used to compile both your application and the static library. The easiest way to do this is to have eclipse build both the static library and the application.
This is hopefully changing with the next version of C++, as Herb Sutter has put forward a proposal to create a platform defined C++ ABI.
Original:
You need to add the folder containing calc_mean.h to the "Additional Includes" for c++ generation. You can think of include statement as cutting and pasting the contents of the file at that exact line. The error is saying "hey, i went looking for a file called calc_mean.h and couldn't find it." You need to link the library and the header (so main.cpp knows the function)
If it was an error saying "unresolved symbols", with the symbols being in your library, then you would know you've messed up with adding the library or library path (-L).
Cmake is a good tool, but it is nice to know how to use an ide. The basic steps (add library name, add library path, add directory containing library headers) are the same in eclipse, netbeans, visual studio, xcode, etc)
I'm a novice at C++. Be patient if this is incoherent. I'm called upon to build a large system on linux that was originally built on OS X, where it works fine. The original authors are no longer with the company. The build system makes use of autotools, but there are also some hand made Makefiles which walk through the system calling the auto-made Makefiles. I've managed to get all of the c++ code compiled. The build system also uses libtools, and shared libraries are produced and deposited in /usr/local/lib.
So now I'd like to use these libraries. I've written a short program that simply instantiates an object of class ds_dictionary and calls one of its methods. Here it is:
#include <iostream>
#include <DSUtils/DSUtils.h>
int main (int argc, char * const argv[]) {
int32_t integer_data=123;
char key_alice_integer[] = "alice_integer";
ds_dictionary my_dict;
my_dict.add_int(key_alice_integer, integer_data);
return 0;
}
I compile this with
g++ -lDSUtils -o main my_test_code.cpp
With the result:
//usr/local/lib/libDSUtils.so: undefined reference to `ds_breakdown_from_time_interval'
//usr/local/lib/libDSUtils.so: undefined reference to `ds_date_breakdown_with_string'
//usr/local/lib/libDSUtils.so: undefined reference to `ds_seconds_duration_of_interval'
... (about 25 lines like these)
collect2: ld returned 1 exit status
Let's look inside the library:
garyp#VM:/usr/local/lib$ nm libDSUtils.so | grep ds_breakdown_from_time
U ds_breakdown_from_time_interval
The "U" in the line above ... does that mean that the library wasn't built correctly?
Am I calling g++ correctly?
Do I have to put something in the code to tell it that I'm using functions found in that library?
What are possible errors? Where should I start poking around?
EDIT:
Aha. The library DSUtils is built from several c++ sources. There is one c program in the source, and it contains all of the problem functions. The Makefile system doesn't deal at all with that one c file. That c program compiles. Ideally I suppose I'd figure out how to modify the Makefile to compile that file and add it to the library, but I'm not to the point where I can figure out how to do that.
Can I add the .o file to the existing library? How? Create a library with one file? etc?
EDIT_2: I simply did
g++ -o main -lDSUtils main.o my_new_objectfile.o
and the thing compiles, links, and runs without error. Should that work? After fixing a logic bug, it does work.
This
U ds_breakdown_from_time_interval
tells me that ds_breakdown_from_time_interval will be resolved by another library during runtime. So I am guessing you need to link to the library that defines ds_breakdown_from_time_interval.
I am writing a fairly large C++ shared-object library, and have run into a small issue that makes debugging a pain:
If I define a function/method in a header file, and forget to create a stub for it (during development), since I am building as a shared object library rather than an executable, no errors appear at compile-time telling me I have forgotten to implement that function. The only way I find out something is wrong is at runtime, when eventually an application linking against this library falls over with an 'undefined symbol' error.
I am looking for an easy way to check if I have all the symbols I need at compile time, perhaps something I can add to my Makefile.
One solution I did come up with is to run the compiled library through nm -C -U to get a demangled list of all undefined references. The problem is this also comes up with the list of all references that are in other libraries, such as GLibC, which of course will be linked against along with this library when the final application is put together. It would be possible to use the output of nm to grep through all my header files and see if any of the names corresponding.. but this seems insane. Surely this is not an uncommon issue and there is a better way of solving it?
Check out the linker option -z defs / --no-undefined. When creating a shared object, it will cause the link to fail if there are unresolved symbols.
If you are using gcc to invoke the linker, you'll use the compiler -Wl option to pass the option to the linker:
gcc -shared ... -Wl,-z,defs
As an example, consider the following file:
#include <stdio.h>
void forgot_to_define(FILE *fp);
void doit(const char *filename)
{
FILE *fp = fopen(filename, "r");
if (fp != NULL)
{
forgot_to_define(fp);
fclose(fp);
}
}
Now, if you build that into a shared object, it will succeed:
> gcc -shared -fPIC -o libsilly.so silly.c && echo succeeded || echo failed
succeeded
But if you add -z defs, the link will fail and tell you about your missing symbol:
> gcc -shared -fPIC -o libsilly.so silly.c -Wl,-z,defs && echo succeeded || echo failed
/tmp/cccIwwbn.o: In function `doit':
silly.c:(.text+0x2c): undefined reference to `forgot_to_define'
collect2: ld returned 1 exit status
failed
On Linux (which you appear to be using) ldd -r a.out should give you exactly the answer you are looking for.
UPDATE: a trivial way to create a.out against which to check:
echo "int main() { return 0; }" | g++ -xc++ - ./libMySharedLib.so
ldd -r ./a.out
What about a testsuite ? You create mock executables that link to the symbols you need. If the linking fails, it means that your library interface is incomplete.
I had the same problem once. I was developing a component model in C++, and, of course, components should load at runtime dynamically. Three solutions come to mind, that were the ones I applied:
Take some time to define a build system that is able to compile statically. You'll lose some time engineering it, but it will save you much time catching these annoying runtime errors.
Group your functions in well-known and well-understood sections, so that you can group of functions/stubs to be sure that each corresponding function has its stub. If you take the time on documenting it well, you can write perhaps a script that checks the definitions (via, for example, its doxygen comments) and check the corresponding .cpp file for it.
Do several test executables that load the same set of libraries and specify the RTLD_NOW flag to dlopen (if you're under *NIX). They will signal the missing symbols.
Hope that helps.
I've tried looking at similar problems, but could not easily find one that helped my problem.
I've created a project in C++ and am working on UNIX to compile, link, and run it. My specific problem is an undefined reference to a method I declare in a separate file.
In the file SharedCache.cpp, I have the following method:
int SharedCache::replaceLine(ullong address){
int evictPID = -1;
int cacheSet = calcCacheSet( address );
//random uniformly-distributed value for cache line
float numLines = static_cast<float>(CACHE_LINES_PER_SET);
uint cacheLine = static_cast<uint>(uniformDistr( numLines ));
if(cache[cacheSet][cacheLine] != NULL){
evictPID = cache[cacheSet][cacheLine]->PID;
}
uint PID= calcPID(address);
uint tag= calcTag(address);
cache[cacheSet][cacheLine]->setLine(PID, tag); //mutex method
return PID;
}
The line uint cacheLine = static_cast<uint>( uniformDistr( numLines )); makes a call to the function I want to use from another file. The linker error is an undefined reference to this method.
uniformDistr( float ); is declared in the header distributions.h and defined in distributions.cpp. In my project options I set the linker flag -distributions and I also compiled the distributions.cpp to make sure a distributions.o file exists to link with.
From here, I don't know where to go, because this has not solved the problem.
Without more precise information on which compiler/linker commands were invoked and the exact error outputs, it is difficult to provide a good answer.
However, from your description of what you did, it seems that you are not passing distributions.o to the linker. Unlike other languages where the compiler/linker search for object files to link in automatically, C++ linkers require an explicit specification of the objects to link together.
Your use of -ldistributions here is incorrect: the -l flag is used to link to a static or dynamic library (respectively .a and .so files on Linux), whereas you want to specify another object file that the linker should consider. Specifying -ldistributions makes the linker look for distributions.a or distributions.so in the standard library locations.
Basically, your linker invocation now looks something like this (probably with many more flags and libraries):
gcc -o my_program SharedCache.o -ldistributions
To correctly link the distributions code in, you need to make it look something like (again, many flags and libraries probably missing compared to the real thing):
gcc -o my_program SharedCache.o distributions.o
This should resolve the missing symbols issue and produce a working binary (or at the very least a different error ;-) ). How to do this in KDevelop however I do not know.
I've not used KDevelop, however, on the command line you would just add distributions.o as an input file to the linking process. No need for dashes or leaving off the .o extension.
Alternatively, can you just add distributions.cpp to your KDevelop project? That way it should get compiled and linked automatically (this is how it works in things like Visual Studio or Eclipse).
Did you add the distributions.cpp to your makefile? Also I believe the required linker flag is -ldistributions.