world leader in high performance signal processing
Trace: » creating_libraries

Creating Libraries

When writing your own libraries, you need to know what format you wish to support. On Blackfin, we support a few different types of libraries:

  • FLAT static
  • FLAT shared
  • FDPIC ELF static
  • FDPIC ELF shared

The FLAT and FDPIC formats are incompatible; so everything must be built for FLAT or everything must be built for FDPIC ELF, there is no in-between.

Not sure which format you wish to use? Check out our executable file formats page for the gory details.

In this document, we'll cover how to build each type of library below using a fictitious library called libbar. This library has the following features:

  • two source files: bar.c and api.c
  • test code: test.c

Before you jump in, you should be comfortable with make. If you are not, please read our make guide.

All set? Lets start cranking out some libraries!

FLAT (static)

This is by far the easiest format to deal with. To create a FLAT static library, simply compile all the objects and run bfin-uclinux-ar to create the archive.

bfin-uclinux-gcc -c bar.c -o bar.o
bfin-uclinux-gcc -c api.c -o api.o
bfin-uclinux-ar rcu libbar.a bar.o api.o

Then to create an application that links against it, just use -lbar (and -Lpath if the library is in a non-standard location).

bfin-uclinux-gcc test.c -o test -L. -lbar -Wl,-elf2flt

The makefile for this format is:

CROSS  = bfin-uclinux-
AR     = $(CROSS)ar
CC     = $(CROSS)gcc
RANLIB = $(CROSS)ranlib

CFLAGS       += -Wall
LDFLAGS_test  = $(LDFLAGS) -Wl,-elf2flt
LDLIBS_test   = $(LDLIBS) -L. -lbar

LIBS = libbar.a
BINS = test

all: $(LIBS) $(BINS)

libbar.a: bar.o api.o
	$(AR) rcu $@ $^
	$(RANLIB) $@

test: test.o
	$(CC) $(CFLAGS) -o $@ $^ $(LDLIBS_$@) $(LDFLAGS_$@)

clean:
	rm -f *.o *.gdb $(BINS) $(LIBS)

.PHONY: all clean

Note that the call to bfin-uclinux-ranlib is not required as it just creates an index to help speed up the linking process.

And a sample run with the above makefile:

$ make
bfin-uclinux-gcc -Wall   -c -o bar.o bar.c
bfin-uclinux-gcc -Wall   -c -o api.o api.c
bfin-uclinux-ar rcu libbar.a bar.o api.o
bfin-uclinux-ranlib libbar.a
bfin-uclinux-gcc -Wall   -c -o test.o test.c
bfin-uclinux-gcc -Wall -o test test.o  -L. -lbar  -Wl,-elf2flt

Remember that since you linked statically with the libbar library, you need only copy the final executable to the target (in this case, the test FLAT binary).

FLAT (shared)

Building FLAT shared libraries can be a bit of a hassle. Each FLAT shared library needs to have a unique ID associated with it, and making sure each ID is unique is a task left up to the end user (where the end user is *you*). So if you're going to be utilizing a lot of FLAT shared libraries, make sure to plan ahead. In this example, we will be using a lib ID of 3.

Some things to remember about the IDs:

  • The value of 0 is taken up by the application itself
  • ID 1 is reserved by the C library by default
  • ID 2 is reserved by the pthread library by default
  • The kernel imposes a max ID limit of 4 (see the MAX_SHARED_LIBS define in linux-2.6.x/include/linux/flat.h if you wish to change this)
  • The toolchain imposes a max ID limit of 255

To generate the FLAT shared library, we need to build all the objects with the right gcc flags, and then bring it all together with some mojo.

To enable support for shared libs, you must enable in the menuconfig (or xconfig, or config) the following:

  • In Kernel configuration say yes to Kernel support for flat binaries and Enable shared FLAT support in Executable file formats menu.
  • In Vendor/User Settings configuration select (Shared-FLAT) Binary format in the Blackfin build Options menu.

We have basically 2 possibilities for our executable:

  • Executable linked dynamically to libc and statically to mylib (or libmylib, our own library we created)
  • Executable linked dynamically to both libc and mylib

Executable linked dynamically to libc

This process is quite simple:

  • Create static library (libmylib.a)
  • Create the executable using -lmylib and some additional options to link it against lib1.so.

Here is the corresponding makefile:

#
# A sample makefile to create FLAT executable with uclibc shared.
# Note: mylib is a sample library composed by mylib.h, mylib_lines.c, mylib_rectangle.c.
#      testlib.c is a sample application that uses mylib (libmylib.a).
#

CROSS  = bfin-uclinux-
AR    = $(CROSS)ar
CC    = $(CROSS)gcc
RANLIB = $(CROSS)ranlib
OBJCOPY = $(CROSS)objcopy

CFLAGS += -Wall -D__uClinux__ -DEMBED -fno-builtin -fpic -mid-shared-library
LDFLAGS_testlib_sharedlibc = -mid-shared-library

LIBS = libmylib.a
BINS = testlib_sharedlibc

all: $(LIBS) $(BINS)

mylib_lines.o: mylib_lines.c mylib.h
mylib_rectangle.o: mylib_rectangle.c mylib.h
testlib.o: testlib.c mylib.h

#
# Create static library libmylib.a
#
libmylib.a: mylib_lines.o mylib_rectangle.o
	$(AR) rcu $@ $^
	$(RANLIB) $@

#
# Create executable linked dynamically to uclibc and statically to libmylib
# Note: testlib.o must be the first file to link. This won't link if '-lmylib' is first :-|
#
testlib_sharedlibc: testlib.o libmylib.a
	$(CC) $(LDFLAGS_$@) -o $@ testlib.o -L. -lmylib

clean:
	rm -f *.o *.gdb *.so $(BINS) $(LIBS)

.PHONY: all clean

Executable linked dynamically to libc and mylib

Using this process can give extremely small executables. I got the main program smaller than 400B!

This process is as following for Blackfin 2009R1 toolchain or later:

  • Create static library (libmylib.a, same as before)
  • Convert libmylib.a to FLAT library libmylib_so, an associated ELF file called libmylib_so.gdb will be created.
  • Copy libmylib_so to lib3.so
  • Create the executable

For the earilier versions of the Blackfin toolchain, please refert to the example at uCdot: http://www.ucdot.org/article.pl?sid=03/11/25/1126257&mode=thread

Here is the Makefile:

CROSS  = bfin-uclinux-
AR     = $(CROSS)ar
CC     = $(CROSS)gcc
RANLIB = $(CROSS)ranlib
OBJCOPY = $(CROSS)objcopy

CFLAGS += -Wall -D__uClinux__ -DEMBED -fno-builtin -fpic -mid-shared-library
LDFLAGS = -mid-shared-library
LDFLAGS_testlib_sharedall  = $(LDFLAGS)

SHARED_LIB_ID = 3
LIBS = libmylib.a libmylib_so lib$(SHARED_LIB_ID).so
BINS = testlib_sharedall

all: $(LIBS) $(BINS)

mylib_lines.o: mylib_lines.c mylib.h
mylib_rectangle.o: mylib_rectangle.c mylib.h
testlib.o: testlib.c mylib.h
lib$(SHARED_LIB_ID).so: libmylib_so

#
# Create static library libmylib.a
#
libmylib.a: mylib_lines.o mylib_rectangle.o
        $(AR) rcu $@ $^
        $(RANLIB) $@

#
# Create flat-shared library libmylib_so.
#  Note: you cannot use dot in the library filename! (libmylib.so won't work)
# This library creation have a bit big commands. Anyway you'll have
#  usually just 1 or 2 shared libs to create in real life.
#
libmylib_so: libmylib.a
        $(CC) $(CFLAGS) \
          -o $@ \
          -mshared-library-id=$(SHARED_LIB_ID) \
          -Wl,--whole-archive,libmylib.a -Wl,--no-whole-archive
        cp $@ lib$(SHARED_LIB_ID).so

#
# Create the executable with everything flat-shared
#
testlib_sharedall: testlib.o libmylib_so
        $(CC) $(CFLAGS) $(LDFLAGS_$@) \
          -o $@ \
          testlib.o \
          -Wl,-R,libmylib_so.gdb

clean:
        rm -f *.o *.gdb *.so $(BINS) $(LIBS)

.PHONY: all clean

You need to copy lib3.so to /lib/ directory on your target board before you can run your application.

FDPIC ELF (static)

Building an FDPIC ELF static library is almost as easy as a FLAT static library. We just need to use a different toolchain.

bfin-linux-uclibc-gcc -c bar.c -o bar.o
bfin-linux-uclibc-gcc -c api.c -o api.o
bfin-linux-uclibc-ar rcu libbar.a bar.o api.o

Then to create an application that links against it, just use -lbar (and -Lpath if the library is in a non-standard location).

bfin-linux-uclibc-gcc test.c -o test -L. -lbar

The makefile for this format is:

CROSS  = bfin-linux-uclibc-
AR     = $(CROSS)ar
CC     = $(CROSS)gcc
RANLIB = $(CROSS)ranlib

CFLAGS       += -Wall
LDLIBS_test   = $(LDLIBS) -L. -lbar

LIBS = libbar.a
BINS = test

all: $(LIBS) $(BINS)

libbar.a: bar.o api.o
	$(AR) rcu $@ $^
	$(RANLIB) $@

test: test.o
	$(CC) $(CFLAGS) -o $@ $^ $(LDLIBS_$@) $(LDFLAGS_$@)

clean:
	rm -f *.o $(BINS) $(LIBS)

.PHONY: all clean

Note that the call to bfin-linux-uclibc-ranlib is not required as it just creates an index to help speed up the linking process.

And a sample run with the above makefile:

$ make
bfin-linux-uclibc-gcc -Wall    -c -o bar.o bar.c
bfin-linux-uclibc-gcc -Wall    -c -o api.o api.c
bfin-linux-uclibc-ar rcu libbar.a bar.o api.o
bfin-linux-uclibc-ranlib libbar.a
bfin-linux-uclibc-gcc -Wall    -c -o test.o test.c
bfin-linux-uclibc-gcc -Wall -o test test.o  -L. -lbar

Remember that since you linked statically with the libbar library, you need only copy the final executable to the target (in this case, the test FDPIC ELF binary).

FDPIC ELF (shared)

Working with FDPIC ELF shared libraries is much easier than FLAT shared libraries. In fact, it's almost like working with FDPIC ELF static libraries.

For this format, we just need to use the flags -shared -Wl,-soname,libbar.so during link.

bfin-linux-uclibc-gcc -c bar.c -o bar.o
bfin-linux-uclibc-gcc -c api.c -o api.o
bfin-linux-uclibc-gcc -shared -Wl,-soname,libbar.so -o libbar.so bar.o api.o

Then to create an application that links against it, just use -lbar (and -Lpath if the library is in a non-standard location).

bfin-linux-uclibc-gcc test.c -o test -L. -lbar

The makefile for this format is:

CROSS  = bfin-linux-uclibc-
CC     = $(CROSS)gcc

CFLAGS            += -Wall
LDFLAGS_libbar.so  = -shared -Wl,-soname,libbar.so
LDLIBS_test        = $(LDLIBS) -L. -lbar

LIBS = libbar.so
BINS = test

all: $(LIBS) $(BINS)

libbar.so: bar.o api.o
	$(CC) $(CFLAGS) -o $@ $^ $(LDLIBS_$@) $(LDFLAGS_$@)

test: test.o
	$(CC) $(CFLAGS) -o $@ $^ $(LDLIBS_$@) $(LDFLAGS_$@)

clean:
	rm -f *.o $(BINS) $(LIBS)

.PHONY: all clean

And a sample run with the above makefile:

$ make
bfin-linux-uclibc-gcc -Wall    -c -o bar.o bar.c
bfin-linux-uclibc-gcc -Wall    -c -o api.o api.c
bfin-linux-uclibc-gcc -Wall  -o libbar.so bar.o api.o  -shared -Wl,-soname,libbar.so
bfin-linux-uclibc-gcc -Wall    -c -o test.o test.c
bfin-linux-uclibc-gcc -Wall  -o test test.o  -L. -lbar

Remember that since you linked dynamically with the libbar library, you need to copy both the libbar.so library as well as the final executable to the target (in this case, the test FDPIC ELF binary). Also make sure you place the library in a system library path like /lib/.

Summary

The things to keep in mind:

  • build FLAT binaries with bfin-uclinux-gcc
  • link FLAT binaries with -Wl,-elf2flt
  • build FDPIC ELF objects with bfin-linux-uclibc-gcc
  • link FDPIC ELF shared libraries with -shared
  • dynamic libraries must be copied to the board
  • shared FLAT libraries requires you to allocate the unique IDs