I'm trying to use Gradle (5.6.2) to build a basic C++ library, and cannot figure out what is going wrong here. I started out using Gradle init to create the basic structure... here's my build.gradle:
plugins {
// Apply the cpp-library plugin to add support for building C++ libraries
id 'cpp-library'
// Apply the cpp-unit-test plugin to add support for building and running C++ test executables
id 'cpp-unit-test'
}
// Set the target operating system and architecture for this library
library {
targetMachines.add(machines.macOS.x86_64)
dependencies {
implementation files('/usr/local/lib/libjsoncpp.a') // used by classA
}
}
tasks.withType(CppCompile).configureEach {
compilerArgs.add "-std=c++11"
compilerArgs.add "-w"
}
The source tree looks like this:
src/main/cpp -> classA.cpp classB.cpp classB.hpp hello.cpp
src/main/public -> classA.hpp cppd.h cpplib.h
src/test/cpp -> classATest.cpp hello_test.cpp
hello.cpp, cppd.h, cpplib.h, and hello_test.cpp all came from the 'gradle init' and aren't actually used.
classA calls a few methods in classB. classB only depends on standard libraries.
classB has a public method classB::method1() that calls two private methods classB::method2() and classB::method3()
When I build, I get a linker error that it can't find classB::method2() or classB::method3(). I checked the method signatures and they all match up (same number and type of arguments in classB.hpp, classB.cpp, and in the linker error message).
I've scoured the Gradle documentation and Googled everything I can think of, tried several variations on the build.gradle file, and... I don't understand why the linker can't find methods in the same CPP file??
Building with Clang 11.0 on MacOS 10.14.6 in case it matters...
Also for reference, here's the relevant bits of the header file:
class classB {
public:
method1();
private:
string& method2(const string& s, bool b);
int method3(uint16_t* b, const string& s);
}
And the methods from the cpp file:
string& method2(const string& s, bool b) {
// blah
}
int method3(uint16_t* b, const string& s) {
// blah
}
OH MY GOODNESS! Just... Nevermind. You know how sometimes posting the question itself is enough to make the problem obvious?
For the record, of course what's missing is the class identifyer-thing (sorry, can't recall the term, I'm coming back from Java) on the front of the method names in the CPP file. They should be:
string& classB::method2(const string& s, bool b) {
// blah
}
int classB::method3(uint16_t* b, const string& s) {
// blah
}
Without the class identifyer-things, the linker doesn't realize they are member functions, and doesn't make the connection.
Related
I have not even begun testing and I am encountering some syntax issues with GMock's MOCK_METHOD macro even though I am following GMock's documentation properly. Could it be a compiler issue? I have:
MingGW (GCC 4.9.2)
Googletest 1.10.x
class SimpleClass {
public:
virtual int simpleFirstFunction(int a, int b) { return (a + simpleSecondFunction(b)); }
virtual int simpleSecondFunction(int b) { return (2 * b); }
virtual ~SimpleClass();
};
class MockSimpleClass :public SimpleClass {
MOCK_METHOD(int, simpleSecondFunction, (int a, int b), (override));
};
I am seeing 3 compiler errors:
Error-1: about the function name
MockSimpleClass.cpp:18:24: error:
'simpleSecondFunction' is not a type
MOCK_METHOD(int, simpleSecondFunction(int a, int b), (override));
Error-2: about input parameters
MockSimpleClass.cpp:18:46: error:
expected identifier before '(' token
MOCK_METHOD(int, simpleSecondFunction, (int a, int b), (override));
Error-3: About parentheses around "override"
MockSimpleClass.cpp:18:60: error:
expected identifier before '(' token
MOCK_METHOD(int, simpleSecondFunction(int a, int b), (override));
MOCK_METHOD macro is not defined.
Here is how I troubleshooted the exact same issue:
Check preprocessor: gcc -E s1.cpp > s1.preproc.
First of all check the gmock.h included.
In my case it was:
72396 # 11 "s1.cpp" 2
72397 # 1 "/usr/include/gmock/gmock.h" 1 3 4
As you can see a system header is included.
I wen to check googletest version on system(Ubuntu 19.10):
doliaru#host:~/test/gtest/build$ dpkg -l google*
rc google-mock:amd64 1.8.1-3 aand using C++ mock classes
ii googletest:amd64 1.8.1-3 amd64 Google's C++ test frame
dpoliaru#host:~/test/gtest/build$
Apparently this feature was not implemented in 1.8.
I cloned the most recent version of googletest here.
Having checked the topmost CMakeLists.txt on master branch I see that
current gtest version on master is:
set(GOOGLETEST_VERSION 1.10.0)
And I built it with these cmake configs:
cmake .. -D CMAKE_INSTALL_PREFIX=/home/dpoliaru/.local/ -D gtest_build_samples=TRUE
After installation, gmock, that I needed for the project was here:
/home/dpoliaru/.local/include/gmock/gmock.h
Thus, I updated CMakeLists.txt file of the project with the proper include directory for given target:
...
target_include_directories(${PROJECT_NAME} PUBLIC ${GTEST_INCLUDE_DIRS} ${GMOCK_INCLUDE_DIRS})
...
If you are new to cmake, please check their webpage and find lots of great stuff in cmake-data debian package.
After cmake configure step I see this definition in flags.cmake file:
CXX_INCLUDES = -I/home/dpoliaru/.local/include
With proper include paths I managed to compile the project.
Hope that helps.
It sounds like the MOCK_METHOD macro is not defined. Have you set up your include path correctly and added the #include "gmock/gmock.h" directive at the top of your file? You are also missing a public access specifier and the number of arguments is wrong for the function.
This should work if you have the gmock headers on your include path:
#include "gmock/gmock.h"
class SimpleClass {
public:
virtual int simpleFirstFunction(int a, int b) { return (a + simpleSecondFunction(b)); }
virtual int simpleSecondFunction(int b) { return (2 * b); }
virtual ~SimpleClass();
};
class MockSimpleClass : public SimpleClass {
public:
MOCK_METHOD(int, simpleSecondFunction, (int b), (override));
};
I have two .so files and I am trying to call a parameterized constructor from one .so to the other. And I am getting a linker error. Here is the piece of code.
ABC.h
class ABC
{
ABC();
ABC(int i);
};
ABC.cpp
ABC::ABC()
{
//do something
}
ABC::ABC(int i)
{
//do something.
}
XYZ.cpp
#include "ABC.h"
void XYZ1()
{
ABC abc(); // this passes
}
void XYZ1(int i)
{
ABC abc(i); // This results in linker error when I run XYZ's executable
}
void main()
{
XYZ1();
}
Please note that I am using netbeans IDE.
I have noticed that parameterized constructor results in the error, default constructor doesn't throw any error. Is there any setting which I need to make am in the netbeans IDE.
Your constructor is private, thus it can't be invoked
I found out the problem, XYZ.so file was looking for ABC.so in the wrong location and thats the reason it was not able to link it properly. The reason why it was looking in some other location was because a path was set in "LD_LIBRARY_PATH", in this path a different version of ABC.so was present.
Thanks for your help.
I am trying to compile a project that uses log4cxx, a c++ logging framework. Once I downloaded the framework and added it as a dependency, however, I get this error:
'Locale' : looks like a function definition, but there is no parameter list; skipping apparent body
This happens in locale.h which looks like this:
#ifndef _LOG4CXX_HELPERS_LOCALE_H
#define _LOG4CXX_HELPERS_LOCALE_H
#include <log4cxx/logstring.h>
namespace log4cxx
{
namespace helpers
{
class LOG4CXX_EXPORT Locale
{
public:
Locale(const LogString& language);
Locale(const LogString& language, const LogString& country);
Locale(const LogString& language, const LogString& country,
const LogString& variant);
const LogString& getLanguage() const;
const LogString& getCountry() const;
const LogString& getVariant() const;
protected:
Locale(const Locale&);
Locale& operator=(const Locale&);
const LogString language;
const LogString country;
const LogString variant;
}; // class Locale
} // namespace helpers
} // namespace log4cxx
#endif // _LOG4CXX_HELPERS_LOCALE_H
Is there anything wrong with this syntax? I am not knowledgeable in C++ at all but I do not see what would be wrong with it.
The one single thing on the internet I could find was this: https://issues.apache.org/jira/browse/LOGCXX-147 which makes perfect sense because I am targetting a windows ce device (although, using Visual Studio 2008 instead of 2005). The suggestion there is to include log4cxx/logstring.h inside "the cpp file" which I assume they mean locale.cpp although if I am clearly misinterpreting this please let me know. It said that would get rid of the compilation error but unfortunately I did that and it did not do anything to help :(.
I know it may be a bit of a longshot but does anyone know how one might fix this?
I use a native C++ code base from C#, with a C++/CLI wrapper built around it (with Visual Studio 2013). There are two projects:
NativeCodeBase: simple C++ project set to be built into a static lib.
ManagedWrapper: C++/CLI project referencing NativeCodeBase.
I have the following native "interface" in NativeCodeBase:
class ITest {
virtual void Foo(const std::string& str, MyEnum me) = 0;
}
For which I have a native implementation in the ManagedWrapper project.
In the header:
class TestManaged : public ITest {
virtual void Foo(const std::string& str, MyEnum me) override;
}
In the cpp:
void TestManaged::Foo(const std::string& str, MyEnum me) {
int length = str.length();
}
The MyEnum enum is used both in native and managed code, so in its implementation I use a conditionally compiled C++/CLI extension, to make it usable from C#:
#ifdef _MANAGED
public
#endif
enum class MyEnum : unsigned char
{
Baz = 0,
Qux = 1
};
In my native code I have a reference to ITest and call its Foo function with a local std::string variable. When Foo is called, I can see in the debugger that the string passed as an argument is a valid string object.
The call is similar to this:
void Bar(ITest& test) {
std::string str = "test";
test.Foo(str, MyEnum::Baz);
}
However, if I put a breakpoint at the beginning of TestManaged::Foo, the debugger says that str has <undefined value>, and the length() call crashes with undefined reference error in the <xstring> header in the following function:
size_type length() const _NOEXCEPT
{ // return length of sequence
return (this->_Mysize);
}
The debugger displays <undefined value> for the this pointer as well.
What can be the reason for this? References somehow get corrupted when passed between the two libraries?
(Additional info: I used not to build the NativeCodeBase project as a separate lib, but linked all the source files from it into the CLI project, and the same code base worked without any problem. It started failing since I configured it to be built into a separate lib and added a reference in the CLI project to the native one.)
The problem wasn't with the reference itself. The problem was with the second enum parameter. The implementation of the enum class looked like this:
#ifdef _MANAGED
public
#endif
enum class MyEnum : unsigned char
{
Baz = 0,
Qux = 1
};
The #ifdef directive was put there in order to create a native enum when built for native C++, but create a CLI enum when built for C++/CLI.
This worked well when all the source files were linked to the CLI project and every piece of source was built again for the CLI project. However, this approach does not work any more when I want to use the native lib from the CLI side.
I guess the problem was that the same header was built differently in the two libraries, so the caller and the calle saw a different binary interface of the object, thus the arguments got garbled when passed. Is this correct?
I got rid of the conditionally compiled public keyword and it started working properly again.
I am trying to figure out exactly how constructors for global objects are called. I understand that they are called before anything in a translation unit is used, and I am fine with that. I am trying to find out how in Linux and Windows (x86 and x64) this is accomplished.
I seem to remember that Windows (x86) used a linked list for construction and destruction, but I am having trouble finding any resources on this matter.
I have found the following material on related topics, but nothing seems to cover exactly what I am looking for.
http://blogs.msdn.com/b/freik/archive/2005/03/17/398200.aspx
http://msdn.microsoft.com/en-us/library/9b372w95.aspx
http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx
And the PE file format document.
Could anyone point me in the correct direction to find this information?
Just in case your failing to understand I have code here to demonstrate.
SourceA.cpp
#include "stdafx.h"
extern bool DoFunctionB();
class MyClassA {
protected:
bool bIsInitialized;
bool bIsBInitialized;
public:
MyClassA () : bIsInitialized(true) {
bIsBInitialized = DoFunctionB();
}
bool IsInitialized() {
return bIsInitialized;
}
};
static MyClassA MyClassGlobal;
bool DoFunctionA() {
return MyClassGlobal.IsInitialized();
}
SourceB.cpp
#include "stdafx.h"
extern bool DoFunctionA();
class MyClassB {
protected:
bool bIsInitialized;
bool bIsAInitialized;
public:
MyClassB () : bIsInitialized(true) {
bIsAInitialized = DoFunctionA();
}
bool IsInitialized() {
return bIsInitialized;
}
};
static MyClassB MyClassGlobal;
bool DoFunctionB() {
return MyClassGlobal.IsInitialized();
}
Main.cpp
#include "stdafx.h"
extern bool DoFunctionA();
extern bool DoFunctionB();
int _tmain(int argc, _TCHAR* argv[])
{
bool a = DoFunctionA();
bool b = DoFunctionB();
return 0;
}
Add these to a new windows console app. Place breakpoints in the constructors, and in the DoFunctionX() code. Hit F11 and step through it. You will see that whichever global initializer gets called first will use the DoFunction in the other cpp file before the static object in that file gets initialized.
Regardless of what you think the standard may be. This is what compilers do. And its a hazard that you have to be concerned with.
And if you step up the stack 2 steps when your in the constructor you will see the list of pointers that I've already told you about.
Happy Coding.
You are wrong to think that global constructors must be run before the object is used. I've fixed many a bug based on this assumption and it simply is not true. Not for gcc, and not for MSVC, abd certainly not for XCode.
You can specify an attribute((init_priority(X))) in gcc to force the order,
or #pragma init_seg({ compiler | lib | user | "section-name" [, func-name]} ) for msvc.
When working with XCode, the initialization code is run in the order that the object files are passed to the linker.
I dont think there is a standard, and if there is then very few people are following it. Its up to the tools creator to decide how they want to keep track of whats getting initialized and when.