CraftCompiler.py 10.8 KB
Newer Older
1
# -*- coding: utf-8 -*-
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Copyright Hannah von Reth <vonreth@kde.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.

Hannah von Reth's avatar
Fix    
Hannah von Reth committed
25
import re
26
from enum import unique, IntFlag
27

28
import utils
29
from CraftConfig import *
Hannah von Reth's avatar
Fixes    
Hannah von Reth committed
30
31
from CraftCore import CraftCore
from CraftDebug import deprecated
32
33


Hannah von Reth's avatar
Hannah von Reth committed
34
class CraftCompiler(object):
35
36
37
38
39
40
    class Platforms(IntFlag):
        NoPlatform  = 0
        Windows     = 0x1 << 0
        Linux       = 0x1 << 1
        MacOS       = 0x1 << 2
        FreeBSD     = 0x1 << 3
41
        Android     = 0x1 << 4
42
43
44
45

        Unix        = Linux | MacOS | FreeBSD
        All         = ~0

46
47
48
49
        # define inverted values to allow usage in info.ini
        NotLinux     = ~Linux
        NotMacOS     = ~MacOS
        NotFreeBSD   = ~FreeBSD
Hannah von Reth's avatar
Hannah von Reth committed
50
        NotWindows   = ~Windows
51
        NotUnix      = ~Unix
52
        NotAndroid   = ~Android
53

54
55
56
57
58
59
60
61
62
        @classmethod
        def fromString(cls, name):
            if not hasattr(cls, "__sting_map"):
                cls.__sting_map = dict([(k.lower(), v) for k, v in cls.__members__.items()])
            return cls.__sting_map[name.lower()]

    @unique
    class Compiler(IntFlag):
        NoCompiler  = 0
63
        CL          = 0x1 << 0
64
65
66
67
68
69
        GCC         = 0x1 << 1
        CLANG       = 0x1 << 2

        GCCLike     = CLANG | GCC
        All         = ~0

70

71
72
73
74
75
76
        @classmethod
        def fromString(cls, name):
            if not hasattr(cls, "__sting_map"):
                cls.__sting_map = dict([(k.lower(), v) for k, v in cls.__members__.items()])
            return cls.__sting_map[name.lower()]

77
78

    def __init__(self):
79
        compiler = CraftCore.settings.get("General", "KDECOMPILER", "")
80
        if compiler != "":
81
            arch = "32" if CraftCore.settings.get("General", "Architecture") == "x86" else "64"
82
            if compiler.startswith("msvc"):
Hannah von Reth's avatar
Hannah von Reth committed
83
                split = ["windows", f"{compiler}_{arch}", "cl"]
84
85
            elif compiler.startswith("mingw"):
                split = ["windows", f"mingw_{arch}", "gcc"]
86
87
88
89
            elif compiler.startswith("linux"):
                split = ["linux", "gcc"]
            elif compiler.startswith("mac"):
                split = ["macos", "clang"]
90
            if not CraftCore.settings.getboolean("ContinuousIntegration", "Enabled", False):
91
                print(f"Your using the old compiler setting\n"
Hannah von Reth's avatar
Hannah von Reth committed
92
93
94
95
96
97
                      f"\t[General]\n"
                      f"\tKDECOMPILER={compiler}\n"
                      f"please update your settings to\n"
                      f"\t[General]\n"
                      f"\tABI=" + "-".join(split),
                      file=sys.stderr)
98
        else:
99
            split = CraftCore.settings.get("General", "ABI").split("-")
100
        if len(split) != 3:
101
            raise Exception("Invalid compiler: " + CraftCore.settings.get("General", "ABI"))
102

103
        platform, self._abi, compiler = split
104

105
106
        self._compiler = CraftCompiler.Compiler.fromString(compiler)
        self._platform = CraftCompiler.Platforms.fromString(platform)
107

108
        self._architecture = "x86" if self._abi.endswith("32") else "x64"
109

110
111
        self._MSVCToolset = None
        if self.isMSVC():
Hannah von Reth's avatar
Fix    
Hannah von Reth committed
112
            self._MSVCToolset = CraftCore.settings.get("General", "MSVCToolset", "")
113

114
115
116
117
118
119
120
121
        if self.isAndroid:
            self._architecture = self._abi
            if self._architecture == "arm":
                self._abi = "armeabi-v7a"
            elif self._architecture == "arm64":
                self._abi = "arm64-v8a"
            self._apiLevel = CraftCore.settings.get("General", "AndroidAPI", 21)

122
123
124
125
126
    def __str__(self):
        return "-".join(self.signature)

    @property
    def signature(self):
127
        return self.platform.name.lower(), self.abi, self.compiler.name.lower()
128
129

    @property
130
    def platform(self) -> Platforms:
131
132
133
134
135
136
137
        return self._platform

    @property
    def abi(self):
        return self._abi

    @property
138
    def compiler(self) -> Compiler:
139
140
141
142
143
144
        return self._compiler

    @property
    def architecture(self):
        return self._architecture

145
146
147
148
    @property
    def msvcToolset(self):
        return self._MSVCToolset

Filipe Azevedo's avatar
Filipe Azevedo committed
149
150
    @property
    def gnuArchitecture(self):
151
        return "x86" if self.isX86() else "x86_64"
Filipe Azevedo's avatar
Filipe Azevedo committed
152

153
154
155
156
    @property
    def bits(self):
        return "64" if self.isX64() else "32"

157
    def _getGCCTarget(self):
158
        _, result = CraftCore.cache.getCommandOutput("gcc", "-dumpmachine")
159
160
        if result:
            result = result.strip()
161
            CraftCore.log.debug(f"GCC Target Processor: {result}")
162
163
164
165
166
167
168
169
        else:
            # if no mingw is installed return mingw-w32 it is part of base
            if self.isX64():
                result = "x86_64-w64-mingw32"
            else:
                result = "i686-w64-mingw32"
        return result

170
    @property
171
172
173
174
175
176
    def isWindows(self) -> bool:
        return self.platform == CraftCompiler.Platforms.Windows

    @property
    def isMacOS(self) -> bool:
        return self.platform == CraftCompiler.Platforms.MacOS
177
178

    @property
179
180
    def isLinux(self) -> bool:
        return self.platform == CraftCompiler.Platforms.Linux
181
182

    @property
183
184
    def isFreeBSD(self) -> bool:
        return self.platform == CraftCompiler.Platforms.FreeBSD
185

186
187
188
189
    @property
    def isAndroid(self) -> bool:
        return self.platform == CraftCompiler.Platforms.Android

190
    @property
191
192
    def isUnix(self) -> bool:
        return bool(self.platform & CraftCompiler.Platforms.Unix)
193
194
195
196
197

    @property
    def executableSuffix(self):
        return ".exe" if self.isWindows else ""

198
    def isNative(self):
199
        return CraftCore.settings.getboolean("General", "Native", True)
200
201
202
203
204
205
206

    def isX64(self):
        return self.architecture == "x64"

    def isX86(self):
        return self.architecture == "x86"

207
208
    def isGCC(self) -> bool:
        return self.compiler == CraftCompiler.Compiler.GCC
209

210
    def isClang(self) -> bool:
Hannah von Reth's avatar
Hannah von Reth committed
211
        return self.compiler == CraftCompiler.Compiler.CLANG
212

213
214
    def isGCCLike(self) -> bool:
        return bool(self.compiler & CraftCompiler.Compiler.GCCLike)
215

216
217
    def isCl(self) -> bool:
        return self.compiler == CraftCompiler.Compiler.CL
218
219
220
221
222
223
224
225
226
227
228
229
230
231

    def isMinGW(self):
        return self.abi.startswith("mingw")

    def isMinGW_W32(self):
        return self.isMinGW() and self.isX86()

    def isMinGW_W64(self):
        return self.isMinGW() and self.isX64()

    def isMSVC(self):
        return self.abi.startswith("msvc")

    def isMSVC2010(self):
Hannah von Reth's avatar
Hannah von Reth committed
232
        return self.abi.startswith("msvc2010")
233
234

    def isMSVC2012(self):
Hannah von Reth's avatar
Hannah von Reth committed
235
        return self.abi.startswith("msvc2012")
236
237

    def isMSVC2013(self):
Hannah von Reth's avatar
Hannah von Reth committed
238
        return self.abi.startswith("msvc2013")
239
240

    def isMSVC2015(self):
Hannah von Reth's avatar
Hannah von Reth committed
241
        return self.abi.startswith("msvc2015")
242
243

    def isMSVC2017(self):
Hannah von Reth's avatar
Hannah von Reth committed
244
        return self.abi.startswith("msvc2017")
245

246
247
248
    def isMSVC2019(self):
        return self.abi.startswith("msvc2019")

249
250
251
    def isMSVC2022(self):
        return self.abi.startswith("msvc2022")

252
253
254
    def isIntel(self):
        return self.compiler == "intel"

255
    @deprecated("CraftCore.compiler")
256
    def getCompilerName(self):
257
        return str(CraftCore.compiler)
258

259
    @deprecated("CraftCore.compiler")
260
    def getSimpleCompilerName(self):
261
        return str(CraftCore.compiler)
262
263

    def getGCCLikeVersion(self, compilerExecutable):
264
        _, result = CraftCore.cache.getCommandOutput(compilerExecutable, "--version")
265
266
        if result:
            result = re.findall("\d+\.\d+\.?\d*", result)[0]
267
            CraftCore.log.debug("{0} Version: {1}".format(compilerExecutable, result))
268
269
270
271
        return result or "0"

    def getVersion(self):
        if self.isGCCLike():
272
            return self.getGCCLikeVersion(self.compiler.name)
273
        elif self.isMSVC():
274
            return self.getInternalVersion()
275
276
277
278
279
280
281
282
283
284
        else:
            return None

    def getVersionWithName(self):
        if self.isGCCLike():
            return f"{self.getCompilerName()} {self.getVersion()}"
        elif self.isIntel():
            return os.getenv("PRODUCT_NAME_FULL")
        elif self.isMSVC():
            return f"Microsoft Visual Studio {self.getVersion()}"
Hannah von Reth's avatar
fix    
Hannah von Reth committed
285
        else:
286
287
288
289
290
            return None

    def getShortName(self):
        if not self.isMSVC():
            return self.getCompilerName()
291
        return f"vc{self.getInternalVersion()}"
292

293
    def getInternalVersion(self):
294
295
296
297
298
299
300
        if not self.isMSVC():
            return self.getVersion()
        versions = {
            "msvc2010": 10,
            "msvc2012": 11,
            "msvc2013": 12,
            "msvc2015": 14,
301
            "msvc2017": 15,
302
303
            "msvc2019": 16,
            "msvc2022": 17
304
305
306
        }
        c = self.abi.split("_")[0]
        if c not in versions:
307
            CraftCore.log.critical(f"Unknown MSVC Compiler {self.abi}")
308
309
        return versions[c]

310
    def getMsvcPlatformToolset(self):
311
312
313
314
315
        versions = {
            "msvc2010": 100,
            "msvc2012": 110,
            "msvc2013": 120,
            "msvc2015": 140,
316
            "msvc2017": 141,
317
318
            "msvc2019": 142,
            "msvc2022": 143
319
320
321
        }
        c = self.abi.split("_")[0]
        if c not in versions:
322
            CraftCore.log.critical(f"Unknown MSVC Compiler {self.abi}")
323
324
        return versions[c]

325
326
327
    def androidApiLevel(self):
        return self._apiLevel

328
329
if __name__ == '__main__':
    print("Testing Compiler.py")
330
331
332
333
334
    print(f"Configured compiler (ABI): {CraftCore.compiler}")
    print("Version: %s" % CraftCore.compiler.getVersionWithName())
    print("Compiler Name: %s" % CraftCore.compiler.getCompilerName())
    print("Native compiler: %s" % ("No", "Yes")[CraftCore.compiler.isNative()])
    if CraftCore.compiler.isGCCLike():
Hannah von Reth's avatar
Hannah von Reth committed
335
336
        print("Compiler Version: %s" % CraftCore.compiler.getGCCLikeVersion(CraftCore.compiler.compiler.name))
        if CraftCore.compiler.isGCC():
337
            print("Compiler Target: %s" % CraftCore.compiler._getGCCTarget())