C Link External Library in Makefile - c

I am having issues linking a library (termbox) when compiling. I get the error:
make: *** No rule to make target `termbox.h', needed by `test.o'. Stop.
Makefile:
edit: test.o
gcc -Wall -o edit test.o
test.o: test.c termbox/src/termbox.h
gcc -Wall -c test.c -ltermbox/src
Include:
#include "termbox/src/termbox.h"
I have also tried using the compiled library but ran into similar issues. Do I have to use some sort of combination of specifying the header file and the location of the compiled library?
The directory of my termbox folder is in the same directory as test.c.
Thanks!

You have managed to compile and include the header file for the library, but you did not yet tell the compiler where the code (definitions) are - i.e. you did not tell it to link in the library yet.
You will need to do that next, this is done in a similar way to telling the linker what files to link, but with some extra syntax. It appears to be a static library (.a suffix) so you can link like this:
test.o: test.c termbox/src/termbox.h
gcc -Wall -c test.c -Itermbox/src -Lsrc -ltermbox
Where -L... specifies where libraries can be found and -l... specifies the library name to link to minus the lib prefix and the .a or .so suffix. Also note that order is important, so leave the library linkage at the end.
More on library linking order here
UPDATE
Sorry I added the linking to the wrong line! - here is the updated answer:
# The linker stage
edit: test.o
gcc -Wall -o edit test.o -Lsrc -ltermbox
# Compile stage
test.o: test.c termbox/src/termbox.h
gcc -Wall -c test.c -ltermbox/src

Related

Using a static library in C

I found a useful library on github for my project, after building this later I tried to use some predefined function on it. I couldn't compile my project because there is some header file missing like this one :
In file included from main.c:2:0:
ptask.h:11:19: fatal error: ptime.h: No such file or directory
I compiled my project using this command :
gcc main.c -L. -lptask
This is all the files in project folder :
libptask.a main.c ptask.h
This is the library content:
$ ar -t libptask.a
pbarrier.c.o
pmutex.c.o
ptask.c.o
ptime.c.o
rtmode.c.o
tstat.c.o
libdl.c.o
dle_timer.c.o
calibrate.c.o
Do I need to add all the headers of this files or just link the lib when compiling ?
Your main.c #include-s ptask.h which in turn #include-s ptime.h. Having compiled static libs alone is not enough (that's the linker's job), you still need to have all used header files (which is the compiler's job), both the ones you use and their dependencies, recursively applicable.
Normally you need to be sure that the header files are in your "include path", something that a lot of compilers define with -I as a command-line option. You'll need to include the source directory of that library, or if it has a make install option, then the place where they got installed.
regarding:
gcc main.c -L. -lptask
this is performing the compile step and the link step in one command.
It is also not enabling the warnings, which should always be enabled during the compile step.
Suggest something similar to the following to compile
gcc -Wall -Wextra -Wconversion -pedantic -std=gnu11 -g -c main.c -o main.o -I.
and when you have fixed all the warnings, then use something similar to the following to link
gcc main.o -o main -L. -lptask

Cannot find -lCommunication collect2: error: ld returned 1 exit status

I do not know gcc and c well. In my /home/pi/Desktop/intern/adis16227_generic directory I have following 5 files.
ADIS16227.c
ADIS16227.h
Communication.c
Communication.h
main.c
main.c
#include<stdio.h>
#include "Communication.h" // Communication definitions.
int main() {
printf("hello!!\n");
unsigned char status = 0;
status = SPI_Init(0, 1000000, 1, 1);
printf("%u", status);
return 0;
}
Run command:
$ sudo gcc -L /home/pi/Desktop/intern/adis16227_generic main.c -lCommunication
Error:
/usr/bin/ld: cannot find -lCommunication
collect2: error: ld returned 1 exit status
Question:
What I am missing here?
What do I need to run the code?
-l is for libraries, and you never built a library from your Communication.c. The simplest solution is just add Communication.c to your compiler command line.
For larger projects, compile each translation unit separately with the -c switch like this:
gcc -c -Wall -Wextra -pedantic -omain.o main.c
gcc -c -Wall -Wextra -pedantic -oCommunication.o Communication.c
and so on ... (as a suggestion, I added some common warning options here, they help you spot errors)
The resulting .o files are object code. That's already compiled machine code, but with meta-information needed for a linker to link it with other object code into a complete executable.
Then link them all with one command:
gcc -oprogram main.o Communication.o
If you actually want a library from -- say -- Communication.c and ADIS16227.c, you could compile both to object code:
gcc -c -Wall -Wextra -pedantic -oCommunication.o Communication.c
gcc -c -Wall -Wextra -pedantic --oADIS16227.o ADIS16227.c
and then use ar to create a static library from them:
ar rcs libCommunication.a Communication.o ADIS16227.o
Then your initial compiler command would work (with the -lCommunication switch).
Final piece of advice: Never compile as root. This is completely unnecessary. So remove your sudo here.
those options:
-L /home/pi/Desktop/intern/adis16227_generic -lCommunication
suggest that the linker should find libCommunication.a (or .so) in the /home/pi/Desktop/intern/adis16227_generic directory.
But there are only sources in this directory. The linker won't build the sources of your "Communication" library for you.
So you could build the library and link with it:
gcc -c ADIS16227.c Communication.c
ar r libCommunication.a ADIS16227.o Communication.o
but maybe the fastest & quickest way to achieve a successful build would be:
sudo gcc -o main *.c
so it compiles all the files of the directory into the executable called main
Of course, it makes compilation times longer, but maybe it's not noticeable.
First move into the /home/pi/Desktop/intern/adis16227_generic directory:
cd /home/pi/Desktop/intern/adis16227_generic
Then, compile the source:
gcc ADIS16227.c Communication.c main.c -I .
You can now run your compiled program (called by default a.out):
./a.out
You have to compile separatedly files and then compile main with related obj file.
gcc -c Communication.c Communication.h
gcc main.c Communication.o -o main

gcc in Windows cannot compile C program written for Unix/Linux

I am a Unix/Linux newbie who is trying to run a shell script written by a person who left no documentation and has since demised. This script contains line:
./search $opt1 $arg1 < $poly 2>&1 | tee $output
Which is trying to get the file $poly and call program ./search and divert the output to $output.
When I get to this line, I am given message: ./search: cannot execute binary file: Exec format error
search is a C program called from the script and is in the same folder as various other C programs to do with this project. Script and C programs were developed and originally executed on a Unix/Linux box which is no longer available, so I have been asked to try to resurrect this project but under Windows using gcc in NetBeans and cygwin.
The message : ./search: cannot execute binary file: Exec format error is most likely to do with the fact there is no executable file for search. When I try to build the C programs I get the following output:
C:\cygwin64\bin\make.exe -f Makefile
gcc -ansi -g -c cbuild.c
gcc -ansi -g -c complex.c
gcc -ansi -g -c mylib.c
gcc -ansi -g -c poly.c
gcc -ansi -g -c real.c
gcc -ansi -g -c zero.c
gcc -lgmp -lm -lrt -o cbuild cbuild.o complex.o mylib.o poly.o real.o zero.o
real.o: In function `rabs':
/cygdrive/c/../progs/real.c:9: undefined reference to `__imp___gmpf_abs'
/cygdrive/c/../progs/real.c:9:(.text+0x1e): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `__imp___gmpf_abs'
real.o: In function `radd':
I assume that R_X86_64_PC32 refers to the environment I am using. I am using a 64 bit version of Netbeans with gcc 5.4.0 in a 64 bit version of cygwin on Windows 10.
Can anyone advise what I must to to resolve this so that I can build the C programs?
The problem is this:
gcc -lgmp -lm -lrt -o cbuild cbuild.o complex.o mylib.o poly.o real.o zero.o
By default, the linker will link libraries and objects in the order specified on the command line, and, when linking a library, will only include symbols needed by things before it on the command line. Since -lgmp is first, there are (as yet) no outstanding symbols (except main), so nothing is included from the library. When later objects need the symbols from it, they won't see them.
Change the order to
gcc -o cbuild cbuild.o complex.o mylib.o poly.o real.o zero.o -lgmp -lm -lrt
and it should work. Alternately, use the -Wl,--as_needed linker option to get the linker to remember earlier libraries and relink them if more symbols from them are referenced by later object files (requires a recent version of the GNU linker -- I have no idea if it works with cygwin).
This kind of misordering is usually a symptom of a broken Makefile. The normal Makefile structure has a bunch of variables that are set to control the default rules that know how to compile source files and link object files. The two variables relevant for linking are LDFLAGS and LDLIBS, and the difference is that LDFLAGS comes before all the object files on the command line and LDLIBS comes after all the object files.
So in order to make things work, you need to ensure that all of the -l options and other libraries are in LDLIBS:
LDLIBS = -lgmp -lrt -lm
and NOT in LDFLAGS

Switched from shared library to dll, now getting an error that it can't find pow()

Here is the error:
symbol lookup error: ./src/libprog3.so: undefined symbol: pow
Everything else in the library works fine, even functions that use math.h, but when I call the function that needs pow(), it crashes. It worked perfectly fine when it was a shared library. I am using gcc and a makefile to compile. The only change I made to the makefile was adding -ldl for the library. I still have -lm in it. I changed the driver program to support the change to the dll instead of the shared library, but the function causing the error hasn't changed.
Is there more to the makefile that I need to change?
Here is the makefile:
testlib: src/driver.o src/prog3.o
gcc -fPIC -Wall -c src/prog3.c -o src/prog3.o
gcc -Wall -shared -o src/libprog3.so src/prog3.o
gcc -Wall -o $# src/driver.c -ldl -lm -Lsrc -lprog3
You need to be doing:
gcc -Wall -shared -o src/libprog3.so src/prog3.o -lm
That is, shared libraries must be built with their dependencies. If you omit the -lm, you're telling the linker that unresolved symbols in libprog3.so are intended to be resolved by symbols in the main program or libraries it has already caused to be loaded. I see you did put -lm on the link command line for the main program, but my guess is that the main program did not actually use any symbols from libm.so and thus it did not get added to the DT_NEEDED table for the main program and therefore is not already loaded.
In any case, making dependencies explicit like this is almost always best.

C: undefined reference... to library used successfully elsewhere

I am trying to compile a C++ project (openFrameworks + CodeBlocks), using an external C library. I get "undefined reference" error, although I succesfully compile and use the library elsewhere.
The code consists of sources main.cpp, testApp.cpp and header files, including one for my library "myprocessing". When I make , the code is compiled and dies at linking with error
obj/i686Release/./src/testApp.o: In function `testApp::update()':
testApp.cpp:(.text+0x261): undefined reference to `gauss_5(datarect_t)'
collect2: ld returned 1 exit status
make: *** [bin/faceGrabber] Error 1
where gauss_5 is my library function, and it is called in testApp.cpp (header with declarations is included there).
Below I paste the make commands used to compile the code, generated by CodeBlocks (I strip it for clarity)
# compiling object for: ./src/testApp.cpp
g++ -c -g [some -I...] -DOF_USING_GTK -DOF_USING_MPG123 -Wall
-fexceptions -I. -Ilib/ -MMD -MP -MFobj/i686Debug/./src/testApp.d
-MTobj/i686Debug/./src/testApp.d -oobj/i686Debug/./src/testApp.o
-c ./src/testApp.cpp
# compiling object for: ./src/main.cpp
g++ -c -g -pthread [some -I...] -DOF_USING_GTK -DOF_USING_MPG123
-Wall -fexceptions -I. -Ilib/ -MMD -MP -MFobj/i686Debug/./src/main.d
-MTobj/i686Debug/./src/main.d -oobj/i686Debug/./src/main.o
-c ./src/main.cpp
# linking bin/faceGrabber_debug . ./src ./lib
g++ -o bin/faceGrabber_debug obj/i686Debug/./src/testApp.o
obj/i686Debug/./src/main.o -Wl,-rpath=./libs -Llib/ -lz
-lmyprocessing [some libs...]
Note that my library is referenced (-lmyprocessing) in the last, linking step. So, all the headers and libraries are found by the compiler, but somehow they are not compiled-in.
I tried both .a static and .so dynamic files for myprocessing, unsuccessfully. As I mentioned, I use the same library in other project (outside openFrameworks and CodeBlocks) and it works.
You say that the library is written in C. However, the fact that the linker is able to print out the type of the argument to gauss_5() suggests that it's working with the mangled, C++ name of the function.
I suspect you might be missing extern "C" { ... } guards around your C header.

Resources