Fix library dependencies when the prefix is specified explicitly.
[scons.git] / src / engine / SCons / Defaults.py
1 """SCons.Defaults
2
3 Builders and other things for the local site.  Here's where we'll
4 duplicate the functionality of autoconf until we move it into the
5 installation procedure or use something like qmconf.
6
7 The code that reads the registry to find MSVC components was borrowed
8 from distutils.msvccompiler.
9
10 """
11
12 #
13 # __COPYRIGHT__
14 #
15 # Permission is hereby granted, free of charge, to any person obtaining
16 # a copy of this software and associated documentation files (the
17 # "Software"), to deal in the Software without restriction, including
18 # without limitation the rights to use, copy, modify, merge, publish,
19 # distribute, sublicense, and/or sell copies of the Software, and to
20 # permit persons to whom the Software is furnished to do so, subject to
21 # the following conditions:
22 #
23 # The above copyright notice and this permission notice shall be included
24 # in all copies or substantial portions of the Software.
25 #
26 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
27 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
28 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 #
34
35 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
36
37
38
39 import os
40 import string
41 import os.path
42
43 import SCons.Action
44 import SCons.Builder
45 import SCons.Node.Alias
46 import SCons.Node.FS
47 import SCons.Scanner.C
48 import SCons.Scanner.Fortran
49 import SCons.Scanner.Prog
50
51 def alias_builder(env, target, source):
52     pass
53
54 Alias = SCons.Builder.Builder(action = alias_builder,
55                               target_factory = SCons.Node.Alias.default_ans.Alias,
56                               source_factory = SCons.Node.FS.default_fs.Entry,
57                               multi = 1)
58
59 CScan = SCons.Scanner.C.CScan()
60
61 FortranScan = SCons.Scanner.Fortran.FortranScan()
62
63 def yaccEmitter(target, source, env, **kw):
64     # Yacc can be configured to emit a .h file as well
65     # as a .c file, if -d is specified on the command line.
66     if len(source) and \
67        os.path.splitext(SCons.Util.to_String(source[0]))[1] in \
68        [ '.y', '.yy'] and \
69        '-d' in string.split(env.subst("$YACCFLAGS")):
70         target.append(os.path.splitext(SCons.Util.to_String(target[0]))[0] + \
71                       '.h')
72     return (target, source)
73
74 def CFile():
75     """Common function to generate a C file Builder."""
76     return SCons.Builder.Builder(action = {},
77                                  emitter = yaccEmitter,
78                                  suffix = '$CFILESUFFIX')
79
80 def CXXFile():
81     """Common function to generate a C++ file Builder."""
82     return SCons.Builder.Builder(action = {},
83                                  emitter = yaccEmitter,
84                                  suffix = '$CXXFILESUFFIX')
85
86 class SharedFlagChecker:
87     """This is a callable class that is used as
88     a build action for all objects, libraries, and programs.
89     Its job is to run before the "real" action that builds the
90     file, to make sure we aren't trying to link shared objects
91     into a static library/program, or static objects into a
92     shared library."""
93
94     def __init__(self, shared, set_target_flag):
95         self.shared = shared
96         self.set_target_flag = set_target_flag
97
98     def __call__(self, source, target, env, **kw):
99         if kw.has_key('shared'):
100             raise SCons.Errors.UserError, "The shared= parameter to Library() or Object() no longer works.\nUse SharedObject() or SharedLibrary() instead."
101         if self.set_target_flag:
102             for tgt in target:
103                 tgt.attributes.shared = self.shared
104
105         same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
106         if same == '0' or same == '' or same == 'False':
107             for src in source:
108                 if hasattr(src.attributes, 'shared'):
109                     if self.shared and not src.attributes.shared:
110                         raise SCons.Errors.UserError, "Source file: %s is static and is not compatible with shared target: %s" % (src, target[0])
111
112 SharedCheck = SCons.Action.Action(SharedFlagChecker(1, 0), None)
113 StaticCheck = SCons.Action.Action(SharedFlagChecker(0, 0), None)
114 SharedCheckSet = SCons.Action.Action(SharedFlagChecker(1, 1), None)
115 StaticCheckSet = SCons.Action.Action(SharedFlagChecker(0, 1), None)
116
117 CAction = SCons.Action.Action([ StaticCheckSet, "$CCCOM" ])
118 ShCAction = SCons.Action.Action([ SharedCheckSet, "$SHCCCOM" ])
119 CXXAction = SCons.Action.Action([ StaticCheckSet, "$CXXCOM" ])
120 ShCXXAction = SCons.Action.Action([ SharedCheckSet, "$SHCXXCOM" ])
121
122 F77Action = SCons.Action.Action([ StaticCheckSet, "$F77COM" ])
123 ShF77Action = SCons.Action.Action([ SharedCheckSet, "$SHF77COM" ])
124 F77PPAction = SCons.Action.Action([ StaticCheckSet, "$F77PPCOM" ])
125 ShF77PPAction = SCons.Action.Action([ SharedCheckSet, "$SHF77PPCOM" ])
126
127 ASAction = SCons.Action.Action([ StaticCheckSet, "$ASCOM" ])
128 ASPPAction = SCons.Action.Action([ StaticCheckSet, "$ASPPCOM" ])
129
130
131 def StaticObject():
132     """A function for generating the static object Builder."""
133     return SCons.Builder.Builder(action = {},
134                                  emitter="$OBJEMITTER",
135                                  prefix = '$OBJPREFIX',
136                                  suffix = '$OBJSUFFIX',
137                                  src_builder = ['CFile', 'CXXFile'])
138
139 def SharedObject():
140     """A function for generating the shared object Builder."""
141     return SCons.Builder.Builder(action = {},
142                                  prefix = '$SHOBJPREFIX',
143                                  suffix = '$SHOBJSUFFIX',
144                                  emitter="$OBJEMITTER",
145                                  src_builder = ['CFile', 'CXXFile'])
146
147 ProgScan = SCons.Scanner.Prog.ProgScan()
148
149 StaticLibrary = SCons.Builder.Builder(action=[ StaticCheck, "$ARCOM" ],
150                                       prefix = '$LIBPREFIX',
151                                       suffix = '$LIBSUFFIX',
152                                       src_suffix = '$OBJSUFFIX',
153                                       src_builder = 'Object')
154
155 SharedLibrary = SCons.Builder.Builder(action=[ SharedCheck, "$SHLINKCOM" ],
156                                       emitter="$SHLIBEMITTER",
157                                       prefix = '$SHLIBPREFIX',
158                                       suffix = '$SHLIBSUFFIX',
159                                       scanner = ProgScan,
160                                       src_suffix = '$SHOBJSUFFIX',
161                                       src_builder = 'SharedObject')
162
163 def DVI():
164     """Common function to generate a DVI file Builder."""
165     return SCons.Builder.Builder(action = {},
166                                  # The suffix is not configurable via a
167                                  # construction variable like $DVISUFFIX
168                                  # because the output file name is
169                                  # hard-coded within TeX.
170                                  suffix = '.dvi')
171
172 def PDF():
173     """A function for generating the PDF Builder."""
174     return SCons.Builder.Builder(action = { },
175                                  prefix = '$PDFPREFIX',
176                                  suffix = '$PDFSUFFIX')
177
178 Program = SCons.Builder.Builder(action=[ StaticCheck, '$LINKCOM' ],
179                                 emitter='$PROGEMITTER',
180                                 prefix='$PROGPREFIX',
181                                 suffix='$PROGSUFFIX',
182                                 src_suffix='$OBJSUFFIX',
183                                 src_builder='Object',
184                                 scanner = ProgScan)
185
186 def _concat(prefix, list, suffix, locals, globals, f=lambda x: x):
187     """Creates a new list from 'list' by first interpolating each
188     element in the list using 'locals' and 'globals' and then calling f
189     on the list, and finally concatenating 'prefix' and 'suffix' onto
190     each element of the list. A trailing space on 'prefix' or leading
191     space on 'suffix' will cause them to be put into seperate list
192     elements rather than being concatenated."""
193
194     if not list:
195         return list
196
197     if not SCons.Util.is_List(list):
198         list = [list]
199
200     def subst(x, locals=locals, globals=globals):
201         if SCons.Util.is_String(x):
202             return SCons.Util.scons_subst(x, locals, globals)
203         else:
204             return x
205
206     list = map(subst, list)
207
208     list = f(list)
209
210     ret = []
211
212     # ensure that prefix and suffix are strings
213     prefix = str(prefix)
214     suffix = str(suffix)
215
216     for x in list:
217         x = str(x)
218
219         if prefix and prefix[-1] == ' ':
220             ret.append(prefix[:-1])
221             ret.append(x)
222         else:
223             ret.append(prefix+x)
224
225         if suffix and suffix[0] == ' ':
226             ret.append(suffix[1:])
227         else:
228             ret[-1] = ret[-1]+suffix
229
230     return ret
231
232 def _stripixes(prefix, list, suffix, locals, globals, stripprefix, stripsuffix, c=_concat):
233     """This is a wrapper around _concat() that checks for the existence
234     of prefixes or suffixes on list elements and strips them where it
235     finds them.  This is used by tools (like the GNU linker) that need
236     to turn something like 'libfoo.a' into '-lfoo'."""
237     def f(list, sp=stripprefix, ss=stripsuffix):
238         ret = []
239         for l in list:
240             if l[:len(sp)] == sp:
241                 l = l[len(sp):]
242             if l[-len(ss):] == ss:
243                 l = l[:-len(ss)]
244             ret.append(l)
245         return ret
246     return c(prefix, list, suffix, locals, globals, f)
247
248 ConstructionEnvironment = {
249     'BUILDERS'   : { 'SharedLibrary'  : SharedLibrary,
250                      'Library'        : StaticLibrary,
251                      'StaticLibrary'  : StaticLibrary,
252                      'Alias'          : Alias,
253                      'Program'        : Program },
254     'SCANNERS'   : [CScan, FortranScan],
255     'PDFPREFIX'  : '',
256     'PDFSUFFIX'  : '.pdf',
257     'PSPREFIX'   : '',
258     'PSSUFFIX'   : '.ps',
259     'ENV'        : {},
260     '_concat'     : _concat,
261     '_stripixes'  : _stripixes,
262     '_LIBFLAGS'    : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, locals(), globals())}',
263     '_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, locals(), globals(), RDirs)} $)',
264     '_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, locals(), globals(), RDirs)} $)',
265     '_F77INCFLAGS' : '$( ${_concat(INCPREFIX, F77PATH, INCSUFFIX, locals(), globals(), RDirs)} $)'
266     }