1from conans.client.tools.apple import to_apple_arch
2from conans.model.version import Version
3
4
5def architecture_flag(settings):
6    """
7    returns flags specific to the target architecture and compiler
8    """
9    compiler = settings.get_safe("compiler")
10    compiler_base = settings.get_safe("compiler.base")
11    arch = settings.get_safe("arch")
12    the_os = settings.get_safe("os")
13    subsystem = settings.get_safe("os.subsystem")
14    if not compiler or not arch:
15        return ""
16
17    if the_os == "Android":
18        return ""
19
20    if str(compiler) in ['gcc', 'apple-clang', 'clang', 'sun-cc']:
21        if str(the_os) == 'Macos' and str(subsystem) == 'catalyst':
22            # FIXME: This might be conflicting with Autotools --target cli arg
23            apple_arch = to_apple_arch(arch)
24            if apple_arch:
25                return '--target=%s-apple-ios-macabi' % apple_arch
26        elif str(arch) in ['x86_64', 'sparcv9', 's390x']:
27            return '-m64'
28        elif str(arch) in ['x86', 'sparc']:
29            return '-m32'
30        elif str(arch) in ['s390']:
31            return '-m31'
32        elif str(the_os) == 'AIX':
33            if str(arch) in ['ppc32']:
34                return '-maix32'
35            elif str(arch) in ['ppc64']:
36                return '-maix64'
37    elif str(compiler) == "intel":
38        # https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-m32-m64-qm32-qm64
39        if str(arch) == "x86":
40            return "/Qm32" if str(compiler_base) == "Visual Studio" else "-m32"
41        elif str(arch) == "x86_64":
42            return "/Qm64" if str(compiler_base) == "Visual Studio" else "-m64"
43    elif str(compiler) == "intel-cc":
44        # https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-m32-m64-qm32-qm64
45        if str(arch) == "x86":
46            return "/Qm32" if the_os == "Windows" else "-m32"
47        elif str(arch) == "x86_64":
48            return "/Qm64" if the_os == "Windows" else "-m64"
49    elif str(compiler) == "mcst-lcc":
50        return {"e2k-v2": "-march=elbrus-v2",
51                "e2k-v3": "-march=elbrus-v3",
52                "e2k-v4": "-march=elbrus-v4",
53                "e2k-v5": "-march=elbrus-v5",
54                "e2k-v6": "-march=elbrus-v6",
55                "e2k-v7": "-march=elbrus-v7"}.get(str(arch), "")
56    return ""
57
58
59def build_type_flags(settings):
60    """
61    returns flags specific to the build type (Debug, Release, etc.)
62    (-s, -g, /Zi, etc.)
63    """
64    compiler = settings.get_safe("compiler.base") or settings.get_safe("compiler")
65    build_type = settings.get_safe("build_type")
66    vs_toolset = settings.get_safe("compiler.toolset")
67    if not compiler or not build_type:
68        return ""
69
70    # https://github.com/Kitware/CMake/blob/d7af8a34b67026feaee558433db3a835d6007e06/
71    # Modules/Platform/Windows-MSVC.cmake
72    if str(compiler) in ['Visual Studio', 'msvc']:
73        if vs_toolset and "clang" in str(vs_toolset):
74            flags = {"Debug": ["-gline-tables-only", "-fno-inline", "-O0"],
75                     "Release": ["-O2"],
76                     "RelWithDebInfo": ["-gline-tables-only", "-O2", "-fno-inline"],
77                     "MinSizeRel": []
78                     }.get(build_type, ["-O2", "-Ob2"])
79        else:
80            flags = {"Debug": ["-Zi", "-Ob0", "-Od"],
81                     "Release": ["-O2", "-Ob2"],
82                     "RelWithDebInfo": ["-Zi", "-O2", "-Ob1"],
83                     "MinSizeRel": ["-O1", "-Ob1"],
84                     }.get(build_type, [])
85        return flags
86    else:
87        # https://github.com/Kitware/CMake/blob/f3bbb37b253a1f4a26809d6f132b3996aa2e16fc/
88        # Modules/Compiler/GNU.cmake
89        # clang include the gnu (overriding some things, but not build type) and apple clang
90        # overrides clang but it doesn't touch clang either
91        if str(compiler) in ["clang", "gcc", "apple-clang", "qcc", "mcst-lcc"]:
92            # FIXME: It is not clear that the "-s" is something related with the build type
93            # cmake is not adjusting it
94            # -s: Remove all symbol table and relocation information from the executable.
95            flags = {"Debug": ["-g"],
96                     "Release": ["-O3", "-s"] if str(compiler) == "gcc" else ["-O3"],
97                     "RelWithDebInfo": ["-O2", "-g"],
98                     "MinSizeRel": ["-Os"],
99                     }.get(build_type, [])
100            return flags
101        elif str(compiler) == "sun-cc":
102            # https://github.com/Kitware/CMake/blob/f3bbb37b253a1f4a26809d6f132b3996aa2e16fc/
103            # Modules/Compiler/SunPro-CXX.cmake
104            flags = {"Debug": ["-g"],
105                     "Release": ["-xO3"],
106                     "RelWithDebInfo": ["-xO2", "-g"],
107                     "MinSizeRel": ["-xO2", "-xspace"],
108                     }.get(build_type, [])
109            return flags
110    return ""
111
112
113def use_win_mingw(conanfile):
114    if hasattr(conanfile, 'settings_build'):
115        os_build = conanfile.settings_build.get_safe('os')
116    else:
117        os_build = conanfile.settings.get_safe('os_build')
118    if os_build is None:  # Assume is the same specified in host settings, not cross-building
119        os_build = conanfile.settings.get_safe("os")
120
121    if os_build == "Windows":
122        compiler = conanfile.settings.get_safe("compiler")
123        sub = conanfile.settings.get_safe("os.subsystem")
124        if sub in ("cygwin", "msys2", "msys") or compiler == "qcc":
125            return False
126        else:
127            return True
128    return False
129
130
131def cppstd_flag(settings):
132    compiler = settings.get_safe("compiler")
133    compiler_version = settings.get_safe("compiler.version")
134    compiler_base = settings.get_safe("compiler.base")
135    cppstd = settings.get_safe("compiler.cppstd")
136
137    if not compiler or not compiler_version or not cppstd:
138        return ""
139
140    cppstd_intel = _cppstd_intel_visualstudio if compiler_base == "Visual Studio" else \
141        _cppstd_intel_gcc
142    func = {"gcc": _cppstd_gcc,
143            "clang": _cppstd_clang,
144            "apple-clang": _cppstd_apple_clang,
145            "Visual Studio": _cppstd_visualstudio,
146            "msvc": _cppstd_msvc,
147            "intel": cppstd_intel,
148            "intel-cc": _cppstd_intel_cc,
149            "mcst-lcc": _cppstd_mcst_lcc}.get(str(compiler), None)
150    flag = None
151    if func:
152        flag = func(str(compiler_version), str(cppstd))
153    return flag
154
155
156def _cppstd_visualstudio(visual_version, cppstd):
157    # https://docs.microsoft.com/en-us/cpp/build/reference/std-specify-language-standard-version
158    v14 = None
159    v17 = None
160    v20 = None
161    v23 = None
162
163    if Version(visual_version) >= "14":
164        v14 = "c++14"
165        v17 = "c++latest"
166    if Version(visual_version) >= "15":
167        v17 = "c++17"
168        v20 = "c++latest"
169    if Version(visual_version) >= "17":
170        v20 = "c++20"
171        v23 = "c++latest"
172
173    flag = {"14": v14, "17": v17, "20": v20, "23": v23}.get(str(cppstd), None)
174    return "/std:%s" % flag if flag else None
175
176
177def _cppstd_msvc(visual_version, cppstd):
178    # https://docs.microsoft.com/en-us/cpp/build/reference/std-specify-language-standard-version
179    v14 = None
180    v17 = None
181    v20 = None
182    v23 = None
183
184    if Version(visual_version) >= "190":
185        v14 = "c++14"
186        v17 = "c++latest"
187    if Version(visual_version) >= "191":
188        v17 = "c++17"
189        v20 = "c++latest"
190    if Version(visual_version) >= "193":
191        v20 = "c++20"
192        v23 = "c++latest"
193
194    flag = {"14": v14, "17": v17, "20": v20, "23": v23}.get(str(cppstd), None)
195    return "/std:%s" % flag if flag else None
196
197
198def _cppstd_apple_clang(clang_version, cppstd):
199    """
200    Inspired in:
201    https://github.com/Kitware/CMake/blob/master/Modules/Compiler/AppleClang-CXX.cmake
202    """
203
204    v98 = vgnu98 = v11 = vgnu11 = v14 = vgnu14 = v17 = vgnu17 = v20 = vgnu20 = None
205
206    if Version(clang_version) >= "4.0":
207        v98 = "c++98"
208        vgnu98 = "gnu++98"
209        v11 = "c++11"
210        vgnu11 = "gnu++11"
211
212    if Version(clang_version) >= "6.1":
213        v14 = "c++14"
214        vgnu14 = "gnu++14"
215    elif Version(clang_version) >= "5.1":
216        v14 = "c++1y"
217        vgnu14 = "gnu++1y"
218
219    if Version(clang_version) >= "6.1":
220        v17 = "c++1z"
221        vgnu17 = "gnu++1z"
222
223    if Version(clang_version) >= "9.1":
224        # Not confirmed that it didn't work before 9.1 but 1z is still valid, so we are ok
225        v17 = "c++17"
226        vgnu17 = "gnu++17"
227
228    if Version(clang_version) >= "10.0":
229        v20 = "c++2a"
230        vgnu20 = "gnu++2a"
231
232    flag = {"98": v98, "gnu98": vgnu98,
233            "11": v11, "gnu11": vgnu11,
234            "14": v14, "gnu14": vgnu14,
235            "17": v17, "gnu17": vgnu17,
236            "20": v20, "gnu20": vgnu20}.get(cppstd, None)
237
238    return "-std=%s" % flag if flag else None
239
240
241def _cppstd_clang(clang_version, cppstd):
242    """
243    Inspired in:
244    https://github.com/Kitware/CMake/blob/
245    1fe2dc5ef2a1f262b125a2ba6a85f624ce150dd2/Modules/Compiler/Clang-CXX.cmake
246
247    https://clang.llvm.org/cxx_status.html
248    """
249    v98 = vgnu98 = v11 = vgnu11 = v14 = vgnu14 = v17 = vgnu17 = v20 = vgnu20 = v23 = vgnu23 = None
250
251    if Version(clang_version) >= "2.1":
252        v98 = "c++98"
253        vgnu98 = "gnu++98"
254
255    if Version(clang_version) >= "3.1":
256        v11 = "c++11"
257        vgnu11 = "gnu++11"
258    elif Version(clang_version) >= "2.1":
259        v11 = "c++0x"
260        vgnu11 = "gnu++0x"
261
262    if Version(clang_version) >= "3.5":
263        v14 = "c++14"
264        vgnu14 = "gnu++14"
265    elif Version(clang_version) >= "3.4":
266        v14 = "c++1y"
267        vgnu14 = "gnu++1y"
268
269    if Version(clang_version) >= "5":
270        v17 = "c++17"
271        vgnu17 = "gnu++17"
272    elif Version(clang_version) >= "3.5":
273        v17 = "c++1z"
274        vgnu17 = "gnu++1z"
275
276    if Version(clang_version) >= "6":
277        v20 = "c++2a"
278        vgnu20 = "gnu++2a"
279
280    if Version(clang_version) >= "12":
281        v20 = "c++20"
282        vgnu20 = "gnu++20"
283
284        v23 = "c++2b"
285        vgnu23 = "gnu++2b"
286
287    flag = {"98": v98, "gnu98": vgnu98,
288            "11": v11, "gnu11": vgnu11,
289            "14": v14, "gnu14": vgnu14,
290            "17": v17, "gnu17": vgnu17,
291            "20": v20, "gnu20": vgnu20,
292            "23": v23, "gnu23": vgnu23}.get(cppstd, None)
293    return "-std=%s" % flag if flag else None
294
295
296def _cppstd_gcc(gcc_version, cppstd):
297    """https://github.com/Kitware/CMake/blob/master/Modules/Compiler/GNU-CXX.cmake"""
298    # https://gcc.gnu.org/projects/cxx-status.html
299    v98 = vgnu98 = v11 = vgnu11 = v14 = vgnu14 = v17 = vgnu17 = v20 = vgnu20 = v23 = vgnu23 = None
300
301    if Version(gcc_version) >= "3.4":
302        v98 = "c++98"
303        vgnu98 = "gnu++98"
304
305    if Version(gcc_version) >= "4.7":
306        v11 = "c++11"
307        vgnu11 = "gnu++11"
308    elif Version(gcc_version) >= "4.3":
309        v11 = "c++0x"
310        vgnu11 = "gnu++0x"
311
312    if Version(gcc_version) >= "4.9":
313        v14 = "c++14"
314        vgnu14 = "gnu++14"
315    elif Version(gcc_version) >= "4.8":
316        v14 = "c++1y"
317        vgnu14 = "gnu++1y"
318
319    if Version(gcc_version) >= "5":
320        v17 = "c++1z"
321        vgnu17 = "gnu++1z"
322
323    if Version(gcc_version) >= "5.2":  # Not sure if even in 5.1 gnu17 is valid, but gnu1z is
324        v17 = "c++17"
325        vgnu17 = "gnu++17"
326
327    if Version(gcc_version) >= "8":
328        v20 = "c++2a"
329        vgnu20 = "gnu++2a"
330
331    if Version(gcc_version) >= "11":
332        v23 = "c++2b"
333        vgnu23 = "gnu++2b"
334
335    flag = {"98": v98, "gnu98": vgnu98,
336            "11": v11, "gnu11": vgnu11,
337            "14": v14, "gnu14": vgnu14,
338            "17": v17, "gnu17": vgnu17,
339            "20": v20, "gnu20": vgnu20,
340            "23": v23, "gnu23": vgnu23}.get(cppstd)
341    return "-std=%s" % flag if flag else None
342
343
344def _cppstd_intel_common(intel_version, cppstd, vgnu98, vgnu0x):
345    # https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-std-qstd
346    # https://software.intel.com/en-us/articles/intel-cpp-compiler-release-notes
347    # NOTE: there are only gnu++98 and gnu++0x, and only for Linux/macOS
348    v98 = v11 = v14 = v17 = v20 = None
349    vgnu11 = vgnu14 = vgnu17 = vgnu20 = None
350
351    if Version(intel_version) >= "12":
352        v11 = "c++0x"
353        vgnu11 = vgnu0x
354    if Version(intel_version) >= "14":
355        v11 = "c++11"
356        vgnu11 = vgnu0x
357    if Version(intel_version) >= "16":
358        v14 = "c++14"
359    if Version(intel_version) >= "18":
360        v17 = "c++17"
361    if Version(intel_version) >= "19.1":
362        v20 = "c++20"
363
364    return {"98": v98, "gnu98": vgnu98,
365            "11": v11, "gnu11": vgnu11,
366            "14": v14, "gnu14": vgnu14,
367            "17": v17, "gnu17": vgnu17,
368            "20": v20, "gnu20": vgnu20}.get(cppstd)
369
370
371def _cppstd_intel_gcc(intel_version, cppstd):
372    flag = _cppstd_intel_common(intel_version, cppstd, "gnu++98", "gnu++0x")
373    return "-std=%s" % flag if flag else None
374
375
376def _cppstd_intel_visualstudio(intel_version, cppstd):
377    flag = _cppstd_intel_common(intel_version, cppstd, None, None)
378    return "/Qstd=%s" % flag if flag else None
379
380
381def _cppstd_mcst_lcc(mcst_lcc_version, cppstd):
382    v11 = vgnu11 = v14 = vgnu14 = v17 = vgnu17 = v20 = vgnu20 = None
383
384    if Version(mcst_lcc_version) >= "1.21":
385        v11 = "c++11"
386        vgnu11 = "gnu++11"
387        v14 = "c++14"
388        vgnu14 = "gnu++14"
389
390    if Version(mcst_lcc_version) >= "1.24":
391        v17 = "c++17"
392        vgnu17 = "gnu++17"
393
394    if Version(mcst_lcc_version) >= "1.25":
395        v20 = "c++2a"
396        vgnu20 = "gnu++2a"
397
398    flag = {"98": "c++98", "gnu98": "gnu++98",
399            "03": "c++03", "gnu03": "gnu++03",
400            "11": v11, "gnu11": vgnu11,
401            "14": v14, "gnu14": vgnu14,
402            "17": v17, "gnu17": vgnu17,
403            "20": v20, "gnu20": vgnu20}.get(cppstd)
404    return "-std=%s" % flag if flag else None
405
406
407def _cppstd_intel_cc(_, cppstd):
408    """
409    Inspired in:
410    https://software.intel.com/content/www/us/en/develop/documentation/
411    oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/
412    compiler-options/compiler-option-details/language-options/std-qstd.html
413    """
414    # Note: for now, we don't care about compiler version
415    v98 = "c++98"
416    vgnu98 = "gnu++98"
417    v03 = "c++03"
418    vgnu03 = "gnu++03"
419    v11 = "c++11"
420    vgnu11 = "gnu++11"
421    v14 = "c++14"
422    vgnu14 = "gnu++14"
423    v17 = "c++17"
424    vgnu17 = "gnu++17"
425    v20 = "c++20"
426    vgnu20 = "gnu++20"
427    v23 = "c++2b"
428    vgnu23 = "gnu++2b"
429
430    flag = {"98": v98, "gnu98": vgnu98,
431            "03": v03, "gnu03": vgnu03,
432            "11": v11, "gnu11": vgnu11,
433            "14": v14, "gnu14": vgnu14,
434            "17": v17, "gnu17": vgnu17,
435            "20": v20, "gnu20": vgnu20,
436            "23": v23, "gnu23": vgnu23}.get(cppstd, None)
437    return "-std=%s" % flag if flag else None
438