1"""llvm
2
3Tool-specific initialization for LLVM
4
5"""
6
7#
8# Copyright (c) 2009 VMware, Inc.
9#
10# Permission is hereby granted, free of charge, to any person obtaining
11# a copy of this software and associated documentation files (the
12# "Software"), to deal in the Software without restriction, including
13# without limitation the rights to use, copy, modify, merge, publish,
14# distribute, sublicense, and/or sell copies of the Software, and to
15# permit persons to whom the Software is furnished to do so, subject to
16# the following conditions:
17#
18# The above copyright notice and this permission notice shall be included
19# in all copies or substantial portions of the Software.
20#
21# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
22# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
23# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28#
29
30import os
31import os.path
32import re
33import platform as host_platform
34import sys
35import distutils.version
36
37import SCons.Errors
38import SCons.Util
39
40
41required_llvm_version = '3.9'
42
43
44def generate(env):
45    env['llvm'] = False
46
47    try:
48        llvm_dir = os.environ['LLVM']
49    except KeyError:
50        # Do nothing -- use the system headers/libs
51        llvm_dir = None
52    else:
53        if not os.path.isdir(llvm_dir):
54            raise SCons.Errors.InternalError("Specified LLVM directory not found")
55
56        if env['debug']:
57            llvm_subdir = 'Debug'
58        else:
59            llvm_subdir = 'Release'
60
61        llvm_bin_dir = os.path.join(llvm_dir, llvm_subdir, 'bin')
62        if not os.path.isdir(llvm_bin_dir):
63            llvm_bin_dir = os.path.join(llvm_dir, 'bin')
64            if not os.path.isdir(llvm_bin_dir):
65                raise SCons.Errors.InternalError("LLVM binary directory not found")
66
67        env.PrependENVPath('PATH', llvm_bin_dir)
68
69    if env['platform'] == 'windows':
70        # XXX: There is no llvm-config on Windows, so assume a standard layout
71        if llvm_dir is None:
72            print('scons: LLVM environment variable must be specified when building for windows')
73            return
74
75        # Try to determine the LLVM version from llvm/Config/config.h
76        llvm_config = os.path.join(llvm_dir, 'include/llvm/Config/llvm-config.h')
77        if not os.path.exists(llvm_config):
78            print('scons: could not find %s' % llvm_config)
79            return
80        llvm_version_major_re = re.compile(r'^#define LLVM_VERSION_MAJOR ([0-9]+)')
81        llvm_version_minor_re = re.compile(r'^#define LLVM_VERSION_MINOR ([0-9]+)')
82        llvm_version = None
83        llvm_version_major = None
84        llvm_version_minor = None
85        for line in open(llvm_config, 'rt'):
86            mo = llvm_version_major_re.match(line)
87            if mo:
88                llvm_version_major = mo.group(1)
89            mo = llvm_version_minor_re.match(line)
90            if mo:
91                llvm_version_minor = mo.group(1)
92        if llvm_version_major is not None and llvm_version_minor is not None:
93            llvm_version = distutils.version.LooseVersion('%s.%s' % (llvm_version_major, llvm_version_minor))
94
95        if llvm_version is None:
96            print('scons: could not determine the LLVM version from %s' % llvm_config)
97            return
98        if llvm_version < distutils.version.LooseVersion(required_llvm_version):
99            print('scons: LLVM version %s found, but %s is required' % (llvm_version, required_llvm_version))
100            return
101
102        env.Prepend(CPPPATH = [os.path.join(llvm_dir, 'include')])
103        env.Prepend(LIBPATH = [os.path.join(llvm_dir, 'lib')])
104
105        # LLVM 5.0 and newer requires MinGW w/ pthreads due to use of std::thread and friends.
106        if llvm_version >= distutils.version.LooseVersion('5.0') and env['crosscompile']:
107            assert env['gcc']
108            env.AppendUnique(CXXFLAGS = ['-posix'])
109
110        # LIBS should match the output of `llvm-config --libs engine mcjit bitwriter x86asmprinter irreader` for LLVM<=7.0
111        # and `llvm-config --libs engine coroutines` for LLVM>=8.0
112        # LLVMAggressiveInstCombine library part of engine component since LLVM 6 is only needed by Mesa3D for LLVM>=8.
113        # While not directly needed by Mesa3D, this library is needed by LLVMipo which is part of coroutines component.
114        if llvm_version >= distutils.version.LooseVersion('11.0'):
115            env.Prepend(LIBS = [
116                'LLVMX86Disassembler', 'LLVMX86AsmParser',
117                'LLVMX86CodeGen', 'LLVMSelectionDAG', 'LLVMAsmPrinter',
118                'LLVMDebugInfoCodeView', 'LLVMCodeGen',
119                'LLVMScalarOpts', 'LLVMInstCombine',
120                'LLVMTransformUtils',
121                'LLVMBitWriter', 'LLVMX86Desc',
122                'LLVMMCDisassembler', 'LLVMX86Info',
123                'LLVMMCJIT', 'LLVMExecutionEngine', 'LLVMTarget',
124                'LLVMAnalysis', 'LLVMProfileData',
125                'LLVMRuntimeDyld', 'LLVMObject', 'LLVMMCParser',
126                'LLVMBitReader', 'LLVMMC', 'LLVMCore',
127                'LLVMSupport',
128                'LLVMIRReader', 'LLVMAsmParser',
129                'LLVMDemangle', 'LLVMGlobalISel', 'LLVMDebugInfoMSF',
130                'LLVMBinaryFormat',
131                'LLVMRemarks', 'LLVMBitstreamReader', 'LLVMDebugInfoDWARF',
132                'LLVMAggressiveInstCombine','LLVMLinker', 'LLVMVectorize',
133                'LLVMInstrumentation', 'LLVMipo', 'LLVMCoroutines',
134                'LLVMCFGuard', 'LLVMTextAPI',
135                'LLVMFrontendOpenMP',
136            ])
137        elif llvm_version >= distutils.version.LooseVersion('10.0'):
138            env.Prepend(LIBS = [
139                'LLVMX86Disassembler', 'LLVMX86AsmParser',
140                'LLVMX86CodeGen', 'LLVMSelectionDAG', 'LLVMAsmPrinter',
141                'LLVMDebugInfoCodeView', 'LLVMCodeGen',
142                'LLVMScalarOpts', 'LLVMInstCombine',
143                'LLVMTransformUtils',
144                'LLVMBitWriter', 'LLVMX86Desc',
145                'LLVMMCDisassembler', 'LLVMX86Info',
146                'LLVMX86Utils',
147                'LLVMMCJIT', 'LLVMExecutionEngine', 'LLVMTarget',
148                'LLVMAnalysis', 'LLVMProfileData',
149                'LLVMRuntimeDyld', 'LLVMObject', 'LLVMMCParser',
150                'LLVMBitReader', 'LLVMMC', 'LLVMCore',
151                'LLVMSupport',
152                'LLVMIRReader', 'LLVMAsmParser',
153                'LLVMDemangle', 'LLVMGlobalISel', 'LLVMDebugInfoMSF',
154                'LLVMBinaryFormat',
155                'LLVMRemarks', 'LLVMBitstreamReader', 'LLVMDebugInfoDWARF',
156                'LLVMAggressiveInstCombine','LLVMLinker', 'LLVMVectorize',
157                'LLVMInstrumentation', 'LLVMipo', 'LLVMCoroutines',
158                'LLVMCFGuard', 'LLVMTextAPI',
159            ])
160        elif llvm_version >= distutils.version.LooseVersion('9.0'):
161            env.Prepend(LIBS = [
162                'LLVMX86Disassembler', 'LLVMX86AsmParser',
163                'LLVMX86CodeGen', 'LLVMSelectionDAG', 'LLVMAsmPrinter',
164                'LLVMDebugInfoCodeView', 'LLVMCodeGen',
165                'LLVMScalarOpts', 'LLVMInstCombine',
166                'LLVMTransformUtils',
167                'LLVMBitWriter', 'LLVMX86Desc',
168                'LLVMMCDisassembler', 'LLVMX86Info',
169                'LLVMX86Utils',
170                'LLVMMCJIT', 'LLVMExecutionEngine', 'LLVMTarget',
171                'LLVMAnalysis', 'LLVMProfileData',
172                'LLVMRuntimeDyld', 'LLVMObject', 'LLVMMCParser',
173                'LLVMBitReader', 'LLVMMC', 'LLVMCore',
174                'LLVMSupport',
175                'LLVMIRReader', 'LLVMAsmParser',
176                'LLVMDemangle', 'LLVMGlobalISel', 'LLVMDebugInfoMSF',
177                'LLVMBinaryFormat',
178                'LLVMRemarks', 'LLVMBitstreamReader', 'LLVMDebugInfoDWARF',
179                # Add these libraries to enable ompute shaders support.
180                'LLVMAggressiveInstCombine','LLVMLinker', 'LLVMVectorize',
181                'LLVMInstrumentation', 'LLVMipo', 'LLVMCoroutines',
182            ])
183        elif llvm_version >= distutils.version.LooseVersion('8.0'):
184            env.Prepend(LIBS = [
185                'LLVMX86Disassembler', 'LLVMX86AsmParser',
186                'LLVMX86CodeGen', 'LLVMSelectionDAG', 'LLVMAsmPrinter',
187                'LLVMDebugInfoCodeView', 'LLVMCodeGen',
188                'LLVMScalarOpts', 'LLVMInstCombine',
189                'LLVMTransformUtils',
190                'LLVMBitWriter', 'LLVMX86Desc',
191                'LLVMMCDisassembler', 'LLVMX86Info',
192                'LLVMX86AsmPrinter', 'LLVMX86Utils',
193                'LLVMMCJIT', 'LLVMExecutionEngine', 'LLVMTarget',
194                'LLVMAnalysis', 'LLVMProfileData',
195                'LLVMRuntimeDyld', 'LLVMObject', 'LLVMMCParser',
196                'LLVMBitReader', 'LLVMMC', 'LLVMCore',
197                'LLVMSupport',
198                'LLVMIRReader', 'LLVMAsmParser',
199                'LLVMDemangle', 'LLVMGlobalISel', 'LLVMDebugInfoMSF',
200                'LLVMBinaryFormat',
201                # Add these libraries to enable ompute shaders support.
202                'LLVMAggressiveInstCombine', 'LLVMLinker', 'LLVMVectorize',
203                'LLVMInstrumentation', 'LLVMipo', 'LLVMCoroutines',
204            ])
205        elif llvm_version >= distutils.version.LooseVersion('5.0'):
206            env.Prepend(LIBS = [
207                'LLVMX86Disassembler', 'LLVMX86AsmParser',
208                'LLVMX86CodeGen', 'LLVMSelectionDAG', 'LLVMAsmPrinter',
209                'LLVMDebugInfoCodeView', 'LLVMCodeGen',
210                'LLVMScalarOpts', 'LLVMInstCombine',
211                'LLVMTransformUtils',
212                'LLVMBitWriter', 'LLVMX86Desc',
213                'LLVMMCDisassembler', 'LLVMX86Info',
214                'LLVMX86AsmPrinter', 'LLVMX86Utils',
215                'LLVMMCJIT', 'LLVMExecutionEngine', 'LLVMTarget',
216                'LLVMAnalysis', 'LLVMProfileData',
217                'LLVMRuntimeDyld', 'LLVMObject', 'LLVMMCParser',
218                'LLVMBitReader', 'LLVMMC', 'LLVMCore',
219                'LLVMSupport',
220                'LLVMIRReader', 'LLVMAsmParser',
221                'LLVMDemangle', 'LLVMGlobalISel', 'LLVMDebugInfoMSF',
222                'LLVMBinaryFormat',
223            ])
224        elif llvm_version >= distutils.version.LooseVersion('4.0'):
225            env.Prepend(LIBS = [
226                'LLVMX86Disassembler', 'LLVMX86AsmParser',
227                'LLVMX86CodeGen', 'LLVMSelectionDAG', 'LLVMAsmPrinter',
228                'LLVMDebugInfoCodeView', 'LLVMCodeGen',
229                'LLVMScalarOpts', 'LLVMInstCombine',
230                'LLVMTransformUtils',
231                'LLVMBitWriter', 'LLVMX86Desc',
232                'LLVMMCDisassembler', 'LLVMX86Info',
233                'LLVMX86AsmPrinter', 'LLVMX86Utils',
234                'LLVMMCJIT', 'LLVMExecutionEngine', 'LLVMTarget',
235                'LLVMAnalysis', 'LLVMProfileData',
236                'LLVMRuntimeDyld', 'LLVMObject', 'LLVMMCParser',
237                'LLVMBitReader', 'LLVMMC', 'LLVMCore',
238                'LLVMSupport',
239                'LLVMIRReader', 'LLVMAsmParser',
240                'LLVMDemangle', 'LLVMGlobalISel', 'LLVMDebugInfoMSF',
241            ])
242        else:
243            env.Prepend(LIBS = [
244                'LLVMX86Disassembler', 'LLVMX86AsmParser',
245                'LLVMX86CodeGen', 'LLVMSelectionDAG', 'LLVMAsmPrinter',
246                'LLVMDebugInfoCodeView', 'LLVMCodeGen',
247                'LLVMScalarOpts', 'LLVMInstCombine',
248                'LLVMInstrumentation', 'LLVMTransformUtils',
249                'LLVMBitWriter', 'LLVMX86Desc',
250                'LLVMMCDisassembler', 'LLVMX86Info',
251                'LLVMX86AsmPrinter', 'LLVMX86Utils',
252                'LLVMMCJIT', 'LLVMExecutionEngine', 'LLVMTarget',
253                'LLVMAnalysis', 'LLVMProfileData',
254                'LLVMRuntimeDyld', 'LLVMObject', 'LLVMMCParser',
255                'LLVMBitReader', 'LLVMMC', 'LLVMCore',
256                'LLVMSupport',
257                'LLVMIRReader', 'LLVMASMParser'
258            ])
259        env.Append(LIBS = [
260            'imagehlp',
261            'psapi',
262            'shell32',
263            'advapi32',
264            'ole32',
265            'uuid',
266        ])
267
268        # Mingw-w64 zlib is required when building with LLVM support in MSYS2 environment
269        if host_platform.system().lower().startswith('mingw'):
270            env.Append(LIBS = [
271                 'z',
272            ])
273
274        if env['msvc']:
275            # Some of the LLVM C headers use the inline keyword without
276            # defining it.
277            env.Append(CPPDEFINES = [('inline', '__inline')])
278            # Match some of the warning options from llvm/cmake/modules/HandleLLVMOptions.cmake
279            env.AppendUnique(CXXFLAGS = [
280                '/wd4355', # 'this' : used in base member initializer list
281                '/wd4624', # 'derived class' : destructor could not be generated because a base class destructor is inaccessible
282            ])
283            if env['build'] in ('debug', 'checked'):
284                # LLVM libraries are static, build with /MT, and they
285                # automatically link agains LIBCMT. When we're doing a
286                # debug build we'll be linking against LIBCMTD, so disable
287                # that.
288                env.Append(LINKFLAGS = ['/nodefaultlib:LIBCMT'])
289    else:
290        llvm_config = os.environ.get('LLVM_CONFIG', 'llvm-config')
291        if not env.Detect(llvm_config):
292            print('scons: %s script not found' % llvm_config)
293            return
294
295        llvm_version = env.backtick('%s --version' % llvm_config).rstrip()
296        llvm_version = distutils.version.LooseVersion(llvm_version)
297
298        if llvm_version < distutils.version.LooseVersion(required_llvm_version):
299            print('scons: LLVM version %s found, but %s is required' % (llvm_version, required_llvm_version))
300            return
301
302        try:
303            # Treat --cppflags specially to prevent NDEBUG from disabling
304            # assertion failures in debug builds.
305            cppflags = env.ParseFlags('!%s --cppflags' % llvm_config)
306            try:
307                cppflags['CPPDEFINES'].remove('NDEBUG')
308            except ValueError:
309                pass
310            env.MergeFlags(cppflags)
311
312            # Match llvm --fno-rtti flag
313            cxxflags = env.backtick('%s --cxxflags' % llvm_config).split()
314            if '-fno-rtti' in cxxflags:
315                env.Append(CXXFLAGS = ['-fno-rtti'])
316
317            if llvm_version < distutils.version.LooseVersion('9.0'):
318               components = ['engine', 'mcjit', 'bitwriter', 'x86asmprinter', 'mcdisassembler', 'irreader']
319            else:
320               components = ['engine', 'mcjit', 'bitwriter', 'mcdisassembler', 'irreader']
321
322            if llvm_version >= distutils.version.LooseVersion('8.0'):
323                components.append('coroutines')
324
325            env.ParseConfig('%s --libs ' % llvm_config + ' '.join(components))
326            env.ParseConfig('%s --ldflags' % llvm_config)
327            env.ParseConfig('%s --system-libs' % llvm_config)
328            env.Append(CXXFLAGS = ['-std=c++14'])
329        except OSError:
330            print('scons: llvm-config version %s failed' % llvm_version)
331            return
332
333    assert llvm_version is not None
334    env['llvm'] = True
335
336    print('scons: Found LLVM version %s' % llvm_version)
337    env['LLVM_VERSION'] = llvm_version
338
339    # Define LLVM_AVAILABLE macro to guard code blocks, and MESA_LLVM_VERSION_STRING
340    env.Prepend(CPPDEFINES = [('LLVM_AVAILABLE', 1)])
341    env.Prepend(CPPDEFINES = [('MESA_LLVM_VERSION_STRING=\\"%s\\"' % llvm_version)])
342
343def exists(env):
344    return True
345
346# vim:set ts=4 sw=4 et:
347