llvm.py 12.9 KB
Newer Older
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
"""llvm

Tool-specific initialization for LLVM

"""

#
# Copyright (c) 2009 VMware, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

import os
import os.path
32
import re
33
import sys
34
import distutils.version
35
36
37
38
39

import SCons.Errors
import SCons.Util


40
required_llvm_version = '3.3'
Jose Fonseca's avatar
Jose Fonseca committed
41
42


43
def generate(env):
44
45
    env['llvm'] = False

46
47
48
49
    try:
        llvm_dir = os.environ['LLVM']
    except KeyError:
        # Do nothing -- use the system headers/libs
50
        llvm_dir = None
51
52
    else:
        if not os.path.isdir(llvm_dir):
53
            raise SCons.Errors.InternalError("Specified LLVM directory not found")
54
55
56
57
58
59
60
61

        if env['debug']:
            llvm_subdir = 'Debug'
        else:
            llvm_subdir = 'Release'

        llvm_bin_dir = os.path.join(llvm_dir, llvm_subdir, 'bin')
        if not os.path.isdir(llvm_bin_dir):
62
63
            llvm_bin_dir = os.path.join(llvm_dir, 'bin')
            if not os.path.isdir(llvm_bin_dir):
64
                raise SCons.Errors.InternalError("LLVM binary directory not found")
65
66
67

        env.PrependENVPath('PATH', llvm_bin_dir)

68
    if env['platform'] == 'windows':
69
        # XXX: There is no llvm-config on Windows, so assume a standard layout
70
        if llvm_dir is None:
71
            print('scons: LLVM environment variable must be specified when building for windows')
72
            return
73
74

        # Try to determine the LLVM version from llvm/Config/config.h
75
        llvm_config = os.path.join(llvm_dir, 'include/llvm/Config/llvm-config.h')
76
        if not os.path.exists(llvm_config):
77
            print('scons: could not find %s' % llvm_config)
78
            return
79
80
        llvm_version_major_re = re.compile(r'^#define LLVM_VERSION_MAJOR ([0-9]+)')
        llvm_version_minor_re = re.compile(r'^#define LLVM_VERSION_MINOR ([0-9]+)')
81
        llvm_version = None
82
83
        llvm_version_major = None
        llvm_version_minor = None
84
        for line in open(llvm_config, 'rt'):
85
            mo = llvm_version_major_re.match(line)
86
            if mo:
87
88
89
90
91
92
93
                llvm_version_major = mo.group(1)
            mo = llvm_version_minor_re.match(line)
            if mo:
                llvm_version_minor = mo.group(1)
        if llvm_version_major is not None and llvm_version_minor is not None:
            llvm_version = distutils.version.LooseVersion('%s.%s' % (llvm_version_major, llvm_version_minor))

94
        if llvm_version is None:
95
            print('scons: could not determine the LLVM version from %s' % llvm_config)
96
            return
Jose Fonseca's avatar
Jose Fonseca committed
97
        if llvm_version < distutils.version.LooseVersion(required_llvm_version):
98
            print('scons: LLVM version %s found, but %s is required' % (llvm_version, required_llvm_version))
Jose Fonseca's avatar
Jose Fonseca committed
99
            return
100
101
102

        env.Prepend(CPPPATH = [os.path.join(llvm_dir, 'include')])
        env.Prepend(LIBPATH = [os.path.join(llvm_dir, 'lib')])
Ben Boeckel's avatar
Ben Boeckel committed
103
        # LIBS should match the output of `llvm-config --libs engine mcjit bitwriter x86asmprinter irreader`
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
        if llvm_version >= distutils.version.LooseVersion('5.0'):
            env.Prepend(LIBS = [
                'LLVMX86Disassembler', 'LLVMX86AsmParser',
                'LLVMX86CodeGen', 'LLVMSelectionDAG', 'LLVMAsmPrinter',
                'LLVMDebugInfoCodeView', 'LLVMCodeGen',
                'LLVMScalarOpts', 'LLVMInstCombine',
                'LLVMTransformUtils',
                'LLVMBitWriter', 'LLVMX86Desc',
                'LLVMMCDisassembler', 'LLVMX86Info',
                'LLVMX86AsmPrinter', 'LLVMX86Utils',
                'LLVMMCJIT', 'LLVMExecutionEngine', 'LLVMTarget',
                'LLVMAnalysis', 'LLVMProfileData',
                'LLVMRuntimeDyld', 'LLVMObject', 'LLVMMCParser',
                'LLVMBitReader', 'LLVMMC', 'LLVMCore',
                'LLVMSupport',
                'LLVMIRReader', 'LLVMAsmParser',
                'LLVMDemangle', 'LLVMGlobalISel', 'LLVMDebugInfoMSF',
                'LLVMBinaryFormat',
            ])
123
124
125
            if env['platform'] == 'windows' and env['crosscompile']:
                # LLVM 5.0 requires MinGW w/ pthreads due to use of std::thread and friends.
                assert env['gcc']
xantares's avatar
xantares committed
126
                env.AppendUnique(CXXFLAGS = ['-posix'])
127
        elif llvm_version >= distutils.version.LooseVersion('4.0'):
Ben Boeckel's avatar
Ben Boeckel committed
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
            env.Prepend(LIBS = [
                'LLVMX86Disassembler', 'LLVMX86AsmParser',
                'LLVMX86CodeGen', 'LLVMSelectionDAG', 'LLVMAsmPrinter',
                'LLVMDebugInfoCodeView', 'LLVMCodeGen',
                'LLVMScalarOpts', 'LLVMInstCombine',
                'LLVMTransformUtils',
                'LLVMBitWriter', 'LLVMX86Desc',
                'LLVMMCDisassembler', 'LLVMX86Info',
                'LLVMX86AsmPrinter', 'LLVMX86Utils',
                'LLVMMCJIT', 'LLVMExecutionEngine', 'LLVMTarget',
                'LLVMAnalysis', 'LLVMProfileData',
                'LLVMRuntimeDyld', 'LLVMObject', 'LLVMMCParser',
                'LLVMBitReader', 'LLVMMC', 'LLVMCore',
                'LLVMSupport',
                'LLVMIRReader', 'LLVMAsmParser',
                'LLVMDemangle', 'LLVMGlobalISel', 'LLVMDebugInfoMSF',
            ])
        elif llvm_version >= distutils.version.LooseVersion('3.9'):
George Kyriazis's avatar
George Kyriazis committed
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
            env.Prepend(LIBS = [
                'LLVMX86Disassembler', 'LLVMX86AsmParser',
                'LLVMX86CodeGen', 'LLVMSelectionDAG', 'LLVMAsmPrinter',
                'LLVMDebugInfoCodeView', 'LLVMCodeGen',
                'LLVMScalarOpts', 'LLVMInstCombine',
                'LLVMInstrumentation', 'LLVMTransformUtils',
                'LLVMBitWriter', 'LLVMX86Desc',
                'LLVMMCDisassembler', 'LLVMX86Info',
                'LLVMX86AsmPrinter', 'LLVMX86Utils',
                'LLVMMCJIT', 'LLVMExecutionEngine', 'LLVMTarget',
                'LLVMAnalysis', 'LLVMProfileData',
                'LLVMRuntimeDyld', 'LLVMObject', 'LLVMMCParser',
                'LLVMBitReader', 'LLVMMC', 'LLVMCore',
                'LLVMSupport',
                'LLVMIRReader', 'LLVMASMParser'
            ])
        elif llvm_version >= distutils.version.LooseVersion('3.7'):
Olivier Pena's avatar
Olivier Pena committed
163
164
165
166
167
168
169
170
171
172
173
174
            env.Prepend(LIBS = [
                'LLVMBitWriter', 'LLVMX86Disassembler', 'LLVMX86AsmParser',
                'LLVMX86CodeGen', 'LLVMSelectionDAG', 'LLVMAsmPrinter',
                'LLVMCodeGen', 'LLVMScalarOpts', 'LLVMProfileData',
                'LLVMInstCombine', 'LLVMInstrumentation', 'LLVMTransformUtils', 'LLVMipa',
                'LLVMAnalysis', 'LLVMX86Desc', 'LLVMMCDisassembler',
                'LLVMX86Info', 'LLVMX86AsmPrinter', 'LLVMX86Utils',
                'LLVMMCJIT', 'LLVMTarget', 'LLVMExecutionEngine',
                'LLVMRuntimeDyld', 'LLVMObject', 'LLVMMCParser',
                'LLVMBitReader', 'LLVMMC', 'LLVMCore', 'LLVMSupport'
            ])
        elif llvm_version >= distutils.version.LooseVersion('3.6'):
175
176
177
178
179
180
181
182
183
184
185
186
            env.Prepend(LIBS = [
                'LLVMBitWriter', 'LLVMX86Disassembler', 'LLVMX86AsmParser',
                'LLVMX86CodeGen', 'LLVMSelectionDAG', 'LLVMAsmPrinter',
                'LLVMCodeGen', 'LLVMScalarOpts', 'LLVMProfileData',
                'LLVMInstCombine', 'LLVMTransformUtils', 'LLVMipa',
                'LLVMAnalysis', 'LLVMX86Desc', 'LLVMMCDisassembler',
                'LLVMX86Info', 'LLVMX86AsmPrinter', 'LLVMX86Utils',
                'LLVMMCJIT', 'LLVMTarget', 'LLVMExecutionEngine',
                'LLVMRuntimeDyld', 'LLVMObject', 'LLVMMCParser',
                'LLVMBitReader', 'LLVMMC', 'LLVMCore', 'LLVMSupport'
            ])
        elif llvm_version >= distutils.version.LooseVersion('3.5'):
187
            env.Prepend(LIBS = [
188
                'LLVMMCDisassembler',
189
190
191
192
193
194
195
196
197
198
199
                'LLVMBitWriter', 'LLVMMCJIT', 'LLVMRuntimeDyld',
                'LLVMX86Disassembler', 'LLVMX86AsmParser', 'LLVMX86CodeGen',
                'LLVMSelectionDAG', 'LLVMAsmPrinter', 'LLVMX86Desc',
                'LLVMObject', 'LLVMMCParser', 'LLVMBitReader', 'LLVMX86Info',
                'LLVMX86AsmPrinter', 'LLVMX86Utils', 'LLVMJIT',
                'LLVMExecutionEngine', 'LLVMCodeGen', 'LLVMScalarOpts',
                'LLVMInstCombine', 'LLVMTransformUtils', 'LLVMipa',
                'LLVMAnalysis', 'LLVMTarget', 'LLVMMC', 'LLVMCore',
                'LLVMSupport'
            ])
        else:
200
            env.Prepend(LIBS = [
201
                'LLVMMCDisassembler',
202
203
204
                'LLVMBitWriter', 'LLVMX86Disassembler', 'LLVMX86AsmParser',
                'LLVMX86CodeGen', 'LLVMX86Desc', 'LLVMSelectionDAG',
                'LLVMAsmPrinter', 'LLVMMCParser', 'LLVMX86AsmPrinter',
205
                'LLVMX86Utils', 'LLVMX86Info', 'LLVMMCJIT', 'LLVMJIT',
206
207
208
209
210
                'LLVMExecutionEngine', 'LLVMCodeGen', 'LLVMScalarOpts',
                'LLVMInstCombine', 'LLVMTransformUtils', 'LLVMipa',
                'LLVMAnalysis', 'LLVMTarget', 'LLVMMC', 'LLVMCore',
                'LLVMSupport', 'LLVMRuntimeDyld', 'LLVMObject'
            ])
211
212
213
        env.Append(LIBS = [
            'imagehlp',
            'psapi',
214
            'shell32',
215
216
217
            'advapi32',
            'ole32',
            'uuid',
218
        ])
219

220
221
222
223
        if env['msvc']:
            # Some of the LLVM C headers use the inline keyword without
            # defining it.
            env.Append(CPPDEFINES = [('inline', '__inline')])
224
225
226
227
228
            # Match some of the warning options from llvm/cmake/modules/HandleLLVMOptions.cmake
            env.AppendUnique(CXXFLAGS = [
                '/wd4355', # 'this' : used in base member initializer list
                '/wd4624', # 'derived class' : destructor could not be generated because a base class destructor is inaccessible
            ])
229
            if env['build'] in ('debug', 'checked'):
230
231
232
233
234
                # LLVM libraries are static, build with /MT, and they
                # automatically link agains LIBCMT. When we're doing a
                # debug build we'll be linking against LIBCMTD, so disable
                # that.
                env.Append(LINKFLAGS = ['/nodefaultlib:LIBCMT'])
235
    else:
236
237
        llvm_config = os.environ.get('LLVM_CONFIG', 'llvm-config')
        if not env.Detect(llvm_config):
238
            print('scons: %s script not found' % llvm_config)
239
            return
240

241
        llvm_version = env.backtick('%s --version' % llvm_config).rstrip()
Jose Fonseca's avatar
Jose Fonseca committed
242
        llvm_version = distutils.version.LooseVersion(llvm_version)
243

Jose Fonseca's avatar
Jose Fonseca committed
244
        if llvm_version < distutils.version.LooseVersion(required_llvm_version):
245
            print('scons: LLVM version %s found, but %s is required' % (llvm_version, required_llvm_version))
Jose Fonseca's avatar
Jose Fonseca committed
246
247
            return

248
        try:
249
250
            # Treat --cppflags specially to prevent NDEBUG from disabling
            # assertion failures in debug builds.
251
            cppflags = env.ParseFlags('!%s --cppflags' % llvm_config)
252
253
254
255
256
257
            try:
                cppflags['CPPDEFINES'].remove('NDEBUG')
            except ValueError:
                pass
            env.MergeFlags(cppflags)

258
            # Match llvm --fno-rtti flag
259
            cxxflags = env.backtick('%s --cxxflags' % llvm_config).split()
260
261
262
            if '-fno-rtti' in cxxflags:
                env.Append(CXXFLAGS = ['-fno-rtti'])

George Kyriazis's avatar
George Kyriazis committed
263
            components = ['engine', 'mcjit', 'bitwriter', 'x86asmprinter', 'mcdisassembler', 'irreader']
264

265
266
            env.ParseConfig('%s --libs ' % llvm_config + ' '.join(components))
            env.ParseConfig('%s --ldflags' % llvm_config)
267
            if llvm_version >= distutils.version.LooseVersion('3.5'):
268
                env.ParseConfig('%s --system-libs' % llvm_config)
269
                env.Append(CXXFLAGS = ['-std=c++11'])
270
        except OSError:
271
            print('scons: llvm-config version %s failed' % llvm_version)
272
            return
273
274

    assert llvm_version is not None
275
    env['llvm'] = True
276

277
    print('scons: Found LLVM version %s' % llvm_version)
278
279
280
281
282
283
284
    env['LLVM_VERSION'] = llvm_version

    # Define HAVE_LLVM macro with the major/minor version number (e.g., 0x0206 for 2.6)
    llvm_version_major = int(llvm_version.version[0])
    llvm_version_minor = int(llvm_version.version[1])
    llvm_version_hex = '0x%02x%02x' % (llvm_version_major, llvm_version_minor)
    env.Prepend(CPPDEFINES = [('HAVE_LLVM', llvm_version_hex)])
285
286
287
288
289

def exists(env):
    return True

# vim:set ts=4 sw=4 et: