3

I wrote myself a littly module I want to reuse. I got my header file bitstream.h with a struct and function declarations and bitstream.c with the implementations. Now I'd like to use this in my other programs, but without manually compiling bitstream.c every time, like you don't have to compile stdio.h every time you use it, but I don't get it to work. My files look like this:

bitstream.c

#include "bitstream.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

bit_stream_t *fbit_stream(const char *path) {
    FILE *f;

    /* open file for reading */
    f = fopen(path, "rb");

    ...

bitstream.h

#ifndef BITSTREAM_H
#define BITSTREAM_H

#define EOS 0x0a

typedef struct {
    int size;
    int i_byte;
    unsigned char i_bit;
    unsigned char current_bit;
    unsigned char *bytes;
} bit_stream_t;

extern bit_stream_t *fbit_stream(const char *path);
extern unsigned char bit_stream_next(bit_stream_t *bs);
extern void bit_stream_close(bit_stream_t *bs);
extern void print_bit_stream(bit_stream_t *bs);

#endif

I put these two files into /usr/local/include (I'm on a Linux machine) and now I'd like to use this in main.c (somewhere else, e.g. /home/foo/main.c):

main.c

#include <bitstream.h>
#include <stdio.h>

int main(int argc, const char *argv[]) {
    if (argc != 2) {
        printf("Need 1 argument!\n");
        return 1;
    }

    bit_stream_t *my_bs;
    my_bs = fbit_stream(argv[1]);

    while (my_bs -> current_bit != EOS) {
        printf("%d", my_bs -> current_bit);
        bit_stream_next(my_bs);
    }

    bit_stream_close(my_bs);
    printf("\n");
    return 0;
}

When I try gcc -Wall -o main.o main.c I get

/tmp/ccgdq66W.o: In function `main':
main.c:(.text+0x35): Undefined reference to `fbit_stream'
main.c:(.text+0x63): Undefined reference to `bit_stream_next'
main.c:(.text+0x7b): Undefined reference to `bit_stream_close'
collect2: error: ld returned 1 exit status

What am I doing wrong? Thanks in advance for any help!

smuecke

smuecke
  • 45
  • 5
  • 1
    The errors are from your linker, not the compiler. It's because you're not compiling bitstream.c and so the linker cannot find the definitions. – teppic Oct 13 '15 at 14:53
  • `stdio`isn't just a header. Take a look on [Lie Ryan answer](http://stackoverflow.com/a/27352493/5118690). I hope this will help you. – Missu Oct 13 '15 at 14:55

2 Answers2

3

compile bitstream.c to create bitstream.o

gcc -Wall -c bitstream.c

compile main.c and bitstream.o to create main (or main.exe if on winX)

gcc -Wall -o main main.c bitstream.o
KevinDTimm
  • 14,226
  • 3
  • 42
  • 60
3

The reason you don't need to "compile" stdio.h every time is that it's implementations (and a lot more) are already compiled and live at GLibC. That is, glibc is a library (a dynamic one) and GCC links your programs to it everytime you compile them. You can check that by running:

ldd hello

assuming hello is a simple Hello World! program that uses printf, for instance. And you'd get something like:

linux-vdso.so.1 =>  (0x00007fff5f98d000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f7e985b2000)
/lib64/ld-linux-x86-64.so.2 (0x00007f7e98977000)

See the line 2: libc.so.6, that's your GNU C Library, and that's the reason you don't "compile" stdio.h every time you use it.


General Case

What you want to do is implement your own library. So, in order to do that, you can do several things.

  1. You create a directory under /usr/include called MyLib and put all your headers there. This way you can include your files using #include <MyLib/myHeader.h>.

  2. Method 1: You compile your implementation myImp.c into an object file and put that object in a folder, /my/libs/path/myImp.o and every time you want to use, you compile with:

    gcc -o prog prog.c /my/libs/path/myImp.o

    Note: prog.c must #include <MyLibs/myHeader.h>.

  3. Method 2: You can make an archive with the utility ar and have all your libraries in it. Check it's manual here. Every time you want to use something from your library, you link it with the .a library.

  4. Method 3: You can make a dynamic library, which will decrease the size of your binaries (linking .o and ar libraries is static linking, which means larger binary sizes). You can do that using the -fPIC (Position Independent Code) gcc flag and some other small things. I'll link some resources .


Your specific case

  1. Compile bitstream.c with gcc -c bitstream.c.
  2. Put that file in /home/you/myLibs/bitstream.o.
  3. Copy the bitstream.h to /usr/include/MyLib/bitstream.h (you'll need root)
  4. Include that with #include <MyLib/bitstream.h>
  5. Compile your program with: gcc -o main main.c ~/myLibs/bitstream.o.

Although this is far from good, this will do what you want. I suggest you read up on how to organize your own libraries and more, check out Rusty Russel's CCAN Library, pretty good starting point on how to build C libraries.

I really recommend checking out CCAN!


Resources

Community
  • 1
  • 1
Enzo Ferber
  • 3,029
  • 1
  • 14
  • 24
  • OK, so as I understand it, there is no way around adding `/foo/bitstream.o` when using my own libraries, because stuff like `stdio` and `math` is always "alive" in gcc? – smuecke Oct 14 '15 at 11:43
  • 1
    @smuecke No, they're not "alive" **in gcc**. GCC is a compiler suite. Stuff like `stdio.h` are headers which define prototypes of functions in libraries. These libraries are compiled **using GCC** and live at files in your system. `stdio.h` for example, is in `glibc`. – Enzo Ferber Oct 14 '15 at 11:45
  • 1
    @smuecke And no, there's no way around having a compiled object file `/foo/bitstream.o` or `/foo/bitstream.a` (archive) or `/lib/bitsream.so` (shared). You need those in order to tell GCC to link them with your program. – Enzo Ferber Oct 14 '15 at 11:46