Followon to PR #4348: more bool fixes
[scons.git] / SCons / Tool / mingw.py
blob0119444a71a5509ff42592c3084c12cda6cdefcc
1 # MIT License
3 # Copyright The SCons Foundation
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 """SCons.Tool.gcc
26 Tool-specific initialization for MinGW (http://www.mingw.org/)
28 There normally shouldn't be any need to import this module directly.
29 It will usually be imported through the generic SCons.Tool.Tool()
30 selection method.
32 """
34 import os
35 import os.path
36 import glob
38 import SCons.Action
39 import SCons.Builder
40 import SCons.Defaults
41 import SCons.Tool
42 import SCons.Util
44 # TODO: should this be synced with SCons/Platform/mingw.py:MINGW_DEFAULTPATHS
45 # i.e. either keep the same, or make sure there's only one?
46 mingw_base_paths = [
47 r'c:\MinGW\bin',
48 r'C:\cygwin64\bin',
49 r'C:\msys64',
50 r'C:\msys64\mingw64\bin',
51 r'C:\cygwin\bin',
52 r'C:\msys',
53 # Chocolatey mingw (pkg name for MinGW-w64) does not use ChocolateyToolsLocation
54 r'C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin',
56 # Chocolatey msys2 uses envvar ChocolateyToolsLocation to base the install
57 # location (unless the user supplied additional params). Try to reproduce:
58 choco = os.environ.get('ChocolateyToolsLocation')
59 if choco:
60 mingw_base_paths.append(choco + r'\msys64\bin')
63 def shlib_generator(target, source, env, for_signature):
64 cmd = SCons.Util.CLVar(['$SHLINK', '$SHLINKFLAGS'])
66 dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX')
67 if dll: cmd.extend(['-o', dll])
69 cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS'])
71 implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX')
72 if implib: cmd.append('-Wl,--out-implib,' + implib.get_string(for_signature))
74 def_target = env.FindIxes(target, 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX')
75 insert_def = env.subst("$WINDOWS_INSERT_DEF")
76 if insert_def not in ['', '0', 0] and def_target: \
77 cmd.append('-Wl,--output-def,' + def_target.get_string(for_signature))
79 return [cmd]
82 def shlib_emitter(target, source, env):
83 dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX')
84 no_import_lib = env.get('no_import_lib', 0)
86 if not dll:
87 raise SCons.Errors.UserError(
88 "A shared library should have exactly one target with the suffix: %s Target(s) are:%s" % \
89 (env.subst("$SHLIBSUFFIX"), ",".join([str(t) for t in target])))
91 if not no_import_lib and \
92 not env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX'):
93 # Create list of target libraries as strings
94 targetStrings = env.ReplaceIxes(dll,
95 'SHLIBPREFIX', 'SHLIBSUFFIX',
96 'LIBPREFIX', 'LIBSUFFIX')
98 # Now add file nodes to target list
99 target.append(env.fs.File(targetStrings))
101 # Append a def file target if there isn't already a def file target
102 # or a def file source or the user has explicitly asked for the target
103 # to be emitted.
104 def_source = env.FindIxes(source, 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX')
105 def_target = env.FindIxes(target, 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX')
106 skip_def_insert = env.subst("$WINDOWS_INSERT_DEF") in ['', '0', 0]
107 if not def_source and not def_target and not skip_def_insert:
108 # Create list of target libraries and def files as strings
109 targetStrings = env.ReplaceIxes(dll,
110 'SHLIBPREFIX', 'SHLIBSUFFIX',
111 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX')
113 # Now add file nodes to target list
114 target.append(env.fs.File(targetStrings))
116 return (target, source)
119 shlib_action = SCons.Action.Action(shlib_generator, '$SHLINKCOMSTR', generator=1)
120 ldmodule_action = SCons.Action.Action(shlib_generator, '$LDMODULECOMSTR', generator=1)
122 res_action = SCons.Action.Action('$RCCOM', '$RCCOMSTR')
124 res_builder = SCons.Builder.Builder(action=res_action, suffix='.o',
125 source_scanner=SCons.Tool.SourceFileScanner)
126 SCons.Tool.SourceFileScanner.add_scanner('.rc', SCons.Defaults.CScan)
128 # This is what we search for to find mingw:
129 # key_program = 'mingw32-gcc'
130 key_program = 'mingw32-make'
133 def find_version_specific_mingw_paths():
134 r"""
135 One example of default mingw install paths is:
136 C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev2\mingw64\bin
138 Use glob'ing to find such and add to mingw_base_paths
140 new_paths = glob.glob(r"C:\mingw-w64\*\mingw64\bin")
142 return new_paths
145 _mingw_all_paths = None
147 def get_mingw_paths():
148 global _mingw_all_paths
149 if _mingw_all_paths is None:
150 _mingw_all_paths = mingw_base_paths + find_version_specific_mingw_paths()
151 return _mingw_all_paths
153 def generate(env) -> None:
154 # Check for reasoanble mingw default paths
155 mingw_paths = get_mingw_paths()
157 mingw = SCons.Tool.find_program_path(env, key_program, default_paths=mingw_paths)
158 if mingw:
159 mingw_bin_dir = os.path.dirname(mingw)
161 # Adjust path if we found it in a chocolatey install
162 if mingw_bin_dir == r'C:\ProgramData\chocolatey\bin':
163 mingw_bin_dir = r'C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin'
165 env.AppendENVPath('PATH', mingw_bin_dir)
167 # Most of mingw is the same as gcc and friends...
168 gnu_tools = ['gcc', 'g++', 'gnulink', 'ar', 'gas', 'gfortran', 'm4']
169 for tool in gnu_tools:
170 SCons.Tool.Tool(tool)(env)
172 # ... but a few things differ:
173 env['CC'] = 'gcc'
174 # make sure the msvc tool doesnt break us, it added a /flag
175 if 'CCFLAGS' in env:
176 # make sure its a CLVar to handle list or str cases
177 if type(env['CCFLAGS']) is not SCons.Util.CLVar:
178 env['CCFLAGS'] = SCons.Util.CLVar(env['CCFLAGS'])
179 env['CCFLAGS'] = SCons.Util.CLVar(str(env['CCFLAGS']).replace('/nologo', ''))
180 env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
181 env['CXX'] = 'g++'
182 env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS')
183 env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared')
184 env['SHLINKCOM'] = shlib_action
185 env['SHLINKCOMSTR'] = shlib_generator
186 env['LDMODULECOM'] = ldmodule_action
187 env.Append(SHLIBEMITTER=[shlib_emitter])
188 env.Append(LDMODULEEMITTER=[shlib_emitter])
189 env['AS'] = 'as'
191 env['WINDOWSDEFPREFIX'] = ''
192 env['WINDOWSDEFSUFFIX'] = '.def'
194 env['SHOBJSUFFIX'] = '.o'
195 env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
196 env['RC'] = 'windres'
197 env['RCFLAGS'] = SCons.Util.CLVar('')
198 env['RCINCFLAGS'] = '${_concat(RCINCPREFIX, CPPPATH, RCINCSUFFIX, __env__, RDirs, TARGET, SOURCE, affect_signature=False)}'
199 env['RCINCPREFIX'] = '--include-dir '
200 env['RCINCSUFFIX'] = ''
201 env['RCCOM'] = '$RC $_CPPDEFFLAGS $RCINCFLAGS ${RCINCPREFIX} ${SOURCE.dir} $RCFLAGS -i $SOURCE -o $TARGET'
202 env['BUILDERS']['RES'] = res_builder
204 # Some setting from the platform also have to be overridden:
205 env['OBJSUFFIX'] = '.o'
206 env['LIBPREFIX'] = 'lib'
207 env['LIBSUFFIX'] = '.a'
208 env['PROGSUFFIX'] = '.exe'
210 # Handle new versioned shared library logic
211 env['_SHLIBSUFFIX'] = '$SHLIBSUFFIX'
212 env["SHLIBPREFIX"] = ""
214 # Disable creating symlinks for versioned shared library.
215 env['SHLIBNOVERSIONSYMLINKS'] = True
216 env['LDMODULENOVERSIONSYMLINKS'] = True
217 env['IMPLIBNOVERSIONSYMLINKS'] = True
221 def exists(env):
222 mingw_paths = get_mingw_paths()
223 mingw = SCons.Tool.find_program_path(env, key_program, default_paths=mingw_paths)
224 if mingw:
225 mingw_bin_dir = os.path.dirname(mingw)
226 env.AppendENVPath('PATH', mingw_bin_dir)
228 return mingw
230 # Local Variables:
231 # tab-width:4
232 # indent-tabs-mode:nil
233 # End:
234 # vim: set expandtab tabstop=4 shiftwidth=4: