Cygwin linking shared library - c++

UPDATE:
Removed old question about .so files. They aren't intended to work on Windows.
I solved the below using a header file. I am guessing it is a standard convention to use .h file every time you link using C++?
mydll.h:
#ifndef mydll_h_
#define mydll_h_
void hello();
#endif
myprog.cc:
#include "mydll.h"
int main ()
{
hello ();
return 0;
}
mydll.cc:
#include <iostream>
void hello()
{
std::cout << "Hello World!\n";
}
Alternatively, I tried .dll library using Cygwin with this guide: https://cygwin.com/cygwin-ug-net/dll.html
The compilation for their .c files work, but I am trying to get it to work for my .cc files. Any ideas?
mydll.cc:
#include <iostream>
void hello()
{
std::cout << "Hello World!\n";
}
myprog.cc:
int main ()
{
hello ();
return 0;
}
I typed:
g++ -c mydll.cc
g++ -shared -o mydll.dll mydll.o
But when I type:
g++ -o myprog myprog.cc -L./ -lmydll
I get:
myprog.cc: In function ‘int main()’:
myprog.cc:4:10: error: ‘hello’ was not declared in this scope
hello ();

You're facing a compiler problem; not a linker problem. The compiler is telling you that when it compiles myprog.cc, it can't find function hello().
You need to write a function declaration for hello(). Note: you're function definition for hello() is in mydll.cc.
A function declaration would simply be:
void hello();
(1) You could place this one line of code in your myprog.cc above int main().
(2) You could also place this one line of code in a header file that is included at least by myprog.cc and optionally by mydll.cc. But good programming practice dictates that the header file should be included by both.
If you follow option 1, the following version of myprog.cc will fix your compiler error:
void hello(); // "extern void hello();" would be more proper.
int main ()
{
hello ();
return 0;
}
Option 2 would entail:
myprog.cc:
#include <mydll.h>
int main ()
{
hello ();
return 0;
}
Either way results in successful compilation and execution:
>g++ -c mydll.cc
>g++ -shared -o mydll.dll mydll.o
>g++ -o myprog myprog.cc -L./ -lmydll
>./myprog.exe
Hello World!
>

Related

Including files correctly , but still getting linker error

hope you guys are doing well. I am just getting linker error in C++ , I don't know why? Everything is correct....
Check below testing.h file
#ifndef __MYClass__
#define __MYClass__
#include<iostream>
using namespace std;
class Abc {
private:
int a;
public:
void input();
void display();
};
#endif
and here's implementation of these functions in Functions.cpp file.
#include"testing.h"
void Abc::input() {
cout<<"Enter any value : ";
cin>>a;
}
void Abc::display() {
cout<<"You Entered : "<<a;
}
And now, in main.cpp
#include<iostream>
#include"testing.h"
using namespace std;
int main() {
Abc obj;
obj.input();
obj.display();
return 0;
}
All files are compiled successfully.
In main.cpp Linker says....
g++ -Wall -o "main" "main.cpp" (in directory: /home/Welcome/C++ Practices/testingLinux)
/usr/bin/ld: /tmp/ccYI9LAy.o: in function main': main.cpp:(.text+0x10): undefined reference to Abc::input()'
/usr/bin/ld: main.cpp:(.text+0x1c): undefined reference to `Abc::display()'
collect2: error: ld returned 1 exit status
Compilation failed.
I'm using built-in linux compiler...
There are multiple ways you can fix this but before that please read up on Translation Unit.
Coming to your problem.
When you write
g++ -Wall -o main main.cpp
The compiler will pick up main.cpp for compilation and expand testing.h that includes the declaration for class ABC and with this header file it can determine what is the size of ABC and be able to generate instructions reserving space for obj on the stack. It can't see the definition for input() and display() hence defers that task to the linker. Note that testing.cpp is not in the picture at all since the compiler doesn't know that the implementation of ABC is in testing.cpp. Now when the linker tries to resolve the symbols input() it fails to find the definition for it and throws the error
undefined reference to Abc::input()
So, to fix this you can tell explicitly upfront that it also needs to take in testing.cpp while compiling main.cpp by
g++ -o main main.cpp testing.cpp
Another way is to create a dynamic library out of testing.h and testing.cpp
g++ -shared -fPIC testing.cpp -o libtest
and then link it against main.cpp
g++ -o main main.cpp -I. -L. libtest
What this does is that the compiler still can't figure out the definition of input() and display() but the linker can since now the library containing the definitions is provided to it.
You are not compiling Functions.cpp file.
This should fix your issue:
g++ main.cpp Functions.cpp

Calling C code from C++ with using extern "C"

I have 3 files with me, one c++ file, main.cpp, one c file, test.c and one header file, test.h
I wanted to try and use C code into C++ file. For the same reason, I have declared an function in test.h and defined that in test.c and using that in main.cpp
main_temp.c is just for explanation.
test.h
void test(int);
test.c
#include <stdio.h>
void test(int a) {
printf("%d", a);
main_temp.cpp
#include "test.h"
int main() {
foo(5);
}
Here, I understand why this would not work. C symbol would be simple 'foo' but since C++ does more things while creating symbols, it might be 'void#test(int)' and to solve this name mangling problem, I have to treat C++ symbol as a C symbol. So, I would use extern "C" and my main.cpp becomes as like:
main.cpp
extern "C" {
#include "test.h"
}
int main() {
foo(5);
}
I could not understand as to why this would not work! I get :
main.cpp:(.text+0xa): undefined reference to `test`
Can somebody share the insights?
I trust you compile or link them together? Else that would be the cause. On gcc it would be something like:
g++ -c -o main.o main.cpp
gcc -c -o test.o test.c
g++ -o a.out main.o test.o
Assuming you have no bugs with compiling/linking, compile both main.cpp and test.c into object files and run nm on both. It will show what symbol main.o wants and what symbol test.o exports. It should become clear then why linker cannot do its job.

C++ gcc Namespace not found

I know there are many similar topics but there are equally many unique mistakes that may lead to this problem (so I think). Therefore I ask, after some research.
My problem is that the compiler, GNU GCC, when compiling one file does not see my namespace declared in another file. The IDE (CodeBlocks) evidently does see it as it auto-completes the name of the namespace. I tried to isolate the problem and came up with this:
File main.cpp:
namespace MyName
{
int MyVar;
}
#include "T1.cpp"
int main()
{
return 0;
}
File T1.cpp:
using namespace MyName;
error: 'MyName' is not a name-space name.
In my project I have a header file, say T1.h, and an implementation file T1.cpp — and MyName isn't accessible in either of them.
Any help or guidance would be appreciated.
What's happening is that CodeBlocks is compiling both main.cpp and T1.cpp. Here is what happens when you try to compile each one:
main.cpp:
$ g++ main.cpp
$
T1.cpp
$ g++ T1.cpp
T1.cpp:1:17: error: ‘MyName’ is not a namespace-name
using namespace MyName;
^
T1.cpp:1:23: error: expected namespace-name before ‘;’ token
using namespace MyName;
^
$
T1.cpp, when compiled on it's own, has no knowledge of MyName. To fix this, don't include .cpp files, and put your declarations in header files.
Edit: From what I gather, this may be a better way to organize your example:
T1.h:
namespace MyName {
extern int MyVar;
}
T1.cpp
#include "T1.h"
int MyName::MyVar = 5;
main.cpp
#include "T1.h"
#include <iostream>
using namespace MyName;
int main()
{
std::cout << MyVar << std::endl;
return 0;
}
Now it will compile correctly:
$ g++ -c T1.cpp -o T1.o
$ g++ -c main.cpp -o main.o
$ g++ T1.o main.o
$ ./a.out
5

Systemc Error with the library

I installed the SystemC library 2.3.1 using this tutorial.
I wrote this hello world example:
//hello.cpp
#include <systemc.h>
SC_MODULE (hello_world) {
SC_CTOR (hello_world) {
}
void say_hello() {
cout << ”Hello World systemc-2.3.0.\n”;
}
};
int sc_main(int argc, char* argv[]) {
hello_world hello(“HELLO”);
hello.say_hello();
return(0);
}
and compiled with this command:
export SYSTEMC_HOME=/usr/local/systemc230/
g++ -I. -I$SYSTEMC_HOME/include -L. -L$SYSTEMC_HOME/lib-linux -Wl,-rpath=$SYSTEMC_HOME/lib-linux -o hello hello.cpp -lsystemc -lm
When I compile the code, I got a error with the library:
In file included from hello.cpp:1:0:
/usr/local/systemc230/include/systemc.h:118:16: error: ‘std::gets’ has not been declared
using std::gets;
^~~~
How can I solve this?
std::gets has been removed in C++11 (See What is gets() equivalent in C11?)
If you're building using C++11 flag (maybe with a g++ alias), you have to disable this line in systemc.h.
Replace
using std::gets;
with
#if defined(__cplusplus) && (__cplusplus < 201103L)
using std::gets;
#endif
As guyguy333 mentioned, in new versions, g++ is an alias for C++11.
so adding -std=c++98 would solve the problem.
The compile command may like
$ g++ -std=c++98 -lsystemc -pthread main.cpp -o main
You seem to have copy pased the code from webpage as it is. Please remember “” and "" are not the same thing. On line 8
cout << ”Hello World systemc-2.3.0.\n”;
replace it with
cout << "Hello World systemc-2.3.0.\n";
and on line 13
hello_world hello(“HELLO”);
replace it with
hello_world hello("HELLO");
And then execute the code again.
GoodLuck.

How to pass arguments to a method loaded from a static library in CPP

I'm trying to write a program to use a static library of a C++ code into another C++ code. The first C++ code is hello.cpp:
#include <iostream>
#include <string.h>
using namespace std;
extern "C" void say_hello(const char* name) {
cout << "Hello " << name << "!\n";
}
int main(){
return 0;
}
The I made a static library from this code, hello.a, using this command:
g++ -o hello.a -static -fPIC hello.cpp -ldl
Here's the second C++ code to use the library, say_hello.cpp:
#include <iostream>
#include <string>
#include <dlfcn.h>
using namespace std;
int main(){
void* handle = dlopen("./hello.a", RTLD_LAZY);
cout<<handle<<"\n";
if (!handle) {
cerr<<"Cannot open library: "<<dlerror()<<'\n';
return 1;
}
typedef void (*hello_t)();
dlerror(); // reset errors
hello_t say_hello = (hello_t) dlsym(handle, "say_hello");
const char *dlsym_error = dlerror();
if (dlsym_error) {
cerr<<"Cannot load symbol 'say_hello': "<<dlsym_error<<'\n';
dlclose(handle);
return 1;
}
say_hello("World");
dlclose(handle);
return 0;
}
Then I compiled say_hello.cpp using:
g++ -W -ldl say_hello.cpp -o say_hello
and ran ./say_hello in the command line. I expected to get Hello World! as output, but I got this instead:
0x8ea4020
Hello ▒▒▒▒!
What is the problem? Is there any trick to make compatibility for method's argument like what we use in ctypes or what?
If it helps I use a lenny.
EDIT 1:
I have changed the code and used a dynamic library, 'hello.so', which I've created using this command:
g++ -o hello.so -shared -fPIC hello.cpp -ldl
The 6th line of the code changed to:
void* handle = dlopen("./hello.so", RTLD_LAZY);
When I tried to compile say_hello.cpp, I got this error:
say_hello.cpp: In function ‘int main()’:
say_hello.cpp:21: error: too many arguments to function
I also tried to compile it using this line:
g++ -Wall -rdynamic say_hello.cpp -ldl -o say_hello
But same error raised. So I removed the argument "World" and the it has been compiled with no error; but when I run the executable, I get the same output like I have mentioned before.
EDIT 2:
Based on #Basile Starynkevitch 's suggestions, I changed my say_hello.cpp code to this:
#include <iostream>
#include <string>
#include <dlfcn.h>
using namespace std;
int main(){
void* handle = dlopen("./hello.so", RTLD_LAZY);
cout<<handle<<"\n";
if (!handle) {
cerr<<"Cannot open library: "<<dlerror()<<'\n';
return 1;
}
typedef void hello_sig(const char *);
void* hello_ad = dlsym(handle, "say_hello");
if (!hello_ad){
cerr<<"dlsym failed:"<<dlerror()<<endl;
return 1;
}
hello_sig* fun = reinterpret_cast<hello_sig*>(hello_ad);
fun("from main");
fun = NULL;
hello_ad = NULL;
dlclose(handle);
return 0;
}
Before that, I used below line to make a .so file:
g++ -Wall -fPIC -g -shared hello.cpp -o hello.so
Then I compiled say_hello.cpp wth this command:
g++ -Wall -rdynamic -g say_hello.cc -ldl -o say_hello
And then ran it using ./say_hello. Now everything is going right. Thanks to #Basile Starynkevitch for being patient about my problem.
Functions never have null addresses, so dlsym on a function name (or actually on any name defined in C++ or C) cannot be NULL without failing:
hello_t say_hello = (hello_t) dlsym(handle, "say_hello");
if (!say_hello) {
cerr<<"Cannot load symbol 'say_hello': "<<dlerror()<<endl;
exit(EXIT_FAILURE);
};
And dlopen(3) is documented to dynamically load only dynamic libraries (not static ones!). This implies shared objects (*.so) in ELF format. Read Drepper's paper How To Use Shared Libraries
I believe you might have found a bug in dlopen (see also its POSIX dlopen specification); it should fail for a static library hello.a; it is always used on position independent shared libraries (like hello.so).
You should dlopen only position independent code shared objects compiled with
g++ -Wall -O -shared -fPIC hello.cpp -o hello.so
or if you have several C++ source files:
g++ -Wall -O -fPIC src1.cc -c -o src1.pic.o
g++ -Wall -O -fPIC src2.cc -c -o src2.pic.o
g++ -shared src1.pic.o src2.pic.o -o yourdynlib.so
you could remove the -O optimization flag or add -g for debugging or replace it with -O2 if you want.
and this works extremely well: my MELT project (a domain specific language to extend GCC) is using this a lot (generating C++ code, forking a compilation like above on the fly, then dlopen-ing the resulting shared object). And my manydl.c example demonstrates that you can dlopen a big lot of (different) shared objects on Linux (typically millions, and hundred of thousands at least). Actually the limitation is the address space.
BTW, you should not dlopen something having a main function, since main is by definition defined in the main program calling (perhaps indirectly) dlopen.
Also, order of arguments to g++ matters a lot; you should compile the main program with
g++ -Wall -rdynamic say_hello.cpp -ldl -o say_hello
The -rdynamic flag is required to let the loaded plugin (hello.so) call functions from inside your say_hello program.
For debugging purposes always pass -Wall -g to g++ above.
BTW, you could in principle dlopen a shared object which don't have PIC (i.e. was not compiled with -fPIC); but it is much better to dlopen some PIC shared object.
Read also the Program Library HowTo and the C++ dlopen mini-howto (because of name mangling).
example
File helloshared.cc (my tiny plugin source code in C++) is
#include <iostream>
#include <string.h>
using namespace std;
extern "C" void say_hello(const char* name) {
cout << __FILE__ << ":" << __LINE__ << " hello "
<< name << "!" << endl;
}
and I am compiling it with:
g++ -Wall -fPIC -g -shared helloshared.cc -o hello.so
The main program is in file mainhello.cc :
#include <iostream>
#include <string>
#include <dlfcn.h>
#include <stdlib.h>
using namespace std;
int main() {
cout << __FILE__ << ":" << __LINE__ << " starting." << endl;
void* handle = dlopen("./hello.so", RTLD_LAZY);
if (!handle) {
cerr << "dlopen failed:" << dlerror() << endl;
exit(EXIT_FAILURE);
};
// signature of loaded function
typedef void hello_sig_t(const char*);
void* hello_ad = dlsym(handle,"say_hello");
if (!hello_ad) {
cerr << "dlsym failed:" << dlerror() << endl;
exit(EXIT_FAILURE);
}
hello_sig_t* fun = reinterpret_cast<hello_sig_t*>(hello_ad);
fun("from main");
fun = NULL; hello_ad = NULL;
dlclose(handle);
cout << __FILE__ << ":" << __LINE__ << " ended." << endl;
return 0;
}
which I compile with
g++ -Wall -rdynamic -g mainhello.cc -ldl -o mainhello
Then I am running ./mainhello with the expected output:
mainhello.cc:7 starting.
helloshared.cc:5 hello from main!
mainhello.cc:24 ended.
Please notice that the signature hello_sig_t in mainhello.cc should be compatible (homomorphic, i.e. the same as) with the function say_hello of the helloshared.cc plugin, otherwise it is undefined behavior (and you probably would have a SIGSEGV crash).