I am a newbie in Linux gcc. I am writing a simple code to learn the weak attribute in Linux gcc.
See my sample code:
weakref.c, the main file. I want to the file could work with or without foo method being defined.
#include <stdio.h>
extern void foo(void) __attribute__((weak));
int main() {
if (foo){
foo();
printf ("foo is defined\n");
} else {
printf("foo is not defined\n");
}
}
so, I run the following command to compile it and run it:
gcc weakref.c -o main_static
./main_static
and the output is "foo is not defined", which is what I expected.
Then I created a new file libfoo.c, see below:
#include <stdio.h>
void foo() {
printf("Print in foo.\n");
}
I attempted 3 ways to try to make main file work with the libfoo.c:
Compile the libfoo.c and weakref.c and link the object files.
Compile the libfoo.c as a static library, and link it with the object file of weakref.c
Compile the libfoo.c as a shared library, and link it with the object file of weakref.c
Only the 3rd way works and get the following output:
Print in foo.
foo is defined
Could you please let me know if the weak ref only works with a shared library, and why? Thanks a lot!
let me know if the weak ref only works with a shared library
Not at all.
Both 1. and 3. are expected to produce "foo is defined".
The 2. is not expected to pull libfoo.o from libfoo.a, because unresolved weak reference from weakref.o does not count as unresolved symbol for the purpose of pulling an object from an archive library. However, you can force libfoo.o to be pulled into the link like so: gcc weakref.o -lfoo -ufoo, and then you should again get "foo is defined".
Now that I stated what should happen, let's see if the practice agrees. Transcript from a Linux/x86_64 system, using gcc (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3 and GNU ld (GNU Binutils for Ubuntu) 2.20.1-system.20100303:
$ gcc -c weakref.c libfoo.c
$ ar ruv libfoo.a libfoo.o
ar: creating libfoo.a
a - libfoo.o
$ gcc weakref.o && ./a.out
foo is not defined
This is your #1:
$ gcc weakref.o libfoo.o && ./a.out
Print in foo.
foo is defined
As you can see #1 "works" as I expected, and not as you claimed. You must have made some mistake somewhere.
This is your #2:
$ gcc weakref.o -L. -lfoo && ./a.out
foo is not defined
Your #2 again, but forcing libfoo.o to be pulled into the link:
$ gcc weakref.o -L. -lfoo -ufoo && ./a.out
Print in foo.
foo is defined
Related
I have compiled a c++ code using g++ -std=c++11 -o main main.cpp -pthread and it compiled fine however if I compile the same code using gcc -std=c++11 -o main main.cpp -pthread it does not compile and throws error. The program uses threading which properly taken care of using -pthread option while compiling. For the reference I am attaching the code below. Any help is highly appreciated.
#include <iostream>
#include <thread>
class foo
{
public:
void bar(int loop_num)
{
for (int i = 0; i < loop_num; ++i) {
std::cout << "Thread executing\n";
++n;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
int n = 0;
};
int main()
{
int n = 0;
foo f;
std::thread t1(&foo::bar, &f, 5);
t1.join();
}
If you’ve written C++ code with GCC, you’ll know that you need to use the program g++, both for compilation and linking. For multi-module programs, this means every .cpp file gets compiled with g++, and then the entire program must be linked separately using g++. If you try to link the program using gcc, it will almost work, but you’ll get a lot of “undefined reference” errors, like this:
test.cpp:(.text+0x11): undefined reference to `std::cout'
The need to use g++ to link the entire program causes trouble when you have a very complicated build process you don’t have full control of. For instance, I’m trying to link C++ code with Mercury, and I have to use the Mercury linker, which in turn calls gcc.
So just a quick tip: If you are forced to use gcc to link the program, just add the library “stdc++”, as you would any other library, and it will work. That is, add the option “-lstdc++” to your GCC linker command line. For example:
g++ -c hello.cpp
gcc -lstdc++ -o hello hello.o
I assume the error you get looks something like this:
/tmp/ccUKAq0K.o: In function `main':
main.cpp:(.text+0x59): undefined reference to `std::thread::join()'
/tmp/ccUKAq0K.o: In function `__static_initialization_and_destruction_0(int, int)':
main.cpp:(.text+0xb6): undefined reference to `std::ios_base::Init::Init()'
main.cpp:(.text+0xcb): undefined reference to `std::ios_base::Init::~Init()'
/tmp/ccUKAq0K.o: In function `std::thread::~thread()':
main.cpp:(.text._ZNSt6threadD2Ev[_ZNSt6threadD5Ev]+0x1d): undefined reference to `std::terminate()'
(And so on.)
C++ programs which use the standard library (so most of them) need to be linked using g++, not gcc. Only the g++ compiler driver links in most of the standard library. The gcc compiler driver compiles C++ programs, just like g++, but when the linker is invoked, the program is treated as a C program, which usually leads to linker errors.
Try adding the -lrt flag after the pthread one.
I am trying to compile a source given a .so file libfoo.so. The only thing in this library is a function that just returns a number (yeah, I know, advanced stuff). The header file equivalent (I was provided with both, but am only supposed to use the .so) is named foo.h and the function is named int foo().
My source file is main.c:
#include <stdio.h>
#include "foo.h"
int main()
{
int x = foo();
printf("%d", x);
return 0;
}
Now, when trying to compile I have the following commands:
gcc -Wall -fPIC -c main.c -o main.o
gcc -Wall -fPIC main.o -o main -lfoo -L.
The first command fails to create the object file, outputting the following error:
fatal error: foo.h: No such file or directory
I am using Ubuntu 16.04.
I have also tried exporting the current location to LD_LIBRARY_PATH as I've seen suggested on a few other answers.
export LD_LBIRARY_PATH=$LD_LIBRARY_PATH:machine/Desktop/lib_test
You need to have the interface definition from the .h file and that file must be in the current directory or a directory on the include search path.
Note that on some systems filenames and paths are case dependent.
I installed gcc 5.4.0 recently, on Windows using Cygwin, because I wanted to test the C++14 standard features of g++. When I tried to compile, I get the following error:
$ g++-5.4.0 -std=c++14 test.cpp
-bash: g++-5.4.0: command not found
This is the code I wrote inside test.cpp:
#include <iostream>
int main()
{
auto lambda = [](auto x){ return x; };
std::cout << lambda("Hello generic lambda!\n");
return 0;
}
What could be the problem? I also tried replacing C++14 with C++11 in the command, but got the same error.
When Cygwin installs a g++ version (in your case, 5.4.0), it will place the g++ executable in your PATH variable. But the installation name is just g++.exe, so you can call the program like this:
g++ -std=c++14 test.cpp
If you really wanted to call the compiler with g++-5.4.0, you could symlink the actual g++ executable to that name:
ln -s /usr/bin/g++.exe /usr/bin/g++-5.4.0.exe
then you will be able to call the program from the command line with either g++ or g++-5.4.0:
g++-5.4.0 -std=c++14 test.cpp
g++ -std=c++14 test.cpp
actually I was compiling with multiple files. Following are the files:
file main.c -->
#include <stdio.h>
void foo3(void)
{
printf("INSIDE foo3 function\n");
}
int main()
{
foo1();
foo2();
foo3();
}
file 1.c -->
#include <stdio.h>
void foo1(void)
{
printf("INSIDE foo1 function\n");
}
file 2.c-->
#include <stdio.h>
void foo2(void)
{
printf("INSIDE foo2 function\n");
}
Now I compiled using gcc as follows-->
gcc 1.c 2.c main.c -o main
following was the output -->
INSIDE foo1 function
INSIDE foo2 function
INSIDE foo3 function
My doubt is how could main() call foo1() and foo2() when they are not declared in main.c. But now if I change main.c as follows ( writing the definition of foo3() after main()) like this:
edited main.c -->
#include <stdio.h>
int main()
{
foo1();
foo2();
foo3();
}
void foo3(void)
{
printf("INSIDE foo3 function\n");
}
and then if I compile I get this error:
main.c:9:6: warning: conflicting types for ‘foo3’ [enabled by default]
void foo3(void)
^
main.c:6:2: note: previous implicit declaration of ‘foo3’ was here
foo3();
^
why was this error not shown earlier in case of foo1() and foo2() . Thankyou in advance.
My doubt is how could main() call foo1() and foo2() when they are not declared in main.c
Because the GCC compiler defaults to the old ANSI C (aka as C89) language, where undeclared functions are permitted and defaults to giving int result.
Try to invoke the compiler as e.g.
gcc -std=c99 -Wall -g -c main.c
or (if you want to compile all files at once)
gcc -std=c99 -Wall -g 1.c 2.c main.c -o main
You could ask for link time interprocedural optimizations with gcc -flto instead of gcc using a recent GCC, e.g. GCC 4.9 in september 2014.
This would want a C99 conforming source code where all functions should be declared.
The -Wall asks for (almost) all warnings. The -g option produces a debuggable object code (or executable for the last command compiling all files at once).
In your edited main.c when foo3 first occurrence (inside main) is encountered, the compiler guesses that it is a function returning int. When the compiler sees the definition of foo3 it rightly complains.
You could use the -Wstrict-prototypes warning option to gcc (but it is implied by -Wall which I always recommend using).
At link time, the type (and signature) of C functions does not matter. The linker just uses name to do its job (but C++ use name mangling). Of course, calling a function with the incorrect arguments or result is undefined behavior.
The good conventional practice is to have a common header file declaring all the used and public functions and types (and constants) and include that header file in your source files (this avoids to have to copy and paste these declarations several times). So you whould have a new header file myheader.h like
// file myheader.h
#ifndef MY_HEADER_INCLUDED
#define MY_HEADER_INCLUDED
void foo1(void);
void foo2(void);
void foo3(void);
#endif /*MY_HEADER_INCLUDED*/
and you would add #include "myheader.h" in all your source files (after the #include <stdio.h> directive there). Notice the include guard trick with MY_HEADER_INCLUDED.
In practice, header files usually contain comments explaining the API of your program.
Learn also about GNU make. It will ease the building of your multi-source code files programs (you just compile and build by running make). See this and that examples of Makefile. Understand that C preprocessing is the first phase of C compilation.
I made shared library using gcc . I would like to link this library using g++ comiler with source code *.c.
Example
test_init.c
#include<stdio.h>
int test_init()
{
printf(" test init success\n");
return 0;
}
gcc -shared -o libtest.so test_init.c
test.c
#include<stdio.h>
extern int test_init();
main()
{
test_init();
}
g++ -I. -L. -ltest test.c
/tmp/ccuH5tIO.o: In function main':
test.c:(.text+0x7): undefined
reference totest_init()' collect2:
ld returned 1 exit status
Note: If i compile test.c with gcc it works, but i would like to use this approach due to other dependencies. Is it possible??
You call C routines from C++ by declaring them
extern "C" {
....
}
Look into a few header files on your system or Google around -- that's the only way to do it because of different function signature systems between the languages.
As Dirk said, change extern int test_init(); to extern "C" { int test_init(); }
Usually -llibrary should be after object files or c/c++ files in gcc command line
g++ -I. -L. test.c -ltest
The linker searches for the symbols mentioned in test.c after it's processed and when you put -llib before test.c, it's just unable to find them.
See man ld for more info.
Not sure how the things are when you use extern, perhaps something is different in this case.