HI,
I have some questions about .h files and .cpp files in c++/linux(ubuntu).
It is possible to compile a .h file using g++ or you can just compile a .cpp file that includes the .h file?
From a .h file and it's .cpp file (.cpp where i include some code to the methods i've defines in .h file) I create a .so file using the command:
g++-fPIC -shared my_code.cpp -o my_code.so`
In the test.cpp I include the .h file and using dlopen i create a handler over the .so file. Why do I have the following error:
undefined reference to bool `Class::method(std::string)` `collect2: ld returned 1 exit status
If I say virtual bool method... in the .h file there is no error when I compile test.cpp. Can someone explain what am I doing wrong? The thing is that i have a template. With templates I cannot use virtual..so..i have this undefined error and i don't know how to resolve it. THX
EDIT:
When i compile the my_code.cpp I have the errors:
/usr/bin/ld: .usr/lib/debug/usr/lib/crt1.o relocation 0 has invalid symbol index 12 (same with index 13,2,14...22 ).
But when i create the .so file there is no error . I use:
g++ test.coo -ldl -o test
for the test.cpp compilation.
Ad 1: It is possible to compile .h file (you can explicitly override the language detection), but you don't want to do it. The .h file is intended to be included and will not compile to anything useful on it's own.
Ad 2: You have to link against the library you created by passing the -lmy_code (but note that for that to work you have to create it as libmy_code.so) along with appropriate -L flag (directory where you placed libmy_code.so) to the linker. Like this:
g++ test.cpp -L. -lmy_code -ldl -o test
But you also have to change the first command to:
g++ -fPIC -shared my_code.cpp -o libmy_code.so
^^^
libraries *must* have `lib` prefix on unix systems.
and this assumes both are done in the same directory—if not, you have to adjust the -L option to point to the directory where libmy_code.so is. Also you have to place libmy_code.so somewhere where the dynamic linker can find it. Either by installing it or by setting environment variable LD_LIBRARY_PATH to appropriate directory. Alternatively you can compile by using
g++ test.cpp my_code.so -ldl -o test
This does not force the lib prefix and it creates an "rpath" entry in the binary so it will find the library in the original place.
This all assumes you want to use it as regular library in which case you don't want to use dlopen. dlopen is for opening libraries as plugins at runtime and than they can only be accessed by fetching pointers to symbols using dlsym(), but if you want to access the library normally, you have to link against it so the linker can resolve the symbols.
If instead you wanted to use dlopen, you must not include my_code.h in test.cpp and must not use anything it defines except by getting the symbols with dlsym. And since this is C++, it in turn requires you understand the symbol mangling scheme, because dlsym will not do this for you.
Generally there is no need to compiling a .h file, it simply generates a huge file with .gch extension I guess.
The error you are getting is a link time. While creating the .so file, you do not actually link the code. So all undefined symbol are assumed to be present at some place. When you link it, the linker will find for those symbols. So, you should compile/link all the .cpp file together. The error will go away.
Also, For templates, the definition of the code must always be visible. So wherever you write the templated function/variable definition, include that file everywhere.
Edit:
You can have virtual method with template classes; but you can not have virtual template methods.
template<typename T>
class A {
virtual void foo(int); // ok
};
class A {
template<typename T>
virtual void foo(T); // illegal
};
Related
I have a template class of a binary tree, tree.tpp and tree.h. I have done a test with the class but I can't compile it
#include <cstdlib>
#include <iostream>
#include "arbolbinario.h"
using namespace std;
int main(int argc, char** argv) {
ArbolBinario<int> pila(45);
return 0;
}
And I'm having the following error when I do: g++ -c -o ./tree.o ./tree.tpp -I ./tree.h
g++: warning: ./tree.tpp: linker input file unused because linking not done
(I'm working with netbeans)
.tpp is not one of the file endings recognized by g++, see its documentation.
Therefore g++ assumes that you want the file to be passed to the linker directly. But since you used the -c flag, which indicates that you want g++ to only compile, but not invoke the linker, you get that error message.
The solution is to tell g++ what kind of file it is that you are passing it explicitly:
g++ -c -o ./tree.o -x c++ ./tree.tpp -I ./tree.h
or, better, rename your C++ source file use one of the common file endings for C++ source files, e.g. .cpp, .cc, .cxx, etc. That would result in less trouble with build tools and less confusion for others looking at your project.
As noted in the question comments -I ./tree.h also is clearly wrong, but not the cause of this particular error (and probably it just doesn't belong there at all).
However:
If your .tpp contains the implementation of methods of a class template, then you should not rename it (.tpp is appropriate in that case), but you also should not compile it as translation unit at all. That means it should not appear in any g++ command.
.tpp files implementing a template classes methods need to be included in the .h file with the class template definition, instead. Otherwise you will get linker errors later when you try to link your files, see Why can templates only be implemented in the header file?.
The -c flag tells GCC to only compile the input source files, not to do any linking.
If you want the compiler to link the object files into an executable binary, you need to remove the -c flag.
I have a c++ project that references the .h and .cpp files from the (ACE_TAO) library. (http://www.theaceorb.com/)
I have included the library paths to the project GCC C++ compiler and GCC C++ Linker.
However, when I try to build my project, I keep getting an error.
undefined reference to ACE_Message_Block::~ACE_Message_Block()
| line 627 external location /home/user/Documents/ACE_wrappers/ace/CDR_Stream.inl
undefined reference to CORBA::ORB~ORB();
| line 45 external location /home/user/Documents/ACE_wrappers/Tao/tao/ORB.inl
Here's my own project header file
#ifndef MESSENGERSERVER_H_
#define MESSENGERSERVER_H_
#include <tao/ORB.h> // this is causing the error
class MessengerServer {
public:
MessengerServer();
virtual ~MessengerServer();
private:
CORBA::ORB_var orb; // this is causing the error
1) I have included the right header file and eclipse is able to to resolve the header file, so this must mean that my library paths is correct right?
2) If my library paths are correct, why is eclipse unable to link to the .cpp files for the implementation of the 2 methods? my .h file and .cpp files are in the same folder directory.
3) I thought that it could be because I do not have the .o files in the library paths, so i ran 'make' and generated the .o files in the same directory, but I still get the same error.
Am I missing/misunderstanding something? Thanks in advance.
update:
Here's the command Eclipse c++ used to build my project
g++ -I/home/user/Documents/ACE_wrappers/TAO/
-I/home/user/Documents/ACE_wrappers/ace/
-I/home/user/Documents/ACE_wrappers/
-O0- g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"myMain.d" -MT"myMain.d" -o"myMain.o" "../myMain.cpp"
Finished Building:../MyMain.cpp
g++ -I/home/user/Documents/ACE_wrappers/TAO/
-I/home/user/Documents/ACE_wrappers/ace/
-I/home/user/Documents/ACE_wrappers/
-O0- g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"MyServer.d" -MT"MyServer.d" -o"MyServer.o" "../MyServer.cpp"
Finished Building:../MyServer.cpp
g++ -L/home/user/Documents/ACE_wrappers/TAO/
-L/home/user/Documents/ACE_wrappers/ace/
-L/home/user/Documents/ACE_wrappers/
-o "TAOServer" ./myMain.o ./MyServer.o
./MyMain.o: In function 'ACE_InputCDR:~ACE_InputCDR()':
/home/user/Documents/ACE_wrappers/ace/CDR_Stream.inl:627: undefined reference to ACE_Message_Block::~ACE_Message_Block()
./MyServer.o: In function 'CORBA::ORB:decr_refcount()':
/home/user/Documents/ACE_wrappers/Tao/tao/ORB.inl:45: undefined reference to CORBA::ORB~ORB();
The linking is failing. No, your "include" path determines whether you can find a header file. The "library" path is used for linking against the object files or the library files. The linking is not working.
The missing functions are the destructors for the classes ACE_Message_Block and ORB. Find the source files for them, compile them, and make sure the compiled object files are on the library path for your project.
I'm new to C and wanted to use a library (MLT Multimedia Framework)
I've built it and it produced the following directories: include lib share
Inside lib there are .so .a .la files
Inside include there are .h files
Now, I'm instructed to do this:
#include <framework/mlt.h> which is inside include/mlt/framework/
Questions:
Why I do I need to place the header file that contains only function prototypes? Where are the real functions then? are they linked someway to the ones included in lib directory?
Where to place my own files and how to compile it?
How to learn more about the topics:
Dynamic/Static libraries
Building / making / installing
How to use any C library
If you don't have the function prototypes, how would the compiler know what functions exist in the library? Short answer is: It doesn't. Longer answer: The compiler doesn't care about library files, static (files ending in .a) or shared (files ending in .so), all it cares about is the current translation unit. It's up to the linker to handle resolving undefined references.
When you use libraries, you include the header files that contain the needed declarations (structures, classes, types, function prototypes) into the source file. The source file plus all included header files forms the translation unit that the compiler uses to generate code. If there are undefined references (for example a call to a function in the library) the compiler adds special information about that to the generated object file. The linker then looks through all object files, and if it finds an unresolved reference it tries to find it in the other object files and the provided libraries. If all definitions are resolved the linker generates the final executable, otherwise it will report the unresolved definitions as errors.
To answer your other questions:
Where to place my own files and how to compile it?
This is two questions, the answer to the first one (about placement of your files) is that it doesn't really matter. For small project with only a few source and header files, it's common to place all files in a common project directory.
The second question, about compiling, there are different ways to do it too. If there are only one or two source files you could use the compiler frontend (e.g. gcc) to compile and link and generate your executable all in one go:
$ gcc -Wall -g source1.c source2.c -o your_program_name
The above command takes two source files, compiles and links them into the program your_program_name.
If you need to use a library, there are one or two things that you need to add to the above command line:
You need to tell the linker to link with the library, this is done with e.g. the -l (lower case L) option:
$ gcc -Wall -g source1.c source2.c -o your_program_name -lthe_library
It's important to note that the_library is the base name of the library. If the library file is named libthe_library.so then only the_library part is needed, the linker will add the other parts automatically.
If the library is not in a standard location, then you need to tell the compiler and linker where the library file are. This is done with the -I (capital i) option to tell the preprocessor where the header files are, and the -L (capital l) where the linker files are.
Something like
$ gcc -Wall -g -Ilocation/of/headers source1.c source2.c -o your_program_name -Llocation/of/libraries -lthe_library
If you have more than a couple of source files, it's common to use so called makefiles that lists all source files, their dependencies, compiler and linker flags, and contain rules on how to build object files and link the final program. Such a makefile could look like
CFLAGS = -Wall -g
LDFLAGS = -g
SOURCES = source1.c source2.c
OBJECTS = $(SOURCES:.c=.o)
TARGET = your_program_name
.PHONY: all
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(LD) $(LDFLAGS) $^ -o $#
%.o: %.c
$(CC) $(CFLAGS) $< -c -o $#
The above makefile should do just about the same as the previous command line. The big difference is that it's much easier to add more source files, add special rules for special files, and most importantly, the make program will handle dependencies so that if one source file haven't been modified since last build then it won't be compiled. The last bit will make big projects with many source files build much quicker when only one or a few source files has been modified.
How to learn more about the topics [...]
By going to your favorite search engine, and looking for those topics there. I also recommend e.g. Wikipedia.
Of course, if you use an Integrated Development Environment (a.k.a. an IDE) then you don't have to compile from the command line, or to make your own makefiles, the IDE will handle all that for you. It will also have dialogs for the project settings where you can enter include paths and library paths, and what libraries to link with.
Why I do I need to place the header file that contains only function prototypes?
So as to satisfy your compiler for declaration of those functions or declaration of classes. As C++ is static type checking language, they must know the type of objects which they will be using.
Where to place my own files and how to compile it?
You can place you code anywhere in you filesystem; only make sure to include .h files in includes path and lib while compiling. Usually you need to modify your path.
You can check about building on this link:
https://en.wikipedia.org/wiki/GNU_build_system
Check the README file that came with the code. It should tell you how to install it into the system properly. Usually there is an install build target which installs the resulting files into the proper directories.
The usual sequence of commands to build and install most products is:
$ ./configure
$ make
$ sudo make install
I've been trying to install a library (gzstream), which consists of one .C, one .h and an appropriate makefile. To be able to use #include <gzstream.h>, which gzstream.C uses, I've put the gzstream.h file in /usr/local/include and the gzstream.C in /usr/local/lib.
When I try to compile aufgabe2.cpp, I get the following error message on the terminal. aufgabe2.cpp:1:22: fatal error: /usr/local/include/gzstream.h: Permission denied
compilation terminated.
What am I doing wrong?
Before being able to use the static library, you need to compile it. This will require you to cd to the directory where the source code for gzstream is present and then type make.
This will compile the library and create an output file libgzstream.a.
Once this is ready, you can include the header file and compile your code.
There is no strict need to copy the gzstream.h into /usr/local/include. It may as well reside in the local directory where your source code is present. Then it can be easily included with
#include "gzstream.h"
See how double quotes are used instead of the angular brackets to indicate relative path in current directory.
The g++ command line should be something like this.
g++ aufgabe2.cpp -L. -lgzstream -lz
-L. tells the linker to look for the static library in the current directory. This assumes that libgzstream.a is copied to your source directory where aufgabe2.cpp is present. If not, then give the relative path to the -L argument where libgzstream.a is present.
Arguments -lgzstream and -lz ask the linker to link these libraries.
I've been working with and testing a self-registering, abstract factory based upon the one described here:
https://stackoverflow.com/a/582456
In all my test cases, it works like a charm, and provides the features and reuse I wanted.
Linking in this factory in my project using cmake has been quite tricky (though it seems to be more of an ar problem).
I have the identical base.hpp, derivedb.hpp/cpp, and an equivalent deriveda.hpp/cpp to the example linked. In main, I simply instantiate the factory and call createInstance() twice, once each with "DerivedA" and "DerivedB".
The executable created by the line:
g++ -o testFactory main.cpp derivedb.o deriveda.o
works as expected. Moving my derived classes into a library (using cmake, but I have tested this with ar alone as well) and then linking fails:
ar cr libbase.a deriveda.o derivedb.o
g++ -o testFactory libbase.a main.cpp
only calls the first static instantiation (from derivedA.cpp) and never the second static instantiation, i.e.
// deriveda.cpp (if listed first in the "ar" line, this gets called)
DerivedRegister<DerivedA> DerivedA::reg("DerivedA");
// derivedb.cpp (if listed second in the "ar" line, this does not get called)
DerivedRegister<DerivedB> DerivedB::reg("DerivedB");
Note that swapping the two in the ar line calls only the derivedb.cpp static instantiation, and not the deriveda.cpp instantiation.
Am I missing something with ar or static libraries that somehow do not play nice with static variables in C++?
Contrary to intuition, including an archive in a link command is not the same as including all of the objects files that are in the archive. Only those object files within the archive necessary to resolve undefined symbols are included. This is a good thing if you consider that once there was no dynamic linking and otherwise the entirety of any libraries (think the C library) would be duplicated into each executable. Here's what the ld(1) manpage (GNU ld on linux) has to say:
The linker will search an archive only once, at the location where it is specified on the command line. If the archive defines a symbol which was undefined in some object which appeared before the archive on the command line, the linker will include the appropriate file(s) from the archive. However, an undefined symbol in an object appearing later on the command line will not cause the linker to search the archive again.
Unfortunately there's no standard way to include every member of an archive in the linked executable. On linux you can use g++ -Wl,-whole-archive and on Mac OS X you can use g++ -all_load.
So with GNU binutils ld, the link command should be
g++ -o testFactory -Wl,-whole-archive libbase.a -Wl,-no-whole-archive main.cpp
the -Wl,-no-whole-archive ensures that any archive appearing later in the final link command generated by g++ will be linked in the normal way.