How do I compile a static library - c

I am trying to compile a static library. I followed the steps which were given in an answer to this question but it is not working. Following is my makefile.
PROJECT = lq.a
OBJECTS = dlmalloc.o queue.o.o
CFLAGS = -o -Wall -pedantic
all: $(PROJECT)
.c.o:
gcc -c $(CFLAGS) $<
$(PROJECT): $(OBJECTS)
libtool -o $(PROJECT) -static $(OBJECTS)
And I get the following error.
libtool: unrecognized option `-o'
What is the correct way of writing this makefile?

You can use the program ar to create static libraries using the following syntax:
ar rcs my_library.a file1.o file2.o
So, in your case:
$(PROJECT): $(OBJECTS)
ar rcs $(PROJECT) $(OBJECTS)
You can find an explanation of the options on the man page, but basically:
r says insert the given object files in to the archive (replacing any older versions of the same thing)
c says create the archive if it isn't already there (normally this happens anyway, but this option suppresses the warning).
s says to write an object-file index into the archive.

Well, this is confusing; but I think that the libtool -o $(PROJECT) -static $(OBJECTS) line (also mentioned in objective c - Combine static libraries) comes from Mac; and apparently the libtool there is NOT the same as the one on Linux:
libtool or ar & ranlib - idevgames forums:
I was using libtool to create a static library on OS X because that's what Xcode was doing, which seems to work fine. Then I go over to Linux and it chokes on my libtool command saying "libtool: unrecognized option '-o'". Looking at them, it seems like libtool on OS X and libtool on Linux are two completely different programs. ...
Followup: Yes, it appears that libtool on Linux is indeed glibtool on OS X. I get essentially the same output when doing "glibtool --help" on OS X as "libtool --help" on Linux.
Ok, that explains the difference - but still doesn't explain how -o can be an unrecognized option, when I've just seen it run from a Makefile on Linux! So I found this:
bug-libtool mailing list (2001): Re: bug in libtool?
You need to set the mode before the mode options:
$ libtool --mode=link --help
Usage: libtool [OPTION]... --mode=link LINK-COMMAND...
Oh dear... now what makes it especially confusing, is this note in libtool --mode=link --help:
$ libtool --mode=link --help
Usage: libtool [OPTION]... --mode=link LINK-COMMAND...
...
LINK-COMMAND is a command using the C compiler that you would use to create
a program from several object files.
The following components of LINK-COMMAND are treated specially: ...
-all-static do not do any dynamic linking at all ...
-o OUTPUT-FILE create OUTPUT-FILE from the specified objects ...
-static do not do any dynamic linking of uninstalled libtool libraries
...
All other options (arguments beginning with `-') are ignored.
Every other argument is treated as a filename. Files ending in `.la' are
treated as uninstalled libtool libraries, other files are standard or library
object files.
...
If OUTPUT-FILE ends in `.a' or `.lib', then a standard library is created
using `ar' and `ranlib', or on Windows using `lib'.
So - if I have to specify a LINK-COMMAND - and at the same time, I specify an OUTPUT-FILE which ends in .a; which command should then run, LINK-COMMAND - or the ar+ranlib that extension .a specifies? Well - here's a terminal snippet, just testing the bash script logic of libtool - without any compilation (though an empty archive does get created):
$ libtool -o test.a
libtool: unrecognized option `-o'
libtool: Try `libtool --help' for more information.
$ libtool --mode=link -o test.a
libtool: link: unrecognized option `-o'
libtool: link: Try `libtool --help' for more information.
$ libtool --mode=link gcc -o test.a
libtool: link: ar cru test.a
libtool: link: ranlib test.a
$ libtool --mode=link ar -o test.a
libtool: link: unable to infer tagged configuration
libtool: link: specify a tag with `--tag'
$ cat $(which libtool) | grep "^# ### BEGIN LIBTOOL TAG CONFIG:"
# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
# ### BEGIN LIBTOOL TAG CONFIG: disable-static
# ### BEGIN LIBTOOL TAG CONFIG: CXX
# ### BEGIN LIBTOOL TAG CONFIG: F77
# ### BEGIN LIBTOOL TAG CONFIG: FC
# ### BEGIN LIBTOOL TAG CONFIG: GCJ
# ### BEGIN LIBTOOL TAG CONFIG: RC
# ### BEGIN LIBTOOL TAG CONFIG: BINCC
# ### BEGIN LIBTOOL TAG CONFIG: BINCXX
## CC tag is not listed, but it will (eventually) be accepted:
$ libtool --mode=link ar --tag CC -o test.a
libtool: link: unable to infer tagged configuration
libtool: link: specify a tag with `--tag'
$ libtool --mode=link --tag CC ar -o test.a
libtool: link: ar cru test.a
libtool: link: ranlib test.a
$ libtool --tag=CC --mode=link ar -o test.a
libtool: link: ar cru test.a
libtool: link: ranlib test.a
$ libtool --tag=XX --mode=link ar -o test.a
libtool: ignoring unknown tag XX
libtool: link: ar cru test.a
libtool: link: ranlib test.a
$ libtool --tag=XX --mode=link whatevar -o test.a
libtool: ignoring unknown tag XX
libtool: link: ar cru test.a
libtool: link: ranlib test.a
$ ls -la test.a
-rw-r--r-- 1 user user 8 2013-04-17 23:12 test.a
So - not only do you have to specify a --mode, but if this mode is link, you MUST specify SOME sort of an argument (LINK-COMMAND) referring to a tool; BUT that LINK-COMMAND argument doesn't even need to exist as a real program - because you must specify an output file anyway; and if that output file ends on .a, it will enforce use of ar/ranlib anyways.
Also, should you have a problem with a tag - simply move the --tag argument before the LINK-COMMAND argument - and you can force libtool to run with a non-existing tag and a non-existing LINK-COMMAND (where it's operation is specified solely by the extension .a of the output file) - as long as the arguments are entered in the proper order for the libtool syntax; which I must admit isn't really documented in the script itself.
But to come back to the Mac libtool -o $(PROJECT) -static $(OBJECTS) line, which would combine static libraries; if you try to do the same with proper static library .a files, you will notice that libtool pushes the .a archives as such in the output archive, not their constituent object files - so this output is not a valid ELF object anymore; here is an example of a corresponding Linux libtool line, with two proper library files I've generated:
$ readelf --syms libmy1.a
File: libmy1.a(my1.o)
Symbol table '.symtab' contains 11 entries:
...
$ readelf --syms libmy2.a
File: libmy2.a(my2.o)
Symbol table '.symtab' contains 12 entries:
...
$ libtool --mode=link --tag=CC ar -o libtest.a -static libmy1.a libmy2.a
libtool: link: ar cru libtest.a libmy1.a libmy2.a
libtool: link: ranlib libtest.a
$ readelf --syms libtest.a
readelf: Error: Not an ELF file - it has the wrong magic bytes at the start
readelf: Error: libtest.a(libmy1.a): Failed to read file header
readelf: Error: Not an ELF file - it has the wrong magic bytes at the start
readelf: Error: libtest.a(libmy2.a): Failed to read file header
So, as the accepted answer says - on Linux, use ar manually to unpack and pack again, to combine static libraries.
Hope this helps someone,
Cheers!

Either use libtool or don't. If you're going to use it, then you should compile the individual files with libtool --mode=compile as well as linking with libtool --mode=link. If you're not going to use libtool, then your link should be done with gcc also, as pointed out in another answer. Also, have you tried man libtool?

The following commands will build your static library:
$gcc -c file1.c -o libfile.o
$ar rcs libfile.a libfile.o

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.

Compiling on RaspberryPi by using make

When I use make to compile the RaspberryPi's source code, the error happens like this:
"bmp180.c:(.text+0xe8): undefined reference to `bcm2835_i2c_write'"
However, I have used the "-l bcm2835", the makefile as follow:
#makefile
bmp: main.o bmp180.o
gcc -o bmp main.o bmp180.o
main.o: main.c bmp180.h
gcc -c main.c -l bcm2835.h
bmp180.o: bmp180.c bmp180.h
gcc -c bmp180.c -l bcm2835.h
clear:
rm -f main.o bmp180.o
You have -l bcm2835.h in your Makefile. The name of the library is simply bcm2835. Files ending with .h are files meant to be #include'd in your C source; they are not dynamic shared libraries.
Additionally, shared libraries are required at the link stage, not the compile stage; you will need to add -l bcm2835 to the linking step:
bmp: main.o bmp180.o
gcc -o bmp main.o bmp180.o -l bcm2835
The -l arguments in your compile steps are effectively no-ops (but they won't hurt anything).

How can you create a libtool object from a dll and lib file?

I have been hacking away at this problem for days now and I can't seem to get this seemingly simple problem solved. There are functions provided by a DLL that I need to use from another DLL. I have verified that all of the missing symbols I need are in the static library extracted by dlltool, but no matter what I try it will not link into the shared library. This is my current attempt which seemed promising but has simply lead me to a new error.
libtool: link: cannot build libtool library 'libnvml.la' from non-libtool object on this host
This is my Makefile.am
AM_CPPFLAGS = -I$(top_srcdir)/include
lib_LTLIBRARIES = libnvml.la
libnvml.la: libnvml.a
ar x libnvml.a `ar -t libnvml.a` && $(LIBTOOL) --mode=link $(CC) -g -O -o $# `ar -t libnvml.a`
libnvml.a: nvml.def
$(DLLTOOL) -d $< -D nvml.dll -k -l $# && ranlib libnvml.a
nvml.def: $(NVML)/lib/nvml.lib
$(LIB2A)/bin/reimp.exe -d $<
Does anyone know how I can convert this lib file into libtool library (.la) so I can link it to my dll?

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.

automake and custom rpath

I have to ship a third-party library with an application. Because I don't want to set LD_LIBRARY_PATH by hand or require any wrapper script I want automake to set a custom rpath. Unfortunately libtool has its own -rpath option and adding -Wl,-rpath,/foo/bar to LDFLAGS only results in
g++: unrecognized option '-rpath'
because libtool seems to get confused with the command line options. The same happens with the alternative form -Wl,-rpath -Wl,/foo/bar.
Is there any way to specify a custom rpath without libtool interference?
As you said, libtool has its own -rpath option. Any reason you don't want to use it?
% libtool link g++ foo.cc -o foo -rpath /somewhere
libtool: link: g++ foo.cc -o foo -Wl,-rpath -Wl,/somewhere
% readelf -d foo | grep RPATH
0x000000000000000f (RPATH) Library rpath: [/somewhere]
None of the examples in the Automake or Libtool manuals use -Wl to specify -rpath.

Resources