few questions on studio library

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

I have some questions in Atmel Studio 7. 

 

If i created a library file in C (static library project) and compile the libraryfile.C, includefile.h and generated libraryfile.a in the debug folder. 

 

Q1.  When I create a new project in C Executable project which I need to use the libraryfile.C, after I import the libraryfile.a into this project, do i still need to import libraryfile.C into this project ?  

 

Q2.  When I change the includefile.h in the new project, such as Pin number, which is difference from when I compile the library, do I need to recompile the initial library with new include.h file ?   or it shall not be required as the new include file is existed in the new project.  or Shall I use Rebuild Solution ? 

 

Q3.   At what situation I shall use Clean and Rebuild Solution ?

 

Q4.  If I have a compile library in C.   When I use new project in C++, can the project still read the compile library in C ?

 

Q5. The library.a file after import shall reside in output directory or libraries directory in the Atmel Studio Solution Explorer window ?

 

 

 

 

 

 

 

     

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

WHY are you looking at using static libs? They have almost no use in the modern age of -ffunction-sections/-gc-sections/etc.

 

In the old days the whole point of static libs was to be able to distribute some code to someone else without giving them the source. It was also a way to delivery a whole bunch of functions from which the user would only take those they required. So libc.a for example might contain printf(), strcpy(), rand() and libm.a would contains sin(), cos(), tan() etc. Almost all these functions would be written one function per file so you would have a sin.c, cos,c, tan.c, When compiled those would make sin.o, cos.o, tan.o. The archive building process (for that is what a "library" really is - an "archive") would collect together sin.o, cos.o, tan.o into a libm.a (and all lib generally have the form lib<some name>.a and at usage time the user would use -l<some name> and the linker would add "lib" onto the front of the name and ".a" onto the back then try to find and open that file.

 

The user would just be given a copy of libm.a and also a copy of math.h which is a header that documents all the interfaces to things that reside in libm.a. You would then make a call to sin() (say) from your own code and when you build it the linker would also take in libm.a. It would scan through and find that it had a function called sin() in the sin.o file that was part of the archive. So it would extract and link the contents of sin.o to the code to resolve your call to sin() from main().

 

This is why every function (generally) was in a separate file. You didn't want to waste space in your final program with the contents of sin(), cos() and tan() when you were only using sin(). 

 

There is a major downside (on AVR) to doing things with static libs. There are about 300+ models of AVR and they fall into something like 18 different architecture categories. These architectures differ in that (for example) Tiny chips don't have the MUL (multiply) opcode so there version of sin/cos/tan has to be built using a library that does shifts and adds rather than MULtiplies. But for other architectures it is more efficient to build a different versions of sin/cos/tan that does use MUL. Other differences are some AVRs that use 24 bits addresses for CALL/JMP while most use 16 bit addresses. Some have all of CALL/JMP/RCALL/RJMP while smaller ones only have RJMP and RCALL. So you end up with:

:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib>dir libm.a /s /b
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\libm.a
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avr25\libm.a
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avr25\tiny-stack\libm.a
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avr3\libm.a
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avr31\libm.a
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avr35\libm.a
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avr4\libm.a
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avr5\libm.a
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avr51\libm.a
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avr6\libm.a
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avrtiny\libm.a
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avrxmega2\libm.a
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avrxmega3\libm.a
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avrxmega3\short-calls\libm.a
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avrxmega4\libm.a
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avrxmega5\libm.a
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avrxmega6\libm.a
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avrxmega7\libm.a
C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\tiny-stack\libm.a

So the same sin.c, cos.c, tan.c(and many others) have to be compiled 18 times to create all these different copies of libm.a (and also libc.a that contains printf, strcpy, rand, etc). You also have to ensure that when you choose to build for one of the 300 different AVR that the right copy of libm.a and libc.a are used. That's a complex process you are probably not even aware of but when you invoke the compiler and the linker with -mmcu=atmega328p to say which of the 300 AVR you are building for it first looks up mega328p in a very big table and finds that it is "architecture=avr5" so when something from libm.a or libc.a is called for it knows to link with the copy libm.a from the ../avr5/ subdirectory in the list above.

 

In this day and age you don't really need to use static libs like this (as you've seen it adds a lot of complication) you could just add (assuming it were available) the files sin.c, cos.c and tan.c to your project then, because you build with the -ffunction-sections option each function from these files would be placed in its own memory section. Then when you link the code with -gc-sections the linker would note that main() does refer to the sin() function in the .text.sin memory section so it would include that section (and the function) in the final binary but it would find that nothing in the code ever refers to .text.cos or .text.tan so the "gc" in -gc-sections means "garbage collect" which basically means "discard the sections that are not referenced". So the section for sin() would be add to the code but those for cos() and tan() would be discarded.

 

Of course there is a penalty in this in that sin(), cos() and tan() are built every time you build but make is "smart" - it only actually builds things once then doesn't bother again if nothing changes (and nothing will change in ancient code like sin/cos/tan)

 

To your questions:

 

Q1 No the whole point of libs is that rather than give someone header.h, file1.c, file2.c, file3.c, etc you build all the .c and archive them together into a single .a (archive) file and then just give them header.h and libfunctions.a. Think about sin()/cos()/tan(). What you actually get with the GCC compiler and it's C library is a copy of math.h and libm.a (well 18 of them!)

 

Q2 this is yet another reason why static libs don't work well for AVR. Often you DO want to configure pins, baud rates, timer speeds and so on. If you are given a .c/.h combination it's easy to edit some config values then just build the .c so it takes on board the new settings. If all you get is .a/.h then that .a was built weeks/moths/years ago by someone else and they didn't know at the time what baud rate or timer speed you might want to use. To overcome that they may provide a prebuilt peripheral_config() function or similar that you call to tell it which pins are being used, the baud rate, the timer requirements but this means that now the other functions cannot be built efficiently with those things "burned in" but have to be written in  such a way that they take into account the dynamic configuration - which makes the code far less efficient. This is another GoodReason(tm) not to use static libs in 2022 when using AVRs

 

Q3 Clean/rebuild have no effect on library code - it was already built (to create the .a file) week/months/years ago by someone else. All that clean/build achieves is to get your own code rebuilt then it will relink with exactly the sme prebuilt stuff in the .a

 

Q4 Just add .c files to the project "as is" but remember the need for using extern "C" at the C/C++ boundaries. Alternatively (possibly better) change the .c file names to be .cpp and they wil be built as C++ anyway - it's a better sytax/type checking system than C but it knows the entire C language (as a subset of C+++

 

Q5 hope you've got the message but simply don't consider static libs for AVR !!

Last Edited: Thu. Apr 7, 2022 - 10:36 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

 

Thank you Cliff for such as details explanation and correction on my wrong ways for doing. Now I understand a little better on using the library. Appreciate very much.yes