I am trying to add a cpp file to arduino project that has the following setup...
project
--folder
--foo.h
--foo.cpp
--project.ino
I have a #include "folder/foo.h at the top of project.ino. However while the header provides the prototype of the function, the function definition is in the cpp file. When I try to compile the code using the Arduino IDE, it fails with error
Undefined reference to 'bar()'
and bar() is located in foo.cpp
I looked at this but I do not have a setting for sketch/import library (however I do have sketch/include library, however I did not see anything close to using a custom folder location)
I looked at this too. But same as above, that setting does not exist in my ide. (Which I downloaded recently)
Code
//project.ino
#include "folder/foo.h"
void setup() {
Serial.begin(9600);
}
void loop() {
bar();
}
//folder/foo.h
#include "Arduino.h"
void bar();
//folder/foo.cpp
#include "foo.h"
void bar() {
Serial.println("bar");
}
Error
/tmp/ccNTRFfU.ltrans0.ltrans.o: In function `loop':
/home/temporary/project/project.ino:9: undefined reference to `bar()'
collect2: error: ld returned 1 exit status
exit status 1
What I would expect to happened is a way to link the cpp folder without having to put all the files in the same root folder of the project.
--Edit 1:
added code
--Edit 2:
added #include "Arduino.h"
--Edit 3:
added Serial.begin(9600);
How to properly include C/C++ headers and source files in your Arduino Project.
This answer has been tested and compiled to ensure it works. (Completed in Linux Ubuntu with the Arduino 1.8.7 IDE).
You have 2 problems.
1st: Arduino's unusual build process (described here) doesn't allow including from sub-folders in your project directory where your .ino file for this project is located.
[UPDATE: THIS ONE MAY HAVE BEEN MY MISTAKE ONLY, NOT YOURS, when I was duplicating your code on my PC: I accidentally used foo.c instead of foo.cpp]
2nd: C++ can only be used inside C++ source files, so you must change foo.c to foo.cpp, since Serial.println() is a C++ call to a C++ class's (Serial's) println() method.
To fix 1, simply change your folder structure to have everything in a single folder:
project
├── foo.cpp
├── foo.hh
└── project.ino
I present an alternate fix for #1 below too.
To fix 2, (this is mandatory!) make foo.c --> foo.cpp and (optionally, but recommended, to show it is a C++ header file) foo.h --> foo.hh. Update your includes in the .ino and .cpp file now too to #include "foo.hh".
That's it! Now close the Arduino IDE, then reopen it and reopen your project, and you'll see the following new tabs show up:
It now compiles just fine!
Learning: how did I figure this out?
First, turn on verbose compilation in the Arduino IDE: File --> Preferences --> check the box for "Show verbose output during 'compilation'".
Now, when you compile, all errors will show up in the bottom of the IDE window, as well as the exact compilation or linking commands which throw the error.
Once I fixed the folder structure, but your files were still C instead of C++ files, I saw this error:
Compiling sketch...
/home/gabriel/Downloads/Install_Files/Arduino/arduino-1.8.7/hardware/tools/avr/bin/avr-gcc -c -g -Os -w -std=gnu11 -ffunction-sections -fdata-sections -MMD -flto -fno-fat-lto-objects -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10807 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR -I/home/gabriel/Downloads/Install_Files/Arduino/arduino-1.8.7/hardware/arduino/avr/cores/arduino -I/home/gabriel/Downloads/Install_Files/Arduino/arduino-1.8.7/hardware/arduino/avr/variants/eightanaloginputs /tmp/arduino_build_233569/sketch/foo.c -o /tmp/arduino_build_233569/sketch/foo.c.o
/tmp/arduino_build_233569/sketch/foo.c: In function 'bar':
foo.c:9:5: error: 'Serial' undeclared (first use in this function)
Serial.println("bar");
^
/tmp/arduino_build_233569/sketch/foo.c:9:5: note: each undeclared identifier is reported only once for each function it appears in
exit status 1
'Serial' undeclared (first use in this function)
Notice the file it failed to compile was /tmp/arduino_build_233569/sketch/foo.c, and that the avr-gcc C compiler (rather than the avr-g++ C++ compiler) was in use at the time.
I then opened the /tmp/arduino_build_233569/sketch/foo.c file to examine it and look for anything unusual about it.
Next, I used Eclipse to start tracking down includes, to see where Serial gets pulled in (it should have been obvious to me already what the problem was, but I didn't see it yet). I found the following:
Arduino.h is found in "Arduino/Source/Arduino/hardware/arduino/avr/cores/arduino/Arduino.h". It includes "HardwareSerial.h". This header externs the Serial object:
#if defined(UBRRH) || defined(UBRR0H)
extern HardwareSerial Serial;
#define HAVE_HWSERIAL0
#endif
HOWEVER, looking back at Arduino.h you'll see that HardwareSerial.h is ONLY included if you are compiling with C++:
#ifdef __cplusplus <========= This means that the following headers are ONLY included if you are compiling with C++! BOOM! That's when it hit me! You're compiling a C file with the C compiler to access a C++ object. That's not ok. Use the C++ compiler!
#include "WCharacter.h"
#include "WString.h"
#include "HardwareSerial.h"
#include "USBAPI.h"
#if defined(HAVE_HWSERIAL0) && defined(HAVE_CDCSERIAL)
#error "Targets with both UART0 and CDC serial not supported"
#endif
#ifdef __cplusplus means that the headers above are ONLY included if you are compiling with C++! That's when it hit me! You're compiling a C file with the C compiler to access a C++ object. That's not ok. You must use the C++ compiler instead. Do this simply by changing foo.c to foo.cpp. Done.
Alternate fix for your problem #1 (the folder structure):
Find your "Sketchbook location" from Arduino IDE: File --> Preferences. Mine, for example, is /home/gabriel/dev/Arduino/Sketches.
Now, go there and create a "libraries" folder. For me that would now be /home/gabriel/dev/Arduino/Sketches/libraries. Everything inside this folder is now considered an Arduino "library", and can be included. Move foo.h [do NOT use foo.hh in this case] and foo.cpp there, like this:
/home/gabriel/dev/Arduino/Sketches/libraries/foo
├── foo.cpp
└── foo.h <==== NOT foo.hh in this case!
Now close and reopen the Arduino IDE, then go to Sketch --> Include Library --> foo, and it will automatically add the following line for you:
#include <foo.h>
The reason you can't use foo.hh in this case is simply because Arduino is looking for .h files only when you add your library include using the menus in this way. That's a bug as far as I'm concerned, and should probably be reported to the Arduino developers. Feel free to take that on.
Addendum:
16 Apr. 2019:
A google search for "arduino add include path" led me to this: https://forum.arduino.cc/index.php?topic=445230.0, where user #pert says:
In recent versions of the Arduino IDE(including 1.6.10) if you want to include libraries from the sketch folder you need to put them in a src subfolder. For example:
Blink
|_Blink.ino
|_src
|_BlinkLib
|_BlinkLib.h
He then says you can include like this:
#include "src/BlinkLib/BlinkLib.h"
I haven't tried this, but that'd be super useful if it works. Give it a shot and let me know if it works. Be sure to tell us which OS and Arduino IDE version you are using.
See Also:
Additional discussion on Github here: https://github.com/arduino/Arduino/issues/5186.
The official Arduino Library specification here: https://arduino.github.io/arduino-cli/latest/library-specification/.
Open a tab in your project for each file.
You can create a new file or import an existing file into your project.
This way you can use multiple *.ino, *.c, *.cpp and *.h files. I didn't find a way to import a local directory or to configure your project structure.
Place your folder inside libraries folder that is a subdirectory of your sketchbook directory.
Open Arduino IDE (if it is already open, quit it and reopen).
Go to Sketch->Include Library. You will find folder under Contributed Libraries section.
Choose folder and you are good to go.
According to "Sketch specification":
In Arduino IDE 1.6.5-r5 and older, no recursive compilation was done.
In Arduino IDE 1.6.6 - 1.6.9, recursive compilation was done of all subfolders of the sketch folder.
In Arduino IDE 1.6.10 and newer, recursive compilation is limited to the src subfolder of the sketch folder.
So, putting your source code files into 'src' subfolder should solve the problem. Tested in "Arduino IDE" v2.0.3.
Related
I am following the course "Introduction to Deep Learning with Xilinx SoCs Technical Training Course" for the Ultra96v2 board and reached Lab No. 5.
I am able to follow along until I am supposed to build the project in the SDK.
It fails and tells me errors like these:
15:49:06 **** Incremental Build of configuration Debug for project mnist_file_io ****
make all
Building file: ../src/mnist_file_io.cc
Invoking: ARM v8 Linux g++ compiler
aarch64-linux-gnu-g++ -Wall -O0 -g3 -I/media/user/6b04b610-ff80-4702-a575-b0b1a78fbafb/training/AvnetTTC/DPU/U96AI_student_20200115/U96AI/2018_3/work/lab5/workspace/ExtraIncludes -I/usr/include -c -fmessage-length=0 -MT"src/mnist_file_io.o" --sysroot=YSROOT -MMD -MP -MF"src/mnist_file_io.d" -MT"src/mnist_file_io.o" -o "src/mnist_file_io.o" "../src/mnist_file_io.cc"
In file included from ../src/mnist_file_io.cc:9:0:
/tools/Xilinx/SDK/2018.3/gnu/aarch64/lin/aarch64-linux/aarch64-linux-gnu/include/c++/7.3.1/cmath:45:15: fatal error: math.h: No such file or directory
#include_next <math.h>
^~~~~~~~
compilation terminated.
src/subdir.mk:21: recipe for target 'src/mnist_file_io.o' failed
make: *** [src/mnist_file_io.o] Error 1
It doesnt find the header file, although it is included in the paths which were provided by the tutorial as well as by me. Actually, two additional files haven't been found:
#include <opencv2/opencv.hpp>
#include <dnndk/dnndk.h>
I was able to include them by picking them by hand from the directories where they were in and adding them to an extra directory in which the Xilinx SDK should search for headers.
But this brings up the question: Why aren't they found in the first place? After correct installation and following the instructions in the above mentioned tutorial, shouldn't I be all set up to just build it?
Actually, by using the installer on the Xilinx Download website (Xilinx_SDK_2018.3_1207_2324_Lin64.bin), the SDK didn't start because there were some files missing for the SDK program (eclipse and some other stuff). So it just started once I copied those files from the other installation (Vivado, etc.). Isn't this also supposed to work just out of the box? Reinstalling, etc. didn't work unfortunately.
So I guess one question that crystallizes here is: Is there a possibility to give Eclipse/Xilinx SDK a path to a directory for all required standard header files and it searches in them? Because in some standard headers, they include other headers, which in turn aren't found by the Xilinx SDK. And will that fix my issues?
Funnily enough, when I use the Ctrl+Click action to jump from header to header, all headers are found and it's no problem. It's only in the build process where embedded further headers aren't found anymore. Also, when I change the #include_next to #include, the whole thing starts working again. The same with changing #include <header> to #include "header.h". Then it works. But that can't be the solution, changing every header that throws an error, since it was generated like this for a reason, right?
This is really annoying and disrupts any workflow.
Is there someone who had this problem as well and may help me?
I am using Ubuntu 16.04 and the Ultra96v2 board.
Update
What I've investigated so far with no avail:
https://e2e.ti.com/support/wireless-connectivity/wi-fi-group/wifi/f/wi-fi-forum/993711/cc3235sf-why-is-ccs-eclipse-unable-to-see-the-c-standard-header-files
Eclipse can't find header file, even though include paths are set
Where are the headers of the C++ standard library
https://www.eclipse.org/forums/index.php/t/1088833/
I have included the path for my C++ gcc standard library as a path in which Eclipse/the Xilinx IDE is supposed to search for headers, but the headers inside the files aren't being found.
Update 2
Here you can see where the problem starts. It's really weird, since everything is auto-generated and thus should just work, especially since those are predefined headers and sources, which haven't been altered by me.
Here, you can see that I included the usual standard header location in the inclusion paths, so the files in question should be found.
I have gtest up and running and confirmed it works with two test projects.
Now I tried including my part of a project written for the ATXMEGA128d4.
If I include my code in my gtest_test file via:
extern "C" {
#include "C:\User\my_workspace\active_development\uC_Project\myCode.h"
}
I get an error when trying to build my test code: THE ERROR IS:
C:\User\my_workspace\active_development\uC_Project\Hardware.h(23):
fatal error C1083: File (Include) cannot be opened: "avr/io.h": No such file or directory
Target //:uC_Project_test failed to build
So any include file that has an "avr/io.h" header include, causes a problem as gtest cannot find "io.h" which actually makes sense since io.h does not really exist.
Since the project was developed with Microchip Studio and you are supposed to use:
#include <avr/io.h>
This tells the Project the IO-pins and other device specific details.
Since the IDE knows its the ATXMEGA128d4 the IDE knows that the required io.h file is the "iox128d4.h" which is in a path of Microchip Studio and somehow communicated to the project, my guess is through the make file.
I have tried replacing all <avr/io.h> with a path to the exact "iox128d4.h" file, but then the project refuses to build at all with the error message "include <avr\io.h> instead of file "..."
My Question is now:
How do I let gtest know what include files to use without altering the original project. if I could somehow tell the project to use "iox128d4" instead of <avr/io.h> it should work. Maybe this is possible through the gtest makefile ? I am an absolute beginner in makefiles so I don't even know where to start there.
Any help or hints would be greatly appreciated.
If you really do not want to modify the original code you would have to create a mock header for io.h and include that in your test project. This would mean that you have to include a definition and implementation in the mock file for every function, variable and define used in the actual project. The implementation can just be an empty function or return/set a default value. For inspiration you could look at gmock.
Alternativly you could look at structuring the project such that the parts you need to unit test do not depend on any specific hardware includes. As these you are unlikely to be able to test on a development pc or build server. This under the assumption you will not run gtest on your mcu.
I've found that a small C++ project, with no dependencies, won't compile under Cygwin with either GCC or Clang. Under Ubuntu there are no problems; and I've been working with this code for a couple of years. I'll introduce a MWE.
The problem arises when including a header in a subdirectory, which itself includes another header, found in that same subdirectory, but specified with the subdirectory in the path provided to the include directive. Executing the following commands can replicate the error:
mkdir foo
echo \#include \"foo/includes.hpp\" > inc.hpp
echo \#include \"foo/bar.hpp\" > foo/includes.hpp
touch foo/bar.hpp
g++ -c inc.hpp
On 64-bit Ubuntu 18.10, the final GCC (or Clang) invocation will produce no errors. On 64-bit Cygwin under Windows 10, the following error message is displayed.
In file included from inc.hpp:1:0:
foo/includes.hpp:1:10: fatal error: foo/bar.hpp: No such file or directory
#include "foo/bar.hpp"
^~~~~~~~~~~~~
compilation terminated.
Can anyone shed some light on the issue? (By the way, I myself do well understand how to properly include header files - this is about the difference between Cygwin and Ubuntu.)
foo/includes.hppshould have local includes if you use "".
That would be:
#include "bar.hpp"
The specification for what paths are used for searching headers is custom for all compilers, although includes with "" should be considered as local for the file where you have the include, not the one that you are compiling.
Basically, it's:
look in the current folder of the current header being processed for a file with that name
use the same paths as <>after
Of course, as I've said, this could change for a new compiler one day. But it is quite safe to assume that this is the behavior for all compilers (What is the difference between #include <filename> and #include "filename"?).
I am working in eclipse with MinGw (g++) compiler.
So my problem is when I import .h file from library I have downloaded and I try to build(compile) my project, error is "no such file or directory" for that .h file you can see on picture but still the class from that header file is recognised in the code!
Another strange thing is if I make intentional error in that .h file #import is succesfull and the error from that .h file is shown, that means it trys to compile that .h file.
So it does not know where the file is but it still compiles it ??? what???
cmd line:
g++ -Ic:D:\Documents\cpp_testing\bignum_testing\lib Main.cpp
error:
Main.cpp:10:22: fatal error: Cbignums.h: No such file or directory
#include "Cbignums.h"
^
compilation terminated.
I hope somone will know how to fix this and that it will help other people!
Picture without error in .h file:
Picture with intentional error in .h file!
I suspect that you should
#include "lib/Cbignums.h"
in bignum_testing.cpp if that is the path of the Cbignums.h - relative to the source file.
The IDE recognizes the type because you have the header in your project but the red lines indicate that the include will fail.
EOF is mostly a C thing from <cstdio> (or <stdio.h> form the C standard library, not the C++ one) which you probably forgot to include (e.g. by commenting its //#include <cstdio>)
Try compiling with appropriate -I and -H preprocessor options to g++ (of course, take time to read the documentation to find what they are doing).
BTW, you could ask for the preprocessed form with g++ -C -E Cbignums.cpp > Cbignums.ii then look, with some editor or pager, into the generated Cbignums.ii file.
I strongly recommend you to read a good book about Programming using C++ and to read the GCC documentation. In general, read the documentation of everything you are using for development (tools, e.g. compilers, and libraries)
PS. Every free software C++ compiler I know (GCC & Clang/LLVM...) are command line tools, so run them in a terminal, perhaps thru GNU make. Notice that Eclipse is not a compiler (it is an editor, self-glorified as an IDE), and you probably are not using it cleverly. Don't forget to pass -Wall -g to g++
I am trying to compile a program that uses rocksdb.
According to the example in the official webpage, the only header i should add to my code is db.h.
Now, the file i am compiling is in folder A.
db.h however is in A/rocksdb-master/include/rocksdb/.
So, i add this line to my file:
#include "rocksdb-master/include/rocksdb"
It finds the file, but the problem is that inside db.h, i have this line:
#include "rocksdb/metadata.h"
And when i compile i get this error:
fatal error: rocksdb/metadata.h: No such file or directory
#include "rocksdb/metadata.h"
I mean, it's obvious. db.h is in the same folder as metadata.h, so it's fine that the compiler cant find any rocksdb folder. But i doubt that people who wrote this library don't know that.
Is there any other way to add the path's to compile it?
Why is it that the path from db.h are not relative to where it is located?
You should normally use just the following header in your project:
#include "rocksdb/db.h"
When compiling your own project, you should then add the RocksDB include path to the list of include directories. For example, if the RocksDB source code is in directory ../rocksdb-master, the include path will be ../rocksdb-master/include.
How to add the include path to the compiler flags is indeed compiler-specific. With g++ or clang, it's done by passing -I../rocksdb-master/include to the compiler when compiling your own program. Note that you many need to link against the RocksDB library as well.
And finally, you may need to include some more RocksDB headers if you use some of its advanced concepts, e.g. transactions.