I have three files:
my.cpp
#include "my.h"
#include <iostream>
void print_foo() {
cout << foo << '\n';
}
void print(int i) {
cout << i << '\n';
}
my.h
extern int foo;
void print_foo();
void print(int);
use.cpp
#include "my.h"
int main(int argc, char *argv[]) {
foo = 7;
print_foo();
print(99);
return 0;
}
Now when I run g++ my.cpp use.cpp I get the error
/usr/bin/ld: /tmp/ccUKJUlZ.o: in function `print_foo()':
my.cpp:(.text+0x6): undefined reference to `foo'
/usr/bin/ld: /tmp/ccN0mIhY.o: in function `main':
use.cpp:(.text+0x11): undefined reference to `foo'
collect2: error: ld returned 1 exit status
Additionally, if I run g++ -c my.cpp everything goes alright, but, if I then run g++ my.o use.cpp I get the same error.
You never actually define a variable foo - in both use.cpp and my.cpp, you use foo, and in my.h you declare it as an extern.
See the beginning of this response for more information on declaring vs. defining. You may think that your problem would be solved if you added a type in front of your foo = 7 line in use.cpp; however, what you also need to do is make foo a global variable instead of a local one (which it is when you declare it simply within main), as extern will only "find" variables that have global scope. You can make a variable global by declaring it outside of any function (side note - you should only use global variables when you absolutely have to).
Therefore, you could solve your problem by changing your use.cpp to the following:
#include "my.h"
int foo = 7;
int main(int argc, char *argv[]) {
print_foo();
print(99);
return 0;
}
Related
I am relatively new to c++ and have a solid C and Object Oriented background. So I have the following code written.
I have Person.hpp which is as follows:
class Person
{
private:
struct h
{
char *name;
unsigned char age;
};
struct h entities;
public:
unsigned char age();
char *name();
Person(char *name, unsigned char a);
~Person();
};
The Person.cpp looks as follows:
#include "Person.hpp"
char *Person::name()
{
return entities.name;
}
unsigned char Person::age()
{
return entities.age;
}
Person::Person(char *name, unsigned char a)
{
entities.name = name;
entities.age = a;
}
And finally main.cpp looks like the following:
#include <iostream>
#include "Person.hpp"
int main()
{
Person someone("something", 100);
printf("%s is %d old\n", someone.name(), someone.age());
return 0;
}
I am already aware of the warning that it will cause due to the fact that the string is not constant. This will not cause an error when trying to compile. I tried compiling the code in two different methods. One by just compiling all together which would look like the following:
g++ -o main main.cpp Person.cpp
And the second method I tried was to compile them into object files and then link them together:
g++ -c main.cpp
g++ -c Person.cpp
g++ -o main main.o Person.o
They both give the following error:
/usr/bin/ld: main.o: in function `main':
main.cpp:(.text+0x5b): undefined reference to `Person::~Person()'
/usr/bin/ld: main.cpp:(.text+0x6e): undefined reference to `Person::~Person()'
collect2: error: ld returned 1 exit status
Any help would be greatly appreciated.
You have a destructor declared here in your header file:
public:
unsigned char age();
char *name();
Person(char *name, unsigned char a);
~Person(); // <===== Declared here
But you haven't provided any definitions for it.
However, the destructor is called after your main function returns (you can learn more about this behavior here), so it needs a definition.
You can make the compiler generate the definition for you by either omitting the destructor declaration or use ~Person() = default.
The problem is that you declare both an constructor and destructor in Person.hpp, but only define the constructor in the Person.cpp file.
Try add the following code to Person.cpp:
Person::~Person()
{
}
This question states that main can be implementation defined with some restrictions.
So, I wrote the following C++ code to try out the following signature of main:
main.h
class MyClass {
private:
int i;
public:
MyClass();
inline int geti() {
return i;
}
inline void seti(int i) {
this->i = i;
}
~MyClass();
};
MyClass::MyClass() {
this->i = 2;
}
MyClass::~MyClass() {
}
main.c++
#include <iostream>
#include "main.h"
int main(MyClass myClass) {
std::cout << myClass.geti() << std::endl;
return 0;
}
Which Gives the following results:
The command g++ -o main main.c++ -O3 compiles successfully with warnings:
main.c++:5:5: warning: first argument of ‘int main(MyClass)’ should be ‘int’ [-Wmain]
5 | int main(MyClass myClass) {
| ^~~~
main.c++:5:5: warning: ‘int main(MyClass)’ takes only zero or two arguments [-Wmain]
The command clang++ -o main main.c++ -std=c++14 gives the error:
main.c++:5:5: error: first parameter of 'main' (argument count) must be of type 'int'
int main(MyClass myClass) {
^
1 error generated.
the main file generated by g++ gives SIGSEGV (why though?)
So, if main can be implementation defined, why does clang give an error while g++ generated file give SIGSEGV?
I also went further and created a different code so that I will be able to pass a MyClass object to main.c++ as follows:
#include <iostream>
#include "main.h"
#include <unistd.h>
int main() {
MyClass myClass;
execve("./main",myClass,NULL);
return 0;
}
However, as execve takes the second parameter to be a char* const *, it does not compile. How do I pass the myClass object to the main file generated by g++?
The command g++ -o main main.c++ -O3 compiles successfully with warnings
This is not successful compilation. You should always use -Werror. If you fail to do so and then decide to ignore the warning and proceed with running the program, it's your own responsibility. You better know full well what you are doing. See this for more information.
the main file generated by g++ gives SIGSEGV (why though?)
The compiler has warned you. It is in your best interest to listen to it. If things go boom, chances are, that's because you have ignored warnings.
why does clang give an error while g++ generated file give SIGSEGV?
The program is not a valid C++ program. There is no meaningful difference between a warning and an error.
How do I pass the myClass object to the main file generated by g++?
You cannot. main must have a form equivalent to one of these two:
int main()
int main(int argc, char* argv[])
(Optional reading in italics) Other forms of main are implementation-defined. This means your implementation needs to support them in a documented way. Unless you have read documentation for your implementation and found that it supports the form of main you want, there's no way to do that.
Other than having an implementation-defined main, the only way a program can get hold of an object of a class type is by constructing that object.
You are close. You have identified your primary issue attempting to pass as a parameter to main() -- that won't work. The declaration for main() is defined by the standard and you are limited to passing string values (nul-terminated character arrays... C-Strings) in as arguments.
In your case you need to create an instance of your class within main(), e.g.
#include <iostream>
#include "main.h"
int main() {
MyClass myClass;
std::cout << myClass.geti() << std::endl;
return 0;
}
Your main.h header has a variable shadowing problem where at line 10:
inline void seti(int i) {
int i shadows a prior declaration at line 3, e.g. int i; (though the consequence would be unlikely to matter). Just replace the variable name in the second declaration with j (or whatever you like). Your code will compile without warning, e.g.
class MyClass {
private:
int i;
public:
MyClass();
inline int geti() {
return i;
}
inline void seti(int j) {
this->i = j;
}
~MyClass();
};
MyClass::MyClass() {
this->i = 2;
}
MyClass::~MyClass() {
}
Example Use/Output
$ ./bin/main
2
You can also call your seti() function to update the private variable in your class, e.g.
myClass.seti(5);
std::cout << myClass.geti() << std::endl;
Which would now output 5.
Let me know if you have further questions.
The man page of gcc 6.3 says:
--wrap=symbol
Use a wrapper function for symbol. Any undefined reference to
symbol will be resolved to "__wrap_symbol". Any undefined
reference to "__real_symbol" will be resolved to symbol.
...
If you link other code with this file using --wrap malloc, then all
calls to "malloc" will call the function "__wrap_malloc" instead.
The call to "__real_malloc" in "__wrap_malloc" will call the real
"malloc" function.
So I created a simple example:
#include <stdio.h>
int foo() {
printf("foo\n");
return 0;
}
int __wrap_foo() {
printf("wrap foo\n");
return 0;
}
int main () {
printf("foo:");foo();
printf("wrapfoo:");__wrap_foo();
printf("realfoo:");__real_foo();
return 0;
}
And compiled it with:
gcc main.c -Wl,--wrap=foo -o main
This gave me a warning:
main.c:18:21: warning: implicit declaration of function ‘__real_foo’ [-Wimplicit-function-declaration]
printf("realfoo:");__real_foo();
^~~~~~~~~~
Well going on. Now I would suggest an output like this:
foo:wrap foo
wrapfoo:wrap foo
realfoo:foo
Instead I get this:
foo:foo
wrapfoo:wrap foo
realfoo:foo
I hope the thing is clear. I am confused about the warning. Normally the __real function should be linked by the linker to foo(). Furthermore a call to foo() should be linked to __wrap_foo. But the output showes, that foo() is being executed instead.
How to use --wrap correctly?
As StoryTeller told me, I ignored the "undefined reference" requirement which I already posted above:
... Any undefined reference to symbol will be resolved to "__wrap_symbol". Any undefined reference to "__real_symbol" will be resolved to symbol.
To use the --wrap option I rearranged my code example like this:
main.c:
#include <stdio.h>
extern int foo();
extern int __real_foo();
int __wrap_foo() {
printf("wrap foo\n");
return 0;
}
int main () {
printf("foo:");foo();
printf("wrapfoo:");__wrap_foo();
printf("realfoo:");__real_foo();
return 0;
}
foo.c:
#include <stdio.h>
int foo() {
printf("foo\n");
return 0;
}
Then compile:
gcc main.c foo.c -Wl,--wrap=foo -o main
And the the amazing output after running ./main:
foo:wrap foo
wrapfoo:wrap foo
realfoo:foo
The trick is (correct me if I am wrong) that the reference of foo() and __real_foo() is not defined at compile time. I. E. they have **undefined references" which is the requierement for the linker to link foo() to __wrap_foo() and __real_foo() to foo().
I am trying to implement some unit tests for a C++ library that does not use OO (all functions are declared at namespace level)
For that purpose, I am trying to create a test binary that mocks (simulate) some functions.
I have achieved the above for functions that I call directly, but I have been unable to replace the calls that the library's functions do. The example below explains this:
Production code
Lets suppose this is the production code, the one that uses the real functions instead of the simulated ones:
CameraHandler.H
namespace Cam {
int myFunc();
int myFunc2();
}
CameraHandler.cpp
#include "CameraHandler.h"
using namespace Cam;
int Cam::myFunc() {
// Imagine this is the function I want to simulate with a mock
// Its mangled name is _ZN3Cam6myFuncEv
return 1;
}
int Cam::myFunc2(){
return Cam::myFunc() + 11;
}
Testing code
This is the code for the unit testing. As you can see in the Makefile, it generates a binary called testsMain.
CameraHandlerMock.h
extern "C" {
int __wrap__ZN3Cam6myFuncEv(); // mangled name of Cam::myFunc(), with the __wrap_ prefix.
}
CameraHandlerMock.cpp
#include "CameraHandlerMock.h"
int __wrap__ZN3Cam6myFuncEv(){
// As you can see, the mocked function returns 999 instead of 1.
return 999;
}
UnitTestsMain.cpp
#include <iostream>
#include <typeinfo>
#include "CameraHandler.h"
#include "CameraHandlerMock.h"
extern "C" int _ZN3Cam6myFuncEv();
int main(){
std::cout << Cam::myFunc() << std::endl;
std::cout << Cam::myFunc2() << std::endl;
return 0;
}
The Makefile
WRAP=-Wl,--wrap,_ZN3Cam6myFuncEv
all: production unitTests
production: // does not matter for this example
g++ main.cpp CameraHandler.cpp -o main
unitTests:
g++ ${WRAP} UnitTestsMain.cpp CameraHandlerMock.cpp CameraHandler.cpp -o testsMain
The problem
If I execute the testsMain program, I obtain the following result:
999 // call to Cam::myFunc()
12 // Cam::myFunc2(), which is Cam::myFunc() + 11.
Taking into account that Cam::myFunc2() calls to Cam::myFunc1(), and I have replaced it by __wrap__ZN3Cam6myFuncEv, what I expect is that t he result of calling Cam::myFunc2() is 999 + 11 = 1010. Nevertheless, Cam::myFunc2() is still calling the non-wrapped Cam::myFunc1(), so the result is 12.
Is there any way to wrap functions that are internally called by the library I want to test?
Let's lint a little bit of fluff first. In UnitTestsMain.cpp,
the declaration:
extern "C" int _ZN3Cam6myFuncEv();
is redundant. It simply instructs the C++ compiler that references to the function
of that prototype whose mangled name is _ZN3Cam6myFuncEv are references to
an externally defined function of that name. This is exactly the same information,
just expressed differently, that that the compiler has already got from:
namespace Cam {
int myFunc();
...
}
when it #include-ed CameraHandler.h, because _ZN3Cam6myFuncEv() is the mangled
form of Cam::myFunc. The extern "C" redeclaration of Cam::myFunc is harmless
but contributes nothing either to compilation or linkage.
On to the main question: Why does your mock
int __wrap__ZN3Cam6myFuncEv() get called instead of int Cam::myFunc in UnitTestsMain.cpp:
int main(){
std::cout << Cam::myFunc() << std::endl;
std::cout << Cam::myFunc2() << std::endl;
return 0;
}
as you want; but your mock is not called for int Cam::myFunc in CameraHandler.cpp:
int Cam::myFunc2(){
return Cam::myFunc() + 11;
}
The answer lies in the documentation of the --wrap linker option:
--wrap=symbol
Use a wrapper function for symbol. Any undefined reference to symbol will be
resolved to __wrap_symbol. Any undefined reference to __real_symbol will be
resolved to symbol.
Maybe you read it and didn't grok the significance of undefined reference.
This means that when --wrap=symbol is in effect, and the linker applies it
to an object file containing undefined references to symbol, it will replace them
with references to __wrap_symbol, and undefined references to __real_symbol,
in that object file, will be replaced with symbol.
Now in UnitTestsMain.o, compiled from UnitTestsMain.cpp, the references to both Cam::myFunc()
and Cam::myFunc2() are undefined. These functions are both defined in CameraHandler.cpp,
compiled in CameraHandler.o.
Therefore in the linkage of UnitTestsMain.o, --wrap ZN3Cam6myFuncEv will take effect and
replace the call to Cam::myFunc ( = ZN3Cam6myFuncEv) with a call to __wrap_ZN3Cam6myFuncEv.
The call to Cam::myFunc2() ( = ZN3Cam7myFunc2Ev) is not wrapped and is unaffected: it will be
resolved to the definition to be found in CameraHandler.o
But in the linkage of CameraHandler.o, both functions are defined, so --wrap has
no effect. When Cam::myFunc2() calls Cam::myFunc(), it calls ZN3Cam6myFuncEv, not
__wrap_ZN3Cam6myFuncEv.
That explains why the program outputs:
999
12
and not:
999
1010
Can you make your mocking work as expected?
Yes. You just have to ensure that every call to Cam::myFunc that you want to be
mocked is compiled into an object file that does not contain the (real) definition
of Cam::myFunc. The obvious way to do that is to define Cam::myFunc in its own
source file. Here's your example fixed:
CameraHandler.h
#ifndef CAMERAHANDLER_H
#define CAMERAHANDLER_H
namespace Cam {
int myFunc();
int myFunc2();
}
#endif
CameraHandlerMock.h
#ifndef CAMERAHANDLERMOCK_H
#define CAMERAHANDLERMOCK_H
extern "C" {
int __wrap__ZN3Cam6myFuncEv();
}
#endif
CameraHandler_myFunc.cpp
#include "CameraHandler.h"
using namespace Cam;
int Cam::myFunc() {
return 1;
}
CameraHandler_myFunc2.cpp
#include "CameraHandler.h"
using namespace Cam;
int Cam::myFunc2(){
return Cam::myFunc() + 11;
}
CameraHandlerMock.cpp
#include "CameraHandlerMock.h"
int __wrap__ZN3Cam6myFuncEv() {
return 999;
}
UnitTestsMain.cpp
#include <iostream>
#include "CameraHandler.h"
#include "CameraHandlerMock.h"
int main(){
std::cout << Cam::myFunc() << std::endl;
std::cout << Cam::myFunc2() << std::endl;
return 0;
}
Makefile
SRCS := UnitTestsMain.cpp CameraHandler_myFunc.cpp \
CameraHandler_myFunc2.cpp CameraHandlerMock.cpp
OBJS := $(SRCS:.cpp=.o)
LDFLAGS := -Wl,--wrap,_ZN3Cam6myFuncEv
.PHONY: unitTests clean
unitTests: testsMain
testsMain: $(OBJS)
$(CXX) $(LDFLAGS) -o $# $^
UnitTestsMain: CameraHandler.h CameraHandlerMock.h
CameraHandler_Func.o CameraHandler_Func2.o: CameraHandler.h
CameraHandlerMock.o: CameraHandlerMock.h
clean:
rm -f $(OBJS) testsMain
(Your production build is not considered at all in this example makefile)
With this, the test build runs like:
$ make
g++ -c -o UnitTestsMain.o UnitTestsMain.cpp
g++ -c -o CameraHandler_myFunc.o CameraHandler_myFunc.cpp
g++ -c -o CameraHandler_myFunc2.o CameraHandler_myFunc2.cpp
g++ -c -o CameraHandlerMock.o CameraHandlerMock.cpp
g++ -Wl,--wrap,_ZN3Cam6myFuncEv -o testsMain UnitTestsMain.o \
CameraHandler_myFunc.o CameraHandler_myFunc2.o CameraHandlerMock.o
and testsMain does what you expect:
$ ./testsMain
999
1010
You can simplify both source files and the makefile somewhat if you rewrite
CameraHandlerMock.cpp as just:
extern "C" {
int __wrap__ZN3Cam6myFuncEv() {
return 999;
}
}
Then you have no need for the mock header file CameraHandlerMock.h at all.
If you have a lot of functions you need to mock in this low-level way, it
may get tedious to define each one in its own source file. You may be aware
that there are higher-level, framework-supported mocking options, e.g. googlemock,
that have rich mocking capabilities and don't entail this tedium. It's fair to say, however, that they may
replace it with more complicated kinds of tedium.
I have three files : myh.h; my.cpp; use.cpp. Here are the contents of the files:
myh.h
extern int foo;
void print_foo();
void print(int);
my.cpp
#include "myh.h"
#include <iostream>
void print_foo()
{
std::cout<<foo<<std::endl;
}
void print(int i)
{
std::cout<<i<<std::endl;
}
use.cpp
#include "myh.h"
int main()
{
foo=7;
print_foo();
print(99);
return 0;
}
GCC spews out the following error:
my.o:my.cpp:(.text+0x7): undefined reference to `foo'
use.o:use.cpp:(.text+0x10): undefined reference to `foo'
collect2: ld returned 1 exit status
I compile the files using the -c command and it doesn't give errors. I link using the following command:
g++ -o final my.o use.o
What is the problem here, I read other topics with similar problems, and the case here is just strange .....
For the curious this is an exercise drill from Stroustrup's book Programming principles of using C++
Edit: I did as dasblinkenlight said, and in use.cpp I added an int in front of foo (so now foo is defined), but I still get this error:
my.o:my.cpp:(.text+0x7): undefined reference to `foo'
collect2: ld returned 1 exit status
Which tells me that it is not defined in my.cpp also? If I have to define it everywhere what is the point of including it in the header file, or how should this be approached more appropriately?
You get a linker error because you declared foo, but you never defined it.
extern int foo is only a declaration; it does not cause allocation of memory for the foo variable, only promises that you will do it at some other place. To fix it, you need to add this line to one of the cpp files, like this:
#include "myh.h"
int foo;
int main()
{
foo=7;
print_foo();
print(99);
return 0;
}
The problem is that foo is declared but not defined. You need to define foo in exactly one of the translation units, e.g.:
int foo = 0;