Creating an Archive/Library File

A Dr. Taylor Tutorial

An archive or library file is a file that contains one or more object files. Its name must begin with lib and it must have .a for its extention. Library files provide a convenient way to distribute pre-compiled code. In addition to the .a file, header files with prototypes for all of the "public" functions must be provided as well.

The C standard library is distributed as a set of header and library files. Prior to writing your own LCD library, you made use of a pre-compiled library of functions for using the LCD.

Command Line Technique

A library file consists of a collection of one or more object files. The command line program to create a library file is avr-ar and is found in the WinAVR/bin directory. Running avr-ar from the command line looks something like this:

avr-ar -rs libSOMETHING.a FIRST.o [SECOND.o ...]

where libSOMETHING.a is the name of the library file you wish to create and FIRST.o and beyond are the name(s) of the object files to be placed in the library file.

A number of command options are available. Here we have used two:

You can see a list of all of the command options by running avr-ar without any parameters.

Suppose we wish to make a library file for our own LCD library that we wrote. The LCD implementation consists of three files:

We can create a library file for our LCD library and then distribute only the .a file and the public header file (lcd.h). Creating the library file is as simple as:

avr-ar -rs libLCD.a lcd.o

Makefile Technique

AVR Studio provides its own set of rules for how to compile a project. When selecting Rebuild All from the Build menu in AVR Studio the build process begins. This process includes compiling each .c file in the project as well as linking the files together to produce a .hex file and potentially creating other files like a .lss file.

The Project -> Configuration Options menu option allows customization of the build process. If we wish to create a library file as part of the the build process, we can specify that by providing a custom makefile. The makefile must contain the instructions for how to create the library file. The addition to the makefile might look something like this:

## Archive into a library file (.a)
$(TARGET): $(OBJECTS)
    avr-ar -rs $(TARGET) $(OBJECTS)

We typically start by asking AVR Studio to generate a makefile that matches its current build process. This is accomplished by Build -> Export Makefile. This file may look something like this:

###############################################################################
# Makefile for the project lcd
###############################################################################

## General Flags
PROJECT = lcd
MCU = atmega32
TARGET = lcd.elf
CC = avr-gcc.exe

## Options common to compile, link and assembly rules
COMMON = -mmcu=$(MCU)

## Compile options common for all C compilation units.
CFLAGS = $(COMMON)
CFLAGS += -Wall -gdwarf-2 -std=gnu99 -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d 

## Assembly specific flags
ASMFLAGS = $(COMMON)
ASMFLAGS += $(CFLAGS)
ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2

## Linker flags
LDFLAGS = $(COMMON)
LDFLAGS +=  -Wl,-Map=lcd.map


## Intel Hex file production flags
HEX_FLASH_FLAGS = -R .eeprom

HEX_EEPROM_FLAGS = -j .eeprom
HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load"
HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings


## Objects that must be built in order to link
OBJECTS = lcd.o 

## Objects explicitly added by the user
LINKONLYOBJECTS = 

## Build
all: $(TARGET) lcd.hex lcd.eep lcd.lss size

## Compile
lcd.o: ../lcd.c
    $(CC) $(INCLUDES) $(CFLAGS) -c  $<

##Link
$(TARGET): $(OBJECTS)
    $(CC) $(LDFLAGS) $(OBJECTS) $(LINKONLYOBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET)

%.hex: $(TARGET)
    avr-objcopy -O ihex $(HEX_FLASH_FLAGS)  $< $@

%.eep: $(TARGET)
    -avr-objcopy $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0

%.lss: $(TARGET)
    avr-objdump -h -S $< > $@

size: ${TARGET}
    @echo
    @avr-size -C --mcu=${MCU} ${TARGET}

## Clean target
.PHONY: clean
clean:
    -rm -rf $(OBJECTS) lcd.elf dep/* lcd.hex lcd.eep lcd.lss lcd.map


## Other dependencies
-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*)

This file can then be modified to build a library file instead of a .hex file. The modified file may look something like this:

###############################################################################
# Makefile for the project lcd (modified to generate .a file)
###############################################################################

## General Flags
PROJECT = lcd
MCU = atmega32
TARGET = libLCD.a
CC = avr-gcc.exe

## Options common to compile, link and assembly rules
COMMON = -mmcu=$(MCU)

## Compile options common for all C compilation units.
CFLAGS = $(COMMON)
CFLAGS += -Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d 

## Assembly specific flags
ASMFLAGS = $(COMMON)
ASMFLAGS += $(CFLAGS)
ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2

## Objects that must be built in order to link
OBJECTS = lcd.o 

## Build
all: $(TARGET)

## Compile
lcd.o: lcd.c
    $(CC) $(INCLUDES) $(CFLAGS) -c  $<

## Archive into a library file (.a)
$(TARGET): $(OBJECTS)
    avr-ar -rs $(TARGET) $(OBJECTS)

## Clean target
.PHONY: clean
clean:
    -rm -rf $(OBJECTS) $(TARGET) dep/*

There are a number of changes between the files:

Using a Library File

Once created, the library file can be used in any other project without needing to add the .c source files to that project. This allows the project to use different compiler settings (e.g., a different optimization level) than were used in compiling the library code and eliminates the need to recompile the library source code in every project that uses the library code.

The library may now be used in other projects as long as the appropriate header files and the .a file are available. If we want to use the libLCD.a library created earlier, we need to let the project know where the libLCD.a file is located. To do this, we must select Project -> Project Configuration and then select the Libraries option from the list on the left. Add the appropriate search path to the list on the upper right pane and then select libLCD.a from the list of Available Link Objects and select Add Library —> in order to tell the compiler to include the libLCD.a file when running the linker for this project. The following figure illustrates the result of these steps:

Adding libLCD.a to Project Configuration

The lcd.h file must be included in any .c that uses functions from the library.

Tutorials for Other Courses

Additional Links

Site Mirror

This is a mirror to be used when http://myweb.msoe.edu/taylor/, (EDU instead of US) is not available.