llvm.py revision 848b8605
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 sys
34import distutils.version
35
36import SCons.Errors
37import SCons.Util
38
39
40required_llvm_version = '3.1'
41
42
43def generate(env):
44    env['llvm'] = False
45
46    try:
47        llvm_dir = os.environ['LLVM']
48    except KeyError:
49        # Do nothing -- use the system headers/libs
50        llvm_dir = None
51    else:
52        if not os.path.isdir(llvm_dir):
53            raise SCons.Errors.InternalError, "Specified LLVM directory not found"
54
55        if env['debug']:
56            llvm_subdir = 'Debug'
57        else:
58            llvm_subdir = 'Release'
59
60        llvm_bin_dir = os.path.join(llvm_dir, llvm_subdir, 'bin')
61        if not os.path.isdir(llvm_bin_dir):
62            llvm_bin_dir = os.path.join(llvm_dir, 'bin')
63            if not os.path.isdir(llvm_bin_dir):
64                raise SCons.Errors.InternalError, "LLVM binary directory not found"
65
66        env.PrependENVPath('PATH', llvm_bin_dir)
67
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/config.h')
76        if not os.path.exists(llvm_config):
77            print 'scons: could not find %s' % llvm_config
78            return
79        llvm_version_re = re.compile(r'^#define PACKAGE_VERSION "([^"]*)"')
80        llvm_version = None
81        for line in open(llvm_config, 'rt'):
82            mo = llvm_version_re.match(line)
83            if mo:
84                llvm_version = mo.group(1)
85                llvm_version = distutils.version.LooseVersion(llvm_version)
86                break
87        if llvm_version is None:
88            print 'scons: could not determine the LLVM version from %s' % llvm_config
89            return
90        if llvm_version < distutils.version.LooseVersion(required_llvm_version):
91            print 'scons: LLVM version %s found, but %s is required' % (llvm_version, required_llvm_version)
92            return
93
94        env.Prepend(CPPPATH = [os.path.join(llvm_dir, 'include')])
95        env.AppendUnique(CPPDEFINES = [
96            '__STDC_LIMIT_MACROS',
97            '__STDC_CONSTANT_MACROS',
98            'HAVE_STDINT_H',
99        ])
100        env.Prepend(LIBPATH = [os.path.join(llvm_dir, 'lib')])
101        if llvm_version >= distutils.version.LooseVersion('3.2'):
102            # 3.2
103            env.Prepend(LIBS = [
104                'LLVMBitWriter', 'LLVMX86Disassembler', 'LLVMX86AsmParser',
105                'LLVMX86CodeGen', 'LLVMX86Desc', 'LLVMSelectionDAG',
106                'LLVMAsmPrinter', 'LLVMMCParser', 'LLVMX86AsmPrinter',
107                'LLVMX86Utils', 'LLVMX86Info', 'LLVMMCJIT', 'LLVMJIT',
108                'LLVMExecutionEngine', 'LLVMCodeGen', 'LLVMScalarOpts',
109                'LLVMInstCombine', 'LLVMTransformUtils', 'LLVMipa',
110                'LLVMAnalysis', 'LLVMTarget', 'LLVMMC', 'LLVMCore',
111                'LLVMSupport', 'LLVMRuntimeDyld', 'LLVMObject'
112            ])
113        else:
114            # 3.1
115            env.Prepend(LIBS = [
116                'LLVMBitWriter', 'LLVMX86Disassembler', 'LLVMX86AsmParser',
117                'LLVMX86CodeGen', 'LLVMX86Desc', 'LLVMSelectionDAG',
118                'LLVMAsmPrinter', 'LLVMMCParser', 'LLVMX86AsmPrinter',
119                'LLVMX86Utils', 'LLVMX86Info', 'LLVMMCJIT', 'LLVMJIT',
120                'LLVMExecutionEngine', 'LLVMCodeGen', 'LLVMScalarOpts',
121                'LLVMInstCombine', 'LLVMTransformUtils', 'LLVMipa',
122                'LLVMAnalysis', 'LLVMTarget', 'LLVMMC', 'LLVMCore',
123                'LLVMSupport'
124            ])
125        env.Append(LIBS = [
126            'imagehlp',
127            'psapi',
128            'shell32',
129            'advapi32'
130        ])
131        if env['msvc']:
132            # Some of the LLVM C headers use the inline keyword without
133            # defining it.
134            env.Append(CPPDEFINES = [('inline', '__inline')])
135            if env['build'] in ('debug', 'checked'):
136                # LLVM libraries are static, build with /MT, and they
137                # automatically link agains LIBCMT. When we're doing a
138                # debug build we'll be linking against LIBCMTD, so disable
139                # that.
140                env.Append(LINKFLAGS = ['/nodefaultlib:LIBCMT'])
141    else:
142        if not env.Detect('llvm-config'):
143            print 'scons: llvm-config script not found'
144            return
145
146        llvm_version = env.backtick('llvm-config --version').rstrip()
147        llvm_version = distutils.version.LooseVersion(llvm_version)
148
149        if llvm_version < distutils.version.LooseVersion(required_llvm_version):
150            print 'scons: LLVM version %s found, but %s is required' % (llvm_version, required_llvm_version)
151            return
152
153        try:
154            # Treat --cppflags specially to prevent NDEBUG from disabling
155            # assertion failures in debug builds.
156            cppflags = env.ParseFlags('!llvm-config --cppflags')
157            try:
158                cppflags['CPPDEFINES'].remove('NDEBUG')
159            except ValueError:
160                pass
161            env.MergeFlags(cppflags)
162
163            # Match llvm --fno-rtti flag
164            cxxflags = env.backtick('llvm-config --cxxflags').split()
165            if '-fno-rtti' in cxxflags:
166                env.Append(CXXFLAGS = ['-fno-rtti'])
167
168            components = ['engine', 'mcjit', 'bitwriter', 'x86asmprinter']
169
170            env.ParseConfig('llvm-config --libs ' + ' '.join(components))
171            env.ParseConfig('llvm-config --ldflags')
172            if llvm_version >= distutils.version.LooseVersion('3.5'):
173                env.ParseConfig('llvm-config --system-libs')
174                env.Append(CXXFLAGS = ['-std=c++11'])
175        except OSError:
176            print 'scons: llvm-config version %s failed' % llvm_version
177            return
178
179    assert llvm_version is not None
180    env['llvm'] = True
181
182    print 'scons: Found LLVM version %s' % llvm_version
183    env['LLVM_VERSION'] = llvm_version
184
185    # Define HAVE_LLVM macro with the major/minor version number (e.g., 0x0206 for 2.6)
186    llvm_version_major = int(llvm_version.version[0])
187    llvm_version_minor = int(llvm_version.version[1])
188    llvm_version_hex = '0x%02x%02x' % (llvm_version_major, llvm_version_minor)
189    env.Prepend(CPPDEFINES = [('HAVE_LLVM', llvm_version_hex)])
190
191def exists(env):
192    return True
193
194# vim:set ts=4 sw=4 et:
195