Undefined reference to... when linking library header - c

I'm trying to compile a C program that uses libvncserver but no matter what I do I keep getting undefined reference errors, the library I'm having troubles with is rfb/rfb.h.
vnc.c code (copied from here):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rfb/rfb.h>
#define WIDTH 640
#define HEIGHT 480
#define BPP 4
/* 15 frames per second (if we can) */
#define PICTURE_TIMEOUT (1.0/15.0)
/*
* throttle camera updates
*/
int TimeToTakePicture() {
static struct timeval now={0,0}, then={0,0};
double elapsed, dnow, dthen;
gettimeofday(&now,NULL);
dnow = now.tv_sec + (now.tv_usec /1000000.0);
dthen = then.tv_sec + (then.tv_usec/1000000.0);
elapsed = dnow - dthen;
if (elapsed > PICTURE_TIMEOUT)
memcpy((char *)&then, (char *)&now, sizeof(struct timeval));
return elapsed > PICTURE_TIMEOUT;
}
/*
* simulate grabbing a picture from some device
*/
int TakePicture(unsigned char *buffer)
{
static int last_line=0, fps=0, fcount=0;
int line=0;
int i,j;
struct timeval now;
/*
* simulate grabbing data from a device by updating the entire framebuffer
*/
for(j=0;j<HEIGHT;++j) {
for(i=0;i<WIDTH;++i) {
buffer[(j*WIDTH+i)*BPP+0]=(i+j)*128/(WIDTH+HEIGHT); /* red */
buffer[(j*WIDTH+i)*BPP+1]=i*128/WIDTH; /* green */
buffer[(j*WIDTH+i)*BPP+2]=j*256/HEIGHT; /* blue */
}
buffer[j*WIDTH*BPP+0]=0xff;
buffer[j*WIDTH*BPP+1]=0xff;
buffer[j*WIDTH*BPP+2]=0xff;
}
/*
* simulate the passage of time
*
* draw a simple black line that moves down the screen. The faster the
* client, the more updates it will get, the smoother it will look!
*/
gettimeofday(&now,NULL);
line = now.tv_usec / (1000000/HEIGHT);
if (line>HEIGHT) line=HEIGHT-1;
memset(&buffer[(WIDTH * BPP) * line], 0, (WIDTH * BPP));
/* frames per second (informational only) */
fcount++;
if (last_line > line) {
fps = fcount;
fcount = 0;
}
last_line = line;
fprintf(stderr,"%03d/%03d Picture (%03d fps)\r", line, HEIGHT, fps);
/* success! We have a new picture! */
return (1==1);
}
/*
* Single-threaded application that interleaves client servicing with taking
* pictures from the camera. This way, we do not update the framebuffer
* while an encoding is working on it too (banding, and image artifacts).
*/
int main(int argc,char** argv)
{
long usec;
rfbScreenInfoPtr server=rfbGetScreen(&argc,argv,WIDTH,HEIGHT,8,3,BPP);
if(!server)
return 0;
server->desktopName = "Live Video Feed Example";
server->frameBuffer=(char*)malloc(WIDTH*HEIGHT*BPP);
server->alwaysShared=(1==1);
/* Initialize the server */
rfbInitServer(server);
/* Loop, processing clients and taking pictures */
while (rfbIsActive(server)) {
if (TimeToTakePicture())
if (TakePicture((unsigned char *)server->frameBuffer))
rfbMarkRectAsModified(server,0,0,WIDTH,HEIGHT);
usec = server->deferUpdateTime*1000;
rfbProcessEvents(server,usec);
}
return(0);
}
Compiler output:
sudo gcc -g -Wall -Wextra -O2 vnc.c
/tmp/cc7dpMCs.o: In function `main':
/home/arcm/Projects/c/vnc.c:77: undefined reference to `rfbGetScreen'
/home/arcm/Projects/c/vnc.c:84: undefined reference to `rfbInitServerWithPthreadsAndZRLE'
/home/arcm/Projects/c/vnc.c:91: undefined reference to `rfbProcessEvents'
/home/arcm/Projects/c/vnc.c:86: undefined reference to `rfbIsActive'
/home/arcm/Projects/c/vnc.c:89: undefined reference to `rfbMarkRectAsModified'
collect2: error: ld returned 1 exit status
I've got libvncserver0 and libvncserver-dev installed and i'm using ubuntu 14.04.
I tried:
sudo gcc -g -Wall -Wextra -O2 vnc.c -lm
sudo gcc -g -Wall -Wextra -O2 vnc.c -ldl
sudo gcc -g -Wall -Wextra -O2 -ldl vnc.c
sudo gcc -g -Wall -Wextra -O2 -I/usr/include/rfb -L/usr/include/rbf/rfb.h vnc.c
sudo gcc -g -Wall -Wextra -O2 -I/usr/include/rfb vnc.c
sudo gcc -g -Wall -Wextra -O2 -L/usr/include/rbf/rfb.h vnc.c
sudo gcc -g -Wall -Wextra -O2 /usr/include/rbf/rfb.h vnc.c
sudo gcc -g -Wall -Wextra -O2 -L/usr/include/rbf/rfb.h -ldl vnc.c
But I get the same errors everytime. What am I doing wrong and how can I fix it?

You don't "link" a library header, you include it so the compiler sees the library's declarations at compile time and knows that rfbGetScreen() is a function that takes so-and-so many arguments of this-and-that type and returns a rfbScreenInfoPtr. How it does this (the definition of the function) is not important to the compiler. It just adds a reference to that function, which is left for the linker to resolve. (Note the vocabulary here.)
You link your compiled code to the library binary. This is done by the linker, in a different (and later) step that just happens to be supported by the same frontend as compiling your source (gcc). In this step, any of the library functions that your code actually uses (references) are resolved by linking them in from the specified libraries.
This here...
sudo gcc -g -Wall -Wextra -O2 vnc.c
...links only the standard library and runtime, as there are no specific linking instructions in there.
This here...
-L/usr/include/rbf/rfb.h
...is nonsense, as -L is for giving directories where library binaries should be looked for (and is not necessary if the library in question is installed in the standard location).
The actual link instruction is -l. If you state -lfoo, then the library libfoo is searched for any undefined references.
This here...
-ldl
...is linking libdl, and from that you should be able to deduce that...
-lvncserver
...is what you're looking for (assuming that <rfb/rfb.h> actually does refer to libvncserver, which I don't know).
Note that the linker is processing libraries in the sequence they are given on the command line, so you need to state -lvncserver after vnc.c, because only then does the linker know which undefined references it ought to be looking for in libvncserver.
And never, ever run a compiler as sudo. Why in {.....}'s name do you think this would be necessary?

Related

Installing and using a shared library

I have a project I'm working on that currently has a matrix.c file containing a some functions and has a corresponding header matrix.h. I made a shared library libccalc.so using matrix.c and another file. I am trying to create a directory in /usr/local/lib and a directory in /usr/local/include, both called ccalc to house the respective .so and .h files which can then later be used to compile programs using the functionality of libccalc.so. However, when I do this I am getting an error.
To be precise, matrix.c contains functions:
Matrix *mat_create(int rows, int cols),
void mat_fill(Matrix *mat, double *entries) and
void mat_print(Matrix *mat)
which are declared in matrix.h. I place the files in their respective directories as explained above, I run ldconfig /usr/local/lib/ccalc and I make a new file test.c in some other directory with the following:
// test.c
#include <stdio.h>
#include "matrix.h"
int main() {
Matrix *m = mat_create(2, 2);
double entries[4] = {1, 2, 3 ,4};
mat_fill(m, entries);
mat_print(m);
return 0;
}
matrix.h contains the following:
// matrix.h
#ifndef MATRIX_H
#define MATRIX_H
#define MAX_SIZE 50
typedef struct Matrix Matrix;
struct Matrix {
int rows;
int cols;
double *data;
};
Matrix *mat_create(int n, int p);
void mat_fill(Matrix *mat, double *entries);
void mat_print(Matrix *mat);
#endif
When I enter the command: gcc -I/usr/local/include/ccalc -L/usr/local/lib/ccalc -lccalc test.c -o test, I get the error:
/usr/bin/ld: /tmp/ccesD44J.o: in function `main':
test.c:(.text+0x26): undefined reference to `mat_create'
/usr/bin/ld: test.c:(.text+0x71): undefined reference to `mat_fill'
/usr/bin/ld: test.c:(.text+0x7d): undefined reference to `mat_print'
collect2: error: ld returned 1 exit status
However, when I place libccalc.so and matrix.h in /usr/local/lib and /usr/local/include, enter ldconfig and enter the command gcc -L/usr/local/lib/ccalc -lccalc test.c -o test, and run ./test, it works perfectly
Can someone tell me what I am doing wrong?
The order of program arguments to gcc matters a lot. Please read the documentation about Invoking GCC.
Also, test is often a builtin command. See test(1).
So (on Linux) rename test.c as prog.c then compile your program with
gcc -Wall -Wextra -g prog.c -L/usr/local/lib/ccalc -lccalc -o prog
Then use strace(1) and gdb(1) to understand the behavior of prog, and ldd(1), objdump(1) with readelf(1) to analyze prog. See also elf(5) and ld.so(8).
Regarding building shared libraries, read Drepper's paper How to write shared libraries
You probably want to compile matrix.c into libcalc.so using
gcc -fPIC -Wall -O -shared -g matrix.c -o libcalc.so
but you might need other program arguments.
Regarding matrix operations, this answer could be inspirational.

Dynamic library dynamic attach

EDIT found an issue, but it still needs to be solved it should be below in answers
My task is to write app based on existing files. test.c(main) randapi.c randapi.h(2 functions in here) and initapi.c(one function). "how can You use dynamic library as dynamic loaded library. Using eg9 (where i made a dynamic library and it worked fine) write app where this libraries will be attached dynamic"
here is my try with a makefile but terminal says that :failed to open when i come to run file using ./program
i have tried also version without attaching initapi.c but then it says initRand is unknown besides that make file clearly attached it
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#define ITERATIONS 1000000L
int main(int argc, char** argv)
{
long i;
long isum;
float fsum;
void *lib;
lib=dlopen("librandapi.so", RTLD_LAZY);
if (!lib)
{
printf("failed to open");
exit(1);
}
int (*getRand)(int);
float (*getSRand)();
void (*initRand)();
getRand=dlsym(lib,"getRand");
getSRand=dlsym(lib,"getSRand");
initRand=dlsym(lib,"initRand");
initRand();
isum = 0L;
for (i = 0 ; i < ITERATIONS ; i++) {
isum += ((*getRand)(10));
}
printf( "getRand() Average %d\n", (int)(isum / ITERATIONS) );
fsum = 0.0;
for (i = 0 ; i < ITERATIONS ; i++) {
fsum += ((*getSRand)());
}
printf( "getSRand() Average %f\n", (fsum / (float)ITERATIONS) );
dlclose(lib);
return 0;
}
//////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
makefile
zad9: test.c
gcc -Wall -o zad9 test.c -ldl
librandapi.so: randapi.o initapi.o
gcc -shared -o librandapi.so randapi.o initapi.o
randapi.o: randapi.c randapi.h
gcc -c -Wall -fPIC randapi.c
initapi.o: initapi.c
gcc -c -Wall -fPIC initapi.c
//////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
zad9: test.c initapi.c
gcc -Wall -o zad9 test.c initapi.c -ldl
librandapi.so: randapi.o initapi.o
gcc -shared -o librandapi.so randapi.o
randapi.o: randapi.c randapi.h
gcc -c -Wall -fPIC randapi.c
Look at this line in man 3 dlopen:
If filename contains a slash ("/"), then it is interpreted as a (relative or absolute) path‐name. Otherwise, the dynamic linker searches for the object as follows (see ld.so(8) for further details):
(and then a buch of rules that do not include the current directory nor the one where the executable is).
My guess is that you are copying librandapi.so to the current directory and that's why dlopen() cannot find it.
If that's the case, the solution is easy:
lib=dlopen("./librandapi.so", RTLD_LAZY);

Clang fails to compile a c11 program, citing that "implicit declaration is illegal in c99"

I have written this trivial little program to demonstrate my problem (titled hello.c) (sidenote: I have noticed the memory leak in this program but it's just an example so it's not important):
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char ** argv) {
char * buf = NULL;
size_t buflen = 0;
ssize_t line_len;
while ((line_len = getline(&buf, &buflen, stdin)) > 0) {
buf[line_len - 1] = '\0';
char * val = getenv(buf);
if (val) {
printf("setenv %s \"%s\"\n", buf, val);
}
else {
fprintf(stderr, "warning: %s not found\n", buf);
}
}
return EXIT_SUCCESS;
}
This compiles fine under Linux, using gcc and gnu make with the following makefile:
CFLAGS += -std=c11 -Wall -Werror -Wpedantic
CPPFLAGS := -D_XOPEN_SOURCE=700
EXES := hello
all: $(EXES)
clean:
rm -f $(EXES) *.o
However, under BSD, using clang and bmake, I cannot compile (using the exact same makefile and source file), because it says
hello.c:11:24: error: implicit declaration of function 'getline' is invalid in
C99 [-Werror,-Wimplicit-function-declaration]
The trouble is, as you can see, that I'm not compiling in c99 mode, but c11, and also, according to the man page defining _POSIX_C_SOURCE to be 200809 or greater should enable getline, and elsewhere I am assured that defining _XOPEN_SOURCE to be 700 should achieve that.
Taking out the -W flags doesn't help.
So, what am I doing wrong? How can I get this to compile? I'm stumped.
You have set -std=c11 -Wpedantic, which means that the normal defines are not available and POSIX function are not declared unless you explicitly set one of _POSIX_C_SOURCE or _XOPEN_SOURCE. Add #define _XOPEN_SOURCE 700 (or even 800 on Linux) before the first #include and all will be well.
You have CPPFLAGS = -D_XOPEN_SOURCE=700 in the makefile; does CPPFLAGS actually show on the GCC command line?
I routinely compile on Mac OS X 10.10.1 with -std=c11 and I have a header which sets _XOPEN_SOURCE to 700. However, I can take your code and compile it verbatim with:
gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition -Werror -pedantic -c yourprog.c
and the only complaint is that neither argc nor argv is used (so the compilation does fail, but not because of getline()).
Note that CPPFLAGS is not necessarily recognized by BSD make. There isn't a universal standard that requires CPPFLAGS to be recognized.

"poll called with fds buffer too small" with link time optimization (-flto)

Suddenly started getting this error at link time on some older code. I managed to replicate the problem with a very simple snippet of code:
#include <poll.h>
#include <stdio.h>
typedef struct
{
struct pollfd m_fds[6000];
nfds_t m_count;
} PollWrapper;
static PollWrapper g_pollWrapper;
int main()
{
return poll(g_pollWrapper.m_fds, g_pollWrapper.m_count, 0);
}
Compiling without -flto is fine.
gcc -Wall -O3 -o poll.exe poll.c # gcc 4.8.1-10ubuntu9
# successful
But adding -flto causes an error when linking:
gcc -Wall -O3 -flto -o poll.exe poll.c # gcc 4.8.1-10ubuntu9
# error
gcc -Wall -O3 -flto -o poll.o -o poll.c
# compilation is fine
gcc -Wall -O3 -flto -o poll.exe poll.o
# linking fails
/usr/include/x86_64-linux-gnu/bits/poll2.h: In function `main`:
/usr/include/x86_64-linux-gnu/bits/poll2.h:41:2: warning: call to `__poll_chk_warn` > declared with attribute warning: poll called with fds buffer too small file nfds entries [enabled by default]
return __poll_chk (__fds, __nfds, __timeout, __bos (__fds));
^
Having read related questions, I tried explicitly enabling and disabling the linker plugin, neither had any effect.
This only appears to happen with an array, none of the following have the same problem:
struct pollfd f;
int numfds = poll(&f, g_pollWrapper.m_size, duration);
or
struct pollfd fds[6000];
int numfds = poll(&f, g_pollWrapper.m_size, duration);
etc.
Am I either missing something obvious or is this an LTO defect in my GCC, and if so is there a way I can work around it?

BCM2835 installed but giving undefined references

So I installed BCM2835 but when I'm trying to compile a .c file with "gcc -c main main.c" it gives the following errors. I have no idea on how to compile linux btw, just follow stuff on the internet.
/tmp/ccSVwHkt.o: In function `main':
main.c:(.text+0x14): undefined reference to `bcm2835_init'
main.c:(.text+0x3c): undefined reference to `bcm2835_gpio_fsel'
main.c:(.text+0x48): undefined reference to `bcm2835_gpio_write'
main.c:(.text+0x50): undefined reference to `bcm2835_delay'
main.c:(.text+0x5c): undefined reference to `bcm2835_gpio_write'
main.c:(.text+0x64): undefined reference to `bcm2835_delay'
collect2: ld returned 1 exit status
This is the content of main.c (copied from Google code)
/*
* main.c
*
* Created on: 23-jun.-2013
* Author: Andreas Backx
*/
#include <bcm2835.h>
// Blinks on RPi Plug P1 pin 11 (which is GPIO pin 17)
#define PIN RPI_GPIO_P1_11
int main(int argc, char **argv)
{
// If you call this, it will not actually access the GPIO
// Use for testing
// bcm2835_set_debug(1);
if (!bcm2835_init())
return 1;
// Set the pin to be an output
bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_OUTP);
// Blink
while (1)
{
// Turn it on
bcm2835_gpio_write(PIN, HIGH);
// wait a bit
bcm2835_delay(500);
// turn it off
bcm2835_gpio_write(PIN, LOW);
// wait a bit
bcm2835_delay(500);
}
bcm2835_close();
return 0;
}
gcc -c main main.c doesn't make sense given the output you're getting. That said, if it's really what you're doing, you need to change it:
gcc -o main main.c
You'll likely still get the "undefined symbol" errors from the linker, since you're not linking with whatever library defines those symbols. A quick check of the examples at the site you linked shows that you need to link with the bcm2835 library:
gcc -o main main.c -lbcm2835
You may also need to add a -L flag if you installed the library somewhere where gcc doesn't know to look for it.
I'll tell you an easier option so that you don't have to worry about writing this command every time.
If you are working on Geany, go to the section, then . There you will see that you are using this command
to compile -> gcc -Wall -c "% f".
Put it in place gcc -Wall -c "% f" -lbcm2835.
And in the line -> gcc -Wall -o "% e" "% f" -lbcm2835.
And in the line -> sudo "./%e"
And press ok.
Now everything will work ;)

Resources