env.py 4.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# cerbero - a multi-platform build system for Open Source software
# Copyright (C) 2016 Nirbheek Chauhan <nirbheek@centricular.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.

import os
import subprocess
21
from pathlib import Path
22
23
24
25
26
27

from cerbero.config import Architecture
from cerbero.errors import FatalError

# We only support Visual Studio 2015 as of now
vcvarsalls = {
28
29
    'vs14': [r'Microsoft Visual Studio 14.0\VC\vcvarsall.bat'],
    'vs15': [r'Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat',
Jos van Egmond's avatar
Jos van Egmond committed
30
31
             r'Microsoft Visual Studio\2017\Professional\VC\Auxiliary\Build\vcvarsall.bat',
             r'Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat'],
32
}
33
34
35
36
37
38
39
40
41

def get_program_files_dir():
    if 'PROGRAMFILES(X86)' in os.environ:
        # Windows 64-bit
        return Path(os.environ['PROGRAMFILES(X86)'])
    elif 'PROGRAMFILES' in os.environ:
        # Windows 32-bit
        return Path(os.environ['PROGRAMFILES'])
    raise FatalError('Could not find path to 32-bit Program Files directory')
42

43
44
45
46
47
def get_vcvarsall(version=None):
    if version is not None:
        versions = [version]
    else:
        versions = sorted(vcvarsalls.keys(), reverse=True)
48
    program_files = get_program_files_dir()
49
50
51
52
53
    for version in versions:
        for path in vcvarsalls[version]:
            path = program_files / path
            # Find the location of the Visual Studio installation
            if path.is_file():
54
                return path.as_posix(), version
55
56
    raise FatalError('Microsoft Visual Studio not found, please file a bug. '
                     'We looked for: ' + ', '.join(versions))
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

def append_path(var, path, sep=';'):
    if var and not var.endswith(sep):
        var += sep
    if path and not path.endswith(sep):
        path += sep
    var += path
    return var

def get_vcvarsall_arg(arch, target_arch):
    if target_arch == Architecture.X86:
        # If arch is x86_64, this will cause the WOW64 version of MSVC to be
        # used, which is how most people compile 32-bit apps on 64-bit.
        return 'x86'
    if arch == Architecture.X86:
        if target_arch == Architecture.X86_64:
            return 'x86_amd64'
        elif target_arch.is_arm():
            return 'x86_arm'
    elif arch == Architecture.X86_64:
        if target_arch == Architecture.X86_64:
            return 'amd64'
        elif target_arch.is_arm():
            return 'amd64_arm'
    elif arch.is_arm() and target_arch.is_arm():
            return 'arm'
    raise FatalError('Unsupported arch/target_arch: {0}/{1}'.format(arch, target_arch))

def run_and_get_env(cmd):
86
87
88
89
90
91
92
93
94
95
    env = os.environ.copy()
    env['VSCMD_ARG_no_logo'] = '1'
    env['VSCMD_DEBUG'] = ''
    output = subprocess.check_output(cmd, shell=True, env=env,
                                     universal_newlines=True)
    lines = []
    for line in output.split('\n'):
        if '=' in line:
            lines.append(line)
    return lines
96

97
98
99
100
101
# For a specific env var, get only the values that were prepended to it by MSVC
def get_envvar_msvc_values(msvc, nomsvc, sep=';'):
    index = msvc.index(nomsvc)
    return msvc[0:index]

102
def get_msvc_env(arch, target_arch, version=None):
103
    ret_env = {}
104
    vcvarsall, vsver = get_vcvarsall(version)
105
106
107
108
109
110

    without_msvc = run_and_get_env('set')
    arg = get_vcvarsall_arg(arch, target_arch)
    vcvars_env_cmd = '"{0}" {1} & {2}'.format(vcvarsall, arg, 'set')
    with_msvc = run_and_get_env(vcvars_env_cmd)

111
112
113
    msvc = dict([each.split('=', 1) for each in with_msvc])
    nomsvc = dict([each.split('=', 1) for each in without_msvc])

114
    for each in set(with_msvc) - set(without_msvc):
115
116
117
118
119
120
        var = each.split('=', 1)[0]
        # Use the new values for all vars, except PATH
        if var == 'PATH':
            ret_env[var] = get_envvar_msvc_values(msvc[var], nomsvc[var])
        else:
            ret_env[var] = msvc[var]
121
    return ret_env, vsver