Search code examples
cstatic-libraries.a

How to link a static library to another


I have a problem with my static libraries. I got one for the use of multimedia elements and another for C general use (linked list...). I want them to be separated to not bloat my program.

Try as I might to use functions from the second library in the first I keep getting the pesky undefined references. I can't find the answer on Google or in the gcc documentation so I came here to find the answer I seek.

How do I link together two .a files? Can gcc even do this ?

linking the .c file of an element of lib1

gcc -g3 -Wall -Wextra -Werror -I src/inc -I src/lib/*/src/inc -L src/lib -locl -o obj/menu/button.o -c src/menu/button.c

creating lib1

ar rcso ../libocml.a  obj/sound/sound.o obj/sys/view.o obj/sys/window.o obj/sys/thread.o obj/sys/clock.o obj/menu/text.o obj/menu/button.o

Compiling of the binary

gcc -g3 -Wall -Wextra -I src/inc -I src/lib/*/src/inc -I src/lib/*/src/lib/*/src/inc -L src/lib -o bin/runner.exe  obj/main.o -locml -lcsfml-graphics -lcsfml-window -lcsfml-audio -lcsfml-system

Unedited error

gcc -g3 -Wall -Wextra -I src/inc -I src/lib/*/src/inc -I src/lib/*/src/lib/*/src/inc -L src/lib -o bin/runner.exe  obj/main.o -locml -lcsfml-graphics -lcsfml-window -lcsfml-audio -lcsfml-system  
/usr/bin/ld : src/lib/libocml.a(sound.o) : dans la fonction « setMusic » :
/home/ornsolot/Bureau/runner/src/lib/ocml/src/sound/sound.c:69 : référence indéfinie vers « setStr »
/usr/bin/ld : src/lib/libocml.a(sound.o) : dans la fonction « unsetMusic » :
/home/ornsolot/Bureau/runner/src/lib/ocml/src/sound/sound.c:82 : référence indéfinie vers « unsetStr »
collect2: error: ld returned 1 exit status
make: *** [Makefile:86 : runner] Erreur 1

the issue is that setMusic and unsetMusic in music.c in lib ocml need setStr and unsetStr in str.c in lib ocl.

Source Tree Source tree

How to reproduce

you need the csfml library for compile it, sudo apt-get install libcsfml-dev create all file at the same place where you fill use the following command.

ocml.h

#include <SFML/Graphics.h>
#include <SFML/Audio.h>
#include <stdio.h>
#define MALLOCSTR(length) (malloc(sizeof(char) * length))
typedef struct osString_s {
    char  *data;
    size_t length;
} String_t;
String_t *setStr(char *data);
void unsetStr(String_t *string);
typedef struct ocmlMusic_s {
    sfMusic  *core;
    String_t *name;
} Music_t;
Music_t *setMusic(char *path, sfBool loop);
void unsetMusic(Music_t *music);

str.c

#include "ocml.h"
static size_t strLen(char *string)
{
    size_t len = 0;
    
    if (string)
        while (string[len] != '\0')
            len++;
    return (len);
}
String_t *setStr(char *data)
{
    size_t len = strLen(data);
    String_t *str = len > 0 ? malloc(sizeof(String_t)) : NULL;

    if (str) {
        str->data = MALLOCSTR(len);
        for (size_t i = 0; i < len ; i++)
            str->data[i] = data[i];
        str->length = len;
    }
    return (str);
}
void unsetStr(String_t *string)
{
    if (string) {
        if (string->data)
            free(string->data);
        free(string);
    }
}
gcc -g3 -Wall -Wextra -Werror -I . -o str.o -c str.c
ar rcso libocml.a  str.o

music.c

#include "ocml.h"

Music_t *setMusic(char *path, sfBool loop)
{
    Music_t *music = (path) ? malloc(sizeof(Music_t)) : NULL;

    if (music) {
        music->core = sfMusic_createFromFile(path);
        sfMusic_setLoop(music->core, loop);
        music->name = setStr(path);
    }
    return (music);
}
void unsetMusic(Music_t *music)
{
    if (music) {
        sfMusic_destroy(music->core);
        unsetStr(music->name);
        free(music);
    }
}
gcc -g3 -Wall -Wextra -Werror -I . -L . -locl -o music.o -c music.c
ar rcso libocml.a  music.o libocl.a

main.c

#include "ocml.h"
int main()
{
    Music_t*loop = setMusic("path/to/file.ogg", sfTrue);
    unsetMusic(loop);
}

gcc -g3 -Wall -Wextra -I . -L . -o a.out main.o -locml -lcsfml-graphics -lcsfml-window -lcsfml-audio -lcsfml-system

Thanks in advance for your guidance.


Solution

  • ar rcso libocml.a  music.o libocl.a
    

    This command creates an archive with two members, music.o and libocl.a. The second member is completely useless for linking. Only members that are object files are useful. When searching libocml.a, the linker will only see music.o. It will not search libocl.a and will not see any objects that are members of that archive.

    If you want an archive that has all the contents of libocl.a plus music.o, you can do it:

    cp libocl.a libocml.a
    ar rs libocml.a music.o
    

    I fail to see the point though. If libocl.a is your library, just skip it and build libocml.a directly out of objects. If it is a third party library, don't modify it. Build your own libraries with your own code.