LinuxQuestions.org
Did you know LQ has a Linux Hardware Compatibility List?
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 12-20-2009, 07:29 PM   #1
MTK358
LQ 5k Club
 
Registered: Sep 2009
Posts: 6,443
Blog Entries: 3

Rep: Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713
Script to list dependencies


I would like to make a script (in whatever language is most suitable) that extracts the contents of "#include "Something.h"" statements.

Example Input File:

Code:
some stuff
/*more stuff*/
#include "Something.h"
#include <stdio.h>
#include "AnotherHeader.h"
more code
Output:

Code:
Something.h
AnotherHeader.h
It would also be nice if it could recursively find the dependencies of these headers, and so on.

How should I do this (or maybe there already is such a thing)?

Last edited by MTK358; 12-20-2009 at 07:31 PM.
 
Old 12-20-2009, 08:07 PM   #2
JohnGraham
Member
 
Registered: Oct 2009
Posts: 467

Rep: Reputation: 138Reputation: 138
find, grep and sed seem like apt tools for this (in that order) - find to get the files, grep to search for #include lines, and sed to edit-out the bits you don't want.

Here's a single command-line that works for a bunch of files I have in one of my projects. It'll probably have bugs, and you'll probably want to wrap it in script-related niceness, but it's a start:

Code:
find | xargs egrep '#include [<"].*[>"]' | sed -e 's|.*#include [<"]||g' -e 's|[>"].*||g' | sort | uniq

Last edited by JohnGraham; 12-20-2009 at 08:11 PM.
 
Old 12-20-2009, 08:52 PM   #3
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian
Posts: 2,396

Rep: Reputation: 814Reputation: 814Reputation: 814Reputation: 814Reputation: 814Reputation: 814Reputation: 814
gcc can do this: see Preprocessor Options (-M and -MM). The output is in Makefile format:
Code:
~/tmp$ cat dep.c 
/*more stuff*/
#include "Something.h"
#include <stdio.h>
#include "AnotherHeader.h"
~/tmp$ gcc -MM -MG dep.c 
dep.o: dep.c Something.h AnotherHeader.h
~/tmp$ gcc -MM -MG dep.c | sed 's/^.*dep\.c //'
Something.h AnotherHeader.h
-MG just tells gcc not to complain about Something.h not existing. If Something.h #includes another header it will be in the dependancy list for dep.c.
 
Old 12-21-2009, 12:03 AM   #4
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
It's hard to track down dependencies with local includes unless you're privy to the include paths to be specified at compile time, in which case you might as well just use automake and see if you can find where it stores dependency information (I've never bothered to look for it, but it's there somewhere.)
Kevin Barry
 
Old 12-21-2009, 07:34 AM   #5
MTK358
LQ 5k Club
 
Registered: Sep 2009
Posts: 6,443
Blog Entries: 3

Original Poster
Rep: Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713
I've started playing with JohnGraham's script, even thought it doesn't do what I want I think I can make it do what I want.

The main thing is that the script fount all the dependencies of all the files, I just need the dependencies of one single .c file recursively.

Also, I only want to catch #include's with quotes (not brackets).

Here's what I came up with so far:

Code:
cat lsd
#!/bin/bash

grep '#include ["].*["]' $1
$ lsd Cat.c
#include "Cat.h"
Wanted Output:

Code:
lsd Cat.c
Cat.h
Animal.h
Object.h
All I need to do now is to strip off the #include statement to just leave the filename, and then run this script on all the dependencies that it found.

Last edited by MTK358; 12-21-2009 at 07:37 AM.
 
Old 12-21-2009, 08:07 AM   #6
MTK358
LQ 5k Club
 
Registered: Sep 2009
Posts: 6,443
Blog Entries: 3

Original Poster
Rep: Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713
Some more progress:

Code:
#!/bin/bash

grep '#include ["].*["]' $1 | sed 's:[^"]*"\([^"]*\)"[^"]*:\1:'
It now lists all the filenames of the dependencies (for some reason it only works when there is a space between #include and the first quotation mark, I don't know why).

Now just the recursive part.

EDIT: I figured out that the grep command is searching for the space, this is how I fixed it:
Code:
grep '#include *["].*["]' $1 | sed 's:[^"]*"\([^"]*\)"[^"]*:\1:'

Last edited by MTK358; 12-21-2009 at 08:12 AM.
 
Old 12-21-2009, 09:42 AM   #7
MTK358
LQ 5k Club
 
Registered: Sep 2009
Posts: 6,443
Blog Entries: 3

Original Poster
Rep: Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713
I really have no idea how to do this.

Is it possible for a for loop in bash to iterate through individual lines of a block text stored in a variable?
 
Old 12-21-2009, 12:32 PM   #8
MTK358
LQ 5k Club
 
Registered: Sep 2009
Posts: 6,443
Blog Entries: 3

Original Poster
Rep: Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713
I found that you can use exec to redirect a file to stdin and then read to read stdin line by line, but how do you redirect the contents of a variable to stdin?
 
Old 12-21-2009, 01:23 PM   #9
tuxdev
Senior Member
 
Registered: Jul 2005
Distribution: Slackware
Posts: 2,011

Rep: Reputation: 110Reputation: 110
Code:
#!/usr/bin/env bash

while read -r file ; do
   :
done < <(grep -rh '^#include *".*"$' | sed 's/^#include *"\(.*\)"$/\1/' | sort | uniq)
I do wonder why you want to do this. Any one of the alternative methods given in this thread is likely to work much better for you.

Last edited by tuxdev; 12-21-2009 at 01:49 PM.
 
Old 12-21-2009, 01:42 PM   #10
MTK358
LQ 5k Club
 
Registered: Sep 2009
Posts: 6,443
Blog Entries: 3

Original Poster
Rep: Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713
You still don't understand that I don't want to get all the dependencies of all the files. I just want the dependencies of 1 file, and the dependencies of those, and so on.

Also the example creates syntax errors.
 
Old 12-21-2009, 01:51 PM   #11
tuxdev
Senior Member
 
Registered: Jul 2005
Distribution: Slackware
Posts: 2,011

Rep: Reputation: 110Reputation: 110
That's not really what you want to do. What you want to do is something like "draw a dependency graph", which doxygen can do for you with the help of graphvis.

What is it that you *really* want to do?

Last edited by tuxdev; 12-21-2009 at 01:56 PM.
 
Old 12-21-2009, 01:57 PM   #12
MTK358
LQ 5k Club
 
Registered: Sep 2009
Posts: 6,443
Blog Entries: 3

Original Poster
Rep: Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713
Actually this is supposed to be a part of an automated script that checks which .c files must be compiled.

For this purpose, I want it so that you just apply a .c file as the argument and it lists out all the .h files it includes.
 
Old 12-21-2009, 02:15 PM   #13
Disillusionist
Senior Member
 
Registered: Aug 2004
Location: England
Distribution: Ubuntu
Posts: 1,013

Rep: Reputation: 83
Code:
#!/bin/bash

read -p "Enter file to be checked ==> " l_file
if [ -f "$l_file" ]
then
   grep '#include' "$l_file"|sed 's/#include *["<]//'|sed 's/[">]//'
else
   echo "File: $l_file not found or not a regular file"
fi
 
Old 12-21-2009, 02:17 PM   #14
MTK358
LQ 5k Club
 
Registered: Sep 2009
Posts: 6,443
Blog Entries: 3

Original Poster
Rep: Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713Reputation: 713
Doesn't that go only 2 levels deep?

Here's my recursive version, but it just freezes at the highlited line and doesn't execute further:

Code:
#!/bin/bash

deps=''
files=$*
filedeps=''

getdeps() {
	$filedeps=$(grep '#include *".*"' $* | sed 's:[^"]*"\([^"]*\)"[^"]*:\1:' | uniq)
	if [ $filedeps ]
	then
		echo $filedeps # Actually this should append $filedefs to $deps, I don't know how to do that
		$files = $filedeps
		getdeps
	fi
}

getdeps
echo $deps

exit 0

Last edited by MTK358; 12-21-2009 at 02:22 PM.
 
Old 12-21-2009, 02:36 PM   #15
Disillusionist
Senior Member
 
Registered: Aug 2004
Location: England
Distribution: Ubuntu
Posts: 1,013

Rep: Reputation: 83
Quote:
Originally Posted by MTK358 View Post
Doesn't that go only 2 levels deep?

Here's my recursive version, but it just freezes at the highlited line and doesn't execute further:

Code:
#!/bin/bash

deps=''
files=$*
filedeps=''

getdeps() {
	$filedeps=$(grep '#include *".*"' $files | sed 's:[^"]*"\([^"]*\)"[^"]*:\1:' | uniq)
	if [ $filedeps ]
	then
		echo $filedeps # Actually this should append $filedefs to $deps, I don't know how to do that
		$files = $filedeps
		getdeps
	fi
}

getdeps
echo $deps

exit 0
You need to use the variable $files instead of $*
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
list all dependencies when one, or more, blocked by 'masked by: ~amd64 keyword'? zymos Gentoo 2 08-18-2009 10:28 PM
yum and packagekit - list installed packages and dependencies allele Linux - Newbie 2 06-24-2009 03:31 PM
Newbie: Can't figure out dependencies list for superkaramba on Slack 12. waco-old-paco Slackware 7 11-30-2007 11:52 AM
libc6 2.4-1 needed to complete list of dependencies for libfame-0.9_0.9.1-0.2_i386.de wabbalee Linux - Desktop 4 10-11-2006 09:07 PM
Sources list and Packages dependencies varaonsite Debian 2 07-31-2006 04:43 PM


All times are GMT -5. The time now is 06:05 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration