1## ---------------------------------------------------------------------
2##
3## Copyright (C) 2012 - 2020 by the deal.II authors
4##
5## This file is part of the deal.II library.
6##
7## The deal.II library is free software; you can use it, redistribute
8## it, and/or modify it under the terms of the GNU Lesser General
9## Public License as published by the Free Software Foundation; either
10## version 2.1 of the License, or (at your option) any later version.
11## The full text of the license can be found in the file LICENSE.md at
12## the top level directory of deal.II.
13##
14## ---------------------------------------------------------------------
15
16########################################################################
17#                                                                      #
18#                 Check for various compiler features:                 #
19#                                                                      #
20########################################################################
21
22#
23# This file sets up:
24#
25#   DEAL_II_COMPILER_USE_VECTOR_ARITHMETICS
26#   DEAL_II_VECTOR_ITERATOR_IS_POINTER
27#   DEAL_II_HAVE_BUILTIN_EXPECT
28#   DEAL_II_HAVE_GLIBC_STACKTRACE
29#   DEAL_II_HAVE_LIBSTDCXX_DEMANGLER
30#   DEAL_II_COMPILER_HAS_ATTRIBUTE_PRETTY_FUNCTION
31#   DEAL_II_COMPILER_HAS_ATTRIBUTE_ALWAYS_INLINE
32#   DEAL_II_ALWAYS_INLINE
33#   DEAL_II_RESTRICT
34#   DEAL_II_COMPILER_HAS_DIAGNOSTIC_PRAGMA
35#   DEAL_II_COMPILER_HAS_FUSE_LD_GOLD
36#
37
38#
39# A couple of test results depend on compiler flags and the C++ mode.
40# Nota Bene: If your test depends on the value of compile flags set in
41# ${DEAL_II_CXX_FLAGS} it is probably a language feature and should go into
42# check_01_cxx_features.cmake
43#
44
45
46#
47# Check whether the compiler allows to use arithmetic operations
48# +-*/ on vectorized data types or whether we need to use
49# _mm_add_pd for addition and so on. +-*/ is preferred because
50# it allows the compiler to choose other optimizations like
51# fused multiply add, whereas _mm_add_pd explicitly enforces the
52# assembler command.
53#
54# - Matthias Maier, rewritten 2012
55#
56CHECK_CXX_SOURCE_COMPILES(
57  "
58  #include <x86intrin.h>
59  int main()
60  {
61    __m128d a, b;
62    a = _mm_set_sd (1.0);
63    b = _mm_set1_pd (2.1);
64    __m128d c = a + b;
65    __m128d d = b - c;
66    __m128d e = c * a + d;
67    __m128d f = e/a;
68#ifdef __AVX512F__
69    __m512d g, h;
70    g = _mm512_set1_pd (1.0);
71    h = _mm512_set1_pd (2.1);
72    __m512d i = g + h;
73    g = i - g;
74    h *= i;
75    i = h/i;
76    (void)i;
77#endif
78    (void)f;
79  }
80  "
81  DEAL_II_COMPILER_USE_VECTOR_ARITHMETICS)
82
83
84#
85# Check whether the std::vector::iterator is just a plain pointer
86#
87# (Yes. It is not a bug. But the logic is the same.)
88#
89# - Matthias Maier, rewritten 2012
90#
91CHECK_CXX_COMPILER_BUG(
92  "
93  #include <vector>
94  template <typename T> void f(T) {}
95  template void f(int *);
96  template void f(std::vector<int>::iterator);
97  int main(){return 0;}
98  "
99  DEAL_II_VECTOR_ITERATOR_IS_POINTER)
100
101
102#
103# Check for existence of the __builtin_expect facility of newer
104# GCC compilers. This can be used to hint the compiler's branch
105# prediction unit in some cases. We use it in the AssertThrow
106# macros.
107#
108# Intel compilers don't handle __builtin_expect in C++14 constexpr contexts
109# properly so we disable this feature in case we are going to use
110# DEAL_II_CONSTEXPR with an Intel compiler.
111#
112# - Matthias Maier, rewritten 2012
113#
114IF(NOT CMAKE_CXX_COMPILER_ID MATCHES "Intel")
115  CHECK_CXX_SOURCE_COMPILES(
116    "
117    bool f() { return true; }
118    int main(){ if (__builtin_expect(f(),false)) {} }
119    "
120    DEAL_II_HAVE_BUILTIN_EXPECT)
121ENDIF()
122
123
124#
125# Check whether glibc-like stacktrace information is available
126# for the Exception class. If it is, then try to also determine
127# whether the compiler accepts the -rdynamic flag, since that is
128# recommended for linking if one wants to have meaningful
129# backtraces.
130#
131# - Matthias Maier, rewritten 2012
132#
133CHECK_CXX_SOURCE_COMPILES(
134  "
135  #include <execinfo.h>
136  #include <stdlib.h>
137  void * array[25];
138  int nSize = backtrace(array, 25);
139  char ** symbols = backtrace_symbols(array, nSize);
140  int main(){ free(symbols); return 0; }
141  "
142  DEAL_II_HAVE_GLIBC_STACKTRACE)
143
144IF(DEAL_II_HAVE_GLIBC_STACKTRACE AND NOT DEAL_II_STATIC_EXECUTABLE)
145  ENABLE_IF_LINKS(DEAL_II_LINKER_FLAGS "-rdynamic")
146ENDIF()
147
148
149#
150# Check whether the compiler offers a way to demangle symbols
151# from within the program. Used inside the exception stacktrace
152# mechanism.
153#
154# The example code is taken from
155#   http://gcc.gnu.org/onlinedocs/libstdc++/18_support/howto.html#6
156#
157# - Matthias Maier, rewritten 2012
158#
159CHECK_CXX_SOURCE_COMPILES(
160  "
161  #include <exception>
162  #include <iostream>
163  #include <cxxabi.h>
164  #include <cstdlib>
165
166  struct empty { };
167
168  template <typename T, int N>
169  struct bar { };
170
171  int     status;
172  char   *realname;
173
174  int main()
175  {
176    // exception classes not in <stdexcept>, thrown by the implementation
177    // instead of the user
178    std::bad_exception  e;
179    realname = abi::__cxa_demangle(e.what(), 0, 0, &status);
180    free(realname);
181
182
183    // typeid
184    bar<empty,17>          u;
185    const std::type_info  &ti = typeid(u);
186
187    realname = abi::__cxa_demangle(ti.name(), 0, 0, &status);
188    free(realname);
189
190      return 0;
191  }
192  "
193  DEAL_II_HAVE_LIBSTDCXX_DEMANGLER)
194
195
196#
197# GCC and some other compilers have __PRETTY_FUNCTION__, showing
198# an unmangled version of the function we are presently in,
199# while __FUNCTION__ (or __func__ in ISO C99) simply give the
200# function name which would not include the arguments of that
201# function, leading to problems in C++ with overloaded function
202# names.
203#
204# If __PRETTY_FUNCTION__ is not available, try to find out whether
205# __func__ is available and use the preprocessor to set the first
206# thing to the second. If this is also not the case, then set it
207# to something indicating non-availability.
208#
209# - Matthias Maier, rewritten 2012
210#
211
212CHECK_CXX_SOURCE_COMPILES(
213  "
214  #include <iostream>
215  int main()
216  {
217    std::cout << __PRETTY_FUNCTION__ << std::endl;
218    return 0;
219  }
220  "
221  DEAL_II_COMPILER_HAS_ATTRIBUTE_PRETTY_FUNCTION)
222
223IF(NOT DEAL_II_COMPILER_HAS_ATTRIBUTE_PRETTY_FUNCTION)
224  CHECK_CXX_SOURCE_COMPILES(
225    "
226    #include <iostream>
227    int main()
228    {
229      std::cout << __func__ << std::endl;
230      return 0;
231    }
232    "
233    DEAL_II_COMPILER_HAS_ATTRIBUTE_FUNC)
234
235  IF(DEAL_II_COMPILER_HAS_ATTRIBUTE_FUNC)
236    SET(__PRETTY_FUNCTION__ "__func__")
237  ELSE()
238    SET(__PRETTY_FUNCTION__ "\"(not available)\"")
239  ENDIF()
240ENDIF()
241
242
243#
244# Newer versions of GCC can pass a flag to the assembler to
245# compress debug sections. At the time of writing this test,
246# this can save around 230 MB of disk space on the object
247# files we produce (810MB down to 570MB for the debug versions
248# of object files). Unfortunately, the sections have to be
249# unpacked again when they are put into the shared libs, so
250# no savings there.
251#
252# The flag also doesn't appear to be working on Cygwin, as
253# per email by John Fowkes on the mailing list in Feb 2012,
254# so don't run the test on cygwin.
255#
256# Finally, Intel's icpc compiler complains about the flag
257# but apparently only if the file to be compiled contains
258# particular content. See bug #46 in the Google Code bug
259# data base (http://code.google.com/p/dealii/issues/detail?id=46).
260# It proved impossible to track down under which circumstances
261# this happens, and so it was disabled for icpc.
262#
263# - Matthias Maier, rewritten 2012, 2013
264#
265IF( (NOT CMAKE_SYSTEM_NAME MATCHES "CYGWIN") AND
266    (NOT CMAKE_SYSTEM_NAME MATCHES "Windows") AND
267    (NOT CMAKE_CXX_COMPILER_ID MATCHES "Intel") )
268  ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${DEAL_II_CXX_FLAGS_DEBUG}")
269  ENABLE_IF_SUPPORTED(DEAL_II_CXX_FLAGS_DEBUG "-Wa,--compress-debug-sections")
270  RESET_CMAKE_REQUIRED()
271ENDIF()
272
273
274#
275# Do a similar check with the always_inline attribute on functions.
276#
277CHECK_CXX_SOURCE_COMPILES(
278  "
279          __attribute__((always_inline)) int fn () { return 0; }
280          int main () { return fn(); }
281  "
282  DEAL_II_COMPILER_HAS_ATTRIBUTE_ALWAYS_INLINE
283  )
284
285IF(DEAL_II_COMPILER_HAS_ATTRIBUTE_ALWAYS_INLINE)
286  SET(DEAL_II_ALWAYS_INLINE "__attribute__((always_inline))")
287ELSE()
288  SET(DEAL_II_ALWAYS_INLINE " ")
289ENDIF()
290
291
292#
293# Check whether the compiler understands the __restrict keyword.
294#
295CHECK_CXX_SOURCE_COMPILES(
296  "
297          void fn (double *__restrict a, double *__restrict b) { a[0] = b[0]; a[1] = b[0]; }
298          int main() { }
299  "
300  DEAL_II_COMPILER_HAS_RESTRICT_KEYWORD
301  )
302
303IF(DEAL_II_COMPILER_HAS_RESTRICT_KEYWORD)
304  SET(DEAL_II_RESTRICT "__restrict")
305ELSE()
306  SET(DEAL_II_RESTRICT " ")
307ENDIF()
308
309
310#
311# GCC and Clang allow fine grained control of diagnostics via the "GCC
312# diagnostic" pragma. Check whether the compiler supports the "push" and
313# "pop" mechanism and the "ignored" toggle. Further, test for the
314# alternative "_Pragma(...)" variant (and that it does not emit a warning).
315#
316# - Matthias Maier, 2015
317#
318ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${_werror_flag}")
319CHECK_CXX_SOURCE_COMPILES(
320  "
321  _Pragma(\"GCC diagnostic push\")
322  _Pragma(\"GCC diagnostic ignored \\\\\\\"-Wextra\\\\\\\"\")
323  _Pragma(\"GCC diagnostic ignored \\\\\\\"-Wunknown-pragmas\\\\\\\"\")
324  _Pragma(\"GCC diagnostic ignored \\\\\\\"-Wpragmas\\\\\\\"\")
325  int main() { return 0; }
326  _Pragma(\"GCC diagnostic pop\")
327  "
328  DEAL_II_COMPILER_HAS_DIAGNOSTIC_PRAGMA)
329RESET_CMAKE_REQUIRED()
330
331
332#
333# Use 'lld' or the 'gold' linker if possible, given that either of them is
334# substantially faster.
335#
336# We have to try to link a full executable with -fuse-ld=lld or -fuse-ld=gold
337# to check whether "ld.lld" or "ld.gold" is actually available.
338#
339# Clang always reports "argument unused during compilation", but fails at link
340# time for an unsupported linker.
341#
342# ICC also emits a warning but passes for unsupported linkers
343# unless we turn diagnostic warnings into errors.
344#
345# We also test linker support with "-shared -fPIC". This catches an
346# incompatibility where LLD refuses to produce a shared object from an
347# object file compiled by the Intel Compiler:
348#
349#   ld.lld: error: can't create dynamic relocation R_X86_64_64 against symbol:
350#   __gxx_personality_v0 in readonly segment; recompile object files with -fPIC
351#   or pass '-Wl,-z,notext' to allow text relocations in the output
352#
353# even if we actually had -fPIC option present. If we add -Wl,-z,notext, it
354# will link, but the produced libdeal_II.so is faulty and will crash randomly.
355#
356# Wolfgang Bangerth, Matthias Maier, Daniel Arndt, Binrui Dong, 2015, 2018-2020
357#
358
359IF(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
360
361  IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
362    ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Wno-unused-command-line-argument")
363  ELSEIF(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
364    ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-diag-error warn")
365  ENDIF()
366  ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-Werror")
367  ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-shared")
368  ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-fPIC")
369
370  #
371  # Check for ld.lld and ld.gold support:
372  #
373  ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-fuse-ld=lld")
374  CHECK_CXX_SOURCE_COMPILES(
375    "
376    #include <iostream>
377    void foo() { std::cout << \"Hello, world!\" << std::endl; }
378    "
379    DEAL_II_COMPILER_HAS_FUSE_LD_LLD)
380
381  STRIP_FLAG(CMAKE_REQUIRED_FLAGS "-fuse-ld=lld")
382  ADD_FLAGS(CMAKE_REQUIRED_FLAGS "-fuse-ld=gold")
383  CHECK_CXX_SOURCE_COMPILES(
384    "
385    #include <iostream>
386    void foo() { std::cout << \"Hello, world!\" << std::endl; }
387    "
388    DEAL_II_COMPILER_HAS_FUSE_LD_GOLD)
389
390  IF(DEAL_II_COMPILER_HAS_FUSE_LD_LLD)
391    ADD_FLAGS(DEAL_II_LINKER_FLAGS "-fuse-ld=lld")
392  ELSEIF(DEAL_II_COMPILER_HAS_FUSE_LD_GOLD)
393    ADD_FLAGS(DEAL_II_LINKER_FLAGS "-fuse-ld=gold")
394  ENDIF()
395
396  RESET_CMAKE_REQUIRED()
397ENDIF()
398