Using static libraries

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have just started to create a static library in Atmel Studio 6.2. My question is if I have a whole myriad of functions, say in a gLCD library, and I only use a handful of them, do I put all those unused functions in my microcontroller?

 

Similarly, when I use stdio.h, and I only use printf, do I include all the codes in stdio even if I did not use them?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

You know in the old days libraries made a lot of sense. They were "cumbersome" to write because you had to put each function into a separate source file so you would have strcpy.c, strncpy.c, strcmp.c and so on. Each would compile to strcpy.o, strncpy.o, strcmp.o and then you would use ar to make an archive (.a file) and give this to a user along with string.h. In their code they could call strncpy() but not strcpy() or strcmp() and the linker would therefore add-in the code of strncpy.o but not of strcpy.o nor strcmp.o

 

The user didn't worry about how the "division" was made because you did that when you wrote the separate C files in the first place. Of course when you wrote malloc() your actually put both malloc() and free() in a single .c (and hence .o) component of the .a file because you knew that anyone who called malloc() must also call free() so they'd always want the code of both functions.

 

Then several things happened:

 

1) PCs got astronomically faster so the libc.a that used to take 20 minutes to compile to contain strcpy(), strncpy() and strcmp() could now all be compiled in 5 seconds so it didn't really matter if everything would be recompiled - any "make" ensures that only changed code gets rebuilt anyway

 

2) AVRs came along - different models have different CPU instructions (Tiny doesn't have MUL, only big ones have ELPM etc) so you found you needed 17 (really, that's how many there are!) different copies of libc.a and a way to ensure that code built for Tiny gets a Tiny version of libc.a while code built for large AVRs gets an ELPM'ing version of libc.a and so on.

 

3) AVRs also had different SFR layouts depending on the model. So if your library code used PORTD for the LCD then if you prebuilt it for PORTD on a mega48 it might be at a completely different I/O location than PORTD on a mega1280. So now you not only need 17 different variants for the CPU differences you need a way for different I/O locations to be taken into account

 

4) then someone turned up and said - yeah I like the LCD library but my LCD is on PORTB not PORTD. So now you not only need different CPU builds, different I/O build but also different chosen target peripheral builds

 

5) then to top it all the compiler writers added -ffunction-sections, -fdata-sections and the linker option -gc-sections. When used the first two put each function and each variable into separate named memory sections during the build then the linker option says "at the end of the link if any section had no references do not output its code or data to the final image". So this completely blew the old .c's -> .o's -> .a's thing out of the water! It's a far better system for dynamically filtering out what gets built in

 

6) finally some bright spark added a feature called LTO (link time optimization) to the linker to further refine code optimization. Not only will unused bits be discarded but in the bits that remain common bits might be pooled and so on.

 

So the bottom line is that for AVR development static libs make almost no sense whatsoever. Atmel only included it in the project creation choices of AS6 because they inherited it from Microsoft Visual Studio that allows the creation of .exe, .dll and .lib and also because avr-gcc (and avr-ld and avr-ar) still allow it to be done.

 

Far better is to make your LCD "library" as simply a collection of .c and .h with an lcd_confg.h or something. The user then puts the files in his project, edits the config to say which PORT/bits to use. Tells AS6 which CPu to build for and makes sure all of -ffunction-sections, -fdata-sections and -gc-sections are enabled (in AS6 they all are by default) and then the user just waits the 3 extra seconds (the first time they build only) for lcd.c to be converted to lcd.o and they have LCD support.

 

if you want a trip down memory lane I suppose it's an interesting intellectual exercise to explore how things used to be done with static lib<something>.a files ;-) But it's not really relevant to AVR development.

 

PS if you are playing the static lib game the user manual includes this: http://www.nongnu.org/avr-libc/u...

Last Edited: Mon. Nov 24, 2014 - 12:27 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wow. Very informative. Thank you for that.

I guess what I want is to just have a place where I could put my glcd library (and any other pieces of code that I might use repeatedly). I guess I wanted to just put it in a library, not change it anymore, and just call the functions when needed.

So maybe static libraries in studio 6 are not the answer to that?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

So maybe static libraries in studio 6 are not the answer to that?

For the reasons given above that would certainly be my opinion.

 

One nice feature AS6 has is "add as link". This allows you to add .c and .h from a common place (/avr/library/lcd/* say?) to multiple projects but instead of it physically copying lcd.c and lcd.h to the new project you created there's still only one .c and .h kept on your hard drive and all the projects just link to it. If you find a bug and edit the file in one project then when you later load some other project that also uses the file it "sees" the fix too as it's the core copy of the file that was edited.

 

This makes doing "libraries" far easier than static libc.a files (along with -ffunction-sections and -gc-sections) as you just start your new project then in addition to the newproject.c that is created you right click the project and "add existing item" then direct the file browser to the place where the core lcd.c lives but instead of just clicking [Add] - which would copy the file to the local directory - you drop the arrow to the right of the [Add] button and instead pick the "Add as link" option which ensures that it's not copied but simply that this project "points" at where the core copy is kept.

 

Then, as I say, because you build with -ffunction-sections and -gc-sections each lcd_init(), lcd_goto_xy(), lcd_print_string(), lcd_putchar() and so on is put in separate named sections when the code builds. When it links the linker will spot that lcd_init() and lcd_putchar() are called and will build them into the code but it will see that lcd_goto_xy() and lcd_print_string() were never called so their code will be dropped from the final output image. This is at least as good as static linking and has the major advantage that you only had to write a single lcd.c not lcd_init.c, lcd_putchar.c, lcd_goto_xy.c and so on.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you clawson! Appreciate the detailed replies. smiley

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was just about to post this in a separate thread:

 

Use following options for avr-gcc to get only stuff you are really using: -fdata-sections -Os -Wl,--relax,--gc-sections

 

Should be used on every firmware where space is an issue!

LibK - device driver support for flash based microcontrollers: GitHub project

http://oskit.se - join me on my quest to become a better programmer

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Should be used on every firmware where space is an issue!

This is the "Studio" forum and Atmel have the good sense to make all of those the default settings in Studio 6.2 in fact ;-)