1# Copyright (C) 2010 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14#
15
16# This script is used to generate a Makefile fragment that will be evaluated
17# at runtime by the NDK build system during its initialization pass.
18#
19# The purpose of this generated fragment is to define a function, named
20# 'cygwin-to-host-path' that will transform a Cygwin-specific path into the
21# corresponding Windows specific one, i.e. calling
22#
23#   $(call cygwin-to-host-path,/cygdrive/c/Stuff/)  --> c:/Stuff
24#
25# A naive implementation of this function would be the following:
26#
27#   cygwin-to-host-path = $(shell cygpath -m $1)
28#
29# Unfortunately, calling 'cygpath -m' from GNU Make is horridly slow and people
30# have complained that this was adding several minutes to their builds, even in
31# the case where there is nothing to do.
32#
33# The script expects its input to be the output of the Cygwin "mount" command
34# as in:
35#
36#  C:/cygwin/bin on /usr/bin type ntfs (binary,auto)
37#  C:/cygwin/lib on /usr/lib type ntfs (binary,auto)
38#  C:/cygwin on / type ntfs (binary,auto)
39#  C: on /cygdrive/c type ntfs (binary,posix=0,user,noumount,auto)
40#  D: on /cygdrive/d type udf (binary,posix=0,user,noumount,auto)
41#
42# The script's output will be passed to the GNU Make 'eval' function
43# and will look like:
44#
45#  $(patsubst /%,C:/cygwin/,
46#  $(patsubst /usr/bin/%,C:/cygwin/bin/,
47#  $(patsubst /usr/lib/%,C:/cygwin/lib/,
48#  $(patsubst /cygdrive/C/%,C:/,
49#  $(patsubst /cygdrive/D/%,D:/,
50#  $(patsubst /cygdrive/c/%,C:/,
51#  $(patsubst /cygdrive/d/%,D:/,$1)))))
52#
53BEGIN {
54  # setup our count
55  count = 0
56}
57
58$2 == "on" {
59    # record a new (host-path,cygwin-path) pair
60    count ++
61    host[count] = $1
62    cygwin[count] = $3
63}
64
65END {
66    # Drive letters are special cases because we must match both
67    # the upper and lower case versions to the same drive, i.e.
68    # if "mount" lists that /cygdrive/c maps to C:, we need to
69    # map both /cygdrive/c and /cygdrive/C to C: in our final rules.
70    #
71    count1 = count
72    for (nn = 1; nn <= count1; nn++) {
73        if (!match(host[nn],"^[A-Za-z]:$")) {
74            # not a driver letter mapping, skip this pair
75            continue
76        }
77        letter = substr(host[nn],1,1)
78        lo     = tolower(letter)
79        up     = toupper(letter)
80
81        # If the cygwin path ends in /<lo>, then substitute it with /<up>
82        # to create a new pair.
83        if (match(cygwin[nn],"/"lo"$")) {
84            count++
85            host[count] = host[nn]
86            cygwin[count] = substr(cygwin[nn],1,length(cygwin[nn])-1) up
87            continue
88        }
89
90        # If the cygwin path ends in /<up>, then substitute it with /<lo>
91        # to create a new pair.
92        if (match(cygwin[nn],"/"up"$")) {
93            count++
94            host[count] = host[nn]
95            cygwin[count] = substr(cygwin[nn],1,length(cygwin[nn])-1) lo
96            continue
97        }
98    }
99
100    # We have recorded all (host,cygwin) path pairs,
101    # now try to sort them so that the ones with the longest cygwin path
102    # appear first
103    for (ii = 2; ii <= count; ii++) {
104        for (jj = ii-1; jj > 0; jj--) {
105            if (length(cygwin[jj]) > length(cygwin[jj+1])) {
106                break;
107            }
108            if (length(cygwin[jj]) == length(cygwin[jj+1]) &&
109                cygwin[jj] > cygwin[jj+1]) {
110                break
111            }
112            tmp = cygwin[jj]
113            cygwin[jj] = cygwin[jj+1]
114            cygwin[jj+1] = tmp
115            tmp = host[jj]
116            host[jj] = host[jj+1]
117            host[jj+1] = tmp
118        }
119    }
120
121    # build/core/init.mk defines VERBOSE to 1 when it needs to dump the
122    # list of substitutions in a human-friendly format, generally when
123    # NDK_LOG is defined in the environment
124    #
125    # Otherwise, just generate the corresponding Make function definition
126    #
127    if (VERBOSE == 1) {
128        for (nn = 1; nn <= count; nn++) {
129            printf( "$(info %s => %s)", cygwin[nn], host[nn]);
130        }
131    } else {
132        RESULT = "$1"
133        for (nn = 1; nn <= count; nn++) {
134            add_drive_rule(host[nn], cygwin[nn])
135        }
136        print RESULT
137    }
138}
139
140function add_drive_rule (hostpath,cygpath)
141{
142    if (cygpath == "/") {
143        # Special case for /
144        RESULT = "$(patsubst /%," hostpath "/%,\n" RESULT ")"
145        return
146    }
147    # default rule otherwise
148    RESULT = "$(patsubst " cygpath "/%," hostpath "/%,\n" RESULT ")"
149}
150