Include an external library in C

Viewed 56295

I'm attempting to use a C library for an opencourseware course from Harvard. The instructor's instructions for setting up the external lib can be found here.

I am following the instructions specific to ubuntu as I am trying to use this lib on my ubuntu box. I followed the instructions on the page to set it up, but when I run a simple helloWorld.c program using a cs50 library function, gcc doesn't want to play along.

Example:

helloWorld.c

#include <stdio.h>
#include <cs50.h>

int
main(void){
        printf("What do you want to say to the world?\n");
        string message = GetString();
        printf("%s!\n\n", message);
}

$ gcc helloWorld.c

/tmp/ccYilBgA.o: In function `main':
helloWorld.c:(.text+0x16): undefined reference to `GetString'
collect2: ld returned 1 exit status

I followed the instructions to the letter as stated in the instructions, but they didn't work for me. I'm runing ubuntu 12.04. Please let me know if I can clarify further my problem.

6 Answers

Research Sources:

  • building on the answers above given by Basile Starynkevitch, and Gunay Anach
  • combined with instructions from some videos on youtube 1 2

Approach:

  • covering the minimum things to do, and sharing the "norms" separately
  • avoiding any modification to anywhere else on the system
  • including the basic breakdown of the commands used
  • not including all the fine details, covering only the requirements absolute to task or for effective communication of instructions. leaving the other mundane details to the reader
  • assuming that the other stuff like compiler, environment variable etc is already setup, and familiarity with shell's file navigation commands is there

My Environment:

  • compiler: gcc via msys2
  • shell: bash via msys2
  • IDE: doesnt matter here

Plan:

  1. getting the source files
  2. building the required files: *.o (object) and *.a (archive)
  3. telling the compiler to use it

Action:

  1. Let's say, current directory = "desktop/cs50"
    It contains all the *.c files like test-file.c which I will be creating for assignments/problem sets/practise etc.

  2. Get the *.h and *.c files
    Source in this particular case: https://github.com/cs50/libcs50/tree/main/src

    1. Go over each file individually
    2. Copy all the content of it
      Say using "Copy raw contents" icon of individual files
    3. Create the corresponding file locally in the computer
      Do it in a a separate folder just to keep things clean, let's say in "desktop/cs50/src" aka ./src
  3. Build the required files using in the terminal after changing your current directory to "desktop/cs50/src" :

    1. gcc -c cs50.c to create the "cs50.o" object file from "cs50.c" using "gcc"
    2. ar cr libcs50.a cs50.o to create "libcs50.a" archive file which'll be containing "cs50.o" object file
    • Here, "libcs50" = "lib" prefix + "cs50" name (same as the header file's name)
    • This is the norm/standard way where the prefix "lib" is significant as well for a later step
    • However, prefix can be skipped, and it's not compulsory for name to match the header file's name either. Though, Skipping prefix is not recommended. And I can't say for sure about the name part
  4. To tell the compiler to be able to use this infrastructure, the commands will be in following syntax after going to the parent directory (i.e. to "desktop/cs50"):

    • gcc test-file.c -Isrc -Lsrc -lcs50 if you used "lib" prefix in step 2.2 above
    • here, -I flag is for specifying the directory of *.h header file included in your test_file.c
    • and -L flag is for specifying the directory to be used for -l
    • and -l is for the name of the *.a file. Here the "lib" prefix talked about earlier, and ".a" extension is not mentioned
    • the order of these flags matter, keep the -I -L -l flags after the "test-file.c"

Some more notees:

  • don't forget to use the additional common flags (like those suggested above for errors etc)
  • if you skipped the "lib" prefix, then you can't use -L -l flags
    so, syntax for command will become: gcc test-file.c -Isrc src/libcs50.a
  • say i created my test-file.c file in "desktop/cs50/psets", so, it can be handled in 2 notable ways (current dir = "desktop/cs50/") :
    • cd psets then changing the relative address correspondingly in -I -L, so result:
      gcc test-file.c -I../src -L../src -lcs50
    • keeping current directory same, but then changing the file's relative address correspondingly, so result:
      gcc psests/test-file.c -Isrc -Lsrc -lcs50
    • or use absolute addresses
  • as it can be seen that this becomes quite long, that's when build automation tools such as make kick in (though i am accomplishing that using a shell script )
Related