How to make CPP files visible to linker in ESP8266 Eclipse project - c++

There is a "hello world" project in Eclipse IDE that is supposed to compile against ESP8266 RTOS SDK.
File structure is as follows
I added one C++ class to it and put it into its own folder. Here is the class header
#ifndef MAIN_BLINKER_BLINKER_H_
#define MAIN_BLINKER_BLINKER_H_
class Blinker {
public:
Blinker( int period );
int Period() const;
private:
int period_;
};
#endif /* MAIN_BLINKER_BLINKER_H_ */
and the definitions
#include "Blinker.h"
Blinker::Blinker( int period ) :
period_( period )
{}
int Blinker::Period() const {
return this->period_;
}
Main.cpp file is like this
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "blinker/Blinker.h"
extern "C" {
void app_main()
{
auto blnk = Blinker( 3000 );
int i = 0;
while ( 1 ) {
printf( "[%d] Hello beautiful world!\n", i );
i++;
vTaskDelay( blnk.Period() / portTICK_PERIOD_MS );
}
}
}
It compiles but fails at final stage because the linker (or what is supposed to be a linker in xtensa toolchain) does not see definitions of Blinker methods. This is what I get in the build log
If I put class files next to main.cpp file, the build succeeds. However with time there will be hundreds of files, and without any grouping it will quickly turn into an unmanageable mess.
Alternatively I could put this class into top-level components folder and equip it with empty component.mk file. This would also make the build system happy, however it would force me to use ugly header includes like ../components/blinker/Blinker.h, which I would like to avoid.
So the question is how to make build system aware of .c and .cpp files residing in subfolders of main folder?

you can set COMPONENT_SRCDIRS in "main" component.mk file
see:
https://docs.espressif.com/projects/esp8266-rtos-sdk/en/latest/api-guides/build-system.html#example-component-makefiles

Try to add blinker/Blinker.cpp to your CMakeLists.txt.
Take a look at
How to add new source file in CMakeLists.txt?

Related

Visual Studio's Test Explorer breaks when trying to link object files

I want to use Visual Studio's Test Explorer to run my Google Tests. When I create a console project and add a default Google Test project, and build the solution, it finds the tests as intended.
Now I want to create my own class, where everything is set up in the header file.
class foo
{
public:
foo() : the_count(0) {}
~foo() = default;
void count_plus() { the_count++; };
int get_count() { return the_count; };
private:
int the_count;
};
Then I modify my test.cpp file (the default file created by Visual Studio's Google Test project) to make use of my new class.
#include "pch.h"
#include <iostream>
#include "..\ConsoleApplication2\foo.h"
class tester : public testing::Test {
public:
foo bar;
void SetUpTestSuite() {
std::cout << "Setup..\n";
}
void TearDownTestSuite() {
std::cout << "Teardown..\n";
}
};
TEST_F(tester, TestFixture1)
{
EXPECT_EQ(bar.get_count(), 0);
bar.count_plus();
EXPECT_EQ(bar.get_count(), 1);
}
Building this solution also automatically detects the tests and runs them succesfully.
Now it gets interesting... When I move my implementation of foo to a .cpp file.
foo.h
class foo
{
public:
foo();
~foo() = default;
void count_plus();
int get_count();
private:
int the_count;
};
foo.cpp
#include "foo.h"
foo::foo()
{
the_count = 0;
}
void
foo::count_plus()
{
the_count++;
}
int
foo::get_count()
{
return the_count;
}
And then I build the solution, I initially get a linker error complaining about unresolved externals.
However, if I change the test project's linker settings to point to the other project like so:
Properties -> Linker -> Input -> Additional Dependencies -> add $(SolutionDir)ConsoleApplication2\$(IntDir)*.obj
which I got from this answer, I can succesfully build the project.
However, after I finish building the project, I'm no longer able to see or run my tests.
Am I doing something wrong here? Or is Visual Studio just broken?
I figured it out. The project which generates the object files cannot have a main() function, as this overrides Google Test's main() function.
I solved it by:
Creating an empty project (with no main()) which contains all my source code and set this project's Configuration Type as Static library (.lib).
Creating a console application project (or whatever suits your needs) which contains my main() entry point. In this project, I add a reference to my .lib project.
Create a Google Test project. In this project, I also add a reference to my .lib project.
Set the project in step two as the Startup project.
Now when you want to run your code, it will run it from your one entry point, but grab the source from .lib project and your Google Test project will also grab this .lib file, detecting all your tests.

Pybind11 - Where to put PYBIND11_MODULE

Im currently playing around with pybind11 a bit. Im trying to create a C++ class which then gets passed to a python interpreter embedded in my C++ source.
I created some dummy class just to test the basic functionality I kept everything in a single source file. This approach compiled and ran without any problems.
Now I separated my dummy Class Test into a Test.h and Test.cpp
Test.h
#pragma once
#include<iostream>
#include"pybind11\pybind11.h"
namespace py = pybind11;
class Test
{
public:
Test(const std::string &s);
~Test();
void printStr();
private:
std::string _s;
};
Test.cpp
#include "Test.h"
PYBIND11_MODULE(TestModule, m)
{
py::class_<Test>(m, "Test")
.def(py::init<const std::string &>())
.def("printStr", &Test::printStr);
}
Test::Test(const std::string &s) : _s(s)
{
}
Test::~Test()
{
}
void Test::printStr()
{
std::cout << "---> " << _s << std::endl;
}
main.cpp
#include"Test.h"
int main(int argc, char **argv)
{
PyImport_AppendInittab("TestModule", PyInit_TestModule);
Py_Initialize();
PyRun_SimpleString("import TestModule");
PyRun_SimpleString("t = TestModule.Test(\"str\")");
PyRun_SimpleString("t.printStr()");
Py_Finalize();
getchar();
return 1;
}
After putting the Class Test into a new file the Compiler cannot find the PyInit_TestModule (main.cpp line: 6) anymore since this is generated by the PYBIND11_MODULE Macro which lives in the Test.cpp file(MSVS2017 Error: C2065).
I tried putting the PYBIND11_MODULE Macro into the Test.h. This however resulted in a linker error which said that "_PyInit_TestModule" is already defined in main.obj (MSVS2017 Error: LNK2005)
Putting the PYBIND11_MODULE Macro in the main.cpp file works.
However I feel like this will become quite unreadable as soon as you put a lot of custom Module definitions into main.cpp or even worse you have multiple Python-Interpreter being started from different source files where you then
need to put the same definition in all those files which will be a mess and most likely turn into a linker error.
Has one of you faced the same Problem and how did you solve it?
I created a file of his own for the bindings, and compiled/linked it together with the original c++ file. This way:
1) Test.h + Test.cpp contain only c++ code of your class
2) Test-bindings.cpp contains the PYBIND11_MODULE and #include <Test.h>
3) Building (with cmake). You will get a PyTest.so file out of it, that you can load in python.
# c++ libray
add_library(TestLib SHARED /path/to/Test.h /path/to/Test.cpp)
# bindings
add_subdirectory(pybind11) # you must have downloaded this repo
include_directories(/path-only/to/Test.h)
pybind11_add_module(PyTest SHARED /path/to/Test-bindings.cpp /path/to/Test.cpp)
4) (I suggest you to) write the main in python, using the python-binding you just created
5) In your main.py
import PyTest
# do something

How to link multiple files in Turbo C++?

I know Turbo C++ is oudated as hell, but so is the curriculum of our central board in my country (India). And I am doing a school project. And I don't have the freedom to choose my own IDE and compiler. Go figure.
NOTE: I am using Turbo C++ 3.0 in DOSBox in Win10
Anyway, here is the project directory I made to test TC++'s linking:
TC/BIN
-MAIN.CPP
#include <iostream.h>
#include <conio.h>
#include "CL.H"
int main()
{
clrscr();
cout<<"HW";
cl c;
c.set(5);
cout<<c.get();
getch();
return 0;
}
-CL.CPP
#include "CL.H"
void cl::set( int i )
{
a = i;
}
int cl::get()
{
return a;
}
-CL.H
#ifndef CL_H
#define CL_H
class cl
{
int a;
public:
void set( int i);
int get();
};
#endif
All of these compile fine. Upon trying to link, I get the following linker error:
LINKER ERROR: Undefined symbol cl::get() in module MAIN.CPP
LINKER ERROR: Undefined symbol cl::set( int ) in module MAIN.CPP
You can do that:
1- Open TC.exe
2- From project select Open Project
3- Enter the name of project eg: MyProj.prj and Press ok.
4- From project select Add item
5- Locate all the source files and add them.
6- compile and build.
(Posted on behalf of the question author).
I had the .h files also added to the project. That caused all the trouble. Removing the .h files from the project seems to make it work.

C++ - Many parse Issues in NSObjCRuntime and NSZone

I'm using the AppGameKit 2 C++ libraries with Xcode.
I'm using a template project that's given for development on Mac OSX and my code is identical to the default template save for changing a initWithCString to initWithUTF8String, but it compiled after that anyway, so it's not a problem.
The problem started when I tried to rename one of the classes that comes with the template, called template.h/.cpp. The option to rename in the refactor menu was greyed out, so I duplicated the class and changed all of the #includes to point to the new class, then removed the old one from the project.
When I hit run, I got about 20 errors all saying stuff like Unknown type name 'NSString' and Unknown type name 'Protocol'.
I looked around and found answers like this one: ios - Parse Issues in NSObjCRuntime, NSZone, and NSObject but it didn't solve the issue, because according to those, my code should work.
The includes of the main class (Core.mm) is here:
// includes
#import <Cocoa/Cocoa.h>
#include "agk.h"
#include "template.h"
The code in template.h is here:
#ifndef _H_APP
#define _H_APP
// Include AGK libraries
#include "agk.h"
// used in Core.mm to set the window properties
#define DEVICE_WIDTH 1280
#define DEVICE_HEIGHT 720
#define WINDOW_TITLE "Title"
#define FULLSCREEN 0
// Global values for the app
class app
{
public:
// global game vars
public:
// constructor
app() {}
~app() {}
void Begin( void );
void Loop( void );
void End( void );
};
extern app App;
#endif
The code in template.cpp is here:
// Includes
#include "template.h"
// Namespace
using namespace AGK;
app App;
void app::Begin (void){
agk::SetVirtualResolution (1280, 720);
agk::SetClearColor(0,0,0); // light blue
agk::SetSyncRate(60,0);
agk::SetScissor(0,0,0,0);
}
void app::Loop (void){
agk::Print( agk::ScreenFPS() );
agk::Sync();
}
void app::End (void){}
I can't make any sense of this because it shouldn't make sense.
Well, I found the problem. In the template project, the template.cpp file was marked as an Objective-C++ source file, but it obviously wasn't being reimported as one. Changing the file type fixed the problem.
Xcode 11.7
( in 2020 )
change the type, to do it more intuitively
This is cause you imports C or C++ file in your project.For this you add all your header file that imported in .pch file or any common file should declare like this:
#ifdef __OBJ C__
//Import header file
#endif

How to auto-include all headers in directory

I'm going through exercises of a C++ book. For each exercise I want to minimize the boilerplate code I have to write. I've set up my project a certain way but it doesn't seem right, and requires too many changes.
Right now I have a single main.cpp file with the following:
#include "e0614.h"
int main()
{
E0614 ex;
ex.solve();
}
Each time I create a new class from an exercise, I have to come and modify this file to change the name of the included header as well as the class i'm instantiating.
So my questions are:
Can I include all headers in the directory so at least I don't have to change the #include line?
Better yet, can I rewrite my solution so that I don't even have to touch main.cpp, without having one file with all the code for every exercise in it?
Update:
I ended up following Poita_'s advice to generate main.cpp via a script.
Since I'm using an IDE (Visual Studio), I wanted this integrated with it, so did a bit of research on how. For those interested in how, read on (it was fairly, but not entirely, straightforward).
Visual Studio lets you use an external tool via the Tools -> External Tools menu, and contains a bunch of pre-defined variables, such as $(ItemFileName), which can be passed on to the tool. So in this instance I used a simple batch file, and it gets passed the name of the currently selected file in Visual Studio.
To add that tool to the toolbar, right click on the toolbar, select Customize -> Commands -> Tools, and select the "External Command X" and drag it to the toolbar. Substitute X with the number corresponding to the tool you created. My installation contained 5 default pre-existing tools listed in Tools -> External Tools, so the one I created was tool number 6. You have to figure out this number as it is not shown. You can then assign an icon to the shortcut (it's the BuildMain command shown below):
No. You have to include them all if that's what you want to do.
No. At least, not in a way that's actually going to save typing.
Of course, you could write a script to create main.cpp for you...
If you build your code using make, you should be able to do this.
Can I include all headers in the directory so at least I don't have to change the #include line?
Change your include line to something like #include <all_headers.h>. Now, you can let your Makefile auto-generate all_headers.h with a target like:
all_headers.h:
for i in `ls *.h`; do echo "#include <$i>" >>all_headers.h; done
Make sure that all_headers.h is getting deleted when you 'make clean'.
Better yet, can I rewrite my solution so that I don't even have to touch main.cpp,
without having one file with all the code for every exercise in it?
You can do this if you abstract away your class with a typedef. In your example, change your class name from E0614 to myClass (or something). Now, add a line to your Makefile underneath the for loop above that says echo "typedef "$MY_TYPE" myClass;" >>all_headers.h. When you build your program, invoke 'make' with something like make MY_TYPE=E0614 and your typedef will be automatically filled in with the class you are wanting to test.
If you're on Unix system, you can have a softlink that points to the latest excercise.
ln -s e0615.h latest.h
and name your class E instead of E0614, of course
P.S. To the best of my knowledge, you can't do #include xxx*
Don't use one main.cpp which you modify for each exercise. This solution makes use of make's builtin rules, so you only have to type make e0614 and it will generate e0614.cpp, compile, and link it. You can customize each .cpp file (they won't be regenerated as written below) and maintain all of that history to refer to as you complete exercises, rather than erasing it as you move from one to the next. (You should also use source control, such as Mercurial.)
Makefile
e%.cpp:
./gen_ex_cpp $# > $#
You can generate boilerplate code with scripts, because you don't want it to be tedious either. There are several options for these scripts—and I use a variety of languages including C++, Python, and shell—but the Python below is short and should be simple and clear enough here.
Sample generate script
#!/usr/bin/python
import sys
args = sys.argv[1:]
if not args:
sys.exit("expected filename")
name = args.pop(0).partition(".")[0]
if args:
sys.exit("unexpected args")
upper_name = name.upper()
print """
#include "%(name)s.hpp"
int main() {
%(upper_name)s ex;
ex.solve();
return 0;
}
""" % locals()
Make a master include file containing the names of all the headers you want.
It's a really bad idea to include *, even if you could.
You could use conditional compilation for the class name by using concatenation.
// Somewhere in your other files
define CLASS_NUMBER E0614
// in main.cpp
#define ENTERCLASSNUMBER(num) \
##num## ex;
// in main()
ENTERCLASSNUMBER(CLASS_NUMBER)
Don't know about the includes though. As suggested above, a script might be the best option.
writing a makefile rule to pass the name of the executable as a -DHEADERFILE=something parameter to the compiler shouldn't be difficult at all. Something like:
%.exe : %.h %.cpp main.cpp
gcc -o $< -DHEADER_FILE=$<F $>
OTOH, I don't know if #include does macro expansion on the filename.
sed -i 's/\<\\([eE]\\)[0-9]+\\>/\19999/' main.cpp
Replace 9999 with the required number. There might be better ways.
Why not using object mechanisms ?
You can use an Exemplar strategy for this.
class BaseExercise
{
public:
static bool Add(BaseExercise* b) { Collection().push_back(b); return true; }
static size_t Solve() {
size_t nbErrors = 0;
for(collections_type::const_iterator it = Collection().begin(), end = Collection().end(); it != end; ++it)
nbErrors += it->solve();
return nbErrors;
}
size_t solve() const
{
try {
this->solveImpl();
return 0;
} catch(std::exception& e) {
std::cout << mName << " - end - " << e.what() << std::endl;
return 1;
}
}
protected:
explicit BaseExercise(const char* name): mName(name)
{
}
private:
typedef std::vector<BaseExercise*> collection_type;
static collection_type& Collection() { collection_type MCollection; return MCollection; }
virtual void solveImpl() const = 0;
const char* mName;
}; // class BaseExercise
template <class T>
class BaseExerciseT: public BaseExercise
{
protected:
explicit BaseExerciseT(const char* b): BaseExercise(b) {
static bool MRegistered = BaseExercise::Add(this);
}
};
Okay, that's the base.
// Exercise007.h
#include "baseExercise.h"
class Exercise007: public BaseExerciseT<Exercise007>
{
public:
Exercise007(): BaseExerciseT<Exercise007>("Exercise007") {}
private:
virtual void solveImpl() const { ... }
};
// Exercise007.cpp
Exercise007 gExemplar007;
And for main
// main.cpp
#include "baseExercise.h"
int main(int argc, char* argv[])
{
size_t nbErrors = BaseExercise::Solve();
if (nbErrors) std::cout << nbErrors << " errors" << std::endl;
return nbErrors;
}
And here, you don't need any script ;)
try this:-
#ifndef a_h
#define a_h
#include <iostream>
#include <conio.h>
#incl....as many u like
class a{
f1();//leave it blank
int d;
}
#endif //save this as a.h
later
include this in ur main program that is cpp file
#include "a.h"
...your program