How do I use an external library with gcc? - c

I am attempting to compile this code:
#include <GLFW/glfw3.h>
int main() {
glfwInit();
glfwTerminate();
return 0;
}
Using this command in MSYS2 on Windows 10:
gcc -Wall runVulkan.c -o runVulkan
as well as this:
gcc -Wall -Llibs/glfw runVulkan.c -o runVulkan
libs/glfw is where I downloaded the library to.
For some reason I keep getting this:
runVulkan.c:1:10: fatal error: GLFW/glfw3.h: No such file or directory
1 | #include <GLFW/glfw3.h>
| ^~~~~~~~~~~~~~
compilation terminated.
It seems like I'm getting something very basic wrong.
I'm just getting started with C, I'm trying to import Vulkan libraries.

Run pacman -S mingw-w64-x86_64-glfw to install GLFW.
Then build using gcc -Wall runVulkan.c -o runVulkan runVulkan.c `pkg-config --cflags --libs glfw3`.
The pkg-config command prints the flags necessary to use GLFW, and the ` backticks pass its output to GCC as flags. You can run it separately and manually pass any printed flags to GCC.
Note that any -l... flags (those are included in pkg-config output) must be specified after .c or .o files, otherwise they'll have no effect.
For me pkg-config prints -I/mingw64/include -L/mingw64/lib -lglfw3.
-I fixes No such file or directory. It specifies a directory where the compiler will look for #included headers. Though it's unnecessrary when installing GLFW via pacman, since /mingw64/include is always searched by default.
-l fixes undefined reference errors, which you'd get after fixing the previous error. -lglfw3 needs a file called libglfw3.a or libglfw3.dll.a (or some other variants).
-L specifies a directory where -l should search for the .a files, though it's unnecessrary when installing GLFW via pacman, since /mingw64/lib is always searched by default.

#include are just headers, for declarations. gcc, as any compilers, needs to know where those .h should be searched.
You can specify that with -I option (or C_INCLUDE_PATH environment variable).
You'll also need -L option, this times to provide the library itself (.h does not contain the library. Just declarations that the compiler needs to know how to compile codes that use the library function's and types).
-L option tells the compiler where to search for libraries.
But here, you haven't specify any libraries (just headers. And I know that it seems logical that they go together. But strictly speaking, there is no way to guess from #include <GLFW/glfw3.h> which library that file contain headers for (that is not just theory. In practice, for example, the well known libc declarations are in many different headers)
So, you will also have to specify a -l option. In your case -lglfw.
This seems over complicated, because in your case you compile and like in a single command (goes from .c to executable directly). But that are two different operations done in one command.
Creation of an executable from .c code source is done in two stage.
Compilation itself. Creating .o from .c (many .c for big codes), so many compilation commands. Using command such as
gcc -I /path/where/to/find/headers -c mycode.c -o mycode.o
Those are not related to the library. So no -l (and therefore no -L) for that. What is compiled is your code, so just your code is needed at this stage. Plus the header files, because your code refers to unknown function and types, and the compiler needs to know, not their code, but at least declarations that they really exist, and what are the types expected and returned by the functions is the headers files.
Then, once all the .o are compiled, you need to put together all compiled code, yours (the .o) and the libraries (which are somehow a sort of .zip of .o) to create an executable. That is called linking. And is done with commands like
gcc -o myexec mycode1.o mycode2.o -L /path/where/to/search/for/libraries -lrary
(-lbla is a compact way to include /path/where/to/search/for/libraries/libbla.so or /path/where/to/search/for/libraries/libbla.a)
At this stage, you no longer need -I or anything related to headers. The code is already compiled, headers has no role left. But you need everything needed to find the compile code of the libraries.
So, tl;dr
At compilation stage (the stage that raises the error you have for now), you need -I option so that the compiler knows where to find GLFW/glfw3.h
But that alone wont avoid you the next error that will occur at linking stage. At this stage, you need -lglfw to specify that you want to use that library, and a -L option so that the compiler knows where to find a libglfw.so

Related

How to write common functions for reusing in C

I was trying to write a common function for other files could reuse it, the example as following, I have three files:
The first file: cat test1.h
void say();
The second file: cat test1.c
void say(){
printf("This is c example!");
}
The third file: cat test2.c
include "test1.h"
void main(){
say();
}
but when I ran: gcc -g -o test2 test2.c
it threw error as:
undefined reference to `say'
Additionally: I knew this would work:gcc -g -o test2 test1.c test2.c
but I don't wanna do this, because the other team would use the server, and I hope them directly use my binary code not source code. I hope that just like we use printf() function, we just need include .
You can build yourself a library from the object files containing your useful functions, and store the header(s) that describe them in a convenient location. You and your colleagues then compile with the headers and link that library with any executables that use any of those functions. That's very much the same general mechanism that the C compiler uses to include the standard headers and automatically link with the standard C library.
The mechanics vary a bit depending on platform (Windows vs Unix being the primary distinction, though there are differences between Unix platforms too), and also on the type of library (static archive vs dynamic linked / loaded libraries — also known as shared objects or shared libraries).
In broad outline, for a Unix system with a static library, you'd:
Compile library object files libfile1.o, libfile2.o, … using (for example) gcc -c libfile1.c libfile2.c.
Create an archive from the object files — using for example ar r libname.a libfile1.o libfile2.o.
Copy the headers to a standard location such as /usr/local/include.
Copy the library to a standard location such as /usr/local/lib.
You'd compile any code that uses the library functions with -I/usr/local/include (if that is not already a standard compilation option).
You'd link the programs with -L/usr/local/lib -lname (you might not need to specify -L… but you would need to specify -lname).
Including a header file does not make a function available. It simply informs the compiler that the function will be provided at a later time.
You should compile the file with the function into a shareable object file (or a library if there is more than one function that you want to share). Mind the switch -c which tells gcc not to build an executable file:
gcc -o test1.o test1.c -c
Similarly, compile the main function into its own object file. Now you or anyone else can link the object file with their main program:
gcc -o test2 test2.o test1.o
The process can be automated using make.
Other programmers can use compiled object files (`*.o') in their programs. They need only to have a header file with function prototypes, extern data declarations and type definitions.
You can also wrap many object files into the library.
On many systems you can also create the dynamic linked libraries which do not have to be linked into the executable.
you also need to compile test1:
gcc -g -o test2 test1.c test2.c.

How to use shared object file in c compilation

I'm trying to use this C library using gcc Apple LLVM version 8.0.0 (clang-800.0.42.1) on macOS Sierra. I've done the following steps:
make libquirc.so
Copied libquirc.so into my project directory
gcc -o quirc_test quirc_test.c -L. -l libquirc.so.1.0
It produces the error:
quirc_test.c:1:10: fatal error: 'quirc.h' file not found
#include <quirc.h>
^
1 error generated.
quirc_test.c
#include <quirc.h>
This is the first time I've tried to do anything in C and other related questions about compiling with the link flag didn't seem to help as seen above.
C is somewhat primitive. Shared object libraries do not contain the declaration of the API they implement - at least not in enough detail or a form that the compiler can understand.
You'll need the header file quirc.h somewhere you can find it. You could just copy it into the current directory just like the library, but you'll need a minor adjustment to the include statement.
#include "quirc.h"
If the included file is surrounded by double quotes instead of angle brackets, it will first look in the source code directory instead of the system header directories.
An alternative is to install the library somewhere e.g. /usr/local. Your library would go in /usr/local/lib nd your header in /usr/local/include. If you do that, use the -I directive on the compiler command line to tell the compiler where to look for the header e.g.
cc -I/usr/local/include -L/usr/local/lib -lquirc quirc_test.c

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.
First, as a beginner, you should always ask GCC to compile with all warnings and debugging information enabled, i.e. gcc -Wall -g. But at some time read How to invoke gcc. Use a good source code editor (such as GNU emacs or vim or gedit, etc...) to edit your C source code, but be able to compile your program on the command line (so don't always use a sophisticated IDE hiding important compilation details from you).
Then you are probably missing some Harvard specific library, some options like -L followed by a library directory, then -l glued to the library name. So you might need gcc -Wall -g -lcs50 (replace cs50 by the appropriate name) and you might need some -Lsome-dir
Notice that the order of program arguments to gcc is significant. As a general rule, if a depends upon b you should put a before b; more specifically I suggest
Start with the gcc program name; add the C standard level eg -std=c99 if wanted
Put compiler warning, debugging (or optimizing) options, eg -Wall -g (you may even want to add -Wextra to get even more warnings).
Put the preprocessor's defines and include directory e.g. -DONE=1 and -Imy-include-dir/
Put your C source file hello.c
Put any object files with which you are linking i.e. bar.o
Put the library directories -Lmy-lib-dir/ if relevant
Pur the library names -laa and -lbb (when the libaa.so depends upon libbb.so, in that order)
End with -o your-program-name to give the name of the produced binary. Don't use the default name a.out
Directory giving options -I (for preprocessor includes) and -L for libraries can be given several times, order is significant (search order).
Very quickly you'll want to use build automation tools like GNU make (perhaps with the help of remake on Linux)
Learn also to use the debugger gdb.
Get the habit to always ask for warnings from the compiler, and always improve your program till you get no warnings: the compiler is your friend, it is helping you!
Read also How to debug small programs and the famous SICP (which teaches very important concepts; you might want to use guile on Linux while reading it, see http://norvig.com/21-days.html for more). Be also aware of tools like valgrind
Have fun.
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"
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 ".
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)
You have to link against the library, how come GCC would know what library you want to use?
gcc helloWorld.c -lcs50
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:
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 *.c files like test-file.c which I will be creating for assignments/problem sets/practise etc.
Get the *.h and *.c files
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.c to create the "cs50.o" object file from "cs50.c" using "gcc"
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
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 😜)

gcc switches - what do these do?

I am new with using gcc and so I have a couple of questions.
What do the following switches accomplish:
gcc -v -lm -lfftw3 code.c
I know that lfftw3 is an .h file used with code.c but why is it part of the command?
I couldn't find out what -lm does in my search. What does it do?
I think I found out -v causes gcc to display programs invoked by it.
-l specifies a library to include. In this case, you're including the math library (-lm) and the fftw3 library (-lffw3). The library will be somewhere in your library path, possibly /usr/lib, and will be named something like libffw3.so
From GCC's man page:
-v Print (on standard error output) the commands executed to run the
stages of compilation. Also print the version number of the
compiler driver program and of the preprocessor and the compiler
proper.
-l library
Search the library named library when linking. (The second
alternative with the library as a separate argument is only for
POSIX compliance and is not recommended.)
It makes a difference where in the command you write this option;
the linker searches and processes libraries and object files in the
order they are specified. Thus, foo.o -lz bar.o searches library z
after file foo.o but before bar.o. If bar.o refers to functions in
z, those functions may not be loaded.
The linker searches a standard list of directories for the library,
which is actually a file named liblibrary.a. The linker then uses
this file as if it had been specified precisely by name.
The directories searched include several standard system
directories plus any that you specify with -L.
Normally the files found this way are library files---archive files
whose members are object files. The linker handles an archive file
by scanning through it for members which define symbols that have
so far been referenced but not defined. But if the file that is
found is an ordinary object file, it is linked in the usual
fashion. The only difference between using an -l option and
specifying a file name is that -l surrounds library with lib and .a
and searches several directories.
libm is the library that math.h uses, so -lm includes that library. You might want to get a better grasp of the concept of linking. Basically, that switch adds a bunch of compiled code to your program.
-lm links your program with the math library.
-v is the verbose (extra ouput) flag for the compiler.
-lfftw3 links your program with fftw3 library.
You just include headers by using #include "fftw3.h". If you want to actually include the code associated to it, you need to link it. -l is for that. Linking with libraries.
arguments starting with -l specify a library which is linked into the program. Like Pablo Santa Cruz said, -lm is the standard math library, -lfftw3 is a library for fourier transformation.
Try man when you're trying to learn about a command.
From man gcc
-v Print (on standard error output) the commands executed to run the
stages of compilation. Also print the version number of the
com-
piler driver program and of the preprocessor and the compiler
proper.
As Pablo stated, -lm links your math library.
-lfftw3 links in a library used for Fourier transforms. The project page, with more info can be found here:
http://www.fftw.org/
The net gist of all these statements is that they compile your code file into a program, which will be named the default (a.out) and is dependent on function calls from the math and fourier transform libs. The -v statement just helps you keep track of the compilation process and diagnose errors should occur.
In addition to man gcc which should be the first stop for questions about any command, you can also try the almost standard --help option. Even for commands that don't support it, an unsupported option usually causes it to print an error containing usage information that should hint at a similar option. In this case, gcc will display a terse (for gcc, its only about 50 lines long) help summary listing the small number of options that are understood by the gcc program itself rather than passed on to its component programs. After the description of the --help option itself, it lists --target-help and -v --help as ways to get more information about the target architecture and the component programs.
My MinGW GCC 3.4.5 installation generates more than 1200 lines of output from gcc -v --help on Windows XP. I'm pretty sure that doesn't get much smaller in other installations.
It would also be a good idea to read the official manual for GCC. It is also helpful to read the documentation for the linker (ld) and assembler (often gas or just as, but it may be some platform specific assembler as well); aside from a platform-specific assembler, these are documented as part of the binutils collection.
General familiarity with the command line style of Unix tools is also helpful. The idea that a single-character option's value might not be delimited from the option name is a convention that goes back essentially as far as Unix does. The modern convention (promulgated by GNU) that multiple-character option names are introduced by -- instead of just - implies that -lm might be a synonym for -l m (or the pair of options -l -m in some conventions but that happens not to be the case for gcc) but it is probably not a single option named -lm. You will see a similar pattern with the -f options that control specific optimizations or the -W options that control warnings, for example.

Static library not included in resulting LLVM executable

I am trying to compile a c program using LLVM and I am having trouble getting some static libraries included. I have successfully compiled those static libraries using LLVM and, for example, libogg.a is present, as is ogg.l.bc.
However, when I try to build the final program, it does not include the static ogg library. I've tried various compiler options with the most notable being:
gcc oggvorbis.c -O3 -Wall -I$OV_DIR/include -l$OV_DIR/lib/libogg.a -l$OV_DIR/lib/libvorbis.a -o test.exe
This results in the following output (directories shortened for brevity):
$OV_DIR/include/vorbis/vorbisfile.h:75: warning: ‘OV_CALLBACKS_DEFAULT’ defined but not used
$OV_DIR/include/vorbis/vorbisfile.h:82: warning: ‘OV_CALLBACKS_NOCLOSE’ defined but not used
$OV_DIR/include/vorbis/vorbisfile.h:89: warning: ‘OV_CALLBACKS_STREAMONLY’ defined but not used
$OV_DIR/include/vorbis/vorbisfile.h:96: warning: ‘OV_CALLBACKS_STREAMONLY_NOCLOSE’ defined but not used
llvm-ld: warning: Cannot find library '$OV_DIR/lib/ogg.l.bc'
llvm-ld: warning: Cannot find library '$OV_DIR/lib/vorbis.l.bc'
WARNING: While resolving call to function 'main' arguments were dropped!
I find this perplexing because $OV_DIR/lib/ogg.l.bc DOES exist, as does vorbis.l.bc and they are both readable (as are their containing directories) by everyone.
Does anyone have any idea with what I am doing wrong?
Thanks,
Matt
As unwind said,
-l is followed by the library name.
For example, in linux library naming conventions,
if a library is named libogg,
-logg will find and choose the *best match in the library directories.
You can add a directory into the list:
-L option is one of the way to add the following folder to the list temporarily.
The environment variable LD_LIBRARY_PATH also affects the list on most of Linux/Unix > with GNU tools.
gcc may find both static and shared library files whose name matches with the requested library name.
For example,
libogg.a
libogg.so
That's why there is a gcc option, -static
-static
On systems that support dynamic linking, this prevents linking
with the shared libraries. On other
systems, this option has no effect.
If you just want to use a shared or static library file - directly, just as an object file,
then give their path without any option, like
gcc oggvorbis.c the_path/libogg.a
I don't think the -l option expects paths. You should split those out, and use the -L option to set the paths, then just use plain library names with -l:
$ gcc oggvorbis.c -O3 -Wall -I$OV_DIR/include -L$OV_DIR/lib -logg -lvorbis -o test.exe
Also note that when used like this, you don't include the "lib" and ".a" parts of the library name.

Resources