I have a problem of undetected dependencies in a project I'm creating with Visual 2019/CMake/ninja. For a demonstration of this problem I have created a small case with two classes ClassA and ClassB.
The .cpp file of ClassA is:
#include "ClassA.h"
#include "ClassB.h"
ClassA::ClassA()
{}
ClassA::~ClassA()
{}
void ClassA::callPrivateB()
{
ClassB toto;
toto.privateFct();
}
The .h file of ClassB is:
#pragma once
class ClassB
{
public:
ClassB();
~ClassB();
void privateFct();
};
And the main.cpp is:
#include <ClassA.h>
int main(int argc, char* argv[])
{
ClassA toto;
toto.callPrivateB();
return 0;
}
Note: ClassA.h, ClassB.cpp, and CMakeLists.txt are not added too do not put to many code.
I'm compiling this application. Everything works well. That is normal. Now, I'm changing the file ClassB.h to put privateFct private. Then I request to recompile the application. And the result is:
ninja: no work to do.
Generate all: OK.
So, the fact that ClassA.cpp depends of ClassB.h has not been detected by ninja? cmake? Visual?
Any idea on how to solve this problem?
Related
I am having a compile issue with C++ Modules, OpenCV 4.5.5 in VS2022
I get C1001 "Internal Compiler Error"
Whats the best way to fix this?
ClassA.ixx:
module;
#include <opencv2/opencv.hpp>
#include "ClassB.h"
export module ClassA;
export class ClassA
{
public:
cv::Mat myMat_; // <- This line fails to compile
ClassB b_; // <- ok
};
main.cpp
import ClassA;
int main()
{
ClassA a;
return 0;
}
Why does codeblocks give this error "Undefined reference to class::classfunction()"
It happens when a class is created in a separated file.All of these files are in the same folder
This is the main .cpp file
#include<iostream>
#include "Class2.h"
using namespace std;
main()
{
Class2 classObject;
cout<<"I'm class2"<<endl;
}
class header file
#ifndef CLASS2_H
#define CLASS2_H
class Class2
{
public:
Class2();
~Class2();
protected:
private:
};
#endif // CLASS2_H
class cpp file
#include "Class2.h"
#include<iostream>
using namespace std;
Class2::Class2()
{
cout<<"Hello, I'm Constructor"<<endl;
}
Class2::~Class2()
{
cout<<"Yo!! I'm Destructor"<<endl;
}
error is "undefined reference to Class2::Class2()"
You need to link both main.o and class.o into your executable. The exact command depends on your compiler and OS. For g++ the command would look something like
g++ -o main main.cpp class.cpp
I have 5 files, a main file and two classes with its two headers files like that:
file main.cpp:
#include "parent.hpp"
#include <iostream>
int main (){
Parent parentInstance;
parentInstance.function();
return 0;
}
file parent.hpp:
class Parent {
public:
void function();
};
file parent.cpp:
#include "child1.hpp"
void Parent::function() {
Child1 Child1Instance;
Child1Instance.speak();
}
file child1.hpp:
#include "parent.hpp"
#include <iostream>
class Child1 : public Parent {
public:
void speak();
};
file child1.cpp:
#include "child1.hpp"
void Child1::speak () {
std::cout << "Hi, I'm child1" << '\n';
}
It compile and works without any problem, -although it may have been done with bad practices-. The problem rises when I try to add a new class with its own cpp and hpp files, called Child2 that its basically the same code than Child1, but I don't know how organize properly the headers for make this code works:
void Parent::function() {
Child1 Child1Instance;
Child2 Child2Instance;
Child1Instance.speak();
Child2Instance.speak();
}
and return me:
Hi, I'm child1
Hi, I'm child2
Some rules:
A header file always has include guards (or #pragma once).
Every .cpp includes its corresponding .hpp as its first (non-comment) line.
Only include into a .cpp what you explicitly use in that .cpp.
This should solve most of your problems.
Some explanations:
Without the guards, you can end up including the same file twice transitively, say you include a.h and b.h, but b.h already includes a.h... This causes some confusing redefinition errors.
You must include the header so that function definitions in the .cpp correspond to the declarations in the .hpp. Having it on the very first line is just good practice.
Including exactly what you use avoids confusing errors if you forgot an #include somewhere else.
I'm very grateful for the comments, all my knowledge is self-taught...now the problem is easily solved:
main.cpp has no change.
file parent.hpp:
#ifndef _PARENT_HPP_
#define _PARENT_HPP_
class Parent {
public:
void function();
};
#endif /* _PARENT_HPP_ */
file parent.cpp:
#include "parent.hpp"
#include "child1.hpp"
#include "child2.hpp"
void Parent::function() {
Child1 Child1Instance;
Child2 Child2Instance;
Child1Instance.speak();
Child2Instance.speak();
}
file child1.hpp and child2.hpp (change 1 to 2):
#include "parent.hpp"
#include <iostream>
class Child1 : public Parent {
public:
void speak();
};
file child1.cpp and child2.cpp (change 1 to 2):
#include "child1.hpp"
void Child1::speak () {
std::cout << "Hi, I'm child1" << '\n';
}
And the result:
Hi, I'm child1
Hi, I'm child2
It works. However, I'd like to hear if there's anything that could be improved or a mistake that could be corrected.
The idea is this: I have SportsCar derived from Car, a Car consists of an Engine, each time Car.drive() is called, it calls Engine.consumeGas(), which in turn creates a Gas object and calls Gas.burn(). As you can see in the source code below.
Each class has its own header file and cpp file. And I wrote a Makefile (for Microsoft's NMAKE program).
The dependency is like this:
test.exe: main.obj Car.obj SportsCar.obj Engine.obj Gas.obj
main.obj: main.cpp Car.h SportsCar.h
Car.obj: Car.cpp Car.h
SportsCar.obj: SportsCar.cpp SportsCar.h // Here is what went wrong
Engine.obj: Engine.cpp Engine.h Gas.h
Gas.obj: Gas.cpp Gas.h
Build the program and run test.exe, produced the output:
Car drive
Engine consuming gas
Gas burning
SportsCar drive
Engine consuming gas
Gas burning
The problem is if I delete the member engine from Car and delete the call engine.consumeGas() in Car.drive() and rebuild the whole program, only Car.cpp and main.cpp are recompiled (SportsCar.cpp is not) and the linker won't complain at all.
After rebuilding, run test.exe get the output:
Car drive
SportsCar drive
Engine consuming gas
Gas burning
Apparently this result has completely violated the semantics of C++.
If I write the dependency like this, the problem will be fixed.
SportsCar.obj: SportsCar.cpp SportsCar.h Car.h
So if I have one source file A which includes a header file B, which in turn includes another header file C, and in A, the class C is used, I have to say A depends on both B and C, not just A depends on B?
If the project is large enough, I'm afraid I'll get lost trying to find out which file depends on which file while writing a Makefile.
Code:
main.cpp
#include "Car.h"
#include "SportsCar.h"
int main()
{
Car *car = new Car();
car->drive();
delete car;
car = new SportsCar();
car->drive();
delete car;
return 0;
}
Car.h
#ifndef CAR_H
#define CAR_H
#include "Engine.h"
class Car
{
protected:
Engine engine;
public:
virtual void drive();
virtual ~Car();
};
#endif // CAR_H
Car.cpp
#include "Car.h"
#include <iostream>
using namespace std;
void Car::drive()
{
cout << "Car drive" << endl;
engine.consumeGas();
}
Car::~Car()
{
// do nothing
}
SportsCar.h
#ifndef SPORTSCAR_H
#define SPORTSCAR_H
#include "Car.h"
class SportsCar : public Car
{
public:
void drive();
};
#endif // SPORTSCAR_H
SportsCar.cpp
#include "SportsCar.h"
#include <iostream>
using namespace std;
void SportsCar::drive()
{
cout << "SportsCar drive" << endl;
engine.consumeGas();
}
Engine.h
#ifndef ENGINE_H
#define ENGINE_H
class Engine
{
public:
void consumeGas();
};
#endif // ENGINE_H
Engine.cpp
#include "Engine.h"
#include "Gas.h"
#include <iostream>
using namespace std;
void Engine::consumeGas()
{
cout << "Engine consuming gas" << endl;
Gas g;
g.burn();
}
Gas.h
#ifndef GAS_H
#define GAS_H
class Gas
{
public:
void burn();
};
#endif // GAS_H
Gas.cpp
#include "Gas.h"
#include <iostream>
using namespace std;
void Gas::burn()
{
cout << "Gas burning" << endl;
}
You should generally never hardcode dependencies into makefiles. Instead, you should use the -M -MF flags to generate the dependencies during compilation and include the resulting file into your Makefile. Otherwise your dependencies will always be out of sync with reality.
Sadly, automatic dependency generation is a complex topic which I can't explain here in full detail. Many of the details can be found in this article: Auto-Dependency Generation
I have a problem with a static library build with Xcode 4.6.2 using the LLVM Clang Compiler. The problem occurs only if I use the C/C++ Compiler flag visibility=hidden. The Linker reports me a duplicate symbol error. I will explain the setup in an easy scenario and I hope someone can explain why this happen.
Imagine I have two classes ClassA and ClassB which I compile into a static library myLib. As said above, I set the Compiler flag -fvisibility=hidden.
Then I have a project which creates an executable from a main.cpp which uses the myLib.
Here are the classes:
ClassA.h
#pragma once
#include <boost/exception/all.hpp>
struct my_error : virtual std::exception, virtual boost::exception {};
class ClassA
{
public:
explicit ClassA() {};
virtual ~ClassA() {};
virtual void doSomething();
};
ClassA.cpp
#include "ClassA.h"
void ClassA::doSomething()
{
BOOST_THROW_EXCEPTION( my_error() << boost::errinfo_api_function("doSomething") );
}
ClassB.h
#pragma once
#include "ClassA.h"
class ClassB
{
public:
explicit ClassB() {};
virtual ~ClassB() {};
virtual void doSomething();
};
ClassB.cpp
#include "ClassB.h"
void ClassB::doSomething()
{
BOOST_THROW_EXCEPTION( my_error() << boost::errinfo_api_function("doSomething") );
}
These two classes a build into my library without a problem. In my executable project which links the myLib I have the following main.cpp
main.cpp
#include <iostream>
#include "ClassA.h"
#include "ClassB.h"
int main(int argc, const char * argv[])
{
ClassA A;
ClassB B;
return 0;
}
The C++ flags:
The build results in the following errors:
duplicate symbol __ZTIPN5boost21errinfo_api_function_E in:
/Users/georg/Library/Developer/Xcode/DerivedData/ExceptionTest-dcnvciwqbwqvciaokkjjaqchftll/Build/Products/Debug/libExceptionLib.a(ClassA.o)
/Users/georg/Library/Developer/Xcode/DerivedData/ExceptionTest-dcnvciwqbwqvciaokkjjaqchftll/Build/Products/Debug/libExceptionLib.a(ClassB.o)
duplicate symbol __ZTSPN5boost21errinfo_api_function_E in:
/Users/georg/Library/Developer/Xcode/DerivedData/ExceptionTest-dcnvciwqbwqvciaokkjjaqchftll/Build/Products/Debug/libExceptionLib.a(ClassA.o)
/Users/georg/Library/Developer/Xcode/DerivedData/ExceptionTest-dcnvciwqbwqvciaokkjjaqchftll/Build/Products/Debug/libExceptionLib.a(ClassB.o)
ld: 2 duplicate symbols for architecture i386 clang: error: linker
command failed with exit code 1 (use -v to see invocation)
If I change the Compiler Flags to the following it works:
The problem is the boost::errinfo_api_function object, but I do not understand why?
I hope someone can help me.
Kind Regards
Georg