Custom static library not included in link within main project.

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

All:

 

Using the latest AS 7.0.634, I've successfully created a small static library; it's components show up as the requisite .d and .o output files, and the library as a .a file. Moreover, they all are about the right size, so I have good confidence that they really are what I expect.

 

I created another project (a C-language executable) in a new solution; from within that solution, I imported/inserted my (existing) static library project. So, the solution now contains the static lib project and the C executable project. I checked the executable project's properties: Toolchain->AVR/GNU Linker->Libraries: this lists my static library, along with libm. So far, so good.

 

I've keep getting an "undefined reference to" error regarding (the first test) function with which I'm trying to link from within the main executable to the static library. Looking at the output window, I began to notice that while my C source files from the executable project were compiled without error and their .o output files included in the link step, the link list did *NOT* list the static library file from my static library project.

 

I used to work exclusively (many years ago in some pretty complicated builds) with makefiles, so I decided to take a look at it. I found that its LIB_DEP symbol *DOES* list my static library, but in the link command

    @echo Building target: $@
    @echo Invoking: AVR8/GNU Linker : 4.9.2
    $(QUOTE)C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin\avr-g++.exe$(QUOTE) -o$(OUTPUT_FILE_PATH_AS_ARGS) $(OBJS_AS_ARGS) $(USER_OBJS) $(LIBS) -Wl,-Map="Startup.map" [remainder elided...]

 

the $(LIBS) symbol's contents are completely missing from the output in the output window. Examining the makefile more closely, I see where $(LIBS) is cleared:

        LIBS := 

 

but, it is never touched afterward. So, the linker is doing exactly what the makefile told it: namely, to exclude my static lib. Also, the $(LIB_DEPS) symbol is a dependency in the linker rule.

 

The output windows shows:

        Invoking: AVR8/GNU Linker : 4.9.2
        "C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin\avr-g++.exe" -o Startup.elf  Journ1.o main.o   -Wl,-Map="Startup.map" -Wl,--start-group -Wl,-lm -Wl,-lMega2561  -Wl,--end-group -Wl,-L"C:\Users\David\Documents\Atmel Studio\7.0\Production0\SH\Mega2561\Debug"  -Wl,--gc-sections -mrelax -mmcu=atmega2561 -B "C:\Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.0.90\gcc\dev\atmega2561"  
        main.o: In function `main':

 

 

Notice the missing library ref (before -Wl in the highlited section).

 

I know, of course, that you're not supposed to edit the makefile, so I'm not even considering that. However, I haven't found anywhere in the properties for either project that would appear to have any bearing this - other than the Toolchain->AVR/GNU Linker->Libraries I mentioned above (which appears correct).

 

is this a bug in the new version, or have I missed something really simple?

 

Also, I tried the two methods of adding a static library to my project that I know about:

1. Add a Project Library from the Add Library command.

2. Add a Browse Library from the Add Library command.

 

Neither work; both report the same "undefined reference" error.

 

Thanks much!

Dave

 

 

The SiliconHacker  Plano, TX  www.siliconhacker.com

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

This works for me:

 

- For the main() project, open the project Properties

- Toolchain

- AVR/GNU Linker

- Libraries

- Add the name of the library file (w/o extension) in the Libraries list box at the top

- Add the path to the library in the Library search path list box at the bottom

 

(Atmel Studio 7.0.582)

 

The possible downside to this is that Studio will not recognize the dependency between the projects so you will have to rebuild the library by hand when you change anything in it.

 

I'm getting all sorts of ugly crashes when I try to add a library in the Solution Explorer. I will not investigate that further at the moment.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Last Edited: Tue. Feb 16, 2016 - 06:16 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Johan:

 

Thanks much for the very prompt reply. As it worked out, I had already tried adding the path yesterday (but tried again just now - and as I mentioned in the original post, my static lib already appeared in the top window). The resulting makefile is identical and still doesn't work; the $(LIBS) symbol is still empty as shown in the output window. It is curious that the makefile didn't change when adding the path. Perhaps this is a consequence of either this bug (and this certainly looks at the moment like a genuine bug) or the fact that the library is added with a complete path. (The "relative path" checkbox appears to affect only the display of the path in the Libraries properties windows.)

 

Regarding dependencies. From the Solution Properties, I had already ensured that the main executable depends on the static lib. Moreover, the output windows shows clearly that the solution honors this and causes the lib to be rebuilt when needed. So, the issue remains that while the static lib is built as expected, it simply is left out of the build commands when running the link for the executable.

 

Until a solution is found, I may actually have to create and use an external makefile (something I really don't want to do...) as a workaround. Later this morning, I'll try creating a new static lib and executable solution just to confirm. See if this is a persistent issue or just some quirk in this solution.

 

While experimenting, I did find that whether the static lib is added as a library or a project doesn't matter: both result in the same commands generated in the makefile. (I know that this isn't part of the solution, but for anyone else researching makefile and/or static lib link issues, this factoid may be useful.)

 

Again, thanks.

Dave

 

 

The SiliconHacker  Plano, TX  www.siliconhacker.com

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

Phoenix710 wrote:
my static lib already appeared in the top window

I believe the operations in the Solution Explorer obfuscates the stuff in the project properties. Remove any lib references in the solution Explorer, and only do the add (of libname and path) in the project Properties.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Can you zip and post the project or is it proprietary?

 

Meanwhile I'll try a quick AS7 experiment to first create a lib and then create a client to use the lib code. Assuming it works I'll post the result here...

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

clawson wrote:
Meanwhile I'll try a quick AS7 experiment to first create a lib and then create a client to use the lib code.

The more the merrier! :-)

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

OK so here it is... (attached).

 

It worked like a charm and exactly as I expected it to.

 

I started AS7 and created a new solution/project to create a "C static library". It called it "GccLibrary1". It created a file with myfunc() in it. So I just added some code to write PORTB, taking it as an input parameter. I built this. It created libGccLibrary1.a as expected.

 

Next I went to the File menu and used File-Add-New Project... and selected a "C executable". It created "GccApplication1". I just put in a declaration for the myfunc() library function then added code to main() to invoke it passing an incrementing counter variable.

 

I then built GccApplication1 and needless to say it gave me an "undefined ref" error to myfunc().

 

So then in the solution explorer in the Libraries section for GccApplication1 I right clicked Libraries and selected "Add Library" which brought me to here:

 

At the left I clicked on "Project Libraries" so it looked like:

As you can see I ticked "GccLibrary1". Now I rebuilt the solution and it built without error - the working result is in the attached.

 

This was using AS7 7.0.634. AFAICS there is no fault here.

Attachment(s): 

Last Edited: Tue. Feb 16, 2016 - 11:17 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

[Answering both replies...]

 

Johan: if I understand your reply, the static lib is referenced only in the executable's project property. Are you suggesting that I remove the static lib project from the Solution, then simply add the static lib (as it is now) to the (single) executable project in the solution? I think I already tried that, but am happy to try that again.

 

clawson: No, it isn't proprietary (and in fact will be open source to support my product release), and yes, I can do so a bit later this morning. (I couldn't sleep last night, so was up VERY early to check this post. I technically haven't started my "official" day yet. I know that hard-core developers can know what I'm talking about... smiley  It's great having dedicated developers in a later time zone.) I'll try to do that as early as possible so that you can review it before the end of your day; it will be close. If I see your solution first, thanks much!

 

Thanks to you both,

Dave

 

The SiliconHacker  Plano, TX  www.siliconhacker.com

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

[clawson: our replies crossed...]

 

That is exactly what I did - added the static library at the project level using the same UI as you used. Will be reviewing your ZIP file soon.

 

Thanks much for the effort. There must be a reason for this issue somewhere, because it clearly worked for you.

Dave

The SiliconHacker  Plano, TX  www.siliconhacker.com

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

clawson: I couldn't wait; I downloaded and looked at the makefile - it's identical to mine ( $(LIBS) is not touched after being cleared).

 

I looked at your library and executable source, and the build output map. The lss file shows the call to myfunc ("call 0x92") and the map shows

 

.text.myfunc   0x00000092        0x4 c:\users\cliff\Documents\Atmel Studio\7.0\GccLibrary1\GccLibrary1\Debug\libGccLibrary1.a(library.o)
                0x00000092                myfunc
                0x00000096                . = ALIGN (0x2)

 

 

which appears to be properly recognizing the lib function myfunc() from library.o. Your forward reference to myfunc takes the place of a "formal" header. Could you copy/paste the output contents after a solution rebuild? I'd really like to see what the makefile inserted for $(LIBS).

 

Also, I'll be installing and building your solution a little later to compare. Maybe it's necessary to actually create the static lib project first, then from the same solution create the executable project (rather than developing them separately)?

 

Thanks!

Dave

The SiliconHacker  Plano, TX  www.siliconhacker.com

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

I don't know if 'I can express this in any other, clearer, way..

 

1. I am suggesting that you set the library name, and the library search path, in the project Properties. Mark the project, then in the Project manu select the PRoperties item. Then, in the tree view Toolchain, AVR/GNU Linker, Libraries to get to the dialogue pane where you can add libraries by name, and library search paths.

 

2. I am suggesting you remove any reference from the executable project  to the library project in the Solution Explorer.

 

Anyway, further experiments seems to indicate that the outcome is stochastic.. See below.


 

@clawson: I did what you did. This was on a solution where I already have other projects, but all of them "unloaded" so they should not interfere. What I end up with is this lovely crash:

 

------ Rebuild All started: Project: GccLibrary1, Configuration: Debug AVR ------
Build started.
Project "GccLibrary1.cproj" (Clean target(s)):
Target "Clean" in file "C:\Program Files (x86)\Atmel\Studio\7.0\Vs\Compiler.targets" from project "C:\Users\johan\Documents\Atmel Studio\7.0\avrfreaks\GccLibrary1\GccLibrary1.cproj" (entry point):
    Task "RunCompilerTask"
        Shell Utils Path C:\Program Files (x86)\Atmel\Studio\7.0\shellUtils
        C:\Program Files (x86)\Atmel\Studio\7.0\shellUtils\make.exe clean
        rm -rf  library.o   
        rm -rf  library.d   
        rm -rf "libGccLibrary1.elf" "libGccLibrary1.a" "libGccLibrary1.hex" "libGccLibrary1.lss" "libGccLibrary1.eep" "libGccLibrary1.map" "libGccLibrary1.srec" "libGccLibrary1.usersignatures"
    Done executing task "RunCompilerTask".
Done building target "Clean" in project "GccLibrary1.cproj".
Done building project "GccLibrary1.cproj".

Build succeeded.

 

------ Rebuild All started: Project: GccLibrary1, Configuration: Debug AVR ------
Build started.
Project "GccLibrary1.cproj" (default targets):
Target "PreBuildEvent" skipped, due to false condition; ('$(PreBuildEvent)'!='') was evaluated as (''!='').
Target "CoreBuild" in file "C:\Program Files (x86)\Atmel\Studio\7.0\Vs\Compiler.targets" from project "C:\Users\johan\Documents\Atmel Studio\7.0\avrfreaks\GccLibrary1\GccLibrary1.cproj" (target "Build" depends on it):
    Task "RunCompilerTask"
        Shell Utils Path C:\Program Files (x86)\Atmel\Studio\7.0\shellUtils
        C:\Program Files (x86)\Atmel\Studio\7.0\shellUtils\make.exe all
        Building file: .././library.c
        Invoking: AVR/GNU C Compiler : 4.9.2
        "C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin\avr-gcc.exe"  -x c -funsigned-char -funsigned-bitfields -DDEBUG  -I"C:\Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.0.90\include"  -O1 -ffunction-sections -fdata-sections -fpack-struct -fshort-enums -g2 -Wall -mmcu=atmega88 -B "C:\Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.0.90\gcc\dev\atmega88" -c -std=gnu99 -MD -MP -MF "library.d" -MT"library.d" -MT"library.o"   -o "library.o" ".././library.c"
        Finished building: .././library.c
        Building target: libGccLibrary1.a
        Invoking: AVR/GNU Archiver : 4.9.2
        "C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin\avr-ar.exe" -r  -o libGccLibrary1.a  library.o   
        C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin\avr-ar.exe: creating libGccLibrary1.a
        Finished building target: libGccLibrary1.a
    Done executing task "RunCompilerTask".
    Task "RunOutputFileVerifyTask"
    Done executing task "RunOutputFileVerifyTask".
Done building target "CoreBuild" in project "GccLibrary1.cproj".
Target "PostBuildEvent" skipped, due to false condition; ('$(PostBuildEvent)' != '') was evaluated as ('' != '').
Target "Build" in file "C:\Program Files (x86)\Atmel\Studio\7.0\Vs\Avr.common.targets" from project "C:\Users\johan\Documents\Atmel Studio\7.0\avrfreaks\GccLibrary1\GccLibrary1.cproj" (entry point):
Done building target "Build" in project "GccLibrary1.cproj".
Done building project "GccLibrary1.cproj".

Build succeeded.

 

------ Rebuild All started: Project: avrfreaks, Configuration: Debug AVR ------
Build started.
Project "avrfreaks.cproj" (Clean target(s)):
Target "Clean" in file "C:\Program Files (x86)\Atmel\Studio\7.0\Vs\Compiler.targets" from project "C:\Users\johan\Documents\Atmel Studio\7.0\avrfreaks\avrfreaks\avrfreaks.cproj" (entry point):
    Task "RunCompilerTask"
        Shell Utils Path C:\Program Files (x86)\Atmel\Studio\7.0\shellUtils
C:\Program Files (x86)\Atmel\Studio\7.0\Vs\Compiler.targets(15,5): error: MakeFileGenFailureException captured - Could not construct the make file properties. Not implemented (Exception from HRESULT: 0x80004001 (E_NOTIMPL))
avrfreaks(0,0): error: Error in generating MakeFile
    Done executing task "RunCompilerTask" -- FAILED.
Done building target "Clean" in project "avrfreaks.cproj" -- FAILED.
Done building project "avrfreaks.cproj" -- FAILED.

Build FAILED.

 

------ Rebuild All started: Project: avrfreaks, Configuration: Debug AVR ------
Build started.
Project "avrfreaks.cproj" (default targets):
Target "PreBuildEvent" skipped, due to false condition; ('$(PreBuildEvent)'!='') was evaluated as (''!='').
Target "CoreBuild" in file "C:\Program Files (x86)\Atmel\Studio\7.0\Vs\Compiler.targets" from project "C:\Users\johan\Documents\Atmel Studio\7.0\avrfreaks\avrfreaks\avrfreaks.cproj" (target "Build" depends on it):
    Task "RunCompilerTask"
        Shell Utils Path C:\Program Files (x86)\Atmel\Studio\7.0\shellUtils
C:\Program Files (x86)\Atmel\Studio\7.0\Vs\Compiler.targets(5,5): error: MakeFileGenFailureException captured - Could not construct the make file properties. Not implemented (Exception from HRESULT: 0x80004001 (E_NOTIMPL))
avrfreaks(0,0): error: Error in generating MakeFile
    Done executing task "RunCompilerTask" -- FAILED.
Done building target "CoreBuild" in project "avrfreaks.cproj" -- FAILED.
Done building project "avrfreaks.cproj" -- FAILED.

Build FAILED.
========== Rebuild All: 1 succeeded, 1 failed, 0 skipped ==========

 

As another test, I started with a fresh and empty solution. In that case it worked like a charm..

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Last Edited: Tue. Feb 16, 2016 - 12:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Phoenix710 wrote:
which appears to be properly recognizing the lib function myfunc() from library.o. Your forward reference to myfunc takes the place of a "formal" header. Could you copy/paste the output contents after a solution rebuild? I'd really like to see what the makefile inserted for $(LIBS).

Not near that laptop right now but I'll do that in while - though I'd hope that if you take the contents of my .zip you should be able to build it with success anyway.

 

To be honest I don't think the order you created the projects within the solution would matter though clearly for the thing to be listed under "Project libraries" in that library selecting dialog the app and the library do both need to be within the one solution together.

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

Note that you can specify project dependencies if you need to have one project built before another . Right click a project->build dependencies->project dependencies

:: Morten

 

(yes, I work for Atmel, yes, I do this in my spare time, now stop sending PMs)

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

Aside:

clawson wrote:
the app and the library do both need to be within the one solution together

Just to avoid any confusion (and at the same time surely adding some): Please note that this does not imply that they need to be in the same filesystem directory tree. A solution is a container for "references to projects", nothing else.

 

A solution can (of-course) reference several projects. But it's also the other way around - a project can be referenced by several solutions. Think of it as a "workspace" or "work area" (terms used by some other IDEs).

 

A solution can reference projects anywhere in the file system.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Some very interesting results from further experiments (inspired of what I wrote above): Adding the projects (lib and executable) that worked in a fresh solution to my solution with the failing projects the working projects also failed. (Did that make sense to you? - it was hard to formulate...).

 

So, my crash seems to be related to the specific solution, or possibly to the other projects.

 

To summarise: Two projects, one executable and one library. Two different Solutions, each referencing the two projects. Right clicking the executable project in one of the solutions and select Rebuild works. Doing the sam in the other solution generates the crash as shown above.

 

If anyone at Atmel wants this setup to test I can tidy it up and let you have it. Let me know, Morten.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

By "be within one solution" I simply meant that for the library to be listed as a selection choice under the "libraries" section of the app then they both needed to be component parts of the solution. I could have built them entirely separately and on different PCs and then just introduced libGCCLibrary.a as an import to the link of the app in its own solution. But it would not have shown up in that dialog I posed the picture of above in that case.

 

BTW here is a philosophical question: in the case of AVR code what IS the point of a static library anyway? Libraries are for generic code like strcpy() or printf(). Most of what you do for AVRs is very heavily bound to the hardware of a specific model of AVR. Even if you take your UCSR0As and TWAR's out of the mix then even in the case of printf()/strcpy() the AVR compiler requires 17 pre-built versions to cater for the 17 different AVR "architectures" and it is frankly a nightmare for the maintainers. Life is much simpler if you simply provide the source and let the user build it for their architecture and, in the case of UCSR0A/TWAR/etc have compile time switches for things like "if mega16/mega32 use UCSRA but for mega48/88/164/324 use UCSR0A instead...". If you wanted to achieve that in a .a file you would need every variant built in and a run-time selection of which one to use.

 

EDIT: having just read #15 I think I need to try further experiments. (BTW if all else fails just go to the "Miscellanaeous" section of the Linker configuration and enter something like "-Wl,-lGccLibrary1 -Wl,-L\path\to\that\lib" as that is surely BOUND to work isn't it?)

Last Edited: Tue. Feb 16, 2016 - 01:02 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

[This is a combined response to #11 thru #16 posts.]

 

As this issue is very important to my fledgling business, and based on the number and scope of the responses thus far, I decided - to the best of my ability - to figure out what this issue is and either how to solve it or, worst case, work around it.

 

I believe that I have identified the problem and have a solution. Whether we want to call this a bug or "user hazard" (for want of a better term) within either the design of MS Visual Studio (on which AS is built), or the implementation of the gnu tools within AS, I'll leave to others to debate...

 

The basic issue is: Where are the AS projects relative to the AS solutions? As you all know, both projects and solutions can be physically represented by folders within the file system.

 

I first noticed this when loading and running clawson's sample. It loaded and built without problem. I then attempted to recreate it to a new solution based on his enumerated steps, with new executable and static lib projects. My recreation of clawson's steps failed with "undefined reference".

 

I didn't realize then that we (clawson and myself) create new solutions/projects in different ways - and here is the heart of the issue:

 

If the top solution's ATSLN file and one of the projects' CPROJ files (either the executable or the static lib, it doesn't matter) are in the same folder, the build will fail with "undefined reference". Conversely, if the ATSLN and CPROJ files are in different folders, the build succeeds. Apparently, there is an implicit arrangement of files "assumed" by the solution (or at least, the solution and one of the projects to be NOT the same folder).

 

Hopefully, a screen grab will illustrate this. Here is clawson's GccLibrary1 folder arrangement (which builds):

 

The key is that even though the static lib and the solution share the same name, the "real" static lib project is located in a different directory from the solution. GccLibrary1.atsln happens to be the parent directory; GccLibrary.cproj is located somewhere else (it happens to be a child folder, but it doesn't really matter).

 

Typically, when I've created new projects, I haven't cared about the location, or distinction, of the solution. MS Visual Studio/Atmel Studio attempts to "hide" the distinction and allows them to essentially overlap. If all you're creating are "simple", relatively flat projects this is not a problem. However, this distinction becomes important when working with static libs.

 

I made several attempts, each failing, because I didn't "isolate" the top-level solution from both of the projects (relative to the location of the ATSLN and CPROJ files, that is). Once I had a "proper" solution, with one or more logically and/or physically enclosed projects, the build succeeded as expected. [My typical way of creating projects is to NOT create a subdirectory - had I allowed this, there would have been no issue.]

 

Johan: your comment about stochastic results was priceless. Of course, true randomness strikes real fear in the minds of those who have to make a living with a tool that appears to be random! I hope that this info/test shows that the tool is not random (whew!), though it does allow an unsuspecting developer to fall thru a hole without any warning.

 

Oh, one other thing: AS was probably trying to warn me with this (though I couldn't find any documentation on what it meant). Notice the yellow triangle icon on the GccLibrary2 library name:

 

Here is the physical arrangement of the solution and the executable of that project. Notice that the solution and executable ATSLN and CPROJ files, respectively, exist in the same directory:

 

 

So, even though GccLibrary2.cproj file was in a separate folder from the GccApplication4.atsln file, the GccApplication4.cproj file wasn't. This causes a build error when attempting to link the GccLibrary2 static lib. (I have no idea why - maybe someone at Atmel can jump in here.) And, adding paths to the library thru the Toolchain->Library UI doesn't fix this. As far as I can tell, the logic that generates the makefile and superintends the build "assumes" that the solution's ATSLN file location in the file system is distinct from both of the project's CPROJ files. This implicit requirement isn't unreasonable - it just occurs without any explicit warning.

 

Anyway, please feel free to comment. If you all concur, then I'll edit the post's subject to mark it SOLVED. Perhaps this can keep someone from encountering the same issue again.

 

Thanks all for all the time you devoted to this!

Dave

The SiliconHacker  Plano, TX  www.siliconhacker.com

Last Edited: Tue. Feb 16, 2016 - 05:47 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just created the thing in the way/order i think anyone doing this would have gone about it. Create a project for the lib then in the solution+project that creates add a further project for the test code that accesses the lib.

 

I suppose the "issue" if there really is an issue here is down to the fundamental way in which VS2013 (and hence AS7) create projects within solutions. If (as may people here do) you simply create one project within one solution then I have always thought it a bit "odd" that the solution (at let's call that "level 1") and the project within it ("level 2") both have the same name. This leads to a directory structure on the disk such as:

 

c:\wherever\Atmel Studio\7.0\myproj\myproj

 

and when you build "Debug" then you get:

 

c:\wherever\Atmel Studio\7.0\myproj\myproj\Debug

 

It's that two levels of "myproj" that seem a bit "curious". Of course if I now add "anotherproj" to this solution I get:

 

c:\wherever\Atmel Studio\7.0\myproj\myproj\Debug

                                   \anotherproj\Debug

 

and it starts to make a bit more sense. I suppose what I really wanted was:

 

c:\wherever\Atmel Studio\7.0\mysolution\myproj\Debug

                                       \anotherproj\Debug

 

where the solution has a different name to the projects below it. But to cater for the one project per solution (which is probably even the "norm" for AVR) then I guess they have to call the solution something and they've chosen to name it after the first project created.

 

Now that is resolved I will bring you back to:

clawson wrote:
BTW here is a philosophical question: in the case of AVR code what IS the point of a static library anyway? Libraries are for generic code like strcpy() or printf(). Most of what you do for AVRs is very heavily bound to the hardware of a specific model of AVR. Even if you take your UCSR0As and TWAR's out of the mix then even in the case of printf()/strcpy() the AVR compiler requires 17 pre-built versions to cater for the 17 different AVR "architectures" and it is frankly a nightmare for the maintainers. Life is much simpler if you simply provide the source and let the user build it for their architecture and, in the case of UCSR0A/TWAR/etc have compile time switches for things like "if mega16/mega32 use UCSRA but for mega48/88/164/324 use UCSR0A instead...". If you wanted to achieve that in a .a file you would need every variant built in and a run-time selection of which one to use.

Libraries really do not make sense for AVR!

 

In fact I often wonder why the "new project.." dialog for avr-gcc in AS7 even mentions the possibility of static C/C++ libs at all - I think that's just inheriting from what VS2013 offers for x86 projects (where static libs do make sense).

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

PS the more I think about this (the original issue) the more I wonder whether one should even bother trying to do battle with the IDE over this at all. Just build a lib, doesn't matter where and once you have libmylib.a in \path\to\the\lib\ literally just -L\path\to\the\lib and -lmylib direct to the linker and cut out the IDE middle man. Basically what I said in the EDIT to #15 in fact. Throw some -Wl,... into the mix if the commands aren't making it as far as the linker.

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

The point with letting the IDE handle this, is that it and its build system should know about the dependency and wether you edit just the executable projects code, the librarys code or both then hitting Build will rebuild what needs to be rebuilt.

 

When a library is stable then this matters little, perhaps.. But when you're developing the library and test it with a test executable then this is convenient.

 

I have yet to read the OPs thorough post in #17.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

[Hi Johan and clawson: This is in (preliminary) response to posts #18, #19, and #20. I'll post the "formal" answer hopefully tomorrow after I've had time to redo my solution/project infrastructure to fix the issue I encountered and according to what I learned earlier today. I know that it is getting late for you both, so it is unlikely that I'll have it worked out and posted much before your - and my - tomorrow.]

 

So, again preliminarily to your point, clawson: I confess that due to the software side of my development experience (about 20 years in Windows), I came to love DLLs. The notion of software modules (understandably CPU-independent) was very powerful. I'm attempting to apply this basic philosophy (I like and agree with your term) to AVR microcontrollers development as well (and not just Atmel AVR, but all their other families as well).

 

I believe that I have both a reason and (now) a method to group code into static libraries AND keep them organized by micro family to accommodate the micro-specific dependencies. The goal in all this is to support my product line with open source code, but to do it in such a way as to save the engineer a great deal of time. I have board-level products that are, of course, micro-specific and can only be built with that micro in mind. There are, however, many other HW modules that use micro-independent code (such as I2C) that can be grouped into one or more static libs. The composition of the static lib at any point is controlled by preprocessor directives according to what the engineer needs for a given project.

 

Because of the number of HW modules that I have, I very much want to give the user of my products the advantage of a major head-start. They may choose - or not - to use my solutions and projects. However, I nevertheless need a framework which can grow over time and which can support both my and my users submitting code to a library (should it be successful).

 

Again, more on this soon once I've had a chance to make the changes and do some preliminary builds. But, I did want to reply soon to you both since you've contribute time and good thought into the issue.

Dave

The SiliconHacker  Plano, TX  www.siliconhacker.com

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

Phoenix710 wrote:
So, again preliminarily to your point, clawson: I confess that due to the software side of my development experience (about 20 years in Windows), I came to love DLLs. The notion of software modules (understandably CPU-independent) was very powerful. I'm attempting to apply this basic philosophy (I like and agree with your term) to AVR microcontrollers development as well (and not just Atmel AVR, but all their other families as well).

Yeah my day job is either building DLLs for Windows or .so (sometimes .ko) for Linux. It makes sense to modularise code in that environment because the target (an AMD64 or i386 Pentium) is unchanging. So you can build your dynamic lib (or static if it's going to an environment that cannot do dynamic loading) and you can share it around with your mates and on the internet and all is rosy.

 

But this is not true of AVR. Say I write an HD44780 LCD library or perhaps a simple UART library. Now I want to share this with the world. So I take the "binary blob" I've built and give it to a mate. Only he comes back and tells me that "when I try to link your lib I get an error about wrong architecture". It turns out I built my binary for atmega16 (which is AVR architecture "AVR5") but he is using an atmega88 which is AVR4 architecture. So already I've hit a wall. "it's OK" I say, "I'll build it for mega88 and send you a lib for that instead". But now I switch my build target from mega16 to mega88 and compile and the compiler tells me that "UCSRA" and "UDR" are unknown symbols. This is because, even though mega16 and mega88 each have just a single UART the registers for mega16 are called UDR/UCSRA/UCSRB but the same registers for mega88 are UDR0/UCSR0A/UCSR0B/etc.

 

In the end I send him the source:

#ifdef UDR
#define UDR_DATA    UDR
#define UART_A_REG  UCSRA
#define UART_TX_READY  UDRE
#elif defined(UDR0)
#define UDR_DATA    UDR0
#define UART_A_REG  UCSR0A
#define UART_TX_READY  UDRE0
#else
#error "you sure this thing even has a UART?"
#endif

void uart_putchar(uint8_t c) {
    while (!(UART_A_REG & (1 << UART_TX_READY)));
    UDR_DATA = c;
}
etc.

and he just adds uart.c to his project and for his mega88 it will build using UDR0/UCSR0A/etc while my build for mega16 will use UDR/UCSRA/etc.

 

As I said above. If I really wanted to send him prebuilt binary libs then to cater for every model of AVR I would need to send SEVENTEEN[*] versions of my libuart.a. He might use libuart4.a and I would use libuart5.a because he uses an AVR4 chip and I use an AVR 5 chip.

 

In fact 17 is not enough for example AVR4 alone consists of at90pwm1, at90pwm2b, at90pwm2, at90pwm3b, at90pwm3, at90pwm81, atmega48a, atmega48, atmega48p, atmega8515, atmega8535, atmega88a, atmega88, atmega88pa, atmega88p, atmega8hva, atmega8. They may not all have UDR(0)/USCR(0)A/etc in the same place and the at90pwm1 (just an example) doesn't even have a "UDR" register.

 

[*] this shows the 17 prebuilt copies of libc in the compiler itself:

~/windows/avr8-gnu-toolchain-linux_x86_64$ find . -name libc.a
./avr/lib/avr3/libc.a
./avr/lib/avr4/libc.a
./avr/lib/avr5/libc.a
./avr/lib/avrtiny/libc.a
./avr/lib/avrxmega6/libc.a
./avr/lib/avr31/libc.a
./avr/lib/avr25/tiny-stack/libc.a
./avr/lib/avr25/libc.a
./avr/lib/avr35/libc.a
./avr/lib/avr51/libc.a
./avr/lib/tiny-stack/libc.a
./avr/lib/avrxmega5/libc.a
./avr/lib/avrxmega4/libc.a
./avr/lib/libc.a
./avr/lib/avrxmega2/libc.a
./avr/lib/avrxmega7/libc.a
./avr/lib/avr6/libc.a

It is possible for libc.a to exist as just 17 different binaries as it has no knowledge of part specific registers built in. It just contains things like printf() and strcpy() that are hardware independent. But even then there has to be 17 of them.

 

The reason for 17 is (for example) that AVRs with 8K or less flash have no need of CALL or JMP opcodes (the entire flash is within range of the shorter/quicker RCALL/RJMP opcodes) so small AVRs cannot use CALL/JMP. Meanwhile at the other end of the scale the 256K and 384K AVRs cannot hold a word address in 16 bits so their versions of CALL and JUMP use 24 bit destinations and when they CALL three bytes (not the normal two) are PUSHd onto the stack. There are other opcode differences besides just this in the 17 different variants.

 

I suppose the ultimate test of all this would be if I ask you to send me a lib that just contains a single function that writes 0x55 to PORTB - but I am not going to tell you which AVR I am using. So you try to send me that lib that will work for me whatever AVR I have here. Good luck with that!

 

OTOH you could just send me:

#include <avr/io.h> 

void func(void) {
#ifdef PORTB
    PORTB = 0x55;
#endif
}

and that will work for me whatever AVR I happen to have here ;-)

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

Hi, clawson:

 

Good example with the UART, and valid. The same could be said for pretty much any other builtin (timer, TWI, etc.). I have envisioned something a bit different, though, since my product line is HW modules with attendant open-source software. I can see where what I've said above might allow for the implicit conclusion that I intended to provide online pre-built static libs; this was not really the case.

 

The scenario is closer to this: I have many HW modules, many of which contain a micro (AVR at this point in time) and others that use TWI(I2C). The software modules I provide are buildable to a specific micro (via the typical preprocessor directives) - but are built by the user to the micro that he/she has chosen. (This assumes, of course, that the preprocessor directives and micro accommodate whatever builtin module is being interfaced.) My desire has been to setup the infrastructure for the user to make it easy and efficient to get from the open-source code I provide to a running prototype with minimal effort and maximal efficiency.

 

As you have capably shown, attempting to provide prebuilt static libs is not practical; however, user-built static libs can be practical.

 

After spending the rest of the yesterday working on various solultion/project architectures, I finally settled on the tried-and-true H, Src, and TB directories - basically, source file sharing (something easy to setup, maintain, and grow). In the near future I will provide one or more blog articles on the building and using of static libs (along with some tutorial videos), but have elected against actually setting up static libs for my open source at this time - for the reasons you cite (and others).

 

Again, thanks much for the details and clear thought. it's great to see experience at work.

Dave

 

The SiliconHacker  Plano, TX  www.siliconhacker.com

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

Phoenix710 wrote:
however, user-built static libs can be practical.

But it just complicates the build for the user doesn't it? What possible advantage is it to them to build a lib and THEN build the app code that links to the lib? They might as well just add your foo.c to the other files they are building in their app?

 

When I first started working with AVRs it used to wind me up that the term "library" was being mis-used not to mean a precompiled libfoo.a but a pair of foo.h/foo.c files that the user was expected to add to their project to gain access to some facility. But now I understand the exact reasons why. In the AVR world a foo.h/foo.c "library" makes total sense.

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

hi i had developed a static library with a simple sum function in atmel studio 7, when i selected my main project as GCC C executable project where i want to use the library. i am able to add the library and access the function in it. when i selected project as GCC C ASF board project i am able to add the library but when i add the function of library in my main project and compile it is showing the error as implicit declaration of the function what may be the problem please help where i am going wrong. 

Last Edited: Wed. Feb 6, 2019 - 04:05 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

(static) Libraries come in TWO pieces. There is the libXXX.a that contains the code and there should be an XXX.h header file that documents the interface to the functions in the library. You #include that .h file where you are going to use the functions that the library provides. Think of something like strcpy() for example - that is in libc.a and it has a header called <string.h> that you must include to use the function.

 

So if your library had a function like:

int add(int a, int b) {
    return a + b;
}

then you would also have a libname.h that has:

int add(int, int);

then in main.c you would use:

#include <avr/io.h>
#include "libname.h"

int main(void) {
    PORTB = add(17, 23);
}

This would work without "implicit declaration" because by the time the compiler reaches the PORTB= line it already knows that the function called add() is a function that takes two integers as parameters and returns one back.

 

If I didn't have the header then the PORTB= line would be the first time the compiler ever encountered something called add() and because it did not know it's effectively "int add(int, int)" it would just have to make some assumptions about the types of the inputs and the output. In this case it would warn about that saying "implicit declaration".

 

BTW there is almost no point on earth in creating static libs for avr-gcc code. It just does not make sense on so many levels!