############################################################################# # Name: build/cmake/setup.cmake # Purpose: Create and configure setup.h # Author: Tobias Taschner # Created: 2016-09-22 # Copyright: (c) 2016 wxWidgets development team # Licence: wxWindows licence ############################################################################# # Include modules required for setup.h generation include(CheckCSourceCompiles) include(CheckCXXCompilerFlag) include(CheckCXXSourceCompiles) include(CheckCXXSymbolExists) include(CheckFunctionExists) include(CheckIncludeFile) include(CheckIncludeFileCXX) include(CheckIncludeFiles) include(CheckPrototypeDefinition) include(CheckStructHasMember) include(CheckSymbolExists) include(CheckTypeSize) include(CMakePushCheckState) include(TestBigEndian) if( APPLE AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS 10.9 AND (CMAKE_CXX_STANDARD EQUAL 11 OR CMAKE_CXX_STANDARD EQUAL 14) ) set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} "-stdlib=libc++") endif() # Add a definition to setup.h and append it to a list of defines for # for compile checks macro(wx_setup_definition def) set(${def} YES) list(APPEND CMAKE_REQUIRED_DEFINITIONS -D${def}) endmacro() # Add define based on system name string(TOUPPER ${CMAKE_SYSTEM_NAME} wxSYS_NAME) wx_setup_definition(__${wxSYS_NAME}__) if(WIN32) wx_setup_definition(__WIN32__) endif() if(CYGWIN) wx_setup_definition(__GNUWIN32__) endif() if(UNIX) wx_setup_definition(wxUSE_UNIX) wx_setup_definition(__UNIX__) endif() if(UNIX AND NOT APPLE) wx_setup_definition(_GNU_SOURCE) endif() if(APPLE) wx_setup_definition(__BSD__) endif() if(WXGTK) # Add GTK version definitions foreach(gtk_version 1.2.7 2.0 2.10 2.18 2.20 3.0) if(wxTOOLKIT_VERSION VERSION_GREATER gtk_version) string(REPLACE . "" gtk_version_dotless ${gtk_version}) set(__WXGTK${gtk_version_dotless}__ ON) endif() endforeach() endif() set(wxINSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) check_include_files("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS) if(wxBUILD_SHARED) if(wxUSE_VISIBILITY) check_cxx_compiler_flag(-fvisibility=hidden HAVE_VISIBILITY) endif() endif() # wxBUILD_SHARED # wx_check_cxx_source_compiles( [headers...]) function(wx_check_cxx_source_compiles code res_var) set(src) foreach(header ${ARGN}) if(header STREQUAL "DEFINITION") set(is_definition TRUE) elseif(is_definition) set(src "${src}${header}") set(is_definition FALSE) else() set(src "${src}#include <${header}>\n") endif() endforeach() set(src "${src}\n\nint main(int argc, char* argv[]) {\n ${code}\nreturn 0; }") check_cxx_source_compiles("${src}" ${res_var}) endfunction() # wx_check_cxx_source_compiles( [headers...]) function(wx_check_c_source_compiles code res_var) set(src) foreach(header ${ARGN}) if(header STREQUAL "DEFINITION") set(is_definition TRUE) elseif(is_definition) set(src "${src}${header}") set(is_definition FALSE) else() set(src "${src}#include <${header}>\n") endif() endforeach() set(src "${src}\n\nint main(int argc, char* argv[]) {\n ${code}\nreturn 0; }") check_c_source_compiles("${src}" ${res_var}) endfunction() # wx_check_funcs(<...>) # define a HAVE_... for every function in list if available function(wx_check_funcs) foreach(func ${ARGN}) string(TOUPPER ${func} func_upper) check_function_exists(${func} HAVE_${func_upper}) endforeach() endfunction() if(NOT MSVC) check_symbol_exists(va_copy stdarg.h HAVE_VA_COPY) if(NOT HAVE_VA_COPY) # try to understand how can we copy va_lists set(VA_LIST_IS_ARRAY YES) endif() endif() wx_check_c_source_compiles( "#define test(fmt, ...) printf(fmt, __VA_ARGS__) test(\"%s %d %p\", \"test\", 1, 0);" HAVE_VARIADIC_MACROS stdio.h ) #TODO: wxNO_VARIADIC_MACROS if(wxUSE_STL) wx_check_cxx_source_compiles(" std::vector moo; std::list foo; std::vector::iterator it = std::find_if(moo.begin(), moo.end(), std::bind2nd(std::less(), 3));" wxTEST_STL string functional algorithm vector list ) if(NOT wxTEST_STL) message(FATAL_ERROR "Can't use wxUSE_STL as basic STL functionality is missing") endif() wx_check_cxx_source_compiles(" std::string foo, bar; foo.compare(bar); foo.compare(1, 1, bar); foo.compare(1, 1, bar, 1, 1); foo.compare(\"\"); foo.compare(1, 1, \"\"); foo.compare(1, 1, \"\", 2);" HAVE_STD_STRING_COMPARE string ) endif() # Check for availability of GCC's atomic operations builtins. wx_check_c_source_compiles(" unsigned int value=0; /* wxAtomicInc doesn't use return value here */ __sync_fetch_and_add(&value, 2); __sync_sub_and_fetch(&value, 1); /* but wxAtomicDec does, so mimic that: */ volatile unsigned int r2 = __sync_sub_and_fetch(&value, 1);" HAVE_GCC_ATOMIC_BUILTINS ) macro(wx_get_socket_param_type name code) # This test needs to be done in C++ mode since gsocket.cpp now # is C++ code and pointer cast that are possible even without # warning in C still fail in C++. wx_check_cxx_source_compiles( "socklen_t len; ${code}" ${name}_IS_SOCKLEN_T sys/types.h sys/socket.h ) if(${name}_IS_SOCKLEN_T) set(${name} socklen_t) else() wx_check_cxx_source_compiles( "size_t len; ${code}" ${name}_IS_SIZE_T sys/types.h sys/socket.h ) if(${name}_IS_SIZE_T) set(${name} size_t) else() wx_check_cxx_source_compiles( "int len; ${code}" ${name}_IS_INT sys/types.h sys/socket.h ) if(${name}_IS_INT) set(${name} int) else() message(ERROR "Couldn't find ${name} for this system") endif() endif() endif() endmacro() # the following tests are for Unix(like) systems only if(UNIX) if(wxUSE_LIBICONV) set(HAVE_ICONV ON) set(ICONV_CONST " ") if(ICONV_SECOND_ARGUMENT_IS_CONST) set(ICONV_CONST "const") endif() endif() # check for POSIX signals if we need them if(wxUSE_ON_FATAL_EXCEPTION) wx_check_funcs(sigaction) if(NOT HAVE_SIGACTION) message(WARNING "No POSIX signal functions on this system, wxApp::OnFatalException will not be called") wx_option_force_value(wxUSE_ON_FATAL_EXCEPTION OFF) endif() endif() if(wxUSE_ON_FATAL_EXCEPTION) wx_check_cxx_source_compiles( "return 0; } extern void testSigHandler(int) { }; int foo() { struct sigaction sa; sa.sa_handler = testSigHandler;" wxTYPE_SA_HANDLER_IS_INT signal.h ) if(wxTYPE_SA_HANDLER_IS_INT) set(wxTYPE_SA_HANDLER int) else() set(wxTYPE_SA_HANDLER void) endif() endif() # backtrace() and backtrace_symbols() for wxStackWalker if(wxUSE_STACKWALKER) wx_check_cxx_source_compiles(" void *trace[1]; char **messages; backtrace(trace, 1); messages = backtrace_symbols(trace, 1);" wxHAVE_BACKTRACE execinfo.h) if(NOT wxHAVE_BACKTRACE) message(WARNING "backtrace() is not available, wxStackWalker will not be available") wx_option_force_value(wxUSE_STACKWALKER OFF) else() wx_check_cxx_source_compiles( "int rc; __cxxabiv1::__cxa_demangle(\"foo\", 0, 0, &rc);" HAVE_CXA_DEMANGLE cxxabi.h) endif() endif() wx_check_funcs(mkstemp mktemp) # get the library function to use for wxGetDiskSpace(): it is statfs() under # Linux and *BSD and statvfs() under Solaris wx_check_c_source_compiles(" return 0; } #if defined(__BSD__) #include #include #else #include #endif int foo() { long l; struct statfs fs; statfs(\"/\", &fs); l = fs.f_bsize; l += fs.f_blocks; l += fs.f_bavail;" HAVE_STATFS) if(HAVE_STATFS) set(WX_STATFS_T "struct statfs") wx_check_cxx_source_compiles(" return 0; } #if defined(__BSD__) #include #include #else #include #endif int foo() { struct statfs fs; statfs(\"/\", &fs);" HAVE_STATFS_DECL) else() # TODO: implement statvfs checks if(HAVE_STATVFS) set(WX_STATFS_T statvfs_t) endif() endif() if(NOT HAVE_STATFS AND NOT HAVE_STATVFS) message(WARNING "wxGetDiskSpace() function won't work without statfs()") endif() # check for fcntl() or at least flock() needed by Unix implementation of # wxSingleInstanceChecker if(wxUSE_SNGLINST_CHECKER) wx_check_funcs(fcntl flock) if(NOT HAVE_FCNTL AND NOT HAVE_FLOCK) message(WARNING "wxSingleInstanceChecker not available") wx_option_force_value(wxUSE_SNGLINST_CHECKER OFF) endif() endif() # look for a function to modify the environment wx_check_funcs(setenv putenv) if(HAVE_SETENV) wx_check_funcs(unsetenv) endif() set(HAVE_SOME_SLEEP_FUNC FALSE) if(APPLE) # Mac OS X/Darwin has both nanosleep and usleep # but only usleep is defined in unistd.h set(HAVE_USLEEP TRUE) set(HAVE_SOME_SLEEP_FUNC TRUE) endif() if(NOT HAVE_SOME_SLEEP_FUNC) # try nanosleep() in libc and libposix4, if this fails - usleep() check_symbol_exists(nanosleep time.h HAVE_NANOSLEEP) if(NOT HAVE_NANOSLEEP) check_symbol_exists(usleep unistd.h HAVE_USLEEP) if(NOT HAVE_USLEEP) message(WARNING "wxSleep() function will not work") endif() endif() endif() # check for uname (POSIX) and gethostname (BSD) check_symbol_exists(uname sys/utsname.h HAVE_UNAME) if(HAVE_UNAME) wx_check_funcs(gethostname) endif() cmake_push_check_state() list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_REENTRANT) wx_check_funcs(strtok_r) cmake_pop_check_state() # check for inet_addr and inet_aton (these may live either in libc, or in # libnsl or libresolv or libsocket) # TODO wx_check_funcs(fdopen) if(wxUSE_TARSTREAM) wx_check_funcs(sysconf) cmake_push_check_state() list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_REENTRANT) check_symbol_exists(getpwuid_r pwd.h HAVE_GETPWUID_R) check_symbol_exists(getgrgid_r grp.h HAVE_GETGRGID_R) cmake_pop_check_state() endif() check_include_file(sys/soundcard.h HAVE_SYS_SOUNDCARD_H) set(HAVE_UNIX98_PRINTF ON) if(wxUSE_SOCKETS) # determine the type of third argument for getsockname wx_get_socket_param_type(WX_SOCKLEN_T "getsockname(0, 0, &len);") # Do this again for getsockopt as it may be different wx_get_socket_param_type(SOCKOPTLEN_T "getsockopt(0, 0, 0, 0, &len);") check_symbol_exists(gethostbyname netdb.h HAVE_GETHOSTBYNAME) check_symbol_exists(gethostbyname_r netdb.h HAVE_GETHOSTBYNAME_R) if(HAVE_GETHOSTBYNAME_R) check_prototype_definition(gethostbyname_r "int gethostbyname_r(const char *name, struct hostent *hp, struct hostent_data *hdata)" "0" "netdb.h" HAVE_FUNC_GETHOSTBYNAME_R_3) check_prototype_definition(gethostbyname_r "struct hostent *gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen, int *herr)" "NULL" "netdb.h" HAVE_FUNC_GETHOSTBYNAME_R_5) check_prototype_definition(gethostbyname_r "int gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen, struct hostent **result, int *herr)" "0" "netdb.h" HAVE_FUNC_GETHOSTBYNAME_R_6) endif() check_symbol_exists(getservbyname netdb.h HAVE_GETSERVBYNAME) check_symbol_exists(inet_aton arpa/inet.h HAVE_INET_ATON) check_symbol_exists(inet_addr arpa/inet.h HAVE_INET_ADDR) endif(wxUSE_SOCKETS) endif(UNIX) if(CMAKE_USE_PTHREADS_INIT) cmake_push_check_state(RESET) set(CMAKE_REQUIRED_LIBRARIES pthread) wx_check_cxx_source_compiles(" void *p; pthread_cleanup_push(ThreadCleanupFunc, p); pthread_cleanup_pop(0);" wxHAVE_PTHREAD_CLEANUP pthread.h DEFINITION "void ThreadCleanupFunc(void *p) { }\;" ) wx_check_c_source_compiles( "pthread_mutexattr_t attr; pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);" HAVE_PTHREAD_MUTEXATTR_T pthread.h ) if(HAVE_PTHREAD_MUTEXATTR_T) # check if we already have the declaration we need, it is not # present in some systems' headers wx_check_c_source_compiles( "pthread_mutexattr_t attr; pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);" HAVE_PTHREAD_MUTEXATTR_SETTYPE_DECL pthread.h ) else() # don't despair, there may be another way to do it wx_check_c_source_compiles( "pthread_mutex_t attr = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;" HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER pthread.h ) if(NOT HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER) # this may break code working elsewhere, so at least warn about it message(WARNING "wxMutex won't be recursive on this platform") endif() endif() if(wxUSE_COMPILER_TLS) # test for compiler thread-specific variables support wx_check_c_source_compiles(" static __thread int n = 0; static __thread int *p = 0;" HAVE___THREAD_KEYWORD pthread.h ) wx_check_cxx_source_compiles( "void foo(abi::__forced_unwind&);" HAVE_ABI_FORCEDUNWIND cxxabi.h) endif() cmake_pop_check_state() endif() # CMAKE_USE_PTHREADS_INIT check_symbol_exists(localtime_r time.h HAVE_LOCALTIME_R) check_symbol_exists(gmtime_r time.h HAVE_GMTIME_R) # --------------------------------------------------------------------------- # Checks for typedefs # --------------------------------------------------------------------------- # check what exactly size_t is on this machine - this is necessary to avoid # ambiguous overloads in several places, notably wx/string.h and wx/array.h # an obvious check like wx_check_cxx_source_compiles(struct Foo { ... };) doesn't work # with egcs (at least) up to 1.1.1 as it allows you to compile duplicate # methods in a local class (i.e. class inside a function) declaration # without any objections!! # # hence the hack below: we must have Foo at global scope! wx_check_cxx_source_compiles("return 0; } struct Foo { void foo(size_t); void foo(unsigned int); }; int bar() {" wxSIZE_T_IS_NOT_UINT stddef.h) if(wxSIZE_T_IS_NOT_UINT) wx_check_cxx_source_compiles("return 0; } struct Foo { void foo(size_t); void foo(unsigned long); }; int bar() {" wxSIZE_T_IS_NOT_ULONG stddef.h) if(NOT wxSIZE_T_IS_NOT_ULONG) set(wxSIZE_T_IS_ULONG YES) endif() else() set(wxSIZE_T_IS_UINT YES) endif() # check if wchar_t is separate type wx_check_cxx_source_compiles("return 0; } struct Foo { void foo(wchar_t); void foo(unsigned short); void foo(unsigned int); void foo(unsigned long); }; int bar() {" wxWCHAR_T_IS_REAL_TYPE wchar.h) # --------------------------------------------------------------------------- # Checks for structures # --------------------------------------------------------------------------- check_struct_has_member("struct passwd" pw_gecos pwd.h HAVE_PW_GECOS) # --------------------------------------------------------------------------- # Check for functions # --------------------------------------------------------------------------- # TODO: wcslen # Check various string symbols foreach(func ftime wcsftime wprintf putws fputws wprintf vswprintf vswscanf wcsdup wcsnlen wcscasecmp wcsncasecmp wcsrctombs wcstoull ) string(TOUPPER ${func} func_upper) check_symbol_exists(${func} wchar.h HAVE_${func_upper}) endforeach() # Check various functions foreach(func fsync snprintf vsnprintf strnlen strtoull setpriority ) string(TOUPPER ${func} func_upper) check_function_exists(${func} HAVE_${func_upper}) endforeach() if(MSVC) check_symbol_exists(vsscanf stdio.h HAVE_VSSCANF) endif() # at least under IRIX with mipsPro the C99 round() function is available when # building using the C compiler but not when using C++ one check_cxx_symbol_exists(round math.h HAVE_ROUND) # Check includes if(NOT MSVC_VERSION LESS 1600) check_include_file_cxx(tr1/type_traits HAVE_TR1_TYPE_TRAITS) check_include_file_cxx(type_traits HAVE_TYPE_TRAITS) endif() check_include_file(fcntl.h HAVE_FCNTL_H) check_include_file(langinfo.h HAVE_LANGINFO_H) check_include_file(sched.h HAVE_SCHED_H) check_include_file(unistd.h HAVE_UNISTD_H) check_include_file(w32api.h HAVE_W32API_H) check_include_file(wchar.h HAVE_WCHAR_H) check_include_file(wcstr.h HAVE_WCSTR_H) wx_check_cxx_source_compiles( "std::wstring s;" HAVE_STD_WSTRING string ) if(wxUSE_DATETIME) # check for timezone variable # doesn't exist under Darwin / Mac OS X which uses tm_gmtoff instead foreach(timezone_def timezone _timezone __timezone) wx_check_cxx_source_compiles(" int tz; tz = ${timezone_def};" wxTEST_TZ_${timezone_def} time.h ) if(${wxTEST_TZ_${timezone_def}}) set(WX_TIMEZONE ${timezone_def}) break() endif() endforeach() check_struct_has_member("struct tm" tm_gmtoff time.h WX_GMTOFF_IN_TM) endif() cmake_push_check_state(RESET) set(CMAKE_REQUIRED_LIBRARIES dl) check_symbol_exists(dlopen dlfcn.h HAVE_DLOPEN) cmake_pop_check_state() if(HAVE_DLOPEN) check_symbol_exists(dlerror dlfcn.h HAVE_DLERROR) check_symbol_exists(dladdr dlfcn.h HAVE_DLADDR) else() check_symbol_exists(shl_load dl.h HAVE_SHL_LOAD) endif() check_function_exists(gettimeofday HAVE_GETTIMEOFDAY) if(APPLE) set(wxUSE_EPOLL_DISPATCHER OFF) set(wxUSE_SELECT_DISPATCHER ON) else() if(NOT WIN32) set(wxUSE_SELECT_DISPATCHER ON) endif() check_include_file(sys/epoll.h wxUSE_EPOLL_DISPATCHER) endif() check_include_file(sys/select.h HAVE_SYS_SELECT_H) if(wxUSE_FSWATCHER) check_include_file(sys/inotify.h wxHAS_INOTIFY) if(NOT wxHAS_INOTIFY) check_include_file(sys/event.h wxHAS_KQUEUE) endif() endif() if(wxUSE_XLOCALE) check_include_file(xlocale.h HAVE_XLOCALE_H) set(CMAKE_EXTRA_INCLUDE_FILES locale.h) if(HAVE_XLOCALE_H) list(APPEND CMAKE_EXTRA_INCLUDE_FILES xlocale.h) endif() check_type_size(locale_t LOCALE_T) set(CMAKE_EXTRA_INCLUDE_FILES) endif() # Check size and availability of various types set(SYSTYPES pid_t size_t wchar_t int long short gid_t uid_t ) if(NOT MSVC) list(APPEND SYSTYPES mode_t off_t) endif() foreach(SYSTYPE ${SYSTYPES}) string(TOUPPER ${SYSTYPE} SYSTYPE_UPPER) check_type_size(${SYSTYPE} SIZEOF_${SYSTYPE_UPPER}) if(NOT HAVE_SIZEOF_${SYSTYPE_UPPER}) # Add a definition if it is not available set(${SYSTYPE} ON) endif() endforeach() check_type_size("long long" SIZEOF_LONG_LONG) check_type_size(ssize_t SSIZE_T) test_big_endian(WORDS_BIGENDIAN) configure_file(build/cmake/setup.h.in ${wxSETUP_HEADER_FILE}) if(DEFINED wxSETUP_HEADER_FILE_DEBUG) # The debug version may be configured with different values in the future configure_file(build/cmake/setup.h.in ${wxSETUP_HEADER_FILE_DEBUG}) endif()