Converting MSVC /showInclude to unix friendly path

Hi guys,

I've been trying to do this for hours, and I've just been running around in circles trying to get this script made. I have a set of files outputted by an MSVC compiler that looks like this

1>  helloworld.cpp
1>  Note: including file: c:\dev\test\makefile\source\helloworld.h
1>  Note: including file:  C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A/Include\windows.h
1>  Note: including file:   C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A/Include\sdkddkver.h
1>  Note: including file:   C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\Tools\../../VC/Include\excpt.h
...

and I'm converting it to spit out something that could then be imported into the makefile.

So far I've got this script:

sed 's/Note: including file: *//' < $(COMPILER_GET_DEPEND_NAME_CPP) | sed '{:q;N;s/\n/" "/g;t q}' | sed 's/.cpp"/.cpp : /';

which gets me close, but doesn't make the paths into anything cygwin would appreciate. The output from this looks like:

helloworld.cpp :  "c:\dev\test\makefile\source\helloworld.h" "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A/Include\windows.h

As you can tell, two things stand out here. First of all, all I'm doing is replacing the \n with a " " and then getting rid of the first quotation when I go to add the ":" to tell the makefile that the source file depends on the headers listed. This means that there is no trailing quotation mark and I'm not familiar enough with unix commands and pipes to be able to add that last quotation.

The second issue is the more difficult one. I need all the paths to be converted to using linux style paths, and I can not figure that one out. I know cygwin has a utility function called cygpath, but that only works when you feed it one path at a time. I don't know how to do that from the bash shell and I have no idea where to even start.

Could you guys give me some tips on how to approach this problem?

---------- Post updated 02-13-11 at 12:49 PM ---------- Previous update was 02-12-11 at 04:16 PM ----------

I think I've got it. It doesn't look pretty, but it works for now

sed -e 's@Note: including file: *@"/cygdrive/@' -e 's@\\@\/@g' -e 's@:@@g' -e 's@\.[hH]@\.h"@g' -e's@.cpp@.cpp : @' depends.d.tmp | sed '{:q;N;s/\n/ /g;t q}'

That appears to format the line the way Make would accept it. I was just wondering, is there an easier way? More flexible way? I'm hard coding quite a bit in this simple script and I don't like that.

---------- Post updated at 01:22 PM ---------- Previous update was at 12:49 PM ----------

Actually, I was a little off. I forgot that makefiles don't care about quotes around file names. It appears as though there is no quick fix for this. Placing wildcards in the file doesn't solve the problem, and moving the folders is also not an option.

This simple makefile is turning out to be a lot more complex then I thought! :wall:

Even putting simple "\\ " when replacing the strings doesn't solve the problem because then it complains about MS-DOS path names. I have no idea where to go next.

awk -F"[>:]" 'NR==1{printf "%s : ",$2;next}{gsub(/\\/,"/");sub(/ */,"",$4);printf "\"/cygdriv/%s%s\" ",$4,$5}' depends.d.tmp

---------- Post updated at 05:27 AM ---------- Previous update was at 05:24 AM ----------

Just see your new post.

Maybe you can search in google how to build in cygwin.

I've got it now. It took a long time of trial-and-error(and lots of errors) but eventually I found out how to do it. A simple google search showed that putting "\\ " would work with file names that have spaces in them, but it actually requires just a "\ "(which actually makes more sense).

The final line looks messy, but here it is:

sed -e 's@Note: including file: *@/cygdrive/@' -e 's@\\@\/@g' -e 's@:@@g' -e 's@ @\\ @g' -e's@.cpp@.obj : @' "depends.d.tmp" | sed -e '{:q;N;s/\n/ /g;t q}' | sed -e 's@^@/object/@' > "depends.d";

Fairly nasty, but it does the trick.

---------- Post updated at 05:00 PM ---------- Previous update was at 04:45 PM ----------

Actually, this solves the problem of taking the /showIncludes output and parsing it to a make readable format. by using:

cl foo.cpp /Fo"foo.obj" /showIncludes > depends.d.tmp

It also pipes the warning and error messages. It can't tell the difference between errors and correct output... This means that the first time you have an error in your code, it will spit out a bad depends.d file which is then included in the makefile, which means any further compiles are going to fail...

I can see why most people don't use /showIncludes to generate the dependency graph! However, it shouldn't be that difficult to write a script that takes the err code returned from cl.exe and then determine if it should even bother converting the depends.d.tmp. Thats the next part I am going to tackle!
:wall:

Can the cygpath command reduce some of the complexity?

$  cygpath 'C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A/Include\sdkddkver.h'
/cygdrive/c/Program Files (x86)/Microsoft SDKs/Windows/v7.0A/Include/sdkddkver.h
 
$ cygpath 'C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\Tools\../../VC/Include\excpt.h'
/cygdrive/c/Program Files (x86)/Microsoft Visual Studio 10.0/VC/Include/excpt.h

I tried using cygpath before, but the limitation with it was that it could only take one argument at a time. I then tried looping through the file using a simple while loop, but that was taking ages. In the end, I found it easier just to use sed. Besides, I'd still have to find a way to get around spaces in names for makefiles to work and cygpath wouldn't do that either.

The only thing I have left is to determine if the compiler has thrown an error, and if so, redirect that error to the screen rather then trying to convert it to a makefile dependency thing.

I also tried using makedepend, but due to the microsoft specific "extensions"(also known as the microsoft incompatibilities) that conflict with some files, and also the cross platform necessity of what I'm working on, means that makedepend wasn't doing a good enough job... too bad, I would prefer to use it!

Does the return code of cl indicate if it worked?

If so how about saveing the stderr to your file and then examine the return code eg:

cl foo.cpp /Fo"foo.obj" /showIncludes > depends.d.tmp 2>&1
if [ $? -ne 0 ]
then
    echo "Failed to compile:" >&2
    cat depends.d.tmp >&2
    exit $?
else
   # Process depends.d.tmp file
fi

I should be able to catch if "cl" has completed successfully from within make and then have an error clause that forces it to output the contents of depends.d.tmp. I'm sure I read something about that somewhere and so I'm doing a little googling right now to see if I can locate it.

If that fails, then your method sounds best.

Thanks!

Just a quick reply... sorry for what appears to be bumping my own thread, but I managed to shorten the sed command a bit after learning more about how it handles the search patterns. Here is the final version

-showIncludes | sed -n -e 's@^Note: including file: *\(.\):\\\(.*\)@$*.obj:"/cygdrive/\1/\2"@gp' | sed -e 's@\\@/@g' > depends.d

I hope someone out there might find this useful!