I have a multi threaded program in C that was working well but was in one single main.cpp file.
I have moved the thread in another .cpp file and added it's signature, void* displayScreen(void*); , in the header. I include the header in my initial main.cpp file.
Compiling works but the linker returns an error when trying to call pthread_create(): undefined reference to `displayScreen(void*)'
It looks like it compiled displayScreen(void *) fine but does not know where to load it from. Is there a way for me to tell the linker where to find it or am I doing it wrong please?
Thank you very much.
Adding the signature alone lets you compile the main translation unit, but you still have to compile the implementation of the function separately and link the two:
main.cpp
void* displayScreen(void*);
int main()
{
/* .... */
}
display.cpp
void* displayScreen(void*)
{
/* implementation */
}
Compile:
g++ -O2 -o main.o main.cpp
g++ -O2 -o display.o display.cpp
Link:
g++ -o myprogram main.o display.o -lpthread -s
Related
I am trying to understand how ld-linux.so resolves references to versioned symbols on Linux. I have the following files:
test.c:
void f();
int main()
{
f();
}
a.c and b.c:
void f() {}
symbols.txt:
ABC {
global:
*;
};
Makefile:
all: liba.so libb.so test
liba.so: a.c
gcc -g -shared $^ -o $# -Wl,--version-script=symbols.txt
libb.so: b.c
gcc -g -shared $^ -o $#
test: test.c liba.so
gcc -g test.c -la -L. -o $#
clean:
rm -f liba.so libb.so test
I then ran the following command
LD_PRELOAD=./libb.so LD_LIBRARY_PATH=. ./test
I find that f() from b.c is invoked even though the symbol f in libb.so does not have the version required by test (f#ABC). Why does this happen ?
version-script is used to confine the symbols to be exported in shared libraries. this means faster link speed and few change for symbols conflict.
By default, most function name will be exported, so you can link with libb.so without any problem.
If you want to determine which version of function should be used, You need to specify it in your program. This need some assembly code to specify .symver.
For more details, please read Ulrich Drepper’s paper https://www.akkadia.org/drepper/dsohowto.pdf
I download jsoncpp on Github. And built and installed it with meson and ninja. But when I include <json/json.h> in my program, I got the error:
‘PrecisionType’ is not a class or namespace.
Is there anything wrong in "json/writer.h" ?
Error:
My guess is that you are using the example test code from
https://finbarr.ca/jsoncpp-example/
The issue would be a Makefile problem in the ordering of the flags:
change Makefile from example to look like this:
CXX = g++
CPPFLAGS = -std=gnu++11
LDFLAGS = -L/{YOUR_PATH}/jsoncpp/build/debug/src/lib_json -ljsoncpp
INC = -I/{YOUR_PATH}/jsoncpp/include
main: main.cpp
$(CXX) -o main main.cpp $(CPPFLAGS) $(INC) $(LDFLAGS)
Fix your path, but make sure the order of flags is correct...
The way you are trying to access an enum (PrecisionType is an enum)i.e. PrecisionType::significantDigits is compliant to -std=c++11 and not to older ones
/** \brief Type of precision for formatting of real values.
*/
enum PrecisionType {
significantDigits = 0, ///< we set max number of significant digits in string
decimalPlaces ///< we set max number of digits after "." in string
};
Solution
If you are compiling with just g++ you can add the following g++ -std=c++11 <file-name>
If its a Makefile you need to edit your CPPFLAGS to CPPFLAGS= -std=c++11
Regards,
I'm a dumb newbie.
I've got a file named file.c with the functions my_putstr(char *) and my_strlen(char *)
my_putstr() writes the parameter with write() (unistd.h)
I wanted to create a library from file.c so I did :
gcc -fPIC -c file.c
gcc -shared -o libfile.so file.o
Then I created a main.c file and called my_putstr() from it.
I tried to compile and link my .so
gcc -L. -lfile main.c -o test
But I got an undefined reference to my_putstr()
I tried to create a .h with my_putstr() and my_strlen() in it, and include it to the main but I got the same error.
Sorry for stupid questions.
Havaniceday.
Your question suffers lack of information, but I can suggest you at first try
gcc main.c ./libfile.so -Wl,-rpath . -o test
If this will fail, you have something wrong with your sources.
If everything is ok at this point, then try
gcc main.c -L . -lfile -Wl,-rpath . -o test
If this will output undefined reference, then probably you already have something like libfile.a without my_putstr(may be from previous experiments) in your lib path.
If everything is ok with it, then your linker is sensible to order in which libraries is supplied to command string, and you must remember, then library always comes after object, that uses this library.
I compiled a library which use the g++ instead gcc. First I thought the source code was written in C++ but I found out later that there was not any C++ code in the *.cc files.
To confirm this, I replaced the g++ in the original makefile with gcc. And I still got the correct program.
Anyone can explain this? It was not the first time I met such a situation.
It depends on what exactly you changed in the makefile. gcc / g++ is really just a front-end driver program which invokes the actual compiler and / or linker based on the options you give it.
If you invoke the compiler as gcc:
it will compile as C or C++ based on the file extension (.c, or .cc / .cpp);
it will link as C, i.e. it will not pull in C++ libraries unless you specifically add additional arguments to do so.
If you invoke the compiler as g++:
it will compile as C++ regardless of whether or not the file extension is .c or .cc / .cpp;
it will link as C++, i.e. automatically pull in the standard C++ libraries.
(see the relevant bit of the GCC documentation).
Here's a simple program which detects whether or not it has been compiled as C or C++.
(It makes use of the fact that a character constant has the size of an int in C, or a char in C++. sizeof(char) is 1 by definition; sizeof(int) will generally be larger - unless you're using an obscure platform with >= 16-bit bytes, which you're probably not.)
I've called it test.c and copied it as test.cc as well:
$ cat test.c
#include <stdio.h>
int main(void)
{
printf("I was compiled as %s!\n", sizeof('a') == 1 ? "C++" : "C");
return 0;
}
$ cp test.c test.cc
$
Compiling and linking test.c with gcc, and test.cc with g++, works as expected:
$ gcc -o test test.c
$ ./test
I was compiled as C!
$ g++ -o test test.cc
$ ./test
I was compiled as C++!
$
Compiling and linking test.cc with gcc doesn't work: it compiles the code as C++ because the file ends in .cc, but fails at the link stage:
$ gcc -o test test.cc
/tmp/ccyb1he5.o:(.eh_frame+0x11): undefined reference to `__gxx_personality_v0'
collect2: ld returned 1 exit status
$
which we can prove by separately compiling with gcc, and linking with g++ (to pull in the right libraries):
$ gcc -c test.cc
$ g++ -o test test.o
$ ./test
I was compiled as C++!
$
...gcc has compiled the code as C++ rather than C, because it had a .cc file extension.
Whereas g++ does not compile .c files as plain C:
$ g++ -o test test.c
$ ./test
I was compiled as C++!
$
It could be that the .cc code happens to be C, but was intended to be linked into a C++ library. The internals are different.
g++ automatically links the C++ runtime library — gcc doesn't. Obvoiusly, when it doesn't matter — then it doesn't matter, but, as already pointed out by spraff, it could be intended for future use.
I don't know why they chose to use g++ instead of gcc, but I believe it shouldn't matter, as any valid C program is also valid C++.
I know that by default undefined symbols are ignored at compile time. However, I would also like them to be ignored at run-time. I need to distribute a .so that will run with and without MPI. I will know ahead of time if it is an MPI job and if it is not I won't make any MPI_* calls. If it's not an MPI run I need the application to not care that it cannot resolve the MPI_* symbols.
Is this possible? I could have sworn I've done this before but I can't get it working. Everytime I run I immediately get the following even though the logic in my code will never allow that symbol to be referenced:
undefined symbol: hpmp_comm_world
For what it's worth I am using the Intel Fortran Compiler to build the .so file.
EDIT
I found the linker flag: "-z lazy" which is supposed to resolve references to functions when the function is called which is what I want. That doesn't fix my problem, but hpmp_comm_world is a variable - not a function. Should that make a difference?
You can define a symbol to be a weak reference to its definition. Then, the symbol's value will be zero if the definition is not present.
For example, suppose the following is ref.c, which references a function and variable that may or may not be present; we'll use it to build libref.so (corresponding to your library, in your question):
#include <stdio.h>
void global_func(void);
void global_func(void) __attribute__ ((weak));
extern int global_variable __attribute__((weak));
void ref_func() {
printf("global_func = %p\n", global_func);
if (&global_variable)
global_variable++;
if (global_func)
global_func();
}
Here, global_func and global_variable are the weak references to the possibly-available function and variable. This code prints the function's address, increments the variable if it is present, and calls the function if it is present. (Note that the function's and variable's addresses are zero when they are not defined, so it is &global_variable that you must compare with zero.)
And suppose this is def.c, which defines global_func and global_variable; we'll use it to build libdef.so (corresponding to MPI, in your question):
#include <stdio.h>
int global_variable;
void global_func(void) {
printf("Hi, from global_func! global_variable = %d\n", global_variable);
}
And finally, suppose we have a main program, main.c, which calls ref_func from libref.so:
#include <stdio.h>
extern void ref_func(void);
int main(int argc, char **argv) {
printf("%s: ", argv[0]);
ref_func();
return 0;
}
Here's the Makefile that builds libref.so and libdef.so, and then builds two executables, both of which link against libref.so, but only one of which links against libdef.so:
all: ref-absent ref-present
ref-absent: main.o libref.so
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $#
ref-present: main.o libref.so libdef.so
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $#
lib%.so: %.o
$(CC) $(CFLAGS) $(LDFLAGS) -shared $^ -o $#
ref.o def.o: CFLAGS += -fpic
clean:
rm -f *.o *.so ref-absent ref-present
Do the build:
$ make
cc -c -o main.o main.c
cc -fpic -c -o ref.o ref.c
cc -shared ref.o -o libref.so
cc main.o libref.so -o ref-absent
cc -fpic -c -o def.o def.c
cc -shared def.o -o libdef.so
cc main.o libref.so libdef.so -o ref-present
$
Note that both ref-absent and ref-present linked without problems, even though there is no definition for global_name in ref-absent.
Now we can run the programs, and see that ref-absent skips the function call, while ref-present uses it. (We have to set LD_LIBRARY_PATH to allow the dynamic linker to find our shared libraries in the current directory.)
$ LD_LIBRARY_PATH=. ./ref-absent
./ref-absent: global_func = (nil)
$ LD_LIBRARY_PATH=. ./ref-present
./ref-present: global_func = 0x15d4ac
Hi, from global_func! global_variable = 1
$
The trick for you will be getting the ((weak)) attribute attached to every declaration of every MPI function your library references. However, as ref.c shows, there can be multiple declarations, and as long as one of them mentions the weak attribute, you're done. So you'll probably have to say something like this (I don't really know MPI):
#include <mpi.h>
mpi_fake_type_t mpi_function_foo(mpi_arg_type_t) __attribute__((weak));
mpi_fake_type_t mpi_function_bar(mpi_other_arg_type_t) __attribute__((weak));
Every reference to an MPI function needs to be in the scope of a ((weak)) declaration for that function; that's how the compiler decides what sort of symbol reference to put in the object file. You'll want to have automated tests to verify that you haven't accidentally generated any non-weak references.