I'm trying to use a library where one of the classes has a constructor like so:
public:
AreaNodeIndex(size_t cacheSize);
I'm trying to instantiate an object of this class in my program like so:
size_t const cacheSize = 50000;
AreaNodeIndex areaNodeIndex(cacheSize);
The linker gives me the following error:
main.o: In function `main':
make: Leaving directory `/home/Dev/_quicktest_build'
main.cpp:(.text+0x212): undefined reference to
osmscout::AreaNodeIndex::AreaNodeIndex(unsigned int)
I think I have the necessary includes and I'm linking to the library with the compiler. For example, if I try to instantiate the object without any arguments on purpose I get this error:
../quicktest/main.cpp: In function ‘int main()’:
../quicktest/main.cpp:36: error: no matching function for call to ‘osmscout::AreaNodeIndex::AreaNodeIndex()’
/usr/local/include/osmscout/AreaNodeIndex.h:75: note: candidates are: osmscout::AreaNodeIndex::AreaNodeIndex(size_t)
/usr/local/include/osmscout/AreaNodeIndex.h:33: note: osmscout::AreaNodeIndex::AreaNodeIndex(const osmscout::AreaNodeIndex&)
So I can see the correct prototype (though here it says size_t and before it said unsigned int)...
I can use other parts of the library fine. Here are the actual source files for the class in question:
http://libosmscout.git.sourceforge.net/git/gitweb.cgi?p=libosmscout/libosmscout;a=blob;f=libosmscout/include/osmscout/AreaNodeIndex.h
http://libosmscout.git.sourceforge.net/git/gitweb.cgi?p=libosmscout/libosmscout;a=blob;f=libosmscout/src/osmscout/AreaNodeIndex.cpp
I'm pretty lost as to why this is happening. I feel like I've missed something obvious.
*In response to the replies:
The library gets size_t from "sys/types.h", so I don't think we're using different versions. The library was compiled on my system with the same compiler (g++, linux).
Changing the 'const' specifier location has no effect.
I am linking to the library. As I mentioned, I can use other classes from the library without issue. Here's the linking command:
g++ -Wl,-O1 -Wl,-rpath,/home/QtSDK/Desktop/Qt/473/gcc/lib -o quicktest main.o -L/home/QtSDK/Desktop/Qt/473/gcc/lib -losmscout -lpthread
The library name is 'osmscout'.
kfl
Possible cause of the problem in your case could be because of mixing of different size_t as mentioned by #rodrigo. For consistency maybe you can include <cstddef> where you are using size_t unless your project declares it own typedef for size_t. Please refer the link below.
Please refer Does "std::size_t" make sense in C++?
Hope this helps!
The problem may be that the actual size_t typedef depends on several compiler options. Even in a full 32-bit machine, it can be unsigned int or unsigned long depending on the mood of the developers.
So, if the library is compiled with typedef unsigned long size_t; and your program is with typedef unsigned int size_t; you have a problem. You can check it with objdump -t library | c++filt | grep AreaNodeIndex or something like that.
You don't show us the most important part: the command line used to
edit. You're probably not specifying the library to be linked in
(options -l and -L, or you can specify the library as you would any
other file).
As for the linker specifying unsigned int, and the compiler size_t,
that's just an artifact of the way the errors are displayed: the
compiler will display the name of the typedef if that's what was used
when declaring the function. The linker doesn't have this information,
so displays the name of the actual type.
It looks like you're not linking with the library correctly.
can you try
const size_t cacheSize = 50000;
instead?
[edit]
Well, I'd guess that if that declaration is giving you an unsigned long than there is some compiler option that's being overlooked, and that size_t is defined as a typedef over an unsigned long, in your compiler, and not a type that would match up with what the library see's.
Related
this must have been answered a million times, yet I cannot find a suitable solution.
I have defined a free function in sensor.cpp:
std::string printTargetGasName(enalu::CombThreshold::TargetGas){}
Then I have declared the prototype of the function
in sensor.hpp
std::string printTargetGasName(enalu::CombThreshold::TargetGas);
Then I include sensor.hpp in core_enose.hpp and try to use the function in core_enose.cpp (enalu is just a namespace).
I get undefined reference linking error
core_enose.cpp:284: undefined reference to `enalu::printTargetGasName(enalu::CombThreshold::TargetGas)'
the linking instructions in the make file seem correct, i.e. the sensor.opp comes after the core_enose.opp:
g++ -g -Wall -Wextra -pedantic -std=c++11 [...] obj_dbg/core_enose.opp [...] obj_dbg/sensor.opp [...]
I also checked to see if the symbol correctly exists in the sensor.opp file:
$> nm obj_dbg/sensor.opp | grep printTarget
$> 000000000000cc9c T _Z18printTargetGasNameN5enalu13CombThreshold9TargetGasE
I have tried desperate late night measures as well, such as extern , or re including the sensor.hpp directly in the core_enose.cpp file. Nothing helps and at this point I am frustrated at the simple answer that eludes me.
Note that I am not providing code because sensor.?pp files are rather big containing a few classes that I have also been using in my program. What I describe above are the exact steps I followed to add this free function to an otherwise working application.
Could you help me?
Because your link error is about enalu::printTargetGasName, I suspect that you declared the function in your header within the enalu namespace, but the corresponding C++ doesn't have the namespace enclosure. This might fix you in the sensor.cpp file.
namespace enalu
{
std::string printTargetGasName(enalu::CombThreshold::TargetGas){}
};
In 29.5 Atomic types of the C++ Standard November 2014 working draft it states:
There is a generic class template atomic. The type of the template argument T shall be trivially copyable (3.9). [ Note: Type arguments that are not also statically initializable may be difficult to use. —end note ]
So - as far as I can tell - this:
#include <atomic>
struct Message {
unsigned long int a;
unsigned long int b;
};
std::atomic<Message> sharedState;
int main() {
Message tmp{1,2};
sharedState.store(tmp);
Message tmp2=sharedState.load();
}
should be perfectly valid standard c++14 (and also c++11) code. However, if I don't link libatomic manually, the command
g++ -std=c++14 <filename>
gives - at least on Fedora 22 (gcc 5.1) - the following linking error:
/tmp/ccdiWWQi.o: In function `std::atomic<Message>::store(Message, std::memory_order)':
main.cpp:(.text._ZNSt6atomicI7MessageE5storeES0_St12memory_order[_ZNSt6atomicI7MessageE5storeES0_St12memory_order]+0x3f): undefined reference to `__atomic_store_16'
/tmp/ccdiWWQi.o: In function `std::atomic<Message>::load(std::memory_order) const':
main.cpp:(.text._ZNKSt6atomicI7MessageE4loadESt12memory_order[_ZNKSt6atomicI7MessageE4loadESt12memory_order]+0x1c): undefined reference to `__atomic_load_16'
collect2: error: ld returned 1 exit status
If I write
g++ -std=c++14 -latomic <filename>
everything is fine.
I know that the standard doesn't say anything about compiler flags or libraries that have to be included, but so far I thought that any standard conformant, single file code can be compiled via the first command.
So why doesn't that apply to my example code? Is there a rational why -latomic is still necessary, or is it just something that hasn't been addressed by the compiler maintainers, yet?
Relevant reading on the GCC homepage on how and why GCC makes library calls in certain cases regarding <atomic> in the first place.
GCC and libstdc++ are only losely coupled. libatomic is the domain of the library, not the compiler -- and you can use GCC with a different library (which might provide the necessary definitions for <atomic> in its main proper, or under a different name), so GCC cannot just assume -latomic.
Also:
GCC 4.7 does not include a library implementation as the API has not been firmly established.
The same page claims that GCC 4.8 shall provide such a library implementation, but plans are the first victims of war. I'd guess the reason for -latomic still being necessary can be found in that vicinity.
Besides...
...so far I thought that any standard conformant, single file code can be compiled via the first command.
...-lm has been around for quite some time if you're using math functions.
I know that the standard doesn't say anything about compiler flags or libraries that have to be included
Right.
but so far I thought that any standard conformant, single file code can be compiled via the first command.
Well, no. As you just said, there is no particular reason to assume this. Consider also that GCC extensions are enabled by default.
That being said, it seems self-evident that the intention is to make -latomic a default part of the runtime when it's settled down a bit.
g++ is a wrapper for gcc which adds the correct C++ libraries. Clearly -latomic is missing from that list. Not a core compiler problem then, simply a minor bug in the wrapper.
Edit: I have updated my question with changes I've made, upon answers.
I'm trying to link to a little library that I've wrote to learn ho this is done with C++ with no luck. G++ is complaining with undefined reference.
The root directory of library I want to link is in directory ~/code/gklib/cxx/. The structure of this directory is as follows:
~/code/gklib/cxx/
|
|`-> gk.{hh,cc}
|`-> libgk.o
|
`-> lib/
|
`-> libgk.a
I have compiled gk.cc with -c flag, then transformed the resulting object file to a .a file with ar rvsc lib/libgk.a libgk.o.
The client to this library is at folder ~/code/cpp. In this directory I compiled some_stuff.cc to an object file again, then I tried to link to it with this command:
$ cxx some_stuff.o -L../gklib/cxx/lib -lgk -o some_stuff
I get this error:
some_stuff.o: In function `main':
some_stuff.cc:(.text+0x49): undefined reference to `void GK::algorithms::insertionSort<int, 5ul>(int*)'
collect2: error: ld returned 1 exit status
These are contents of these files:
~/code/cpp/some_stuff.cc
#include <cstdlib>
#include <iostream>
#include <gk.hh>
using namespace std;
int main(int argc, char **argv) {
int i = -1;
int arr[5] = { 3, 4, 2, 1, 5 };
const size_t len = sizeof(arr)/sizeof(int);
GK::algorithms::insertionSort<int, len>(arr);
while(++i < 5)
cout << arr[i] << " ";
cout << endl;
exit(EXIT_SUCCESS);
}
~/code/gklib/cxx/gk.cc
#include "gk.hh"
template<class T, size_t len>
void GK::algorithms::insertionSort(T arr[len]){
// insertion sort
}
~/code/gklib/cxx/gk.hh
#pragma once
#include <cstdlib>
#define NAMESPACE(ns) namespace ns {
#define END_NAMESPACE(ns) }
NAMESPACE(GK)
NAMESPACE(algorithms)
template<class T, size_t len>
extern void insertionSort(T arr[len]);
END_NAMESPACE(algorithms)
END_NAMESPACE(GK)
I've tried many variations on my commands with no result. Internet is full of tutorials and forums with instructions those did not work for me. This code ran perfectly when all the stuff was in one file. How can I resolve this problem? Thanks in advance.
I think it's more something like:
cxx some_stuff.o -L$HOME/gklib/cxx/lib -B../gklib/cxx/lib -lgklib -o some_stuff
-lgklib, not -Igklib (-I option specify an include folder)
but you'll have to rename your gklib.a by libgklib.a
Maybe you can even remove -B../gklib/cxx/lib, just try it out :)
I see several problems: in order:
If this is your exact command line, the -L option doesn't
point to the structure you've shown above (where there is no
cxx in the path).
I don't know why you're using -B. This tells the compiler
where to look for its libraries, etc. Normally, this is only
necessary when you want to test parts of the compiler you've
modified.
I don't see where you've specified to link against the
library. Since the library doesn't respect the usual naming
conventions (libname.a), you'll have to
specify it directly (in the same way you'd specify an object
file), and the -L option isn't used. Alternatively, you name
it libgk.a, or something like that, and add a -lgk to the
command line, after your object files.
Finally, the error messages refer to an instantiation of
a template. This typically occurs because the implementation of
the template is in a source file, not in the header. The
standard requires that the implementation be visible when it
triggers the instantiation of a template. The way g++ (and
almost every other compiler) works is that if the implementation
isn't visible, they suppose that the template will be
instantiated in another translation unit, and output external
references to it. But if the implementation is in a source,
there will be no instantiation, and you'll get a linker error.
(You'll also not find the assembler for the instantiation
anywhere, either, because the template hasn't been
instantiated.) You should include the source code at the bottom
of your header, and not compile it separately.
I have solved this problem, with the help of this and this questions. The problem lies in the fact that void insertionSort(T *) is a template function, and template functions can only be implemented in header files. The reason for this is, the compiler needs to reach the definition of the to create a new function for each call to it with a different type as the argument to template. I have moved the definition of this function to gk.h, which resulted in a successfull compilation and linkage.
I'm a novice at C++. Be patient if this is incoherent. I'm called upon to build a large system on linux that was originally built on OS X, where it works fine. The original authors are no longer with the company. The build system makes use of autotools, but there are also some hand made Makefiles which walk through the system calling the auto-made Makefiles. I've managed to get all of the c++ code compiled. The build system also uses libtools, and shared libraries are produced and deposited in /usr/local/lib.
So now I'd like to use these libraries. I've written a short program that simply instantiates an object of class ds_dictionary and calls one of its methods. Here it is:
#include <iostream>
#include <DSUtils/DSUtils.h>
int main (int argc, char * const argv[]) {
int32_t integer_data=123;
char key_alice_integer[] = "alice_integer";
ds_dictionary my_dict;
my_dict.add_int(key_alice_integer, integer_data);
return 0;
}
I compile this with
g++ -lDSUtils -o main my_test_code.cpp
With the result:
//usr/local/lib/libDSUtils.so: undefined reference to `ds_breakdown_from_time_interval'
//usr/local/lib/libDSUtils.so: undefined reference to `ds_date_breakdown_with_string'
//usr/local/lib/libDSUtils.so: undefined reference to `ds_seconds_duration_of_interval'
... (about 25 lines like these)
collect2: ld returned 1 exit status
Let's look inside the library:
garyp#VM:/usr/local/lib$ nm libDSUtils.so | grep ds_breakdown_from_time
U ds_breakdown_from_time_interval
The "U" in the line above ... does that mean that the library wasn't built correctly?
Am I calling g++ correctly?
Do I have to put something in the code to tell it that I'm using functions found in that library?
What are possible errors? Where should I start poking around?
EDIT:
Aha. The library DSUtils is built from several c++ sources. There is one c program in the source, and it contains all of the problem functions. The Makefile system doesn't deal at all with that one c file. That c program compiles. Ideally I suppose I'd figure out how to modify the Makefile to compile that file and add it to the library, but I'm not to the point where I can figure out how to do that.
Can I add the .o file to the existing library? How? Create a library with one file? etc?
EDIT_2: I simply did
g++ -o main -lDSUtils main.o my_new_objectfile.o
and the thing compiles, links, and runs without error. Should that work? After fixing a logic bug, it does work.
This
U ds_breakdown_from_time_interval
tells me that ds_breakdown_from_time_interval will be resolved by another library during runtime. So I am guessing you need to link to the library that defines ds_breakdown_from_time_interval.
I've tried looking at similar problems, but could not easily find one that helped my problem.
I've created a project in C++ and am working on UNIX to compile, link, and run it. My specific problem is an undefined reference to a method I declare in a separate file.
In the file SharedCache.cpp, I have the following method:
int SharedCache::replaceLine(ullong address){
int evictPID = -1;
int cacheSet = calcCacheSet( address );
//random uniformly-distributed value for cache line
float numLines = static_cast<float>(CACHE_LINES_PER_SET);
uint cacheLine = static_cast<uint>(uniformDistr( numLines ));
if(cache[cacheSet][cacheLine] != NULL){
evictPID = cache[cacheSet][cacheLine]->PID;
}
uint PID= calcPID(address);
uint tag= calcTag(address);
cache[cacheSet][cacheLine]->setLine(PID, tag); //mutex method
return PID;
}
The line uint cacheLine = static_cast<uint>( uniformDistr( numLines )); makes a call to the function I want to use from another file. The linker error is an undefined reference to this method.
uniformDistr( float ); is declared in the header distributions.h and defined in distributions.cpp. In my project options I set the linker flag -distributions and I also compiled the distributions.cpp to make sure a distributions.o file exists to link with.
From here, I don't know where to go, because this has not solved the problem.
Without more precise information on which compiler/linker commands were invoked and the exact error outputs, it is difficult to provide a good answer.
However, from your description of what you did, it seems that you are not passing distributions.o to the linker. Unlike other languages where the compiler/linker search for object files to link in automatically, C++ linkers require an explicit specification of the objects to link together.
Your use of -ldistributions here is incorrect: the -l flag is used to link to a static or dynamic library (respectively .a and .so files on Linux), whereas you want to specify another object file that the linker should consider. Specifying -ldistributions makes the linker look for distributions.a or distributions.so in the standard library locations.
Basically, your linker invocation now looks something like this (probably with many more flags and libraries):
gcc -o my_program SharedCache.o -ldistributions
To correctly link the distributions code in, you need to make it look something like (again, many flags and libraries probably missing compared to the real thing):
gcc -o my_program SharedCache.o distributions.o
This should resolve the missing symbols issue and produce a working binary (or at the very least a different error ;-) ). How to do this in KDevelop however I do not know.
I've not used KDevelop, however, on the command line you would just add distributions.o as an input file to the linking process. No need for dashes or leaving off the .o extension.
Alternatively, can you just add distributions.cpp to your KDevelop project? That way it should get compiled and linked automatically (this is how it works in things like Visual Studio or Eclipse).
Did you add the distributions.cpp to your makefile? Also I believe the required linker flag is -ldistributions.