201 lines
6.7 KiB
Awk
201 lines
6.7 KiB
Awk
# 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;"
|
|
}
|