Why can't gcc find my static library? - c

I am trying to link the cspec library into my C project. This is my Makefile located in the tests folder:
all: test
test: sample.o
gcc -Wall -o test sample.o -L ../lib/cspec -llibcspec.a
sample.o: sample.c
gcc -Wall -c sample.c -I../lib/cspec
clean:
rm -rf *o test
My directory is:
/
/src
/lib
/lib/cspec
/tests
When I run make I receive the following error:
gcc -Wall -o test sample.o -L ../lib/cspec -llibcspec.a
/usr/bin/ld: cannot find -llibcspec.a
I have made sure that the the libcspec.a file is located in the lib/cspec folder but to be sure I have also tried placing it within the tests folder and removing the -L command, to no avail.

Change:
gcc -Wall -o test sample.o -L ../lib/cspec -llibcspec.a
to:
gcc -Wall -o test sample.o -L ../lib/cspec -lcspec
(By convention, gcc and other *nix compilers automatically add the lib prefix and the appropriate suffix.)

Related

Ocaml/C interop using bigarray: 'undefined symbol: caml_ba_alloc'

I'm trying to compile a 'Hello World'-level Ocaml/C interop program that uses bigarray. I'm getting an error about undefined symbol: caml_ba_alloc (details below). It seems like it should be provided by bigarray.h.
Here are my files:
wrap_mylib.c:
#include <caml/bigarray.h>
#include <caml/mlvalues.h>
#include <caml/memory.h>
CAMLprim value caml_fn(value x) {
float* result = malloc(sizeof(float));
long dims[] = {1, 1};
return caml_ba_alloc(CAML_BA_NATIVE_INT, 2, result, dims);
}
mylib.ml:
external ext_caml_fn : int -> (float, Bigarray.float32_elt, Bigarray.c_layout) Bigarray.Array2.t
= "caml_fn" ;;
Makefile:
wrap_mylib.o: wrap_mylib.c
gcc -c wrap_mylib.c
another_wrapper.so: wrap_mylib.o
cc -shared -o another_wrapper.so wrap_mylib.o
mylib.mli: mylib.ml
ocamlc -i $< > $#
mylib.cmi: mylib.mli
ocamlc -c $<
mylib.cmo: mylib.ml mylib.cmi
ocamlc -c $<
mylib_test: mylib.cmo another_wrapper.so
ocamlc -linkall -o mylib_test mylib.cmo another_wrapper.so
clean:
rm *.cma *.cmo *.cmi *.cmx *.cmxa *.mli *.o *.a *.so
Here is the output when I try to compile mylib_test:
$ make mylib_test
ocamlc -i mylib.ml > mylib.mli
ocamlc -c mylib.mli
ocamlc -c mylib.ml
gcc -c wrap_mylib.c
cc -shared -o another_wrapper.so wrap_mylib.o
ocamlc -linkall -o mylib_test mylib.cmo another_wrapper.so
File "_none_", line 1:
Error: Error on dynamically loaded library: ./another_wrapper.so: ./another_wrapper.so: undefined symbol: caml_ba_alloc
Makefile:17: recipe for target 'mylib_test' failed
make: *** [mylib_test] Error 2
Environment
OS: Ubuntu 18.04.2 LTS (Bionic Beaver)
$ ocaml --version
The OCaml toplevel, version 4.05.0
Thank you!
Files like bigarray.h define things that are useful at compile time. But your problem is a link-time problem. You need to find the library that contains the function you're looking for and include it in the link step.
If I use ocamlopt (native code implementation) and use ordinary object files (OCaml .cmx and C .o) rather than a shared library, I can get things to link up like this:
$ ocamlopt -c mylib.ml
$ gcc -I $(ocamlc -where) -c wrap_mylib.c
$ ocamlopt -o mylib_test wrap_mylib.o mylib.cmx
This produces an executable mylib_test that I can run:
$ ./mylib_test
$
Of course nothing happens when I run the executable because there is no top-level code in your file mylib.ml. So this is just testing whether things will link up OK.
I hope this is helpful.
Answering my own question. Here's how I was able to get it to work. Compile mylib_test by linking bigarray.cma:
ocamlc -linkall -o mylib_test mylib.cmo another_wrapper.so bigarray.cma
Then run with:
LD_LIBRARY_PATH=. ./mylib_test
The LD_LIBRARY_PATH=. is necessary for it to find the shared library another_wrapper.so in the same directory.
According to https://caml.inria.fr/pub/docs/manual-ocaml/libbigarray.html bigarray is now part of the standard library and so linking bigarray.cma should only be necessary when using the legacy compatibility library. Possibly my version of the standard library is old.

Linking static library with -l flag

How can I have my makefile compile with the -l flag?
I have a makefile that looks like
myLibrary:
gcc -c myLibrary.c -o myLibrary.o
ar cr libmyLibrary.a myLibrary.o
and then I compile my main program with
main:
gcc -g -c -o main.o main.c
gcc main.o -o main libmyLibrary.a
The above makefile works, but if I want to replace
libmyLibrary.a
with -lmyLibrary I get an error. Shouldn't both be working the same?
Here is a rudimentary, unrealistic makefile that will make the static library libmyLibary
before it makes the program main, which it will link with the static library
using the -L (library search-path) and -l (library) options.
Makefile
.PHONY: all clean
all: libmyLibrary.a main
main: main.o | libmyLibrary.a
$(CC) -o main main.o -L. -lmyLibrary
libmyLibrary.a: myLibrary.o
$(AR) rcs libmyLibrary.a myLibrary.o
clean:
rm -f *.o libmyLibrary.a main
which runs like:
$ make
cc -c -o myLibrary.o myLibrary.c
ar rcs libmyLibrary.a myLibrary.o
cc -c -o main.o main.c
cc -o main main.o -L. -lmyLibrary
As I think you know, it's unrealistic to make both a library and a program
that links with it in the same makefile, since the point of a library is
that you don't need to keep remaking it to link it with many programs. You'd really have
a makefile for libmyLibrary.a and other makefiles for programs that
use it.
This is how the gcc linkage options -L and -l work:
-L/path/to/search
tells the linker to look for any libraries that you specify with the -l option in /path/to/search,
before it looks for them in its default search directories. The current directory, .,
isn't one of the linker's default search directories. So if you want it to
find a library specified with the -l option in the current directory, then you need to
specify -L.
-lfoo
tells the linker to search for either a dynamic library, libfoo.so, or a static
library, libfoo.a, first in your -L directories, if any, in the order you've
specified them, and then in its default search directories. It stops searching
as soon as if finds either libfoo.so or libfoo.a in one of the search directories.
If it finds both of them in the same directory, then by default it will link libfoo.so with
your program and not link libfoo.a.
To link purely statically library, use -static, Like
gcc -static main.c libmyLibrary.a
And run executable file ./a.out GCC Linux.

dynamic library gcc compilation error

I have the following code:
gcc -Wall -fno-stack-protector -O2 -g -fPIC -c ec.c
pwd
gcc -shared -Wl,-soname,libec.so.1 -o libec.so.1.0 ec.o /urs/src/soem/ethercat*.o ../soem/nicdrv.o -lc -lpthread
mv libec.so.1.0 /usr/lib/.
cd /usr/lib
ldconfig -v -n
ln -sf libec.so.1.0 libec.so
ln -sf libec.so.1.0 libec.so.1
It gives the following error when compiling:
/home/ebox/Documents/SVN/Libs/ec
gcc: error: /urs/src/soem/ethercat*.o: No such file or directory
mv: cannot stat ‘libec.so.1.0’: No such file or directory
I understand there is something wrong with the gcc command, but cannot figure out how to fix this. There are several .o files in the path that start with ethercat*.
How can I get this fixed?
The error means that there are no files that match the pattern /urs/src/soem/ethercat*.o.
Note that the first component is urs. Probably it should be usr.

GCC compile with mysql library

when I try to compile a self written project in C with includes the mysql libraries I get this error:
gcc -c src/oDAO.c
src/oDAO.c:4:23: fatal error: my_global.h: No such file or directory
I included the my_global.h as following:
#include <my_global.h>
The error comes up, because my system copied the header files to /usr/include/mysql/ and gcc is searching for system header files only in /usr/include (without subdirectories). How can I call gcc with adding /usr/include/mysql as additional shared library root?
Here is my acutal Makefile:
all: main.o oDAO.o FileUtils.o DVDDAO.o
gcc -Llib -o oDAO main.o oDAO.o FileUtils.o DVDDAO.o -llinkedlist -lncurses `mysql_config --cflags --libs`
main.o:
gcc -c src/main.c
oDAO.o:
gcc -c src/oDAO.c
FileUtils.o:
gcc -c src/FileUtils.c
DVDDAO.o:
gcc -c src/DVDDAO.c
clean:
rm -f *.o
rm -f oDAO
rm -f *.bak
rm -f *.~
I've got the answer on my own:
Everytime i try to compile a .c file that includes a mysql library into an object file I have to compile it like that:
gcc -c DVDDAO.c `mysql_config --cflags`
Then everything works fine
Try the option -I for adding a include directory and -L for adding a libary directory.

Running gcc's steps manually, compiling, assembling, linking

If you have a simple C program, like
int main(void) {return 0;}
It can be compiled with gcc -o test test.c.
As I understand, gcc performs compiling, assembling then linking. The latter two steps are achieved by it running as and ld.
I can generate the assembly code by using gcc -S test.c.
What would you type into a terminal, to convert the assembly code into an executable?
(the reason for doing so is to learn assembly)
These are the different stages using gcc
gcc -E --> Preprocessor, but don't compile
gcc -S --> Compile but don't assemble
gcc -c --> Preprocess, compile, and assemble, but don't link
gcc with no switch will link your object files and generate the executable
// main.c
#include <stdio.h>
int main(void)
{
printf("Hello World !\n");
return 0;
}
For preprocessing, compiling, assembling and then finally linking the simple aforementioned hello world program, follow the steps below:
Step 1/4) Preprocess main.c to generate main.i:
$: gcc -E main.c -o main.i
NOTE: You could call the C preprocessor directly as well:
$: cpp main.c -o main.i
Step 2/4) Compile main.i to generate main.s:
$: gcc -S main.i -o main.s
Step 3/4) Assemble main.s to generate main.o:
$: as main.s -o main.o
NOTE: You can combine the aforementioned steps 1, 2 and 3 by using the -c (small C) flag of gcc:
$: gcc -c main.s -o main.o // OR $: gcc -c main.c -o main.o
Step 4/4) Link main.o with other necessary object files namely, crti.o & crtn.o (they define function prologs & epilogs, respectively), crt1.o (contains _start symbol for bootstrapping the initial execution of the program), libc.so path or -lc flag for libc and then finally set the name of the dynamic linker, to generate a dynamically linked ELF executable:
On x86_64:
$: ld /usr/lib/x86_64-linux-gnu/crti.o /usr/lib/x86_64-linux-gnu/crtn.o /usr/lib/x86_64-linux-gnu/crt1.o -lc main.o -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o main_ELF_executable
OR (if you'd like to specify path to libc.so)
$: ld /usr/lib/x86_64-linux-gnu/crti.o /usr/lib/x86_64-linux-gnu/crtn.o /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/libc.so main.o -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o main_ELF_executable
On 32-bit ARM:
$: ld /usr/lib/arm-linux-gnueabihf/crti.o /usr/lib/arm-linux-gnueabihf/crtn.o /usr/lib/arm-linux-gnueabihf/crt1.o -lc main.o -dynamic-linker /lib/ld-linux.so.3 -o main_ELF_executable
OR (if you'd like to specify path to libc.so)
$: ld /usr/lib/arm-linux-gnueabihf/crti.o /usr/lib/arm-linux-gnueabihf/crtn.o /usr/lib/arm-linux-gnueabihf/crt1.o /usr/lib/arm-linux-gnueabihf/libc.so main.o -dynamic-linker /lib/ld-linux-armhf.so.3 -o main_ELF_executable
You can then run the ELF executable 'main_ELF_executable':
$: ./main_ELF_executable
Hello World !
Sources:
https://linux.die.net/man/1/gcc
https://linux.die.net/man/1/ld
https://dev.gentoo.org/~vapier/crt.txt
gcc test.s -o test will compile the test from test.s for you.
NASM might also be worth your time -- it might be easier / more friendly than gcc for compiling assembly.
After you do gcc -S -o test.s test.c, type gcc -o test test.s.
As you may or may not know, the four stages of compilation are to preprocess (-E), compile to assembly (-S), assemble to object code (-c), and finally link. The hardest for me to figure out was how to use the preprocessor output. Here's how to do it:
gcc -E hello.c | gcc -S -xc -o hello.s -
gcc -c hello.s -o hello.o
gcc hello.o -o hello
You can have gcc start and stop the compilation process wherever you want. gcc test.s -o test will have it compile test.s from assembly into an executable.
what I did was first I run the preprocessor by
clang++ test.cpp -E > test.i
then compiled it with ...
clang++ -S test.i
it should create a assembly file test.s ... then make the machine insturction file by
as test.s -o test.o
now you need to link it which is kinda confusing for dumb peoples like me ...
so we don't know the arguments for our last process which is linking ... to find out ... run
clang++ -v test.s
it should give you some big text of something ... find this line "-dynamic-linker" ... there's definately a -dynamic-linker in your output text ... now copy the text from -dynamic-linker to rest of the output ... just copy everything afterwards including "-dynamic-linker" ... now what i got is ...
-dynamic-linker /system/bin/linker -o a.out /data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib/crtbegin_dynamic.o -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0 -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../.. -L/data/data/com.termux/files/usr/lib -L/system/lib /data/data/com.termux/files/usr/tmp/test-169b42.o -lc++_shared -lgcc -ldl -lm -lc -lgcc -ldl /data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib/crtend_android.o
in this what you have to change is where your object file is ... in my case it is /data/data/com.termux/files/usr/tmp/test-169b42.o ... i need to change it to where my test.o file is ... /data/data/com.termux/files/home/CPP/Cpp_Log/hello_world/test.o ... this is where my test.o file is ...
so the argument we have to pass is ...
-dynamic-linker /system/bin/linker -o a.out /data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib/crtbegin_dynamic.o -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0 -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../.. -L/data/data/com.termux/files/usr/lib -L/system/lib /data/data/com.termux/files/home/CPP/Cpp_Log/hello_world/main.o -lc++_shared -lgcc -ldl -lm -lc -lgcc -ldl /data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib/crtend_android.o
now to link ... use the ld ... so the command is ld args -o test or in our case ...
ld -dynamic-linker /system/bin/linker -o a.out /data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib/crtbegin_dynamic.o -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0 -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../.. -L/data/data/com.termux/files/usr/lib -L/system/lib /data/data/com.termux/files/home/CPP/Cpp_Log/hello_world/main.o -lc++_shared -lgcc -ldl -lm -lc -lgcc -ldl /data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib/crtend_android.o -pie -o test ...
since andriod 5+ can only run pie elf executables ... i also added the "-pie" (position independent executable) before the -o test ...
now it should give you a executable file test ... just run it by ./test
it should work

Resources