cmake_minimum_required(VERSION 3.12 FATAL_ERROR) # Set build type to "Release" if user did not specify any build type yet # Other possible values: Debug, Release, RelWithDebInfo and MinSizeRel if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif(NOT CMAKE_BUILD_TYPE) if(APPLE AND CMAKE_BUILD_TYPE STREQUAL "Release") set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "Target architectures") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "Target minimum macOS version") endif(APPLE AND CMAKE_BUILD_TYPE STREQUAL "Release") project(Hatari C) enable_testing() set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") include(CheckIncludeFiles) include(CheckFunctionExists) include(CheckStructHasMember) include(CheckSymbolExists) include(CheckCCompilerFlag) include(DistClean) include(CheckTypeSize) # set(CMAKE_VERBOSE_MAKEFILE 1) find_package(PkgConfig) ###################################################################### # Check if Large File Support is available # We test if the size of the type 'off_t' is at least 8 bytes ###################################################################### function (check_large_file) set (CMAKE_REQUIRED_FLAGS ${HATARI_LFS_FLAGS} ) check_type_size("off_t" SIZEOF_OFF_T ) if ( SIZEOF_OFF_T GREATER 7 ) set ( HATARI_HAVE_LFS 1 CACHE INTERNAL "Large file Support" ) else() set ( HATARI_HAVE_LFS 0 CACHE INTERNAL "Large file Support" ) endif() endfunction (check_large_file) # ########################## # Conditional build features # ########################## set(ENABLE_DSP_EMU 1 CACHE BOOL "Enable DSP 56k emulator for Falcon mode") set(ENABLE_TRACING 1 CACHE BOOL "Enable tracing messages for debugging") # Run-time checks with GCC / LLVM (Clang) AddressSanitizer: # - stack protection # - checking of pointer accesses # # Configure Hatari with AddressSanitizer: # cd build; make clean; cmake -D ENABLE_ASAN:BOOL=1 -D .. # If everything's fine, CMake output should include: # Performing Test ASAN_AVAILABLE - Success" # # After (re-)building Hatari, run it as following to see # available AddressSanitizer options (and that it works): # ASAN_OPTIONS=help=true src/hatari # # For more info: # https://github.com/google/sanitizers/wiki/AddressSanitizer # CHECK_C_COMPILER_FLAG("-fsanitize=address" ASAN_AVAILABLE) if(ASAN_AVAILABLE) set(ENABLE_ASAN 0 CACHE BOOL "Enable GCC/LLVM run-time stack/pointer debugging (~2x slowdown)") endif(ASAN_AVAILABLE) CHECK_C_COMPILER_FLAG("-fsanitize=undefined" UBSAN_AVAILABLE) if(UBSAN_AVAILABLE) set(ENABLE_UBSAN 0 CACHE BOOL "Enable GCC/LLVM run-time undefined behavior debugging") endif(UBSAN_AVAILABLE) find_program(GZIP gzip) if(UNIX AND GZIP) set(ENABLE_MAN_PAGES 1 CACHE BOOL "Built and install man pages") else() set(ENABLE_MAN_PAGES 0 CACHE BOOL "Built and install man pages") endif() if(APPLE) set(ENABLE_OSX_BUNDLE 1 CACHE BOOL "Built Hatari as macOS application bundle") set(CMAKE_XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@loader_path/../Frameworks") else() set(ENABLE_OSX_BUNDLE 0 CACHE BOOL "Built Hatari as macOS application bundle") endif(APPLE) if(ENABLE_OSX_BUNDLE) set(APP_NAME "Hatari") else() set(APP_NAME "hatari") endif(ENABLE_OSX_BUNDLE) # #################### # Check for libraries: # #################### find_package(SDL2) if(NOT SDL2_FOUND) message(FATAL_ERROR "SDL2 library not found!") endif(NOT SDL2_FOUND) find_package(Math) find_package(Readline) if(Readline_FOUND) set(HAVE_LIBREADLINE 1) endif(Readline_FOUND) find_package(ZLIB) if(ZLIB_FOUND) set(HAVE_LIBZ 1) set(HAVE_ZLIB_H 1) endif(ZLIB_FOUND) find_package(PNG) if(PNG_FOUND) set(HAVE_LIBPNG 1) endif(PNG_FOUND) if (NOT ENABLE_OSX_BUNDLE) find_package(X11) if(X11_FOUND) set(HAVE_X11 1) endif(X11_FOUND) endif() find_package(PortMidi) if(PortMidi_FOUND) set(HAVE_PORTMIDI 1) endif(PortMidi_FOUND) find_package(CapsImage) if(CapsImage_FOUND) set(HAVE_CAPSIMAGE 1) endif(CapsImage_FOUND) find_package(Udev) if(Udev_FOUND) set(HAVE_UDEV 1) endif(Udev_FOUND) find_package(Capstone) if(Capstone_FOUND) set(CMAKE_REQUIRED_INCLUDES ${CAPSTONE_INCLUDE_DIR}) CHECK_INCLUDE_FILE("m68k.h" HAVE_CAPSTONE_M68K) unset(CMAKE_REQUIRED_INCLUDES) if(NOT HAVE_CAPSTONE_M68K) unset(Capstone_FOUND) endif() endif(Capstone_FOUND) # Check if Large File Support is available with the standard POSIX flags set (HATARI_LFS_FLAGS "-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64") check_large_file() # ################ # CPP Definitions: # ################ # We still want to have assert() in RelWithDebInfo builds: string(REPLACE " -DNDEBUG" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") # Test for large file support: execute_process(COMMAND getconf LFS_CFLAGS OUTPUT_VARIABLE DETECTED_LFS_CFLAGS ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if(DETECTED_LFS_CFLAGS) add_definitions(${DETECTED_LFS_CFLAGS}) # message(STATUS "Large filesystem flags: ${DETECTED_LFS_CFLAGS}") endif(DETECTED_LFS_CFLAGS) # Additional CFLAGS suggested by the SDL library: if(PKG_CONFIG_FOUND) execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --cflags-only-other sdl2 OUTPUT_VARIABLE SDL2_OTHER_CFLAGS ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) endif(PKG_CONFIG_FOUND) if(ENABLE_OSX_BUNDLE) # Use OSX native alert windows add_definitions(-DALERT_HOOKS=1) # We still want to use our SDLMain.m with SDL2 add_definitions(-DSDL_MAIN_NEEDED=1) endif(ENABLE_OSX_BUNDLE) if(MSVC) add_definitions(-D_CRT_SECURE_NO_WARNINGS) endif(MSVC) # ########################### # Check for optional headers: # ########################### check_include_files(byteswap.h HAVE_BYTESWAP_H) check_include_files(termios.h HAVE_TERMIOS_H) check_include_files(sys/ioctl.h HAVE_SYS_IOCTL_H) check_include_files(strings.h HAVE_STRINGS_H) check_include_files(sys/time.h HAVE_SYS_TIME_H) check_include_files(sys/times.h HAVE_SYS_TIMES_H) check_include_files(utime.h HAVE_UTIME_H) check_include_files(sys/utime.h HAVE_SYS_UTIME_H) check_include_files("sys/socket.h;sys/un.h" HAVE_UNIX_DOMAIN_SOCKETS) # ############################# # Check for optional functions: # ############################# check_symbol_exists(bswap_16 "byteswap.h" HAVE_BSWAP_16) check_symbol_exists(bswap_32 "byteswap.h" HAVE_BSWAP_32) check_symbol_exists(cfmakeraw "termios.h" HAVE_CFMAKERAW) check_symbol_exists(tcsetattr "termios.h" HAVE_TCSETATTR) check_symbol_exists(setenv "stdlib.h" HAVE_SETENV) check_symbol_exists(select "sys/select.h" HAVE_SELECT) check_symbol_exists(gettimeofday "sys/time.h" HAVE_GETTIMEOFDAY) check_symbol_exists(nanosleep "time.h" HAVE_NANOSLEEP) check_symbol_exists(alphasort "dirent.h" HAVE_ALPHASORT) check_symbol_exists(scandir "dirent.h" HAVE_SCANDIR) check_symbol_exists(statvfs "sys/statvfs.h" HAVE_STATVFS) check_symbol_exists(fseeko "stdio.h" HAVE_FSEEKO) check_symbol_exists(ftello "stdio.h" HAVE_FTELLO) check_symbol_exists(flock "sys/file.h" HAVE_FLOCK) check_struct_has_member("struct dirent" d_type dirent.h HAVE_DIRENT_D_TYPE) # ############# # Other CFLAGS: # ############# # GCC/Clang stack/pointer debugging (~2x slowdown) if(ENABLE_ASAN) # better backtraces set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -fno-omit-frame-pointer") # enable stack protection set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-all") # enable AddressSanitizer with global variable tracking set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-common") endif(ENABLE_ASAN) # GCC/Clang undefined behavior debugging if(ENABLE_UBSAN) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined") add_definitions(-DENABLE_UBSAN=1) endif(ENABLE_UBSAN) # GCC/Clang specific flags: if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") # We want to allow ‘for’-loop initial declarations a la for(int i=0; ...) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") # Warning flags: set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-qual -Wbad-function-cast -Wpointer-arith") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-prototypes -Wstrict-prototypes") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wwrite-strings -Wsign-compare") #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra -Wno-unused-parameter -Wno-empty-body") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat-security") endif() if(APPLE AND CMAKE_C_COMPILER_ID MATCHES "Clang") # Silence linker warning with AppleClang 17 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-common") endif() CHECK_C_COMPILER_FLAG("-Wimplicit-fallthrough=2" WARN_FALLTRHOUGH_AVAILABLE) if(WARN_FALLTRHOUGH_AVAILABLE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wimplicit-fallthrough=2") endif(WARN_FALLTRHOUGH_AVAILABLE) CHECK_C_COMPILER_FLAG("-Wshadow=local" WARN_SHADOW_LOCAL_AVAILABLE) if(WARN_SHADOW_LOCAL_AVAILABLE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow=local") endif(WARN_SHADOW_LOCAL_AVAILABLE) CHECK_C_COMPILER_FLAG("-Wvla" WARN_VARIABLE_LENGTH_ARRAY_AVAILABLE) if(WARN_VARIABLE_LENGTH_ARRAY_AVAILABLE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wvla") endif(WARN_VARIABLE_LENGTH_ARRAY_AVAILABLE) if(EMSCRIPTEN) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti -fno-exceptions -O3 -s USE_SDL=2 -s USE_ZLIB=1") set(CMAKE_EXECUTABLE_SUFFIX ".html") endif() if(ENABLE_WERROR) if (ENABLE_TRACING) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") else() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wno-error=unused-function") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=unused-but-set-variable") endif() endif(ENABLE_WERROR) # Building Hatari w/o optimization is no fun... IF (CMAKE_BUILD_TYPE STREQUAL "Debug") set(CMAKE_C_FLAGS "-O ${CMAKE_C_FLAGS}") ENDIF (CMAKE_BUILD_TYPE STREQUAL "Debug") # Always add the Large File Support flags in case they are supported set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${HATARI_LFS_FLAGS}") # #################### # Paths configuration: # #################### if(NOT BINDIR) set(BINDIR bin) endif() if(NOT DATADIR) set(DATADIR share/hatari) endif() if(NOT BIN2DATADIR) if(WIN32) set(BIN2DATADIR "." CACHE STRING "Relative path from bindir to datadir") elseif(ENABLE_OSX_BUNDLE) set(BIN2DATADIR "../Resources" CACHE STRING "Relative path from bindir to datadir") else() set(BIN2DATADIR "../share/hatari" CACHE STRING "Relative path from bindir to datadir") endif(WIN32) mark_as_advanced(BIN2DATADIR) endif() if(NOT MANDIR) set(MANDIR share/man/man1) endif() if(NOT DOCDIR) set(DOCDIR share/doc/hatari) endif() if(NOT ETCDIR) if(WIN32) set(ETCDIR .) else() set(ETCDIR /etc) endif() endif() if(NOT ICONDIR) set(ICONDIR share/icons/hicolor) endif() if(ENABLE_OSX_BUNDLE) # put the config files in the app's bundle add_definitions(-DCONFDIR=\"../Resources\") else() add_definitions(-DCONFDIR=\"${ETCDIR}\") endif() # ######################################### # Create config.h and recurse into subdirs: # ######################################### configure_file(${CMAKE_SOURCE_DIR}/cmake/config-cmake.h ${CMAKE_BINARY_DIR}/config.h) add_subdirectory(src) add_subdirectory(doc) add_subdirectory(tools) if(NOT CMAKE_CROSSCOMPILING) add_subdirectory(tests) endif(NOT CMAKE_CROSSCOMPILING) include(FindPython) if(Python_Interpreter_FOUND AND Python_VERSION_MAJOR LESS 3) message("Note: Hatari needs at least Python 3 ... ignoring older version") unset(Python_Interpreter_FOUND) endif() set(PYTHON_GTK_FOUND 0) if(Python_Interpreter_FOUND) execute_process(COMMAND ${Python_EXECUTABLE} -c "\ import gi\n\ gi.require_version('Gtk', '3.0')\n\ from gi.repository import Gtk\n\ from gi.repository import Gdk\n\ from gi.repository import GdkPixbuf\n\ from gi.repository import GLib" RESULT_VARIABLE PYTHON_GTK_RESULT OUTPUT_QUIET ERROR_QUIET) if(${PYTHON_GTK_RESULT} EQUAL 0) set(PYTHON_GTK_FOUND 1) add_subdirectory(python-ui) endif() endif(Python_Interpreter_FOUND) if(UNIX AND NOT ENABLE_OSX_BUNDLE) add_subdirectory(share) endif() add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/cmake/Uninstall.cmake) # ################################################################### # Print a summary of the optional libraries with a short explanation: # ################################################################### message( " Libraries summary : ------------------- ") message(" - sdl :\tusing SDL2 ${SDL2_VERSION}") if(Readline_FOUND) message( " - readline :\tfound, enables history/completion in the debugger" ) else() message( " - readline :\tnot found, install it to enable debugger history/completion" ) endif(Readline_FOUND) if(ZLIB_FOUND) message( " - zlib :\tfound, allows to use zip/gz files directly" ) else() message( " - zlib :\tnot found, install it to use zip/gz files" ) endif(ZLIB_FOUND) if(PNG_FOUND) message( " - png :\tfound, allows to compress screenshot/avi files using png" ) else() message( " - png :\tnot found, install it to compress screenshot/avi files using png" ) endif(PNG_FOUND) if(PortMidi_FOUND) message( " - portmidi :\tfound, required for (non-Linux) MIDI support" ) else() message( " - portmidi :\tnot found, install it for MIDI support on Windows / OSX" ) endif(PortMidi_FOUND) if(CapsImage_FOUND) message( " - capsimage :\tv5 found, allow to use .IPF, .RAW and .CTR disk images" ) else() message( " - capsimage :\tv5 not found, install it to use .IPF, .RAW and .CTR disk images" ) endif(CapsImage_FOUND) if(PYTHON_GTK_FOUND) message( " - python Gtk:\tfound, python-ui can be used" ) else() message( " - python Gtk:\tnot found, install it to enable the python-ui" ) endif(PYTHON_GTK_FOUND) if(Udev_FOUND) message( " - udev :\tfound, required for media change detection in NatFeats SCSI" ) message( " \tdevices on udev-based systems (Linux)" ) else() if(UNIX AND NOT APPLE AND NOT CYGWIN) message( " - udev :\tnot found, install it to enable media change detection in" ) message( " \tNatFeats SCSI devices on udev-based systems (Linux)" ) endif() endif(Udev_FOUND) if(Capstone_FOUND) message( " - capstone :\tfound, allows nice disassembly with --disasm ext" ) else() message( " - capstone :\tnot found, install it to use extend disassembly options" ) endif(Capstone_FOUND) if (HATARI_HAVE_LFS) message(" - LFS :\tLarge File Support is available (size of off_t = ${SIZEOF_OFF_T}),") message(" \tAVI recording and HD image files can be bigger than 2 GB") else() message(" - LFS :\tLarge File Support is NOT available (size of off_t = ${SIZEOF_OFF_T}),") message(" \tAVI recording and HD image files will be limited to 2 GB") endif() if(NOT HAVE_SYS_TIMES_H) message("\n Note: times() function is missing (sys/times.h is not available)") message(" ==> using inaccurate SDL_GetTicks() instead") endif() message( "" )