'Include an external library in C
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.
Solution 1:[1]
I take this course and sometimes I need to practice offline while I am traveling or commuting. Under Windows using MinGW and Notepad++ as an IDE (because I love it and use it usually while codding python) I finally found a solution and some time to write it down.
Starting from scratch. Steps for setting up gcc C compiler, if already set please skip to 5
- Download Git and install. It includes Git Bash, which is MINGW64 linux terminal. I prefer to use Git as I need linux tools such as sed, awk, pull, push on my Windows and can replace Guthub's terminal.
- Once Git installed make sure that gcc packages are installed. You can use my configuration for reference...

Make sure your compiler works. Throw it this simple code,
- by saving it in your working directory Documents/Harvard_CS50/Week2/ hello.c
#include <stdio.h> int main(void) { printf("Hello StackOverflow\n"); }- start Git Bash -> navigate to working directory
cd Documents/Harvard_CS50/Week2/
- compile it in bash terminal
gcc helloworld.c -o helloworld.exe
- execute it using bash terminal
./helloworld.exe
Hello StackOverflow
- If you see Hello StackOverflow, your compiler works and you can write C code.
Now to the important bit, installing CS50 library locally and using it offline. This should be applicable for any other libraries introduced later in the course.
Download latest source code file cs50.c and header file cs50.h from https://github.com/cs50/libcs50/tree/develop/src and save them in Documents/Harvard_CS50/src
Navigate into src directory and list the files to make sure you are on the right location using
ls
cs50.c cs50.h
Cool, we are here. Now we need to compile object file for the library using
gcc -c -ggdb -std=c99 cs50.c -o cs50.o
Now using the generated cs50.o object file we can create our cs50 library archive file.
ar rcs libcs50.a cs50.o
After all this steps we ended with 2 additional files to our original files. We are interested in only 2 of them cs50.h libcs50.a
ls
cs50.c cs50.h cs50.o libcs50.a
Copy Library and header files to their target locations. My MinGW is installed in C:\ so I copy them there
cs50.h --> C:\MinGW\include
libcs50.a --> C:\MinGW\lib
Testing the cs50 Library
To make sure our library works, we can throw one of the example scripts in the lecture and see if we can compile it using cs50.h header file for the get_string() method.
#include <stdio.h>
#include <cs50.h>
int main(void)
{
printf("Please input a string to count how long it is: ");
string s = get_string();
int n = 0;
while (s[n] != '\0')
{
n++;
}
printf("Your string is %i chars long\n", n);
}
Compile cs50 code using gcc and cs50 library. I want to be explicit and use:
gcc -ggdb -std=c99 -Wall -Werror test.c -lcs50 -o test.exe
But you can simply point the source, output filename and cs50 library
gcc test.c -o test.exe -lcs50
Here we go, program is compiled using header and methods can be used within.
If you want Notepad++ as an IDE you can follow this tip to set it up with gcc as a compiler and run your code from there. Just make sure your nppexec script includes the cs50 library
npp_save
gcc -ggdb -std=c99 -Wall -Werror "$(FULL_CURRENT_PATH)" -lcs50 -o "$(CURRENT_DIRECTORY)\$(NAME_PART).exe"
cmd /c "$(CURRENT_DIRECTORY)\$(NAME_PART).exe"
Solution 2:[2]
You need to link against the library during compilation. The library should end in .a or .so if you are on Ubuntu. To link against a library:
gcc -o myProgram myProgram.c -l(library name goes here but no parentheses)
Solution 3:[3]
You have to link against the library, how come GCC would know what library you want to use?
gcc helloWorld.c -lcs50
Solution 4:[4]
- Download the cs50 from: http://mirror.cs50.net/library50/c/library50-c-5.zip
- Extract it. (You will get two files cs50.c and cs50.h)
- Now copy both the files to your default library folder. (which includes your stdio.h file)
- Now while writing your program use: #include < cs50.c >
- You can also copy the files to the folder containing your helloWorld.c file.
- You have to use: #include " cs50.c ".
OR =====================================================================>
- Open cs50.c and cs50.h files in text editor.
- In cs50.h, just below #include < stdlib.h > add #include < stdio.h > and #include < string.h > both on new line.
- Now open cs50.c file, copy everything (from: /**Reads a line of text from standard input and returns the equivalent {from line 47 to last}) and paste it in cs50.h just above the #endif and save the files.
- Now you can copy the file cs50.h to either your default library folder or to your current working folder.
- If you copied the file to default folder then use: #include < cs50.h > and if you copied the files to current working folder then use: #include " cs50.h ".
Solution 5:[5]
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:
gccvia msys2 - shell:
bashvia msys2 - IDE: doesnt matter here
Plan:
- getting the source files
- building the required files:
*.o(object) and*.a(archive) - telling the compiler to use it
Action:
Let's say, current directory = "desktop/cs50"
It contains all the*.cfiles like test-file.c which I will be creating for assignments/problem sets/practise etc.Get the
*.hand*.cfiles
Source in this particular case: https://github.com/cs50/libcs50/tree/main/src- Go over each file individually
- Copy all the content of it
Say using "Copy raw contents" icon of individual files - 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
Build the required files using in the terminal after changing your current directory to "desktop/cs50/src" :
gcc -c cs50.cto create the "cs50.o" object file from "cs50.c" using "gcc"ar cr libcs50.a cs50.oto 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
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 -lcs50if you used "lib" prefix in step 2.2 above- here,
-Iflag is for specifying the directory of*.hheader file included in your test_file.c - and
-Lflag is for specifying the directory to be used for-l - and
-lis for the name of the*.afile. Here the "lib" prefix talked about earlier, and ".a" extension is not mentioned - the order of these flags matter, keep the
-I -L -lflags 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 -lflags
so, syntax for command will become:gcc test-file.c -Isrc src/libcs50.a - say i created my
test-file.cfile in "desktop/cs50/psets", so, it can be handled in 2 notable ways (current dir = "desktop/cs50/") :cd psetsthen 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
makekick in (though i am accomplishing that using a shell script ?)
Solution 6:[6]
Actually you are using it wrong the compiler error makes it clear. It should be something like this
string message = get_string();
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Gunay Anach |
| Solution 2 | C0deH4cker |
| Solution 3 | |
| Solution 4 | |
| Solution 5 | |
| Solution 6 | Sanket Pagadpalliwar |

