Using cscope and ctags to develop with avr-libc and avr-gcc under Linux

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

Hello All,

 

I have looked around and don't see any information on configuring cscope and ctags to develop for AVRs.  I'm a bit of a newbie when it comes to both cscope and ctags, but find they help me understand code better than simply editing files with a text editor.  I am looking for some guidance in determining what files to include in cscope.files.  Specifically, how can I determine what headers I need from the avr directory for my micro controller.  I have a atmega168, so I have included avr/iom168.h and avr/iomx8.h as well as the files that are clearly generic (eg. avr/common.h).  To accomplish this I run find /usr/lib/avr/include -name '*.h' > cscope.files, then remove all the avr/ioXXX.h that aren't iomx8.h and iom168.h by hand.  I then build the cscope database as if I were building a kernel cscope -b -q -k, so I don't get /usr/include files.  Then I build the ctags database with ctags -L cscope.files.  I believe I have all the necessary headers and am not missing any, but was looking for an automated way to determine whether or not this is the case.  Is there an easier method to accomplish my goal?

 

Thanks in advance,

 

Chris

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

I like to use cscope with gvim (with cscope plugin).

I don't know of any easier way than what you are doing, other than you could probably modify your find comand to only pick the headers you're interested in, or pipe the result through grep etc.

Probably worth worth making it into a script so easy to re-run.

Personally I haven't even been bothering with the avr headers (just grep them if I ever want to find something),  I have just been doing cscope -Rb to build database for my c and h files.

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

I have had a suggestion from MrKendo to improve my find command.  Now I can run find /usr/lib/avr/include -name '*.h' ! -name 'io[a-z0-9]*.h' ! -name "xmega.h" > cscope.files. Then I run find /usr/lib/avr/include/avr/  -name -name 'iom168.h' >> cscope.files.  Then find /usr/lib/avr/include/avr/  -name -name 'iomx8.h' >> cscope.files.  This builds the complete files list that I had to edit by hand before.  Then I need to populate the cscope.files with my project files find `pwd` -name '*.[ch]' >> cscope.files and I am done.  Then cscope -b -q -k followed by ctags -L cscope.files.  And my databases are made.  

 

Thanks to MrKendo.

 

Chris

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

Well you prompted me to be a bit less lazy and do a bit better than the basic csope -Rb.

So I knocked uo a quick script.

In terms of which headers to use for a given processor, I decided it's easiest to work it out manually from looking in avr/io.h, and following that through (eg. if the header specified in avr/io,h itself includes another header). You only have to do this once for a given pocessor. I'm using mega328p here.

Your find command may be better, I just hacked an 'inverse grep' onto the end.

This script would be run from within the top level source code directory.

#!/bin/bash

# 'common' headers ie. anything that doesn't start with io
find /usr/lib/avr/include  -name "*.h" | grep -v "io.*\.h" >cscope.files
# but let's have avr/io.h
echo "/usr/lib/avr/include/avr/io.h" >>cscope.files
# specific headers for mega328P, worked it out manually from looking at avr/io.h
echo "/usr/lib/avr/include/avr/iom328p.h" >>cscope.files
# c and h src files
find . -name "*.[ch]" >>cscope.files
cscope -b -k

 

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

Thanks MrKendo.  That's a wonderful script.  I have copied it to my bin directory.

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

Sounds like what you were already doing.

And you had better commands!

My 'grep -v' (couldn't remember all the find syntax) would exclude any file that happens to have io in the name like version.h or stdio.h

Now that I have looked up the find syntax, for benefit of anyone else, I think a slightly better version

 

#!/bin/sh
# 'common' headers ie. anything that doesn't start with io
find /usr/lib/avr/include  -name "*.h" -a -not -name "io*.h" -print >cscope.files
# but let's have avr/io.h
echo "/usr/lib/avr/include/avr/io.h" >>cscope.files
# specific headers for mega328P, worked it out manually from looking at avr/io.h
echo "/usr/lib/avr/include/avr/iom328p.h" >>cscope.files
# c and h src files
find . -name "*.[ch]" -print >>cscope.files
cscope -b -k

 

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

Thank you MrKendo for your time and scripts.  I don't know if anyone else uses cscope and ctags, but if they wish to now there is some documentation on how to do it.  I believe most folks run atmel studio, where folks can put a cursor over a PORTB and find out it is defined as _SFR_IO8(0x05).  Now I can do the same from within vim.  Just for the benefit of others once you have run MrKendo's script from the base of your project tree, you can make a tags file with ctags -L cscope.files.  You will also need to tune MrKendo's script to your mcu.  In my case echo "/usr/lib/avr/include/avr/iom328p.h" >>cscope.files should be replaced with echo "/usr/lib/avr/include/avr/iom168.h" >>cscope.files and echo "/usr/lib/avr/include/avr/iomx8.h" >>cscope.files. 

 

To find out what files you need from the avr/io*.h set that was excluded, I tried to use gcc -save-temps when I built my project to see what headers it included.

 

 

 

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

Just to note that the way io.h works is related to the -mmcu=atmega328 or whatever that is passed when you compile. The compiler (actually preprocessor) has an internal lookup table that maps something like "atmega328p" to create a predefined macro called something like __AVR_ATmega328__ then in io.h it is simply a cascade of #if/#else that picks out iom328.h as being the relevant .h file because __AVR_ATmega328__ is defined.

 

So the point is that if the C analysing code you are using (have to admit I've not heard of it) has the way to introduce the equivalent of -D's then you should add a -D__AVR_ATmega328__ (or whatever the device is) so that when it scans io.h it ignores all the other io*.h and only includes iom328.h

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

cscope is a tool where if you give it a symbol name (eg. name of a function), it can show you the definition of that function, or show everywhere in the code that callls the function etc. The kind of features you would already have if using a typical IDE, but you don't have if working with basically just a text editor. It integrates very nicely with (g)vim, so you can position the cursor over a symbol name and hit a key combination and it will take you to the function definition etc, so you now have something a bit more like an IDE. It basically saves a lot of 'grepping' through the code to find what you're looking for.

 

It requires a list of files from which it will create a database of all the symbol names.

You obviously are going to want all of your own c and h files in that list, but you might also want the system headers.

So what we have ben talking about is how to determine which of the ioxxxx headers to include in that list.

 

You could write a more sophisticated script, which you would provide with the processor name, and that script would then work out (from avr/io.h) which device specific header(s) to add to the list.

But I took the easy option and did that proces manually.

 

https://en.wikipedia.org/wiki/Cs...

http://cscope.sourceforge.net/cs...

 

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

I presume that if it sees:

#ifdef DEBUG
#define DELAY 200
#else
#define DELAY 4000
#endif

then it can process such condition code and will later show "DELAY" to be 4000 if DEBUG is not defined? If so does it have the facility to handle something like -DDEBUG ? Like I say if you can influence it's parsing by defining command line macros (perhaps they come out of a config file or something like that?) then you might be able to predefine __AVR_ATmega328__ or similar.

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

No it's not that smart, doesn't do macro expansion, if you look for the definition of DELAY it wil simply show you both options where DELAY is defined.

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

Ah that's a shame. I imagine things can get pretty confusing then in projects with a lot of conditional build alternatives?

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

I hadn't thought of conditional build alternatives being difficult with cscope and ctags, but you are probably right.  I'm using cscope and ctags to peruse the code from Elliot Williams book, Make: AVR Programming.  I am a real beginner on building software for hardware.  As MrKendo said these programs allow you to jump back and forth through files by function call or variable definition, simply by hitting a key.  I assume Atmel Studio does this kind of thing well for Windows users.  My other alternative is to edit files by hand and run grep on the command line to find out where in the code base variable X is defined.  It's doable but not as easy.  I believe cscope and ctags are more meant for large projects, but they work for me on my small one.  

 

Thanks for your time and interest.

 

 

 

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

 

chrisgorman wrote:
I assume Atmel Studio does this kind of thing well for Windows users. 
Yup, very. It is VS2015 after all. However it's not smart enough to work out something like:

 

 

It clearly cannot "see" that it must be 20 in this case. This is what "real" Visual Studio 2017 (that has "Intellisense") does with the same challenge...

 

 

So it knows! (and I love the fact that it auto-greys the non-active sections of the code).

 

Last Edited: Thu. Jul 18, 2019 - 01:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Very nice.  I looked at eclipse at one point and it greyed out sections of code from headers that were not relevant based on the mcu, if I recall.  I don't know if it would work for the case you presented based on the #define DEBUG.  I would test it and see, but if I did, I would be spending all day playing with eclipse. ;)

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

clawson wrote:
The compiler (actually preprocessor) ...
Might be able to run AVR source code through Clang then there are at least a few tools to visualize that code.

Clang Related Projects

...

 

DXR

Site: https://github.com/mozilla/dxr

DXR is a code search and navigation tool aimed at making sense of large projects like Firefox. It supports full-text and regex searches as well as structural queries like "Find all the callers of this function."

 

CodeCompass

Site: http://github.com/Ericsson/CodeCompass

CodeCompass is an open-source, extensible code comprehension framework which uses LLVM/Clang to analyze and visualize C and C++ projects. It also supports both regex-based text search, discovering complex C/C++ language elements, with advanced navigation and visualisation.

 

...

VisualGDB (Windows) has Clang for parsing and such then typically GCC for compile.

AVR LLVM/Clang is in-work though appears to be complete enough now (release should be by early northern Fall in LLVM 9)

 


The new-generation IntelliSense engine for VisualGDB

https://bugs.llvm.org/buglist.cgi?quicksearch=AVR

https://github.com/llvm/llvm-project/blob/release/9.x/llvm/lib/Target/AVR/AVRDevices.td#L244 (most recent are tiny102 and tiny104; ie, no unified memory AVR)

 

"Dare to be naïve." - Buckminster Fuller

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

I tried what @clawson showed with VScode.

 

 

 

VScode seems to know what to show; I think it must be using the defines to do this.

 

 

This image shows my setup, but who knows if that is correct or complete.

 

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

Nice.  You made me think about using an editor other than vim.  

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

 

chrisgorman wrote:

Nice.  You made me think about using an editor other than vim.  

Yes, use gvim :)

 

 

I see 2 separate cases.

If I'm going through source code and come across TCNT1 = DELAY, then one thing I might want is  'show me all the places in the code where DELAY is defined'. It might be defined conditionally lots of times eg.

#if CHIP_VERSION == 1

#define DELAY 10

#elif CHIP_VERSION == 2

#define DELAY 23

etc.

I just want to see all the possibilities. cscope does this. I would be very annoyed if the tool was trying to be clever and only shows me one option.

 

The other case would be to show the expansion of a macro based on some specific configuration, which would have to include any -D arguments given to compiler. In this case the tool does need to be clever. cscope doesn't do this, so you would have to go and run the preprocessor (or compiler with -save-temps) yourself. Not a big deal, but I certainly wouldn't object to a 'one click' solution to do this.

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

Cool!

ron_sutherland wrote:
This image shows my setup, but who knows if that is correct or complete.
Can add AVR GDB to that and maybe Microchip EDBG via the Arduino extension.

https://www.avrfreaks.net/forum/avr-studio-mac-linux#comment-2600281

 

"Dare to be naïve." - Buckminster Fuller

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

Yep, VScode is clever++. Additionally, I have no idea what I'm doing with it; I am sure not everyone will like it. This image shows how it seems to locate multiple defines.

 

 

update: Not sure I understand what an "expansion of a macro based on some specific configuration" looks like. VScode (IntelliSense actually) seems to expand based on the current defines of the codebase it is editing. I can tell that it does not pick up stuff that I have passed from the Makefile, but it is expanding from the defines it knows.

 

Last Edited: Thu. Jul 18, 2019 - 11:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

VSCode is effectively a cut-down VS2015/2017/2019 so it's little surprise that it handles the conditional logic in the same way as Visual Studio. I rather imagine Microsoft will have simply reused the same code browser.