| # Copyright (C) 2011 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| |
| # This script is used to generate a shell script that will be |
| # run by the NDK build system to process dependency files generated by |
| # GCC on Windows, and convert them to a format that is suitable for |
| # Cygwin's GNU Make. |
| # |
| # The main issue to solve here is that the dependency files generated |
| # by GCC use native windows path names, as in: |
| # |
| # C:/Foo/foo.o: \ |
| # C:/Foo/src/foo.h \ |
| # C:/Foo/src/foo.c \ |
| # D:/Bar/bar/bar.h |
| # |
| # And the file needs to be processed to convert each such path into |
| # a Cygwin-specific one, as in: |
| # |
| # /cygdrive/c/Foo/foo.o: \ |
| # /cygdrive/c/Foo/src/foo.h \ |
| # /cygdrive/c/Foo/src/foo.c \ |
| # /cygdrive/d/Bar/bar/bar.h |
| # |
| # Previously, this conversion was done with an awk script that assumed |
| # that the cygwin drive prefix was always 'cygdrive'. This didn't work |
| # well when this was not the case, or when using drive-less mounts |
| # (e.g. when /home/mnt would map to //server/subdir) |
| # |
| # To solve the issue correctly, we need to parse the output of the |
| # Cygwin mount table (i.e. the output of the 'mount' command), and |
| # build a sed script that will properly replace host paths into the |
| # corresponding cygwin equivalent. |
| # |
| # NOTE: The sed script will be run during command execution, not during the |
| # parse phase. |
| # |
| # This awk script expects its input to be the output of the Cygwin "mount" command |
| # as in: |
| # |
| # C:/cygwin/bin on /usr/bin type ntfs (binary,auto) |
| # C:/cygwin/lib on /usr/lib type ntfs (binary,auto) |
| # C:/cygwin on / type ntfs (binary,auto) |
| # C: on /cygdrive/c type ntfs (binary,posix=0,user,noumount,auto) |
| # D: on /cygdrive/d type udf (binary,posix=0,user,noumount,auto) |
| # //server/subdir on /home/mnt.2$ type .... |
| # |
| # It first builds a sed script that convert all windows path in the |
| # an input file into the cygwin equivalent. For example, this would look |
| # like the following (but all on a single line): |
| # |
| # s!^//server/subdir!/home/mnt\.2\$!ig; |
| # s! //server/subdir! /home/mnt\.2\$!ig; |
| # s!^C:/cygwin/bin!/usr/bin!ig; |
| # s! C:/cygwin/bin! /usr/bin!ig; |
| # s!^C:/cygwin/lib!/usr/lib!ig; |
| # s! C:/cygwin/lib! /usr/lib!ig; |
| # s!^C:/cygwin/!/!ig; |
| # s! C:/cygwin/! /!ig; |
| # s!^C:!/cygdrive/c!ig; |
| # s! C:! /cygdrive/c!ig; |
| # s!^D:!/cygdrive/d!ig; |
| # s! D:! /cygdrive/d!ig; |
| # |
| # Note that we properly escape regex meta characters like . or $ |
| # to avoid confusing sed. Also deal with the cases where the path |
| # is the first in the line, or prefixed with a space in the deps file. |
| # |
| # After this, the sed invokation is hard-coded into a generated shell |
| # script that can be invoked directly at build time. |
| # |
| BEGIN { |
| # setup our count |
| count = 0 |
| } |
| |
| $2 == "on" { |
| # record a new (host-path,cygwin-path) pair |
| count ++ |
| |
| # Convert backwards slashes into forward ones in the host path. |
| # This is to support MSys' mount command, which outputs Windows-style |
| # separators, unlike Cygwin's version of the same tool. |
| gsub("\\\\","/",$1) |
| |
| host[count] = $1 |
| cygwin[count] = $3 |
| } |
| |
| END { |
| # We have recorded all (host,cygwin) path pairs, |
| # now try to sort them so that the ones with the longest host path |
| # appear first |
| for (ii = 2; ii <= count; ii++) { |
| for (jj = ii-1; jj > 0; jj--) { |
| if (length(host[jj]) > length(host[jj+1])) { |
| break; |
| } |
| if (length(host[jj]) == length(host[jj+1]) && |
| host[jj] > host[jj+1]) { |
| break |
| } |
| tmp = cygwin[jj] |
| cygwin[jj] = cygwin[jj+1] |
| cygwin[jj+1] = tmp |
| tmp = host[jj] |
| host[jj] = host[jj+1] |
| host[jj+1] = tmp |
| } |
| } |
| |
| # build/core/init.mk defines VERBOSE to 1 when it needs to dump the |
| # list of substitutions in a human-friendly format, generally when |
| # NDK_LOG is defined in the environment |
| # |
| # Otherwise, just generate the corresponding sed script |
| # |
| if (VERBOSE == 1) { |
| for (nn = 1; nn <= count; nn++) { |
| printf( "$(info %s => %s)", cygwin[nn], host[nn]); |
| } |
| } else { |
| RESULT = "" |
| for (nn = 1; nn <= count; nn++) { |
| add_drive_rule(host[nn], cygwin[nn]) |
| } |
| |
| # Note: the role of the generated shell script is to first check |
| # that $1.org exists. If this is not the case, this simply |
| # means that GCC didn't generate a depedency file (e.g. when |
| # compiling an assembler file). |
| # |
| # If the file exists, it is processed with our sed script, |
| # the output is written to $1, and we remove the original $1.org |
| # |
| print "#!/bin/sh" |
| print "# AUTO-GENERATED FILE, DO NOT EDIT!" |
| print "if [ -f $1.org ]; then" |
| print " sed -e '" RESULT "' $1.org > $1 && rm -f $1.org" |
| print "fi" |
| } |
| } |
| |
| # We need to quote some characters so that 'sed' doesn't |
| # believe they are regex operators. For example, if a path |
| # contains a dot (.), we need to escape it into "\." |
| # |
| function sed_quote_path (str) |
| { |
| # Windows path names cannot contain any of: <>:"|?* |
| # see msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx |
| # |
| # Anything else is valid. The regex meta characters are: ^.[]$()|*+?{}\ |
| # |
| # This means we need to escape these when they appear in path names: ^.[]$()+{}\ |
| # |
| gsub("\\^","\\^",str) |
| gsub("\\.","\\.",str) |
| gsub("\\[","\\[",str) |
| gsub("\\]","\\]",str) |
| gsub("\\$","\\$",str) |
| gsub("\\(","\\(",str) |
| gsub("\\)","\\)",str) |
| gsub("\\+","\\+",str) |
| gsub("\\{","\\{",str) |
| gsub("\\}","\\}",str) |
| |
| return str |
| } |
| |
| function add_drive_rule (hostpath,cygpath) |
| { |
| hostpath = sed_quote_path(hostpath) |
| cygpath = sed_quote_path(cygpath) |
| |
| # The root directory is a special case, because we need |
| # to add a slash at the end of the corresponding host path |
| # otherwise c:/cygwin/foo will be translated into //foo |
| # instead of /foo. |
| # |
| if (cygpath == "/") { |
| hostpath = hostpath "/" |
| } |
| # when the hostpath starts the line |
| RESULT = RESULT "s!^" hostpath "!" cygpath "!ig;" |
| |
| # when the hostpath does not start the line (it will always be after a space) |
| RESULT = RESULT "s! " hostpath "! " cygpath "!ig;" |
| } |