summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/gcc/genmultilib
blob: d4cc7ff7fe50d5a028e8e6a208ef8333f92a0d27 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#!/bin/sh 
# Generates multilib.h.
#   Copyright (C) 1994, 1995 Free Software Foundation, Inc.

#This file is part of GNU CC.

#GNU CC is free software; you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation; either version 2, or (at your option)
#any later version.

#GNU CC is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.

#You should have received a copy of the GNU General Public License
#along with GNU CC; see the file COPYING.  If not, write to
#the Free Software Foundation, 59 Temple Place - Suite 330,
#Boston, MA 02111-1307, USA.

# This shell script produces a header file which the gcc driver
# program uses to pick which library to use based on the machine
# specific options that it is given.

# The first argument is a list of sets of options.  The elements in
# the list are separated by spaces.  Within an element, the options
# are separated by slashes.  No leading dash is used on the options.
# Each option in a set is mutually incompatible with all other options
# in the set.

# The optional second argument is a list of subdirectory names.  If
# the second argument is non-empty, there must be as many elements in
# the second argument as there are options in the first argument.  The
# elements in the second list are separated by spaces.  If the second
# argument is empty, the option names will be used as the directory
# names.

# The optional third argument is a list of options which are
# identical.  The elements in the list are separated by spaces.  Each
# element must be of the form OPTION=OPTION.  The first OPTION should
# appear in the first argument, and the second should be a synonym for
# it.  Question marks are replaced with equal signs in both options.

# The output looks like
#   #define MULTILIB_MATCHES "\
#   SUBDIRECTORY OPTIONS;\
#   ...
#   "
# The SUBDIRECTORY is the subdirectory to use.  The OPTIONS are
# multiple options separated by spaces.  Each option may start with an
# exclamation point.  gcc will consider each line in turn.  If none of
# the options beginning with an exclamation point are present, and all
# of the other options are present, that subdirectory will be used.
# The order of the subdirectories is such that they can be created in
# order; that is, a subdirectory is preceded by all its parents.

# Here is a example (this is simplified from the actual 680x0 case):
#   genmultilib "m68000/m68020 msoft-float" "m68000 m68020 msoft-float"
#		"m68000=mc68000"
# This produces:
#   #define MULTILIB_SELECT "\
#   . !m68000 !mc68000 !m68020 !msoft-float;\
#   m68000 m68000 !m68020 !msoft-float;\
#   m68000 mc60000 !m68020 !msoft-float;\
#   m68020 !m68000 !mc68000 m68020 !msoft-float;\
#   msoft-float !m68000 !mc68000 !m68020 msoft-float;\
#   m68000/msoft-float m68000 !m68020 msoft-float;\
#   m68000/msoft-float mc68000 !m68020 msoft-float;\
#   m68020/msoft-float !m68000 !mc68000 m68020 msoft-float;\
#   "
# The effect is that `gcc -msoft-float' (for example) will append
# msoft-float to the directory name when searching for libraries or
# startup files, and `gcc -m68000 -msoft-float' (for example) will
# append m68000/msoft-float.

# Copy the positional parameters into variables.
options=$1
dirnames=$2
matches=$3

# What we want to do is select all combinations of the sets in
# options.  Each combination which includes a set of mutually
# exclusive options must then be output multiple times, once for each
# item in the set.  Selecting combinations is a recursive process.
# Since not all versions of sh support functions, we achieve recursion
# by creating a temporary shell script which invokes itself.
rm -f tmpmultilib
cat >tmpmultilib <<\EOF
#!/bin/sh
# This recursive script basically outputs all combinations of its
# input arguments, handling mutually exclusive sets of options by
# repetition.  When the script is called, ${initial} is the list of
# options which should appear before all combinations this will
# output.  The output looks like a list of subdirectory names with
# leading and trailing slashes.
if [ "$#" != "0" ]; then
  first=$1
  shift
  for opt in `echo $first | sed -e 's|/| |'g`; do
    echo ${initial}${opt}/
  done
  ./tmpmultilib $@
  for opt in `echo $first | sed -e 's|/| |'g`; do
    initial="${initial}${opt}/" ./tmpmultilib $@
  done
fi
EOF
chmod +x tmpmultilib

combinations=`initial=/ ./tmpmultilib ${options}`

rm -f tmpmultilib

# Construct a sed pattern which will convert option names to directory
# names.
todirnames=
if [ -n "${dirnames}" ]; then
  set x ${dirnames}
  shift
  for set in ${options}; do
    for opt in `echo ${set} | sed -e 's|/| |'g`; do
      if [ "$1" != "${opt}" ]; then
        todirnames="${todirnames} -e s|/${opt}/|/${1}/|g"
      fi
      shift
    done
  done
fi

# Construct a sed pattern which will add negations based on the
# matches.  The semicolons are easier than getting the shell to accept
# quoted spaces when expanding a variable.
matchnegations=
for i in ${matches}; do
  l=`echo $i | sed -e 's/=.*$//' -e 's/?/=/g'`
  r=`echo $i | sed -e 's/^.*=//' -e 's/?/=/g'`
  matchnegations="${matchnegations} -e s/;!${l};/;!${l};!${r};/"
done

# We need another recursive shell script to correctly handle positive
# matches.  If we are invoked as
#   genmultilib "opt1 opt2" "" "opt1=nopt1 opt2=nopt2"
# we must output
#   opt1/opt2 opt1 opt2
#   opt1/opt2 nopt1 opt2
#   opt1/opt2 opt1 nopt2
#   opt1/opt2 nopt1 nopt2
# In other words, we must output all combinations of matches.
rm -f tmpmultilib2
cat >tmpmultilib2 <<\EOF
#!/bin/sh
# The positional parameters are a list of matches to consider.
# ${dirout} is the directory name and ${optout} is the current list of
# options.
if [ "$#" = "0" ]; then
  echo "${dirout} ${optout};\\"
else
  first=$1
  shift
  dirout="${dirout}" optout="${optout}" ./tmpmultilib2 $@
  l=`echo ${first} | sed -e 's/=.*$//' -e 's/?/=/g'`
  r=`echo ${first} | sed -e 's/^.*=//' -e 's/?/=/g'`
  if expr " ${optout} " : ".* ${l} .*" > /dev/null; then
    newopt=`echo " ${optout} " | sed -e "s/ ${l} / ${r} /" -e 's/^ //' -e 's/ $//'`
    dirout="${dirout}" optout="${newopt}" ./tmpmultilib2 $@
  fi
fi
EOF
chmod +x tmpmultilib2

# We are ready to start output.
echo '#define MULTILIB_SELECT "\'

# Start with the current directory, which includes only negations.
optout=
for set in ${options}; do
  for opt in `echo ${set} | sed -e 's|/| |'g`; do
    optout="${optout} !${opt}"
  done
done
optout=`echo ${optout} | sed -e 's/^ //'`
if [ -n "${matchnegations}" ]; then
  optout=`echo ";${optout};" | sed -e 's/ /;/g' ${matchnegations} -e 's/^;//' -e 's/;$//' -e 's/;/ /g'`
fi
echo ". ${optout};\\"

# Work over the list of combinations.  We have to translate each one
# to use the directory names rather than the option names, we have to
# include the information in matches, and we have to generate the
# correct list of options and negations.
for combo in ${combinations}; do
  # Use the directory names rather than the option names.
  if [ -n "${todirnames}" ]; then
    dirout=`echo ${combo} | sed ${todirnames}`
  else
    dirout=${combo}
  fi
  # Remove the leading and trailing slashes.
  dirout=`echo ${dirout} | sed -e 's|^/||' -e 's|/$||g'`

  # Look through the options.  We must output each option that is
  # present, and negate each option that is not present.
  optout=
  for set in ${options}; do
    setopts=`echo ${set} | sed -e 's|/| |g'`
    for opt in ${setopts}; do
      if expr "${combo} " : ".*/${opt}/.*" > /dev/null; then
	optout="${optout} ${opt}"
      else
	optout="${optout} !${opt}"
      fi
    done
  done
  optout=`echo ${optout} | sed -e 's/^ //'`

  # Add any negations of matches.
  if [ -n "${matchnegations}" ]; then
    optout=`echo ";${optout};" | sed -e 's/ /;/g' ${matchnegations} -e 's/^;//' -e 's/;$//' -e 's/;/ /g'`
  fi

  # Output the line with all appropriate matches.
  dirout="${dirout}" optout="${optout}" ./tmpmultilib2 ${matches}
done

rm -f tmpmultilib2

# That's it.
echo '"'

exit 0